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])

Évolution future

Ces tables seront enrichies dans les prochains domaines :

Sprint 4

Reservation

ajoutera :

Property

↓

Reservations

Sprint 7

Owner

ajoutera :

PropertyOwner

OwnerDocuments

OwnerRevenue

Sprint 17

ajoutera :

DynamicPrice

PricingRule

RevenueSimulation

Sprint 18

ajoutera :

PropertyDistribution

OTA Mapping

Channel Publication

Validation

npx prisma format
 
npx prisma validate
 
npx prisma generate

Migration

npx prisma migrate dev \
--name property_catalog

Résultat

À ce stade, vous disposez enfin du premier domaine métier central de la plateforme :

Tenant

User

Role

Permission

Property

PropertyAddress

PropertyFeature

PropertyMedia

PropertyAvailability

PropertyRate

Toutes les futures fonctionnalités métier pourront désormais s'appuyer sur ce socle immobilier.

ujusum/3-codage/1-repository/2-prisma-schema.1780802082.txt.gz · Dernière modification : 2026/06/07 05:14 de 91.170.108.99 · Actuellement bloqué par : 192.168.0.100,216.73.216.72

DokuWiki Appliance - Powered by TurnKey Linux