Commit graph

5 commits

Author SHA1 Message Date
Ubuntu
18d19538d3 feat(ce): Sprint P — seed démo CE + tests invites + cleanup helper
All checks were successful
CI / test (pull_request) Successful in 2m40s
Seed plugin `demo-ce-seed` :
- Nouveau descriptor dans registry (category visual).
- src/lib/plugins/seeds/demo-ce.ts : seedDemoCe() + archiveDemoCe().
  Crée org « Comité ESA Kourou (démo) » approved=true + 2 CE_MANAGERs
  + 3 CE_MEMBERs (password "demo") + 2 carbets co-gérés
  (OrganizationCarbetMembership) + 1 RentalProvider org-scoped +
  4 items (hamac, moustiquaire, kayak, réchaud).
- Idempotent : check existence par slug/email avant create. Upsert
  pour users.
- Disable : soft-archive carbets (status=ARCHIVED), delete
  RentalProvider démo (best-effort si pas de booking), delete users
  démo (cascade memberships) + delete org.
- Branchement hooks onEnable/onDisable dans plugins/hooks.ts.

Permet de visualiser le module CE end-to-end sans signup manuel :
admin active le plugin → l'org démo et son écosystème apparaissent
sur le site (badge « Géré par le CE Comité ESA Kourou (démo) » sur
les fiches carbet, items rental dans le catalogue /materiel).

ce-invites.ts refactor :
- Exporte hashToken (déjà sha256, désormais documenté).
- Extrait isInviteValid(row, now=Date) : helper pur testable. La
  fonction getOrgInviteByToken le réutilise.

tests/lib/ce-invites.test.ts (9 cas) :
- hashToken : déterminisme, format sha256 64-hex, inputs différents,
  pas de fuite du plain.
- isInviteValid : non consommé+non expiré → vrai ; consommé → faux ;
  expiré → faux ; les 2 raisons → faux ; injection now pour tests
  temporels.

Total tests : 83/83 ✓ (74 précédents + 9 nouveaux).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-03 03:13:14 +00:00
Ubuntu
946dd8d5d2 feat(ce): Sprint G — data model + admin validation
All checks were successful
CI / test (pull_request) Successful in 2m38s
Schema:
- Organization gagne le workflow d'approbation (approved + approvedAt +
  approvedBy + contactEmail). Backfill : toutes les orgs existantes
  (CMCK) → approved=true via migration.
- Nouveau OrganizationCarbetMembership (manyToMany Org↔Carbet) pour la
  co-gestion CE : un Carbet a un ownerId (créateur initial) + 0..n
  memberships ; chaque CE_MANAGER d'une org liée peut gérer le carbet
  en plus de l'owner. Pour un hôte individuel = pas de membership.
- RentalProvider.organizationId (nullable, SetNull on delete) : un CE
  peut posséder son provider ; les CE_MANAGERs membres de l'org y ont
  accès en plus du manager nominal.

Plugin ce-management ajouté au registry (catégorie business, off par
défaut). Quand off : signup CE caché + dashboard /espace-ce 404.

Admin organizations :
- Tab statut (Toutes / À valider [count] / Validées) avec compteur des
  organisations pending dans l'en-tête.
- Badge statut sur la liste et la page détail.
- Bouton « Valider l'organisation » sur le détail (action
  approveOrganizationAction → flip approved=true + approvedAt + audit
  log organization.approve). Idempotent : un re-appel sur une org déjà
  validée ne re-loggue pas.
- Détail montre les compteurs carbetMemberships + rentalProviders.

Migration appliquée à la DB prod (CMCK backfill validé).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 22:55:54 +00:00
Ubuntu
5607a51980 feat(rental): Sprint E — emails + plugin toggle + tests
Some checks failed
CI / test (pull_request) Failing after 1m10s
3 nouveaux templates email (best-effort, dry-run sans Resend) :
- sendRentalRequestedTenant : récap de demande au locataire (par RB)
- sendRentalRequestedProvider : nouvelle demande au prestataire
- sendRentalConfirmed : confirmation paiement reçu

Branchements :
- POST /api/rentals/checkout : envoie tenant + provider après création
  des RentalBooking (PENDING), catch global pour ne pas bloquer
- Webhook Stripe rental-bundle : envoie sendRentalConfirmed à chaque
  locataire après update CONFIRMED+SUCCEEDED

Plugin gear-rental :
- Ajout au registry (catégorie business)
- layout.tsx /materiel + /espace-prestataire avec requirePluginOr404
- requirePluginOr404 dans /panier et /mes-locations
- isPluginEnabled guard dans POST /api/rentals/checkout (404 si off)
- SiteHeader masque liens Matériel / Mes locations / Espace prestataire
  + CartBadge si plugin désactivé
- CompleteYourStay renvoie null si plugin désactivé
Décision admin → activable depuis /admin/plugins comme tous les autres.

Tests vitest (tests/lib/rentals.test.ts, 16 tests) :
- diffDays (mêmes dates, 1 nuit, 7 jours, négatif)
- parseCart (null/garbage/schéma invalide/valide/format date)
- serializeCart (updatedAt, roundtrip)
- commission formula (0%, 15%, arrondi centime)
- availability arithmetic (totalQty libre, soustractions, plancher 0)

53 tests pass total. Build OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 08:49:39 +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
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