Commit graph

63 commits

Author SHA1 Message Date
Claude Integration
cf9da94bb5 feat(plugin): i18n FR + EN (Phase 4.2)
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.
2026-05-31 11:38:39 +00:00
efeea16467 Merge pull request 'feat(plugin): pirogue-providers' (#34) from feat/pirogue-providers into main 2026-05-31 11:29:32 +00:00
Claude Integration
a174f99eba feat(plugin): pirogue-providers (Phase 3.3)
Modèle PirogueProvider (id, name, contacts, fleuves, tarif, description)
+ enum TransportMode (OWNER_PROVIDES, SELF_ARRANGE, PARTNER_PROVIDER) sur Carbet
+ relation Carbet → PirogueProvider (nullable, ondelete:SetNull)

Composants :
- PirogueTransportBlock (server, gated par plugin) sur fiche carbet :
  affiche le mode + provider partenaire avec contacts/tarif/description
- Page publique /partenaires-pirogue : liste des partenaires actifs

Seed onEnable :
- 3 partenaires démo (Pirogues du Maroni, Approuague Aventures, Oyapock Frontière)
  avec tarifs estimatifs et fleuves desservis réels
- Attribution aux 6 carbets démo :
  · Awara (Maroni), Maripa (Approuague), Paripou (Oyapock) → PARTNER_PROVIDER
  · Wapa (Comté), Mahury CE → OWNER_PROVIDES
  · Kourou Couleuvre → SELF_ARRANGE

onDisable désactive les partenaires démo et détache les carbets démo.
2026-05-31 11:29:29 +00:00
8c0b849ad7 Merge pull request 'feat(plugins): content-pages + legal-pages' (#33) from feat/content-pages-and-legal into main 2026-05-31 10:12:28 +00:00
Claude Integration
68f37f554f 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)
2026-05-31 10:12:13 +00:00
ae8f79b436 Merge pull request 'chore: wire StayConstraints' (#32) from chore/wire-stay-constraints into main 2026-05-31 08:59:48 +00:00
Claude Integration
a7761ca323 chore: wire StayConstraints + minStayNights dans carbet-card + search (oubli PR#30) 2026-05-31 08:59:46 +00:00
fdf66bfc74 Merge pull request 'chore(prisma): champs Carbet min-stay + seasonality' (#31) from chore/schema-min-stay-seasonality into main 2026-05-31 08:52:48 +00:00
Claude Integration
3405f00476 chore(prisma): ajoute minStayNights/maxStayNights/minCapacity/seasonalConstraints au modèle Carbet (oubli PR#30) 2026-05-31 08:52:46 +00:00
32410c95c7 Merge pull request 'feat(plugins): seasonality + min-stay' (#30) from feat/seasonality-and-min-stay into main 2026-05-31 08:50:28 +00:00
Claude Integration
be2391998d feat(plugins): seasonality + min-stay (Phase 3.2 + 3.4)
Plugin seasonality :
- Migration : Carbet.seasonalConstraints JSONB nullable
- lib/seasonality.ts : enum Season (DRY|LOW_WATER|WET), currentSeason() helper
  Guyane (juil-sept sèche, oct-nov étiage, déc-juin pluies), parseSeasonalConstraints,
  isCurrentlyOpen, SEASON_META (label/emoji/tone)
- Composant <SeasonBanner /> server, gated par plugin, ajouté dans layout
  au-dessus de tout le contenu — bandeau couleur+emoji+message contextuel

Plugin min-stay :
- Migration : Carbet.minStayNights, maxStayNights, minCapacity nullable
- Composant <StayConstraints /> client, gated par plugin — pill text
  '2 nuits minimum', '2-7 nuits', 'groupe 4+ recommandé'
- Carbet card et fiche enrichies avec les contraintes

Tous deux désactivables : sans le toggle, comportement legacy inchangé.
2026-05-31 08:50:26 +00:00
4842a44746 Merge pull request 'chore(prisma): enum AccessType' (#29) from chore/access-type-enum-v2 into main 2026-05-31 03:00:54 +00:00
Claude Integration
bc571b38d1 chore(prisma): déclare enum AccessType (oublié dans PR#27) 2026-05-31 03:00:52 +00:00
35080dcde1 Merge pull request 'feat(plugins): access-type + demo-carbets-seed' (#27) from feat/access-type-and-demo-carbets into main 2026-05-31 02:56:41 +00:00
Claude Integration
5e59202505 feat(plugins): access-type + demo-carbets-seed (Phase 3.1 + 2.5)
Plugin access-type :
- Migration : enum AccessType (ROAD_AND_RIVER, RIVER_ONLY), champ accessType
  sur Carbet avec default ROAD_AND_RIVER, roadAccessNote optionnel,
  pirogueDurationMin rendu nullable + index sur accessType
- Schema Prisma mis à jour
- Composant <AccessTypeBadge> client, gated par le plugin
- Carbet card et fiche enrichies : badge + texte adapté (Pirogue vs Route+pirogue
  vs Route directe), section Accès enrichie avec roadAccessNote
- formatPirogueDuration accepte null

Plugin demo-carbets-seed :
- Hook onEnable : 3 propriétaires demo (Yann/Émilie/CE Hôpital) + 6 carbets
  variés (Maroni, Approuague, Comté, Oyapock, Mahury, Kourou) avec mix
  3 RIVER_ONLY + 3 ROAD_AND_RIVER, GPS plausibles, descriptions naturelles
- Hook onDisable : archive (status=ARCHIVED) les carbets demo via slug prefix
- Toutes les fixtures idempotentes (upsert via slug + email)
2026-05-31 02:56:25 +00:00
9b9963403d Merge pull request 'chore(layout): force-dynamic' (#26) from chore/layout-dynamic into main 2026-05-30 23:36:44 +00:00
Claude Integration
049d0bb423 chore(layout): force-dynamic pour refléter l'état des plugins en live
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.
2026-05-30 23:36:42 +00:00
de9f73246b Merge pull request 'chore(sitemap): force dynamic' (#25) from chore/sitemap-runtime into main 2026-05-30 23:32:09 +00:00
Claude Integration
b1c2877e43 chore(sitemap): force dynamic + try/catch DB
Évite que le build échoue quand la DB n'est pas joignable au prerender.
2026-05-30 23:32:07 +00:00
dc05fe118b Merge pull request 'chore(plugins): cast config en Prisma.InputJsonValue' (#24) from chore/plugin-json-type into main 2026-05-30 23:30:25 +00:00
Claude Integration
e433ebc439 chore(plugins): cast config en Prisma.InputJsonValue
Le type Record<string,unknown> ne satisfait pas le narrowing JSON Prisma.
Cast explicite pour faire passer le build TS.
2026-05-30 23:30:12 +00:00
1868b36379 Merge pull request 'chore(docker): npx prisma generate dans builder' (#23) from chore/dockerfile-prisma-generate-builder into main
Merge PR#23
2026-05-30 23:28:30 +00:00
Claude Integration
26922329d4 chore(docker): npx prisma generate dans builder stage
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.
2026-05-30 23:28:19 +00:00
d3ce396b20 Merge pull request 'chore(docker): copier prisma/ avant npm ci' (#22) from chore/dockerfile-prisma-copy into main
Merge PR#22: fix Dockerfile prisma copy
2026-05-30 23:25:44 +00:00
Claude Integration
a564373a07 chore(docker): copier prisma/ avant npm ci + dans runner
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.
2026-05-30 23:25:32 +00:00
800a06afc6 Merge pull request 'chore: sync package-lock.json' (#21) from chore/lockfile-sync into main
Merge PR#21: sync lockfile
2026-05-30 23:22:38 +00:00
Claude Integration
abc3844af2 chore: sync package-lock.json (qs@6.15.2 missing) 2026-05-30 23:22:25 +00:00
b4617545d0 Merge pull request 'feat(plugins): visuels Phase 2 (theme-guyane, landing-hero, landing-sections)' (#19) from feat/plugins-visuals-phase2 into main
Merge PR#19: plugins visuels Phase 2
2026-05-30 23:19:42 +00:00
Claude Integration
d19701e275 feat(plugins-visuels): theme-guyane + landing-hero + landing-sections
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.
2026-05-30 23:19:24 +00:00
4454f7331d Merge pull request 'feat(plugins): foundation système Plugin Karbé' (#18) from feat/plugin-foundation into main
Merge PR#18: plugin foundation
2026-05-30 22:17:27 +00:00
Claude Integration
62cc464738 feat(plugins): foundation système Plugin Karbé
- Modèle Prisma Plugin (key, name, description, category, version, enabled,
  config JSONB, migrationsApplied, timestamps) + migration SQL
- PluginRegistry (src/lib/plugins/registry.ts) avec 12 plugins déclarés :
  visuels (theme-guyane, landing-hero, landing-sections, image-gallery-seed,
  demo-carbets-seed), métier (access-type, seasonality, pirogue-providers,
  min-stay), contenus (content-pages, legal-pages), i18n (i18n-fr-en)
- Server helpers (server.ts) : sync, isEnabled, getEnabledKeys, toggle avec
  hooks onEnable/onDisable, updateConfig, cache 5s
- Client bridge (client.tsx) : PluginProvider + useIsPluginEnabled
- Composant <IfPluginEnabled plugin=... fallback=...>
- Guard requirePluginOr404 pour pages et routes
- Page admin /admin/plugins avec table toggle par catégorie + édition config
- Route PATCH /api/admin/plugins/[key] + GET
- Layout async qui sync registry + passe enabledKeys au PluginProvider

Tous plugins en enabled=false par défaut, activation pilotée depuis l'admin.
2026-05-30 22:17:10 +00:00
d7de43a70e Merge pull request 'SYS-19: Compléter docker-compose.prod.yml avec Postgres et MinIO co-déployés' (#17) from feat/sys-19-prod-compose-postgres-minio into main
Merge PR#17: postgres + minio co-déployés (SYS-19)
2026-05-30 18:39:12 +00:00
6898649898 feat(prod): co-deploy postgres and minio in production compose 2026-05-30 18:36:38 +00:00
b8d14d8f9d Merge pull request 'SYS-18 Déployer Karbé sur karbe.cosmolan.fr (MVP, Stripe TEST)' (#16) from feat/sys-18-deploy-karbe-mvp-stripe-test into main
Merge PR#16: deployment stack (Dockerfile + Caddy + .env). À compléter avec Postgres+MinIO co-déployés via SYS-19.
2026-05-30 18:35:07 +00:00
c9be24a969 SYS-18: add production deployment stack for karbe.cosmolan.fr (Stripe test)
- enable Next.js standalone output and add Docker/Caddy production stack
- add production env template and deployment runbook
- add healthcheck endpoint for container supervision
- fix existing lint/type blockers discovered during validation

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-30 18:01:56 +00:00
0a366c65db Merge pull request 'SYS-17 Ajouter lastBookedAt au modèle Carbet + endpoint' (#15) from feat/carbet-last-booked into main
Merge PR#15: lastBookedAt + endpoint (SYS-17, test autonomie v3)
2026-05-30 17:55:18 +00:00
fcc2749d1d feat(carbet): add lastBookedAt and endpoint 2026-05-30 17:52:41 +00:00
8d36f7008f Avis & notes — SYS-8 (#12)
Closes SYS-8.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-30 15:12:52 +00:00
Karbé Frontend
7515981336 feat(reviews): avis & notes carbet (SYS-8)
- 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
2026-05-30 15:08:55 +00:00
f0d6cdf46c Merge pull request 'feat(payment): intégration Stripe' (#11) from feat/payment-stripe into main
Merge PR#11: paiement Stripe
2026-05-30 15:01:11 +00:00
Claude Integration
74f39293cc feat(payment): intégration Stripe (subscription loueur + booking checkout + webhook) 2026-05-30 15:00:21 +00:00
eb398fe3f5 Merge pull request 'Réservation : API bookings + availability (récup workspace Backend)' (#10) from feat/booking into main
Merge PR#10: réservation (booking + availability)
2026-05-30 14:43:48 +00:00
Claude Integration
0de034022a feat(booking): API réservation + availability + lib métier
Récupéré du workspace Backend (3 fichiers, 406 lignes) :
- src/lib/booking.ts : logique métier réservation
- src/app/api/bookings/route.ts : POST/GET bookings
- src/app/api/carbets/[carbetId]/availability/route.ts : calendrier dispo

Le schéma Booking/Availability était déjà dans main.
2026-05-30 14:42:29 +00:00
9f3eda8bb4 Merge pull request 'fix(build): app global-error fallback pour Next 16 prerender' (#9) from fix/sys-12-global-error-v2 into main
Merge fix Next 16 global-error fallback
2026-05-30 10:50:39 +00:00
6985396db5 fix(build): add app global-error fallback for Next 16 prerender 2026-05-30 04:42:21 +00:00
ba0494611b Carbets publics — recherche + fiche SSR (SYS-5) (#8)
Implémente SYS-5 : page /carbets (recherche SSR + filtres river/dates/capacité) et /carbets/[slug] (fiche SSR avec generateMetadata OG/Twitter, galerie, équipements, accès), plus SEO sitewide (robots.ts, sitemap.xml, metadataBase, title.template).

Reviewed-by: Karbé Architect <karbe-architect@cosmolan.fr>
2026-05-29 22:28:29 +00:00
Karbé Architect
c2df6722f2 feat(carbets): public search + carbet detail page (SSR/SEO)
Implémente SYS-5 : la marketplace publique pour découvrir les carbets
fluviaux publiés par les hôtes.

- /carbets : page de recherche server-side avec filtres GET
  (fleuve, dates de séjour, capacité min.), grille de résultats
  avec photo de couverture, fleuve, capacité, durée pirogue
- /carbets/[slug] : fiche carbet SSR
  - generateMetadata (title/description + OpenGraph/Twitter cards)
  - galerie médias (photo couverture + vignettes vidéo/photo)
  - description, équipements (catalogue), accès, coords GPS,
    capacité, prénom de l'hôte
- robots.ts + sitemap.xml (incluant les carbets publiés)
- metadataBase / title.template au niveau du root layout, OG par
  défaut Karbé
- Lien "Découvrir les carbets" sur la home
- Helpers partagés : lib/carbet-search.ts (parse filters + query),
  lib/carbet-public.ts (fetch SSR mémoïsé via React cache),
  lib/format.ts (durée pirogue, troncature, coords)
- Nouvelle variable d'env NEXT_PUBLIC_SITE_URL (canonical/OG/sitemap)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-29 22:24:25 +00:00
3567eb975b Merge pull request 'CRUD Carbet (propriétaire) + pages connexion/espace-hote' (#7) from feat/owner-carbet-crud into main
Merge PR#7: CRUD Carbet + interface propriétaire
2026-05-29 22:14:58 +00:00
d5d2ad2228 Merge main into feat/owner-carbet-crud (integrate SYS-2 schema + SYS-3 auth)
main now contains the Prisma schema (SYS-2) and NextAuth (SYS-3) that the
owner carbet CRUD depends on. Integrating them so the branch compiles and
the PR is cleanly mergeable.

- package.json: union of S3 SDK (@aws-sdk/client-s3) + auth deps.
- No source conflicts; espace-hote "Gérer mes carbets" link already in main.
- Verified: tsc --noEmit OK, next build OK (all carbet + auth routes compile).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-29 21:33:57 +00:00
4f0b434f70 Merge pull request 'Auth multi-rôles (NextAuth) — sur base schéma propre' (#6) from feat/auth into main
Merge PR#6: auth multi-rôles NextAuth
2026-05-29 21:26:32 +00:00