Registry : ajoute 2 plugins :
- theme-aquarelle (carnet naturaliste XIXᵉ, mutual exclusion avec theme-guyane)
- image-gallery-aquarelle-seed (14 aquarelles → MinIO + Media carbets démo)
Hooks :
- theme-guyane et theme-aquarelle se désactivent mutuellement au toggle ON
via disableOtherTheme()
CSS (globals.css) :
- body[data-theme=aquarelle] : background papier teinté #faf5e9 + texture
grain papier inline SVG + radial gradients ocres/canopy délavés
- Surcharges automatiques des borders zinc/gray vers sépia délavé
Layout :
- PT_Serif (au lieu de Cormorant) en theme aquarelle, plus dense et encrée
- data-theme = aquarelle prioritaire sur guyane si les deux sont enabled
(défensif — le hook garantit normalement la mutual exclusion)
Hero :
- 2 versions dans le composant : guyane (existant, SVG CarbetRiver) et
aquarelle (image MinIO 01-hero-fleuve-maroni.jpg en fond, voile crème,
texte sépia, CTAs carrés sans rounded, hairlines, ornement de planche)
- Branchement via getActiveTheme()
- aquarelleUrl() helper qui construit l'URL MinIO publique
Partie 2/2 (PR ultérieure) : upload des 14 images dans MinIO + hook
image-gallery-aquarelle-seed + variantes aquarelle des autres composants
(CarbetCard, ExperiencesSection, HowItWorksSection, CESection, Footer).
Migration : ContentPage.id devient PK composite (slug, lang) au lieu de slug
seul, pour stocker une version FR et une version EN du même slug. Index sur
slug seul pour les lookups.
Schema Prisma : @@id([slug, lang]).
Helpers :
- getContentPage(slug, lang) avec fallback FR si la version dans la langue
demandée n'existe pas
- listContentPages(category?, lang?) accepte un filtre lang
- upsertContentPage : utilise le composite key
Pages publiques (a-propos, faq, comment-ca-marche, pour-comites-entreprise,
devenir-loueur, cgv, mentions-legales, politique-de-confidentialite) :
ajoutent un appel à getLocale() et le passent à getContentPage.
Seeds :
- src/lib/plugins/seeds/content-pages-en.ts : 8 pages traduites en anglais
- hook onEnable du plugin i18n-fr-en : seed EN pages au toggle on. Désactiver
i18n n'efface pas les EN pages (elles dorment, fallback FR reprend).
Résultat : quand l'utilisateur switche vers EN, /a-propos, /faq, /cgv, etc.
basculent en anglais. Le contenu hors-DB (composants UI) bascule déjà via les
dictionnaires de la PR i18n-fr-en initiale.
Infrastructure i18n légère, sans deps externe :
- lib/i18n/types.ts : LOCALES, DEFAULT_LOCALE, cookie name
- lib/i18n/server.ts : getLocale (cookie > Accept-Language > FR),
t(key) async server-side, dict(locale)
- lib/i18n/client.tsx : LocaleProvider + useLocale + useT
- messages/fr.json + messages/en.json : ~50 clés pour landing + header + footer
- LocaleSwitcher component (cookie + router.refresh)
Plugin gated :
- Quand i18n-fr-en désactivé, getLocale() force FR. Le switcher ne s'affiche
pas dans le hero. Pas d'impact sur le rendu existant.
- Quand activé, switcher visible coin haut-droit du hero. Les composants
landing/header/footer rendent en FR ou EN selon le cookie utilisateur.
Composants i18n-isés :
- HeroSection (eyebrow, titre, CTA)
- ExperiencesSection (route/fleuve vs expédition, tous les bullets)
- HowItWorksSection (3 étapes)
- CESection (KPIs + body + CTA)
- TestimonialsSection (eyebrow + titre, citations restent en VO)
- Footer (taglines, colonnes)
- SeasonBanner (3 saisons + messages)
- AccessTypeBadge (labels + tooltips)
Pour les ContentPage, le champ lang existait déjà. Une suite (PR ultérieure)
ajoutera le filtre lang dans getContentPage + seed pages EN.
Sans ça, le layout est rendu statiquement au build et ne re-fetch jamais
l'état des plugins, donc les toggles depuis /admin/plugins ne prennent
jamais effet sur la home jusqu'à un nouveau build.
Le client Prisma est généré dans src/generated/prisma (cf. schema.prisma
output). Le post-install npm de deps stage le génère mais on n'embarque
que node_modules, pas le src/generated. Le builder doit donc régénérer
explicitement avant npm run build.
Le postinstall hook `prisma generate` du package.json a besoin de
prisma/schema.prisma pour s'exécuter. Sans ça, npm ci échoue dès l'étape deps.
Ajoute aussi prisma/ dans l'image runner pour pouvoir exécuter
`prisma migrate deploy` depuis l'app en prod.
Phase 2 visuals — la page d'accueil prend vie via 3 plugins activables :
- theme-guyane : palette tropicale (vert canopée, eau Maroni, ocre latérite,
bois karbé, blanc cassé), tokens CSS, typographie display Cormorant Garamond,
gradient ambient discret. Activé via body[data-theme=guyane].
- landing-hero : section plein écran avec illustration vectorielle SVG (carbet
sur pilotis au crépuscule + fleuve + jungle), claim 'Le karbé qui dort vous
attend', double CTA Découvrir / Proposer. Fallback = hero minimaliste actuel.
- landing-sections : 5 sections en cascade — 2 expériences (route+fleuve vs
expédition fleuve), Comment ça marche (3 étapes), CE (registre coop sans
commission), Témoignages (3 stubs), Footer riche avec navigation.
Illustrations 100% SVG inline (pas de dépendance image externe). Quand le
plugin image-gallery-seed sera activé (Phase 2.4), les photos remplaceront
progressivement les SVG. Aucune coupure sur le rendu actuel : tous les plugins
visuels sont disabled par défaut, le site garde son look minimaliste tant que
l'admin ne les a pas activés depuis /admin/plugins.
- Lib reviews: constants/types (client-safe) + DB helpers (server-only)
- API POST /api/bookings/[bookingId]/review : avis locataire après séjour COMPLETED
- API POST /api/reviews/[reviewId]/response : réponse loueur
- API GET /api/carbets/[carbetId]/reviews : liste + stats agrégées
- Fiche carbet : note moyenne + nombre d'avis + liste avec réponses loueur
- Carte carbet : étoiles + note moyenne + compteur
- /mes-reservations : formulaire d'avis pour les séjours terminés du locataire