docs: migrer schémas BDD de Mermaid vers DBML

Remplace les diagrammes Mermaid par DBML (via kroki-dbml) pour
une meilleure expressivité des schémas de base de données :
- Ajout support notes, contraintes et indexes détaillés
- Migration de tous les schémas d'entités partagées
- Ajout fichier exemple dbml-example.md
- Configuration plugin mkdocs-kroki pour rendu DBML
This commit is contained in:
jpgiannetti
2026-02-12 20:49:02 +01:00
parent ae2fc3ee6f
commit 23fe67470b
16 changed files with 566 additions and 224 deletions

View File

@@ -137,6 +137,10 @@ make docs-pdf # Generate PDF of all documentation
make docs-clean # Remove generated docs and PDF make docs-clean # Remove generated docs and PDF
``` ```
**First run**: The first `make docs-serve` will build a custom Docker image with mkdocs-kroki-plugin. This takes ~30s but is cached for subsequent runs.
**DBML Support**: The documentation now supports DBML (Database Markup Language) for database diagrams via the Kroki plugin. Use `kroki-dbml` code blocks in markdown files. See [docs/examples/dbml-example.md](docs/examples/dbml-example.md) for examples.
## Working with sqlc ## Working with sqlc
When adding or modifying database queries: When adding or modifying database queries:

View File

@@ -4,22 +4,37 @@
## Diagramme ## Diagramme
```mermaid ```kroki-dbml
erDiagram Table users {
USERS ||--o| ACCOUNT_DELETIONS : "demande" id uuid [primary key]
email varchar(255)
status varchar(20)
}
ACCOUNT_DELETIONS { Table account_deletions {
uuid id PK id uuid [primary key]
uuid user_id FK user_id uuid [not null, unique, ref: - users.id, note: 'One-to-one: un user ne peut avoir qu une seule demande active']
string status status deletion_status_enum [not null, default: 'pending']
string cancellation_token cancellation_token varchar(64) [unique, note: 'Token dans email pour annuler (expire après 30j)']
timestamp requested_at requested_at timestamp [not null, default: `now()`]
timestamp effective_at "requested_at + 30j" effective_at timestamp [not null, note: 'Auto-calculated: requested_at + 30 days']
timestamp cancelled_at cancelled_at timestamp [note: 'Timestamp annulation via lien email (NULL si non annulé)']
timestamp deleted_at deleted_at timestamp [note: 'Timestamp suppression effective (NULL si pending/cancelled)']
string deletion_reason deletion_reason text [note: 'Raison optionnelle fournie par l utilisateur']
json deleted_data_summary deleted_data_summary jsonb [note: 'Résumé des données supprimées (audit trail)']
indexes {
(user_id) [unique]
(status, effective_at) [note: 'Daily cron job: WHERE status = pending AND effective_at < NOW()']
(cancellation_token) [unique]
} }
}
Enum deletion_status_enum {
pending [note: 'Grace period actif (30j), compte désactivé, annulation possible']
cancelled [note: 'Utilisateur a annulé via lien email']
completed [note: 'Suppression effective réalisée après 30j']
}
``` ```
## Légende ## Légende

View File

@@ -4,33 +4,57 @@
## Diagramme ## Diagramme
```mermaid ```kroki-dbml
erDiagram Table breach_incidents {
BREACH_INCIDENTS ||--o{ BREACH_AFFECTED_USERS : "impacte" id uuid [primary key]
USERS ||--o{ BREACH_AFFECTED_USERS : "est impacté" severity breach_severity_enum [not null]
description text [not null, note: 'Description détaillée de l incident']
data_categories_affected jsonb [not null, note: 'Array: ["gps", "email", "listening_history"]']
estimated_users_count int [not null, note: 'Estimation nombre users impactés']
detected_at timestamp [not null, default: `now()`, note: 'H+0: Détection initiale']
contained_at timestamp [note: 'Timestamp confinement de la faille']
cnil_notified_at timestamp [note: 'H+48: Notification CNIL si requis']
users_notified_at timestamp [note: 'H+72: Notification users si risque élevé']
mitigation_actions text [note: 'Actions correctives mises en place']
cnil_notification_required boolean [not null, default: false]
user_notification_required boolean [not null, default: false]
BREACH_INCIDENTS { indexes {
uuid id PK (severity, detected_at) [note: 'Incidents par gravité et chronologie']
string severity "low/medium/high/critical" (cnil_notification_required, cnil_notified_at) [note: 'Track CNIL notification compliance']
text description
json data_categories_affected
int estimated_users_count
timestamp detected_at
timestamp contained_at
timestamp cnil_notified_at
timestamp users_notified_at
text mitigation_actions
boolean cnil_notification_required
boolean user_notification_required
} }
}
BREACH_AFFECTED_USERS { Table users {
uuid id PK id uuid [primary key]
uuid breach_id FK }
uuid user_id FK
timestamp notified_at Table breach_affected_users {
string notification_channel "email/push/sms" id uuid [primary key]
breach_id uuid [not null, ref: > breach_incidents.id]
user_id uuid [not null, ref: > users.id]
notified_at timestamp [note: 'Timestamp notification user (NULL si pas encore notifié)']
notification_channel notification_channel_enum [note: 'Canal utilisé pour notifier']
indexes {
(breach_id, user_id) [unique, note: 'Un user ne peut être listé qu une fois par incident']
(breach_id, notified_at) [note: 'Track notification progress']
(user_id) [note: 'Historique incidents pour un user']
} }
}
Enum breach_severity_enum {
low [note: 'Pas de notification requise (mesures techniques suffisantes)']
medium [note: 'Notification CNIL uniquement']
high [note: 'Notification CNIL + utilisateurs']
critical [note: 'Notification immédiate tous canaux + SMS fondateur']
}
Enum notification_channel_enum {
email [note: 'Email notification']
push [note: 'Push notification mobile']
sms [note: 'SMS (critical only)']
}
``` ```
## Légende ## Légende

View File

@@ -4,20 +4,33 @@
## Diagramme ## Diagramme
```mermaid ```kroki-dbml
erDiagram Table users {
USERS ||--o{ USER_CONSENTS : "donne" id uuid [primary key]
}
USER_CONSENTS { Table user_consents {
uuid id PK id uuid [primary key]
uuid user_id FK user_id uuid [not null, ref: > users.id]
string consent_type consent_type consent_type_enum [not null]
string consent_version consent_version varchar(10) [not null, note: 'Format: v1.0, v2.0, etc.']
boolean accepted accepted boolean [not null, note: 'true = opted-in, false = opted-out']
timestamp given_at given_at timestamp [not null, default: `now()`]
inet ip_address ip_address inet [not null, note: 'Proof of consent for CNIL audits']
string user_agent user_agent text [not null, note: 'Device/browser proof']
indexes {
(user_id, consent_type, consent_version) [note: 'Latest consent per type']
(user_id, given_at) [note: 'Consent history timeline']
} }
}
Enum consent_type_enum {
geolocation_precise [note: 'Géolocalisation GPS précise (obligatoire pour contenu hyperlocal)']
analytics [note: 'Analytics Matomo (optionnel)']
push_notifications [note: 'Notifications push (optionnel)']
cookies_analytics [note: 'Cookies analytiques (optionnel)']
}
``` ```
## Légende ## Légende

View File

@@ -4,18 +4,28 @@
## Diagramme ## Diagramme
```mermaid ```kroki-dbml
erDiagram Table data_retention_logs {
DATA_RETENTION_LOGS { id uuid [primary key]
uuid id PK action_type retention_action_enum [not null]
string action_type users_processed int [not null, default: 0, note: 'Nombre total users analysés']
int users_processed users_warned int [not null, default: 0, note: 'Nombre users notifiés (90j/30j/7j)']
int users_warned users_deleted int [not null, default: 0, note: 'Nombre users supprimés effectivement']
int users_deleted details jsonb [note: 'Détails: threshold_date, user_ids_deleted, notifications_sent']
json details executed_at timestamp [not null, default: `now()`, note: 'Timestamp exécution du job cron']
timestamp executed_at execution_duration_ms bigint [not null, note: 'Durée d exécution en millisecondes']
bigint execution_duration_ms
indexes {
(action_type, executed_at) [note: 'Historique jobs par type']
(executed_at) [note: 'Timeline complète des jobs']
} }
}
Enum retention_action_enum {
check_inactive [note: 'Vérification quotidienne comptes inactifs > 5 ans']
send_warnings [note: 'Envoi notifications (90j/30j/7j avant suppression)']
delete_accounts [note: 'Suppression effective comptes inactifs']
}
``` ```
## Légende ## Légende

View File

@@ -4,26 +4,43 @@
## Diagramme ## Diagramme
```mermaid ```kroki-dbml
erDiagram Table users {
USERS ||--o{ DEVICES : "possède" id uuid [primary key]
DEVICES ||--o{ SESSIONS : "a" }
DEVICES { Table devices {
uuid id PK id uuid [primary key]
uuid user_id FK user_id uuid [not null, ref: > users.id]
string device_name device_name varchar(255) [note: 'User-defined device name']
string os os varchar(50) [note: 'iOS, Android, Windows, macOS, Linux']
string browser browser varchar(50) [note: 'Safari, Chrome, Firefox, etc.']
string device_type device_type device_type_enum [not null, note: 'mobile, tablet, desktop, car']
boolean is_trusted is_trusted boolean [not null, default: false, note: 'Bypass 2FA for 30 days if true']
timestamp trusted_until trusted_until timestamp [note: 'NULL if not trusted, expires after 30 days']
timestamp first_seen_at first_seen_at timestamp [not null, default: `now()`]
timestamp last_seen_at last_seen_at timestamp [not null, default: `now()`]
inet last_ip last_ip inet [not null]
string last_city last_city varchar(100)
string last_country_code last_country_code char(2)
indexes {
(user_id, last_seen_at) [note: 'List user devices by recent activity']
(user_id, is_trusted) [note: 'Find trusted devices for user']
} }
}
Table sessions {
id uuid [primary key]
device_id uuid [ref: > devices.id]
}
Enum device_type_enum {
mobile [note: 'Smartphone Android/iOS']
tablet [note: 'Tablette']
desktop [note: 'Ordinateur']
car [note: 'Système embarqué (CarPlay/Android Auto)']
}
``` ```
## Légende ## Légende

View File

@@ -4,22 +4,43 @@
## Diagramme ## Diagramme
```mermaid ```kroki-dbml
erDiagram Table users {
USERS ||--o{ DATA_EXPORTS : "demande" id uuid [primary key]
}
DATA_EXPORTS { Table data_exports {
uuid id PK id uuid [primary key]
uuid user_id FK user_id uuid [not null, ref: > users.id]
string status status export_status_enum [not null, default: 'pending']
string export_url export_url varchar(512) [note: 'S3/CDN signed URL (NULL until generated)']
bigint size_bytes size_bytes bigint [note: 'File size in bytes (NULL until generated)']
string format format export_format_enum [not null, default: 'json']
timestamp requested_at requested_at timestamp [not null, default: `now()`]
timestamp generated_at generated_at timestamp [note: 'When export file was created (NULL if pending/generating)']
timestamp expires_at expires_at timestamp [note: 'Auto-calculated: generated_at + 7 days']
timestamp downloaded_at downloaded_at timestamp [note: 'First download timestamp (NULL if not yet downloaded)']
indexes {
(user_id, requested_at) [note: 'User export history']
(status, requested_at) [note: 'Background worker queue (WHERE status = pending)']
(expires_at) [note: 'Daily cleanup job (DELETE WHERE expires_at < NOW())']
} }
}
Enum export_status_enum {
pending [note: 'Demande en file d attente']
generating [note: 'Génération en cours (worker background)']
ready [note: 'Export disponible au téléchargement']
downloaded [note: 'Export téléchargé par l utilisateur']
expired [note: 'Export expiré (supprimé automatiquement)']
}
Enum export_format_enum {
json [note: 'Machine-readable (données brutes)']
html [note: 'Human-readable (page web stylée)']
zip [note: 'Archive complète (JSON + HTML + audio files)']
}
``` ```
## Légende ## Légende

View File

@@ -4,18 +4,37 @@
## Diagramme ## Diagramme
```mermaid ```kroki-dbml
erDiagram Table users {
USERS ||--o{ INTEREST_GAUGES : "possède" id uuid [primary key]
}
INTEREST_GAUGES { Table interest_gauges {
uuid id PK id uuid [primary key]
uuid user_id FK user_id uuid [not null, ref: > users.id]
string category category interest_category_enum [not null]
decimal score score decimal(5,2) [not null, default: 0, note: 'Range: 0.00 to 100.00']
timestamp last_updated last_updated timestamp [not null, default: `now()`]
int interactions_count interactions_count int [not null, default: 0, note: 'Total interactions for this category']
indexes {
(user_id, category) [unique, note: 'One gauge per user per category']
(user_id, score) [note: 'Order categories by score for recommendations']
} }
}
Enum interest_category_enum {
automobile [note: 'Voitures, mécanique, course automobile']
travel [note: 'Voyages, tourisme, découverte']
music [note: 'Musique, concerts, artistes']
news [note: 'Actualités, politique, économie']
sport [note: 'Sports, événements sportifs']
culture [note: 'Cinéma, livres, expositions']
food [note: 'Gastronomie, restaurants, recettes']
tech [note: 'Technologie, innovation, gadgets']
history [note: 'Histoire, patrimoine, musées']
nature [note: 'Nature, randonnée, écologie']
}
``` ```
## Légende ## Légende

View File

@@ -4,22 +4,37 @@
## Diagramme ## Diagramme
```mermaid ```kroki-dbml
erDiagram Table users {
USERS ||--o{ LOCATION_HISTORY : "génère" id uuid [primary key]
}
LOCATION_HISTORY { Table location_history {
uuid id PK id uuid [primary key]
uuid user_id FK user_id uuid [not null, ref: > users.id]
geography location location geography [note: 'PostGIS geography type: POINT with SRID 4326 (WGS84)']
string geohash geohash varchar(12) [note: 'Precision 5 geohash (~5km²) after anonymization']
boolean anonymized anonymized boolean [not null, default: false, note: 'true after 24h auto-anonymization']
string context context location_context_enum [not null]
float speed_kmh speed_kmh float [note: 'GPS speed in km/h (NULL if stationary)']
float accuracy_meters accuracy_meters float [not null, note: 'GPS accuracy radius in meters']
timestamp created_at created_at timestamp [not null, default: `now()`]
timestamp anonymized_at anonymized_at timestamp [note: 'When precise location was replaced by geohash']
indexes {
(user_id, created_at) [note: 'User location timeline']
(created_at, anonymized) [note: 'Daily anonymization job (WHERE anonymized = false AND created_at < NOW() - 24h)']
(location) [type: gist, note: 'PostGIS spatial index for proximity queries']
(geohash) [note: 'Analytics queries on anonymized data']
} }
}
Enum location_context_enum {
listening [note: 'Position pendant écoute de contenu']
search [note: 'Position lors d une recherche']
background [note: 'Tracking en arrière-plan']
manual [note: 'Position partagée manuellement']
}
``` ```
## Légende ## Légende

View File

@@ -4,34 +4,45 @@
## Diagramme ## Diagramme
```mermaid ```kroki-dbml
erDiagram Table users {
USERS ||--o{ PARENTAL_CONSENTS : "a" id uuid [primary key]
PARENTAL_CONSENTS ||--|| PARENTAL_CONTROLS : "configure" birthdate date [not null]
}
PARENTAL_CONSENTS { Table parental_consents {
uuid id PK id uuid [primary key]
uuid user_id FK "Ado 13-15 ans" user_id uuid [not null, unique, ref: > users.id, note: 'Ado 13-15 ans (1 consent par user max)']
string parent_email parent_email varchar(255) [not null, note: 'Email du parent pour validation']
string validation_token validation_token varchar(64) [unique, note: 'Token de validation envoyé par email (expire 7j)']
boolean validated validated boolean [not null, default: false, note: 'true après clic parent sur lien email']
timestamp token_expires_at token_expires_at timestamp [not null, note: 'validation_token expire après 7 jours']
timestamp validated_at validated_at timestamp [note: 'Timestamp de validation parent (NULL si non validé)']
inet parent_ip parent_ip inet [note: 'IP du parent lors de la validation']
string parent_user_agent parent_user_agent text [note: 'User agent parent (preuve validation)']
timestamp revoked_at revoked_at timestamp [note: 'Révocation du consentement parental']
string revocation_reason revocation_reason text [note: 'Raison de la révocation (optionnel)']
}
PARENTAL_CONTROLS { indexes {
uuid id PK (user_id) [unique, note: 'Un seul consentement parental actif par user']
uuid parental_consent_id FK (validation_token) [unique, note: 'Lookup rapide pour validation lien email']
boolean gps_enabled (validated, token_expires_at) [note: 'Cleanup des tokens expirés non validés']
boolean messaging_enabled
boolean content_16plus_enabled
json weekly_digest_config
timestamp updated_at
} }
}
Table parental_controls {
id uuid [primary key]
parental_consent_id uuid [not null, unique, ref: - parental_consents.id, note: 'One-to-one relationship']
gps_enabled boolean [not null, default: false, note: 'Autoriser GPS précis (false = GeoIP uniquement)']
messaging_enabled boolean [not null, default: false, note: 'Autoriser messagerie privée']
content_16plus_enabled boolean [not null, default: false, note: 'Autoriser contenu 16+']
weekly_digest_config jsonb [note: 'Config notifications hebdo parent (email, contenu, format)']
updated_at timestamp [not null, default: `now()`]
indexes {
(parental_consent_id) [unique]
}
}
``` ```
## Légende ## Légende

View File

@@ -4,29 +4,40 @@
## Diagramme ## Diagramme
```mermaid ```kroki-dbml
erDiagram Table privacy_policy_versions {
PRIVACY_POLICY_VERSIONS ||--o{ USER_POLICY_ACCEPTANCES : "acceptée par" id uuid [primary key]
USERS ||--o{ USER_POLICY_ACCEPTANCES : "accepte" version varchar(10) [not null, unique, note: 'Format: v1.0, v2.0, etc.']
content_markdown text [not null, note: 'Source: docs/legal/politique-confidentialite.md (versionné Git)']
major_change boolean [not null, default: false, note: 'true = popup obligatoire pour tous les users']
changelog text [not null, note: 'Résumé des changements pour communication']
effective_date timestamp [not null, note: 'Date d entrée en vigueur de cette version']
created_at timestamp [not null, default: `now()`]
PRIVACY_POLICY_VERSIONS { indexes {
uuid id PK (version) [unique]
string version "v1.0, v2.0, etc." (effective_date) [note: 'Order versions chronologically']
text content_markdown
boolean major_change
text changelog
timestamp effective_date
timestamp created_at
} }
}
USER_POLICY_ACCEPTANCES { Table users {
uuid id PK id uuid [primary key]
uuid user_id FK }
uuid policy_version_id FK
boolean accepted Table user_policy_acceptances {
timestamp accepted_at id uuid [primary key]
inet ip_address user_id uuid [not null, ref: > users.id]
policy_version_id uuid [not null, ref: > privacy_policy_versions.id]
accepted boolean [not null, note: 'true = accepté, false = refusé (compte gelé)']
accepted_at timestamp [not null, default: `now()`]
ip_address inet [not null, note: 'IP de l utilisateur lors de l acceptation (preuve CNIL)']
indexes {
(user_id, policy_version_id) [unique, note: 'Un user ne peut accepter qu une fois une version']
(user_id, accepted_at) [note: 'Historique acceptations user']
(policy_version_id) [note: 'Count acceptances par version']
} }
}
``` ```
## Légende ## Légende

View File

@@ -4,26 +4,67 @@
## Diagramme ## Diagramme
```mermaid ```kroki-dbml
erDiagram Table users {
USERS ||--o{ REPORTS : "signale" id uuid [primary key]
CONTENTS ||--o{ REPORTS : "reçoit" username varchar(50)
USERS ||--o{ REPORTS : "modère" }
REPORTS { Table contents {
uuid id PK id uuid [primary key]
uuid content_id FK title varchar(255)
uuid reporter_id FK user_id uuid [not null]
uuid moderator_id FK }
string category
string status Table reports {
text comment id uuid [primary key]
string evidence_url content_id uuid [not null, ref: > contents.id, note: 'Content being reported']
timestamp reported_at reporter_id uuid [not null, ref: > users.id, note: 'User who filed the report']
timestamp reviewed_at moderator_id uuid [ref: > users.id, note: 'Moderator assigned to review (NULL if pending)']
text moderator_notes category report_category_enum [not null]
string action_taken status report_status_enum [not null, default: 'pending']
comment text [note: 'Reporter explanation (mandatory for "other" category)']
evidence_url varchar(512) [note: 'Screenshot or additional proof URL']
reported_at timestamp [not null, default: `now()`]
reviewed_at timestamp [note: 'When moderator reviewed the report']
moderator_notes text [note: 'Internal moderator notes']
action_taken report_action_enum [note: 'Action decided by moderator']
indexes {
(content_id, status) [note: 'Find all reports for a content']
(status, reported_at) [note: 'Queue for moderators (pending first)']
(reporter_id) [note: 'User report history (detect abuse)']
(moderator_id) [note: 'Reports assigned to moderator']
} }
}
Enum report_category_enum {
spam [note: 'Contenu publicitaire non sollicité']
hate_speech [note: 'Discours haineux, discrimination']
violence [note: 'Violence explicite']
sexual_content [note: 'Contenu sexuel inapproprié']
misinformation [note: 'Désinformation, fake news']
copyright [note: 'Violation de droits d auteur']
wrong_age_rating [note: 'Classification d âge incorrecte']
other [note: 'Autre raison (commentaire obligatoire)']
}
Enum report_status_enum {
pending [note: 'En attente de revue']
under_review [note: 'En cours d examen par modérateur']
actioned [note: 'Action prise (contenu retiré/édité)']
dismissed [note: 'Signalement rejeté (contenu valide)']
duplicate [note: 'Doublon d un signalement existant']
}
Enum report_action_enum {
content_removed [note: 'Contenu supprimé']
content_edited [note: 'Métadonnées modifiées (âge, tags)']
warning_sent [note: 'Avertissement au créateur']
strike_issued [note: 'Strike ajouté au créateur']
account_suspended [note: 'Compte créateur suspendu']
no_action [note: 'Aucune action (signalement infondé)']
}
``` ```
## Légende ## Légende

View File

@@ -4,27 +4,43 @@
## Diagramme ## Diagramme
```mermaid ```kroki-dbml
erDiagram Table users {
USERS ||--o{ SESSIONS : "possède" id uuid [primary key]
DEVICES ||--o{ SESSIONS : "associé" email varchar(255) [not null, unique]
username varchar(50) [not null, unique]
}
SESSIONS { Table devices {
uuid id PK id uuid [primary key]
uuid user_id FK user_id uuid [not null, ref: > users.id]
uuid device_id FK device_name varchar(255)
string access_token_hash device_type varchar(50)
string refresh_token_hash }
timestamp access_token_expires_at
timestamp refresh_token_expires_at Table sessions {
inet ip_address id uuid [primary key]
string user_agent user_id uuid [not null, ref: > users.id]
string city device_id uuid [ref: > devices.id]
string country_code access_token_hash varchar(64) [not null, note: 'SHA256 hash, never stored in clear']
timestamp created_at refresh_token_hash varchar(64) [not null, note: 'SHA256 hash, auto-rotated']
timestamp last_activity_at access_token_expires_at timestamp [not null, note: 'Lifetime: 15 minutes']
timestamp revoked_at refresh_token_expires_at timestamp [not null, note: 'Lifetime: 30 days (rolling)']
ip_address inet [not null]
user_agent text [not null]
city varchar(100)
country_code char(2)
created_at timestamp [not null, default: `now()`]
last_activity_at timestamp [not null, default: `now()`]
revoked_at timestamp [note: 'NULL if active, timestamp if manually revoked']
indexes {
(user_id, revoked_at) [note: 'Find active sessions for user']
(device_id)
(refresh_token_hash) [unique, note: 'Detect replay attacks']
(last_activity_at) [note: 'Auto-cleanup inactive sessions']
} }
}
``` ```
## Légende ## Légende

View File

@@ -4,20 +4,44 @@
## Diagramme ## Diagramme
```mermaid ```kroki-dbml
erDiagram Table users {
USERS ||--o{ USER_PROFILE_HISTORY : "modifie" id uuid [primary key]
email varchar(255)
username varchar(50)
bio text
}
USER_PROFILE_HISTORY { Table user_profile_history {
uuid id PK id uuid [primary key]
uuid user_id FK user_id uuid [not null, ref: > users.id]
string field_name "email/username/bio/etc." field_name profile_field_enum [not null, note: 'Champ modifié (email, username, bio, etc.)']
text old_value old_value text [note: 'Valeur avant modification (NULL si création)']
text new_value new_value text [not null, note: 'Nouvelle valeur']
string change_reason "user_edit/admin_correction/gdpr_request" change_reason change_reason_enum [not null]
inet ip_address ip_address inet [not null, note: 'IP de l origine du changement']
timestamp changed_at changed_at timestamp [not null, default: `now()`]
indexes {
(user_id, changed_at) [note: 'Timeline modifications user (ordre chronologique)']
(field_name, changed_at) [note: 'Track modifications par type de champ']
(user_id, field_name) [note: 'Historique d un champ spécifique']
} }
}
Enum profile_field_enum {
email [note: 'Re-vérification requise après changement']
username [note: 'Limite: 1 changement/30j']
bio [note: 'Biographie utilisateur']
avatar_url [note: 'URL de l avatar']
date_of_birth [note: 'Date de naissance']
}
Enum change_reason_enum {
user_edit [note: 'Modification self-service utilisateur']
admin_correction [note: 'Correction par admin (via backoffice)']
gdpr_request [note: 'Suite demande RGPD formelle (droit de rectification)']
}
``` ```
## Légende ## Légende

View File

@@ -0,0 +1,95 @@
# Exemple DBML avec Kroki
Ce fichier montre comment utiliser DBML dans la documentation MkDocs avec le plugin Kroki.
## Syntaxe de base
Pour créer un diagramme de base de données DBML, utilisez un bloc de code avec la balise `kroki-dbml` :
## Exemple : Schéma utilisateurs et contenus
```kroki-dbml
Table users {
id uuid [primary key]
email varchar(255) [not null, unique]
username varchar(50) [not null, unique]
password_hash varchar(255) [not null]
created_at timestamp [not null, default: `now()`]
updated_at timestamp [not null, default: `now()`]
indexes {
(email) [unique]
(username) [unique]
}
}
Table contents {
id uuid [primary key]
user_id uuid [not null, ref: > users.id]
title varchar(255) [not null]
description text
audio_url varchar(512) [not null]
location geography(POINT, 4326) [note: 'PostGIS geography type']
duration_seconds int [not null]
category content_category [not null]
status content_status [not null, default: 'draft']
created_at timestamp [not null, default: `now()`]
published_at timestamp
indexes {
(user_id)
(status)
(location) [type: gist, note: 'Spatial index']
(created_at)
}
}
Table interest_gauges {
id uuid [primary key]
user_id uuid [not null, ref: > users.id]
category varchar(50) [not null]
score decimal(5,2) [not null, default: 0, note: 'Score 0-100']
last_updated timestamp [not null, default: `now()`]
indexes {
(user_id, category) [unique]
}
}
Enum content_category {
"automobile"
"travel"
"music"
"culture"
"sport"
"education"
}
Enum content_status {
"draft"
"published"
"archived"
"moderated"
}
```
## Avantages de DBML
- ✅ **Syntaxe claire** : Plus lisible que Mermaid pour les schémas BDD
- ✅ **Types PostGIS** : Peut documenter les types spéciaux (geography, geometry)
- ✅ **Index et contraintes** : Documentation complète des index et contraintes
- ✅ **Relations** : Relations explicites entre tables
- ✅ **Enums** : Support natif des types énumérés
- ✅ **Notes** : Annotations directement dans le schéma
## Utilisation dans votre projet
Pour documenter vos schémas de base de données dans RoadWave :
1. Créez vos fichiers `.md` dans `docs/domains/<domain>/`
2. Ajoutez des blocs `kroki-dbml` pour les schémas
3. Le rendu sera automatique lors de `make docs-serve`
## Référence DBML
Consultez la [documentation DBML officielle](https://dbml.dbdiagram.io/docs/) pour la syntaxe complète.

View File

@@ -35,6 +35,12 @@ theme:
plugins: plugins:
- search: - search:
lang: fr lang: fr
- kroki:
ServerURL: https://kroki.io
EnableBlockDiag: true
Enablebpmn: true
EnableExcalidraw: true
EnableMermaid: true
# - glightbox: # Lightbox pour agrandir les images (désactivé temporairement) # - glightbox: # Lightbox pour agrandir les images (désactivé temporairement)
markdown_extensions: markdown_extensions: