Includes detailed sections on architecture, stack, data model, security measures, deployment procedures, compliance (GDPR), and API integrations.
258 lines
7.0 KiB
Plaintext
258 lines
7.0 KiB
Plaintext
---
|
|
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"
|
|
|
|
CONTENT ||--o{ CONTENT_TAG : "possede"
|
|
TAG ||--o{ CONTENT_TAG : "est_lie_a"
|
|
CONTENT ||--o{ REPORT : "est_signale"
|
|
TAG ||--o{ REPORT : "est_signale"
|
|
|
|
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 status
|
|
}
|
|
CONTENT {
|
|
string title
|
|
string type
|
|
string storage_key
|
|
}
|
|
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 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
|
|
content_type type
|
|
varchar title
|
|
varchar storage_key
|
|
varchar mime_type
|
|
integer file_size
|
|
timestamp created_at
|
|
timestamp updated_at
|
|
timestamp deleted_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
|
|
}
|
|
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{ 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"
|
|
```
|
|
|
|
### 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"
|
|
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 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`).
|
|
- **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.
|