# Modèle de données — SIOP V2 > **Rôle de ce document (playbook)** : le modèle est introduit **par release** (on ne > modélise pas ce qu'on ne construit pas). Chaque section explique les invariants et OÙ > ils vivent (base / service). La v1 sert de référence éprouvée pour les entités à venir. ## R0 — Identité & permissions ```prisma model Role { id String @id @default(uuid()) @db.Uuid name String @unique // Administrateur, Dispatcher, Technicien, users User[] // Technicien limité, Gestionnaire, permissions Permission[] // Demandeur, Vue seule } model Permission { // matrice rôles × objets × droits — EN BASE, jamais dans le JWT id String @id @default(uuid()) @db.Uuid roleId String @db.Uuid role Role @relation(...) objectCategory String // enum applicatif : WORK_ORDERS, ASSETS, … canView Boolean @default(false) canViewOther Boolean @default(false) // « voir autre » : au-delà de ses propres objets canCreate Boolean @default(false) canEdit Boolean @default(false) canDelete Boolean @default(false) @@unique([roleId, objectCategory]) } model User { id String @id @default(uuid()) @db.Uuid email String @unique displayName String passwordHash String? // null tant que le compte n'est pas activé (R1) roleId String @db.Uuid role Role @relation(...) isActive Boolean @default(true) isDemo Boolean @default(false) // seul un compte isDemo est empruntable (ADR-002) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } ``` **Invariants R0** : | Invariant | Où il vit | | --- | --- | | Un rôle par utilisateur ; la matrice décide de tout accès | `PermissionsGuard` (relit la base, cache 60 s) | | Le JWT ne porte jamais de droits (seulement l'identité + roleId) | conception auth | | `demo-login` refuse tout compte `isDemo=false` | service auth (+ test e2e) | | Matrice complète : chaque rôle a une ligne par catégorie d'objet | seed idempotent (+ test) | ## À venir (référence v1 éprouvée, sera réintroduit release par release) - **R1** : `Location` (hiérarchie + colonne PostGIS), `Asset` + organes (hiérarchie 2 niveaux, CHECK « un organe n'a pas d'emplacement propre »), `Category`, `Team`. - **R2** : `WorkOrder` (machine à états stricte, priorité « personne bloquée »), `Request` (lien 1-1 vers OT), `InterventionReport` (bilan codé 6 champs → `ReferenceValue`), `TaskTemplate`/`PreventivePlan`/`ChecklistItem` (périodicité calendrier), `Meter`. - **R3** : `Part`/`StockMovement` (stock **dérivé des mouvements**), `PurchaseOrder`, `Partner`, `LaborTime` (taux figé), `Document`. - **R4** : `WorkOrder.version` (verrou optimiste de la synchro mobile). - **R5** : tables d'embeddings pgvector (côté service IA). ## Journal des migrations | # | Migration | Contenu | | --- | --- | --- | | 1 | `r0_identity` | Role, Permission, User (+ index & uniques ci-dessus) |