Claude Integration
b59b8a0af2
feat(p1): calendrier dispo + emails Resend + amount calculé + best-effort welcome/confirmation/refund
2026-06-01 02:20:38 +00:00
4e14854245
Merge pull request 'feat(p0): pricing + booking + signup' ( #51 ) from feat/p0-pricing-booking-signup into main
2026-06-01 01:34:03 +00:00
Claude Integration
e79b6dd141
feat(p0): prix/nuit + booking form public + /inscription + /reservations/[id]
2026-06-01 01:34:00 +00:00
f09a680059
Merge pull request 'feat(admin): /admin/home — éditeur page d'accueil' ( #50 ) from feat/admin-home-editor into main
2026-06-01 01:10:51 +00:00
Claude Integration
a9fcd18022
feat(admin): /admin/home — éditeur des textes de la page d'accueil (FR+EN, override DB)
2026-06-01 01:10:49 +00:00
d3cc5bdfb9
Merge pull request 'fix(admin): PATCH content-pages respecte ?lang=' ( #49 ) from fix/admin-content-pages-patch-lang into main
2026-06-01 00:51:21 +00:00
Claude Integration
1f8dd90979
fix(admin): PATCH content-pages respecte ?lang= (sinon écrasait FR)
2026-06-01 00:51:19 +00:00
0244eb5029
Merge pull request 'fix(admin): content-pages multilang' ( #48 ) from fix/admin-content-pages-multilang into main
2026-06-01 00:49:32 +00:00
Claude Integration
a5ae692cf4
fix(admin): content-pages éditait FR quel que soit le lien cliqué — support multilang complet
2026-06-01 00:49:31 +00:00
c8c97e467d
Merge pull request 'feat(admin): Sprint 6 — Polish' ( #47 ) from feat/admin-sprint6-polish into main
2026-06-01 00:44:41 +00:00
Claude Integration
4e6867b365
feat(admin): Sprint 6 — /admin/media gallery + theme write-through
2026-06-01 00:44:39 +00:00
f9c10f151c
Merge pull request 'feat(admin): Sprint 5 — Gouvernance' ( #46 ) from feat/admin-sprint5-gouvernance into main
2026-06-01 00:13:51 +00:00
Claude Integration
79ddcd23f5
feat(admin): Sprint 5 — Audit log + Settings (gouvernance)
2026-06-01 00:13:49 +00:00
2ad4cbed80
Merge pull request 'feat(admin): Sprint 4 — Écosystème' ( #45 ) from feat/admin-sprint4-ecosysteme into main
2026-05-31 21:36:24 +00:00
Claude Integration
99f3bbdc71
feat(admin): Sprint 4 — Organisations CE + Prestataires pirogue (CRUD)
2026-05-31 21:36:22 +00:00
19b4ff8293
Merge pull request 'feat(admin): Sprint 3 — Activity' ( #44 ) from feat/admin-sprint3-activity into main
2026-05-31 21:20:48 +00:00
Claude Integration
d9ee072744
feat(admin): Sprint 3 — Réservations, Utilisateurs, Avis
2026-05-31 21:20:46 +00:00
8f31047b36
Merge pull request 'chore: prisma type + cleanup' ( #43 ) from chore/admin-carbets-prisma-where into main
2026-05-31 21:08:37 +00:00
Claude Integration
fea55a7ddb
chore(admin): Prisma.CarbetWhereInput type + cleanup options orphelines
2026-05-31 21:08:35 +00:00
00a5533bea
Merge pull request 'chore: split options client/server' ( #42 ) from chore/admin-carbet-options-split into main
2026-05-31 21:06:49 +00:00
Claude Integration
fc01144e0e
chore(admin): split options enum dans fichier neutre
...
Le client component CarbetForm importait des options depuis lib/admin/carbets
qui contient "server-only" → erreur build turbopack. Sortie des options dans
src/lib/admin/carbet-options.ts sans server-only.
2026-05-31 21:06:47 +00:00
820f7a821b
Merge pull request 'feat(admin): CRUD carbets + médias (Sprint 2)' ( #41 ) from feat/admin-carbets-crud into main
2026-05-31 21:04:56 +00:00
Claude Integration
9aa0771001
feat(admin): CRUD complet carbets + gestion médias (Sprint 2)
...
Server actions (src/app/admin/carbets/actions.ts) avec validation Zod :
- createCarbetAction → INSERT + audit + redirect /admin/carbets/[id]
- updateCarbetAction → UPDATE + revalidate page publique
- updateCarbetStatusAction → DRAFT/PUBLISHED/ARCHIVED
- deleteCarbetAction → soft archive (bookings/reviews FK Restrict)
- addMediaAction(carbetId, fd) → INSERT Media + sortOrder
- removeMediaAction, reorderMediaAction (transactionnel up/down)
Helpers (src/lib/admin/carbets.ts) :
- listCarbetsAdmin avec filtres (q/river/status/accessType)
- listDistinctRivers, listOwners, listPirogueProviders
- getCarbetForEdit (include owner, provider, media, _count bookings/reviews)
- Options enum pour les selects (ACCESS_TYPE, TRANSPORT_MODE, STATUS)
Pages :
- /admin/carbets : liste tableau dense avec recherche/filtres GET, status badge,
liens vers édition, count médias/résas
- /admin/carbets/new : page création avec CarbetForm
- /admin/carbets/[id] : header titre+badge+actions, MediaManager, CarbetForm
d'édition. Lien public si PUBLISHED.
Composants admin réutilisables :
- StatusBadge (DRAFT/PUBLISHED/ARCHIVED + statuts Booking)
- FormField + inputCls/selectCls/textareaCls
- CarbetForm (client, 5 sections : identité, localisation, accès, séjour,
publication) avec useTransition + erreur + succès inline
- MediaManager (client, liste + reorder ↑↓ + suppression + ajout par URL)
- StatusActions (client, publier/dépublier/archiver/réactiver avec confirm)
API :
- GET /api/admin/carbets/[id]/media pour refresh client après mutation
Audit léger en log console (JSON structuré) — Sprint 5 ajoutera la table.
2026-05-31 19:51:33 +00:00
3ec7a3ff10
Merge pull request 'feat(admin): shell + dashboard + ⌘K (Sprint 1)' ( #40 ) from feat/admin-shell-foundation into main
2026-05-31 18:22:08 +00:00
Claude Integration
bcb93c6b29
feat(admin): shell admin + dashboard KPI + recherche ⌘K (Sprint 1)
...
Layout admin :
- src/app/admin/layout.tsx : route protégée requireRole(ADMIN), sidebar + topbar + breadcrumbs, data-admin sur racine pour theme sobre indépendant du theme public
- Sidebar : 12 sections groupées (Vue d'ensemble, Catalogue, Activité, Membres, Contenu, Système), highlight de la route courante
- TopBar : prompt ⌘K, lien vers site public, email admin
- Breadcrumbs : auto depuis pathname
- CommandPalette : ⌘K / Ctrl K, navigation ↑↓ + Entrée, recherche live debounced 150ms
Dashboard :
- 7 KPI cards avec tone neutral/ok/warn/info (réservations semaine, confirmées 30j, revenus reversés, occupation, nouveaux users, carbets publiés, avis à modérer)
- Section raccourcis fréquents
Theme admin :
- globals.css : [data-admin] override le background+font, neutralise les borders sépia/papier teinté du theme aquarelle, garantit lisibilité permanente
Recherche globale :
- lib/admin/search.ts : query parallèle sur Carbet, User, Booking, ContentPage, PirogueProvider (5 résultats par catégorie, LIKE insensitive)
- api/admin/search?q=… route handler avec requireRole
KPI :
- lib/admin/kpis.ts : 7 métriques live (cache 0), Promise.all, helper formatEur
Pas de dépendance externe ajoutée (cmdk, shadcn) — composants custom Tailwind pour rester léger.
2026-05-31 18:21:50 +00:00
ffb39a3bf5
Merge pull request 'feat(plugin): aquarelle seed media + upload script' ( #39 ) from feat/aquarelle-seed-media into main
2026-05-31 12:20:56 +00:00
Claude Integration
47258bf1be
feat(plugin): image-gallery-aquarelle-seed hook + upload script
...
Hook onEnable du plugin image-gallery-aquarelle-seed :
- Pour chaque carbet démo, crée une entrée Media qui pointe vers son aquarelle
hébergée dans MinIO sous karbe-medias/seed/aquarelle/.
- s3Key préfixé seed/aquarelle/ pour faciliter le détachement au disable.
- Idempotent (skip si Media existe déjà).
Hook onDisable :
- Supprime tous les Media avec s3Key startsWith seed/aquarelle/.
- Les fichiers MinIO restent (pas de coût de redéploiement).
Script scripts/upload-aquarelles.sh :
- Upload depuis /tmp/karbe-aquarelles/*.{jpg,png} vers le bucket karbe-medias.
- Applique la policy public-download au bucket pour que media.karbe.cosmolan.fr
serve les fichiers sans auth.
- À exécuter une fois après génération des illustrations.
2026-05-31 12:20:35 +00:00
93aebc4e87
Merge pull request 'feat(plugin): theme-aquarelle + hero' ( #38 ) from feat/theme-aquarelle into main
2026-05-31 12:15:30 +00:00
Claude Integration
c69c355f90
feat(plugin): theme-aquarelle + hero variant (Phase 2.4 partie 1/2)
...
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).
2026-05-31 12:15:07 +00:00
bb2fee7659
Merge pull request 'chore(admin): findUnique composite key' ( #37 ) from chore/admin-content-composite-key into main
2026-05-31 11:48:16 +00:00
Claude Integration
8196a1a3f9
chore(admin): adapter findUnique/update à la PK composite (slug, lang)
...
Admin édite la version FR par défaut. Édition multi-langues = future feature.
2026-05-31 11:48:14 +00:00
df9eb5fcbd
Merge pull request 'feat: pages contenu bilingues' ( #36 ) from feat/i18n-content-pages into main
2026-05-31 11:45:49 +00:00
Claude Integration
87c3e7a581
feat: ContentPage bilingue (PK composite slug+lang) + seed pages EN
...
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.
2026-05-31 11:45:47 +00:00
88a937f2fd
Merge pull request 'feat(plugin): i18n FR + EN' ( #35 ) from feat/i18n-fr-en into main
2026-05-31 11:38:41 +00:00
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