- README enrichi (présentation Karbé, fonctionnalités, setup dev, env, structure, conventions Git) - ROADMAP.md : phases MVP -> V2 -> V3 - docs/ARCHITECTURE.md : stack, modèle de données (Prisma) et flux principaux Co-Authored-By: Paperclip <noreply@paperclip.ing>
12 KiB
Architecture — Karbé
Ce document décrit l'architecture technique de Karbé, la marketplace de location de carbets fluviaux de Guyane : la stack, le modèle de données et les flux principaux.
Sommaire
- Vue d'ensemble
- Stack technique
- Organisation du code
- Modèle de données
- Flux principaux
- Sécurité & conformité
Vue d'ensemble
Karbé est une application Next.js (App Router) full-stack : le même projet sert le rendu des pages (React Server Components + Client Components) et expose la logique serveur (route handlers, server actions). La persistance est assurée par PostgreSQL via Prisma. L'authentification repose sur NextAuth, et les paiements sur Stripe.
┌─────────────────────────────────────────────┐
Navigateur │ Next.js (App Router) │
(voyageur / │ │
hôte / admin)│ React Server / Client Components │
│ │ Route handlers / Server actions │
│ HTTPS │ │ │ │
└───────▶│ NextAuth Prisma Client │
│ (sessions, (requêtes) │
│ rôles) │ │
└─────────────────────────────────┼─────────────┘
│
┌────────────────────────┼───────────────┐
▼ ▼ ▼
PostgreSQL Stripe Stockage
(données) (paiements) médias (photos)
Note de version : ce dépôt utilise une version récente de Next.js dont certaines API peuvent différer de la documentation publique. La référence embarquée se trouve dans
node_modules/next/dist/docs/.
Stack technique
| Couche | Technologie | Rôle |
|---|---|---|
| Framework | Next.js 16 (App Router) | Rendu SSR/RSC, routing, logique serveur. |
| UI | React 19 + Tailwind CSS v4 | Composants et styles. |
| Langage | TypeScript | Typage statique de bout en bout. |
| ORM | Prisma 7 | Accès aux données, migrations, typage. Client généré dans src/generated/prisma. |
| Base de données | PostgreSQL | Persistance relationnelle. |
| Authentification | NextAuth | Sessions et contrôle d'accès par rôle. |
| Paiement | Stripe | Encaissement réservations + abonnement loueur. |
| Lint | ESLint (eslint-config-next) |
Qualité de code. |
Organisation du code
src/
├── app/ # App Router : pages, layouts, route handlers
│ ├── layout.tsx # Layout racine
│ ├── page.tsx # Page d'accueil
│ └── globals.css # Styles globaux (Tailwind)
└── generated/prisma/ # Client Prisma généré (NE PAS éditer à la main)
prisma/
├── schema.prisma # Source de vérité du modèle de données
└── migrations/ # Migrations SQL
Principes :
- App Router — chaque dossier de
src/appest un segment de route. Les pages sont des Server Components par défaut ; on bascule en Client Component ("use client") seulement pour l'interactivité. - Accès données côté serveur — les requêtes Prisma s'exécutent côté serveur (Server Components, route handlers, server actions), jamais dans le navigateur.
- Client Prisma généré — importé depuis
src/generated/prisma; il est régénéré vianpx prisma generate(scriptpostinstall).
Modèle de données
Le modèle est défini dans prisma/schema.prisma et
porté par PostgreSQL. Il couvre cinq grands domaines : comptes, offre
(carbets), réservation, paiement et relation (messagerie & avis).
Énumérations
| Enum | Valeurs |
|---|---|
UserRole |
TRAVELER, HOST, ADMIN |
CarbetStatus |
DRAFT, PUBLISHED, ARCHIVED |
BookingStatus |
PENDING, CONFIRMED, CANCELLED, COMPLETED |
PaymentStatus |
PENDING, AUTHORIZED, SUCCEEDED, FAILED, REFUNDED |
MessageSenderType |
TRAVELER, HOST, SYSTEM |
Schéma relationnel
erDiagram
User ||--o| HostProfile : "a (si hôte)"
User ||--o{ Booking : "réserve"
User ||--o{ Review : "rédige"
User ||--o{ FavoriteCarbet : "favoris"
HostProfile ||--o{ Carbet : "publie"
Carbet ||--o{ CarbetPhoto : "photos"
Carbet ||--o{ CarbetAvailability : "disponibilités"
Carbet ||--o{ Booking : "réservations"
Carbet ||--o{ Review : "avis"
Carbet ||--o{ FavoriteCarbet : "favoris"
Carbet }o--o{ Amenity : "équipements (CarbetAmenity)"
Booking ||--o{ Payment : "paiements"
Booking ||--o| Conversation : "fil de discussion"
Booking ||--o| Review : "avis"
Conversation ||--o{ Message : "messages"
Entités principales
Comptes
User— compte unique pour tous les rôles (role:TRAVELER,HOST,ADMIN). Champs clés :email(unique),passwordHash,firstName,lastName,phone?,avatarUrl?,isActive. Relations : un éventuelHostProfile, sesbookings, sesreviews, sesfavoriteCarbets, et ses conversations (en tant que voyageur ou hôte).HostProfile— profil hôte en 1:1 avecUser(relation optionnelle : seuls les hôtes en ont un). Contientbio?,verificationAt?(date de vérification),payoutInfo?(infos de versement) et la liste descarbets.
Offre (carbets)
Carbet— l'annonce. Champs :title,slug(unique, pour le SEO),description, localisation (river,locality,latitude?,longitude?), capacité (maxGuests,bedrooms,beds,bathrooms), tarification (basePricePerNight,cleaningFee,serviceFee),status(DRAFT/PUBLISHED/ARCHIVED) etpublishedAt?. Indexé par hôte, statut, (fleuve, localité) et prix pour la recherche.Amenity/CarbetAmenity— catalogue d'équipements et table de liaison N:N entre carbets et équipements (clé composite[carbetId, amenityId]).CarbetPhoto— photos d'un carbet (url,alt?,sortOrder).CarbetAvailability— calendrier : une ligne pardateet par carbet (@@unique([carbetId, date])), avecisAvailable,customPrice?(tarif spécifique) etminNights(séjour minimum).
Réservation
Booking— réservation reliant unCarbetet unUser(voyageur). Champs :checkIn,checkOut,guests,status, instantané de tarification (nightlyRate,cleaningFee,serviceFee,totalAmount,currency=EUR),notes?, et champs d'annulation (canceledAt?,cancellationReason?). Les suppressions de carbet/voyageur sont enRestrictpour préserver l'historique des réservations.
Paiement
Payment— un ou plusieurs paiements rattachés à uneBooking. Champs :provider,providerPaymentId?(unique, ex. id Stripe),amount,currency,status(PENDING→AUTHORIZED→SUCCEEDED/FAILED,REFUNDED),paidAt?,refundedAt?et détails d'échec (failureCode?,failureMessage?).
Relation : messagerie & avis
Conversation— un fil 1:1 avec uneBooking, reliant le voyageur (travelerId) et l'hôte (hostId).Message— message d'une conversation (senderType:TRAVELER,HOSTouSYSTEM,senderUserId?,content,sentAt,readAt?).Review— avis 1:1 avec uneBooking(un avis par séjour), portant unerating, untitle?et uncomment?, rattaché au carbet et au voyageur.FavoriteCarbet— table de liaison N:N (wishlist) entreUseretCarbet(clé composite[userId, carbetId]).
Conventions
- Identifiants :
cuid()(chaînes) en clé primaire. - Horodatage :
createdAt/updatedAtsur la plupart des entités. - Montants :
Decimal(10,2)pour les prix,Decimal(9,6)pour les coordonnées GPS. - Suppressions :
Cascadepour les données dépendantes (photos, messages, disponibilités) ;Restrictpour préserver l'historique financier (réservations, paiements, avis). - Index : posés sur les colonnes de recherche/jointure fréquentes (statut, fleuve+localité, prix, dates, clés étrangères).
Flux principaux
1. Authentification & rôles
sequenceDiagram
actor U as Utilisateur
participant App as Next.js
participant Auth as NextAuth
participant DB as PostgreSQL
U->>App: Inscription / Connexion (email + mot de passe)
App->>Auth: Vérifie les identifiants
Auth->>DB: Lit User (passwordHash, role, isActive)
Auth-->>App: Session (id + role)
App-->>U: Accès adapté au rôle (TRAVELER / HOST / ADMIN)
Le role porté par la session conditionne l'accès : espace voyageur, interface
hôte (gestion des carbets), ou back-office admin.
2. Publication d'un carbet (hôte)
- Un
Userde rôleHOST(avecHostProfile) crée unCarbetenDRAFT. - Il ajoute des
CarbetPhoto, sélectionne desAmenity(viaCarbetAmenity) et renseigne le calendrierCarbetAvailability(dates, prix, nuits min). - Il publie :
statuspasse àPUBLISHEDetpublishedAtest renseigné. Le carbet devient visible dans la recherche publique.
3. Recherche & consultation (public, SSR/SEO)
- La page de listing interroge les
CarbetenPUBLISHED(filtres : fleuve, localité, capacité, prix…), rendue côté serveur pour l'indexation. - La fiche carbet est servie via son
slugunique (URL stable, SEO-friendly) et affiche photos, équipements, disponibilités et avis.
4. Réservation & paiement
sequenceDiagram
actor V as Voyageur
participant App as Next.js
participant DB as PostgreSQL
participant Stripe as Stripe
V->>App: Choisit des dates + nombre de voyageurs
App->>DB: Vérifie CarbetAvailability (dispo + minNights)
App->>App: Calcule le total (nuitées, ménage, frais de service)
App->>DB: Crée Booking (status = PENDING)
V->>App: Procède au paiement
App->>Stripe: Crée l'intention de paiement
Stripe-->>App: Webhook / callback (succès ou échec)
alt Paiement réussi
App->>DB: Payment = SUCCEEDED, Booking = CONFIRMED
App-->>V: Confirmation de réservation
else Paiement échoué
App->>DB: Payment = FAILED, Booking reste PENDING
App-->>V: Échec, nouvelle tentative possible
end
À l'issue du séjour, la Booking passe en COMPLETED. Une annulation renseigne
canceledAt/cancellationReason et peut déclencher un REFUNDED côté
Payment.
5. Messagerie
À la création d'une réservation, une Conversation (1:1 avec la Booking) est
ouverte entre le voyageur et l'hôte. Les Message portent un senderType
(TRAVELER, HOST, SYSTEM pour les notifications automatiques) et un statut
de lecture (readAt).
6. Avis
Après un séjour COMPLETED, le voyageur peut déposer un Review (un seul par
réservation, contrainte d'unicité sur bookingId). La note alimente la
réputation du carbet affichée sur sa fiche.
Sécurité & conformité
- Mots de passe stockés hachés (
passwordHash), jamais en clair. - Secrets (
AUTH_SECRET/NEXTAUTH_SECRET, clés Stripe,DATABASE_URL) en variables d'environnement, hors du dépôt (voir.env.example). - Contrôle d'accès par rôle (
UserRole) appliqué côté serveur. - Intégrité financière : suppressions en
Restrictsur les réservations, paiements et avis pour conserver l'historique. - RGPD & mentions légales : pages dédiées (CGV, politique de confidentialité, mentions légales) — voir la roadmap.