karbe/docs/ARCHITECTURE.md
Karbé Architect f9310c380f docs: README, roadmap produit et doc d'architecture
- 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>
2026-05-29 04:42:28 +00:00

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.

  • Pour démarrer le projet, voir le README.
  • Pour la trajectoire produit, voir la roadmap.

Sommaire

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/app est 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é via npx prisma generate (script postinstall).

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 éventuel HostProfile, ses bookings, ses reviews, ses favoriteCarbets, et ses conversations (en tant que voyageur ou hôte).
  • HostProfile — profil hôte en 1:1 avec User (relation optionnelle : seuls les hôtes en ont un). Contient bio?, verificationAt? (date de vérification), payoutInfo? (infos de versement) et la liste des carbets.

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) et publishedAt?. 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 par date et par carbet (@@unique([carbetId, date])), avec isAvailable, customPrice? (tarif spécifique) et minNights (séjour minimum).

Réservation

  • Booking — réservation reliant un Carbet et un User (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 en Restrict pour préserver l'historique des réservations.

Paiement

  • Payment — un ou plusieurs paiements rattachés à une Booking. Champs : provider, providerPaymentId? (unique, ex. id Stripe), amount, currency, status (PENDINGAUTHORIZEDSUCCEEDED/FAILED, REFUNDED), paidAt?, refundedAt? et détails d'échec (failureCode?, failureMessage?).

Relation : messagerie & avis

  • Conversation — un fil 1:1 avec une Booking, reliant le voyageur (travelerId) et l'hôte (hostId).
  • Message — message d'une conversation (senderType : TRAVELER, HOST ou SYSTEM, senderUserId?, content, sentAt, readAt?).
  • Review — avis 1:1 avec une Booking (un avis par séjour), portant une rating, un title? et un comment?, rattaché au carbet et au voyageur.
  • FavoriteCarbet — table de liaison N:N (wishlist) entre User et Carbet (clé composite [userId, carbetId]).

Conventions

  • Identifiants : cuid() (chaînes) en clé primaire.
  • Horodatage : createdAt / updatedAt sur la plupart des entités.
  • Montants : Decimal(10,2) pour les prix, Decimal(9,6) pour les coordonnées GPS.
  • Suppressions : Cascade pour les données dépendantes (photos, messages, disponibilités) ; Restrict pour 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)

  1. Un User de rôle HOST (avec HostProfile) crée un Carbet en DRAFT.
  2. Il ajoute des CarbetPhoto, sélectionne des Amenity (via CarbetAmenity) et renseigne le calendrier CarbetAvailability (dates, prix, nuits min).
  3. Il publie : status passe à PUBLISHED et publishedAt est renseigné. Le carbet devient visible dans la recherche publique.

3. Recherche & consultation (public, SSR/SEO)

  1. La page de listing interroge les Carbet en PUBLISHED (filtres : fleuve, localité, capacité, prix…), rendue côté serveur pour l'indexation.
  2. La fiche carbet est servie via son slug unique (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 Restrict sur 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.