feat(plugins): content-pages + legal-pages (Phase 4.1 + 4.3)

Plugin content-pages :
- Modèle Prisma ContentPage (slug PK, title, body markdown, category, published)
- lib/content-pages.ts : helpers upsert/get/list/unpublish
- lib/markdown.ts : mini-renderer markdown server-side sans deps externe
  (h1-h3, paragraphes, gras/italique, liens, listes ul/ol, hr, blockquote,
  échappement HTML)
- ContentPageRenderer server component, applique le theme Guyane (font-serif)
- 5 pages seedées : /a-propos, /faq, /comment-ca-marche,
  /pour-comites-entreprise, /devenir-loueur
- Routes publiques + force-dynamic + guard requirePluginOr404

Plugin legal-pages :
- Réutilise le même modèle ContentPage, catégorie 'legal'
- 3 pages seedées : /cgv, /mentions-legales, /politique-de-confidentialite
  (contenu de base, à valider par avocat avant prod réelle)

Admin :
- /admin/content-pages : table par catégorie, statut publié/dépublié
- /admin/content-pages/[slug] : éditeur markdown + toggle publié
- PATCH /api/admin/content-pages/[slug]

Hooks plugin :
- onEnable seed + republish toutes les pages
- onDisable dépublie toute la catégorie sans la supprimer (preserve les edits)
This commit is contained in:
Claude Integration 2026-05-31 10:12:13 +00:00
parent ae8f79b436
commit 68f37f554f
20 changed files with 1116 additions and 0 deletions

View file

@ -0,0 +1,16 @@
-- Plugin content-pages + legal-pages : table ContentPage
CREATE TABLE "ContentPage" (
"slug" TEXT PRIMARY KEY,
"title" TEXT NOT NULL,
"body" TEXT NOT NULL,
"lang" TEXT NOT NULL DEFAULT 'fr',
"category" TEXT NOT NULL DEFAULT 'general',
"published" BOOLEAN NOT NULL DEFAULT true,
"lastEditedBy" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL
);
CREATE INDEX "ContentPage_category_idx" ON "ContentPage" ("category");
CREATE INDEX "ContentPage_published_idx" ON "ContentPage" ("published");

View file

@ -280,3 +280,19 @@ model Plugin {
@@index([category])
@@index([enabled])
}
model ContentPage {
slug String @id
title String
body String
lang String @default("fr")
// 'general' (about, faq, ...) ou 'legal' (cgv, mentions, ...)
category String @default("general")
published Boolean @default(true)
lastEditedBy String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([category])
@@index([published])
}