--- title: Modèle de Données description: Structure et organisation des données --- ## 📊 Modèle de Données ### Conceptuel (MCD) Le Modèle Conceptuel de Données décrit les grandes entités du système et leurs relations métier, incluant la gestion des accès et la modération. ```mermaid erDiagram USER ||--o{ CONTENT : "publie" USER ||--o{ REPORT : "signale" USER ||--o{ USER_ROLE : "possede" USER ||--o{ SESSION : "detient" USER ||--o{ API_KEY : "genere" USER ||--o{ AUDIT_LOG : "genere" USER ||--o{ FAVORITE : "ajoute" USER ||--o{ COMMENT : "rédige" USER ||--o{ COMMENT_LIKE : "aime" USER ||--o{ CONVERSATION_PARTICIPANT : "participe" USER ||--o{ MESSAGE : "envoie" CONTENT ||--o{ CONTENT_TAG : "possede" TAG ||--o{ CONTENT_TAG : "est_lie_a" CONTENT ||--o{ REPORT : "est_signale" CONTENT ||--o{ FAVORITE : "est_mis_en" CONTENT ||--o{ COMMENT : "reçoit" TAG ||--o{ REPORT : "est_signale" COMMENT ||--o{ COMMENT : "possède des réponses" COMMENT ||--o{ COMMENT_LIKE : "est aimé par" CONVERSATION ||--o{ CONVERSATION_PARTICIPANT : "regroupe" CONVERSATION ||--o{ MESSAGE : "contient" CATEGORY ||--o{ CONTENT : "catégorise" ROLE ||--o{ USER_ROLE : "attribue_a" ROLE ||--o{ ROLE_PERMISSION : "possede" PERMISSION ||--o{ ROLE_PERMISSION : "est_lie_a" USER { string username string email string display_name string avatar_url string bio string status } CONTENT { string title string slug string type string storage_key } COMMENT { string text } CONVERSATION { timestamp created_at } MESSAGE { string text } TAG { string name string slug } ROLE { string name string slug } REPORT { string reason string status } SESSION { string refresh_token boolean is_valid } API_KEY { string name string prefix boolean is_active } AUDIT_LOG { string action string entity_type jsonb details } ``` ### Logique (MLD) Le Modèle Logique de Données précise les tables, les colonnes et les clés étrangères (FK). ```mermaid erDiagram users { uuid uuid PK varchar username bytea email varchar email_hash varchar display_name varchar avatar_url varchar bio varchar password_hash user_status status bytea two_factor_secret boolean is_two_factor_enabled varchar terms_version varchar privacy_version timestamp gdpr_accepted_at timestamp last_login_at timestamp created_at timestamp updated_at timestamp deleted_at } contents { uuid id PK uuid user_id FK uuid category_id FK content_type type varchar title varchar slug varchar storage_key varchar mime_type integer file_size integer views integer usage_count timestamp created_at timestamp updated_at timestamp deleted_at } categories { uuid id PK varchar name varchar slug varchar description varchar icon_url timestamp created_at timestamp updated_at } favorites { uuid user_id PK, FK uuid content_id PK, FK timestamp created_at } tags { uuid id PK varchar name varchar slug timestamp created_at timestamp updated_at } contents_to_tags { uuid content_id PK, FK uuid tag_id PK, FK } comments { uuid id PK uuid content_id FK uuid user_id FK uuid parent_id FK text text timestamp created_at timestamp updated_at timestamp deleted_at } comment_likes { uuid comment_id PK, FK uuid user_id PK, FK timestamp created_at } conversations { uuid id PK timestamp created_at timestamp updated_at } conversation_participants { uuid conversation_id PK, FK uuid user_id PK, FK timestamp joined_at } messages { uuid id PK uuid conversation_id FK uuid sender_id FK text text timestamp created_at timestamp read_at } roles { uuid id PK varchar name varchar slug varchar description timestamp created_at } permissions { uuid id PK varchar name varchar slug varchar description timestamp created_at } roles_to_permissions { uuid role_id PK, FK uuid permission_id PK, FK } users_to_roles { uuid user_id PK, FK uuid role_id PK, FK } reports { uuid id PK uuid reporter_id FK uuid content_id FK uuid tag_id FK report_reason reason text description report_status status timestamp expires_at timestamp created_at timestamp updated_at } sessions { uuid id PK uuid user_id FK varchar refresh_token varchar user_agent varchar ip_hash boolean is_valid timestamp expires_at timestamp created_at timestamp updated_at } api_keys { uuid id PK uuid user_id FK varchar key_hash varchar name varchar prefix boolean is_active timestamp last_used_at timestamp expires_at timestamp created_at timestamp updated_at } audit_logs { uuid id PK uuid user_id FK varchar action varchar entity_type uuid entity_id jsonb details varchar ip_hash varchar user_agent timestamp created_at } users ||--o{ favorites : "user_id" contents ||--o{ favorites : "content_id" categories ||--o{ contents : "category_id" users ||--o{ contents : "user_id" users ||--o{ users_to_roles : "user_id" roles ||--o{ users_to_roles : "role_id" roles ||--o{ roles_to_permissions : "role_id" permissions ||--o{ roles_to_permissions : "permission_id" contents ||--o{ contents_to_tags : "content_id" tags ||--o{ contents_to_tags : "tag_id" users ||--o{ reports : "reporter_id" contents ||--o{ reports : "content_id" tags ||--o{ reports : "tag_id" users ||--o{ sessions : "user_id" users ||--o{ api_keys : "user_id" users ||--o{ audit_logs : "user_id" contents ||--o{ comments : "content_id" users ||--o{ comments : "user_id" comments ||--o{ comments : "parent_id" comments ||--o{ comment_likes : "comment_id" users ||--o{ comment_likes : "user_id" conversations ||--o{ conversation_participants : "conversation_id" users ||--o{ conversation_participants : "user_id" conversations ||--o{ messages : "conversation_id" users ||--o{ messages : "sender_id" ``` ### Physique (MPD) Le Modèle Physique de Données détaille l'implémentation spécifique pour **PostgreSQL**. ```mermaid erDiagram users { uuid uuid "DEFAULT gen_random_uuid()" bytea email "ENCRYPTED, NOT NULL" varchar email_hash "UNIQUE, INDEXED" varchar username "UNIQUE, NOT NULL" varchar password_hash "NOT NULL" varchar avatar_url "NULLABLE" varchar bio "NULLABLE" bytea two_factor_secret "ENCRYPTED" boolean is_two_factor_enabled "DEFAULT false" timestamp gdpr_accepted_at "NULLABLE" timestamp deleted_at "SOFT DELETE" } contents { uuid id "DEFAULT gen_random_uuid()" uuid user_id "REFERENCES users(uuid)" varchar slug "UNIQUE, NOT NULL" varchar storage_key "UNIQUE, NOT NULL" integer file_size "NOT NULL" timestamp deleted_at "SOFT DELETE" } reports { uuid id "DEFAULT gen_random_uuid()" uuid reporter_id "REFERENCES users(uuid)" timestamp expires_at "RGPD PURGE" } api_keys { uuid id "DEFAULT gen_random_uuid()" varchar key_hash "UNIQUE, INDEXED, SHA-256" varchar prefix "NOT NULL" } audit_logs { uuid id "DEFAULT gen_random_uuid()" jsonb details "STORED AS JSONB" varchar ip_hash "RGPD COMPLIANT" } sessions { uuid id "DEFAULT gen_random_uuid()" varchar refresh_token "UNIQUE, NOT NULL" varchar ip_hash "RGPD COMPLIANT" } ``` #### Sécurité et Chiffrement - **Chiffrement PGP (Native)** : Les colonnes `email` et `two_factor_secret` sont stockées au format `bytea` et chiffrées/déchiffrées via les fonctions `pgp_sym_encrypt` et `pgp_sym_decrypt` de PostgreSQL (via l'extension `pgcrypto`). - **Cryptographie Post-Quantique** : Utilisation de la bibliothèque `@noble/post-quantum` pour anticiper les futures menaces cryptographiques. - **Hachage aveugle (Blind Indexing)** : La colonne `email_hash` stocke un hash (SHA-256) de l'email pour permettre les recherches d'unicité et les recherches rapides sans déchiffrer la donnée. #### Index et Optimisations - **Index B-Tree** systématiques sur toutes les clés étrangères (`user_id`, `role_id`, etc.). - **Index sur `deleted_at`** : Pour optimiser les requêtes excluant les données supprimées logiciellement. - **Index unique sur `email_hash`** et `username`. #### Conformité RGPD - **Soft Delete** : Implémenté via `deleted_at` pour permettre le "droit à l'oubli" tout en conservant l'intégrité référentielle temporaire. - **Purge Automatique** : La colonne `expires_at` dans la table `reports` permet de programmer la suppression automatique des données de signalement après traitement.