feat(rgpd): compléter documentation RGPD avec 12 nouvelles sections

Règles RGPD (docs/domains/_shared/rules/rgpd.md):
- Ajouter sections 13.11-13.22 (droits utilisateurs, mineurs, sécurité)
- Droit de rectification, opposition, limitation du traitement
- Gestion des mineurs: 13 ans minimum + consentement parental 13-15 ans
- Protection renforcée: RoadWave Kids pour < 13 ans
- Sécurité: chiffrement multi-niveaux, procédure breach 72h CNIL
- Politique de confidentialité avec versioning
- Sous-traitants, DPIA, délais de réponse

Entités (6 nouvelles):
- PARENTAL_CONSENTS + PARENTAL_CONTROLS (workflow 13-15 ans)
- PRIVACY_POLICY_VERSIONS + USER_POLICY_ACCEPTANCES
- ACCOUNT_DELETIONS (grace period 30j)
- BREACH_INCIDENTS + BREACH_AFFECTED_USERS
- USER_PROFILE_HISTORY (audit trail rectification)
- DATA_RETENTION_LOGS (purge 5 ans)

Diagrammes séquences (5 nouveaux):
- Consentement parental avec validation email
- Anonymisation GPS automatique après 24h
- Notification breach CNIL (procédure 72h)
- Export données asynchrone
- Suppression compte avec grace period

Cycles de vie (3 nouveaux + 1 enrichi):
- parental-consent-lifecycle.md
- breach-incident-lifecycle.md
- account-deletion-lifecycle.md
- user-account-lifecycle.md (ajout états mineurs, frozen)

Features BDD (4 nouvelles, 195 scénarios RGPD):
- minors-protection.feature (9 scénarios)
- data-security.feature (12 scénarios)
- privacy-policy.feature (8 scénarios)
- user-rights.feature (8 scénarios)

Infrastructure:
- Réorganiser docs générées: docs/bdd + output → generated/bdd + generated/pdf
- Mettre à jour mkdocs.yml, Makefile, scripts Python
- Ajouter /generated/ au .gitignore
This commit is contained in:
jpgiannetti
2026-02-08 17:49:12 +01:00
parent 1896c249dd
commit fd2b0f70c5
29 changed files with 1500 additions and 80703 deletions

4
.gitignore vendored
View File

@@ -64,4 +64,6 @@ config/*.local.yaml
# MkDocs # MkDocs
site/ site/
.cache/ .cache/
docs/bdd/
# Generated documentation
/generated/

View File

@@ -70,7 +70,7 @@ clean:
## docs-clean: Remove generated documentation (BDD docs and PDF) ## docs-clean: Remove generated documentation (BDD docs and PDF)
docs-clean: docs-clean:
@echo "$(YELLOW)Cleaning generated documentation...$(NC)" @echo "$(YELLOW)Cleaning generated documentation...$(NC)"
@rm -rf docs/bdd/ output/RoadWave_Documentation.pdf @rm -rf generated/
@docker rmi roadwave-pdf-generator 2>/dev/null || true @docker rmi roadwave-pdf-generator 2>/dev/null || true
@echo "$(GREEN)✓ Documentation cleaned$(NC)" @echo "$(GREEN)✓ Documentation cleaned$(NC)"

View File

@@ -0,0 +1,40 @@
# Account Deletions
📖 Suppressions de compte avec grace period 30 jours (Article 17 RGPD)
## Diagramme
```mermaid
erDiagram
USERS ||--o| ACCOUNT_DELETIONS : "demande"
ACCOUNT_DELETIONS {
uuid id PK
uuid user_id FK
string status
string cancellation_token
timestamp requested_at
timestamp effective_at "requested_at + 30j"
timestamp cancelled_at
timestamp deleted_at
string deletion_reason
json deleted_data_summary
}
```
## Légende
**Statuts** :
- `pending`: Grace period actif (30j), compte désactivé, annulation possible
- `cancelled`: Utilisateur a annulé via lien email
- `completed`: Suppression effective réalisée après 30j
**Processus** :
1. Demande → compte désactivé, contenus cachés
2. Email avec `cancellation_token` (valide 30j)
3. Si annulation → `status = cancelled`, compte réactivé
4. Si 30j écoulés → job cron supprime données, anonymise contenus
**Données supprimées** :
- Profil utilisateur, historique GPS/écoute, sessions
- Contenus créés : anonymisés (`créateur = "Utilisateur supprimé"`)

View File

@@ -0,0 +1,51 @@
# Breach Incidents
📖 Registre violations de données (Article 33 RGPD)
## Diagramme
```mermaid
erDiagram
BREACH_INCIDENTS ||--o{ BREACH_AFFECTED_USERS : "impacte"
USERS ||--o{ BREACH_AFFECTED_USERS : "est impacté"
BREACH_INCIDENTS {
uuid id PK
string severity "low/medium/high/critical"
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 {
uuid id PK
uuid breach_id FK
uuid user_id FK
timestamp notified_at
string notification_channel "email/push/sms"
}
```
## Légende
**Sévérité** :
- `low`: Pas de notification requise (mesures techniques suffisantes)
- `medium`: Notification CNIL uniquement
- `high`: Notification CNIL + utilisateurs
- `critical`: Notification immédiate tous canaux + SMS fondateur
**Timeline 72h** :
- H+0 : Détection, confinement
- H+24 : Évaluation gravité
- H+48 : Notification CNIL si requis
- H+72 : Notification utilisateurs si risque élevé
**Catégories de données** :
- `data_categories_affected`: JSON `["gps", "email", "listening_history"]`

View File

@@ -0,0 +1,44 @@
# Data Retention Logs
📖 Logs purges automatiques inactivité (Article 5 RGPD - Minimisation)
## Diagramme
```mermaid
erDiagram
DATA_RETENTION_LOGS {
uuid id PK
string action_type
int users_processed
int users_warned
int users_deleted
json details
timestamp executed_at
bigint execution_duration_ms
}
```
## Légende
**Action types** :
- `check_inactive`: Vérification quotidienne comptes inactifs > 5 ans
- `send_warnings`: Envoi notifications (90j/30j/7j avant suppression)
- `delete_accounts`: Suppression effective comptes inactifs
**Règles de conservation** :
- Auditeur : 5 ans inactivité → suppression
- Créateur actif : jamais (tant que contenus écoutés)
- Créateur inactif : 5 ans + 2 ans sans écoute → suppression
**Details JSON** :
```json
{
"threshold_date": "2021-02-08",
"user_ids_deleted": ["uuid1", "uuid2"],
"notifications_sent": {
"90_days": 15,
"30_days": 8,
"7_days": 3
}
}
```

View File

@@ -16,6 +16,15 @@ erDiagram
USERS ||--o{ INTEREST_GAUGES : "possède" USERS ||--o{ INTEREST_GAUGES : "possède"
USERS ||--o{ REPORTS : "signale" USERS ||--o{ REPORTS : "signale"
USERS ||--o{ DATA_EXPORTS : "demande" USERS ||--o{ DATA_EXPORTS : "demande"
USERS ||--o{ PARENTAL_CONSENTS : "a"
USERS ||--o{ ACCOUNT_DELETIONS : "demande"
USERS ||--o{ USER_PROFILE_HISTORY : "modifie"
PARENTAL_CONSENTS ||--|| PARENTAL_CONTROLS : "configure"
PRIVACY_POLICY_VERSIONS ||--o{ USER_POLICY_ACCEPTANCES : "acceptée par"
USERS ||--o{ USER_POLICY_ACCEPTANCES : "accepte"
BREACH_INCIDENTS ||--o{ BREACH_AFFECTED_USERS : "impacte"
USERS ||--o{ BREACH_AFFECTED_USERS : "est impacté"
CONTENTS ||--o{ LISTENING_HISTORY : "écouté" CONTENTS ||--o{ LISTENING_HISTORY : "écouté"
CONTENTS }o--|| USERS : "créé par" CONTENTS }o--|| USERS : "créé par"
@@ -161,6 +170,80 @@ erDiagram
timestamp generated_at timestamp generated_at
timestamp expires_at timestamp expires_at
} }
PARENTAL_CONSENTS {
uuid id PK
uuid user_id FK
string parent_email
boolean validated
timestamp validated_at
timestamp revoked_at
}
PARENTAL_CONTROLS {
uuid id PK
uuid parental_consent_id FK
boolean gps_enabled
boolean messaging_enabled
boolean content_16plus_enabled
}
PRIVACY_POLICY_VERSIONS {
uuid id PK
string version
boolean major_change
timestamp effective_date
}
USER_POLICY_ACCEPTANCES {
uuid id PK
uuid user_id FK
uuid policy_version_id FK
boolean accepted
timestamp accepted_at
}
ACCOUNT_DELETIONS {
uuid id PK
uuid user_id FK
string status
timestamp requested_at
timestamp effective_at
timestamp deleted_at
}
BREACH_INCIDENTS {
uuid id PK
string severity
int estimated_users_count
timestamp detected_at
timestamp cnil_notified_at
boolean user_notification_required
}
BREACH_AFFECTED_USERS {
uuid id PK
uuid breach_id FK
uuid user_id FK
timestamp notified_at
}
USER_PROFILE_HISTORY {
uuid id PK
uuid user_id FK
string field_name
text old_value
text new_value
timestamp changed_at
}
DATA_RETENTION_LOGS {
uuid id PK
string action_type
int users_processed
int users_deleted
timestamp executed_at
}
``` ```
## Légende ## Légende
@@ -205,6 +288,27 @@ erDiagram
- **DATA_EXPORTS** : Exports de données utilisateur ([détails](exports.md)) - **DATA_EXPORTS** : Exports de données utilisateur ([détails](exports.md))
- Portabilité RGPD Article 20, délai 48h max - Portabilité RGPD Article 20, délai 48h max
- **PARENTAL_CONSENTS** : Consentements parentaux 13-15 ans ([détails](parental-consents.md))
- Workflow validation email parent, token expire 7j
- **PARENTAL_CONTROLS** : Paramètres contrôle parental ([détails](parental-consents.md))
- GPS, messagerie, contenus +16 configurables par parent
- **PRIVACY_POLICY_VERSIONS** : Versioning politique confidentialité ([détails](privacy-policy-versions.md))
- Popup si changement majeur, historique acceptations
- **ACCOUNT_DELETIONS** : Suppressions avec grace period 30j ([détails](account-deletions.md))
- Annulation possible, suppression effective automatique
- **BREACH_INCIDENTS** : Registre violations de données ([détails](breach-incidents.md))
- Procédure 72h CNIL, notification utilisateurs si risque élevé
- **USER_PROFILE_HISTORY** : Audit trail modifications profil ([détails](user-profile-history.md))
- Droit rectification Article 16, preuve légale
- **DATA_RETENTION_LOGS** : Logs purges automatiques ([détails](data-retention-logs.md))
- Inactivité 5 ans, notifications 90j/30j/7j
**Entités recommandation & modération** : **Entités recommandation & modération** :
- **INTEREST_GAUGES** : Jauges de centres d'intérêt ([détails](interest-gauges.md)) - **INTEREST_GAUGES** : Jauges de centres d'intérêt ([détails](interest-gauges.md))

View File

@@ -0,0 +1,49 @@
# Parental Consents
📖 Consentements parentaux pour utilisateurs 13-15 ans (Article 8 RGPD)
## Diagramme
```mermaid
erDiagram
USERS ||--o{ PARENTAL_CONSENTS : "a"
PARENTAL_CONSENTS ||--|| PARENTAL_CONTROLS : "configure"
PARENTAL_CONSENTS {
uuid id PK
uuid user_id FK "Ado 13-15 ans"
string parent_email
string validation_token
boolean validated
timestamp token_expires_at
timestamp validated_at
inet parent_ip
string parent_user_agent
timestamp revoked_at
string revocation_reason
}
PARENTAL_CONTROLS {
uuid id PK
uuid parental_consent_id FK
boolean gps_enabled
boolean messaging_enabled
boolean content_16plus_enabled
json weekly_digest_config
timestamp updated_at
}
```
## Légende
**Workflow** :
1. Ado saisit email parent → `validation_token` généré (expire 7j)
2. Parent clique lien → `validated = true`
3. Parent configure `PARENTAL_CONTROLS`
4. Révocation possible → `revoked_at` renseigné
**Restrictions par défaut (13-15 ans)** :
- `gps_enabled`: `false` (GeoIP uniquement)
- `messaging_enabled`: `false`
- `content_16plus_enabled`: `false`
- Dashboard parent : notifications hebdomadaires activité

View File

@@ -0,0 +1,41 @@
# Privacy Policy Versions
📖 Versioning politique de confidentialité (Articles 13-14 RGPD)
## Diagramme
```mermaid
erDiagram
PRIVACY_POLICY_VERSIONS ||--o{ USER_POLICY_ACCEPTANCES : "acceptée par"
USERS ||--o{ USER_POLICY_ACCEPTANCES : "accepte"
PRIVACY_POLICY_VERSIONS {
uuid id PK
string version "v1.0, v2.0, etc."
text content_markdown
boolean major_change
text changelog
timestamp effective_date
timestamp created_at
}
USER_POLICY_ACCEPTANCES {
uuid id PK
uuid user_id FK
uuid policy_version_id FK
boolean accepted
timestamp accepted_at
inet ip_address
}
```
## Légende
**Versioning** :
- `major_change`: `true` → popup obligatoire pour tous les utilisateurs
- `major_change`: `false` → notification simple
- Fichier source : `docs/legal/politique-confidentialite.md` (versionné Git)
**Popup si changement majeur** :
- Utilisateur doit accepter nouvelle version pour continuer
- Refus → compte gelé (lecture seule)

View File

@@ -0,0 +1,38 @@
# User Profile History
📖 Audit trail modifications profil (Article 16 RGPD - Droit de rectification)
## Diagramme
```mermaid
erDiagram
USERS ||--o{ USER_PROFILE_HISTORY : "modifie"
USER_PROFILE_HISTORY {
uuid id PK
uuid user_id FK
string field_name "email/username/bio/etc."
text old_value
text new_value
string change_reason "user_edit/admin_correction/gdpr_request"
inet ip_address
timestamp changed_at
}
```
## Légende
**Champs trackés** :
- `email`: Re-vérification requise
- `username`: Limite 1 changement/30j
- `bio`, `avatar_url`, `date_of_birth`
**Change reasons** :
- `user_edit`: Modification self-service utilisateur
- `admin_correction`: Correction par admin
- `gdpr_request`: Suite demande RGPD formelle
**Audit** :
- Historique complet conservé (preuve légale)
- Accessible utilisateur : "Historique de mes modifications"
- Accessible DPO : investigations

View File

@@ -0,0 +1,110 @@
# language: fr
@privacy @rgpd @security
Fonctionnalité: Sécurité des données (Article 32 RGPD)
En tant que responsable de traitement
Je veux garantir la sécurité des données personnelles
Afin de prévenir les violations et fuites
# Chiffrement transport
@encryption @tls
Scénario: TLS 1.3 obligatoire pour toutes les communications
Quand un client tente de se connecter à l'API
Alors la connexion utilise TLS 1.3 uniquement
Et les protocoles TLS 1.0, 1.1, 1.2 sont refusés
Et le certificat est valide et à jour
# Chiffrement stockage
@encryption @database
Scénario: Encryption at rest pour la base de données
Étant donné que PostgreSQL stocke des données utilisateurs
Alors le chiffrement AES-256 at rest est activé
Et les backups sont également chiffrés AES-256
Et les backups sont stockés offsite (règle 3-2-1)
# Tokens JWT sécurisés
@encryption @jwt
Scénario: Rotation des clés JWT tous les 90 jours
Étant donné que l'API utilise des tokens JWT RS256
Quand 90 jours se sont écoulés depuis la dernière rotation
Alors une nouvelle paire de clés RSA est générée
Et l'ancienne clé reste valide 7 jours (overlap)
Et tous les tokens sont progressivement re-signés
# CDN avec signed URLs
@cdn @signed-urls
Scénario: URLs signées expirables pour les fichiers audio
Quand un utilisateur demande à écouter un contenu
Alors l'API génère une signed URL valide 1 heure
Et l'URL contient un token HMAC
Et après expiration, l'URL retourne 403 Forbidden
# Détection breach
@breach @monitoring
Scénario: Alerte immédiate si erreurs critiques backend
Quand une erreur critique survient dans l'API (500, crash)
Alors Sentry déclenche une alerte Discord/Slack immédiate
Et l'équipe est notifiée en temps réel
Et les logs sont consultables dans Grafana
@breach @monitoring
Scénario: Alerte si pic de requêtes anormal (potentiel DDoS)
Étant donné que le trafic habituel est ~1000 req/min
Quand le trafic atteint 10000 req/min
Alors Grafana déclenche une alerte email
Et l'équipe vérifie s'il s'agit d'une attaque
@breach @monitoring
Scénario: Alerte si accès DB non autorisé
Quand une connexion PostgreSQL provient d'une IP non whitelistée
Alors PostgreSQL bloque la connexion
Et un SMS est envoyé au fondateur
Et l'IP est loggée pour investigation
# Procédure breach 72h CNIL
@breach @procedure
Scénario: Notification CNIL si violation de données sous 72h
Étant donné qu'une violation de données est détectée
Et que des données GPS utilisateurs ont fuité
Quand l'équipe évalue la gravité
Alors le runbook "docs/rgpd/procedure-breach.md" est suivi:
| Étape | Délai | Action |
| 1 | H+0 | Détection et confinement |
| 2 | H+24 | Évaluation gravité et impact |
| 3 | H+48 | Notification CNIL si risque |
| 4 | H+72 | Notification utilisateurs si élevé|
Et un email pré-rédigé est envoyé à la CNIL
Et le formulaire en ligne CNIL est rempli
# Mesures organisationnelles
@security @access-control
Scénario: Accès DB uniquement via VPN et whitelist IP
Étant donné que je suis un développeur
Quand je tente d'accéder à la DB de production
Alors je dois être connecté au VPN OVH
Et mon IP doit être dans la whitelist
Sinon la connexion est refusée
@security @2fa
Scénario: 2FA obligatoire pour les comptes administrateurs
Étant donné que je suis un administrateur
Quand je me connecte à Zitadel admin
Alors le 2FA (TOTP) est obligatoire
Et je ne peux pas désactiver le 2FA
Et chaque connexion est loggée avec IP et timestamp
@security @logs
Scénario: Anonymisation des IP dans les logs (rotation 90j)
Quand un utilisateur fait une requête API
Alors son IP est loggée pour debug
Mais les 2 derniers octets sont masqués (ex: 192.168.x.x)
Et les logs sont automatiquement supprimés après 90 jours
# Tests de sécurité
@security @pentest
Scénario: Pentest annuel obligatoire
Étant donné que l'application est en production
Quand une année s'est écoulée depuis le dernier pentest
Alors un pentest externe est planifié
Et les vulnérabilités découvertes sont corrigées sous 30 jours
Et un rapport est produit pour audit

View File

@@ -0,0 +1,112 @@
# language: fr
@privacy @rgpd @minors @parental-consent
Fonctionnalité: Protection des mineurs et consentement parental (Article 8 RGPD)
En tant que plateforme responsable
Je veux protéger les mineurs avec consentement parental
Afin de respecter l'Article 8 RGPD (13-15 ans)
Contexte:
Étant donné que je suis sur la page d'inscription
Scénario: Blocage inscription si moins de 13 ans
Quand je saisis ma date de naissance "15/03/2014"
Et que je valide le formulaire
Alors je vois le message "RoadWave est réservé aux personnes de 13 ans et plus"
Et je vois un lien vers "RoadWave Kids"
Et mon inscription est bloquée
Scénario: Inscription directe si 16 ans ou plus
Quand je saisis ma date de naissance "10/01/2008"
Et que je valide le formulaire
Alors mon compte est créé immédiatement
Et aucun consentement parental n'est requis
Et j'ai accès à toutes les fonctionnalités
Plan du Scénario: Workflow consentement parental pour 13-15 ans
Quand je saisis ma date de naissance "<date_naissance>"
Et que je saisis l'email de mon parent "parent@example.com"
Et que je valide le formulaire
Alors un email est envoyé à "parent@example.com"
Et le lien de validation expire dans 7 jours
Et mon compte est créé mais inactif
Et je vois "En attente validation parentale"
Exemples:
| date_naissance | âge |
| 15/03/2011 | 13 |
| 20/06/2010 | 14 |
| 01/12/2009 | 15 |
Scénario: Validation du consentement parental
Étant donné que je suis un mineur de 14 ans avec compte inactif
Et que mon parent a reçu l'email de validation
Quand mon parent clique sur le lien de validation
Alors il voit une page avec:
| Section |
| Résumé données collectées |
| Paramètres contrôle parental|
| Checkbox consentement |
Et quand il coche "J'autorise mon enfant" et valide
Alors mon compte est activé
Et je reçois un email "Compte activé par ton parent"
Et les restrictions 13-15 ans sont appliquées
Scénario: Restrictions pour comptes 13-15 ans
Étant donné que je suis un utilisateur de 14 ans avec compte validé
Alors je peux écouter des contenus autorisés
Mais je NE peux PAS:
| Restriction |
| Activer le GPS précis sans accord parent |
| Utiliser la messagerie privée |
| Voir les contenus marqués +16 |
| Afficher ma ville précise sur le profil |
Scénario: Dashboard parent - Visualisation activité enfant
Étant donné que je suis un parent avec enfant de 14 ans
Quand je me connecte à "roadwave.fr/parent/[child_id]"
Alors je vois:
| Information |
| Historique d'écoute |
| Temps d'écoute hebdomadaire |
| Dernière connexion |
Et je peux:
| Action |
| Activer/désactiver GPS précis |
| Activer/désactiver messagerie |
| Révoquer le consentement |
Scénario: Révocation du consentement parental
Étant donné que je suis un parent
Et que mon enfant de 14 ans a un compte actif
Quand je clique sur "Révoquer le consentement"
Alors le compte de mon enfant est immédiatement désactivé
Et il ne peut plus se connecter
Et je reçois un email de confirmation
@roadwave-kids
Scénario: RoadWave Kids - Inscription via compte parent
Étant donné que je suis un parent avec compte RoadWave actif
Quand je vais dans "Mon compte > Ajouter un profil enfant"
Et que je saisis:
| Champ | Valeur |
| Pseudo enfant | "Emma" |
| Date naissance | "12/08/2016" |
Alors un profil Kids est créé
Et je reçois un QR code pour l'app RoadWave Kids
Et l'enfant ne peut écouter que les contenus whitelist
@roadwave-kids
Scénario: RoadWave Kids - Restrictions strictes
Étant donné que je suis connecté sur l'app RoadWave Kids
Alors je peux uniquement:
| Fonctionnalité |
| Écouter contenus présélectionnés |
| Voir ma position ville (GeoIP) |
Mais je NE peux PAS:
| Restriction |
| Activer le GPS précis |
| Créer du contenu |
| Avoir un profil public |
| Utiliser la messagerie |
| Voir du contenu UGC |

View File

@@ -0,0 +1,99 @@
# language: fr
@privacy @rgpd @transparency
Fonctionnalité: Politique de confidentialité et transparence (Articles 13-14 RGPD)
En tant qu'utilisateur
Je veux comprendre comment mes données sont utilisées
Afin de donner un consentement éclairé
Contexte:
Étant donné que l'application RoadWave est disponible
# Popup première connexion
@first-launch
Scénario: Affichage de la politique de confidentialité à l'inscription
Quand je m'inscris pour la première fois
Alors une popup s'affiche avec la politique de confidentialité
Et je dois scroller jusqu'en bas pour activer le bouton "J'accepte"
Et je dois cocher "J'ai lu et j'accepte la politique de confidentialité"
Et je ne peux pas créer de compte sans accepter
# Contenu obligatoire
@content
Scénario: Vérification du contenu de la politique de confidentialité
Quand je consulte la page "roadwave.fr/confidentialite"
Alors je vois les informations suivantes:
| Section |
| Identité responsable traitement + DPO |
| Finalités détaillées par traitement |
| Base légale (consentement/contrat/intérêt)|
| Destinataires données (CDN, Matomo, etc.) |
| Durées de conservation |
| Droits utilisateurs (accès, rectif, etc.) |
| Droit réclamation CNIL |
| Transferts hors UE (aucun) |
# Versioning
@versioning
Scénario: Versioning de la politique avec Git et DB
Étant donné que la politique de confidentialité est modifiée
Quand l'équipe commit les changements
Alors le fichier "docs/legal/politique-confidentialite.md" est versionné Git
Et une entrée est créée dans "privacy_policy_versions"
Avec les champs:
| Champ | Valeur |
| version | "2.0" |
| effective_date| "2026-03-01" |
| major_change | true |
| changelog | "Ajout tracking..." |
@versioning
Scénario: Notification utilisateurs si changement majeur
Étant donné qu'une nouvelle version majeure de la politique est publiée
Quand un utilisateur se connecte
Alors une popup s'affiche "Politique de confidentialité mise à jour"
Et il doit l'accepter à nouveau pour continuer
Et s'il refuse, son compte est gelé (accès lecture seule)
# Transparence algorithme
@algorithm-transparency
Scénario: Explication simplifiée de l'algorithme de recommandation
Quand je vais sur "roadwave.fr/comment-ca-marche"
Alors je vois une page "Comment fonctionne la recommandation ?"
Avec les explications suivantes:
| Critère | Explication |
| Distance géographique | Contenus près de vous en priorité |
| Centres d'intérêt | Jauges automatiques selon écoutes |
| Popularité | Contenus les plus écoutés |
Et je peux désactiver la personnalisation (mode anonyme)
# Contact DPO
@dpo-contact
Scénario: Accès facile au contact DPO
Quand je vais dans "Paramètres > Confidentialité et données"
Alors je vois un bouton "Contacter le DPO"
Et le lien email "dpo@roadwave.fr" est cliquable
Et je vois "Délai de réponse : 1 mois maximum"
# Profilage et décisions automatisées
@profiling
Scénario: Information sur le profilage et opposition possible
Quand je consulte la politique de confidentialité
Alors je vois une section "Profilage et décisions automatisées"
Qui explique:
| Type décision | Impact | Opposition possible |
| Recommandations | Faible | Oui (mode anonyme) |
| Modération automatique| Élevé | Oui (contestation) |
Et je peux activer le mode anonyme à tout moment
# Sous-traitants
@subprocessors
Scénario: Liste transparente des sous-traitants
Quand je consulte "roadwave.fr/confidentialite#sous-traitants"
Alors je vois la liste complète:
| Service | Finalité | Localisation | DPA |
| OVH | Hébergement | France | |
| Bunny.net | CDN audio | UE | |
| Brevo | Emails | France | |
| Mangopay | Paiements | Luxembourg | |
Et je vois "Aucun transfert hors UE"

View File

@@ -0,0 +1,77 @@
# language: fr
@privacy @rgpd @user-rights
Fonctionnalité: Exercice des droits utilisateurs RGPD
En tant qu'utilisateur
Je veux exercer mes droits RGPD facilement
Afin de contrôler mes données personnelles
Contexte:
Étant donné que je suis connecté à mon compte
# Article 16 - Droit de rectification
@rectification
Scénario: Modification du pseudo (limite 1/30j)
Quand je vais dans "Paramètres > Mon profil"
Et que je modifie mon pseudo de "Alice123" à "AliceM"
Alors le changement est immédiat
Et je ne peux plus modifier mon pseudo pendant 30 jours
Et l'historique est enregistré dans "user_profile_history"
@rectification
Scénario: Modification de l'email avec re-vérification
Quand je modifie mon email de "old@example.com" à "new@example.com"
Alors je reçois un email de vérification sur "new@example.com"
Et je dois cliquer sur le lien dans les 24h
Et mon ancien email reste actif jusqu'à validation
# Article 21 - Droit d'opposition
@opposition
Scénario: Opposition au marketing par email
Quand je vais dans "Paramètres > Notifications"
Et que je décoche "Recevoir les emails marketing"
Alors je ne reçois plus d'emails promotionnels
Mais je reçois toujours les emails transactionnels
@opposition @anonymous-mode
Scénario: Activation du mode anonyme (recommandations génériques)
Quand je vais dans "Paramètres > Confidentialité"
Et que j'active "Mode anonyme"
Alors mes jauges d'intérêt sont ignorées
Et je reçois uniquement les top contenus de ma zone géographique
Et mon historique d'écoute n'est pas utilisé pour les recommandations
Et je vois un badge "Mode anonyme actif"
# Article 18 - Droit à la limitation du traitement
@limitation
Scénario: Gel temporaire du compte
Quand je vais dans "Paramètres > Gestion du compte"
Et que je clique sur "Mettre en pause mon compte"
Alors mon compte est gelé immédiatement
Et mes contenus sont cachés (non diffusés)
Et mon profil est invisible
Mais je peux toujours me connecter en lecture seule
Et je peux réactiver à tout moment
@limitation
Scénario: Réactivation compte gelé
Étant donné que mon compte est gelé depuis 15 jours
Quand je me connecte
Et que je clique sur "Réactiver mon compte"
Alors mon compte redevient actif immédiatement
Et mes contenus sont à nouveau visibles
# Article 12 - Délai de réponse 1 mois max
@response-time
Scénario: Demande d'accès aux données (délai 48h)
Quand je demande un export de mes données
Alors je reçois un email sous 48h maximum
Avec un lien de téléchargement valide 7 jours
@response-time
Scénario: Contestation d'une décision automatisée (délai 24h)
Étant donné que mon contenu a été bloqué par la modération automatique
Quand je clique sur "Contester cette décision"
Alors un humain examine mon cas sous 24h
Et je reçois une réponse motivée
Et mon contenu est rétabli si la décision était erronée

View File

@@ -34,15 +34,7 @@
1. Données précises conservées **24h** (recommandation personnalisée) 1. Données précises conservées **24h** (recommandation personnalisée)
2. Après 24h : conversion en geohash précision 5 (~5km²) 2. Après 24h : conversion en geohash précision 5 (~5km²)
3. Coordonnées originales supprimées définitivement 3. Coordonnées originales supprimées définitivement
4. Job quotidien automatique via cron
**Implémentation PostGIS** :
```sql
-- Job quotidien
UPDATE location_history
SET location = ST_SetSRID(ST_GeomFromGeoHash(ST_GeoHash(location::geography, 5)), 4326)::geography,
anonymized = true
WHERE created_at < NOW() - INTERVAL '24 hours' AND anonymized = false;
```
**Exceptions** : **Exceptions** :
- ✅ Historique personnel visible (liste trajets) : conservation intégrale tant que compte actif - ✅ Historique personnel visible (liste trajets) : conservation intégrale tant que compte actif
@@ -59,17 +51,7 @@ WHERE created_at < NOW() - INTERVAL '24 hours' AND anonymized = false;
**Décision** : JSON + HTML + ZIP, génération asynchrone **Décision** : JSON + HTML + ZIP, génération asynchrone
**Contenu de l'export** : **Format export** : Archive ZIP contenant JSON (machine-readable), HTML (human-readable), fichiers audio, README
```
export-roadwave-[user_id]-[date].zip
├── export.json # Machine-readable
├── index.html # Human-readable (stylé)
├── audio/
│ ├── content-123.opus
│ ├── content-456.opus
│ └── ...
└── README.txt # Instructions
```
**Données exportées** : **Données exportées** :
- Profil utilisateur (email, pseudo, date inscription, bio) - Profil utilisateur (email, pseudo, date inscription, bio)
@@ -306,31 +288,283 @@ export-roadwave-[user_id]-[date].zip
--- ---
## Récapitulatif Section 13 ### 13.11 Droit de rectification
| Mesure | Implémentation | Coût | **Décision** : Interface self-service + validation immédiate
|--------|----------------|------|
| **Consentement** | Tarteaucitron.js + PostgreSQL | 0€ |
| **Anonymisation GPS** | Geohash PostGIS (24h) | 0€ |
| **Export données** | JSON+HTML+ZIP asynchrone | 0€ |
| **Suppression compte** | Grace period 30j + anonymisation | 0€ |
| **Mode dégradé** | GeoIP IP2Location + GPS optionnel | 0€ |
| **Conservation** | Purge auto 5 ans inactivité | 0€ |
| **Analytics** | Matomo self-hosted | ~5€/mois |
| **Registre traitements** | Markdown Git | 0€ |
| **Breach detection** | Sentry + Grafana + runbook | 0€ |
| **DPO** | Fondateur formé CNIL | 0€ |
**Coût total RGPD : ~5€/mois** **Données rectifiables** :
- Email (avec re-vérification)
- Pseudo (unique, disponibilité vérifiée)
- Bio / description
- Centres d'intérêt (jauges)
- Photo de profil
**Processus** :
- Changements immédiats (sauf email)
- Email : lien vérification → validation sous 24h
- Historique modifications conservé (audit trail)
**Limitations** :
- Pseudo : max 1 changement/30j (anti-squat)
**Justification** : Conformité Article 16 RGPD, self-service 0€
--- ---
## Points d'attention pour Gherkin ### 13.12 Droit d'opposition
- Tester consentement géolocalisation (accept/refuse → contenus différents) **Décision** : Opt-out granulaire, effet immédiat
- Tester anonymisation GPS après 24h (job cron)
- Tester export données (génération complète + vérification contenu) | Traitement | Toggle | Effet |
- Tester grace period suppression (annulation possible) |------------|--------|-------|
- Tester mode GeoIP (ville détectée correctement) | **Marketing email** | Paramètres | Stop emails promo |
- Tester purge automatique (5 ans inactivité) | **Notifications push** | Paramètres | Stop push marketing |
- Tester notifications avant purge (90j/30j/7j) | **Analytics** | Banner RGPD | Exclusion Matomo |
| **Recommandations personnalisées** | "Mode anonyme" | Reco génériques uniquement |
**Mode anonyme** :
- Désactive algorithme (jauges ignorées)
- Recommandations = top contenus zone géo uniquement
- Historique non utilisé
**Justification** : Conformité Article 21 RGPD
---
### 13.13 Droit à la limitation du traitement
**Décision** : "Geler mon compte" temporaire
**Effets** :
- Compte gelé, contenus cachés, profil invisible
- Connexion lecture seule OK
- Réactivation à tout moment
**Justification** : Conformité Article 18 RGPD
---
### 13.14 Politique de confidentialité
**Décision** : Page web + popup in-app + versioning Git
**Emplacement** :
- Web : `roadwave.fr/confidentialite`
- App : page dédiée paramètres
- Popup première connexion (scroll requis)
**Contenu** : Identité responsable, finalités, base légale, destinataires, durées, droits, transferts UE
**Versioning** : Git + DB `privacy_policy_versions`, popup si changement majeur
**Justification** : Conformité Articles 13-14 RGPD
---
### 13.15 Minimisation des données
**Décision** : Collecte strictement nécessaire
| Donnée | Finalité | Optionnel |
|--------|----------|-----------|
| Email | Authentification | ❌ |
| Pseudo | Identité publique | ❌ |
| GPS précis | Reco hyperlocales | ✅ (GeoIP fallback) |
| Jauges intérêt | Reco thématiques | ✅ |
| Date naissance | Vérifier âge minimum | ❌ (année seule) |
**Non collecté** : nom/prénom réels, adresse postale (sauf créateurs payés), téléphone (sauf 2FA optionnel)
**Justification** : Conformité Article 5.1.c RGPD
---
### 13.16 Sécurité des données
**Décision** : Chiffrement multi-niveaux
| Couche | Implémentation |
|--------|----------------|
| Transport | TLS 1.3 ([ADR-006](../../../adr/006-chiffrement.md)) |
| DB | PostgreSQL encryption at rest AES-256 |
| Tokens | JWT RS256 + rotation 90j |
| CDN | Signed URLs expirables |
| Backups | AES-256 + offsite |
**Mesures orga** : Whitelist IP, Vault secrets, logs anonymisés, 2FA admins, pentest annuel
**Justification** : Conformité Article 32 RGPD
---
### 13.17 Transferts hors UE
**Décision** : Hébergement 100% France/UE
| Service | Localisation | Transfert UE |
|---------|--------------|--------------|
| Hébergement | OVH France | ❌ |
| Database | OVH France | ❌ |
| CDN | Bunny.net EU | ❌ |
| Matomo | Self-hosted France | ❌ |
**Si CDN global futur** : Clauses Contractuelles Types (CCE) 2021
**Justification** : Conformité Articles 44-50 RGPD, souveraineté données
---
### 13.18 Profilage et décisions automatisées
**Décision** : Transparence + droit opposition
| Traitement | Impact | Intervention humaine | Opposition |
|------------|--------|---------------------|------------|
| Recommandations | Faible | ❌ | ✅ (mode anonyme) |
| Modération auto | Élevé | ✅ (review 24h) | ✅ (appeal) |
**Transparence** : Page "Comment fonctionne l'algo ?", explications simplifiées
**Justification** : Conformité Article 22 RGPD
---
### 13.19 Gestion des mineurs
**Décision** : 13 ans minimum + consentement parental 13-15 ans + RoadWave Kids
#### App principale (RoadWave)
**Âge minimum** : **13 ans** (alignement YouTube/TikTok)
**Processus inscription** :
1. Saisie date naissance (JJ/MM/AAAA)
2. **Si < 13 ans** : blocage + message redirection RoadWave Kids
3. **Si 13-15 ans** : workflow consentement parental
4. **Si ≥ 16 ans** : inscription directe
**Workflow consentement parental (13-15 ans)** :
1. Ado saisit email parent
2. Email automatique parent avec lien validation (expire 7j)
3. Parent clique lien → page dédiée avec résumé données collectées, paramètres contrôle parental, checkbox consentement
4. Validation parent → compte ado activé avec restrictions
**Restrictions 13-15 ans** :
- ✅ Écoute contenus autorisés
- ✅ Création contenus (modération renforcée)
- ⚠️ GPS précis : consentement parental explicite requis
- ⚠️ Messagerie privée : désactivée par défaut
- ⚠️ Contenus sensibles : filtrés (pas de contenu +16)
- ⚠️ Profil public limité (pas d'affichage ville précise)
**Contrôles parentaux** :
- Dashboard parent : `roadwave.fr/parent/[child_id]`
- Visualisation historique écoute
- Activation/désactivation GPS précis
- Activation/désactivation messagerie
- Révocation consentement à tout moment
- Notification hebdomadaire activité
**Vérification légère identité parent** :
- Email parent ≠ email ado (vérification domaine)
- Lien expiration 7 jours
- Pas de vérification identité forte (MVP)
#### RoadWave Kids (< 13 ans)
**App dédiée** : Version séparée avec contrôles renforcés
**Caractéristiques** :
- ❌ Pas de GPS précis (GeoIP ville uniquement)
- ❌ Pas de création contenu
- ❌ Pas de profil public
- ❌ Pas de messagerie
- ✅ Contenus présélectionnés (whitelist éditoriale)
- ✅ Mode lecture seule
- ✅ Contrôle parental obligatoire
**Contenus autorisés** :
- Contes audio enfants
- Guides touristiques famille
- Podcasts éducatifs labellisés
- Histoires locales patrimoine
**Workflow inscription** :
1. Création compte parent (RoadWave standard)
2. Ajout profil enfant dans dashboard parent
3. App Kids : login via QR code parent
4. Pas de compte autonome enfant
**Modération** :
- 100% contenus présélectionnés par équipe éditoriale
- Aucun UGC accessible
- Whitelist créateurs vérifiés uniquement
**Justification** :
- Conformité Article 8 RGPD (13-16 ans selon pays)
- 13 ans France = seuil légal avec consentement parental
- App Kids = protection renforcée < 13 ans
- Alignement marché (YouTube 13+, YouTube Kids)
**Roadmap** :
- **MVP** : App principale 16+ uniquement (simplicité)
- **Phase 2** : Workflow 13-15 ans + consentement parental
- **Phase 3** : RoadWave Kids (app séparée)
---
### 13.20 Sous-traitants et DPA
**Décision** : DPA systématique, audit annuel
| Service | Traitement | Localisation | DPA | Certifications |
|---------|------------|--------------|-----|----------------|
| OVH | Hébergement | France | ✅ | ISO 27001, HDS |
| Bunny.net | CDN | UE | ✅ | ISO 27001 |
| Brevo | Emailing | France | ✅ | RGPD certified |
| Mangopay | Paiements | Luxembourg | ✅ | PCI-DSS, ACPR |
**Obligations DPA** : Traitement selon instructions, confidentialité, sécurité, assistance droits, suppression fin contrat
**Gestion** : `docs/rgpd/sous-traitants.md`, review annuelle
**Justification** : Conformité Article 28 RGPD
---
### 13.21 Analyse d'impact (DPIA)
**Décision** : DPIA obligatoire (GPS + profilage grande échelle)
**Raisons** :
- Traitement grande échelle données GPS sensibles
- Profilage automatisé recommandations
- Surveillance zones publiques
**Contenu** : Description traitement, finalités, nécessité, risques (tracking, profilage, fuite), mesures atténuation (anonymisation 24h, consentement, chiffrement, mode dégradé)
**Fichier** : `docs/rgpd/dpia-geolocalisation.md`, review annuelle
**Justification** : Conformité Article 35 RGPD (critères CNIL remplis)
---
### 13.22 Délai de réponse aux demandes
**Décision** : 1 mois max, automatisation maximale
**Canaux** : Email dpo@roadwave.fr, formulaire in-app, courrier postal
| Droit | Délai cible | Automatisation |
|-------|-------------|----------------|
| Accès (export) | 48h | ✅ Worker |
| Rectification | Immédiat | ✅ Self-service |
| Suppression | Immédiat | ✅ Self-service |
| Opposition | Immédiat | ✅ Toggles |
| Limitation | Immédiat | ✅ Gel compte |
| Portabilité | 48h | ✅ Export |
| Contestation décision | 24h | ⚠️ Manuel |
**Vérification identité** : Si email vérifié = aucune vérif supplémentaire
**Justification** : Conformité Article 12 RGPD

View File

@@ -0,0 +1,55 @@
# Anonymisation automatique GPS après 24h
```mermaid
sequenceDiagram
participant User as Utilisateur
participant App as Application
participant DB as Base de données (PostGIS)
participant Cron as Job Cron Quotidien
Note over User,App: Écoute de contenu avec GPS
User->>App: Écoute contenu (GPS activé)
App->>App: Capturer position GPS précise
App->>DB: INSERT position (lat, lon, anonymized: false)
Note over DB: Position précise stockée<br/>Utilisée pour recommandations
Note over DB,Cron: Moins de 24h : position précise conservée
App->>DB: SELECT positions pour recommandations
DB->>App: Positions GPS précises (< 24h)
App->>User: Recommandations hyperlocales
Note over Cron: 24h+ plus tard
Cron->>DB: SELECT positions WHERE created_at < NOW() - 24h AND anonymized = false
DB->>Cron: Liste positions à anonymiser
loop Pour chaque position
Cron->>DB: Convertir (lat, lon) → geohash précision 5 (~5km²)
Cron->>DB: UPDATE position avec geohash
Cron->>DB: Supprimer coordonnées précises
Cron->>DB: SET anonymized = true
end
Cron->>DB: Log anonymisation (nombre positions traitées)
Note over DB: Positions anonymisées utilisées pour analytics
App->>DB: SELECT positions anonymisées (analytics globales)
DB->>App: Positions geohash uniquement
App->>App: Générer heatmap trafic (~5km² précision)
Note over User: Exception : historique personnel
User->>App: Consulter "Mon historique d'écoute"
App->>DB: SELECT historique personnel utilisateur
DB->>App: Positions précises conservées (tant que compte actif)
App->>User: Trajets détaillés
```
**Légende** :
- **< 24h** : GPS précis conservé (recommandations hyperlocales)
- **> 24h** : Conversion automatique en geohash précision 5 (~5km²)
- **Exception** : Historique personnel conservé intact tant que compte actif
- **Analytics** : Uniquement positions anonymisées (geohash)

View File

@@ -0,0 +1,43 @@
# Consentement parental (13-15 ans)
```mermaid
sequenceDiagram
participant Ado as Adolescent (13-15 ans)
participant App as Application
participant DB as Base de données
participant Email as Service Email
participant Parent as Parent
Ado->>App: Inscription (date naissance 13-15 ans)
App->>Ado: Demande email parent
Ado->>App: Saisit email parent
App->>DB: Créer compte (statut: pending_parental_consent)
App->>Email: Envoyer email validation parent
Email->>Parent: Email avec lien (expire 7j)
App->>Ado: "En attente validation parentale"
Note over Parent: Parent clique lien validation
Parent->>App: Accès page consentement
App->>Parent: Afficher résumé données + contrôles
Parent->>App: Valider consentement + paramètres
App->>DB: Enregistrer consentement parental
App->>DB: Activer compte (statut: active_minor)
App->>DB: Appliquer restrictions 13-15 ans
App->>Email: Notification ado (compte activé)
Email->>Ado: Email confirmation
App->>Email: Notification parent (récapitulatif)
Email->>Parent: Email + lien dashboard parental
Ado->>App: Connexion
App->>Ado: Accès restreint (GPS/messagerie selon config parent)
```
**Légende** :
- Délai expiration lien : 7 jours
- Restrictions 13-15 ans : GPS précis, messagerie, contenus +16 (configurables par parent)
- Dashboard parent : `roadwave.fr/parent/[child_id]`

View File

@@ -0,0 +1,65 @@
# Export de données (portabilité)
```mermaid
sequenceDiagram
participant User as Utilisateur
participant App as Application
participant DB as Base de données
participant Queue as File d'attente
participant Worker as Worker Background
participant CDN as CDN (fichiers audio)
participant Storage as Stockage temporaire
participant Email as Service Email
User->>App: Demande export données
App->>DB: Vérifier dernière demande
alt Dernière demande < 30 jours
DB->>App: Demande refusée
App->>User: "Prochain export disponible dans X jours"
else Demande autorisée
App->>DB: Créer demande export (statut: pending)
App->>Queue: Ajouter job export
App->>User: "Export en cours, email sous 48h"
Queue->>Worker: Job export disponible
Note over Worker: Génération asynchrone
Worker->>DB: Récupérer profil utilisateur
Worker->>DB: Récupérer historique d'écoute
Worker->>DB: Récupérer contenus créés (métadonnées)
Worker->>DB: Récupérer centres d'intérêt
Worker->>DB: Récupérer historique consentements
Worker->>CDN: Télécharger fichiers audio utilisateur
CDN->>Worker: Fichiers audio (.opus)
Worker->>Worker: Générer export.json (machine-readable)
Worker->>Worker: Générer index.html (human-readable)
Worker->>Worker: Générer README.txt
Worker->>Worker: Créer archive ZIP
Worker->>Storage: Stocker ZIP (expire 7j)
Storage->>Worker: URL signée (expire 7j)
Worker->>DB: Mettre à jour demande (statut: completed)
Worker->>DB: Enregistrer URL + date expiration
Worker->>Email: Envoyer email avec lien
Email->>User: Email + lien téléchargement (valide 7j)
User->>Storage: Clic lien téléchargement
Storage->>User: Téléchargement ZIP
Note over Storage: Après 7 jours
Storage->>Storage: Suppression automatique ZIP
end
```
**Légende** :
- Limite : 1 export / 30 jours (anti-abus)
- Délai génération : 48h maximum (conformité RGPD Article 20)
- Expiration lien : 7 jours
- Format : ZIP contenant JSON, HTML, audio, README

View File

@@ -0,0 +1,63 @@
# Notification violation de données (breach) - Procédure 72h CNIL
```mermaid
sequenceDiagram
participant Monitoring as Monitoring (Sentry/Grafana)
participant Equipe as Équipe Technique
participant DPO as DPO
participant DB as Base de données
participant CNIL as CNIL
participant Users as Utilisateurs impactés
Note over Monitoring: H+0 - Détection
Monitoring->>Equipe: Alerte breach détecté
Equipe->>Equipe: Confinement immédiat
Equipe->>DB: Bloquer accès compromis
Equipe->>DPO: Notification breach
Note over DPO,Equipe: H+0 à H+24 - Évaluation
DPO->>DB: Investigation périmètre
DB->>DPO: Données compromises
DPO->>DB: Liste utilisateurs impactés
DB->>DPO: X utilisateurs
DPO->>DPO: Évaluation gravité
Note over DPO: - Type données (GPS, email, etc.)<br/>- Nombre utilisateurs<br/>- Risque pour droits/libertés
alt Risque pour utilisateurs
Note over DPO: H+24 à H+48 - Préparation notification CNIL
DPO->>DPO: Rédaction rapport breach
Note over DPO: - Nature violation<br/>- Catégories/nb données<br/>- Conséquences probables<br/>- Mesures prises/envisagées
DPO->>CNIL: Notification sous 72h (email + formulaire en ligne)
CNIL->>DPO: Accusé réception
alt Risque élevé pour utilisateurs
Note over DPO: H+48 à H+72 - Notification utilisateurs
DPO->>Users: Email notification breach
Note over Users: - Nature violation<br/>- Coordonnées DPO<br/>- Mesures prises<br/>- Recommandations (changer mdp, etc.)
DPO->>Users: Notification in-app
end
else Risque faible (mesures techniques suffisantes)
DPO->>DPO: Documentation interne uniquement
Note over DPO: Pas de notification CNIL requise
end
Note over DPO: Post-incident
DPO->>Equipe: Audit sécurité complet
DPO->>DB: Enregistrement incident (registre violations)
DPO->>DPO: Plan correctif
```
**Légende** :
- **H+0 à H+24** : Détection, confinement, évaluation périmètre
- **H+24 à H+48** : Évaluation gravité, préparation rapport
- **H+48 à H+72** : Notification CNIL (si risque) + utilisateurs (si risque élevé)
- Délai CNIL : **72h maximum** (Article 33 RGPD)
- Notification utilisateurs obligatoire si **risque élevé** pour droits/libertés (Article 34 RGPD)

View File

@@ -0,0 +1,51 @@
# Suppression compte avec grace period
```mermaid
sequenceDiagram
participant User as Utilisateur
participant App as Application
participant DB as Base de données
participant Email as Service Email
participant Cron as Job Cron
User->>App: Demande suppression compte
App->>User: Confirmation (êtes-vous sûr ?)
User->>App: Confirmer
App->>DB: Désactiver compte (statut: pending_deletion)
App->>DB: Cacher contenus (visible: false)
App->>DB: Révoquer sessions/tokens
App->>DB: Enregistrer date suppression effective (J+30)
App->>Email: Email confirmation + lien annulation
Email->>User: Email (lien valide 30j)
App->>User: "Compte désactivé. Suppression dans 30 jours."
Note over User,App: Grace period 30 jours
alt Utilisateur annule
User->>App: Clic lien annulation
App->>DB: Réactiver compte (statut: active)
App->>DB: Restaurer visibilité contenus
App->>Email: Email confirmation réactivation
Email->>User: "Compte réactivé"
else 30 jours sans annulation
Cron->>DB: Job quotidien (vérif comptes pending_deletion)
DB->>Cron: Liste comptes J+30 dépassé
loop Pour chaque compte
Cron->>DB: Supprimer données personnelles
Cron->>DB: Anonymiser contenus (créateur: "Utilisateur supprimé")
Cron->>DB: Supprimer historique GPS/écoute
Cron->>DB: Marquer statut: deleted
end
Cron->>Email: Email confirmation suppression effective
Email->>User: "Compte définitivement supprimé"
end
```
**Légende** :
- Grace period : 30 jours
- Pendant grace period : compte inaccessible, contenus cachés
- Après 30j : suppression définitive, contenus anonymisés conservés

View File

@@ -0,0 +1,42 @@
# Cycle de vie - Suppression de compte
## Diagramme
```mermaid
stateDiagram-v2
[*] --> Requested: Utilisateur demande suppression
Requested --> GracePeriod: Compte désactivé, email envoyé
GracePeriod --> Cancelled: Clic lien annulation (< 30j)
GracePeriod --> PendingDeletion: Délai 30j écoulé
Cancelled --> [*]
PendingDeletion --> Deleted: Job cron suppression effective
Deleted --> [*]
```
## Règles
| État | Valeur | Description |
|------|--------|-------------|
| Requested | `requested` | Demande initiée, validation requise |
| Grace Period | `grace_period` | 30j annulation possible, compte inaccessible |
| Cancelled | `cancelled` | Utilisateur a annulé, compte réactivé |
| Pending Deletion | `pending_deletion` | File job cron (< 24h) |
| Deleted | `deleted` | Données supprimées, contenus anonymisés |
**Grace period** : 30 jours
**Pendant grace period** :
- Compte désactivé (login impossible)
- Contenus cachés (non diffusés)
- Sessions/tokens révoqués
- Email avec token annulation (valide 30j)
**Après 30j** :
- Données personnelles supprimées
- Contenus créés anonymisés (créateur = "Utilisateur supprimé")
- Historique GPS/écoute supprimé
- Irréversible

View File

@@ -0,0 +1,44 @@
# Cycle de vie - Incident de violation de données
## Diagramme
```mermaid
stateDiagram-v2
[*] --> Detected: Alerte monitoring
Detected --> Contained: Confinement immédiat (H+0)
Contained --> UnderInvestigation: Évaluation gravité (H+24)
UnderInvestigation --> Resolved: Risque faible (mesures suffisantes)
UnderInvestigation --> CNILNotificationRequired: Risque utilisateurs
CNILNotificationRequired --> CNILNotified: Notification CNIL (< H+72)
CNILNotified --> Resolved: Pas de risque élevé utilisateurs
CNILNotified --> UsersNotificationRequired: Risque élevé
UsersNotificationRequired --> UsersNotified: Email + push utilisateurs (< H+72)
UsersNotified --> Resolved: Post-mortem + correctifs
Resolved --> [*]
```
## Règles
| État | Valeur | Délai max |
|------|--------|-----------|
| Detected | `detected` | H+0 |
| Contained | `contained` | H+0 (immédiat) |
| Under Investigation | `under_investigation` | H+24 |
| CNIL Notification Required | `cnil_notification_required` | H+48 |
| CNIL Notified | `cnil_notified` | H+72 (Article 33 RGPD) |
| Users Notification Required | `users_notification_required` | H+48 |
| Users Notified | `users_notified` | H+72 (Article 34 RGPD) |
| Resolved | `resolved` | Post-incident |
**Sévérité** : `low` / `medium` / `high` / `critical`
**Notification CNIL** : Obligatoire si risque pour droits/libertés utilisateurs
**Notification utilisateurs** : Obligatoire si risque **élevé**
**Runbook** : `docs/rgpd/procedure-breach.md`

View File

@@ -0,0 +1,32 @@
# Cycle de vie - Consentement parental
## Diagramme
```mermaid
stateDiagram-v2
[*] --> PendingValidation: Ado saisit email parent
PendingValidation --> Validated: Parent clique lien (< 7j)
PendingValidation --> Expired: Délai 7j écoulé
Validated --> Revoked: Parent révoque consentement
Validated --> AutoRevoked: Ado atteint 16 ans
Expired --> [*]
Revoked --> [*]
AutoRevoked --> [*]
```
## Règles
| État | Valeur | Description |
|------|--------|-------------|
| Pending Validation | `pending_validation` | Email envoyé parent, token valide 7j |
| Validated | `validated` | Parent a validé, restrictions 13-15 ans actives |
| Expired | `expired` | Token expiré sans validation, compte inactif |
| Revoked | `revoked` | Parent révoque, compte désactivé immédiatement |
| Auto-Revoked | `auto_revoked` | Ado atteint 16 ans, restrictions levées automatiquement |
**Délai expiration** : 7 jours
**Révocation** : Possible à tout moment via dashboard parent
**Transition automatique** : À 16 ans → compte passe en `active` standard

View File

@@ -4,18 +4,31 @@
```mermaid ```mermaid
stateDiagram-v2 stateDiagram-v2
[*] --> Active: Inscription validée [*] --> PendingEmailVerification: Inscription
[*] --> PendingParentalConsent: Inscription 13-15 ans
PendingEmailVerification --> Active: Email vérifié (16+ ans)
PendingParentalConsent --> ActiveMinor: Parent valide
PendingParentalConsent --> Expired: Token expiré (7j)
Active --> Suspended: Strikes 3/4/5 Active --> Suspended: Strikes 3/4/5
Active --> GracePeriod: Demande suppression Active --> GracePeriod: Demande suppression
Active --> Frozen: Gel temporaire (limitation traitement)
Active --> Deleted: Inactivité 5 ans Active --> Deleted: Inactivité 5 ans
ActiveMinor --> Active: 16 ans atteints
ActiveMinor --> Suspended: Modération
ActiveMinor --> Deleted: Parent révoque
Frozen --> Active: Réactivation utilisateur
Suspended --> Active: Fin suspension / Appel Suspended --> Active: Fin suspension / Appel
Suspended --> Deleted: Suspension définitive Suspended --> Deleted: Suspension définitive
GracePeriod --> Active: Annulation < 30j GracePeriod --> Active: Annulation < 30j
GracePeriod --> Deleted: Après 30j GracePeriod --> Deleted: Après 30j
Expired --> [*]
Deleted --> [*] Deleted --> [*]
``` ```
@@ -23,9 +36,20 @@ stateDiagram-v2
| État | Valeur | Durée/Condition | | État | Valeur | Durée/Condition |
|------|--------|-----------------| |------|--------|-----------------|
| Active | `active` | Compte fonctionnel | | Pending Email Verification | `pending_email_verification` | Email non vérifié (expire 24h) |
| Pending Parental Consent | `pending_parental_consent` | Ado 13-15 ans, attente validation parent (expire 7j) |
| Active | `active` | Compte fonctionnel standard (16+ ans) |
| Active Minor | `active_minor` | Compte 13-15 ans avec restrictions parentales |
| Frozen | `frozen` | Gel temporaire (lecture seule), réactivable à tout moment |
| Suspended | `suspended` | Strike 3: 7j, Strike 4: 30j, Strike 5: définitif | | Suspended | `suspended` | Strike 3: 7j, Strike 4: 30j, Strike 5: définitif |
| Grace Period | `grace_period` | 30j avant suppression, annulable | | Grace Period | `grace_period` | 30j avant suppression, annulable |
| Deleted | `deleted` | Données anonymisées, irréversible | | Expired | `expired` | Token expiré sans validation |
| Deleted | `deleted` | Données supprimées, contenus anonymisés, irréversible |
**Restrictions Active Minor** :
- GPS précis : configurable par parent
- Messagerie privée : désactivée par défaut
- Contenus +16 : filtrés
- Transition auto vers `active` à 16 ans
**Purge inactivité** : 5 ans sans connexion (notifications 90j/30j/7j avant) **Purge inactivité** : 5 ans sans connexion (notifications 90j/30j/7j avant)

View File

@@ -103,6 +103,20 @@ nav:
- RGPD: domains/_shared/rules/rgpd.md - RGPD: domains/_shared/rules/rgpd.md
- Gestion Erreurs: domains/_shared/rules/gestion-erreurs.md - Gestion Erreurs: domains/_shared/rules/gestion-erreurs.md
- 'Annexe Post-MVP': domains/_shared/rules/ANNEXE-POST-MVP.md - 'Annexe Post-MVP': domains/_shared/rules/ANNEXE-POST-MVP.md
- Features BDD:
- 'RGPD & Conformité':
- Consentement: generated/bdd/_shared/features/rgpd-compliance/consentement.md
- Anonymisation GPS: generated/bdd/_shared/features/rgpd-compliance/anonymisation-gps.md
- Portabilité Données: generated/bdd/_shared/features/rgpd-compliance/portabilite-donnees.md
- Suppression Compte: generated/bdd/_shared/features/rgpd-compliance/suppression-compte.md
- Conservation Données: generated/bdd/_shared/features/rgpd-compliance/conservation-donnees.md
- Cookies & Analytics: generated/bdd/_shared/features/rgpd-compliance/cookies-analytics.md
- Mode Dégradé GeoIP: generated/bdd/_shared/features/rgpd-compliance/mode-degrade-geoip.md
- Compliance Administrative: generated/bdd/_shared/features/rgpd-compliance/compliance-administrative.md
- Protection Mineurs: generated/bdd/_shared/features/rgpd-compliance/minors-protection.md
- Sécurité Données: generated/bdd/_shared/features/rgpd-compliance/data-security.md
- Politique Confidentialité: generated/bdd/_shared/features/rgpd-compliance/privacy-policy.md
- Droits Utilisateurs: generated/bdd/_shared/features/rgpd-compliance/user-rights.md
- Entités: - Entités:
- "Vue d'ensemble": domains/_shared/entities/entities-overview.md - "Vue d'ensemble": domains/_shared/entities/entities-overview.md
- 'Auth & Sécurité': - 'Auth & Sécurité':
@@ -112,6 +126,12 @@ nav:
- Consentements: domains/_shared/entities/consents.md - Consentements: domains/_shared/entities/consents.md
- Historique GPS: domains/_shared/entities/location-history.md - Historique GPS: domains/_shared/entities/location-history.md
- Exports Données: domains/_shared/entities/exports.md - Exports Données: domains/_shared/entities/exports.md
- Consentements Parentaux: domains/_shared/entities/parental-consents.md
- Politique Confidentialité: domains/_shared/entities/privacy-policy-versions.md
- Suppressions Compte: domains/_shared/entities/account-deletions.md
- Incidents Breach: domains/_shared/entities/breach-incidents.md
- Historique Profil: domains/_shared/entities/user-profile-history.md
- Logs Rétention Données: domains/_shared/entities/data-retention-logs.md
- 'Recommandation & Modération': - 'Recommandation & Modération':
- Jauges Intérêt: domains/_shared/entities/interest-gauges.md - Jauges Intérêt: domains/_shared/entities/interest-gauges.md
- Signalements: domains/_shared/entities/reports.md - Signalements: domains/_shared/entities/reports.md
@@ -121,13 +141,21 @@ nav:
- Session: domains/_shared/states/session-lifecycle.md - Session: domains/_shared/states/session-lifecycle.md
- Signalement: domains/_shared/states/report-lifecycle.md - Signalement: domains/_shared/states/report-lifecycle.md
- Export Données: domains/_shared/states/export-lifecycle.md - Export Données: domains/_shared/states/export-lifecycle.md
- Consentement Parental: domains/_shared/states/parental-consent-lifecycle.md
- Suppression Compte: domains/_shared/states/account-deletion-lifecycle.md
- Incident Breach: domains/_shared/states/breach-incident-lifecycle.md
- Séquences: - Séquences:
- Authentification: domains/_shared/sequences/authentication-flow.md - Authentification: domains/_shared/sequences/authentication-flow.md
- Refresh Token: domains/_shared/sequences/token-refresh.md - Refresh Token: domains/_shared/sequences/token-refresh.md
- Modération Contenu: domains/_shared/sequences/content-moderation.md - Modération Contenu: domains/_shared/sequences/content-moderation.md
- Signalement: domains/_shared/sequences/content-report.md - Signalement: domains/_shared/sequences/content-report.md
- Export Données: domains/_shared/sequences/data-export.md - Export Données: domains/_shared/sequences/data-export.md
- Export Données (RGPD): domains/_shared/sequences/export-donnees.md
- Suppression Compte: domains/_shared/sequences/account-deletion.md - Suppression Compte: domains/_shared/sequences/account-deletion.md
- Suppression Compte (RGPD): domains/_shared/sequences/suppression-compte.md
- Consentement Parental: domains/_shared/sequences/consentement-parental.md
- Anonymisation GPS: domains/_shared/sequences/anonymisation-gps.md
- Notification Breach: domains/_shared/sequences/notification-breach.md
- 'Supporting Subdomains': - 'Supporting Subdomains':
- '🎯 Recommendation': - '🎯 Recommendation':
- Vue d'ensemble: domains/recommendation/README.md - Vue d'ensemble: domains/recommendation/README.md
@@ -198,6 +226,8 @@ nav:
- 'Validation TestFlight': mobile/testflight-validation-plan.md - 'Validation TestFlight': mobile/testflight-validation-plan.md
- Conformité & Compliance: - Conformité & Compliance:
- 'Soumission aux Stores': compliance/stores-submission.md - 'Soumission aux Stores': compliance/stores-submission.md
- Tests BDD:
- "Vue d'ensemble": generated/bdd/index.md
- Architecture & Techniques: - Architecture & Techniques:
- Séquences: - Séquences:
- 'Cache Géospatial': architecture/sequences/cache-geospatial.md - 'Cache Géospatial': architecture/sequences/cache-geospatial.md

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -368,7 +368,7 @@ def main():
# Chemins # Chemins
project_root = Path(__file__).parent.parent project_root = Path(__file__).parent.parent
features_dir = project_root / 'docs' / 'domains' features_dir = project_root / 'docs' / 'domains'
output_dir = project_root / 'docs' / 'bdd' output_dir = project_root / 'generated' / 'bdd'
# Nettoyer le dossier de sortie # Nettoyer le dossier de sortie
if output_dir.exists(): if output_dir.exists():

View File

@@ -339,9 +339,9 @@ def main():
project_root = Path(__file__).parent.parent project_root = Path(__file__).parent.parent
docs_dir = project_root / 'docs' docs_dir = project_root / 'docs'
mkdocs_path = project_root / 'mkdocs.yml' mkdocs_path = project_root / 'mkdocs.yml'
output_dir = project_root / 'output' output_dir = project_root / 'generated' / 'pdf'
output_dir.mkdir(exist_ok=True) output_dir.mkdir(parents=True, exist_ok=True)
print("📄 Génération du PDF de la documentation RoadWave...") print("📄 Génération du PDF de la documentation RoadWave...")