update
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"email" TEXT NOT NULL,
|
||||
"passwordHash" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Waffle" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"ingredients" TEXT NOT NULL,
|
||||
"price" REAL NOT NULL,
|
||||
"isNew" BOOLEAN NOT NULL DEFAULT false,
|
||||
"category" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Waffle" ADD COLUMN "imageUrl" TEXT;
|
||||
@@ -0,0 +1,9 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "GalleryImage" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"imageUrl" TEXT NOT NULL,
|
||||
"alt" TEXT NOT NULL,
|
||||
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
@@ -0,0 +1,11 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "SiteContent" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"heroEyebrow" TEXT NOT NULL,
|
||||
"heroTitle" TEXT NOT NULL,
|
||||
"heroSubtitle" TEXT NOT NULL,
|
||||
"menuIntro" TEXT NOT NULL,
|
||||
"galleryIntro" TEXT NOT NULL,
|
||||
"hours" TEXT NOT NULL,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
@@ -0,0 +1,3 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "SiteContent" ADD COLUMN "heroBackgroundImageUrl" TEXT;
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Add configurable default upload image resolution.
|
||||
ALTER TABLE "SiteContent" ADD COLUMN "uploadImageWidth" INTEGER NOT NULL DEFAULT 1920;
|
||||
ALTER TABLE "SiteContent" ADD COLUMN "uploadImageHeight" INTEGER NOT NULL DEFAULT 1080;
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "SiteContent" ADD COLUMN "heroTextOverImage" BOOLEAN NOT NULL DEFAULT true;
|
||||
@@ -0,0 +1,16 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "SiteContent" ADD COLUMN "scheduleIntro" TEXT NOT NULL DEFAULT '';
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "TruckEvent" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"eventDate" TEXT NOT NULL,
|
||||
"timeLabel" TEXT NOT NULL DEFAULT '',
|
||||
"location" TEXT NOT NULL,
|
||||
"note" TEXT NOT NULL DEFAULT '',
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "TruckEvent_eventDate_idx" ON "TruckEvent"("eventDate");
|
||||
@@ -0,0 +1,14 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "TruckEventRecurrence" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"dayOfWeek" INTEGER NOT NULL,
|
||||
"timeLabel" TEXT NOT NULL DEFAULT '',
|
||||
"location" TEXT NOT NULL,
|
||||
"note" TEXT NOT NULL DEFAULT '',
|
||||
"active" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "TruckEventRecurrence_dayOfWeek_idx" ON "TruckEventRecurrence"("dayOfWeek");
|
||||
@@ -0,0 +1,23 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Ingredient" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"price" REAL NOT NULL,
|
||||
"imageUrl" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_IngredientToWaffle" (
|
||||
"A" TEXT NOT NULL,
|
||||
"B" TEXT NOT NULL,
|
||||
CONSTRAINT "_IngredientToWaffle_A_fkey" FOREIGN KEY ("A") REFERENCES "Ingredient" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "_IngredientToWaffle_B_fkey" FOREIGN KEY ("B") REFERENCES "Waffle" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "_IngredientToWaffle_AB_unique" ON "_IngredientToWaffle"("A", "B");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_IngredientToWaffle_B_index" ON "_IngredientToWaffle"("B");
|
||||
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "SiteContent" ADD COLUMN "logoUrl" TEXT;
|
||||
@@ -0,0 +1,6 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "SiteContent" ADD COLUMN "customWaffleTitle" TEXT NOT NULL DEFAULT 'La gaufre sur mesure';
|
||||
ALTER TABLE "SiteContent" ADD COLUMN "customWaffleDescription" TEXT NOT NULL DEFAULT 'Composez votre gaufre en choisissant parmi nos ingrédients : chacun avec sa photo et son prix.';
|
||||
ALTER TABLE "SiteContent" ADD COLUMN "customWaffleBasePrice" REAL NOT NULL DEFAULT 3;
|
||||
ALTER TABLE "SiteContent" ADD COLUMN "customWaffleImageUrl" TEXT;
|
||||
ALTER TABLE "SiteContent" ADD COLUMN "customWaffleVisible" BOOLEAN NOT NULL DEFAULT true;
|
||||
@@ -0,0 +1,3 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "TruckEvent" ADD COLUMN "imageUrl" TEXT;
|
||||
ALTER TABLE "TruckEventRecurrence" ADD COLUMN "imageUrl" TEXT;
|
||||
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (e.g., Git)
|
||||
provider = "sqlite"
|
||||
@@ -0,0 +1,105 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client"
|
||||
output = "../src/generated/prisma"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "sqlite"
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
email String @unique
|
||||
passwordHash String
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
model Ingredient {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
price Float
|
||||
imageUrl String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
waffles Waffle[]
|
||||
}
|
||||
|
||||
model Waffle {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
/** Description textuelle affichée sur la fiche menu. */
|
||||
ingredients String
|
||||
price Float
|
||||
isNew Boolean @default(false)
|
||||
category String
|
||||
imageUrl String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
ingredientItems Ingredient[]
|
||||
}
|
||||
|
||||
model GalleryImage {
|
||||
id String @id @default(cuid())
|
||||
imageUrl String
|
||||
alt String
|
||||
sortOrder Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
/** Une seule ligne (id = default) : textes affichés sur la page d’accueil et horaires. */
|
||||
model SiteContent {
|
||||
id String @id @default("default")
|
||||
heroEyebrow String
|
||||
heroTitle String
|
||||
heroSubtitle String
|
||||
heroBackgroundImageUrl String?
|
||||
/** Logo affiché dans l’en-tête du site public */
|
||||
logoUrl String?
|
||||
/** true : texte sur l’image (héros) ; false : image seule, texte au-dessus du menu */
|
||||
heroTextOverImage Boolean @default(true)
|
||||
menuIntro String
|
||||
galleryIntro String
|
||||
scheduleIntro String @default("")
|
||||
customWaffleTitle String @default("La gaufre sur mesure")
|
||||
customWaffleDescription String @default("Composez votre gaufre en choisissant parmi nos ingrédients : chacun avec sa photo et son prix.")
|
||||
customWaffleBasePrice Float @default(3)
|
||||
customWaffleImageUrl String?
|
||||
customWaffleVisible Boolean @default(true)
|
||||
uploadImageWidth Int @default(1920)
|
||||
uploadImageHeight Int @default(1080)
|
||||
hours Json
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
/** Présence du food truck (calendrier « Où me trouver »). */
|
||||
model TruckEvent {
|
||||
id String @id @default(cuid())
|
||||
eventDate String
|
||||
timeLabel String @default("")
|
||||
location String
|
||||
note String @default("")
|
||||
imageUrl String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([eventDate])
|
||||
}
|
||||
|
||||
/** Règle hebdomadaire : répétée chaque semaine (0 = lundi … 6 = dimanche). */
|
||||
model TruckEventRecurrence {
|
||||
id String @id @default(cuid())
|
||||
dayOfWeek Int
|
||||
timeLabel String @default("")
|
||||
location String
|
||||
note String @default("")
|
||||
imageUrl String?
|
||||
active Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([dayOfWeek])
|
||||
}
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
import "dotenv/config";
|
||||
import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3";
|
||||
import { PrismaClient } from "../src/generated/prisma/client";
|
||||
import { hashPassword } from "../src/lib/password";
|
||||
import { DEFAULT_PUBLIC_SITE_COPY } from "../src/lib/site-content-defaults";
|
||||
import { WAFFLE_CATEGORIES } from "../src/lib/constants";
|
||||
import { formatDateIso } from "../src/lib/week-calendar";
|
||||
|
||||
const url = process.env.DATABASE_URL ?? "file:./dev.db";
|
||||
const adapter = new PrismaBetterSqlite3({ url });
|
||||
const prisma = new PrismaClient({ adapter });
|
||||
|
||||
async function main() {
|
||||
const email =
|
||||
process.env.ADMIN_EMAIL?.trim().toLowerCase() || "admin@lagaufredor.local";
|
||||
const password = process.env.ADMIN_PASSWORD || "changeme123";
|
||||
|
||||
const existing = await prisma.user.findUnique({ where: { email } });
|
||||
if (!existing) {
|
||||
await prisma.user.create({
|
||||
data: {
|
||||
email,
|
||||
passwordHash: await hashPassword(password),
|
||||
},
|
||||
});
|
||||
console.log(
|
||||
`Compte admin créé : ${email} (mot de passe : variable ADMIN_PASSWORD ou défaut changeme123)`
|
||||
);
|
||||
}
|
||||
|
||||
const count = await prisma.waffle.count();
|
||||
if (count === 0) {
|
||||
await prisma.waffle.createMany({
|
||||
data: [
|
||||
{
|
||||
name: "Coco-Belge",
|
||||
ingredients:
|
||||
"Pâte Liège, perles de sucre, noix de coco râpée, touche de vanille Bourbon.",
|
||||
price: 6.5,
|
||||
isNew: true,
|
||||
category: WAFFLE_CATEGORIES.DU_MOIS,
|
||||
imageUrl: "/gallery/hero-coco.png",
|
||||
},
|
||||
{
|
||||
name: "Classique dorée",
|
||||
ingredients: "Sucre perlé, beurre AOP, sirop d’érable ou chocolat.",
|
||||
price: 5.9,
|
||||
isNew: false,
|
||||
category: WAFFLE_CATEGORIES.SUCREE,
|
||||
imageUrl: "/gallery/gaufres-sucrees.png",
|
||||
},
|
||||
{
|
||||
name: "Bubble chantilly",
|
||||
ingredients: "Bubble waffle, chantilly maison, copeaux de chocolat noir.",
|
||||
price: 7.2,
|
||||
isNew: false,
|
||||
category: WAFFLE_CATEGORIES.SUCREE,
|
||||
imageUrl: "/gallery/bubble-waffle.png",
|
||||
},
|
||||
{
|
||||
name: "Montagnarde",
|
||||
ingredients:
|
||||
"Pâte aux herbes, comté fondant, jambon cru, poivre noir concassé.",
|
||||
price: 8.5,
|
||||
isNew: false,
|
||||
category: WAFFLE_CATEGORIES.SALEE,
|
||||
imageUrl: "/gallery/gaufre-salee.png",
|
||||
},
|
||||
{
|
||||
name: "Bacon & ciboulette",
|
||||
ingredients: "Crème légère, bacon croustillant, ciboulette fraîche.",
|
||||
price: 7.9,
|
||||
isNew: false,
|
||||
category: WAFFLE_CATEGORIES.SALEE,
|
||||
imageUrl: "/gallery/gaufre-salee.png",
|
||||
},
|
||||
],
|
||||
});
|
||||
console.log("Gaufres d’exemple insérées.");
|
||||
}
|
||||
|
||||
const galleryCount = await prisma.galleryImage.count();
|
||||
if (galleryCount === 0) {
|
||||
await prisma.galleryImage.createMany({
|
||||
data: [
|
||||
{
|
||||
imageUrl: "/gallery/hero-coco.png",
|
||||
alt: "Gaufres belges caramélisées sur ardoise, noix de coco et drapeau belge.",
|
||||
sortOrder: 0,
|
||||
},
|
||||
{
|
||||
imageUrl: "/gallery/gaufres-sucrees.png",
|
||||
alt: "Stack de gaufres dorées, sucre glace et sirop.",
|
||||
sortOrder: 1,
|
||||
},
|
||||
{
|
||||
imageUrl: "/gallery/bubble-waffle.png",
|
||||
alt: "Bubble waffles en cornet, chantilly et chocolat.",
|
||||
sortOrder: 2,
|
||||
},
|
||||
{
|
||||
imageUrl: "/gallery/gaufre-salee.png",
|
||||
alt: "Gaufre salée aux herbes, crème, bacon et ciboulette.",
|
||||
sortOrder: 3,
|
||||
},
|
||||
],
|
||||
});
|
||||
console.log("Galerie d’exemple insérée.");
|
||||
}
|
||||
|
||||
await prisma.siteContent.upsert({
|
||||
where: { id: "default" },
|
||||
create: {
|
||||
id: "default",
|
||||
...DEFAULT_PUBLIC_SITE_COPY,
|
||||
},
|
||||
update: {},
|
||||
});
|
||||
|
||||
const truckCount = await prisma.truckEvent.count();
|
||||
if (truckCount === 0) {
|
||||
const start = new Date();
|
||||
const day = start.getDay();
|
||||
const diff = day === 0 ? -6 : 1 - day;
|
||||
start.setDate(start.getDate() + diff);
|
||||
|
||||
const dateAt = (offset: number) => {
|
||||
const d = new Date(start);
|
||||
d.setDate(start.getDate() + offset);
|
||||
return formatDateIso(d);
|
||||
};
|
||||
|
||||
await prisma.truckEvent.createMany({
|
||||
data: [
|
||||
{
|
||||
eventDate: dateAt(1),
|
||||
timeLabel: "9h — 13h",
|
||||
location: "Marché de Bagnols-sur-Cèze",
|
||||
note: "Place du marché",
|
||||
},
|
||||
{
|
||||
eventDate: dateAt(3),
|
||||
timeLabel: "11h — 19h",
|
||||
location: "Festival gourmand — Uzès",
|
||||
note: "",
|
||||
},
|
||||
{
|
||||
eventDate: dateAt(5),
|
||||
timeLabel: "10h — 18h",
|
||||
location: "Place de la République, Alès",
|
||||
note: "Food truck zone nord",
|
||||
},
|
||||
],
|
||||
});
|
||||
console.log("Événements food truck d’exemple insérés.");
|
||||
}
|
||||
|
||||
const recurCount = await prisma.truckEventRecurrence.count();
|
||||
if (recurCount === 0) {
|
||||
await prisma.truckEventRecurrence.create({
|
||||
data: {
|
||||
dayOfWeek: 1,
|
||||
timeLabel: "9h — 13h",
|
||||
location: "Marché hebdomadaire — Bagnols-sur-Cèze",
|
||||
note: "Place du marché",
|
||||
},
|
||||
});
|
||||
console.log("Récurrence food truck d’exemple insérée.");
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => prisma.$disconnect())
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
prisma.$disconnect();
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user