Outils pour utilisateurs

Outils du site


ujusum:3-codage:1-repository:2-prisma-schema

Ceci est une ancienne révision du document !


Table des matières

Phase 2 — Prisma Schema

Objectif

Construire le schéma Prisma qui deviendra la source de vérité unique du système.

À partir de ce schéma seront générés :

  • PostgreSQL
  • Prisma Client
  • DTO
  • Entités NestJS
  • OpenAPI
  • SDK TypeScript
  • Migrations SQL

Le schéma doit refléter l'intégralité des domaines définis dans les 20 sprints.


Objectifs techniques

Le schéma Prisma doit supporter :

Multi-tenant

Audit

Historisation

Soft Delete

RBAC

CRM

Catalogue

Réservations

Paiements

Contrats

OTA

IA

Revenue Management

Internationalisation

Sécurité Enterprise

Ordre de construction recommandé

Ne jamais commencer par les 80 tables.

Construire par couches.


Couche 1 — Fondations

Construire en premier :

Tenant

User

Role

Permission

UserRole

RolePermission

Ces tables sont nécessaires partout.


Couche 2 — Référentiels

Créer :

Address

Country

Language

Currency

Timezone

Couche 3 — Catalogue

Créer :

Property

PropertyType

PropertyMedia

PropertyFeature

PropertyAvailability

PropertyRate

Couche 4 — Réservations

Créer :

Reservation

ReservationGuest

ReservationStatus

ReservationEvent

Couche 5 — Contrats

Créer :

Contract

ContractTemplate

ContractSignature

Document

Couche 6 — Paiements

Créer :

Payment

Invoice

Refund

AccountingEntry

Couche 7 — CRM

Créer :

Lead

Customer

Activity

Task

Pipeline

Couche 8 — Propriétaires

Créer :

Owner

OwnerProperty

OwnerDocument

Couche 9 — Notifications

Créer :

Notification

NotificationTemplate

Message

Campaign

Couche 10 — Administration

Créer :

AuditLog

FeatureFlag

CustomField

Workflow

Couche 11 — IA

Créer :

AiConversation

AiMessage

KnowledgeDocument

AutomationRule

Couche 12 — OTA

Créer :

Channel

ChannelConnection

PropertyDistribution

ChannelReservation

Couche 13 — Revenue Management

Créer :

PricingRule

DynamicPrice

RevenueSimulation

CompetitorSnapshot

Couche 14 — Sécurité

Créer :

Consent

SecurityPolicy

Risk

ComplianceAudit

Couche 15 — Internationalisation

Créer :

Translation

CurrencyRate

Region

EnterpriseLicense

Organisation du dossier Prisma

Au lieu d'un unique fichier géant :

prisma/

├── schema.prisma
│
├── models/
│
│   ├── tenant.prisma
│   ├── user.prisma
│   ├── property.prisma
│   ├── reservation.prisma
│   ├── contract.prisma
│   ├── payment.prisma
│   ├── crm.prisma
│   ├── owner.prisma
│   ├── notification.prisma
│   ├── audit.prisma
│   ├── ai.prisma
│   ├── channel.prisma
│   ├── revenue.prisma
│   ├── security.prisma
│   └── localization.prisma

Configuration initiale

schema.prisma

Version minimale :

generator client {
  provider = "prisma-client-js"
}
 
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

Première implémentation

Étape 1

Créer :

prisma/models/tenant.prisma

Tenant

model Tenant {
 
  id            String   @id @default(uuid())
 
  code          String   @unique
 
  name          String
 
  status        TenantStatus
 
  createdAt     DateTime @default(now())
 
  updatedAt     DateTime @updatedAt
 
  users         User[]
 
  properties    Property[]
 
}

Enum

enum TenantStatus {
 
  ACTIVE
 
  SUSPENDED
 
  TRIAL
 
  ARCHIVED
}

Étape 2

Créer :

prisma/models/user.prisma

User

model User {
 
  id              String @id @default(uuid())
 
  tenantId        String
 
  email           String @unique
 
  passwordHash    String
 
  firstName       String
 
  lastName        String
 
  active          Boolean @default(true)
 
  createdAt       DateTime @default(now())
 
  updatedAt       DateTime @updatedAt
 
  tenant          Tenant @relation(
                    fields:[tenantId],
                    references:[id]
                  )
 
  roles           UserRole[]
 
}

Role

model Role {
 
  id            String @id @default(uuid())
 
  code          String @unique
 
  name          String
 
  userRoles     UserRole[]
 
  permissions   RolePermission[]
}

Permission

model Permission {
 
  id            String @id @default(uuid())
 
  code          String @unique
 
  name          String
 
  rolePermissions RolePermission[]
}

UserRole

model UserRole {
 
  userId        String
 
  roleId        String
 
  assignedAt    DateTime @default(now())
 
  user          User @relation(
                  fields:[userId],
                  references:[id]
                )
 
  role          Role @relation(
                  fields:[roleId],
                  references:[id]
                )
 
  @@id([userId, roleId])
}

RolePermission

model RolePermission {
 
  roleId        String
 
  permissionId  String
 
  role          Role @relation(
                  fields:[roleId],
                  references:[id]
                )
 
  permission    Permission @relation(
                  fields:[permissionId],
                  references:[id]
                )
 
  @@id([roleId, permissionId])
}

Génération

Après chaque bloc important :

npx prisma format

Validation

npx prisma validate

Génération Client

npx prisma generate

Migration

npx prisma migrate dev \
--name init_security

Vérification

Ouvrir :

npx prisma studio

Vérifier la présence :

Tenant

User

Role

Permission

UserRole

RolePermission

Phase 2-A — Fondation complète (Tenant + RBAC + Propriétés de sécurité)

Vous avez raison.

La version précédente contient :

  • Tenant
  • User
  • Role
  • Permission
  • UserRole
  • RolePermission

mais il manque plusieurs éléments indispensables pour un véritable système Enterprise :

  • propriétés du compte utilisateur
  • préférences utilisateur
  • sessions
  • refresh tokens
  • MFA
  • audit de connexion
  • catalogue complet des permissions

Sans ces éléments, le Sprint 1 (Authentification) et le Sprint 19 (Sécurité Enterprise) ne pourront pas être implémentés proprement.


Modèle User complet

User

model User {
 
  id                String      @id @default(uuid())
 
  tenantId          String
 
  email             String      @unique
 
  passwordHash      String
 
  firstName         String
 
  lastName          String
 
  phone             String?
 
  avatarUrl         String?
 
  languageCode      String?
 
  timezoneCode      String?
 
  active            Boolean     @default(true)
 
  emailVerified     Boolean     @default(false)
 
  lastLoginAt       DateTime?
 
  createdAt         DateTime    @default(now())
 
  updatedAt         DateTime    @updatedAt
 
  deletedAt         DateTime?
 
  tenant            Tenant      @relation(
                                  fields:[tenantId],
                                  references:[id]
                                )
 
  roles             UserRole[]
 
  sessions          UserSession[]
 
  refreshTokens     RefreshToken[]
 
  preferences       UserPreference?
 
  loginHistory      LoginHistory[]
 
  mfaMethods        UserMfaMethod[]
}

Préférences utilisateur

UserPreference

model UserPreference {
 
  id                String      @id @default(uuid())
 
  userId            String      @unique
 
  theme             String?
 
  language          String?
 
  timezone          String?
 
  notifications     Json?
 
  createdAt         DateTime    @default(now())
 
  updatedAt         DateTime    @updatedAt
 
  user              User @relation(
                        fields:[userId],
                        references:[id]
                      )
}

Gestion des sessions

UserSession

model UserSession {
 
  id                String      @id @default(uuid())
 
  userId            String
 
  ipAddress         String?
 
  userAgent         String?
 
  country           String?
 
  city              String?
 
  lastActivityAt    DateTime
 
  expiresAt         DateTime
 
  revokedAt         DateTime?
 
  createdAt         DateTime    @default(now())
 
  user              User @relation(
                        fields:[userId],
                        references:[id]
                      )
}

Refresh Tokens

RefreshToken

model RefreshToken {
 
  id                String      @id @default(uuid())
 
  userId            String
 
  tokenHash         String
 
  expiresAt         DateTime
 
  revokedAt         DateTime?
 
  createdAt         DateTime    @default(now())
 
  user              User @relation(
                        fields:[userId],
                        references:[id]
                      )
}

Historique des connexions

LoginHistory

model LoginHistory {
 
  id                String      @id @default(uuid())
 
  userId            String
 
  success           Boolean
 
  ipAddress         String?
 
  userAgent         String?
 
  country           String?
 
  city              String?
 
  createdAt         DateTime @default(now())
 
  user              User @relation(
                        fields:[userId],
                        references:[id]
                      )
}

MFA

UserMfaMethod

model UserMfaMethod {
 
  id                String      @id @default(uuid())
 
  userId            String
 
  methodType        String
 
  secret            String?
 
  enabled           Boolean     @default(true)
 
  createdAt         DateTime    @default(now())
 
  user              User @relation(
                        fields:[userId],
                        references:[id]
                      )
}

RBAC Enterprise

Role

model Role {
 
  id                String      @id @default(uuid())
 
  code              String      @unique
 
  name              String
 
  description       String?
 
  systemRole        Boolean     @default(false)
 
  createdAt         DateTime    @default(now())
 
  updatedAt         DateTime    @updatedAt
 
  userRoles         UserRole[]
 
  permissions       RolePermission[]
}

Permission

model Permission {
 
  id                String      @id @default(uuid())
 
  code              String      @unique
 
  name              String
 
  description       String?
 
  module            String
 
  createdAt         DateTime    @default(now())
 
  rolePermissions   RolePermission[]
}

Catalogue initial des permissions

Auth

AUTH_LOGIN

AUTH_REGISTER

AUTH_RESET_PASSWORD

AUTH_MANAGE_USERS

Users

USER_READ

USER_CREATE

USER_UPDATE

USER_DELETE

Properties

PROPERTY_READ

PROPERTY_CREATE

PROPERTY_UPDATE

PROPERTY_DELETE

PROPERTY_PUBLISH

Reservations

RESERVATION_READ

RESERVATION_CREATE

RESERVATION_UPDATE

RESERVATION_CANCEL

Contracts

CONTRACT_READ

CONTRACT_CREATE

CONTRACT_SIGN

Payments

PAYMENT_READ

PAYMENT_CREATE

PAYMENT_REFUND

CRM

CRM_READ

CRM_WRITE

CRM_EXPORT

Administration

ADMIN_READ

ADMIN_WRITE

ADMIN_AUDIT

ADMIN_TENANT

Rôles système

SUPER_ADMIN

Accès complet plateforme.


TENANT_ADMIN

Administration d'agence.


AGENCY_MANAGER

Gestion opérationnelle.


OWNER

Extranet propriétaire.


AGENT

Collaborateur.


CUSTOMER

Client final.


Indexes recommandés

User

@@index([tenantId])
 
@@index([email])
 
@@index([active])

LoginHistory

@@index([userId])
 
@@index([createdAt])

UserSession

@@index([userId])
 
@@index([expiresAt])

Architecture du domaine Property

Entités

Property

PropertyType

PropertyStatus

PropertyAddress

PropertyFeature

PropertyMedia

PropertyAvailability

PropertyRate

PropertyOwner

Property

Table principale

model Property {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  propertyTypeId        String
 
  code                  String @unique
 
  reference             String?
 
  title                 String
 
  slug                  String @unique
 
  description           String?
 
  shortDescription      String?
 
  maxGuests             Int
 
  bedrooms              Int
 
  bathrooms             Int
 
  area                  Decimal? @db.Decimal(10,2)
 
  floor                 Int?
 
  constructionYear      Int?
 
  checkInTime           String?
 
  checkOutTime          String?
 
  active                Boolean @default(true)
 
  published             Boolean @default(false)
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  deletedAt             DateTime?
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  propertyType          PropertyType @relation(
                            fields:[propertyTypeId],
                            references:[id]
                         )
 
  address               PropertyAddress?
 
  features              PropertyFeature[]
 
  media                 PropertyMedia[]
 
  availabilities        PropertyAvailability[]
 
  rates                 PropertyRate[]
 
  owners                PropertyOwner[]
 
  reservations         Reservation[]
 
}

PropertyType

Référentiel

model PropertyType {
 
  id                String @id @default(uuid())
 
  code              String @unique
 
  name              String
 
  properties        Property[]
}

Valeurs

HOUSE

APARTMENT

VILLA

STUDIO

LOFT

CHALET

COTTAGE

MOBILE_HOME

PropertyAddress

Adresse du bien

model PropertyAddress {
 
  id                String @id @default(uuid())
 
  propertyId        String @unique
 
  addressLine1      String
 
  addressLine2      String?
 
  postalCode        String
 
  city              String
 
  state             String?
 
  countryCode       String
 
  latitude          Decimal? @db.Decimal(10,7)
 
  longitude         Decimal? @db.Decimal(10,7)
 
  property          Property @relation(
                      fields:[propertyId],
                      references:[id]
                    )
}

PropertyFeature

Équipements

model PropertyFeature {
 
  id                String @id @default(uuid())
 
  propertyId        String
 
  featureCode       String
 
  featureValue      String?
 
  property          Property @relation(
                      fields:[propertyId],
                      references:[id]
                    )
}

Exemples

POOL

WIFI

PARKING

AIR_CONDITIONING

TERRACE

SEA_VIEW

PET_ALLOWED

PropertyMedia

Médias

model PropertyMedia {
 
  id                String @id @default(uuid())
 
  propertyId        String
 
  fileName          String
 
  fileUrl           String
 
  mediaType         String
 
  position          Int
 
  isCover           Boolean @default(false)
 
  createdAt         DateTime @default(now())
 
  property          Property @relation(
                      fields:[propertyId],
                      references:[id]
                    )
}

MediaType

IMAGE

VIDEO

VIRTUAL_TOUR

DOCUMENT

PropertyAvailability

Calendrier

model PropertyAvailability {
 
  id                String @id @default(uuid())
 
  propertyId        String
 
  startDate         DateTime
 
  endDate           DateTime
 
  status            AvailabilityStatus
 
  property          Property @relation(
                      fields:[propertyId],
                      references:[id]
                    )
}

Enum

enum AvailabilityStatus {
 
  AVAILABLE
 
  RESERVED
 
  BLOCKED
 
  MAINTENANCE
}

PropertyRate

Tarification

model PropertyRate {
 
  id                String @id @default(uuid())
 
  propertyId        String
 
  startDate         DateTime
 
  endDate           DateTime
 
  nightlyRate       Decimal @db.Decimal(10,2)
 
  weekendRate       Decimal? @db.Decimal(10,2)
 
  cleaningFee       Decimal? @db.Decimal(10,2)
 
  securityDeposit   Decimal? @db.Decimal(10,2)
 
  currencyCode      String
 
  property          Property @relation(
                      fields:[propertyId],
                      references:[id]
                    )
}

PropertyOwner

Association propriétaire

model PropertyOwner {
 
  propertyId        String
 
  ownerId           String
 
  ownershipRate     Decimal @db.Decimal(5,2)
 
  property          Property @relation(
                      fields:[propertyId],
                      references:[id]
                    )
 
  owner             Owner @relation(
                      fields:[ownerId],
                      references:[id]
                    )
 
  @@id([propertyId, ownerId])
}

Indexes

Property

@@index([tenantId])
 
@@index([propertyTypeId])
 
@@index([published])
 
@@index([active])
 
@@index([title])
 
@@index([slug])

PropertyAvailability

@@index([propertyId])
 
@@index([startDate])
 
@@index([endDate])

PropertyRate

@@index([propertyId])
 
@@index([startDate])
 
@@index([endDate])

Domaine Owner

Architecture

Owner

OwnerAddress

OwnerDocument

OwnerBankAccount

PropertyOwner

Owner

model Owner {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  code                  String @unique
 
  companyName           String?
 
  firstName             String?
 
  lastName              String?
 
  email                 String
 
  phone                 String?
 
  mobile                String?
 
  taxIdentifier         String?
 
  vatNumber             String?
 
  active                Boolean @default(true)
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  deletedAt             DateTime?
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  address               OwnerAddress?
 
  documents             OwnerDocument[]
 
  bankAccounts          OwnerBankAccount[]
 
  properties            PropertyOwner[]
}

OwnerAddress

model OwnerAddress {
 
  id                    String @id @default(uuid())
 
  ownerId               String @unique
 
  addressLine1          String
 
  addressLine2          String?
 
  postalCode            String
 
  city                  String
 
  state                 String?
 
  countryCode           String
 
  owner                 Owner @relation(
                            fields:[ownerId],
                            references:[id]
                         )
}

OwnerDocument

model OwnerDocument {
 
  id                    String @id @default(uuid())
 
  ownerId               String
 
  documentType          String
 
  fileUrl               String
 
  createdAt             DateTime @default(now())
 
  owner                 Owner @relation(
                            fields:[ownerId],
                            references:[id]
                         )
}

Document Types

IDENTITY

TAX_DOCUMENT

MANDATE

BANK_DETAILS

INSURANCE

OwnerBankAccount

model OwnerBankAccount {
 
  id                    String @id @default(uuid())
 
  ownerId               String
 
  iban                  String
 
  bic                   String?
 
  accountHolder         String
 
  active                Boolean @default(true)
 
  owner                 Owner @relation(
                            fields:[ownerId],
                            references:[id]
                         )
}

Domaine Reservation

Architecture

Reservation

ReservationGuest

ReservationStatusHistory

ReservationEvent

ReservationPricing

Reservation

Table centrale

model Reservation {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  propertyId            String
 
  customerId            String?
 
  reference             String @unique
 
  status                ReservationStatus
 
  checkInDate           DateTime
 
  checkOutDate          DateTime
 
  nights                Int
 
  adults                Int
 
  children              Int
 
  infants               Int
 
  totalGuests           Int
 
  notes                 String?
 
  source                ReservationSource
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  cancelledAt           DateTime?
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  property              Property @relation(
                            fields:[propertyId],
                            references:[id]
                         )
 
  guests                ReservationGuest[]
 
  events                ReservationEvent[]
 
  statusHistory         ReservationStatusHistory[]
 
  pricing               ReservationPricing?
}

ReservationStatus

enum ReservationStatus {
 
  DRAFT
 
  PENDING
 
  CONFIRMED
 
  SIGNED
 
  PAID
 
  CHECKED_IN
 
  COMPLETED
 
  CANCELLED
}

ReservationSource

enum ReservationSource {
 
  WEBSITE
 
  BACKOFFICE
 
  AIRBNB
 
  BOOKING
 
  VRBO
 
  API
}

ReservationGuest

model ReservationGuest {
 
  id                    String @id @default(uuid())
 
  reservationId         String
 
  firstName             String
 
  lastName              String
 
  birthDate             DateTime?
 
  email                 String?
 
  phone                 String?
 
  isPrimary             Boolean @default(false)
 
  reservation           Reservation @relation(
                            fields:[reservationId],
                            references:[id]
                         )
}

ReservationPricing

model ReservationPricing {
 
  id                    String @id @default(uuid())
 
  reservationId         String @unique
 
  nightlyAmount         Decimal @db.Decimal(10,2)
 
  cleaningFee           Decimal @db.Decimal(10,2)
 
  touristTax            Decimal @db.Decimal(10,2)
 
  discountAmount        Decimal @db.Decimal(10,2)
 
  totalAmount           Decimal @db.Decimal(10,2)
 
  currencyCode          String
 
  reservation           Reservation @relation(
                            fields:[reservationId],
                            references:[id]
                         )
}

ReservationEvent

model ReservationEvent {
 
  id                    String @id @default(uuid())
 
  reservationId         String
 
  eventType             String
 
  payload               Json?
 
  createdAt             DateTime @default(now())
 
  reservation           Reservation @relation(
                            fields:[reservationId],
                            references:[id]
                         )
}

Event Types

CREATED

CONFIRMED

SIGNED

PAID

CHECK_IN

CHECK_OUT

CANCELLED

ReservationStatusHistory

model ReservationStatusHistory {
 
  id                    String @id @default(uuid())
 
  reservationId         String
 
  previousStatus        ReservationStatus?
 
  newStatus             ReservationStatus
 
  changedAt             DateTime @default(now())
 
  reservation           Reservation @relation(
                            fields:[reservationId],
                            references:[id]
                         )
}

Relations à ajouter

Property

Ajouter :

reservations Reservation[]

Tenant

Ajouter :

owners Owner[]
 
reservations Reservation[]

Indexes

Owner

@@index([tenantId])
 
@@index([email])
 
@@index([active])

Reservation

@@index([tenantId])
 
@@index([propertyId])
 
@@index([status])
 
@@index([checkInDate])
 
@@index([checkOutDate])
 
@@index([reference])

ReservationGuest

@@index([reservationId])

Validation

npx prisma format
 
npx prisma validate
 
npx prisma generate

Migration

npx prisma migrate dev \
--name owners_and_reservations

État actuel du schéma

À ce stade, le noyau fonctionnel est enfin présent :

Tenant

User

Role

Permission

Owner

Property

Reservation

avec :

Catalogue Immobilier

Propriétaires

Réservations

RBAC

Multi-tenant

Phase 2-E — Contrats, Documents, Paiements & Facturation

Objectif

Construire le premier flux métier complet de la plateforme :

Client

↓

Réservation

↓

Contrat

↓

Signature

↓

Paiement

↓

Facture

↓

Comptabilité

Cette phase couvre :

  • Sprint 5 — Contrats & Signature Électronique
  • Sprint 6 — Paiements & Facturation

Prérequis

Avant cette phase, le schéma doit déjà contenir :

Tenant

User

Role

Permission

Owner

Property

Reservation

Domaine Client

Avant les contrats et paiements, il faut définir le client.


Customer

model Customer {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  customerNumber        String @unique
 
  firstName             String
 
  lastName              String
 
  email                 String
 
  phone                 String?
 
  mobile                String?
 
  birthDate             DateTime?
 
  nationality           String?
 
  languageCode          String?
 
  active                Boolean @default(true)
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  deletedAt             DateTime?
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  address               CustomerAddress?
 
  documents             CustomerDocument[]
 
  reservations          Reservation[]
}

CustomerAddress

model CustomerAddress {
 
  id                    String @id @default(uuid())
 
  customerId            String @unique
 
  addressLine1          String
 
  addressLine2          String?
 
  postalCode            String
 
  city                  String
 
  state                 String?
 
  countryCode           String
 
  customer              Customer @relation(
                            fields:[customerId],
                            references:[id]
                         )
}

CustomerDocument

model CustomerDocument {
 
  id                    String @id @default(uuid())
 
  customerId            String
 
  documentType          String
 
  fileUrl               String
 
  createdAt             DateTime @default(now())
 
  customer              Customer @relation(
                            fields:[customerId],
                            references:[id]
                         )
}

Mise à jour Reservation

Ajouter

customerId String?

Relation

customer Customer? @relation(
  fields:[customerId],
  references:[id]
)

Domaine Contrats

Architecture

Contract

ContractTemplate

ContractVersion

ContractSignature

Contract

model Contract {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  reservationId         String
 
  templateId            String
 
  contractNumber        String @unique
 
  status                ContractStatus
 
  signedAt              DateTime?
 
  generatedAt           DateTime?
 
  pdfUrl                String?
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  reservation           Reservation @relation(
                            fields:[reservationId],
                            references:[id]
                         )
 
  template              ContractTemplate @relation(
                            fields:[templateId],
                            references:[id]
                         )
 
  signatures            ContractSignature[]
 
  versions              ContractVersion[]
}

ContractStatus

enum ContractStatus {
 
  DRAFT
 
  GENERATED
 
  SENT
 
  VIEWED
 
  SIGNED
 
  CANCELLED
}

ContractTemplate

model ContractTemplate {
 
  id                    String @id @default(uuid())
 
  code                  String @unique
 
  name                  String
 
  content               String
 
  active                Boolean @default(true)
 
  createdAt             DateTime @default(now())
 
  contracts             Contract[]
}

ContractVersion

model ContractVersion {
 
  id                    String @id @default(uuid())
 
  contractId            String
 
  versionNumber         Int
 
  pdfUrl                String
 
  createdAt             DateTime @default(now())
 
  contract              Contract @relation(
                            fields:[contractId],
                            references:[id]
                         )
}

ContractSignature

model ContractSignature {
 
  id                    String @id @default(uuid())
 
  contractId            String
 
  signerName            String
 
  signerEmail           String
 
  signedAt              DateTime?
 
  providerReference     String?
 
  status                String
 
  contract              Contract @relation(
                            fields:[contractId],
                            references:[id]
                         )
}

Domaine Documents

Document

model Document {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  documentType          String
 
  fileName              String
 
  fileUrl               String
 
  mimeType              String
 
  fileSize              Int
 
  uploadedAt            DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
}

Domaine Paiements

Architecture

Payment

PaymentTransaction

Refund

PaymentMethod

Payment

model Payment {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  reservationId         String
 
  paymentReference      String @unique
 
  status                PaymentStatus
 
  amount                Decimal @db.Decimal(10,2)
 
  currencyCode          String
 
  paidAt                DateTime?
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  reservation           Reservation @relation(
                            fields:[reservationId],
                            references:[id]
                         )
 
  transactions          PaymentTransaction[]
 
  refunds               Refund[]
}

PaymentStatus

enum PaymentStatus {
 
  PENDING
 
  AUTHORIZED
 
  PAID
 
  FAILED
 
  CANCELLED
 
  REFUNDED
}

PaymentTransaction

model PaymentTransaction {
 
  id                    String @id @default(uuid())
 
  paymentId             String
 
  gateway               String
 
  gatewayReference      String
 
  status                String
 
  amount                Decimal @db.Decimal(10,2)
 
  createdAt             DateTime @default(now())
 
  payment               Payment @relation(
                            fields:[paymentId],
                            references:[id]
                         )
}

Refund

model Refund {
 
  id                    String @id @default(uuid())
 
  paymentId             String
 
  amount                Decimal @db.Decimal(10,2)
 
  reason                String?
 
  refundedAt            DateTime?
 
  payment               Payment @relation(
                            fields:[paymentId],
                            references:[id]
                         )
}

Facturation

Invoice

model Invoice {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  reservationId         String
 
  invoiceNumber         String @unique
 
  issueDate             DateTime
 
  dueDate               DateTime
 
  amountExclTax         Decimal @db.Decimal(10,2)
 
  taxAmount             Decimal @db.Decimal(10,2)
 
  amountInclTax         Decimal @db.Decimal(10,2)
 
  status                InvoiceStatus
 
  pdfUrl                String?
 
  createdAt             DateTime @default(now())
 
  reservation           Reservation @relation(
                            fields:[reservationId],
                            references:[id]
                         )
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
}

InvoiceStatus

enum InvoiceStatus {
 
  DRAFT
 
  ISSUED
 
  PAID
 
  PARTIALLY_PAID
 
  CANCELLED
}

Comptabilité

AccountingEntry

model AccountingEntry {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  entryDate             DateTime
 
  accountCode           String
 
  label                 String
 
  debit                 Decimal @db.Decimal(12,2)
 
  credit                Decimal @db.Decimal(12,2)
 
  reference             String?
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
}

Indexes

Contract

@@index([reservationId])
 
@@index([status])
 
@@index([contractNumber])

Payment

@@index([reservationId])
 
@@index([status])
 
@@index([paymentReference])

Invoice

@@index([reservationId])
 
@@index([invoiceNumber])
 
@@index([status])

Validation

npx prisma format
 
npx prisma validate
 
npx prisma generate

Migration

npx prisma migrate dev \
--name contracts_payments_invoices

État du noyau métier

À ce stade, le schéma couvre :

Tenant

User

RBAC

Owner

Property

Customer

Reservation

Contract

Document

Payment

Invoice

Accounting

Flux métier désormais couvert

Owner

↓

Property

↓

Customer

↓

Reservation

↓

Contract

↓

Signature

↓

Payment

↓

Invoice

↓

Accounting

Phase 2-F — CRM & Relation Client

Objectif

Mettre en place le CRM intégré de la plateforme.

Contrairement à un CRM externe, ce module est directement connecté aux :

  • Clients
  • Réservations
  • Contrats
  • Paiements
  • Propriétaires
  • Campagnes marketing

Le CRM devient ainsi la vue 360° du client.


Architecture CRM

Domaines

Lead

Opportunity

Pipeline

PipelineStage

Activity

Task

CustomerNote

Tag

Segment

CustomerTag

LeadSource

Vue d'ensemble

Lead

↓

Qualification

↓

Opportunity

↓

Reservation

↓

Customer

Lead

Prospect

model Lead {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  leadNumber            String @unique
 
  firstName             String
 
  lastName              String
 
  email                 String?
 
  phone                 String?
 
  company               String?
 
  sourceId              String?
 
  status                LeadStatus
 
  score                 Int @default(0)
 
  estimatedBudget       Decimal? @db.Decimal(10,2)
 
  expectedCheckIn       DateTime?
 
  expectedCheckOut      DateTime?
 
  notes                 String?
 
  assignedToUserId      String?
 
  convertedAt           DateTime?
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  source                LeadSource? @relation(
                            fields:[sourceId],
                            references:[id]
                         )
 
  opportunities         Opportunity[]
 
  activities            Activity[]
}

LeadStatus

enum LeadStatus {
 
  NEW
 
  QUALIFIED
 
  CONTACTED
 
  PROPOSAL
 
  WON
 
  LOST
 
  ARCHIVED
}

LeadSource

Origine du prospect

model LeadSource {
 
  id                    String @id @default(uuid())
 
  code                  String @unique
 
  name                  String
 
  leads                 Lead[]
}

Valeurs

WEBSITE

PHONE

EMAIL

FACEBOOK

INSTAGRAM

GOOGLE

AIRBNB

BOOKING

REFERRAL

Pipeline

Pipeline commercial

model Pipeline {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  name                  String
 
  active                Boolean @default(true)
 
  stages                PipelineStage[]
 
  opportunities         Opportunity[]
}

PipelineStage

model PipelineStage {
 
  id                    String @id @default(uuid())
 
  pipelineId            String
 
  name                  String
 
  position              Int
 
  probability           Int
 
  pipeline              Pipeline @relation(
                            fields:[pipelineId],
                            references:[id]
                         )
}

Exemple

Nouveau

Qualification

Proposition

Négociation

Gagné

Perdu

Opportunity

Opportunité commerciale

model Opportunity {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  leadId                String
 
  pipelineId            String
 
  stageId               String
 
  title                 String
 
  amount                Decimal? @db.Decimal(10,2)
 
  probability           Int
 
  expectedCloseDate     DateTime?
 
  status                OpportunityStatus
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  lead                  Lead @relation(
                            fields:[leadId],
                            references:[id]
                         )
 
  pipeline              Pipeline @relation(
                            fields:[pipelineId],
                            references:[id]
                         )
}

OpportunityStatus

enum OpportunityStatus {
 
  OPEN
 
  WON
 
  LOST
 
  CANCELLED
}

Activity

Historique des interactions

model Activity {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  leadId                String?
 
  customerId            String?
 
  activityType          ActivityType
 
  subject               String
 
  description           String?
 
  occurredAt            DateTime
 
  createdByUserId       String
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  lead                  Lead? @relation(
                            fields:[leadId],
                            references:[id]
                         )
 
  customer              Customer? @relation(
                            fields:[customerId],
                            references:[id]
                         )
}

ActivityType

enum ActivityType {
 
  CALL
 
  EMAIL
 
  MEETING
 
  SMS
 
  NOTE
 
  TASK
 
  SYSTEM
}

Task

Tâches CRM

model Task {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  title                 String
 
  description           String?
 
  assignedToUserId      String
 
  dueDate               DateTime?
 
  completedAt           DateTime?
 
  priority              TaskPriority
 
  status                TaskStatus
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
}

TaskPriority

enum TaskPriority {
 
  LOW
 
  MEDIUM
 
  HIGH
 
  URGENT
}

TaskStatus

enum TaskStatus {
 
  OPEN
 
  IN_PROGRESS
 
  DONE
 
  CANCELLED
}

CustomerNote

Notes internes

model CustomerNote {
 
  id                    String @id @default(uuid())
 
  customerId            String
 
  authorUserId          String
 
  content               String
 
  createdAt             DateTime @default(now())
 
  customer              Customer @relation(
                            fields:[customerId],
                            references:[id]
                         )
}

Tag

Classification

model Tag {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  code                  String @unique
 
  name                  String
 
  color                 String?
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  customerTags          CustomerTag[]
}

CustomerTag

Relation N:N

model CustomerTag {
 
  customerId            String
 
  tagId                 String
 
  customer              Customer @relation(
                            fields:[customerId],
                            references:[id]
                         )
 
  tag                   Tag @relation(
                            fields:[tagId],
                            references:[id]
                         )
 
  @@id([customerId, tagId])
}

Segment

Segmentation marketing

model Segment {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  code                  String @unique
 
  name                  String
 
  description           String?
 
  rules                 Json
 
  active                Boolean @default(true)
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
}

Relations à ajouter

Customer

Ajouter :

activities Activity[]
 
notes CustomerNote[]
 
tags CustomerTag[]

Tenant

Ajouter :

leads Lead[]
 
opportunities Opportunity[]
 
pipelines Pipeline[]
 
tasks Task[]
 
segments Segment[]

Indexes

Lead

@@index([tenantId])
 
@@index([status])
 
@@index([email])
 
@@index([assignedToUserId])

Opportunity

@@index([tenantId])
 
@@index([status])
 
@@index([expectedCloseDate])

Task

@@index([assignedToUserId])
 
@@index([status])
 
@@index([dueDate])

Validation

npx prisma format
 
npx prisma validate
 
npx prisma generate

Migration

npx prisma migrate dev \
--name crm_and_customer_relationship

Fonctionnalités désormais couvertes

Sprint 8

Prospects

Pipeline

Relances

Activités

Tâches

Segmentation

Historique client

Vue 360°

Nouveau flux métier

Lead

↓

Qualification

↓

Opportunity

↓

Reservation

↓

Contract

↓

Payment

↓

Customer Loyalty

État global du schéma

Le noyau métier couvre désormais :

RBAC

Utilisateurs

Propriétaires

Catalogue

Réservations

Contrats

Paiements

Facturation

CRM

soit environ :

35 à 40 modèles Prisma

Phase 2-G — Notifications, Messagerie & Communication

Objectif

Mettre en place le centre de communication unifié de la plateforme.

Ce domaine couvre :

  • Notifications Back Office
  • Notifications Client
  • Notifications Propriétaire
  • Emails transactionnels
  • SMS transactionnels
  • Messagerie interne
  • Conversations liées aux réservations
  • Historique des communications

Ce domaine sera utilisé par :

Reservations

Contracts

Payments

CRM

Owner Portal

Administration

Architecture

Modèles

Notification

NotificationTemplate

NotificationPreference

Conversation

ConversationParticipant

Message

EmailLog

SmsLog

Notification

Centre de notifications

model Notification {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  userId                String
 
  type                  NotificationType
 
  title                 String
 
  content               String
 
  status                NotificationStatus
 
  entityType            String?
 
  entityId              String?
 
  readAt                DateTime?
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  user                  User @relation(
                            fields:[userId],
                            references:[id]
                         )
 
  @@index([tenantId])
 
  @@index([userId])
 
  @@index([status])
 
  @@index([createdAt])
}

NotificationType

enum NotificationType {
 
  SYSTEM
 
  RESERVATION
 
  CONTRACT
 
  PAYMENT
 
  CRM
 
  OWNER
 
  SECURITY
 
  MARKETING
}

NotificationStatus

enum NotificationStatus {
 
  UNREAD
 
  READ
 
  ARCHIVED
}

NotificationTemplate

Modèles de notification

model NotificationTemplate {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  code                  String
 
  name                  String
 
  subject               String?
 
  content               String
 
  channel               NotificationChannel
 
  active                Boolean @default(true)
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  @@unique([tenantId, code])
}

NotificationChannel

enum NotificationChannel {
 
  IN_APP
 
  EMAIL
 
  SMS
 
  PUSH
}

NotificationPreference

Préférences utilisateur

model NotificationPreference {
 
  id                    String @id @default(uuid())
 
  userId                String
 
  notificationType      NotificationType
 
  emailEnabled          Boolean @default(true)
 
  smsEnabled            Boolean @default(false)
 
  pushEnabled           Boolean @default(false)
 
  inAppEnabled          Boolean @default(true)
 
  user                  User @relation(
                            fields:[userId],
                            references:[id]
                         )
 
  @@unique([userId, notificationType])
}

Conversation

Fil de discussion

model Conversation {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  reservationId         String?
 
  subject               String
 
  status                ConversationStatus
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  reservation           Reservation? @relation(
                            fields:[reservationId],
                            references:[id]
                         )
 
  participants          ConversationParticipant[]
 
  messages              Message[]
 
  @@index([tenantId])
 
  @@index([reservationId])
}

ConversationStatus

enum ConversationStatus {
 
  OPEN
 
  CLOSED
 
  ARCHIVED
}

ConversationParticipant

Participants

model ConversationParticipant {
 
  conversationId        String
 
  userId                String?
 
  customerId            String?
 
  ownerId               String?
 
  joinedAt              DateTime @default(now())
 
  conversation          Conversation @relation(
                            fields:[conversationId],
                            references:[id]
                         )
 
  user                  User? @relation(
                            fields:[userId],
                            references:[id]
                         )
 
  customer              Customer? @relation(
                            fields:[customerId],
                            references:[id]
                         )
 
  owner                 Owner? @relation(
                            fields:[ownerId],
                            references:[id]
                         )
 
  @@id([
    conversationId,
    userId,
    customerId,
    ownerId
  ])
}

Message

Message

model Message {
 
  id                    String @id @default(uuid())
 
  conversationId        String
 
  senderUserId          String?
 
  senderCustomerId      String?
 
  senderOwnerId         String?
 
  content               String
 
  sentAt                DateTime @default(now())
 
  readAt                DateTime?
 
  conversation          Conversation @relation(
                            fields:[conversationId],
                            references:[id]
                         )
 
  senderUser            User? @relation(
                            fields:[senderUserId],
                            references:[id]
                         )
 
  senderCustomer        Customer? @relation(
                            fields:[senderCustomerId],
                            references:[id]
                         )
 
  senderOwner           Owner? @relation(
                            fields:[senderOwnerId],
                            references:[id]
                         )
 
  @@index([conversationId])
 
  @@index([sentAt])
}

EmailLog

Historique Emails

model EmailLog {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  templateId            String?
 
  recipientEmail        String
 
  subject               String
 
  provider              String?
 
  providerMessageId     String?
 
  status                EmailStatus
 
  errorMessage          String?
 
  sentAt                DateTime?
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  template              NotificationTemplate?
                          @relation(
                            fields:[templateId],
                            references:[id]
                          )
 
  @@index([tenantId])
 
  @@index([recipientEmail])
 
  @@index([status])
}

EmailStatus

enum EmailStatus {
 
  PENDING
 
  SENT
 
  DELIVERED
 
  OPENED
 
  FAILED
 
  BOUNCED
}

SmsLog

Historique SMS

model SmsLog {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  recipientPhone        String
 
  content               String
 
  provider              String?
 
  providerMessageId     String?
 
  status                SmsStatus
 
  errorMessage          String?
 
  sentAt                DateTime?
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  @@index([tenantId])
 
  @@index([recipientPhone])
 
  @@index([status])
}

SmsStatus

enum SmsStatus {
 
  PENDING
 
  SENT
 
  DELIVERED
 
  FAILED
}

Relations à ajouter

User

notifications Notification[]
 
notificationPreferences NotificationPreference[]
 
conversationParticipants
  ConversationParticipant[]
 
messages Message[]

Customer

conversationParticipants
  ConversationParticipant[]
 
messages Message[]

Owner

conversationParticipants
  ConversationParticipant[]
 
messages Message[]

Reservation

conversations Conversation[]

Tenant

notifications Notification[]
 
notificationTemplates NotificationTemplate[]
 
conversations Conversation[]
 
emailLogs EmailLog[]
 
smsLogs SmsLog[]

Validation

npx prisma format
 
npx prisma validate
 
npx prisma generate

Migration

npx prisma migrate dev \
--name notifications_messaging

Fonctionnalités couvertes

Sprint 9

Notifications temps réel

Centre de notifications

Messagerie propriétaire

Messagerie client

Messagerie réservation

Emails transactionnels

SMS transactionnels

Préférences utilisateur

État du schéma

Après Phase 2-G :

≈ 60 modèles Prisma

avec les domaines :

Core

Security

Properties

Owners

Customers

Reservations

Contracts

Payments

CRM

Notifications

Messaging

Phase 2-H — Campagnes Marketing & Automatisation

Objectif

Mettre en place la couche marketing et automatisation de la plateforme.

Ce domaine permettra :

  • Campagnes Email
  • Campagnes SMS
  • Segmentation avancée
  • Marketing Automation
  • Relances automatiques
  • Nurturing prospects
  • Fidélisation clients
  • Déclencheurs métiers

Cette phase finalise :

Sprint 8 CRM

Sprint 9 Communication

Sprint 13 Automatisation & IA

Architecture

Modèles

Campaign

CampaignRecipient

CampaignExecution

MarketingSegment

MarketingEvent

AutomationRule

AutomationExecution

Campaign

Campagne Marketing

model Campaign {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  code                  String
 
  name                  String
 
  description           String?
 
  campaignType          CampaignType
 
  status                CampaignStatus
 
  startDate             DateTime?
 
  endDate               DateTime?
 
  createdByUserId       String?
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  createdByUser         User? @relation(
                            "CampaignCreator",
                            fields:[createdByUserId],
                            references:[id]
                         )
 
  recipients            CampaignRecipient[]
 
  executions            CampaignExecution[]
 
  @@unique([tenantId, code])
 
  @@index([tenantId])
 
  @@index([status])
}

CampaignType

enum CampaignType {
 
  EMAIL
 
  SMS
 
  MIXED
 
  PUSH
 
  WORKFLOW
}

CampaignStatus

enum CampaignStatus {
 
  DRAFT
 
  SCHEDULED
 
  RUNNING
 
  COMPLETED
 
  PAUSED
 
  CANCELLED
}

CampaignRecipient

Destinataires

model CampaignRecipient {
 
  id                    String @id @default(uuid())
 
  campaignId            String
 
  customerId            String?
 
  leadId                String?
 
  email                 String?
 
  phone                 String?
 
  status                CampaignRecipientStatus
 
  sentAt                DateTime?
 
  openedAt              DateTime?
 
  clickedAt             DateTime?
 
  unsubscribedAt        DateTime?
 
  campaign              Campaign @relation(
                            fields:[campaignId],
                            references:[id]
                         )
 
  customer              Customer? @relation(
                            fields:[customerId],
                            references:[id]
                         )
 
  lead                  Lead? @relation(
                            fields:[leadId],
                            references:[id]
                         )
 
  @@index([campaignId])
 
  @@index([status])
}

CampaignRecipientStatus

enum CampaignRecipientStatus {
 
  PENDING
 
  SENT
 
  OPENED
 
  CLICKED
 
  FAILED
 
  UNSUBSCRIBED
}

CampaignExecution

Exécution

model CampaignExecution {
 
  id                    String @id @default(uuid())
 
  campaignId            String
 
  startedAt             DateTime
 
  completedAt           DateTime?
 
  recipientsCount       Int
 
  successCount          Int
 
  failedCount           Int
 
  status                ExecutionStatus
 
  campaign              Campaign @relation(
                            fields:[campaignId],
                            references:[id]
                         )
 
  @@index([campaignId])
 
  @@index([status])
}

ExecutionStatus

enum ExecutionStatus {
 
  PENDING
 
  RUNNING
 
  COMPLETED
 
  FAILED
}

MarketingSegment

Segmentation avancée

model MarketingSegment {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  code                  String
 
  name                  String
 
  description           String?
 
  rules                 Json
 
  active                Boolean @default(true)
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  @@unique([tenantId, code])
}

Exemples

CLIENTS_FIDELES

CLIENTS_INACTIFS

PROPRIETAIRES_ACTIFS

PROSPECTS_CHAUDS

RESERVATIONS_30J

ANNIVERSAIRES

MarketingEvent

Événements Marketing

model MarketingEvent {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  customerId            String?
 
  leadId                String?
 
  eventType             MarketingEventType
 
  payload               Json?
 
  occurredAt            DateTime
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  customer              Customer? @relation(
                            fields:[customerId],
                            references:[id]
                         )
 
  lead                  Lead? @relation(
                            fields:[leadId],
                            references:[id]
                         )
 
  @@index([tenantId])
 
  @@index([eventType])
 
  @@index([occurredAt])
}

MarketingEventType

enum MarketingEventType {
 
  EMAIL_OPEN
 
  EMAIL_CLICK
 
  SMS_SENT
 
  PAGE_VISIT
 
  FORM_SUBMIT
 
  LEAD_CREATED
 
  RESERVATION_CREATED
 
  CONTRACT_SIGNED
 
  PAYMENT_COMPLETED
}

AutomationRule

Règle métier

model AutomationRule {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  code                  String
 
  name                  String
 
  description           String?
 
  triggerEvent          String
 
  conditions            Json?
 
  actions               Json
 
  active                Boolean @default(true)
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  executions            AutomationExecution[]
 
  @@unique([tenantId, code])
 
  @@index([tenantId])
 
  @@index([active])
}

Exemples

ReservationConfirmed

↓

SendEmail

----------------

PaymentReceived

↓

GenerateInvoice

----------------

LeadCreated

↓

AssignSalesAgent

AutomationExecution

Historique

model AutomationExecution {
 
  id                    String @id @default(uuid())
 
  automationRuleId      String
 
  status                ExecutionStatus
 
  entityType            String?
 
  entityId              String?
 
  startedAt             DateTime
 
  completedAt           DateTime?
 
  errorMessage          String?
 
  automationRule        AutomationRule @relation(
                            fields:[automationRuleId],
                            references:[id]
                         )
 
  @@index([automationRuleId])
 
  @@index([status])
}

Relations à ajouter

Tenant

campaigns Campaign[]
 
marketingSegments MarketingSegment[]
 
marketingEvents MarketingEvent[]
 
automationRules AutomationRule[]

Customer

campaignRecipients CampaignRecipient[]
 
marketingEvents MarketingEvent[]

Lead

campaignRecipients CampaignRecipient[]
 
marketingEvents MarketingEvent[]

User

createdCampaigns Campaign[]
  @relation("CampaignCreator")

Validation

npx prisma format
 
npx prisma validate
 
npx prisma generate

Migration

npx prisma migrate dev \
--name marketing_automation

Fonctionnalités couvertes

CRM

Lead Nurturing

Relances

Segmentation

Scoring

Qualification

Communication

Campagnes Email

Campagnes SMS

Suivi Ouvertures

Suivi Clics

Désabonnement

Automatisation

Déclencheurs

Workflows

Actions Automatiques

Historisation

État du schéma

Après Phase 2-H :

≈ 67 modèles Prisma

avec les domaines :

Core

Security

Properties

Owners

Customers

Reservations

Contracts

Payments

CRM

Messaging

Marketing

Automation

Phase 2-I — Administration, Audit & Gouvernance

Objectif

Mettre en place la couche transverse de gouvernance de la plateforme.

Cette couche doit permettre :

  • Audit complet des actions
  • Historisation métier
  • Activation dynamique de fonctionnalités
  • Workflows métiers configurables
  • Gouvernance des données
  • Traçabilité réglementaire
  • Préparation RGPD / ISO27001 / SOC2

Cette phase prépare directement :

Sprint 10 — Reporting

Sprint 11 — Administration

Sprint 19 — Gouvernance & Conformité

Architecture

Modèles

AuditLog

EntityHistory

FeatureFlag

Workflow

WorkflowStep

WorkflowInstance

WorkflowExecution

AuditLog

Journal d'audit

Toutes les actions sensibles doivent être tracées.

model AuditLog {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  userId                String?
 
  entityType            String
 
  entityId              String
 
  action                AuditAction
 
  oldValues             Json?
 
  newValues             Json?
 
  ipAddress             String?
 
  userAgent             String?
 
  correlationId         String?
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  user                  User? @relation(
                            fields:[userId],
                            references:[id]
                         )
 
  @@index([tenantId])
 
  @@index([entityType])
 
  @@index([entityId])
 
  @@index([action])
 
  @@index([createdAt])
}

AuditAction

enum AuditAction {
 
  CREATE
 
  UPDATE
 
  DELETE
 
  RESTORE
 
  LOGIN
 
  LOGOUT
 
  EXPORT
 
  IMPORT
 
  EXECUTE
 
  APPROVE
 
  REJECT
}

EntityHistory

Historisation métier

Permet de reconstruire l'état d'une entité à n'importe quelle date.

model EntityHistory {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  entityType            String
 
  entityId              String
 
  version               Int
 
  snapshot              Json
 
  createdByUserId       String?
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  createdByUser         User? @relation(
                            fields:[createdByUserId],
                            references:[id]
                         )
 
  @@unique([
    entityType,
    entityId,
    version
  ])
 
  @@index([tenantId])
 
  @@index([entityType])
 
  @@index([entityId])
}

FeatureFlag

Activation dynamique

Permet de déployer progressivement des fonctionnalités.

model FeatureFlag {
 
  id                    String @id @default(uuid())
 
  tenantId              String?
 
  code                  String @unique
 
  name                  String
 
  description           String?
 
  enabled               Boolean @default(false)
 
  configuration         Json?
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  tenant                Tenant? @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  @@index([tenantId])
 
  @@index([enabled])
}

Exemples

AI_ASSISTANT

OWNER_PORTAL_V2

OTA_SYNC

REVENUE_MANAGEMENT

ADVANCED_REPORTING

Workflow

Définition d'un workflow

model Workflow {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  code                  String
 
  name                  String
 
  description           String?
 
  entityType            String
 
  active                Boolean @default(true)
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  steps                 WorkflowStep[]
 
  instances             WorkflowInstance[]
 
  @@unique([tenantId, code])
 
  @@index([tenantId])
 
  @@index([entityType])
}

WorkflowStep

Étapes du workflow

model WorkflowStep {
 
  id                    String @id @default(uuid())
 
  workflowId            String
 
  code                  String
 
  name                  String
 
  position              Int
 
  approverRoleCode      String?
 
  automatic             Boolean @default(false)
 
  configuration         Json?
 
  workflow              Workflow @relation(
                            fields:[workflowId],
                            references:[id]
                         )
 
  @@unique([
    workflowId,
    code
  ])
 
  @@index([workflowId])
 
  @@index([position])
}

Exemple

ReservationApproval

↓

ManagerApproval

↓

ContractGeneration

↓

PaymentValidation

↓

Completed

WorkflowInstance

Exécution métier

model WorkflowInstance {
 
  id                    String @id @default(uuid())
 
  workflowId            String
 
  entityType            String
 
  entityId              String
 
  currentStepId         String?
 
  status                WorkflowInstanceStatus
 
  startedAt             DateTime @default(now())
 
  completedAt           DateTime?
 
  workflow              Workflow @relation(
                            fields:[workflowId],
                            references:[id]
                         )
 
  currentStep           WorkflowStep?
                          @relation(
                            fields:[currentStepId],
                            references:[id]
                          )
 
  executions            WorkflowExecution[]
 
  @@index([workflowId])
 
  @@index([entityType])
 
  @@index([entityId])
 
  @@index([status])
}

WorkflowInstanceStatus

enum WorkflowInstanceStatus {
 
  RUNNING
 
  WAITING
 
  APPROVED
 
  REJECTED
 
  COMPLETED
 
  CANCELLED
}

WorkflowExecution

Historique des étapes

model WorkflowExecution {
 
  id                    String @id @default(uuid())
 
  workflowInstanceId    String
 
  workflowStepId        String
 
  executedByUserId      String?
 
  status                WorkflowExecutionStatus
 
  comments              String?
 
  executedAt            DateTime @default(now())
 
  workflowInstance      WorkflowInstance @relation(
                            fields:[workflowInstanceId],
                            references:[id]
                         )
 
  workflowStep          WorkflowStep @relation(
                            fields:[workflowStepId],
                            references:[id]
                         )
 
  executedByUser        User? @relation(
                            fields:[executedByUserId],
                            references:[id]
                         )
 
  @@index([workflowInstanceId])
 
  @@index([workflowStepId])
 
  @@index([executedAt])
}

WorkflowExecutionStatus

enum WorkflowExecutionStatus {
 
  PENDING
 
  APPROVED
 
  REJECTED
 
  SKIPPED
 
  COMPLETED
}

Relations à ajouter

Tenant

auditLogs AuditLog[]
 
entityHistories EntityHistory[]
 
featureFlags FeatureFlag[]
 
workflows Workflow[]

User

auditLogs AuditLog[]
 
entityHistories EntityHistory[]
 
workflowExecutions WorkflowExecution[]

Cas d'usage métiers

Réservation

Reservation Created

↓

AuditLog

↓

Workflow Instance

↓

Manager Approval

↓

Contract Generation

Paiement

Payment Refunded

↓

AuditLog

↓

History Snapshot

↓

Compliance Trace

Administration

Feature Enabled

↓

AuditLog

↓

History

↓

Reporting

Validation

npx prisma format
 
npx prisma validate
 
npx prisma generate

Migration

npx prisma migrate dev \
--name administration_audit_governance

Fonctionnalités couvertes

Administration

Feature Flags

Workflows

Validation

Approbation

Audit

Journalisation

Traçabilité

Historisation

Conformité

Gouvernance

Contrôle

Supervision

Rétention

Preuve d'audit

État du schéma

Après Phase 2-I :

≈ 74 modèles Prisma

avec les domaines :

Core

Security

Properties

Owners

Customers

Reservations

Contracts

Payments

CRM

Messaging

Marketing

Automation

Governance

Phase 2-J — OTA & Channel Manager

Objectif

Construire le moteur de distribution multicanal de la plateforme.

Ce domaine permettra :

  • Synchronisation Airbnb
  • Synchronisation Booking.com
  • Synchronisation Vrbo
  • Synchronisation Abritel
  • Publication automatique des biens
  • Synchronisation des disponibilités
  • Synchronisation des tarifs
  • Synchronisation des réservations
  • Gestion des erreurs de synchronisation

Cette phase couvre :

Sprint 12 — OTA & Distribution

Sprint 14 — API & Partenaires

Sprint 18 — Channel Manager Enterprise

Architecture

Modèles

Channel

ChannelConnection

PropertyDistribution

ChannelReservation

SyncExecution

SyncError

Channel

Catalogue OTA

Référentiel des plateformes connectables.

model Channel {
 
  id                    String @id @default(uuid())
 
  code                  String @unique
 
  name                  String
 
  channelType           ChannelType
 
  active                Boolean @default(true)
 
  apiDocumentationUrl   String?
 
  logoUrl               String?
 
  createdAt             DateTime @default(now())
 
  connections           ChannelConnection[]
 
  distributions         PropertyDistribution[]
}

ChannelType

enum ChannelType {
 
  OTA
 
  DIRECT
 
  PARTNER
 
  API
 
  MARKETPLACE
}

Valeurs initiales

AIRBNB

BOOKING

VRBO

ABRITEL

EXPEDIA

DIRECT_WEBSITE

ChannelConnection

Connexion OTA

Une agence peut posséder plusieurs connexions.

model ChannelConnection {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  channelId             String
 
  connectionName        String
 
  accountIdentifier     String?
 
  apiKey                String?
 
  apiSecret             String?
 
  refreshToken          String?
 
  configuration         Json?
 
  active                Boolean @default(true)
 
  lastSyncAt            DateTime?
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  channel               Channel @relation(
                            fields:[channelId],
                            references:[id]
                         )
 
  propertyDistributions PropertyDistribution[]
 
  syncExecutions        SyncExecution[]
 
  @@index([tenantId])
 
  @@index([channelId])
 
  @@index([active])
}

PropertyDistribution

Publication d'un bien

Permet d'associer un bien à un canal de distribution.

model PropertyDistribution {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  propertyId            String
 
  channelId             String
 
  channelConnectionId   String
 
  externalPropertyId    String?
 
  externalListingId     String?
 
  published             Boolean @default(false)
 
  publicationStatus     DistributionStatus
 
  publishedAt           DateTime?
 
  lastSyncAt            DateTime?
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  property              Property @relation(
                            fields:[propertyId],
                            references:[id]
                         )
 
  channel               Channel @relation(
                            fields:[channelId],
                            references:[id]
                         )
 
  channelConnection     ChannelConnection @relation(
                            fields:[channelConnectionId],
                            references:[id]
                         )
 
  reservations          ChannelReservation[]
 
  @@unique([
    propertyId,
    channelConnectionId
  ])
 
  @@index([tenantId])
 
  @@index([propertyId])
 
  @@index([channelId])
 
  @@index([publicationStatus])
}

DistributionStatus

enum DistributionStatus {
 
  DRAFT
 
  PENDING
 
  PUBLISHED
 
  SUSPENDED
 
  ERROR
 
  ARCHIVED
}

ChannelReservation

Réservation OTA

Historise le lien entre la réservation interne et la réservation OTA.

model ChannelReservation {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  reservationId         String
 
  propertyDistributionId String
 
  externalReservationId String
 
  externalStatus        String?
 
  importedAt            DateTime @default(now())
 
  lastSyncAt            DateTime?
 
  reservation           Reservation @relation(
                            fields:[reservationId],
                            references:[id]
                         )
 
  propertyDistribution  PropertyDistribution @relation(
                            fields:[propertyDistributionId],
                            references:[id]
                         )
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  @@unique([
    propertyDistributionId,
    externalReservationId
  ])
 
  @@index([tenantId])
 
  @@index([reservationId])
 
  @@index([importedAt])
}

SyncExecution

Historique des synchronisations

Chaque synchronisation OTA doit être historisée.

model SyncExecution {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  channelConnectionId   String
 
  syncType              SyncType
 
  status                SyncStatus
 
  startedAt             DateTime
 
  completedAt           DateTime?
 
  processedCount        Int @default(0)
 
  successCount          Int @default(0)
 
  errorCount            Int @default(0)
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  channelConnection     ChannelConnection @relation(
                            fields:[channelConnectionId],
                            references:[id]
                         )
 
  errors                SyncError[]
 
  @@index([tenantId])
 
  @@index([channelConnectionId])
 
  @@index([syncType])
 
  @@index([status])
 
  @@index([startedAt])
}

SyncType

enum SyncType {
 
  PROPERTY_EXPORT
 
  AVAILABILITY_EXPORT
 
  RATE_EXPORT
 
  RESERVATION_IMPORT
 
  FULL_SYNC
}

SyncStatus

enum SyncStatus {
 
  PENDING
 
  RUNNING
 
  COMPLETED
 
  PARTIAL_SUCCESS
 
  FAILED
}

SyncError

Gestion des erreurs

Permet d'analyser les échecs OTA.

model SyncError {
 
  id                    String @id @default(uuid())
 
  syncExecutionId       String
 
  errorCode             String?
 
  errorMessage          String
 
  entityType            String?
 
  entityId              String?
 
  payload               Json?
 
  occurredAt            DateTime @default(now())
 
  syncExecution         SyncExecution @relation(
                            fields:[syncExecutionId],
                            references:[id]
                         )
 
  @@index([syncExecutionId])
 
  @@index([errorCode])
 
  @@index([occurredAt])
}

Relations à ajouter

Tenant

channelConnections ChannelConnection[]
 
propertyDistributions PropertyDistribution[]
 
channelReservations ChannelReservation[]
 
syncExecutions SyncExecution[]

Property

propertyDistributions PropertyDistribution[]

Reservation

channelReservations ChannelReservation[]

Synchronisations couvertes

Disponibilités

PropertyAvailability

↓

OTA

Tarifs

PropertyRate

↓

OTA

Réservations

OTA

↓

ChannelReservation

↓

Reservation

Publication

Property

↓

PropertyDistribution

↓

Airbnb

Booking

Vrbo

Abritel

Validation

npx prisma format
 
npx prisma validate
 
npx prisma generate

Migration

npx prisma migrate dev \
--name ota_channel_manager

Fonctionnalités couvertes

Sprint 12

Publication OTA

Synchronisation calendrier

Synchronisation tarifs

Import réservations

Sprint 14

Partenaires

API externes

Marketplace

Sprint 18

Channel Manager Enterprise

Multi-OTA

Monitoring synchronisations

Gestion erreurs

État du schéma

Après Phase 2-J :

≈ 80 modèles Prisma

avec les domaines :

Core

Security

Properties

Owners

Customers

Reservations

Contracts

Payments

CRM

Messaging

Marketing

Automation

Governance

OTA

Phase 2-K — Revenue Management & Tarification Dynamique

Objectif

Construire le moteur de Revenue Management de la plateforme.

Ce domaine permettra :

  • Tarification dynamique
  • Yield Management
  • Prévisions de revenus
  • Analyse de la demande
  • Analyse concurrentielle
  • Optimisation automatique des prix
  • Simulation financière
  • Aide à la décision

Cette phase couvre :

Sprint 10 — Reporting

Sprint 13 — IA & Prévisions

Sprint 17 — Revenue Management

Sprint 20 — Enterprise Analytics

Architecture

Modèles

PricingRule

DynamicPrice

RevenueForecast

RevenueSimulation

CompetitorSnapshot

MarketDemand

PricingRule

Règle tarifaire

Définit les règles d'ajustement automatique.

model PricingRule {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  propertyId            String?
 
  code                  String
 
  name                  String
 
  description           String?
 
  priority              Int @default(100)
 
  active                Boolean @default(true)
 
  conditions            Json
 
  actions               Json
 
  validFrom             DateTime?
 
  validTo               DateTime?
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  property              Property? @relation(
                            fields:[propertyId],
                            references:[id]
                         )
 
  @@unique([tenantId, code])
 
  @@index([tenantId])
 
  @@index([propertyId])
 
  @@index([active])
 
  @@index([priority])
}

Exemples

Occupation > 80%

↓

+15%

----------------

Weekend

↓

+10%

----------------

Haute saison

↓

+25%

DynamicPrice

Prix calculé

Prix final appliqué à une date donnée.

model DynamicPrice {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  propertyId            String
 
  pricingDate           DateTime
 
  basePrice             Decimal @db.Decimal(12,2)
 
  adjustedPrice         Decimal @db.Decimal(12,2)
 
  occupancyFactor       Decimal? @db.Decimal(5,2)
 
  seasonalityFactor     Decimal? @db.Decimal(5,2)
 
  demandFactor          Decimal? @db.Decimal(5,2)
 
  competitorFactor      Decimal? @db.Decimal(5,2)
 
  generatedAt           DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  property              Property @relation(
                            fields:[propertyId],
                            references:[id]
                         )
 
  @@unique([
    propertyId,
    pricingDate
  ])
 
  @@index([tenantId])
 
  @@index([propertyId])
 
  @@index([pricingDate])
}

RevenueForecast

Prévisions

Prévision de revenus futurs.

model RevenueForecast {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  propertyId            String?
 
  forecastDate          DateTime
 
  forecastPeriodStart   DateTime
 
  forecastPeriodEnd     DateTime
 
  expectedRevenue       Decimal @db.Decimal(14,2)
 
  expectedOccupancy     Decimal @db.Decimal(5,2)
 
  confidenceLevel       Decimal @db.Decimal(5,2)
 
  modelVersion          String?
 
  generatedAt           DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  property              Property? @relation(
                            fields:[propertyId],
                            references:[id]
                         )
 
  @@index([tenantId])
 
  @@index([propertyId])
 
  @@index([forecastDate])
}

RevenueSimulation

Simulation

Analyse de scénarios.

model RevenueSimulation {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  propertyId            String?
 
  name                  String
 
  assumptions           Json
 
  projectedRevenue      Decimal @db.Decimal(14,2)
 
  projectedOccupancy    Decimal @db.Decimal(5,2)
 
  createdByUserId       String?
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  property              Property? @relation(
                            fields:[propertyId],
                            references:[id]
                         )
 
  createdByUser         User? @relation(
                            fields:[createdByUserId],
                            references:[id]
                         )
 
  @@index([tenantId])
 
  @@index([propertyId])
}

Exemple

Prix +10%

↓

Occupation -3%

↓

CA +6%

CompetitorSnapshot

Veille concurrentielle

Capture des prix concurrents.

model CompetitorSnapshot {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  propertyId            String
 
  competitorName        String
 
  competitorPropertyId  String?
 
  snapshotDate          DateTime
 
  nightlyRate           Decimal @db.Decimal(12,2)
 
  occupancy             Decimal? @db.Decimal(5,2)
 
  source                String?
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  property              Property @relation(
                            fields:[propertyId],
                            references:[id]
                         )
 
  @@index([tenantId])
 
  @@index([propertyId])
 
  @@index([snapshotDate])
}

MarketDemand

Indicateurs marché

Mesure de la demande.

model MarketDemand {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  regionCode            String
 
  demandDate            DateTime
 
  demandIndex           Decimal @db.Decimal(5,2)
 
  occupancyIndex        Decimal @db.Decimal(5,2)
 
  averageDailyRate      Decimal @db.Decimal(12,2)
 
  source                String?
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  @@index([tenantId])
 
  @@index([regionCode])
 
  @@index([demandDate])
}

Relations à ajouter

Property

pricingRules PricingRule[]
 
dynamicPrices DynamicPrice[]
 
revenueForecasts RevenueForecast[]
 
revenueSimulations RevenueSimulation[]
 
competitorSnapshots CompetitorSnapshot[]

Tenant

pricingRules PricingRule[]
 
dynamicPrices DynamicPrice[]
 
revenueForecasts RevenueForecast[]
 
revenueSimulations RevenueSimulation[]
 
marketDemands MarketDemand[]

Cas d'usage

Tarification dynamique

Occupation

+

Saisonnalité

+

Concurrence

+

Demande

↓

Prix optimal

Prévision

Historique réservations

↓

Forecast IA

↓

Revenus prévus

Simulation

Nouveau tarif

↓

Simulation

↓

Impact CA

Validation

npx prisma format
 
npx prisma validate
 
npx prisma generate

Migration

npx prisma migrate dev \
--name revenue_management

Fonctionnalités couvertes

Revenue Management

Yield Management

Dynamic Pricing

Optimisation tarifaire

Analytics

Forecast

Simulation

Benchmark concurrence

Demand Analytics

IA

Aide à la décision

Prévisions

Recommandations

État du schéma

Après Phase 2-K :

≈ 86 modèles Prisma

avec les domaines :

Core

Security

Properties

Owners

Customers

Reservations

Contracts

Payments

CRM

Messaging

Marketing

Automation

Governance

OTA

Revenue Management

Phase 2-L — Sécurité Enterprise & Conformité

Objectif

Construire la couche Enterprise de sécurité, conformité et gouvernance des données.

Cette phase permettra :

  • Conformité RGPD
  • Gestion des consentements
  • Gestion des risques
  • Gouvernance des données
  • Classification des données
  • Rétention réglementaire
  • Gestion des incidents de sécurité
  • Préparation ISO 27001
  • Préparation SOC2
  • Préparation NIS2

Cette phase couvre :

Sprint 19

Governance

Compliance

Enterprise Security

Architecture

Modèles

Consent

SecurityPolicy

Risk

ComplianceAudit

SecurityIncident

DataClassification

RetentionPolicy

Consent

Gestion des consentements

Traçabilité complète des consentements utilisateurs.

model Consent {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  customerId            String?
 
  userId                String?
 
  consentType           ConsentType
 
  granted               Boolean
 
  version               String
 
  source                String?
 
  ipAddress             String?
 
  userAgent             String?
 
  grantedAt             DateTime
 
  revokedAt             DateTime?
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  customer              Customer? @relation(
                            fields:[customerId],
                            references:[id]
                         )
 
  user                  User? @relation(
                            fields:[userId],
                            references:[id]
                         )
 
  @@index([tenantId])
 
  @@index([customerId])
 
  @@index([userId])
 
  @@index([consentType])
}

ConsentType

enum ConsentType {
 
  GDPR
 
  COOKIES
 
  MARKETING_EMAIL
 
  MARKETING_SMS
 
  PROFILING
 
  THIRD_PARTY_SHARING
}

SecurityPolicy

Politiques de sécurité

Configuration centralisée.

model SecurityPolicy {
 
  id                    String @id @default(uuid())
 
  tenantId              String?
 
  code                  String @unique
 
  name                  String
 
  description           String?
 
  configuration         Json
 
  active                Boolean @default(true)
 
  createdAt             DateTime @default(now())
 
  updatedAt             DateTime @updatedAt
 
  tenant                Tenant? @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  @@index([tenantId])
 
  @@index([active])
}

Exemples

PASSWORD_POLICY

SESSION_POLICY

MFA_POLICY

RETENTION_POLICY

ACCESS_CONTROL_POLICY

Risk

Registre des risques

model Risk {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  code                  String
 
  title                 String
 
  description           String?
 
  category              RiskCategory
 
  probability           Int
 
  impact                Int
 
  score                 Int
 
  mitigationPlan        String?
 
  ownerUserId           String?
 
  status                RiskStatus
 
  identifiedAt          DateTime
 
  reviewedAt            DateTime?
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  ownerUser             User? @relation(
                            fields:[ownerUserId],
                            references:[id]
                         )
 
  @@unique([tenantId, code])
 
  @@index([tenantId])
 
  @@index([status])
 
  @@index([score])
}

RiskCategory

enum RiskCategory {
 
  SECURITY
 
  COMPLIANCE
 
  OPERATIONAL
 
  FINANCIAL
 
  LEGAL
 
  TECHNICAL
}

RiskStatus

enum RiskStatus {
 
  IDENTIFIED
 
  ASSESSED
 
  MITIGATED
 
  ACCEPTED
 
  CLOSED
}

ComplianceAudit

Audits réglementaires

model ComplianceAudit {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  auditType             ComplianceAuditType
 
  scope                 String?
 
  status                ComplianceAuditStatus
 
  auditor               String?
 
  findings              Json?
 
  recommendations       Json?
 
  startedAt             DateTime
 
  completedAt           DateTime?
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  @@index([tenantId])
 
  @@index([auditType])
 
  @@index([status])
}

ComplianceAuditType

enum ComplianceAuditType {
 
  GDPR
 
  ISO27001
 
  SOC2
 
  NIS2
 
  INTERNAL
}

ComplianceAuditStatus

enum ComplianceAuditStatus {
 
  PLANNED
 
  RUNNING
 
  COMPLETED
 
  CLOSED
}

SecurityIncident

Gestion des incidents

model SecurityIncident {
 
  id                    String @id @default(uuid())
 
  tenantId              String
 
  code                  String
 
  title                 String
 
  description           String?
 
  severity              IncidentSeverity
 
  status                IncidentStatus
 
  detectedAt            DateTime
 
  resolvedAt            DateTime?
 
  reportedByUserId      String?
 
  rootCause             String?
 
  correctiveActions     String?
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  reportedByUser        User? @relation(
                            fields:[reportedByUserId],
                            references:[id]
                         )
 
  @@unique([tenantId, code])
 
  @@index([tenantId])
 
  @@index([severity])
 
  @@index([status])
}

IncidentSeverity

enum IncidentSeverity {
 
  LOW
 
  MEDIUM
 
  HIGH
 
  CRITICAL
}

IncidentStatus

enum IncidentStatus {
 
  OPEN
 
  INVESTIGATING
 
  MITIGATED
 
  RESOLVED
 
  CLOSED
}

DataClassification

Classification des données

model DataClassification {
 
  id                    String @id @default(uuid())
 
  code                  String @unique
 
  name                  String
 
  description           String?
 
  level                 ClassificationLevel
 
  active                Boolean @default(true)
 
  createdAt             DateTime @default(now())
}

ClassificationLevel

enum ClassificationLevel {
 
  PUBLIC
 
  INTERNAL
 
  CONFIDENTIAL
 
  RESTRICTED
}

Exemples

Client

→ CONFIDENTIAL

----------------

Paiement

→ RESTRICTED

----------------

Catalogue public

→ PUBLIC

RetentionPolicy

Politique de conservation

model RetentionPolicy {
 
  id                    String @id @default(uuid())
 
  tenantId              String?
 
  code                  String @unique
 
  entityType            String
 
  retentionDays         Int
 
  archiveBeforeDelete   Boolean @default(true)
 
  active                Boolean @default(true)
 
  createdAt             DateTime @default(now())
 
  tenant                Tenant? @relation(
                            fields:[tenantId],
                            references:[id]
                         )
 
  @@index([tenantId])
 
  @@index([entityType])
}

Exemples

AuditLog

3650 jours

----------------

LoginHistory

365 jours

----------------

MarketingEvent

1095 jours

----------------

Consent

1825 jours

Relations à ajouter

Tenant

consents Consent[]
 
securityPolicies SecurityPolicy[]
 
risks Risk[]
 
complianceAudits ComplianceAudit[]
 
securityIncidents SecurityIncident[]
 
retentionPolicies RetentionPolicy[]

User

consents Consent[]
 
ownedRisks Risk[]
 
reportedIncidents SecurityIncident[]

Customer

consents Consent[]

Validation

npx prisma format
 
npx prisma validate
 
npx prisma generate

Migration

npx prisma migrate dev \
--name enterprise_security_compliance

Fonctionnalités couvertes

RGPD

Consentements

Traçabilité

Conservation

Export

Suppression

Sécurité

Politiques

Incidents

MFA

Gestion des risques

Gouvernance

Classification

Rétention

Audit

Conformité

État du schéma

Après Phase 2-L :

≈ 93 modèles Prisma

avec les domaines :

Core

Security

Properties

Owners

Customers

Reservations

Contracts

Payments

CRM

Messaging

Marketing

Automation

Governance

OTA

Revenue Management

Enterprise Security

Étape suivante

Phase 2-M

Internationalisation & Multi-régions

Country

Currency

Language

Timezone

CurrencyRate

Translation

Region

EnterpriseLicense

Cette phase couvrira :

  • Sprint 15 — Multi-sites & Réseau
  • Sprint 20 — Internationalisation
  • Multi-devises
  • Multi-langues
  • Multi-régions
  • Commercialisation internationale
ujusum/3-codage/1-repository/2-prisma-schema.1780851656.txt.gz · Dernière modification : 2026/06/07 19:00 de 91.170.108.99

DokuWiki Appliance - Powered by TurnKey Linux