feat(bdd): réorganiser features en catégories api/ui/e2e et créer ADR-024
Résolution des incohérences #10, #11, et #12 de l'analyse d'architecture. ## Phase 1 : Réorganisation Features BDD (Point #10 - RÉSOLU) - Créer structure features/{api,ui,e2e} - Déplacer 83 features en 3 catégories via git mv (historique préservé) - features/api/ : 53 features (tests API backend) - features/ui/ : 22 features (tests UI mobile) - features/e2e/ : 8 features (tests end-to-end) Domaines déplacés : - API : authentication, recommendation, rgpd-compliance, content-creation, moderation, monetisation, premium, radio-live, publicites - UI : audio-guides, navigation, interest-gauges, mode-offline, partage, profil, recherche - E2E : abonnements, error-handling ## Phase 2 : Mise à jour Documentation ### ADR-007 - Tests BDD - Ajouter section "Convention de Catégorisation des Features" - Documenter règles api/ui/e2e avec exemples concrets - Spécifier step definitions (backend Go, mobile Dart) ### ADR-024 - Stratégie CI/CD Monorepo (NOUVEAU) - Créer ADR dédié pour stratégie CI/CD avec path filters - Architecture workflows séparés (backend.yml, mobile.yml, shared.yml) - Configuration path filters détaillée avec exemples YAML - Matrice de déclenchement et optimisations (~70% gain temps CI) - Plan d'implémentation (~2h, reporté jusqu'au développement) ### ADR-016 - Organisation Monorepo - Simplifier en retirant section CI/CD détaillée - Ajouter référence vers ADR-024 pour stratégie CI/CD ### INCONSISTENCIES-ANALYSIS.md - Point #10 (Tests BDD synchronisés) : ✅ RÉSOLU - Catégorisation features implémentée - ADR-007 mis à jour avec convention complète - Point #11 (70/30 Split paiements) : ✅ ANNULÉ (faux problème) - ADR-009 et Règle 18 parfaitement cohérents - Documentation exhaustive existante (formule, SQL, comparaisons) - Point #12 (Monorepo path filters) : ⏸️ DOCUMENTÉ - Architecture CI/CD complète dans ADR-024 - Implémentation reportée (projet en phase documentation) - Métriques mises à jour : - MODERATE : 6/9 traités (4 résolus + 1 annulé + 1 documenté) - ADR à jour : 100% (19/19 avec ADR-024) ## Phase 3 : Validation - Structure features validée (api/ui/e2e, aucun répertoire restant) - Historique Git préservé (git mv, renommages détectés) - 83 features total (API: 53, UI: 22, E2E: 8) Closes: Point #10 (résolu), Point #11 (annulé), Point #12 (documenté) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
176
features/api/rgpd-compliance/anonymisation-gps.feature
Normal file
176
features/api/rgpd-compliance/anonymisation-gps.feature
Normal file
@@ -0,0 +1,176 @@
|
||||
# language: fr
|
||||
|
||||
@rgpd @anonymization @gps
|
||||
Fonctionnalité: Anonymisation des données GPS après 24h
|
||||
|
||||
# 13.2 - Geohash après 24h (conformité RGPD + CNIL)
|
||||
|
||||
Contexte:
|
||||
Étant donné que je suis un utilisateur avec le GPS activé
|
||||
Et que j'utilise l'application depuis plusieurs jours
|
||||
|
||||
Scénario: Conservation des données GPS précises pendant 24h
|
||||
Étant donné que j'écoute un contenu à la position GPS 48.8566, 2.3522 (Paris, Tour Eiffel)
|
||||
Et qu'il est 10:00 le 2025-01-20
|
||||
Quand l'événement d'écoute est enregistré en base de données
|
||||
Alors les coordonnées précises 48.8566, 2.3522 sont stockées
|
||||
Et le champ `anonymized` est à `false`
|
||||
Et le champ `created_at` contient "2025-01-20 10:00:00"
|
||||
Et ces données précises servent à la recommandation personnalisée
|
||||
|
||||
Scénario: Conversion en geohash après 24h
|
||||
Étant donné que j'ai écouté un contenu le 2025-01-20 à 10:00 à la position 48.8566, 2.3522
|
||||
Quand le job quotidien d'anonymisation s'exécute le 2025-01-21 à 02:00
|
||||
Alors les coordonnées précises sont converties en geohash précision 5
|
||||
Et le geohash correspond à une zone d'environ 5km²
|
||||
Et les coordonnées originales 48.8566, 2.3522 sont supprimées définitivement
|
||||
Et le champ `anonymized` passe à `true`
|
||||
Et il est impossible de retrouver la position précise d'origine
|
||||
|
||||
Scénario: Requête SQL d'anonymisation (PostGIS)
|
||||
Étant donné que le job quotidien d'anonymisation s'exécute
|
||||
Quand la requête SQL suivante est exécutée:
|
||||
"""sql
|
||||
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;
|
||||
"""
|
||||
Alors toutes les positions vieilles de plus de 24h sont anonymisées
|
||||
Et le processus est automatique et irréversible
|
||||
Et les données sont conformes RGPD
|
||||
|
||||
Scénario: Précision du geohash niveau 5
|
||||
Étant donné qu'une position GPS est convertie en geohash précision 5
|
||||
Quand on analyse la zone couverte
|
||||
Alors la zone fait environ 5km² (4.9km × 4.9km)
|
||||
Et cette précision est suffisante pour des analytics agrégées
|
||||
Et cette précision ne permet pas d'identifier un individu (conformité CNIL)
|
||||
|
||||
Scénario: Exemple de conversion Paris
|
||||
Étant donné que ma position précise est 48.8566, 2.3522 (Tour Eiffel)
|
||||
Quand la conversion en geohash précision 5 est appliquée
|
||||
Alors le geohash généré est "u09wh"
|
||||
Et ce geohash couvre une zone de ~5km² autour de la Tour Eiffel
|
||||
Et toutes les positions dans cette zone partagent le même geohash
|
||||
Et il est impossible de distinguer deux utilisateurs dans cette zone
|
||||
|
||||
# Exception: Historique personnel
|
||||
|
||||
Scénario: Conservation de l'historique personnel utilisateur
|
||||
Étant donné que j'ai écouté des contenus aux positions suivantes:
|
||||
| date | heure | latitude | longitude | lieu |
|
||||
| 2025-01-15 | 08:30 | 48.8566 | 2.3522 | Paris |
|
||||
| 2025-01-16 | 14:00 | 43.6047 | 1.4442 | Toulouse |
|
||||
| 2025-01-17 | 19:00 | 45.7640 | 4.8357 | Lyon |
|
||||
Quand j'ouvre mon historique personnel dans "Profil > Mes trajets"
|
||||
Alors je vois mes trajets avec les positions précises intégrales
|
||||
Et ces données ne sont pas anonymisées tant que mon compte est actif
|
||||
Et seul moi peut accéder à ces données
|
||||
Et elles ne sont pas utilisées pour des analytics globales
|
||||
|
||||
Scénario: Anonymisation pour analytics globales uniquement
|
||||
Étant donné que RoadWave génère des analytics agrégées
|
||||
Quand l'équipe analyse les zones géographiques populaires
|
||||
Alors seules les données anonymisées (geohash) sont utilisées
|
||||
Et les positions précises de l'historique personnel ne sont jamais agrégées
|
||||
Et les heatmaps de trafic utilisent uniquement les geohash ~5km²
|
||||
|
||||
# Job quotidien automatique
|
||||
|
||||
Scénario: Planification du job d'anonymisation
|
||||
Étant donné que le système est en production
|
||||
Quand on consulte les jobs planifiés (cron)
|
||||
Alors un job "anonymize_gps_data" est configuré
|
||||
Et le job s'exécute tous les jours à 02:00 (heure creuse)
|
||||
Et le job traite toutes les positions vieilles de plus de 24h
|
||||
Et un log est généré pour traçabilité
|
||||
|
||||
Scénario: Exécution du job avec métriques
|
||||
Étant donné que le job d'anonymisation s'exécute le 2025-01-21 à 02:00
|
||||
Quand le job se termine
|
||||
Alors un rapport est généré avec:
|
||||
| métrique | valeur |
|
||||
| Nombre de positions traitées | 15420 |
|
||||
| Nombre de positions anonymisées| 15420 |
|
||||
| Durée d'exécution | 3.5s |
|
||||
| Erreurs | 0 |
|
||||
Et le rapport est loggé dans Sentry/Grafana
|
||||
Et une alerte est envoyée si le job échoue
|
||||
|
||||
Scénario: Performances du job d'anonymisation
|
||||
Étant donné que 100 000 positions doivent être anonymisées
|
||||
Quand le job s'exécute
|
||||
Alors le traitement se fait en moins de 30 secondes
|
||||
Et la requête PostGIS est optimisée avec index
|
||||
Et aucun impact sur les performances de l'application en production
|
||||
|
||||
# Vraie anonymisation RGPD
|
||||
|
||||
Scénario: Impossibilité de réidentification
|
||||
Étant donné qu'une position a été anonymisée en geohash "u09wh"
|
||||
Quand un attaquant tente de retrouver la position précise d'origine
|
||||
Alors il est impossible de déterminer la position exacte
|
||||
Et des milliers de positions précises correspondent au même geohash
|
||||
Et il n'y a aucune traçabilité vers la position originale
|
||||
Et cette anonymisation est irréversible
|
||||
|
||||
Scénario: Conformité CNIL - données véritablement anonymisées
|
||||
Étant donné que les positions sont converties en geohash précision 5
|
||||
Quand un auditeur CNIL vérifie la conformité
|
||||
Alors les données sont considérées comme véritablement anonymisées
|
||||
Et elles ne sont plus considérées comme des données personnelles
|
||||
Et aucun consentement n'est requis pour leur traitement analytique
|
||||
Et elles peuvent être conservées indéfiniment
|
||||
|
||||
# Analytics agrégées autorisées
|
||||
|
||||
Scénario: Heatmap de trafic avec données anonymisées
|
||||
Étant donné que RoadWave génère une heatmap des zones populaires
|
||||
Quand on analyse les données utilisées
|
||||
Alors seules les positions anonymisées (geohash) sont agrégées
|
||||
Et la heatmap montre des zones de ~5km²
|
||||
Et aucune position précise n'est révélée
|
||||
Et cette analyse ne nécessite pas de consentement utilisateur (données anonymes)
|
||||
|
||||
Scénario: Statistiques géographiques par département
|
||||
Étant donné que RoadWave analyse l'utilisation par département
|
||||
Quand les statistiques sont générées
|
||||
Alors les données anonymisées sont agrégées par département
|
||||
Et les résultats montrent: "Paris (75): 12 500 écoutes, Lyon (69): 8 300 écoutes"
|
||||
Et aucune donnée personnelle n'est révélée
|
||||
Et les statistiques sont RGPD-compliant
|
||||
|
||||
# PostGIS natif - 0€
|
||||
|
||||
Scénario: Coût de la solution d'anonymisation
|
||||
Étant donné que PostGIS est utilisé pour l'anonymisation GPS
|
||||
Quand on calcule le coût de la solution
|
||||
Alors le coût est de 0€ (PostGIS inclus dans PostgreSQL)
|
||||
Et aucune librairie tierce n'est nécessaire
|
||||
Et la solution est entièrement maîtrisée (self-hosted)
|
||||
|
||||
# Cas limites
|
||||
|
||||
Scénario: Anonymisation respecte les positions en cours de session
|
||||
Étant donné que je suis en train d'écouter du contenu actuellement
|
||||
Et que certaines de mes positions ont plus de 24h
|
||||
Quand le job d'anonymisation s'exécute
|
||||
Alors mes positions de plus de 24h sont anonymisées
|
||||
Mais ma position actuelle (session en cours) reste précise
|
||||
Et la recommandation continue de fonctionner normalement
|
||||
|
||||
Scénario: Suppression de compte et anonymisation GPS
|
||||
Étant donné que je demande la suppression de mon compte
|
||||
Quand le compte est supprimé (après grace period de 30j)
|
||||
Alors toutes mes positions GPS (précises et anonymisées) sont supprimées
|
||||
Et mon historique personnel de trajets est supprimé
|
||||
Et aucune donnée GPS ne subsiste, même anonymisée
|
||||
|
||||
Scénario: Export de données avant anonymisation
|
||||
Étant donné que je demande un export de mes données
|
||||
Et que certaines de mes positions ont été anonymisées
|
||||
Quand l'export est généré
|
||||
Alors les positions précises de mon historique personnel sont incluses
|
||||
Mais les positions déjà anonymisées (>24h, analytics) apparaissent en geohash
|
||||
Et l'export précise quelles données ont été anonymisées et pourquoi
|
||||
256
features/api/rgpd-compliance/compliance-administrative.feature
Normal file
256
features/api/rgpd-compliance/compliance-administrative.feature
Normal file
@@ -0,0 +1,256 @@
|
||||
# language: fr
|
||||
|
||||
@rgpd @administrative @dpo
|
||||
Fonctionnalité: Conformité administrative RGPD (Registre, Breach, DPO)
|
||||
|
||||
# 13.8 - Registre des traitements (Article 30 RGPD)
|
||||
|
||||
@registre-traitements
|
||||
Scénario: Registre des traitements en Markdown versionné Git
|
||||
Étant donné que RoadWave doit tenir un registre des traitements
|
||||
Quand on consulte la documentation
|
||||
Alors un fichier `docs/rgpd/registre-traitements.md` existe
|
||||
Et le fichier est versionné dans Git
|
||||
Et l'historique des modifications est traçable via Git
|
||||
Et chaque traitement est documenté dans une section dédiée
|
||||
|
||||
Scénario: Contenu obligatoire pour chaque traitement
|
||||
Étant donné que le registre des traitements contient le traitement "Géolocalisation utilisateurs"
|
||||
Quand on lit la section correspondante
|
||||
Alors les informations suivantes sont présentes:
|
||||
| information obligatoire | exemple |
|
||||
| Nom du traitement | Géolocalisation utilisateurs |
|
||||
| Finalité | Recommandation de contenu géolocalisé |
|
||||
| Catégories de données | Coordonnées GPS, historique de position |
|
||||
| Base légale | Consentement (Article 6.1.a RGPD) |
|
||||
| Durée de conservation | 24h (précis), puis geohash anonymisé |
|
||||
| Destinataires | Aucun tiers |
|
||||
| Transferts hors UE | Aucun |
|
||||
| Mesures de sécurité | TLS 1.3, anonymisation après 24h |
|
||||
|
||||
Plan du Scénario: Traitements documentés dans le registre
|
||||
Étant donné que le registre des traitements est complet
|
||||
Quand on liste tous les traitements
|
||||
Alors le traitement "<traitement>" est documenté avec la base légale "<base_legale>"
|
||||
|
||||
Exemples:
|
||||
| traitement | base_legale |
|
||||
| Géolocalisation utilisateurs | Consentement |
|
||||
| Historique d'écoute | Intérêt légitime |
|
||||
| Création de contenu | Exécution du contrat |
|
||||
| Analytics (Matomo) | Consentement |
|
||||
| Paiements (Mangopay) | Exécution du contrat |
|
||||
| Modération contenus | Intérêt légitime |
|
||||
| Notifications push | Consentement |
|
||||
|
||||
Scénario: Review trimestrielle du registre
|
||||
Étant donné que le registre des traitements existe
|
||||
Quand on consulte l'historique Git
|
||||
Alors une mise à jour est effectuée au moins tous les 3 mois
|
||||
Et chaque mise à jour a un commit avec message explicite
|
||||
Et un tag Git marque chaque review trimestrielle
|
||||
Et les modifications sont traçables (auteur, date, changements)
|
||||
|
||||
Scénario: Mise à jour immédiate si nouveau traitement
|
||||
Étant donné qu'une nouvelle fonctionnalité nécessite un traitement de données
|
||||
Quand la fonctionnalité est développée
|
||||
Alors le registre est mis à jour AVANT le déploiement en production
|
||||
Et le nouveau traitement est documenté complètement
|
||||
Et un commit Git enregistre l'ajout
|
||||
Et le DPO valide la conformité RGPD du nouveau traitement
|
||||
|
||||
Scénario: Migration future vers interface admin PostgreSQL
|
||||
Étant donné que RoadWave dépasse 100 000 utilisateurs
|
||||
Quand la complexité du registre augmente
|
||||
Alors une interface admin PostgreSQL est développée
|
||||
Et le registre Markdown est migré vers la base de données
|
||||
Et l'historique Git est conservé pour audit
|
||||
Et l'interface permet une gestion plus efficace des traitements
|
||||
|
||||
# 13.9 - Notification violations de données (Breach)
|
||||
|
||||
@breach-notification
|
||||
Scénario: Détection automatique d'événements critiques
|
||||
Étant donné que le système de monitoring est actif
|
||||
Quand un événement critique se produit
|
||||
Alors une alerte est envoyée selon le type d'événement:
|
||||
| événement | outil | alerte |
|
||||
| Erreur backend critique | Sentry | Discord/Slack immédiat |
|
||||
| Pic requêtes anormal | Grafana | Email équipe |
|
||||
| Accès non autorisé DB | PostgreSQL logs | SMS fondateur |
|
||||
| Authentification suspecte | Zitadel alerts | Email équipe |
|
||||
Et les alertes permettent une réaction rapide
|
||||
|
||||
Scénario: Runbook de procédure breach disponible
|
||||
Étant donné qu'une violation de données potentielle est détectée
|
||||
Quand l'équipe consulte la documentation
|
||||
Alors un runbook `docs/rgpd/procedure-breach.md` existe
|
||||
Et le runbook contient une checklist 72h CNIL
|
||||
Et chaque étape est clairement documentée
|
||||
Et les contacts d'urgence sont listés
|
||||
|
||||
Scénario: Checklist 72h en cas de breach
|
||||
Étant donné qu'une violation de données est confirmée
|
||||
Quand l'équipe suit la procédure breach
|
||||
Alors les étapes suivantes sont exécutées dans les délais:
|
||||
| délai | étape |
|
||||
| H+0 | Détection et confinement immédiat |
|
||||
| H+24 | Évaluation gravité (données concernées, users impactés) |
|
||||
| H+48 | Notification CNIL si risque pour utilisateurs |
|
||||
| H+72 | Notification utilisateurs si risque élevé |
|
||||
Et chaque étape est documentée pour audit
|
||||
|
||||
Scénario: Évaluation de la gravité du breach
|
||||
Étant donné qu'une violation de données est détectée
|
||||
Quand l'équipe évalue la gravité
|
||||
Alors les critères suivants sont analysés:
|
||||
| critère | exemple |
|
||||
| Type de données concernées | Emails, mots de passe, GPS, etc. |
|
||||
| Nombre d'utilisateurs impactés | 10, 100, 10000, etc. |
|
||||
| Mesures de sécurité existantes | Chiffrement, hachage, anonymisation |
|
||||
| Risque pour les droits et libertés | Faible, modéré, élevé |
|
||||
Et si le risque est élevé, la CNIL est notifiée sous 72h
|
||||
|
||||
Scénario: Notification CNIL dans les 72h
|
||||
Étant donné qu'un breach avec risque élevé est confirmé à 10:00 le 2025-01-20
|
||||
Quand la gravité est évaluée comme nécessitant une notification
|
||||
Alors la CNIL est notifiée avant 10:00 le 2025-01-23 (72h)
|
||||
Et la notification contient:
|
||||
| information |
|
||||
| Nature de la violation |
|
||||
| Données concernées |
|
||||
| Nombre d'utilisateurs impactés |
|
||||
| Conséquences probables |
|
||||
| Mesures prises |
|
||||
| Mesures de remédiation |
|
||||
Et un email pré-rédigé (template) est utilisé pour gagner du temps
|
||||
|
||||
Scénario: Notification des utilisateurs si risque élevé
|
||||
Étant donné qu'un breach impacte 5000 utilisateurs
|
||||
Et que le risque est élevé (mots de passe non chiffrés exposés)
|
||||
Quand la CNIL est notifiée
|
||||
Alors les utilisateurs impactés sont notifiés dans les 72h
|
||||
Et l'email contient:
|
||||
"""
|
||||
Objet: Alerte sécurité - Action requise
|
||||
|
||||
Bonjour,
|
||||
|
||||
Nous vous informons qu'une violation de données a affecté votre compte RoadWave.
|
||||
|
||||
Données concernées: [liste]
|
||||
Date de l'incident: [date]
|
||||
Actions prises: [mesures]
|
||||
|
||||
Action requise: Changez immédiatement votre mot de passe.
|
||||
|
||||
Pour toute question: security@roadwave.fr
|
||||
"""
|
||||
Et un lien de réinitialisation de mot de passe est inclus
|
||||
|
||||
Scénario: Aucune notification si risque faible
|
||||
Étant donné qu'un breach mineur est détecté (logs techniques exposés, aucune donnée personnelle)
|
||||
Quand l'équipe évalue la gravité
|
||||
Alors le risque est jugé faible
|
||||
Et aucune notification CNIL n'est requise (Article 33.1 RGPD)
|
||||
Et aucune notification utilisateur n'est envoyée
|
||||
Et un log interne est créé pour traçabilité
|
||||
|
||||
Scénario: Monitoring proactif pour éviter découverte tardive
|
||||
Étant donné que Sentry et Grafana sont configurés
|
||||
Quand un comportement anormal est détecté
|
||||
Alors une alerte est envoyée en temps réel
|
||||
Et l'équipe peut réagir avant qu'un breach majeur ne se produise
|
||||
Et les logs sont analysés quotidiennement pour détecter des anomalies
|
||||
Et cette approche proactive limite les risques de découverte tardive
|
||||
|
||||
# 13.10 - DPO (Délégué à la Protection des Données)
|
||||
|
||||
@dpo
|
||||
Scénario: Fondateur = DPO temporaire (MVP)
|
||||
Étant donné que RoadWave est en phase MVP
|
||||
Et que l'entreprise a moins de 250 employés
|
||||
Quand on vérifie l'obligation légale d'avoir un DPO
|
||||
Alors le DPO n'est pas obligatoire selon le RGPD Article 37
|
||||
Et le fondateur assume temporairement le rôle de DPO
|
||||
Et le fondateur suit la formation CNIL gratuite (4h)
|
||||
|
||||
Scénario: Formation CNIL du DPO temporaire
|
||||
Étant donné que le fondateur est DPO temporaire
|
||||
Quand on vérifie sa formation
|
||||
Alors le fondateur a suivi la formation CNIL en ligne (4h)
|
||||
Et le fondateur a obtenu la certification "Atelier RGPD" (gratuit)
|
||||
Et le certificat est conservé pour audit
|
||||
Et la formation couvre:
|
||||
| sujet |
|
||||
| Principes fondamentaux du RGPD |
|
||||
| Droits des personnes |
|
||||
| Sécurité des données |
|
||||
| Violations de données (breach) |
|
||||
| Registre des traitements |
|
||||
|
||||
Scénario: Contact DPO publié et accessible
|
||||
Étant donné que je consulte les mentions légales de RoadWave
|
||||
Quand je cherche le contact du DPO
|
||||
Alors l'email "dpo@roadwave.fr" est clairement affiché
|
||||
Et cet email est également dans les CGU
|
||||
Et le délai de réponse garanti est de 1 mois maximum (RGPD Article 12.3)
|
||||
Et une adresse postale est également fournie
|
||||
|
||||
Scénario: Demande d'exercice de droits RGPD au DPO
|
||||
Étant donné que je veux exercer mon droit d'accès à mes données
|
||||
Quand j'envoie un email à dpo@roadwave.fr
|
||||
Alors je reçois un accusé de réception dans les 48h
|
||||
Et ma demande est traitée dans un délai maximum de 1 mois
|
||||
Et si le délai dépasse 1 mois, je suis informé de la prolongation (max 2 mois supplémentaires)
|
||||
Et la réponse est complète et conforme au RGPD
|
||||
|
||||
Scénario: Types de demandes gérées par le DPO
|
||||
Étant donné que je contacte le DPO
|
||||
Quand j'envoie une demande
|
||||
Alors le DPO peut traiter les demandes suivantes:
|
||||
| type de demande |
|
||||
| Droit d'accès (Article 15) |
|
||||
| Droit de rectification (Article 16) |
|
||||
| Droit à l'effacement (Article 17) |
|
||||
| Droit à la portabilité (Article 20) |
|
||||
| Droit d'opposition (Article 21) |
|
||||
| Plainte RGPD |
|
||||
| Question sur le traitement des données |
|
||||
Et chaque demande reçoit une réponse personnalisée
|
||||
|
||||
Scénario: Migration vers DPO externe si croissance
|
||||
Étant donné que RoadWave dépasse 100 000 utilisateurs
|
||||
Quand la charge de travail DPO augmente
|
||||
Alors un DPO externe mutualisé est engagé
|
||||
Et le coût est d'environ 200€/mois
|
||||
Et le DPO externe a les certifications CNIL requises
|
||||
Et un contrat de sous-traitance RGPD est signé
|
||||
|
||||
Scénario: Recrutement DPO interne si >10 employés
|
||||
Étant donné que RoadWave a plus de 10 employés
|
||||
Quand l'entreprise se structure
|
||||
Alors un DPO interne peut être recruté
|
||||
Et le DPO interne a une certification CNIL (AFCDP ou équivalent)
|
||||
Et le DPO est indépendant et ne peut être licencié pour ses fonctions
|
||||
Et le DPO a un accès direct à la direction
|
||||
|
||||
# Coût total conformité RGPD
|
||||
|
||||
Scénario: Récapitulatif des coûts RGPD
|
||||
Étant donné que toutes les mesures RGPD sont en place
|
||||
Quand on calcule le coût total mensuel
|
||||
Alors le récapitulatif est le suivant:
|
||||
| mesure | implémentation | coût |
|
||||
| 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€ (< 5K events) |
|
||||
| DPO | Fondateur formé CNIL | 0€ |
|
||||
Et le coût total est d'environ 5€/mois
|
||||
Et cette conformité est 100% opensource et maîtrisée
|
||||
186
features/api/rgpd-compliance/consentement.feature
Normal file
186
features/api/rgpd-compliance/consentement.feature
Normal file
@@ -0,0 +1,186 @@
|
||||
# language: fr
|
||||
|
||||
@rgpd @consent
|
||||
Fonctionnalité: Gestion du consentement RGPD
|
||||
|
||||
Contexte:
|
||||
Étant donné que je suis un nouvel utilisateur
|
||||
Et que j'accède à l'application pour la première fois
|
||||
|
||||
# 13.1 - Gestion du consentement avec Tarteaucitron.js + PostgreSQL
|
||||
|
||||
Scénario: Affichage du banner de consentement au premier lancement web
|
||||
Étant donné que j'accède à l'application web pour la première fois
|
||||
Quand la page se charge
|
||||
Alors un banner RGPD Tarteaucitron.js s'affiche
|
||||
Et le banner est en français
|
||||
Et le banner propose les options suivantes:
|
||||
| option | description |
|
||||
| Tout accepter | Active tous les consentements |
|
||||
| Tout refuser | Refuse tous les consentements optionnels |
|
||||
| Personnaliser | Ouvre le panneau de personnalisation |
|
||||
Et le banner est customisé aux couleurs de RoadWave
|
||||
|
||||
Scénario: Granularité des consentements
|
||||
Étant donné que le banner RGPD est affiché
|
||||
Quand je clique sur "Personnaliser"
|
||||
Alors je vois les catégories de consentements suivantes:
|
||||
| catégorie | type | requis |
|
||||
| Fonctionnel | Nécessaire | oui |
|
||||
| Analytique | Optionnel | non |
|
||||
| Marketing | Optionnel | non |
|
||||
Et chaque catégorie a une description claire de son usage
|
||||
Et je peux accepter ou refuser chaque catégorie individuellement
|
||||
|
||||
Scénario: Consentement géolocalisation précise - obligatoire
|
||||
Étant donné que je suis sur l'application mobile
|
||||
Et que l'onboarding est terminé
|
||||
Quand l'application a besoin d'accéder à ma position précise
|
||||
Alors un écran de demande de consentement s'affiche
|
||||
Et le message explique clairement l'usage:
|
||||
"""
|
||||
RoadWave utilise votre position GPS pour vous proposer du contenu audio géolocalisé pertinent.
|
||||
Vos données sont anonymisées après 24h.
|
||||
"""
|
||||
Et je peux accepter ou refuser
|
||||
Et si je refuse, l'application bascule en mode dégradé (GeoIP uniquement)
|
||||
|
||||
Scénario: Double consentement GPS - banner app + permission OS
|
||||
Étant donné que je veux activer la géolocalisation précise
|
||||
Quand j'accepte le consentement dans l'application
|
||||
Alors l'application demande également la permission au système d'exploitation
|
||||
Et sur iOS, la popup système s'affiche: "Autoriser RoadWave à accéder à votre position ?"
|
||||
Et sur Android, la popup système s'affiche avec les options "Toujours autoriser / Autoriser seulement pendant l'utilisation / Refuser"
|
||||
Et les deux consentements (app + OS) doivent être acceptés pour activer le GPS précis
|
||||
|
||||
# Historique des consentements - PostgreSQL backend
|
||||
|
||||
Scénario: Enregistrement du consentement en base de données
|
||||
Étant donné que j'ai accepté les consentements suivants:
|
||||
| type | accepté |
|
||||
| Fonctionnel | oui |
|
||||
| Analytique | oui |
|
||||
| Marketing | non |
|
||||
| GPS précis | oui |
|
||||
Quand je valide mes choix
|
||||
Alors un enregistrement est créé dans la table `user_consents`
|
||||
Et l'enregistrement contient les champs suivants:
|
||||
| champ | valeur |
|
||||
| user_id | [mon ID utilisateur] |
|
||||
| consent_type | fonctionnel / analytique / gps |
|
||||
| version | 1 |
|
||||
| accepted | true / false |
|
||||
| timestamp | [date et heure exacte] |
|
||||
Et chaque type de consentement a un enregistrement séparé
|
||||
|
||||
Scénario: Versioning des consentements
|
||||
Étant donné que j'ai accepté le consentement "Analytique" version 1 le 2025-01-01
|
||||
Et que les CGU sont mises à jour le 2025-06-01
|
||||
Quand je me connecte après la mise à jour
|
||||
Alors un nouveau consentement version 2 m'est demandé
|
||||
Et mon ancien consentement version 1 reste dans l'historique
|
||||
Et je dois accepter la nouvelle version pour continuer à utiliser les analytics
|
||||
|
||||
Scénario: Historique complet conservé pour preuve légale
|
||||
Étant donné que j'ai modifié mes consentements plusieurs fois:
|
||||
| date | consent_type | accepted | version |
|
||||
| 2025-01-01 | Analytique | oui | 1 |
|
||||
| 2025-03-15 | Analytique | non | 1 |
|
||||
| 2025-06-01 | Analytique | oui | 2 |
|
||||
Quand un auditeur CNIL consulte mon historique de consentements
|
||||
Alors tous les enregistrements sont conservés
|
||||
Et l'historique prouve que chaque consentement a été donné librement
|
||||
Et les timestamps permettent de prouver la conformité à tout moment
|
||||
|
||||
# Consentements requis vs optionnels
|
||||
|
||||
Scénario: Consentement analytique - optionnel
|
||||
Étant donné que je refuse le consentement "Analytique"
|
||||
Quand j'utilise l'application
|
||||
Alors aucun cookie Matomo `_pk_id` n'est déposé
|
||||
Et aucune donnée d'usage n'est envoyée à Matomo
|
||||
Et l'application fonctionne normalement sans analytics
|
||||
|
||||
Scénario: Consentement notifications push - optionnel
|
||||
Étant donné que je refuse le consentement "Notifications push"
|
||||
Quand un créateur que je suis publie un nouveau contenu
|
||||
Alors je ne reçois pas de notification push
|
||||
Mais je peux voir le nouveau contenu dans l'application
|
||||
Et l'application fonctionne normalement
|
||||
|
||||
Scénario: Consentement GPS précis - requis pour fonctionnalités géo
|
||||
Étant donné que je refuse le consentement "GPS précis"
|
||||
Quand j'utilise l'application
|
||||
Alors je peux accéder aux contenus nationaux
|
||||
Mais les contenus géolocalisés précis (Ancré, Contextuel) ne sont pas disponibles
|
||||
Et les audio-guides nécessitent l'activation du GPS
|
||||
Et un banner permanent me rappelle que l'activation du GPS améliore l'expérience
|
||||
|
||||
# Modification des consentements
|
||||
|
||||
Scénario: Révocation d'un consentement depuis les paramètres
|
||||
Étant donné que j'ai accepté le consentement "Analytique"
|
||||
Et que j'utilise l'application depuis 3 mois
|
||||
Quand j'ouvre "Paramètres > Confidentialité > Gérer mes consentements"
|
||||
Alors je vois la liste de tous mes consentements actuels
|
||||
Et je peux révoquer le consentement "Analytique"
|
||||
Quand je révoque le consentement
|
||||
Alors un nouvel enregistrement est créé avec `accepted = false`
|
||||
Et le cookie Matomo est supprimé immédiatement
|
||||
Et les analytics sont désactivées à partir de ce moment
|
||||
|
||||
Scénario: Acceptation d'un consentement précédemment refusé
|
||||
Étant donné que j'avais refusé le consentement "GPS précis"
|
||||
Quand j'ouvre "Paramètres > Confidentialité > Gérer mes consentements"
|
||||
Et que je clique sur "Activer la géolocalisation précise"
|
||||
Alors un nouvel enregistrement est créé avec `accepted = true`
|
||||
Et la permission OS est demandée si ce n'est pas déjà fait
|
||||
Et l'application bascule en mode géolocalisation précise
|
||||
Et les contenus géolocalisés deviennent disponibles immédiatement
|
||||
|
||||
# Preuves légales pour contrôle CNIL
|
||||
|
||||
Scénario: Export de l'historique des consentements pour audit
|
||||
Étant donné qu'un contrôle CNIL est en cours
|
||||
Quand l'équipe RoadWave exporte l'historique des consentements
|
||||
Alors l'export contient pour chaque utilisateur:
|
||||
| champ | description |
|
||||
| user_id | ID anonymisé |
|
||||
| consent_type | Type de consentement |
|
||||
| version | Version des CGU/consentement |
|
||||
| accepted | Accepté ou refusé |
|
||||
| timestamp | Date et heure exacte |
|
||||
| ip_address | IP (anonymisée) au moment du consentement |
|
||||
| user_agent | Navigateur/app utilisé |
|
||||
Et l'export est au format CSV pour analyse
|
||||
Et les données prouvent la conformité RGPD
|
||||
|
||||
Scénario: Conformité recommandations CNIL
|
||||
Étant donné que le système de consentement est implémenté
|
||||
Quand un auditeur CNIL vérifie la conformité
|
||||
Alors le système respecte les critères suivants:
|
||||
| critère CNIL | respecté |
|
||||
| Consentement libre | oui |
|
||||
| Consentement spécifique (granulaire) | oui |
|
||||
| Consentement éclairé (information claire) | oui |
|
||||
| Consentement univoque (action positive) | oui |
|
||||
| Révocable à tout moment | oui |
|
||||
| Preuve du consentement conservée | oui |
|
||||
|
||||
# Opensource et self-hosted
|
||||
|
||||
Scénario: Tarteaucitron.js self-hosted
|
||||
Étant donné que l'application web utilise Tarteaucitron.js
|
||||
Quand je consulte les sources JavaScript chargées
|
||||
Alors le script Tarteaucitron.js est hébergé sur les serveurs RoadWave
|
||||
Et aucun script tiers (CDN externe) n'est chargé
|
||||
Et le code source de Tarteaucitron.js est vérifiable
|
||||
Et aucune donnée n'est envoyée à un tiers lors de l'affichage du banner
|
||||
|
||||
Scénario: Coût de la solution - 0€
|
||||
Étant donné que Tarteaucitron.js est opensource
|
||||
Et que PostgreSQL est utilisé pour le backend
|
||||
Quand on calcule le coût de la solution de consentement
|
||||
Alors le coût est de 0€
|
||||
Et la solution est entièrement maîtrisée (self-hosted)
|
||||
Et aucune dépendance à un service SaaS tiers
|
||||
245
features/api/rgpd-compliance/conservation-donnees.feature
Normal file
245
features/api/rgpd-compliance/conservation-donnees.feature
Normal file
@@ -0,0 +1,245 @@
|
||||
# language: fr
|
||||
|
||||
@rgpd @data-retention
|
||||
Fonctionnalité: Durée de conservation des données et purge automatique
|
||||
|
||||
# 13.6 - 5 ans inactivité → purge automatique (principe de minimisation RGPD)
|
||||
|
||||
Contexte:
|
||||
Étant donné que le système de purge automatique est actif
|
||||
|
||||
# Règles de conservation
|
||||
|
||||
Scénario: Auditeur inactif depuis 5 ans - suppression automatique
|
||||
Étant donné que je suis un auditeur (sans contenu créé)
|
||||
Et que je ne me suis pas connecté depuis le 2020-01-01
|
||||
Et que la date actuelle est 2025-01-02 (>5 ans)
|
||||
Quand le job de purge automatique s'exécute
|
||||
Alors mon compte est automatiquement supprimé
|
||||
Et toutes mes données personnelles sont effacées
|
||||
Et aucune trace ne subsiste dans la base de données
|
||||
|
||||
Scénario: Créateur avec contenus actifs - conservation indéfinie
|
||||
Étant donné que je suis un créateur
|
||||
Et que j'ai créé 10 contenus qui reçoivent encore des écoutes
|
||||
Et que je ne me suis pas connecté depuis 6 ans
|
||||
Quand le job de purge automatique s'exécute
|
||||
Alors mon compte n'est pas supprimé
|
||||
Et mes données personnelles sont conservées tant que mes contenus sont écoutés
|
||||
Et mes contenus continuent d'être diffusés normalement
|
||||
|
||||
Scénario: Créateur inactif sans écoutes - suppression automatique
|
||||
Étant donné que je suis un créateur
|
||||
Et que j'ai créé 5 contenus
|
||||
Et que je ne me suis pas connecté depuis 5 ans (depuis 2020-01-01)
|
||||
Et que mes contenus n'ont reçu aucune écoute depuis 2 ans (depuis 2023-01-01)
|
||||
Et que la date actuelle est 2025-01-02
|
||||
Quand le job de purge automatique s'exécute
|
||||
Alors mon compte est automatiquement supprimé
|
||||
Et mes contenus sont anonymisés (créateur = "Utilisateur supprimé")
|
||||
Et les fichiers audio restent disponibles mais anonymisés
|
||||
|
||||
# Notifications avant suppression
|
||||
|
||||
Scénario: Notifications par email avant purge
|
||||
Étant donné que je suis inactif depuis 4 ans et 9 mois
|
||||
Quand le système détecte que je suis éligible à la purge dans 90 jours
|
||||
Alors je reçois un email avec le sujet "Votre compte RoadWave sera supprimé dans 90 jours"
|
||||
Et l'email contient:
|
||||
"""
|
||||
Bonjour,
|
||||
|
||||
Votre compte RoadWave n'a pas été utilisé depuis plus de 4 ans.
|
||||
Conformément à notre politique de conservation des données, votre compte sera automatiquement supprimé dans 90 jours si vous ne vous connectez pas.
|
||||
|
||||
Pour conserver votre compte, il suffit de vous connecter avant le [date limite].
|
||||
|
||||
Date de dernière connexion: [date]
|
||||
Date de suppression prévue: [date + 90j]
|
||||
|
||||
Si vous ne souhaitez pas conserver ce compte, aucune action n'est requise.
|
||||
"""
|
||||
Et un lien de connexion est inclus dans l'email
|
||||
|
||||
Scénario: Rappels à 90j, 30j et 7j avant suppression
|
||||
Étant donné que je suis éligible à la purge automatique
|
||||
Quand les délais s'écoulent
|
||||
Alors je reçois les emails suivants:
|
||||
| délai | sujet email |
|
||||
| 90 jours | Votre compte sera supprimé dans 90 jours |
|
||||
| 30 jours | Rappel: Votre compte sera supprimé dans 30 jours |
|
||||
| 7 jours | Dernière alerte: suppression dans 7 jours |
|
||||
Et chaque email contient un lien de connexion pour réactiver le compte
|
||||
Et les notifications push sont également envoyées si activées
|
||||
|
||||
Scénario: Connexion annule la suppression programmée
|
||||
Étant donné que je suis éligible à la purge dans 15 jours
|
||||
Et que j'ai reçu plusieurs emails d'avertissement
|
||||
Quand je me connecte à mon compte
|
||||
Alors la suppression programmée est annulée immédiatement
|
||||
Et le compteur d'inactivité est remis à zéro
|
||||
Et je reçois un email de confirmation: "Votre compte a été réactivé"
|
||||
Et je peux continuer à utiliser l'application normalement
|
||||
|
||||
# Job de purge automatique
|
||||
|
||||
Scénario: Exécution quotidienne du job de purge
|
||||
Étant donné que le système est en production
|
||||
Quand on consulte les jobs planifiés
|
||||
Alors un job "purge_inactive_accounts" est configuré
|
||||
Et le job s'exécute tous les jours à 03:00 (heure creuse)
|
||||
Et le job identifie les comptes éligibles à la purge
|
||||
Et le job traite les suppressions automatiques
|
||||
|
||||
Scénario: Critères d'éligibilité à la purge
|
||||
Étant donné que le job de purge s'exécute
|
||||
Quand le système identifie les comptes éligibles
|
||||
Alors les critères suivants sont appliqués:
|
||||
| type_compte | critères |
|
||||
| Auditeur uniquement | 5 ans sans connexion |
|
||||
| Créateur avec contenus actifs| Jamais (tant qu'écoutes) |
|
||||
| Créateur inactif | 5 ans sans connexion + 2 ans sans écoute |
|
||||
Et seuls les comptes remplissant tous les critères sont supprimés
|
||||
|
||||
Scénario: Métriques du job de purge
|
||||
Étant donné que le job de purge s'exécute le 2025-01-15
|
||||
Quand le job se termine
|
||||
Alors un rapport est généré avec:
|
||||
| métrique | exemple |
|
||||
| Comptes analysés | 150 000 |
|
||||
| Comptes éligibles à la purge | 350 |
|
||||
| Auditeurs supprimés | 300 |
|
||||
| Créateurs inactifs supprimés | 50 |
|
||||
| Créateurs conservés (actifs) | 0 |
|
||||
| Erreurs | 0 |
|
||||
| Durée d'exécution | 45s |
|
||||
Et le rapport est loggé pour audit
|
||||
|
||||
# Contenus conservés après purge
|
||||
|
||||
Scénario: Contenus de comptes purgés conservés anonymement
|
||||
Étant donné que mon compte créateur est purgé automatiquement
|
||||
Quand la suppression est effective
|
||||
Alors mes contenus créés sont conservés indéfiniment
|
||||
Et les contenus sont anonymisés (créateur = "Utilisateur supprimé")
|
||||
Et les fichiers audio restent sur le CDN
|
||||
Et les statistiques d'écoute sont préservées
|
||||
Et les utilisateurs peuvent toujours écouter mes contenus
|
||||
|
||||
# Exception: créateurs avec écoutes régulières
|
||||
|
||||
Scénario: Créateur inactif mais contenus populaires - pas de purge
|
||||
Étant donné que je suis un créateur inactif depuis 6 ans
|
||||
Mais que mes contenus reçoivent 500+ écoutes par mois
|
||||
Quand le job de purge s'exécute
|
||||
Alors mon compte n'est pas supprimé
|
||||
Et je continue de recevoir les emails d'avertissement tous les 6 mois
|
||||
Et mes contenus continuent d'être diffusés
|
||||
Et je peux me reconnecter à tout moment
|
||||
|
||||
# Définition de "écoute" pour les créateurs
|
||||
|
||||
Scénario: Qu'est-ce qu'une "écoute" pour le calcul d'inactivité
|
||||
Étant donné que je suis un créateur
|
||||
Quand le système calcule si mes contenus sont "actifs"
|
||||
Alors une "écoute" est comptabilisée si:
|
||||
| condition | comptabilisée |
|
||||
| Écoute complète (>80%) | oui |
|
||||
| Écoute partielle (>30%) | oui |
|
||||
| Skip rapide (<30%) | non |
|
||||
| Écoute par un bot (détecté) | non |
|
||||
Et au moins 1 écoute valide dans les 2 dernières années maintient le compte actif
|
||||
|
||||
# Principe de minimisation RGPD
|
||||
|
||||
Scénario: Conformité principe de minimisation
|
||||
Étant donné que le système de purge automatique est en place
|
||||
Quand un auditeur RGPD vérifie la conformité
|
||||
Alors le système respecte le principe de minimisation:
|
||||
| principe | respecté |
|
||||
| Conservation limitée dans le temps | oui |
|
||||
| Suppression automatique après inactivité | oui |
|
||||
| Délai raisonnable (5 ans) | oui |
|
||||
| Notifications préalables | oui |
|
||||
| Exception justifiée (contenus actifs) | oui |
|
||||
Et le délai de 5 ans est conforme aux standards de l'industrie
|
||||
|
||||
# Reset du compteur d'inactivité
|
||||
|
||||
Scénario: Actions qui réinitialisent le compteur d'inactivité
|
||||
Étant donné que je suis inactif depuis 4 ans
|
||||
Quand j'effectue l'une des actions suivantes:
|
||||
| action |
|
||||
| Connexion à l'application |
|
||||
| Publication d'un nouveau contenu |
|
||||
| Like d'un contenu |
|
||||
| Abonnement à un créateur |
|
||||
| Modification de mon profil |
|
||||
Alors le compteur d'inactivité est remis à zéro
|
||||
Et la suppression programmée est annulée
|
||||
Et je ne suis plus éligible à la purge pour 5 ans
|
||||
|
||||
# Logs d'audit
|
||||
|
||||
Scénario: Traçabilité des suppressions automatiques
|
||||
Étant donné qu'un compte est supprimé automatiquement
|
||||
Quand la suppression est effective
|
||||
Alors un log d'audit est créé avec:
|
||||
| champ | valeur |
|
||||
| user_id | [ID anonymisé] |
|
||||
| account_type | auditeur / créateur |
|
||||
| last_login | 2020-01-15T10:00:00Z |
|
||||
| last_content_listen | 2023-06-01T14:30:00Z |
|
||||
| purge_date | 2025-01-15T03:00:00Z |
|
||||
| notifications_sent | 3 (90j, 30j, 7j) |
|
||||
| reason | 5_years_inactivity |
|
||||
Et le log est conservé 5 ans pour audit RGPD
|
||||
Et l'user_id est pseudonymisé pour anonymat
|
||||
|
||||
# Cas particuliers
|
||||
|
||||
Scénario: Compte Premium inactif - pas de privilège spécial
|
||||
Étant donné que je suis un utilisateur Premium
|
||||
Et que je suis inactif depuis 5 ans
|
||||
Quand le job de purge s'exécute
|
||||
Alors mon compte est supprimé comme un compte gratuit
|
||||
Et l'abonnement Premium ne prolonge pas la durée de conservation
|
||||
Et aucun remboursement n'est effectué (compte inactif depuis 5 ans)
|
||||
|
||||
Scénario: Compte avec signalements de modération - purge différée
|
||||
Étant donné que je suis éligible à la purge
|
||||
Mais que j'ai des signalements de modération en cours
|
||||
Quand le job de purge s'exécute
|
||||
Alors ma purge est différée de 90 jours
|
||||
Et les signalements sont traités en priorité
|
||||
Et si les signalements aboutissent à un ban, le compte est supprimé immédiatement
|
||||
Et si les signalements sont infondés, la purge automatique reprend son cours
|
||||
|
||||
# Durée de 5 ans - justification
|
||||
|
||||
Scénario: Pourquoi 5 ans d'inactivité
|
||||
Étant donné que le délai de purge est fixé à 5 ans
|
||||
Quand on justifie ce choix
|
||||
Alors les raisons suivantes sont avancées:
|
||||
| justification |
|
||||
| Standard de l'industrie (Google, Facebook: 2-3 ans) |
|
||||
| Équilibre raisonnable entre minimisation et utilité |
|
||||
| Conforme aux recommandations CNIL |
|
||||
| Laisse une marge de réactivation pour utilisateurs |
|
||||
| Exception pour créateurs = intérêt légitime communauté |
|
||||
|
||||
# Communication transparente
|
||||
|
||||
Scénario: Politique de conservation visible dans les CGU
|
||||
Étant donné que je consulte les CGU de RoadWave
|
||||
Quand je lis la section "Conservation des données"
|
||||
Alors la politique de purge automatique est clairement expliquée:
|
||||
"""
|
||||
Conservation des données:
|
||||
- Comptes auditeurs: suppression automatique après 5 ans d'inactivité
|
||||
- Comptes créateurs: suppression après 5 ans d'inactivité + 2 ans sans écoute de leurs contenus
|
||||
- Exception: créateurs dont les contenus sont encore écoutés régulièrement
|
||||
- Notifications: 90j, 30j et 7j avant suppression
|
||||
- Contenus créés: conservés de manière anonyme après suppression du compte
|
||||
"""
|
||||
Et les utilisateurs sont informés dès l'inscription
|
||||
227
features/api/rgpd-compliance/cookies-analytics.feature
Normal file
227
features/api/rgpd-compliance/cookies-analytics.feature
Normal file
@@ -0,0 +1,227 @@
|
||||
# language: fr
|
||||
|
||||
@rgpd @cookies @analytics
|
||||
Fonctionnalité: Cookies et analytics avec Matomo self-hosted
|
||||
|
||||
# 13.7 - Matomo self-hosted, zéro cookie tiers (souveraineté données)
|
||||
|
||||
Contexte:
|
||||
Étant donné que je suis un utilisateur de l'application web RoadWave
|
||||
|
||||
# Liste des cookies utilisés
|
||||
|
||||
Scénario: Cookies strictement nécessaires - pas de consentement requis
|
||||
Étant donné que j'accède à l'application web
|
||||
Quand je me connecte
|
||||
Alors les cookies techniques suivants sont déposés:
|
||||
| cookie | type | durée | finalité | consentement |
|
||||
| session | Technique | 30j | Authentification | Non requis |
|
||||
| refresh_token | Technique | 30j | Session persistante | Non requis |
|
||||
Et ces cookies sont essentiels au fonctionnement de l'application
|
||||
Et ils sont exemptés de consentement selon l'article 82 de la loi Informatique et Libertés
|
||||
|
||||
Scénario: Cookie analytique Matomo - consentement requis
|
||||
Étant donné que j'ai accepté le consentement "Analytique"
|
||||
Quand je navigue sur l'application web
|
||||
Alors le cookie `_pk_id` est déposé
|
||||
Et la durée de conservation est de 13 mois
|
||||
Et ce cookie sert à Matomo pour analytics
|
||||
Et mon IP est automatiquement anonymisée (2 derniers octets)
|
||||
|
||||
Scénario: Refus du consentement analytique - pas de cookie Matomo
|
||||
Étant donné que j'ai refusé le consentement "Analytique"
|
||||
Quand je navigue sur l'application web
|
||||
Alors aucun cookie `_pk_id` n'est déposé
|
||||
Et aucune donnée d'usage n'est collectée
|
||||
Et l'application fonctionne normalement sans analytics
|
||||
|
||||
# Matomo self-hosted
|
||||
|
||||
Scénario: Matomo hébergé sur les serveurs RoadWave
|
||||
Étant donné que RoadWave utilise Matomo pour les analytics
|
||||
Quand on analyse l'infrastructure
|
||||
Alors Matomo est installé sur les serveurs RoadWave (Docker)
|
||||
Et aucune donnée n'est envoyée à un service tiers
|
||||
Et toutes les données restent dans l'UE
|
||||
Et l'accès à Matomo est restreint à l'équipe RoadWave
|
||||
|
||||
Scénario: IP anonymisées automatiquement
|
||||
Étant donné que Matomo collecte des données d'usage
|
||||
Quand une requête est enregistrée
|
||||
Alors l'adresse IP est automatiquement anonymisée
|
||||
Et les 2 derniers octets sont remplacés par des zéros
|
||||
Et une IP 192.168.1.100 devient 192.168.0.0
|
||||
Et cette anonymisation est irréversible
|
||||
Et elle est conforme aux recommandations CNIL
|
||||
|
||||
Scénario: Configuration Matomo conforme RGPD
|
||||
Étant donné que Matomo est configuré pour RoadWave
|
||||
Quand on vérifie les paramètres
|
||||
Alors les configurations suivantes sont activées:
|
||||
| paramètre | valeur |
|
||||
| Anonymisation IP (2 octets) | activé |
|
||||
| Respect Do Not Track | activé |
|
||||
| Suppression auto anciens logs (25 mois)| activé |
|
||||
| Géolocalisation IP désactivée | activé |
|
||||
| User ID anonymisé | activé |
|
||||
Et la configuration est RGPD-compliant
|
||||
|
||||
# Trackers interdits
|
||||
|
||||
Scénario: Aucun tracker tiers utilisé
|
||||
Étant donné que j'accède à l'application web
|
||||
Quand j'inspecte les requêtes réseau avec les DevTools
|
||||
Alors aucune requête n'est envoyée vers les domaines suivants:
|
||||
| domaine tiers interdit |
|
||||
| google-analytics.com |
|
||||
| facebook.com (Pixel) |
|
||||
| hotjar.com |
|
||||
| mixpanel.com |
|
||||
| segment.io |
|
||||
| amplitude.com |
|
||||
Et toutes les requêtes analytics vont uniquement vers matomo.roadwave.fr
|
||||
|
||||
Scénario: Conformité zéro cookie tiers
|
||||
Étant donné que j'analyse les cookies déposés sur roadwave.fr
|
||||
Quand je consulte la liste des cookies
|
||||
Alors tous les cookies sont first-party (domaine roadwave.fr)
|
||||
Et aucun cookie tiers (third-party) n'est présent
|
||||
Et cette politique respecte les recommandations CNIL 2020
|
||||
|
||||
# Alternative: Plausible (si besoin)
|
||||
|
||||
Scénario: Alternative Plausible SaaS (EU-hosted)
|
||||
Étant donné que RoadWave pourrait utiliser Plausible au lieu de Matomo
|
||||
Quand on compare les deux solutions
|
||||
Alors Plausible a les caractéristiques suivantes:
|
||||
| caractéristique | valeur |
|
||||
| Hébergement | UE (Allemagne) |
|
||||
| Conformité RGPD | Natif (pas de cookie) |
|
||||
| Coût | 9€/mois (50K pageviews) |
|
||||
| IP anonymisées | Automatique |
|
||||
| Consentement requis | Non (selon CNIL 2020) |
|
||||
Mais Matomo self-hosted reste le choix prioritaire (0€, contrôle total)
|
||||
|
||||
# Souveraineté des données
|
||||
|
||||
Scénario: Aucun transfert de données hors UE
|
||||
Étant donné que Matomo est self-hosted
|
||||
Quand on analyse les flux de données
|
||||
Alors aucune donnée d'analytics n'est transférée hors de l'UE
|
||||
Et les serveurs sont localisés en France
|
||||
Et aucun transfert vers les US (pas de Privacy Shield / DPF requis)
|
||||
Et la souveraineté des données est garantie
|
||||
|
||||
# Coût de la solution
|
||||
|
||||
Scénario: Matomo self-hosted - coût estimé
|
||||
Étant donné que Matomo est hébergé sur l'infrastructure RoadWave
|
||||
Quand on calcule le coût mensuel
|
||||
Alors le coût est d'environ 5€/mois:
|
||||
| composant | coût |
|
||||
| Serveur supplémentaire | 0€ (mutualisé) |
|
||||
| Base de données MySQL | 0€ (mutualisé) |
|
||||
| Stockage logs (25 mois) | ~5€/mois |
|
||||
| License Matomo | 0€ (opensource) |
|
||||
Et ce coût est marginal comparé à un SaaS tiers (9-50€/mois)
|
||||
|
||||
# Respect Do Not Track
|
||||
|
||||
Scénario: Respect du signal Do Not Track (DNT)
|
||||
Étant donné que mon navigateur envoie le header "DNT: 1"
|
||||
Quand j'accède à l'application web
|
||||
Alors Matomo détecte le signal DNT
|
||||
Et aucune donnée d'usage n'est collectée
|
||||
Et aucun cookie `_pk_id` n'est déposé
|
||||
Et l'application fonctionne normalement
|
||||
Et un message discret s'affiche: "Vos préférences de confidentialité sont respectées (DNT activé)"
|
||||
|
||||
# Suppression automatique des anciens logs
|
||||
|
||||
Scénario: Logs Matomo supprimés après 25 mois
|
||||
Étant donné que Matomo collecte des données d'usage
|
||||
Quand les logs atteignent 25 mois d'ancienneté
|
||||
Alors un job automatique supprime les anciens logs
|
||||
Et seules les données agrégées (rapports) sont conservées
|
||||
Et les données brutes (logs) sont supprimées définitivement
|
||||
Et cette politique respecte le principe de minimisation RGPD
|
||||
|
||||
# Métriques collectées par Matomo
|
||||
|
||||
Scénario: Données collectées par Matomo
|
||||
Étant donné que j'ai accepté le consentement "Analytique"
|
||||
Quand je navigue sur l'application web
|
||||
Alors Matomo collecte les données suivantes:
|
||||
| donnée collectée | anonymisée |
|
||||
| Pages visitées | non |
|
||||
| Durée de visite | non |
|
||||
| Navigateur / OS | non |
|
||||
| Résolution écran | non |
|
||||
| Provenance (referrer) | non |
|
||||
| IP (2 derniers octets) | oui |
|
||||
| User ID (hashé) | oui |
|
||||
Et aucune donnée personnelle identifiable n'est collectée
|
||||
|
||||
Scénario: User ID hashé pour analytics
|
||||
Étant donné que je suis connecté à l'application
|
||||
Et que j'ai accepté le consentement "Analytique"
|
||||
Quand Matomo enregistre mes actions
|
||||
Alors mon user_id est hashé (SHA-256)
|
||||
Et le hash est 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
|
||||
Et il est impossible de retrouver mon user_id original depuis ce hash
|
||||
Et ce processus garantit l'anonymat
|
||||
|
||||
# Conformité CNIL 2020
|
||||
|
||||
Scénario: Conformité recommandations CNIL sur les cookies
|
||||
Étant donné que RoadWave utilise Matomo self-hosted
|
||||
Quand un auditeur CNIL vérifie la conformité
|
||||
Alors le système respecte les recommandations CNIL 2020:
|
||||
| recommandation CNIL | respecté |
|
||||
| Consentement requis pour cookies analytics | oui |
|
||||
| IP anonymisées | oui |
|
||||
| Pas de transfert hors UE | oui |
|
||||
| Durée conservation limitée (25 mois) | oui |
|
||||
| Respect Do Not Track | oui |
|
||||
| Transparence (liste cookies dans CGU) | oui |
|
||||
|
||||
# Tarteaucitron.js - gestion du consentement
|
||||
|
||||
Scénario: Intégration Tarteaucitron.js pour gérer Matomo
|
||||
Étant donné que Tarteaucitron.js gère les consentements
|
||||
Quand je personnalise mes consentements
|
||||
Alors je vois l'option "Analytique (Matomo)"
|
||||
Et une description est affichée:
|
||||
"""
|
||||
Matomo nous aide à comprendre comment vous utilisez l'application pour l'améliorer.
|
||||
Vos données restent anonymes et ne sont jamais partagées avec des tiers.
|
||||
"""
|
||||
Et je peux activer ou désactiver Matomo indépendamment
|
||||
Et si je désactive, le cookie `_pk_id` est supprimé immédiatement
|
||||
|
||||
# Application mobile - analytics
|
||||
|
||||
Scénario: Analytics sur application mobile
|
||||
Étant donné que j'utilise l'application mobile
|
||||
Quand j'accepte le consentement "Analytique"
|
||||
Alors l'app utilise le SDK Matomo Mobile
|
||||
Et les données sont envoyées à la même instance Matomo self-hosted
|
||||
Et les mêmes règles d'anonymisation s'appliquent
|
||||
Et aucun SDK tiers (Google Analytics, Firebase) n'est utilisé
|
||||
|
||||
Scénario: Refus analytics sur mobile
|
||||
Étant donné que j'ai refusé le consentement "Analytique" sur mobile
|
||||
Quand j'utilise l'application
|
||||
Alors aucune donnée d'usage n'est collectée
|
||||
Et le SDK Matomo est désactivé
|
||||
Et l'application fonctionne normalement sans différence d'UX
|
||||
|
||||
# Opensource et auditabilité
|
||||
|
||||
Scénario: Matomo opensource et auditable
|
||||
Étant donné que Matomo est opensource
|
||||
Quand on consulte le code source
|
||||
Alors le code est disponible publiquement sur GitHub
|
||||
Et le code peut être audité par des experts indépendants
|
||||
Et aucune backdoor ou collecte cachée n'est possible
|
||||
Et cette transparence renforce la confiance utilisateur
|
||||
224
features/api/rgpd-compliance/mode-degrade-geoip.feature
Normal file
224
features/api/rgpd-compliance/mode-degrade-geoip.feature
Normal file
@@ -0,0 +1,224 @@
|
||||
# language: fr
|
||||
|
||||
@rgpd @geoip @degraded-mode
|
||||
Fonctionnalité: Mode dégradé avec GeoIP (sans GPS précis)
|
||||
|
||||
# 13.5 - GeoIP par défaut, GPS optionnel (progressive disclosure)
|
||||
|
||||
Contexte:
|
||||
Étant donné que je suis un nouvel utilisateur
|
||||
Et que je lance l'application pour la première fois
|
||||
|
||||
# Niveaux de précision
|
||||
|
||||
Plan du Scénario: Trois niveaux de géolocalisation disponibles
|
||||
Étant donné que j'utilise le niveau de géolocalisation "<niveau>"
|
||||
Quand le système détermine ma position
|
||||
Alors la technologie utilisée est "<technologie>"
|
||||
Et les contenus accessibles sont "<contenus>"
|
||||
Et le consentement RGPD est "<consentement>"
|
||||
|
||||
Exemples:
|
||||
| niveau | technologie | contenus | consentement |
|
||||
| Pays | Aucune géoloc | Contenus nationaux uniquement | Non requis |
|
||||
| Ville | GeoIP (IP2Location) | Contenus régionaux/ville | Non requis |
|
||||
| Précis | GPS | Tous contenus (hyperlocaux inclus) | Requis |
|
||||
|
||||
# Démarrage avec GeoIP automatique
|
||||
|
||||
Scénario: GeoIP activé par défaut au premier lancement
|
||||
Étant donné que je lance l'application pour la première fois
|
||||
Et que je n'ai pas encore accepté le GPS précis
|
||||
Quand l'application démarre
|
||||
Alors le système utilise automatiquement GeoIP basé sur mon adresse IP
|
||||
Et ma position est détectée au niveau ville: "Paris, France"
|
||||
Et aucun consentement n'est requis (GeoIP ne collecte pas de données personnelles)
|
||||
Et je peux accéder aux contenus régionaux et de ville
|
||||
|
||||
Scénario: Détection de ville avec IP2Location Lite
|
||||
Étant donné que mon adresse IP est 93.184.216.34
|
||||
Quand le système utilise GeoIP IP2Location Lite
|
||||
Alors ma ville est détectée: "Paris"
|
||||
Et ma région est détectée: "Île-de-France"
|
||||
Et mon pays est détecté: "France"
|
||||
Et la précision est d'environ 80% au niveau ville
|
||||
Et aucune coordonnée GPS précise n'est révélée
|
||||
|
||||
# Banner in-app pour upgrade vers GPS
|
||||
|
||||
Scénario: Banner d'invitation à activer le GPS
|
||||
Étant donné que j'utilise l'application en mode GeoIP
|
||||
Quand je suis sur l'écran principal
|
||||
Alors un banner discret s'affiche en haut:
|
||||
"""
|
||||
Activez la géolocalisation pour découvrir du contenu près de chez vous
|
||||
[Activer]
|
||||
"""
|
||||
Et le banner n'est pas intrusif (pas de popup modale)
|
||||
Et je peux le fermer temporairement avec un bouton X
|
||||
Et le banner réapparaît tous les 7 jours si je ne l'active pas
|
||||
|
||||
Scénario: Upgrade volontaire vers GPS depuis le banner
|
||||
Étant donné que le banner d'invitation au GPS est affiché
|
||||
Quand je clique sur "Activer"
|
||||
Alors un écran de consentement GPS s'affiche
|
||||
Et l'écran explique les avantages:
|
||||
"""
|
||||
En activant la géolocalisation précise, vous pouvez:
|
||||
- Découvrir du contenu hyperlocal près de vous
|
||||
- Accéder aux audio-guides géolocalisés
|
||||
- Recevoir des notifications quand vous passez près de points d'intérêt
|
||||
"""
|
||||
Et je peux accepter ou refuser
|
||||
Et si j'accepte, la permission OS est demandée
|
||||
|
||||
# Contenus accessibles selon le niveau
|
||||
|
||||
Scénario: Contenus disponibles en mode Pays (aucune géoloc)
|
||||
Étant donné que je n'autorise aucune géolocalisation
|
||||
Quand le système recherche du contenu à me proposer
|
||||
Alors seuls les contenus "National" sont disponibles
|
||||
Et les contenus géolocalisés (Ancré, Contextuel) ne sont pas proposés
|
||||
Et je vois un message: "Activez la géolocalisation pour plus de contenu local"
|
||||
|
||||
Scénario: Contenus disponibles en mode Ville (GeoIP)
|
||||
Étant donné que j'utilise le mode GeoIP et que je suis détecté à Paris
|
||||
Quand le système recherche du contenu à me proposer
|
||||
Alors les contenus suivants sont disponibles:
|
||||
| type_contenu | disponible |
|
||||
| National | oui |
|
||||
| Région Île-de-France | oui |
|
||||
| Ville Paris | oui |
|
||||
| Hyperlocal (GPS) | non |
|
||||
| Audio-guides | non |
|
||||
Et je reçois des recommandations pertinentes pour Paris
|
||||
|
||||
Scénario: Tous contenus disponibles en mode Précis (GPS)
|
||||
Étant donné que j'ai activé la géolocalisation précise
|
||||
Quand le système recherche du contenu à me proposer
|
||||
Alors tous les types de contenus sont disponibles:
|
||||
| type_contenu | disponible |
|
||||
| National | oui |
|
||||
| Régional | oui |
|
||||
| Ville | oui |
|
||||
| Hyperlocal (Ancré) | oui |
|
||||
| Contextuel | oui |
|
||||
| Audio-guides | oui |
|
||||
|
||||
# Pas de consentement requis pour GeoIP
|
||||
|
||||
Scénario: GeoIP ne nécessite pas de consentement RGPD
|
||||
Étant donné que j'utilise le mode GeoIP
|
||||
Quand un auditeur CNIL vérifie la conformité
|
||||
Alors GeoIP n'est pas considéré comme une donnée personnelle
|
||||
Et l'adresse IP n'est pas conservée après détection de la ville
|
||||
Et seule la ville est stockée (non identifiant)
|
||||
Et aucun consentement n'est requis conformément au RGPD
|
||||
|
||||
# Implémentation IP2Location Lite
|
||||
|
||||
Scénario: Base de données IP2Location self-hosted
|
||||
Étant donné que RoadWave utilise IP2Location Lite
|
||||
Quand on analyse l'infrastructure
|
||||
Alors la base de données IP2Location est hébergée sur les serveurs RoadWave
|
||||
Et aucune requête n'est envoyée à un service tiers
|
||||
Et la base de données est mise à jour automatiquement chaque mois
|
||||
Et le coût est de 0€ (IP2Location Lite est gratuit)
|
||||
|
||||
Scénario: Mise à jour mensuelle de la base GeoIP
|
||||
Étant donné que IP2Location publie des mises à jour mensuelles
|
||||
Quand le 1er du mois arrive
|
||||
Alors un job automatique télécharge la nouvelle base IP2Location Lite
|
||||
Et la base est mise à jour sans interruption de service
|
||||
Et un log est créé pour traçabilité
|
||||
Et si la mise à jour échoue, une alerte est envoyée
|
||||
|
||||
# Progressive disclosure - UX dégradée acceptable
|
||||
|
||||
Scénario: UX acceptable en mode GeoIP
|
||||
Étant donné que j'utilise le mode GeoIP à Paris
|
||||
Quand je parcours l'application
|
||||
Alors je peux écouter du contenu pertinent pour Paris et l'Île-de-France
|
||||
Et l'expérience est satisfaisante même sans GPS précis
|
||||
Et je ne suis pas bloqué dans l'utilisation de l'application
|
||||
Et je peux choisir d'activer le GPS quand je le souhaite
|
||||
|
||||
Scénario: Incitation progressive à activer le GPS
|
||||
Étant donné que j'utilise le mode GeoIP depuis 2 semaines
|
||||
Et que je n'ai pas activé le GPS
|
||||
Quand je consulte un audio-guide dans les résultats de recherche
|
||||
Alors un message s'affiche:
|
||||
"""
|
||||
Cet audio-guide nécessite la géolocalisation précise pour fonctionner.
|
||||
[Activer le GPS] [Plus tard]
|
||||
"""
|
||||
Et si je clique "Plus tard", je peux continuer à utiliser l'app normalement
|
||||
Et l'incitation reste douce et non intrusive
|
||||
|
||||
# Passage d'un mode à l'autre
|
||||
|
||||
Scénario: Upgrade GeoIP vers GPS
|
||||
Étant donné que j'utilise le mode GeoIP
|
||||
Quand j'active la géolocalisation précise
|
||||
Alors le système bascule immédiatement en mode GPS
|
||||
Et les contenus hyperlocaux deviennent disponibles
|
||||
Et mon feed se rafraîchit avec du contenu plus précis
|
||||
Et un toast de confirmation s'affiche: "Géolocalisation activée"
|
||||
|
||||
Scénario: Downgrade GPS vers GeoIP
|
||||
Étant donné que j'utilise le mode GPS précis
|
||||
Quand je désactive la géolocalisation dans les paramètres OS
|
||||
Alors le système bascule automatiquement en mode GeoIP
|
||||
Et les contenus hyperlocaux ne sont plus proposés
|
||||
Et un banner s'affiche: "Géolocalisation désactivée. Seul le contenu régional est disponible."
|
||||
Et l'application continue de fonctionner normalement
|
||||
|
||||
# Détection automatique du mode
|
||||
|
||||
Scénario: Détection automatique au démarrage de l'app
|
||||
Étant donné que j'ouvre l'application
|
||||
Quand l'app vérifie les permissions de géolocalisation
|
||||
Alors le système détecte automatiquement le mode disponible:
|
||||
| permission GPS | consentement app | mode activé |
|
||||
| Refusée | Non demandé | Pays |
|
||||
| Refusée | Accepté | GeoIP |
|
||||
| Accordée | Accepté | GPS précis |
|
||||
Et le mode est appliqué sans interaction utilisateur
|
||||
|
||||
# Précision GeoIP ~80%
|
||||
|
||||
Scénario: Précision acceptable pour la plupart des cas
|
||||
Étant donné que j'habite à Lyon
|
||||
Et que mon IP est une IP résidentielle standard
|
||||
Quand le système utilise GeoIP pour me localiser
|
||||
Alors la ville détectée est "Lyon" (correct à 80%)
|
||||
Et dans 20% des cas, la ville peut être légèrement erronée (banlieue proche)
|
||||
Et cette précision est suffisante pour proposer du contenu régional pertinent
|
||||
|
||||
Scénario: GeoIP avec VPN ou proxy
|
||||
Étant donné que j'utilise un VPN avec une IP sortante à Paris
|
||||
Mais que je suis physiquement à Lyon
|
||||
Quand le système utilise GeoIP
|
||||
Alors la ville détectée est "Paris" (IP du VPN)
|
||||
Et les contenus proposés sont pour Paris
|
||||
Et je peux activer le GPS précis pour corriger la localisation
|
||||
|
||||
# Conformité RGPD
|
||||
|
||||
Scénario: Pas de donnée personnelle collectée avec GeoIP
|
||||
Étant donné que j'utilise le mode GeoIP
|
||||
Quand le système détermine ma ville via mon IP
|
||||
Alors l'adresse IP n'est pas conservée après détection
|
||||
Et seule la ville "Paris" est stockée en base de données
|
||||
Et la ville seule n'est pas une donnée personnelle (RGPD)
|
||||
Et aucun consentement n'est donc requis
|
||||
|
||||
# Coût de la solution: 0€
|
||||
|
||||
Scénario: Solution GeoIP gratuite et self-hosted
|
||||
Étant donné que RoadWave utilise IP2Location Lite
|
||||
Quand on calcule le coût de la solution
|
||||
Alors le coût est de 0€
|
||||
Et la solution est opensource
|
||||
Et la base de données est hébergée sur les serveurs RoadWave
|
||||
Et aucun coût SaaS tiers
|
||||
282
features/api/rgpd-compliance/portabilite-donnees.feature
Normal file
282
features/api/rgpd-compliance/portabilite-donnees.feature
Normal file
@@ -0,0 +1,282 @@
|
||||
# language: fr
|
||||
|
||||
@rgpd @data-portability
|
||||
Fonctionnalité: Portabilité des données (Article 20 RGPD)
|
||||
|
||||
# 13.3 - Export JSON + HTML + ZIP, génération asynchrone
|
||||
|
||||
Contexte:
|
||||
Étant donné que je suis un utilisateur connecté
|
||||
Et que j'ai utilisé l'application depuis 6 mois
|
||||
|
||||
Scénario: Demande d'export depuis les paramètres
|
||||
Étant donné que je suis dans "Paramètres > Confidentialité"
|
||||
Quand je clique sur "Exporter mes données"
|
||||
Alors une page d'information s'affiche expliquant:
|
||||
"""
|
||||
Vous allez recevoir une archive contenant toutes vos données personnelles:
|
||||
- Profil et informations de compte
|
||||
- Historique d'écoute complet
|
||||
- Contenus audio que vous avez créés
|
||||
- Abonnements et likes
|
||||
- Centres d'intérêt
|
||||
- Historique des consentements
|
||||
|
||||
L'export sera généré sous 48h maximum et vous recevrez un email avec un lien de téléchargement valide 7 jours.
|
||||
"""
|
||||
Et un bouton "Confirmer l'export" est disponible
|
||||
|
||||
Scénario: Confirmation et démarrage de l'export
|
||||
Étant donné que je clique sur "Confirmer l'export"
|
||||
Quand la demande est validée
|
||||
Alors un message de confirmation s'affiche:
|
||||
"""
|
||||
Votre demande d'export a été prise en compte. Vous recevrez un email sous 48h avec un lien de téléchargement.
|
||||
"""
|
||||
Et un worker background démarre la génération de l'export
|
||||
Et le statut de l'export est "En cours de génération"
|
||||
Et je peux voir le statut dans "Paramètres > Confidentialité > Mes exports"
|
||||
|
||||
# Structure de l'export
|
||||
|
||||
Scénario: Contenu de l'archive ZIP
|
||||
Étant donné que mon export est généré
|
||||
Quand je télécharge et ouvre l'archive
|
||||
Alors l'archive a la structure suivante:
|
||||
"""
|
||||
export-roadwave-[user_id]-[date].zip
|
||||
├── export.json # Machine-readable (JSON complet)
|
||||
├── index.html # Human-readable (stylé, navigation)
|
||||
├── audio/
|
||||
│ ├── content-123.opus # Mes contenus créés
|
||||
│ ├── content-456.opus
|
||||
│ └── ...
|
||||
└── README.txt # Instructions et informations
|
||||
"""
|
||||
Et tous les fichiers sont inclus
|
||||
|
||||
Scénario: Contenu du fichier export.json
|
||||
Étant donné que j'ouvre le fichier export.json
|
||||
Quand j'analyse le contenu
|
||||
Alors le JSON contient les sections suivantes:
|
||||
| section | description |
|
||||
| profile | Email, pseudo, date inscription, bio |
|
||||
| listening_history | Historique complet d'écoute |
|
||||
| created_contents | Métadonnées des contenus créés |
|
||||
| subscriptions | Liste des créateurs suivis |
|
||||
| likes | Liste des contenus likés |
|
||||
| interest_gauges | Valeurs des jauges d'intérêt |
|
||||
| consent_history | Historique des consentements |
|
||||
| premium_subscription | Informations abonnement Premium |
|
||||
Et le JSON est formaté de manière lisible (indentation)
|
||||
Et toutes les dates sont au format ISO 8601
|
||||
|
||||
Scénario: Contenu du fichier index.html
|
||||
Étant donné que j'ouvre le fichier index.html dans un navigateur
|
||||
Quand la page se charge
|
||||
Alors je vois un site web stylé avec navigation
|
||||
Et les sections suivantes sont affichées:
|
||||
| section | contenu |
|
||||
| Mon profil | Email, pseudo, date inscription, statistiques |
|
||||
| Historique d'écoute | Liste paginée avec dates, titres, durées |
|
||||
| Mes contenus | Liste avec lectures audio intégrées |
|
||||
| Mes abonnements | Grille des créateurs suivis |
|
||||
| Mes likes | Liste des contenus likés avec liens |
|
||||
| Centres d'intérêt | Graphiques des jauges |
|
||||
| Consentements | Historique des acceptations/refus |
|
||||
Et la navigation est intuitive (menu latéral)
|
||||
Et le design est responsive (mobile/desktop)
|
||||
|
||||
Scénario: Fichiers audio inclus dans l'export
|
||||
Étant donné que j'ai créé 5 contenus audio
|
||||
Quand mon export est généré
|
||||
Alors le dossier `audio/` contient mes 5 fichiers
|
||||
Et les fichiers sont au format Opus original
|
||||
Et chaque fichier est nommé: `content-[id].opus`
|
||||
Et les fichiers audio correspondent aux métadonnées dans export.json
|
||||
|
||||
Scénario: Fichier README.txt explicatif
|
||||
Étant donné que j'ouvre le fichier README.txt
|
||||
Quand je lis le contenu
|
||||
Alors le fichier explique:
|
||||
"""
|
||||
Bienvenue dans votre export de données RoadWave.
|
||||
|
||||
Contenu de l'archive:
|
||||
- export.json: Toutes vos données au format JSON (machine-readable)
|
||||
- index.html: Visualisation web de vos données (ouvrir dans un navigateur)
|
||||
- audio/: Vos contenus audio créés au format Opus
|
||||
|
||||
Cet export a été généré le [date] et contient toutes vos données personnelles conformément à l'article 20 du RGPD.
|
||||
|
||||
Pour toute question: dpo@roadwave.fr
|
||||
"""
|
||||
|
||||
# Données exportées en détail
|
||||
|
||||
Plan du Scénario: Données de profil exportées
|
||||
Étant donné que mon export est généré
|
||||
Quand j'ouvre export.json et lis la section "profile"
|
||||
Alors je trouve les données suivantes:
|
||||
| champ | exemple |
|
||||
| email | user@example.com |
|
||||
| pseudo | @roadwave_user |
|
||||
| date_inscription | 2025-01-15T10:30:00Z |
|
||||
| bio | Passionné d'automobile... |
|
||||
| avatar_url | https://cdn.roadwave.fr/... |
|
||||
| compte_verifie | false |
|
||||
| premium | true |
|
||||
|
||||
Scénario: Historique d'écoute exporté
|
||||
Étant donné que j'ai écouté 150 contenus depuis 6 mois
|
||||
Quand mon export est généré
|
||||
Alors la section "listening_history" contient 150 entrées
|
||||
Et chaque entrée contient:
|
||||
| champ | exemple |
|
||||
| content_id | C123 |
|
||||
| content_title | Histoire de la Tour Eiffel |
|
||||
| creator_name | @historien_paris |
|
||||
| listened_at | 2025-01-20T15:30:00Z |
|
||||
| duration_listened | 180 (secondes) |
|
||||
| completion_rate | 0.85 (85%) |
|
||||
| location | [geohash ou coords précises]|
|
||||
Et les contenus sont triés par date décroissante
|
||||
|
||||
Scénario: Centres d'intérêt exportés
|
||||
Étant donné que mes jauges d'intérêt sont:
|
||||
| catégorie | valeur |
|
||||
| Automobile | 78% |
|
||||
| Voyage | 65% |
|
||||
| Musique | 52% |
|
||||
| Politique | 30% |
|
||||
Quand mon export est généré
|
||||
Alors la section "interest_gauges" contient ces valeurs
|
||||
Et chaque jauge indique la date de dernière modification
|
||||
|
||||
Scénario: Historique des consentements exporté
|
||||
Étant donné que j'ai modifié mes consentements plusieurs fois
|
||||
Quand mon export est généré
|
||||
Alors la section "consent_history" contient:
|
||||
| date | consent_type | accepted | version |
|
||||
| 2025-01-15T10:00 | Fonctionnel | oui | 1 |
|
||||
| 2025-01-15T10:00 | Analytique | oui | 1 |
|
||||
| 2025-01-15T10:00 | Marketing | non | 1 |
|
||||
| 2025-03-20T14:30 | Analytique | non | 1 |
|
||||
Et l'historique complet est visible
|
||||
|
||||
# Génération asynchrone
|
||||
|
||||
Scénario: Génération asynchrone pour éviter timeout
|
||||
Étant donné que j'ai beaucoup de données (500 contenus créés, 10 000 écoutes)
|
||||
Quand je demande un export
|
||||
Alors la génération se fait en arrière-plan via un worker
|
||||
Et la page web ne timeout pas
|
||||
Et je peux continuer à utiliser l'application pendant la génération
|
||||
Et je reçois un email quand l'export est prêt
|
||||
|
||||
Scénario: Délai de génération conforme RGPD
|
||||
Étant donné que je demande un export le 2025-01-20 à 10:00
|
||||
Quand le worker génère l'export
|
||||
Alors l'export est disponible maximum 48h plus tard (avant le 2025-01-22 à 10:00)
|
||||
Et la plupart des exports sont prêts en moins de 6h
|
||||
Et le délai respecte l'article 20 du RGPD
|
||||
|
||||
Scénario: Email de notification avec lien de téléchargement
|
||||
Étant donné que mon export est terminé
|
||||
Quand le worker finalise la génération
|
||||
Alors je reçois un email avec le sujet "Votre export de données RoadWave est prêt"
|
||||
Et l'email contient:
|
||||
"""
|
||||
Bonjour,
|
||||
|
||||
Votre export de données est prêt. Vous pouvez le télécharger via le lien ci-dessous:
|
||||
|
||||
[Télécharger mon export] (lien sécurisé, expire dans 7 jours)
|
||||
|
||||
Taille de l'archive: 45 MB
|
||||
Contenu: Profil, historique, contenus audio, abonnements, likes, centres d'intérêt
|
||||
|
||||
Pour toute question: dpo@roadwave.fr
|
||||
"""
|
||||
Et le lien de téléchargement est sécurisé (token unique)
|
||||
|
||||
Scénario: Lien de téléchargement expire après 7 jours
|
||||
Étant donné que mon export a été généré le 2025-01-20
|
||||
Et que je reçois le lien de téléchargement
|
||||
Quand j'essaie d'accéder au lien le 2025-01-28 (8 jours plus tard)
|
||||
Alors le lien est expiré
|
||||
Et je reçois un message "Ce lien a expiré. Veuillez demander un nouvel export."
|
||||
Et je peux demander un nouvel export si nécessaire
|
||||
|
||||
# Limite anti-abus
|
||||
|
||||
Scénario: Limite de 1 export par mois
|
||||
Étant donné que j'ai demandé un export le 2025-01-15
|
||||
Quand j'essaie de demander un nouvel export le 2025-01-20
|
||||
Alors je reçois un message d'erreur:
|
||||
"""
|
||||
Vous avez déjà demandé un export ce mois-ci. Vous pourrez demander un nouvel export à partir du 2025-02-15.
|
||||
"""
|
||||
Et le bouton "Confirmer l'export" est désactivé
|
||||
Et la date du prochain export possible est affichée
|
||||
|
||||
Scénario: Nouvel export possible après 1 mois
|
||||
Étant donné que j'ai demandé un export le 2025-01-15
|
||||
Quand la date atteint le 2025-02-15
|
||||
Alors je peux demander un nouvel export
|
||||
Et le bouton "Confirmer l'export" est actif
|
||||
Et aucune limite ne s'applique
|
||||
|
||||
# Sécurité
|
||||
|
||||
Scénario: Lien de téléchargement sécurisé avec token unique
|
||||
Étant donné que mon export est prêt
|
||||
Quand je reçois le lien de téléchargement
|
||||
Alors le lien contient un token unique et non devinable
|
||||
Et le format du lien est: `https://roadwave.fr/exports/download/[token_unique]`
|
||||
Et le token est valide uniquement pour mon compte
|
||||
Et le token expire après 7 jours ou après 3 téléchargements
|
||||
|
||||
Scénario: Vérification de l'authentification avant téléchargement
|
||||
Étant donné que je reçois le lien d'export
|
||||
Quand je clique sur le lien
|
||||
Alors le système vérifie que je suis connecté
|
||||
Et si je ne suis pas connecté, je suis redirigé vers la page de connexion
|
||||
Et après connexion, le téléchargement démarre automatiquement
|
||||
Et seul le propriétaire du compte peut télécharger l'export
|
||||
|
||||
# Conformité RGPD Article 20
|
||||
|
||||
Scénario: Conformité portabilité des données
|
||||
Étant donné que mon export est généré
|
||||
Quand un auditeur RGPD vérifie la conformité
|
||||
Alors l'export respecte les exigences de l'article 20:
|
||||
| exigence RGPD | respecté |
|
||||
| Format structuré (JSON) | oui |
|
||||
| Format couramment utilisé | oui |
|
||||
| Format lisible par machine | oui |
|
||||
| Format interopérable | oui |
|
||||
| Délai raisonnable (48h max) | oui |
|
||||
| Exhaustivité des données | oui |
|
||||
| Gratuité pour l'utilisateur | oui |
|
||||
|
||||
Scénario: Gratuité de l'export
|
||||
Étant donné que je demande un export de mes données
|
||||
Quand l'export est généré et téléchargé
|
||||
Alors aucun coût n'est facturé
|
||||
Et l'export est entièrement gratuit
|
||||
Et aucune inscription Premium n'est requise
|
||||
Et le droit à la portabilité est accessible à tous les utilisateurs
|
||||
|
||||
# Statut de l'export visible
|
||||
|
||||
Scénario: Suivi du statut de génération
|
||||
Étant donné que j'ai demandé un export
|
||||
Quand j'ouvre "Paramètres > Confidentialité > Mes exports"
|
||||
Alors je vois le statut actuel:
|
||||
| statut | description |
|
||||
| En cours de génération| Worker en train de générer l'archive |
|
||||
| Prêt au téléchargement| Lien de téléchargement disponible |
|
||||
| Expiré | Lien expiré (>7j), nouvel export requis |
|
||||
Et la date de demande est affichée
|
||||
Et la taille estimée de l'archive est visible
|
||||
254
features/api/rgpd-compliance/suppression-compte.feature
Normal file
254
features/api/rgpd-compliance/suppression-compte.feature
Normal file
@@ -0,0 +1,254 @@
|
||||
# language: fr
|
||||
|
||||
@rgpd @account-deletion
|
||||
Fonctionnalité: Suppression du compte utilisateur (Article 17 RGPD - Droit à l'effacement)
|
||||
|
||||
# 13.4 - Grace period 30j + anonymisation contenus
|
||||
|
||||
Contexte:
|
||||
Étant donné que je suis un utilisateur connecté
|
||||
Et que j'ai utilisé l'application depuis plusieurs mois
|
||||
|
||||
Scénario: Demande de suppression depuis les paramètres
|
||||
Étant donné que je suis dans "Paramètres > Compte"
|
||||
Quand je clique sur "Supprimer mon compte"
|
||||
Alors une page d'avertissement s'affiche avec le message:
|
||||
"""
|
||||
Attention: La suppression de votre compte est définitive.
|
||||
|
||||
Que se passe-t-il lors de la suppression?
|
||||
- Votre compte sera désactivé immédiatement (connexion impossible)
|
||||
- Vos données personnelles seront supprimées dans 30 jours
|
||||
- Vos contenus créés resteront disponibles de manière anonyme
|
||||
- Vous pouvez annuler la suppression dans les 30 jours
|
||||
|
||||
Voulez-vous vraiment continuer?
|
||||
"""
|
||||
Et deux boutons sont disponibles: "Annuler" et "Confirmer la suppression"
|
||||
|
||||
Scénario: Confirmation de suppression avec mot de passe
|
||||
Étant donné que je clique sur "Confirmer la suppression"
|
||||
Quand un formulaire de confirmation s'affiche
|
||||
Alors je dois entrer mon mot de passe pour confirmer
|
||||
Et je dois cocher "Je comprends que cette action est définitive"
|
||||
Et un captcha peut être requis pour éviter les suppressions automatisées
|
||||
Quand je valide le formulaire
|
||||
Alors la suppression est initiée
|
||||
|
||||
# Désactivation immédiate
|
||||
|
||||
Scénario: Compte désactivé immédiatement après confirmation
|
||||
Étant donné que j'ai confirmé la suppression de mon compte
|
||||
Quand la demande est traitée
|
||||
Alors mon compte est désactivé immédiatement
|
||||
Et je suis déconnecté de toutes mes sessions
|
||||
Et je ne peux plus me reconnecter
|
||||
Et si j'essaie de me connecter, je reçois le message:
|
||||
"""
|
||||
Votre compte est en cours de suppression. Si vous souhaitez annuler, cliquez sur le lien reçu par email.
|
||||
"""
|
||||
|
||||
Scénario: Contenus cachés pendant le grace period
|
||||
Étant donné que mon compte est en cours de suppression
|
||||
Quand un autre utilisateur recherche mes contenus
|
||||
Alors mes contenus ne sont plus diffusés dans l'application
|
||||
Et mes contenus n'apparaissent plus dans les recherches
|
||||
Et mes contenus ne sont plus recommandés
|
||||
Mais mes contenus ne sont pas encore supprimés définitivement
|
||||
|
||||
# Email de confirmation avec lien d'annulation
|
||||
|
||||
Scénario: Email de confirmation envoyé immédiatement
|
||||
Étant donné que j'ai confirmé la suppression de mon compte
|
||||
Quand la demande est traitée
|
||||
Alors je reçois un email avec le sujet "Confirmation de suppression de votre compte RoadWave"
|
||||
Et l'email contient:
|
||||
"""
|
||||
Bonjour,
|
||||
|
||||
Votre compte RoadWave est en cours de suppression. Vos données seront définitivement supprimées le [date + 30j].
|
||||
|
||||
Si vous changez d'avis, vous pouvez annuler la suppression en cliquant sur le lien ci-dessous (valide 30 jours):
|
||||
|
||||
[Annuler la suppression]
|
||||
|
||||
Que se passe-t-il ensuite?
|
||||
- Votre compte est désactivé immédiatement
|
||||
- Vos contenus sont masqués de l'application
|
||||
- Vos données seront supprimées dans 30 jours
|
||||
- Vous pouvez annuler à tout moment pendant ces 30 jours
|
||||
|
||||
Pour toute question: dpo@roadwave.fr
|
||||
"""
|
||||
Et le lien d'annulation est valide 30 jours
|
||||
|
||||
# Grace period de 30 jours
|
||||
|
||||
Scénario: Annulation de la suppression dans les 30 jours
|
||||
Étant donné que j'ai demandé la suppression de mon compte le 2025-01-20
|
||||
Et que je reçois l'email de confirmation
|
||||
Quand je clique sur le lien "Annuler la suppression" le 2025-02-05 (16 jours plus tard)
|
||||
Alors mon compte est réactivé immédiatement
|
||||
Et je peux me reconnecter normalement
|
||||
Et mes contenus redeviennent visibles dans l'application
|
||||
Et toutes mes données sont restaurées
|
||||
Et je reçois un email de confirmation: "Votre compte a été réactivé"
|
||||
|
||||
Scénario: Lien d'annulation expire après 30 jours
|
||||
Étant donné que j'ai demandé la suppression de mon compte le 2025-01-20
|
||||
Quand j'essaie de cliquer sur le lien d'annulation le 2025-02-25 (36 jours plus tard)
|
||||
Alors le lien est expiré
|
||||
Et je reçois un message "Ce lien a expiré. Votre compte a été définitivement supprimé."
|
||||
Et la suppression effective a déjà eu lieu
|
||||
|
||||
# Suppression effective après 30 jours
|
||||
|
||||
Scénario: Suppression effective sans annulation
|
||||
Étant donné que j'ai demandé la suppression de mon compte le 2025-01-20
|
||||
Et que je n'ai pas cliqué sur le lien d'annulation
|
||||
Quand la date atteint le 2025-02-19 (30 jours plus tard)
|
||||
Alors un job automatique exécute la suppression définitive
|
||||
Et toutes mes données personnelles sont supprimées
|
||||
|
||||
# Données supprimées
|
||||
|
||||
Scénario: Liste des données supprimées définitivement
|
||||
Étant donné que la suppression effective est exécutée
|
||||
Quand le job de suppression se termine
|
||||
Alors les données suivantes sont supprimées:
|
||||
| données | supprimé |
|
||||
| Compte utilisateur (email, mdp) | oui |
|
||||
| Profil (pseudo, bio, avatar) | oui |
|
||||
| Historique d'écoute | oui |
|
||||
| Historique GPS | oui |
|
||||
| Centres d'intérêt (jauges) | oui |
|
||||
| Sessions et tokens | oui |
|
||||
| Likes et abonnements | oui |
|
||||
| Notifications non lues | oui |
|
||||
| Historique consentements | oui |
|
||||
| Données de paiement | oui |
|
||||
Et ces suppressions sont irréversibles
|
||||
|
||||
# Contenus conservés anonymement
|
||||
|
||||
Scénario: Anonymisation des contenus créés
|
||||
Étant donné que j'ai créé 10 contenus audio
|
||||
Quand la suppression effective est exécutée
|
||||
Alors mes contenus audio restent disponibles dans l'application
|
||||
Et le nom du créateur devient "Utilisateur supprimé"
|
||||
Et mon pseudo n'est plus visible
|
||||
Et les métadonnées (titre, description, tags, géolocalisation) sont conservées
|
||||
Et les fichiers audio restent sur le CDN
|
||||
Et les statistiques d'écoute sont conservées
|
||||
|
||||
Scénario: Justification de l'anonymisation (intérêt légitime)
|
||||
Étant donné que mes contenus sont conservés anonymement
|
||||
Quand un auditeur RGPD vérifie la conformité
|
||||
Alors la conservation est justifiée par l'intérêt légitime de la communauté
|
||||
Et les contenus ne contiennent plus de données personnelles identifiables
|
||||
Et la suppression complète nuirait à l'expérience des autres utilisateurs
|
||||
Et cette pratique est conforme au RGPD si anonymisation réelle
|
||||
|
||||
Scénario: Contenu anonymisé visible pour les autres utilisateurs
|
||||
Étant donné que mon compte a été supprimé
|
||||
Et que mes contenus ont été anonymisés
|
||||
Quand un utilisateur consulte un de mes anciens contenus
|
||||
Alors le créateur affiché est "Utilisateur supprimé"
|
||||
Et le profil du créateur n'est plus accessible
|
||||
Et le contenu reste écoutable normalement
|
||||
Et les likes et statistiques sont conservés
|
||||
|
||||
# Likes et abonnements supprimés
|
||||
|
||||
Scénario: Suppression de mes likes avec conservation des compteurs
|
||||
Étant donné que j'avais liké 50 contenus
|
||||
Quand la suppression effective est exécutée
|
||||
Alors mes likes sont supprimés de la base de données
|
||||
Mais les compteurs de likes sur les contenus sont préservés
|
||||
Et les créateurs ne perdent pas leurs statistiques
|
||||
Et seule la relation "user X a liké content Y" est supprimée
|
||||
|
||||
Scénario: Suppression de mes abonnements
|
||||
Étant donné que je suivais 20 créateurs
|
||||
Quand la suppression effective est exécutée
|
||||
Alors mes abonnements sont supprimés
|
||||
Et les compteurs d'abonnés des créateurs sont décrémentés de 1
|
||||
Et les créateurs ne reçoivent pas de notification de désabonnement
|
||||
|
||||
# Sessions et tokens révoqués
|
||||
|
||||
Scénario: Révocation de tous les tokens immédiatement
|
||||
Étant donné que je suis connecté sur 3 appareils (mobile, tablette, web)
|
||||
Quand je demande la suppression de mon compte
|
||||
Alors tous mes tokens d'authentification sont révoqués immédiatement
|
||||
Et je suis déconnecté de tous mes appareils
|
||||
Et toute tentative de reconnexion échoue
|
||||
|
||||
# Notifications avant suppression
|
||||
|
||||
Scénario: Rappels par email pendant le grace period
|
||||
Étant donné que j'ai demandé la suppression de mon compte le 2025-01-20
|
||||
Quand le grace period s'écoule
|
||||
Alors je reçois des emails de rappel:
|
||||
| date | jours restants | sujet email |
|
||||
| 2025-02-04 | 15 jours | Plus que 15 jours pour annuler la suppression |
|
||||
| 2025-02-12 | 7 jours | Dernière semaine pour annuler la suppression |
|
||||
| 2025-02-17 | 2 jours | Attention: suppression définitive dans 2 jours |
|
||||
Et chaque email contient le lien d'annulation
|
||||
|
||||
# Conformité RGPD Article 17
|
||||
|
||||
Scénario: Conformité droit à l'effacement
|
||||
Étant donné que la suppression de mon compte est complète
|
||||
Quand un auditeur RGPD vérifie la conformité
|
||||
Alors le processus respecte l'article 17 du RGPD:
|
||||
| exigence RGPD | respecté |
|
||||
| Suppression de toutes les données personnelles | oui |
|
||||
| Délai raisonnable (30j grace period acceptable)| oui |
|
||||
| Possibilité d'annulation (bonne pratique) | oui |
|
||||
| Anonymisation des contenus (intérêt légitime) | oui |
|
||||
| Révocation des tokens et sessions | oui |
|
||||
| Suppression irréversible | oui |
|
||||
|
||||
# Cas particuliers
|
||||
|
||||
Scénario: Suppression d'un compte Premium
|
||||
Étant donné que j'ai un abonnement Premium actif
|
||||
Quand je demande la suppression de mon compte
|
||||
Alors mon abonnement est annulé immédiatement
|
||||
Et aucun remboursement n'est effectué (conformément aux CGV)
|
||||
Et je reçois un email de confirmation d'annulation de l'abonnement
|
||||
Et le reste du processus de suppression se déroule normalement
|
||||
|
||||
Scénario: Suppression d'un compte créateur avec revenus en attente
|
||||
Étant donné que je suis un créateur avec 75€ de revenus en attente de paiement
|
||||
Quand je demande la suppression de mon compte
|
||||
Alors un message m'informe:
|
||||
"""
|
||||
Vous avez 75€ de revenus en attente. Souhaitez-vous recevoir ce paiement avant suppression?
|
||||
"""
|
||||
Et je peux choisir "Recevoir le paiement et attendre" ou "Renoncer au paiement"
|
||||
Et si je choisis "Recevoir le paiement", la suppression est repoussée de 7 jours
|
||||
|
||||
Scénario: Suppression avec signalements de modération en cours
|
||||
Étant donné que j'ai 2 signalements en cours de traitement
|
||||
Quand je demande la suppression de mon compte
|
||||
Alors les signalements sont automatiquement clôturés
|
||||
Et les contenus signalés sont masqués immédiatement
|
||||
Et aucune sanction n'est appliquée (compte déjà en suppression)
|
||||
|
||||
# Traçabilité pour audit
|
||||
|
||||
Scénario: Log de la suppression pour traçabilité
|
||||
Étant donné que la suppression effective est exécutée
|
||||
Quand le job de suppression se termine
|
||||
Alors un log est créé avec:
|
||||
| champ | valeur |
|
||||
| user_id | [ID anonymisé] |
|
||||
| deletion_requested_at | 2025-01-20T10:00:00Z |
|
||||
| deletion_executed_at | 2025-02-19T02:00:00Z |
|
||||
| deletion_cancelled | false |
|
||||
| data_deleted | [liste des tables] |
|
||||
| contents_anonymized | 10 |
|
||||
Et ce log est conservé 5 ans pour audit RGPD
|
||||
Et l'user_id est pseudonymisé pour anonymat
|
||||
Reference in New Issue
Block a user