From 19d9afd2b4da771e923d20261e8142d7b14525e5 Mon Sep 17 00:00:00 2001 From: jessy-david-dev Date: Fri, 10 Apr 2026 22:48:15 +0200 Subject: [PATCH] feat: add 404 page, migrate to UUID v7, and consolidate DB --- app/not-found.tsx | 36 ++++++++++++ lib/generated/prisma/internal/class.ts | 2 +- lib/prisma.ts | 2 +- prisma.config.ts | 2 +- .../20260410132623_init/migration.sql | 29 ---------- .../migration.sql | 30 ++++++++++ prisma/schema.prisma | 54 +++++++++--------- wikirace.db | Bin 65536 -> 0 bytes 8 files changed, 95 insertions(+), 60 deletions(-) create mode 100644 app/not-found.tsx delete mode 100644 prisma/migrations/20260410132623_init/migration.sql rename prisma/migrations/{20260410193825_add_daily_blitz => 20260410204435_init}/migration.sql (54%) delete mode 100644 wikirace.db diff --git a/app/not-found.tsx b/app/not-found.tsx new file mode 100644 index 0000000..5defe82 --- /dev/null +++ b/app/not-found.tsx @@ -0,0 +1,36 @@ +import type { Metadata } from "next"; +import Link from "next/link"; + +export const metadata: Metadata = { + title: "Page introuvable - WikiRush", + description: "Cette page n'existe pas.", +}; + +export default function NotFound() { + return ( +
+
+
+ 404 +

Page introuvable

+

+ Cet article n'existe pas sur WikiRush. +
+ Tu t'es peut-être perdu en chemin ? +

+
+ + + + Retour à l'accueil + +
+
+ ); +} diff --git a/lib/generated/prisma/internal/class.ts b/lib/generated/prisma/internal/class.ts index eadcbd7..6b3d3cc 100644 --- a/lib/generated/prisma/internal/class.ts +++ b/lib/generated/prisma/internal/class.ts @@ -20,7 +20,7 @@ const config: runtime.GetPrismaClientConfig = { "clientVersion": "7.7.0", "engineVersion": "75cbdc1eb7150937890ad5465d861175c6624711", "activeProvider": "sqlite", - "inlineSchema": "generator client {\n provider = \"prisma-client\"\n output = \"../lib/generated/prisma\"\n}\n\ndatasource db {\n provider = \"sqlite\"\n}\n\nmodel User {\n id String @id @default(cuid())\n name String\n email String @unique\n password String\n createdAt DateTime @default(now())\n games Game[]\n dailyResults DailyResult[]\n}\n\nmodel Game {\n id String @id @default(cuid())\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n mode String // \"solo\" | \"multi\" | \"daily\" | \"blitz\"\n startArticle String\n targetArticle String\n path String // JSON array de titres\n clicks Int\n timeSeconds Float\n won Boolean @default(true)\n playedAt DateTime @default(now())\n\n @@index([userId])\n}\n\nmodel DailyPuzzle {\n id String @id @default(cuid())\n date String @unique // \"YYYY-MM-DD\"\n startArticle String\n targetArticle String\n results DailyResult[]\n}\n\nmodel DailyResult {\n id String @id @default(cuid())\n puzzleId String\n puzzle DailyPuzzle @relation(fields: [puzzleId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n path String // JSON\n clicks Int\n timeSeconds Float\n won Boolean\n playedAt DateTime @default(now())\n\n @@unique([puzzleId, userId])\n @@index([puzzleId])\n}\n", + "inlineSchema": "generator client {\n provider = \"prisma-client\"\n output = \"../lib/generated/prisma\"\n}\n\ndatasource db {\n provider = \"sqlite\"\n}\n\nmodel User {\n id String @id @default(uuid(7))\n name String\n email String @unique\n password String\n createdAt DateTime @default(now())\n games Game[]\n dailyResults DailyResult[]\n}\n\nmodel Game {\n id String @id @default(uuid(7))\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n mode String // \"solo\" | \"multi\" | \"daily\" | \"blitz\"\n startArticle String\n targetArticle String\n path String // JSON array de titres\n clicks Int\n timeSeconds Float\n won Boolean @default(true)\n playedAt DateTime @default(now())\n\n @@index([userId])\n}\n\nmodel DailyPuzzle {\n id String @id @default(uuid(7))\n date String @unique // \"YYYY-MM-DD\"\n startArticle String\n targetArticle String\n results DailyResult[]\n}\n\nmodel DailyResult {\n id String @id @default(uuid(7))\n puzzleId String\n puzzle DailyPuzzle @relation(fields: [puzzleId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n path String // JSON\n clicks Int\n timeSeconds Float\n won Boolean\n playedAt DateTime @default(now())\n\n @@unique([puzzleId, userId])\n @@index([puzzleId])\n}\n", "runtimeDataModel": { "models": {}, "enums": {}, diff --git a/lib/prisma.ts b/lib/prisma.ts index 29d983e..d91d8bc 100644 --- a/lib/prisma.ts +++ b/lib/prisma.ts @@ -5,7 +5,7 @@ import { PrismaClient } from "./generated/prisma/client"; const globalForPrisma = globalThis as unknown as { prisma?: PrismaClient }; function createPrisma() { - const adapter = new PrismaBetterSqlite3({ url: "./wikirace.db" }); + const adapter = new PrismaBetterSqlite3({ url: "./wikirush.db" }); return new PrismaClient({ adapter }); } diff --git a/prisma.config.ts b/prisma.config.ts index cfa2f83..9bfb773 100644 --- a/prisma.config.ts +++ b/prisma.config.ts @@ -4,7 +4,7 @@ const config = { path: "prisma/migrations", }, datasource: { - url: "file:./wikirace.db", + url: "file:./wikirush.db", }, }; diff --git a/prisma/migrations/20260410132623_init/migration.sql b/prisma/migrations/20260410132623_init/migration.sql deleted file mode 100644 index a33e961..0000000 --- a/prisma/migrations/20260410132623_init/migration.sql +++ /dev/null @@ -1,29 +0,0 @@ --- CreateTable -CREATE TABLE "User" ( - "id" TEXT NOT NULL PRIMARY KEY, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "password" TEXT NOT NULL, - "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP -); - --- CreateTable -CREATE TABLE "Game" ( - "id" TEXT NOT NULL PRIMARY KEY, - "userId" TEXT NOT NULL, - "mode" TEXT NOT NULL, - "startArticle" TEXT NOT NULL, - "targetArticle" TEXT NOT NULL, - "path" TEXT NOT NULL, - "clicks" INTEGER NOT NULL, - "timeSeconds" REAL NOT NULL, - "won" BOOLEAN NOT NULL DEFAULT true, - "playedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT "Game_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE -); - --- CreateIndex -CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); - --- CreateIndex -CREATE INDEX "Game_userId_idx" ON "Game"("userId"); diff --git a/prisma/migrations/20260410193825_add_daily_blitz/migration.sql b/prisma/migrations/20260410204435_init/migration.sql similarity index 54% rename from prisma/migrations/20260410193825_add_daily_blitz/migration.sql rename to prisma/migrations/20260410204435_init/migration.sql index e22938c..cb0e8cd 100644 --- a/prisma/migrations/20260410193825_add_daily_blitz/migration.sql +++ b/prisma/migrations/20260410204435_init/migration.sql @@ -1,3 +1,27 @@ +-- CreateTable +CREATE TABLE "User" ( + "id" TEXT NOT NULL PRIMARY KEY, + "name" TEXT NOT NULL, + "email" TEXT NOT NULL, + "password" TEXT NOT NULL, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +-- CreateTable +CREATE TABLE "Game" ( + "id" TEXT NOT NULL PRIMARY KEY, + "userId" TEXT NOT NULL, + "mode" TEXT NOT NULL, + "startArticle" TEXT NOT NULL, + "targetArticle" TEXT NOT NULL, + "path" TEXT NOT NULL, + "clicks" INTEGER NOT NULL, + "timeSeconds" REAL NOT NULL, + "won" BOOLEAN NOT NULL DEFAULT true, + "playedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "Game_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + -- CreateTable CREATE TABLE "DailyPuzzle" ( "id" TEXT NOT NULL PRIMARY KEY, @@ -20,6 +44,12 @@ CREATE TABLE "DailyResult" ( CONSTRAINT "DailyResult_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE ); +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); + +-- CreateIndex +CREATE INDEX "Game_userId_idx" ON "Game"("userId"); + -- CreateIndex CREATE UNIQUE INDEX "DailyPuzzle_date_key" ON "DailyPuzzle"("date"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index c792f3f..bc5b462 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -7,36 +7,34 @@ datasource db { provider = "sqlite" } - - model User { - id String @id @default(cuid()) - name String - email String @unique - password String - createdAt DateTime @default(now()) + id String @id @default(uuid(7)) + name String + email String @unique + password String + createdAt DateTime @default(now()) games Game[] dailyResults DailyResult[] } model Game { - id String @id @default(cuid()) - userId String - user User @relation(fields: [userId], references: [id], onDelete: Cascade) - mode String // "solo" | "multi" | "daily" | "blitz" - startArticle String + id String @id @default(uuid(7)) + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + mode String // "solo" | "multi" | "daily" | "blitz" + startArticle String targetArticle String - path String // JSON array de titres - clicks Int - timeSeconds Float - won Boolean @default(true) - playedAt DateTime @default(now()) + path String // JSON array de titres + clicks Int + timeSeconds Float + won Boolean @default(true) + playedAt DateTime @default(now()) @@index([userId]) } model DailyPuzzle { - id String @id @default(cuid()) + id String @id @default(uuid(7)) date String @unique // "YYYY-MM-DD" startArticle String targetArticle String @@ -44,16 +42,16 @@ model DailyPuzzle { } model DailyResult { - id String @id @default(cuid()) - puzzleId String - puzzle DailyPuzzle @relation(fields: [puzzleId], references: [id], onDelete: Cascade) - userId String - user User @relation(fields: [userId], references: [id], onDelete: Cascade) - path String // JSON - clicks Int - timeSeconds Float - won Boolean - playedAt DateTime @default(now()) + id String @id @default(uuid(7)) + puzzleId String + puzzle DailyPuzzle @relation(fields: [puzzleId], references: [id], onDelete: Cascade) + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + path String // JSON + clicks Int + timeSeconds Float + won Boolean + playedAt DateTime @default(now()) @@unique([puzzleId, userId]) @@index([puzzleId]) diff --git a/wikirace.db b/wikirace.db deleted file mode 100644 index b23aee2c55521143c1a7504530eceb92c1eff1ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65536 zcmeI5U2NOd6~`qz{%jnzD-3Px2Cz(q#7O0mqCPzoiX$tjTU&N)X-yks0!3chtR+$* zsl;+IV6ON1us!r`55tCGK#>B&9tP}T0}2er1{8bP%hv5>PkmUi#||9|3#!55QI=D^c3w+(%#u7 z>EJ}?gx>=KZPvU>qq(zFV~cvF=`x4j zwpgnt`N{lRVZKxl%EiSi<$|zSTqs->#2$e``9)!+*e4{O6Fb$2&k16?CUM3)H5Pq= zl$t(XDO2xNHWFxaCp9R?9qXU5r^cd5s`crET33Ar6iz_Qjh56#)v_?&BF@4?>g#|LR(&BQVD|D9CBEf(fq()~1^eIuM0Vv)_?UOUf zlcUka)8UYB$?lCBeVVDLP0#kvD?Qd#k$X<2cJmXyLB6?sV36&``%>-0$pHr0C3Now z=?{T{2IqRJqx zO&t7mqJNG#B+(w_{2~qSPA`_nMx!&+;Wzvuc`sI2on}}*mGHCifpbW|T)SL;jmq_N z)4UNH8H-L&hrg@&-NY;9`)Gg1_`2NB6w#zg77tG)!C0=_`Z0a+V7(O--}wK|G2I!& zbDFH9!o!(xIQ5R-L;aYJ3edECFy--^@uAJXE%)4wyEn1G>aJ|u&QcXy|o^y z(w_m2=yiwtw$^kUW_cC<0f92t8$oqyqfs-dAlG9Jx1!li%WrAt<3+i+PWS7=LYHB8 z7)z5g`JvJ1EAnvz;%LWJ=ovO-uJgsP%jH0MX7FRNcqNn5pQ>1KMm6c37o?vPsm8>SK2|24K^lJFW z+y8jx4{<4;k`l5cXO&DmSy6SJ+$rQ`s#NKz^o}p{qur^nubRSDOJ$U*lGU=YjGB>S z35CUDSzVT5OwtocIiczaBbhSPOj^pQiY7~1Hj_xiQ}L{tO0udfB^4=|uBNgHMM|KZ41i2ksF00@8p2!H?x zfB*=900@8p2!H?xJUD^f&xOZw(d6#PWvyiTBZTs5{f#<@1s>CrRA@AC7zwqCadP00JNY z0w4eaAOHd&00JNY0w4eak1v5Q4d*6~ed56V|HDswBXmlidV}7ufdB}A00@8p2!H?x zfB*=5S_Jmq7(SWHMZc2!_C|PY!gmYqB)yjIdj-iYm@#hd+-y-yvg7=Pb&6hVUTkWu zSdGP&Y-?jxbyVHnW`fRK+MC+~vkcYp+-qX5nE0G{$x$th(ZMnWB;3DE(Z9_bP3F>t zRmZNXRg-?Rynovj&QVHFy0Cw{M$#11Of?{t1aN|d3u1$0^>{cXo=LwTK`aFGL0 zLXq9l?0VI&iDGeD!e!ObEeb=~C*}$~ik@v*CUbmD2PO2Q7OzJx?7eh;=;Y#WdR?!H zIZ2*NCTA1zY}@s^YYb8EPoIBg_j;%ITN`T4px%#jr|=ESaMH?l`qlvkI;k`3P0Q5U zp$-L2wMdv*7IRlzO?3iut5ab$)+9UBHmPk?2-(PnN$qFX#D`HCA*E)`{{ET2KmWy__VjX{344=* zCrFlI*zui|P6yt>&-}k;o7=)U({eqh$s={lEZfbSJlcn#HfcElyUr*oh|mu0fcXCp zp=(eC2!H?xfB*=900@8p2!H?xfB*2;GGZ&uB<#Kz|;jwYPe1=!O;g~yoSpn`Dw=xaY-P+nX)@9Bk>a_-a zEB=~z#D`Ad_*eNd3AC;Ttu1hq)_^eEOJML={M}^|x(D3l&bag46--OtzujP#PU~=( zu15uQz3)_LF<1n{bbHt?%!>{a!eABTT`?vi?8E9<*TEk%3ZdWT_pSZw2 z-v0A{|MlyGF9ww4>|B!8p-9grl0EVN!;udt{{LsRi=h?>fB*=900@8p2!H?xfB*=9 z00@A}1iJqJK~V$S|Np-iioAE1QjiP+ jAOHd&00JNY0w4eaAOHd&00JQJ=n14w