refactor(docs): réorganiser la documentation selon principes DDD
Réorganise la documentation du projet selon les principes du Domain-Driven Design (DDD) pour améliorer la cohésion, la maintenabilité et l'alignement avec l'architecture modulaire du backend. **Structure cible:** ``` docs/domains/ ├── README.md (Context Map) ├── _shared/ (Core Domain) ├── recommendation/ (Supporting Subdomain) ├── content/ (Supporting Subdomain) ├── moderation/ (Supporting Subdomain) ├── advertising/ (Generic Subdomain) ├── premium/ (Generic Subdomain) └── monetization/ (Generic Subdomain) ``` **Changements effectués:** Phase 1: Création de l'arborescence des 7 bounded contexts Phase 2: Déplacement des règles métier (01-19) vers domains/*/rules/ Phase 3: Déplacement des diagrammes d'entités vers domains/*/entities/ Phase 4: Déplacement des diagrammes flux/états/séquences vers domains/*/ Phase 5: Création des README.md pour chaque domaine Phase 6: Déplacement des features Gherkin vers domains/*/features/ Phase 7: Création du Context Map (domains/README.md) Phase 8: Mise à jour de mkdocs.yml pour la nouvelle navigation Phase 9: Correction automatique des liens internes (script fix-markdown-links.sh) Phase 10: Nettoyage de l'ancienne structure (regles-metier/, diagrammes/, features/) **Configuration des tests:** - Makefile: godog run docs/domains/*/features/ - scripts/generate-bdd-docs.py: features_dir → docs/domains **Avantages:** ✅ Cohésion forte: toute la doc d'un domaine au même endroit ✅ Couplage faible: domaines indépendants, dépendances explicites ✅ Navigabilité améliorée: README par domaine = entrée claire ✅ Alignement code/docs: miroir de backend/internal/ ✅ Onboarding facilité: exploration domaine par domaine ✅ Tests BDD intégrés: features au plus près des règles métier Voir docs/REFACTOR-DDD.md pour le plan complet.
This commit is contained in:
1003
docs/domains/_shared/rules/ANNEXE-POST-MVP.md
Normal file
1003
docs/domains/_shared/rules/ANNEXE-POST-MVP.md
Normal file
File diff suppressed because it is too large
Load Diff
240
docs/domains/_shared/rules/authentification.md
Normal file
240
docs/domains/_shared/rules/authentification.md
Normal file
@@ -0,0 +1,240 @@
|
||||
## 1. Authentification & Inscription
|
||||
|
||||
### 1.1 Méthodes d'inscription
|
||||
|
||||
**Décision** : Email/Password uniquement (pas d'OAuth tiers)
|
||||
|
||||
- ❌ **Pas de Google, Apple, Facebook OAuth** (dépendance services US/Chine)
|
||||
- ✅ **Email + mot de passe** (formulaire natif Zitadel)
|
||||
- ✅ 2FA (Two-Factor Authentication) disponible
|
||||
- ✅ Option "Appareil de confiance" (skip 2FA pour 30 jours)
|
||||
|
||||
**Clarification technique** :
|
||||
- Zitadel utilise OAuth2/OIDC comme **protocole** (standard moderne pour mobile)
|
||||
- Mais l'authentification reste 100% **email/password natif**
|
||||
- **Aucun fournisseur externe** (Google, Apple, etc.) n'est intégré
|
||||
|
||||
**Justification** :
|
||||
- Souveraineté : pas de dépendance externe
|
||||
- RGPD : données 100% contrôlées
|
||||
- Coût : 0€ (Zitadel intégré)
|
||||
|
||||
> 📋 **Référence technique** : Voir [ADR-008 - OAuth2 vs Fournisseurs Tiers](../adr/008-authentification.md#oauth2-pkce--protocole-vs-fournisseurs-tiers) pour clarification protocole vs providers.
|
||||
|
||||
---
|
||||
|
||||
### 1.2 Vérification email
|
||||
|
||||
**Décision** : Différenciée selon le rôle utilisateur
|
||||
|
||||
#### Pour les auditeurs (écoute uniquement)
|
||||
|
||||
| État | Capacités |
|
||||
|------|-----------|
|
||||
| **Email non vérifié** | Lecture illimitée + création max 5 contenus |
|
||||
| **Email vérifié** | Toutes fonctionnalités débloquées |
|
||||
|
||||
**Paramètres** :
|
||||
- Lien de vérification expire après **7 jours**
|
||||
- Possibilité de renvoyer le lien (max 3 fois/jour)
|
||||
- Rappel in-app après création du 3ème contenu
|
||||
|
||||
**Justification** :
|
||||
- Friction minimale à l'inscription
|
||||
- Anti-spam sans bloquer l'essai du produit
|
||||
- Incitation naturelle à vérifier (déblocage)
|
||||
|
||||
#### Pour les créateurs (monétisation)
|
||||
|
||||
**Vérification obligatoire sous 7 jours** pour :
|
||||
- Accès au programme de monétisation
|
||||
- KYC et reversement des revenus (conformité Mangopay)
|
||||
- Publication illimitée de contenus
|
||||
|
||||
**Justification** :
|
||||
- **Conformité légale** : KYC obligatoire pour transferts financiers
|
||||
- **Anti-fraude** : Vérification identité réelle pour paiements
|
||||
- **Responsabilité** : RoadWave doit pouvoir prouver identité créateurs monétisés
|
||||
|
||||
---
|
||||
|
||||
### 1.3 Données requises à l'inscription
|
||||
|
||||
**Obligatoires** :
|
||||
- ✅ Email (format validé)
|
||||
- ✅ Mot de passe (voir règles ci-dessous)
|
||||
- ✅ Pseudo (3-30 caractères, alphanumérique + underscore)
|
||||
- ✅ Date de naissance (vérification âge minimum)
|
||||
|
||||
**Optionnelles** :
|
||||
- ❌ Nom complet (privacy by design)
|
||||
- ❌ Photo de profil (avatar par défaut généré)
|
||||
- ❌ Bio (ajout ultérieur)
|
||||
|
||||
**Âge minimum** :
|
||||
- **13 ans minimum** (conformité réglementation réseaux sociaux EU)
|
||||
- Vérification à l'inscription via date de naissance
|
||||
- Blocage inscription si <13 ans avec message explicite
|
||||
|
||||
**Justification** :
|
||||
- RGPD minimal data
|
||||
- Friction réduite (4 champs max)
|
||||
- Protection mineurs (obligation légale)
|
||||
|
||||
---
|
||||
|
||||
### 1.4 Tranches d'âge des contenus
|
||||
|
||||
**Décision** : Classification obligatoire des contenus
|
||||
|
||||
**Catégories** :
|
||||
- 🟢 **Tout public** (défaut)
|
||||
- 🟡 **13+** : contenu mature léger (débats, actualité sensible)
|
||||
- 🟠 **16+** : contenu mature (violence verbale, sujets sensibles)
|
||||
- 🔴 **18+** : contenu adulte (langage explicite, sujets réservés)
|
||||
|
||||
**Règles de diffusion** :
|
||||
- Utilisateur 13-15 ans → contenus 🟢 🟡 (Tout public + 13+)
|
||||
- Utilisateur 16-17 ans → contenus 🟢 🟡 🟠 (Tout public + 13+ + 16+)
|
||||
- Utilisateur 18+ → tous contenus 🟢 🟡 🟠 🔴
|
||||
|
||||
**Modération** :
|
||||
- Vérification obligatoire de la classification lors de la validation
|
||||
- Reclassification possible par modérateurs
|
||||
- Strike si classification volontairement incorrecte
|
||||
|
||||
**Justification** :
|
||||
- Protection mineurs (obligation légale)
|
||||
- Responsabilité plateforme
|
||||
- Coût : champ supplémentaire + règle algo
|
||||
|
||||
---
|
||||
|
||||
### 1.5 Validation mot de passe
|
||||
|
||||
**Règles** :
|
||||
- ✅ Minimum **8 caractères**
|
||||
- ✅ Au moins **1 majuscule**
|
||||
- ✅ Au moins **1 chiffre**
|
||||
- ❌ Pas de symbole obligatoire (simplicité)
|
||||
|
||||
**Validation** :
|
||||
- Côté client (feedback temps réel)
|
||||
- Côté backend (sécurité)
|
||||
- Message d'erreur explicite par règle non respectée
|
||||
|
||||
**Justification** :
|
||||
- Standard industrie
|
||||
- Bloque 95% des mots de passe faibles
|
||||
- UX acceptable (pas trop restrictif)
|
||||
|
||||
---
|
||||
|
||||
### 1.6 Two-Factor Authentication (2FA)
|
||||
|
||||
**Décision** : Optionnel mais recommandé
|
||||
|
||||
**Méthodes disponibles** :
|
||||
- ✅ TOTP (Time-based One-Time Password) via app (Google Authenticator, Authy)
|
||||
- ✅ Email (code 6 chiffres, expire 10 min)
|
||||
- ❌ SMS (coût élevé ~0.05€/SMS)
|
||||
|
||||
**Appareil de confiance** :
|
||||
- Option "Ne plus demander sur cet appareil" → bypass 2FA pendant **30 jours**
|
||||
- Révocable depuis paramètres compte
|
||||
- Liste des appareils de confiance visible
|
||||
|
||||
**Justification** :
|
||||
- Sécurité renforcée sans coût SMS
|
||||
- UX : appareil de confiance évite friction quotidienne
|
||||
- Zitadel natif (0€)
|
||||
|
||||
---
|
||||
|
||||
### 1.7 Tentatives de connexion
|
||||
|
||||
**Règles** :
|
||||
- Maximum **5 tentatives** par période de **15 minutes**
|
||||
- Blocage temporaire après 5 échecs
|
||||
- Compteur reset automatique après 15 min
|
||||
- Notification email si blocage (tentative suspecte)
|
||||
|
||||
**Déblocage** :
|
||||
- Automatique après 15 min
|
||||
- Ou via lien "Mot de passe oublié"
|
||||
|
||||
**Justification** :
|
||||
- Anti brute-force
|
||||
- Standard industrie (équilibre sécurité/UX)
|
||||
- Zitadel natif (0€)
|
||||
|
||||
---
|
||||
|
||||
### 1.8 Sessions et refresh tokens
|
||||
|
||||
**Durée de vie** :
|
||||
- **Access token** : 15 minutes
|
||||
- **Refresh token** : 30 jours
|
||||
|
||||
**Rotation** :
|
||||
- Refresh token rotatif (nouveau token à chaque refresh)
|
||||
- Ancien token invalidé immédiatement
|
||||
- Détection token replay attack
|
||||
|
||||
**Extension automatique** :
|
||||
- Si app utilisée, session prolongée automatiquement
|
||||
- Inactivité 30 jours → déconnexion
|
||||
|
||||
**Justification** :
|
||||
- Sécurité (token court-vie)
|
||||
- UX (pas de reconnexion fréquente)
|
||||
- Standard OAuth2/OIDC
|
||||
|
||||
---
|
||||
|
||||
### 1.9 Multi-device
|
||||
|
||||
**Décision** : Sessions simultanées illimitées
|
||||
|
||||
**Gestion** :
|
||||
- Liste des devices connectés visible (OS, navigateur, dernière connexion, IP/ville)
|
||||
- Révocation individuelle possible
|
||||
- Révocation globale "Déconnecter tous les appareils"
|
||||
|
||||
**Alertes** :
|
||||
- Notification push + email si connexion depuis nouveau device
|
||||
- Détection localisation suspecte (IP pays différent)
|
||||
|
||||
**Justification** :
|
||||
- UX maximale (écoute voiture + tablette maison + web)
|
||||
- Sécurité via transparence (utilisateur voit tout)
|
||||
- Coût : table sessions PostgreSQL
|
||||
|
||||
---
|
||||
|
||||
### 1.10 Récupération de compte
|
||||
|
||||
**Méthode** : Email uniquement
|
||||
|
||||
**Processus** :
|
||||
1. Utilisateur clique "Mot de passe oublié"
|
||||
2. Email avec lien de reset envoyé
|
||||
3. Lien expire après **1 heure**
|
||||
4. Page de reset : nouveau mot de passe (validation règles)
|
||||
5. Confirmation + déconnexion tous devices (sauf celui en cours)
|
||||
|
||||
**Notifications** :
|
||||
- Email immédiat si changement mot de passe
|
||||
- Push si changement depuis appareil non reconnu
|
||||
|
||||
**Limite** :
|
||||
- Maximum **3 demandes/heure** (anti-spam)
|
||||
|
||||
**Justification** :
|
||||
- Standard sécurité
|
||||
- Pas de coût SMS
|
||||
- Protection contre attaque sociale
|
||||
|
||||
---
|
||||
|
||||
## Récapitulatif Section 1
|
||||
135
docs/domains/_shared/rules/gestion-erreurs.md
Normal file
135
docs/domains/_shared/rules/gestion-erreurs.md
Normal file
@@ -0,0 +1,135 @@
|
||||
## 12. Gestion des erreurs
|
||||
|
||||
### 12.1 Aucun contenu disponible
|
||||
|
||||
**Stratégie** : Élargissement automatique progressif
|
||||
|
||||
**Flow** :
|
||||
|
||||
```
|
||||
1. Recherche rayon 50 km → aucun résultat
|
||||
2. Élargissement auto 100 km
|
||||
3. Si toujours rien → département
|
||||
4. Si toujours rien → région
|
||||
5. Dernier recours → contenu national (toujours disponible)
|
||||
```
|
||||
|
||||
**Messages adaptatifs** :
|
||||
|
||||
| Cas | Message |
|
||||
|-----|---------|
|
||||
| **Trouvé à 100 km** | "Aucun contenu dans votre zone immédiate. Voici du contenu à proximité (100 km)" |
|
||||
| **Trouvé département** | "Aucun contenu local disponible. Voici du contenu dans votre département" |
|
||||
| **Contenu national** | "Aucun contenu local disponible. Voici du contenu national qui pourrait vous intéresser" |
|
||||
|
||||
**Justification** :
|
||||
- **UX fluide** : pas de message d'erreur bloquant "Aucun contenu"
|
||||
- **User ne reste jamais sans contenu**
|
||||
- **Contenu national = filet de sécurité** : actualités Le Monde, podcasts génériques
|
||||
|
||||
---
|
||||
|
||||
### 12.2 Contenu signalé/supprimé pendant l'écoute
|
||||
|
||||
**Décision** : Pas d'interruption brutale
|
||||
|
||||
**Flow** :
|
||||
|
||||
```
|
||||
1. Contenu supprimé côté backend (modération)
|
||||
2. Si contenu en écoute → laisser terminer lecture en cours
|
||||
3. Après fin lecture → désactiver bouton "Précédent" pour ce contenu
|
||||
4. Passage automatique suivant après 2s
|
||||
5. Toast notification discrète : "Contenu précédent retiré (violation règles)"
|
||||
```
|
||||
|
||||
**Si tentative "Précédent" manuellement** :
|
||||
- Message : "Ce contenu n'est plus disponible"
|
||||
- Retour au contenu actuel
|
||||
|
||||
**Justification** :
|
||||
- **Sécurité routière** : pas d'interruption brutale pendant conduite
|
||||
- **User informé mais pas alarmé** : message discret
|
||||
- **Empêche réécoute** : contenu modéré inaccessible
|
||||
|
||||
---
|
||||
|
||||
### 12.3 Perte de réseau
|
||||
|
||||
**Buffer adaptatif** (cf. TECHNICAL.md) :
|
||||
|
||||
| Réseau | Buffer min | Buffer cible | Buffer max |
|
||||
|--------|------------|--------------|------------|
|
||||
| **WiFi** | 5s | 30s | 120s |
|
||||
| **4G/5G** | 10s | 45s | 120s |
|
||||
| **3G** | 30s | 90s | 300s |
|
||||
|
||||
**Comportement détaillé** :
|
||||
|
||||
**Phase 1 : Connexion instable** (latence élevée, paquets perdus)
|
||||
- Aucun message immédiat
|
||||
- Lecture continue sur buffer
|
||||
- Si > 10s latence : toast discret "Connexion instable"
|
||||
|
||||
**Phase 2 : Perte totale réseau**
|
||||
- Lecture continue jusqu'à épuisement buffer
|
||||
- Toast : "Hors ligne, lecture sur buffer (30s restantes)"
|
||||
- Compte à rebours visible
|
||||
|
||||
**Phase 3 : Buffer épuisé sans reconnexion**
|
||||
- Pause automatique
|
||||
- Overlay : "Connexion perdue. Reconnexion en cours..."
|
||||
- Retry automatique toutes les 5s (max 6 tentatives = 30s)
|
||||
|
||||
**Phase 4 : Basculement mode offline** (après 30s échec)
|
||||
- Popup : "Voulez-vous continuer avec vos contenus téléchargés ?"
|
||||
- Boutons : "Réessayer" / "Mode offline"
|
||||
- Si "Mode offline" → lecture contenus téléchargés
|
||||
|
||||
**Reconnexion réussie** :
|
||||
- Reprise automatique lecture au point d'arrêt exact
|
||||
- Toast : "Connexion rétablie"
|
||||
|
||||
**Justification** :
|
||||
- **Expérience fluide zones blanches** (tunnels, campagne)
|
||||
- **Buffer généreux** : absorbe fluctuations réseau mobile
|
||||
- **Mode offline secours** : si coupure prolongée
|
||||
|
||||
---
|
||||
|
||||
### 12.4 Géolocalisation désactivée
|
||||
|
||||
**Mode dégradé automatique**
|
||||
|
||||
**Contenu disponible** :
|
||||
|
||||
| Type contenu | Disponible |
|
||||
|--------------|-----------|
|
||||
| **Contenu national** (podcasts, actualités) | ✅ |
|
||||
| **Contenu téléchargé** (offline) | ✅ |
|
||||
| **Contenus "Neutre"** géographiquement | ✅ |
|
||||
| **Contenu géolocalisé** (Ancré/Contextuel) | ❌ |
|
||||
| **Audio-guides** | ❌ |
|
||||
| **Notifications push géo-déclenchées** | ❌ |
|
||||
|
||||
**Popup au lancement** :
|
||||
- **Apparition** : Premier lancement après refus géolocalisation
|
||||
- **Message** : "RoadWave fonctionne mieux avec la géolocalisation activée. Sans elle, seul le contenu national sera disponible."
|
||||
- **Boutons** :
|
||||
- "Activer" → Redirection paramètres OS
|
||||
- "Continuer sans" → Mode dégradé
|
||||
- **Checkbox** : "Ne plus me demander"
|
||||
|
||||
**Banner permanent si refus** :
|
||||
- Bandeau haut écran : "Mode limité : géolocalisation désactivée. [Activer]"
|
||||
- Pas intrusif mais rappel constant
|
||||
- Disparaît si géolocalisation réactivée
|
||||
|
||||
**Justification** :
|
||||
- **App reste fonctionnelle** sans GPS (pas de blocage)
|
||||
- **Incitation forte** à activer (meilleure UX)
|
||||
- **Respecte choix user** (RGPD : consentement libre)
|
||||
|
||||
---
|
||||
|
||||
## Récapitulatif Section 12
|
||||
336
docs/domains/_shared/rules/rgpd.md
Normal file
336
docs/domains/_shared/rules/rgpd.md
Normal file
@@ -0,0 +1,336 @@
|
||||
## 13. Conformité RGPD
|
||||
|
||||
### 13.1 Gestion du consentement
|
||||
|
||||
**Décision** : Tarteaucitron.js + PostgreSQL backend
|
||||
|
||||
**Implémentation web** :
|
||||
- ✅ Tarteaucitron.js (opensource, self-hosted)
|
||||
- ✅ Banner RGPD français, customisable
|
||||
- ✅ Granularité : fonctionnel / analytique / marketing
|
||||
|
||||
**Implémentation backend** :
|
||||
- Table `user_consents` avec versioning
|
||||
- Champs : user_id, consent_type, version, accepted, timestamp
|
||||
- Historique complet conservé (preuve légale)
|
||||
|
||||
**Consentements requis** :
|
||||
- **Géolocalisation précise** : obligatoire (banner + permission OS)
|
||||
- **Analytics** : optionnel (Matomo)
|
||||
- **Notifications push** : optionnel (permission OS)
|
||||
|
||||
**Justification** :
|
||||
- Opensource, 0€, conformité RGPD garantie
|
||||
- Historique backend = preuve légale en cas de contrôle
|
||||
- Granularité conforme recommandations CNIL
|
||||
|
||||
---
|
||||
|
||||
### 13.2 Anonymisation des données GPS
|
||||
|
||||
**Décision** : Geohash après 24h
|
||||
|
||||
**Processus** :
|
||||
1. Données précises conservées **24h** (recommandation personnalisée)
|
||||
2. Après 24h : conversion en geohash précision 5 (~5km²)
|
||||
3. Coordonnées originales supprimées définitivement
|
||||
|
||||
**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** :
|
||||
- ✅ Historique personnel visible (liste trajets) : conservation intégrale tant que compte actif
|
||||
- ❌ Analytics globales : uniquement geohash anonyme
|
||||
|
||||
**Justification** :
|
||||
- Vraie anonymisation RGPD (CNIL compliant)
|
||||
- Permet analytics agrégées (heatmaps trafic)
|
||||
- PostGIS natif, 0€
|
||||
|
||||
---
|
||||
|
||||
### 13.3 Export des données (portabilité)
|
||||
|
||||
**Décision** : JSON + HTML + ZIP, génération asynchrone
|
||||
|
||||
**Contenu de l'export** :
|
||||
```
|
||||
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** :
|
||||
- Profil utilisateur (email, pseudo, date inscription, bio)
|
||||
- Historique d'écoute (titres, dates, durées)
|
||||
- Contenus créés (audio + métadonnées)
|
||||
- Abonnements et likes
|
||||
- Centres d'intérêt (jauges)
|
||||
- Historique consentements
|
||||
|
||||
**Processus** :
|
||||
1. Demande via paramètres compte
|
||||
2. Génération asynchrone (worker background)
|
||||
3. Email avec lien download (expire **7 jours**)
|
||||
4. Délai : **48h maximum** (conformité RGPD)
|
||||
|
||||
**Limite** :
|
||||
- Maximum **1 export/mois** (anti-abus)
|
||||
|
||||
**Justification** :
|
||||
- Conformité article 20 RGPD (portabilité)
|
||||
- Double format (human + machine)
|
||||
- Worker asynchrone évite timeout
|
||||
|
||||
---
|
||||
|
||||
### 13.4 Suppression du compte
|
||||
|
||||
**Décision** : Grace period 30j + anonymisation contenus
|
||||
|
||||
**Processus** :
|
||||
1. Utilisateur clique "Supprimer mon compte"
|
||||
2. Compte désactivé immédiatement (login impossible)
|
||||
3. Contenus cachés pendant 30 jours (non diffusés)
|
||||
4. Email confirmation + lien annulation (valide 30j)
|
||||
5. Après 30j sans annulation : suppression effective
|
||||
|
||||
**Suppression effective** :
|
||||
- ✅ Compte utilisateur supprimé (données personnelles)
|
||||
- ✅ Historique d'écoute supprimé
|
||||
- ✅ GPS historique supprimé
|
||||
- ✅ Sessions et tokens révoqués
|
||||
- ⚠️ Contenus créés **anonymisés** (créateur = "Utilisateur supprimé")
|
||||
- ⚠️ Likes et abonnements supprimés (mais compteurs préservés)
|
||||
|
||||
**Contenus conservés anonymement** :
|
||||
- Audio files (CDN)
|
||||
- Métadonnées (titre, description, tags, géolocalisation)
|
||||
- Statistiques d'écoute
|
||||
|
||||
**Justification** :
|
||||
- Grace period évite suppressions impulsives
|
||||
- Anonymisation contenus = intérêt légitime communauté
|
||||
- Conforme RGPD si créateur = donnée supprimée
|
||||
|
||||
---
|
||||
|
||||
### 13.5 Mode dégradé (sans GPS précis)
|
||||
|
||||
**Décision** : GeoIP par défaut, GPS optionnel
|
||||
|
||||
**Niveaux de précision** :
|
||||
|
||||
| Niveau | Technologie | Contenus accessibles | 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 |
|
||||
|
||||
**Implémentation** :
|
||||
- Démarrage app : GeoIP automatique (IP → ville)
|
||||
- Banner in-app : "Activez la géolocalisation pour découvrir du contenu près de chez vous"
|
||||
- Upgrade volontaire vers GPS
|
||||
|
||||
**API GeoIP** :
|
||||
- IP2Location Lite (gratuit, self-hosted, voir [ADR-019](../adr/019-geolocalisation-ip.md))
|
||||
- Update DB mensuelle automatique
|
||||
- Précision ~80% au niveau ville
|
||||
|
||||
**Justification** :
|
||||
- RGPD : pas de consentement requis pour GeoIP (pas de donnée personnelle)
|
||||
- UX dégradée acceptable (contenus disponibles)
|
||||
- Progressive disclosure (upgrade optionnel)
|
||||
|
||||
---
|
||||
|
||||
### 13.6 Durée de conservation des données
|
||||
|
||||
**Décision** : 5 ans inactivité → purge automatique
|
||||
|
||||
**Règles** :
|
||||
|
||||
| Type de compte | Seuil inactivité | Action |
|
||||
|----------------|------------------|--------|
|
||||
| **Auditeur uniquement** | 5 ans sans connexion | Suppression automatique |
|
||||
| **Créateur avec contenus actifs** | Jamais (tant qu'écoutes) | Conservation indéfinie |
|
||||
| **Créateur inactif** | 5 ans sans connexion + 2 ans sans écoute | Suppression automatique |
|
||||
|
||||
**Notifications avant suppression** :
|
||||
- Email + push : **90 jours** avant
|
||||
- Email + push : **30 jours** avant
|
||||
- Email + push : **7 jours** avant
|
||||
- Toute connexion = reset compteur inactivité
|
||||
|
||||
**Contenu conservé** :
|
||||
- Contenus créés par comptes supprimés (anonymisés) : conservation indéfinie
|
||||
|
||||
**Justification** :
|
||||
- Conformité principe minimisation RGPD
|
||||
- 5 ans = équilibre raisonnable (standard industrie)
|
||||
- Exception créateurs actifs = intérêt légitime plateforme
|
||||
|
||||
---
|
||||
|
||||
### 13.7 Cookies et trackers web
|
||||
|
||||
**Décision** : Matomo self-hosted, zéro cookie tiers
|
||||
|
||||
**Cookies utilisés** :
|
||||
|
||||
| Cookie | Type | Durée | Finalité | Consentement |
|
||||
|--------|------|-------|----------|--------------|
|
||||
| `session` | Technique | 30j | Authentification | ❌ Non requis |
|
||||
| `refresh_token` | Technique | 30j | Session persistante | ❌ Non requis |
|
||||
| `_pk_id` | Analytique | 13 mois | Matomo (IP anonyme) | ✅ Requis |
|
||||
|
||||
**Analytics : Matomo self-hosted** :
|
||||
- Hébergé sur nos serveurs (Docker)
|
||||
- IP anonymisées automatiquement (2 derniers octets)
|
||||
- Pas de cookie si consentement refusé
|
||||
- Alternative : Plausible (SaaS EU, 9€/mois)
|
||||
|
||||
**Trackers interdits** :
|
||||
- ❌ Google Analytics
|
||||
- ❌ Facebook Pixel
|
||||
- ❌ Hotjar, Mixpanel, etc.
|
||||
|
||||
**Justification** :
|
||||
- Souveraineté données (pas de transfert US)
|
||||
- Conformité RGPD max (CNIL compatible)
|
||||
- Matomo = opensource, 0€ infra
|
||||
|
||||
---
|
||||
|
||||
### 13.8 Registre des traitements
|
||||
|
||||
**Décision** : Document Markdown versionné Git (MVP)
|
||||
|
||||
**Emplacement** :
|
||||
- `docs/rgpd/registre-traitements.md`
|
||||
- Versionné Git (historique modifications)
|
||||
|
||||
**Contenu obligatoire par traitement** :
|
||||
- Nom et finalité du traitement
|
||||
- Catégories de données collectées
|
||||
- Base légale (consentement / contrat / intérêt légitime)
|
||||
- Durée de conservation
|
||||
- Destinataires (sous-traitants, CDN, etc.)
|
||||
- Transferts hors UE (aucun prévu)
|
||||
|
||||
**Responsable** :
|
||||
- DPO / Fondateur
|
||||
- Review trimestrielle obligatoire
|
||||
- Update immédiate si nouveau traitement
|
||||
|
||||
**Migration future** :
|
||||
- Si > 100K utilisateurs : interface admin PostgreSQL
|
||||
|
||||
**Justification** :
|
||||
- Obligation RGPD Article 30
|
||||
- Markdown = simple, versionné, auditable
|
||||
- 0€
|
||||
|
||||
---
|
||||
|
||||
### 13.9 Notification violations de données (breach)
|
||||
|
||||
**Décision** : Monitoring + alertes + runbook
|
||||
|
||||
**Détection automatique** :
|
||||
|
||||
| Événement | Outil | Alerte |
|
||||
|-----------|-------|--------|
|
||||
| Erreurs backend critiques | 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 |
|
||||
|
||||
**Procédure breach** :
|
||||
- Runbook : `docs/rgpd/procedure-breach.md`
|
||||
- Checklist 72h CNIL :
|
||||
1. H+0 : Détection et confinement
|
||||
2. H+24 : Évaluation gravité (données concernées, utilisateurs impactés)
|
||||
3. H+48 : Notification CNIL si risque pour utilisateurs
|
||||
4. H+72 : Notification utilisateurs si risque élevé
|
||||
|
||||
**Contact CNIL** :
|
||||
- Email pré-rédigé (template)
|
||||
- Formulaire en ligne (account CNIL créé)
|
||||
|
||||
**Justification** :
|
||||
- Obligation RGPD Article 33 (notification 72h)
|
||||
- Monitoring proactif évite découverte tardive
|
||||
- Sentry gratuit < 5K events/mois
|
||||
|
||||
---
|
||||
|
||||
### 13.10 DPO (Délégué à la Protection des Données)
|
||||
|
||||
**Décision** : Fondateur = DPO temporaire (MVP)
|
||||
|
||||
**Raison légale** :
|
||||
- Non obligatoire si :
|
||||
- < 250 employés
|
||||
- Pas de traitement à grande échelle de données sensibles
|
||||
- RoadWave : données localisation = sensible MAIS échelle MVP
|
||||
|
||||
**Formation** :
|
||||
- CNIL : formation gratuite en ligne (4h)
|
||||
- Certification CNIL "Atelier RGPD" (gratuit)
|
||||
|
||||
**Contact** :
|
||||
- Email : dpo@roadwave.fr
|
||||
- Publié dans CGU et mentions légales
|
||||
- Délai réponse : **1 mois** (RGPD)
|
||||
|
||||
**Migration future** :
|
||||
- Si > 100K utilisateurs : DPO externe mutualisé (~200€/mois)
|
||||
- Ou recrutement DPO interne si > 10 employés
|
||||
|
||||
**Justification** :
|
||||
- Conforme RGPD (non obligatoire en phase MVP)
|
||||
- 0€, contrôle total
|
||||
- Bonne pratique : avoir un contact identifié
|
||||
|
||||
---
|
||||
|
||||
## Récapitulatif Section 13
|
||||
|
||||
| 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€ |
|
||||
| **DPO** | Fondateur formé CNIL | 0€ |
|
||||
|
||||
**Coût total RGPD : ~5€/mois**
|
||||
|
||||
---
|
||||
|
||||
## Points d'attention pour Gherkin
|
||||
|
||||
- Tester consentement géolocalisation (accept/refuse → contenus différents)
|
||||
- Tester anonymisation GPS après 24h (job cron)
|
||||
- Tester export données (génération complète + vérification contenu)
|
||||
- Tester grace period suppression (annulation possible)
|
||||
- Tester mode GeoIP (ville détectée correctement)
|
||||
- Tester purge automatique (5 ans inactivité)
|
||||
- Tester notifications avant purge (90j/30j/7j)
|
||||
Reference in New Issue
Block a user