diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 876fa5d..41a11f5 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -74,6 +74,7 @@ Fonctionnalité: Recherche avancée de contenus ``` **Conventions Gherkin** : + - Langue française (`# language: fr`) - Mots-clés : `Fonctionnalité`, `Scénario`, `Étant donné`, `Quand`, `Alors` - Commentaires pour référencer les règles DDD @@ -94,6 +95,7 @@ Cette commande : Si la catégorie n'existe pas encore, l'ajouter : ```yaml + - '🎯 Recommendation': # ... - Tests BDD: @@ -156,6 +158,7 @@ Description du contexte métier... **Justification** : Parce que... **Exemple** : + - Cas nominal : ... - Cas d'erreur : ... @@ -177,6 +180,7 @@ Les règles métier doivent être testables → créer des features BDD. ### Étape 5 : Ajouter dans `mkdocs.yml` ```yaml + - '🎙️ Content': - Règles: - Création & Publication: domains/content/rules/creation-publication.md @@ -234,6 +238,7 @@ Requêtes sqlc : `backend/queries/nouvelle_thing.sql` ### Ajouter dans `mkdocs.yml` ```yaml + - Entités: - Vue d'ensemble: domains/[domain]/entities/vue-ensemble.md - Nouvelle Entité: domains/[domain]/entities/nouvelle-entite.md # ← NOUVEAU @@ -268,6 +273,7 @@ sequenceDiagram ## Légende **Acteurs** : + - Utilisateur : Client de l'API - API : Backend RoadWave - Database : PostgreSQL diff --git a/docs/README.md b/docs/README.md index ff2e491..b002dd1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -80,6 +80,7 @@ Lorsque plusieurs contenus sont disponibles dans une zone, **seul le plus pertin Chaque utilisateur possède des **jauges d'intérêt** qui évoluent dynamiquement : ### Catégories + - Automobile - Voyage - Famille @@ -116,6 +117,7 @@ Interactions simplifiées pour sécurité routière maximale : | **Play/Pause** | Mettre en pause / reprendre la lecture | **Like automatique** : Le système détecte automatiquement vos préférences selon votre temps d'écoute : + - Écoute ≥80% du contenu → Like renforcé (+2 points jauge) - Écoute 30-79% du contenu → Like standard (+1 point jauge) - Skip après <10s → Signal négatif (-0.5 point) @@ -198,6 +200,7 @@ Approche hybride combinant participation communautaire, IA et modérateurs dédi | **Strike 4** | Ban définitif du compte créateur | Permanent | **Notes** : + - **Tolérance 1ère fois** (droits d'auteur uniquement) : avertissement sans strike - **Violations graves** (haine, illégalité, violence) : strike immédiat sans tolérance - **Réhabilitation** : -1 strike tous les 6 mois sans nouvelle violation diff --git a/docs/TECHNICAL.md b/docs/TECHNICAL.md index a9557b3..caec620 100644 --- a/docs/TECHNICAL.md +++ b/docs/TECHNICAL.md @@ -8,6 +8,7 @@ |-----------|-------------|-----| | **Backend** | Go + Fiber | [ADR-001](adr/001-langage-backend.md) | | **Architecture Backend** | Monolithe Modulaire | [ADR-010](adr/010-architecture-backend.md) | +| **Librairies Backend** | Fiber, pgx, rueidis, sqlc, etc. | [ADR-018](adr/018-librairies-go.md) | | **Authentification** | Zitadel (self-hosted OVH) | [ADR-008](adr/008-authentification.md) | | **Streaming** | HLS | [ADR-002](adr/002-protocole-streaming.md) | | **Codec** | Opus | [ADR-003](adr/003-codec-audio.md) | diff --git a/docs/adr/002-protocole-streaming.md b/docs/adr/002-protocole-streaming.md index b6e2b1c..d7d29c5 100644 --- a/docs/adr/002-protocole-streaming.md +++ b/docs/adr/002-protocole-streaming.md @@ -47,6 +47,7 @@ Streaming audio vers des utilisateurs mobiles en voiture, avec réseaux instable La latence HLS (5-30s) entre en conflit avec les notifications géolocalisées qui doivent déclencher l'audio **au moment précis** où l'utilisateur atteint un point d'intérêt. **Exemple critique** : + - Utilisateur en voiture à 90 km/h (25 m/s) - ETA de 7 secondes avant le point → notification affichée - Latence HLS de 15 secondes @@ -69,6 +70,7 @@ La latence HLS (5-30s) entre en conflit avec les notifications géolocalisées q ``` **Stratégie de cache** : + - Télécharge les **15 premières secondes** de chaque POI à proximité - Limite : 3 POI simultanés en cache (max ~25 MB) - Purge automatique après 200m de distance passée @@ -152,16 +154,19 @@ Si le pre-buffer échoue (réseau faible, pas de cache), afficher un **loader av ### Impact sur l'Infrastructure #### Backend (Go) + - **Nouveau service** : `audiocache.Service` pour préparer les extraits M4A - **Endpoint** : `GET /api/v1/audio/poi/:id/intro` (retourne 15s d'audio) - **CDN** : Cache NGINX avec TTL 7 jours sur `/audio/*/intro.m4a` #### Mobile (Flutter) + - **Package** : `just_audio` avec cache local (`flutter_cache_manager`) - **Stockage** : Max 100 MB de cache audio (auto-purge LRU) - **Logique** : `PreBufferService` avec scoring de priorité POI #### Coûts + - **Bande passante** : +10-15 MB/utilisateur/session (vs streaming pur) - **Stockage CDN** : +500 MB pour 1000 POI × 5 MB intro (négligeable) - **Économie** : Cache CDN réduit les requêtes origin (-60% selon tests) diff --git a/docs/adr/005-base-de-donnees.md b/docs/adr/005-base-de-donnees.md index 8974874..aee0f67 100644 --- a/docs/adr/005-base-de-donnees.md +++ b/docs/adr/005-base-de-donnees.md @@ -44,12 +44,14 @@ flowchart LR ## Justification ### PostgreSQL + PostGIS + - Requêtes géospatiales complexes et précises - Index GIST pour performance - ACID, fiabilité éprouvée - Écosystème mature ### PgBouncer + - **Connection pooling** : Réduit l'overhead de création de connexions PostgreSQL - **Mode transaction** : Connexion réutilisée entre transactions (optimal pour API stateless) - **Performance** : Permet de gérer 1000+ connexions concurrentes avec ~100 connexions réelles à PostgreSQL @@ -57,6 +59,7 @@ flowchart LR - **Port** : :6432 (vs :5432 pour PostgreSQL direct) ### Redis + - Cache géo natif (`GEORADIUS`) : 100K+ requêtes/sec - Sessions utilisateurs - Pub/sub pour temps réel @@ -81,11 +84,13 @@ LIMIT 20; ### Configuration PgBouncer **Mode recommandé** : `transaction` + - Connexion libérée après chaque transaction - Optimal pour API stateless (Go + Fiber) - Maximise la réutilisation des connexions **Pool sizing** : + - `default_pool_size` : 20 (connexions par base) - `max_client_conn` : 1000 (connexions clients max) - `reserve_pool_size` : 5 (connexions de secours) diff --git a/docs/adr/007-tests-bdd.md b/docs/adr/007-tests-bdd.md index 4b539bc..c96d957 100644 --- a/docs/adr/007-tests-bdd.md +++ b/docs/adr/007-tests-bdd.md @@ -67,11 +67,13 @@ features/ **Exécuté par** : Backend (Godog + step definitions Go dans `/backend/tests/bdd/`) **Exemples de scénarios** : + - `POST /api/v1/auth/register` avec email invalide → retourne 400 - `GET /api/v1/contents/nearby` avec rayon 500m → retourne POI triés par distance - `DELETE /api/v1/user/account` → supprime données RGPD conformément **Caractéristiques** : + - Focus sur la **logique métier backend** (algorithme, validation, persistance) - Pas d'interface utilisateur - Testable via requêtes HTTP directes @@ -85,11 +87,13 @@ features/ **Exécuté par** : Mobile (Flutter `integration_test` + step definitions Dart dans `/mobile/tests/bdd/`) **Exemples de scénarios** : + - Cliquer sur "Lecture" → widget audio player s'affiche avec progress bar - Mode piéton activé → carte interactive affichée + bouton "Télécharger zone" - Scroll dans liste podcasts → lazy loading déclenche pagination **Caractéristiques** : + - Focus sur l'**expérience utilisateur mobile** - Validation visuelle (widgets, animations, navigation) - Mock du backend si nécessaire (tests UI isolés) @@ -103,11 +107,13 @@ features/ **Exécuté par** : Backend **ET** Mobile ensemble **Exemples de scénarios** : + - Abonnement Premium : Formulaire mobile → API Zitadel → API RoadWave → Mangopay → Confirmation UI - Erreur réseau : Perte connexion pendant streaming → Fallback mode offline → Reprise auto après reconnexion - Notification géolocalisée : GPS détecte POI → Backend calcule recommandation → Push notification → Ouverture app → Lecture audio **Caractéristiques** : + - Tests **cross-composants** (intégration complète) - Implique souvent des **services tiers** (Zitadel, Mangopay, Firebase) - Validation du **parcours utilisateur de bout en bout** @@ -117,10 +123,12 @@ features/ ### Implémentation Step Definitions **Backend** : `/backend/tests/bdd/` + - Step definitions Go pour features `api/` et `e2e/` - Utilise `godog` et packages backend (`service`, `repository`) **Mobile** : `/mobile/tests/bdd/` + - Step definitions Dart pour features `ui/` et `e2e/` - Utilise Flutter `integration_test` framework diff --git a/docs/adr/008-authentification.md b/docs/adr/008-authentification.md index dc7bad6..a417582 100644 --- a/docs/adr/008-authentification.md +++ b/docs/adr/008-authentification.md @@ -14,11 +14,13 @@ RoadWave nécessite un système d'authentification sécurisé pour mobile (iOS/A **Zitadel self-hosted sur OVH France** pour l'IAM avec validation JWT locale côté API Go. **Méthode d'authentification** : **Email/Password uniquement** (pas d'OAuth tiers) + - ✅ Authentification native Zitadel (email + mot de passe) - ❌ **Pas de fournisseurs OAuth externes** (Google, Apple, Facebook) - **Protocole** : OAuth2 PKCE (entre app mobile et Zitadel uniquement) **Architecture de déploiement** : + - Container Docker sur le même VPS OVH (Gravelines, France) que l'API - Base de données PostgreSQL partagée avec RoadWave (séparation logique par schéma) - Aucune donnée d'authentification ne transite par des serveurs tiers @@ -102,12 +104,14 @@ graph TB 4. App mobile → Go API avec JWT → validation locale **Ce que nous N'UTILISONS PAS** : + - ❌ "Sign in with Google" - ❌ "Sign in with Apple" - ❌ "Sign in with Facebook" - ❌ Aucun autre fournisseur externe **Pourquoi OAuth2 alors ?** : + - OAuth2 PKCE est le **standard moderne** pour auth mobile (sécurisé, refresh tokens, etc.) - Zitadel implémente OAuth2/OIDC comme **protocole**, mais l'auth reste email/password - Alternative serait session cookies (moins adapté mobile) ou JWT custom (réinventer la roue) diff --git a/docs/adr/012-frontend-mobile.md b/docs/adr/012-frontend-mobile.md index 6e32770..f41e3c8 100644 --- a/docs/adr/012-frontend-mobile.md +++ b/docs/adr/012-frontend-mobile.md @@ -45,6 +45,7 @@ RoadWave nécessite applications iOS et Android avec support CarPlay/Android Aut - **Cache images** : `cached_network_image` (LRU cache) **Points d'attention** : + - ⚠️ **Permissions progressives requises** pour `geofence_service` et `geolocator` (voir section "Stratégie de Permissions") - ⚠️ **Licences** : 100% permissives (MIT, BSD-3) - voir ADR-020 @@ -53,6 +54,7 @@ RoadWave nécessite applications iOS et Android avec support CarPlay/Android Aut ### Contexte et Enjeux **Problème** : La géolocalisation en arrière-plan (requise pour le mode piéton) est **très scrutée** par Apple et Google : + - **iOS App Store** : Taux de rejet ~70% si permission "Always Location" mal justifiée - **Android Play Store** : `ACCESS_BACKGROUND_LOCATION` nécessite déclaration spéciale depuis Android 10 - **RGPD** : Permissions doivent être **optionnelles** et l'app **utilisable sans** @@ -74,6 +76,7 @@ Trois niveaux de permissions doivent être gérés : **Quand** : Premier lancement de l'app **Demande** : `locationWhenInUse` uniquement + - iOS : "Allow While Using App" - Android : `ACCESS_FINE_LOCATION` @@ -136,21 +139,25 @@ Pour vous proposer du contenu audio adapté Le service de gestion des permissions (`lib/core/services/location_permission_service.dart`) doit implémenter : **Détection du niveau actuel** : + - Vérifier le statut de la permission `location` (when in use) - Vérifier le statut de la permission `locationAlways` (background) - Retourner le niveau le plus élevé accordé **Demande de permission de base** (Étape 1) : + - Demander uniquement la permission `location` (when in use) - Utilisée lors de l'onboarding - Aucun écran d'éducation requis **Demande de permission arrière-plan** (Étape 2) : + - **Toujours** afficher un écran d'éducation AVANT la demande OS - Demander la permission `locationAlways` (iOS) ou `ACCESS_BACKGROUND_LOCATION` (Android) - Si refusée de manière permanente, proposer l'ouverture des réglages système **Gestion des refus** : + - Détecter si la permission est refusée de manière permanente - Proposer l'ouverture des réglages de l'appareil avec un message clair - Permettre à l'utilisateur d'annuler @@ -160,6 +167,7 @@ Le service de gestion des permissions (`lib/core/services/location_permission_se #### iOS (`ios/Runner/Info.plist`) **Clés requises** : + - `NSLocationWhenInUseUsageDescription` : Décrire l'usage pour le mode voiture (contenu géolocalisé en temps réel) - `NSLocationAlwaysAndWhenInUseUsageDescription` : Décrire l'usage optionnel pour le mode piéton (notifications audio-guides en arrière-plan), mentionner explicitement que c'est optionnel et désactivable - `UIBackgroundModes` : Activer les modes `location` et `remote-notification` @@ -170,11 +178,13 @@ Le service de gestion des permissions (`lib/core/services/location_permission_se #### Android (`android/app/src/main/AndroidManifest.xml`) **Permissions requises** : + - `ACCESS_FINE_LOCATION` et `ACCESS_COARSE_LOCATION` : Permission de base (when in use) - `ACCESS_BACKGROUND_LOCATION` : Permission arrière-plan (Android 10+), nécessite justification Play Store - `FOREGROUND_SERVICE` et `FOREGROUND_SERVICE_LOCATION` : Service persistant pour mode piéton (Android 12+) **Android Play Store** : Déclaration requise dans Play Console lors de la soumission : + - Justification : "Notifications géolocalisées pour audio-guides touristiques en arrière-plan" - Vidéo démo obligatoire montrant le flow de demande de permission @@ -191,12 +201,14 @@ Le service de gestion des permissions (`lib/core/services/location_permission_se ### Tests de Validation Stores **Checklist App Store (iOS)** : + - [ ] Permission "Always" demandée **uniquement** si user active mode piéton - [ ] Écran d'éducation **avant** demande OS (requis iOS 13+) - [ ] App fonctionne sans permission "Always" (validation critique) - [ ] Texte `Info.plist` clair et honnête (pas de tracking publicitaire) **Checklist Play Store (Android)** : + - [ ] Déclaration `ACCESS_BACKGROUND_LOCATION` avec justification détaillée - [ ] Vidéo démo flow de permissions (< 30s, requis Play Console) - [ ] App fonctionne sans permission background (validation critique) diff --git a/docs/adr/013-strategie-tests.md b/docs/adr/013-strategie-tests.md index 294cd25..7b1a5ae 100644 --- a/docs/adr/013-strategie-tests.md +++ b/docs/adr/013-strategie-tests.md @@ -79,6 +79,7 @@ Approche **multi-niveaux** : unitaires, intégration, BDD (Gherkin), E2E, load t - `github.com/cucumber/godog` - `github.com/testcontainers/testcontainers-go` - `grafana/k6` (AGPL-3.0, usage interne OK) + - Temps CI : ~3-5 min (tests unitaires + BDD) - Tests intégration/E2E : nightly builds (15-30 min) - Load tests : avant chaque release majeure diff --git a/docs/adr/014-organisation-monorepo.md b/docs/adr/014-organisation-monorepo.md index 2cac858..0b955de 100644 --- a/docs/adr/014-organisation-monorepo.md +++ b/docs/adr/014-organisation-monorepo.md @@ -68,6 +68,7 @@ mobile/tests/bdd/inscription_steps.dart → Teste l'UI mobile ``` Cela garantit que : + - Les spécifications métier sont uniques et cohérentes - Chaque couche teste sa responsabilité - Les tests valident le contrat entre front et back diff --git a/docs/adr/015-hebergement.md b/docs/adr/015-hebergement.md index 047e43a..ef1ed6a 100644 --- a/docs/adr/015-hebergement.md +++ b/docs/adr/015-hebergement.md @@ -52,6 +52,7 @@ OVH Object Storage (~1.20€/100GB) | **Scale** | 100K+ | Scaleway Kubernetes (Kapsule) | ~500€ | Auto-scaling OU multi-région | **Triggers détaillés** : + - **Phase 2** : CPU > 70% (7j), latence p99 > 100ms, backups > 1h/semaine, MRR > 2000€ - **Phase 3** : Auto-scaling horizontal requis, multi-région Europe, DevOps dédié, > 5 services diff --git a/docs/adr/016-service-emailing.md b/docs/adr/016-service-emailing.md index 43b3a1c..7770ca1 100644 --- a/docs/adr/016-service-emailing.md +++ b/docs/adr/016-service-emailing.md @@ -8,6 +8,7 @@ RoadWave nécessite un service d'envoi d'emails **techniques uniquement** (pas de notifications sociales, alertes marketing, promotions). **Périmètre strict** : + - ✅ **Authentification** : Vérification email (inscription), réinitialisation mot de passe, changement email - ✅ **Sécurité** : Alertes connexion inhabituelle, changement password - ✅ **Modération** : Strikes, suspensions, bannissements diff --git a/docs/adr/017-notifications-geolocalisees.md b/docs/adr/017-notifications-geolocalisees.md index e752ef9..cd5167f 100644 --- a/docs/adr/017-notifications-geolocalisees.md +++ b/docs/adr/017-notifications-geolocalisees.md @@ -45,6 +45,7 @@ Architecture hybride en **2 phases** : 5. Utilisateur clique → app s'ouvre → HLS démarre l'audio (ADR-002) **Limitations MVP** : + - Fonctionne uniquement si l'utilisateur a envoyé sa position < 5 minutes - En voiture rapide (>80 km/h), possible de "manquer" un POI si position pas mise à jour @@ -96,10 +97,12 @@ Architecture hybride en **2 phases** : ### Pourquoi implémentation directe APNS/FCM et pas SDK Firebase ? **Réalité technique** : Notifications natives requièrent obligatoirement Google/Apple + - **APNS (Apple)** : Seul protocole pour notifications iOS → dépendance Apple inévitable - **FCM (Google)** : Protocole standard Android (Google Play Services) **Implémentation directe choisie** : + - **Gratuit** : APNS et FCM sont gratuits (pas de limite de volume) - **Self-hosted** : Code backend 100% maîtrisé, pas de dépendance SDK tiers - **Fiabilité** : Infrastructure Apple/Google avec 99.95% uptime @@ -123,6 +126,7 @@ Architecture hybride en **2 phases** : - ❌ Toujours wrapper autour APNS/FCM **Décision technique** : + - Implémentation directe APNS/FCM dès le MVP - **Cohérence ADR** : Respecte ADR-008 (self-hosted) et ADR-015 (souveraineté française) - **Abstraction layer** : Interface `NotificationProvider` pour faciliter maintenance @@ -150,9 +154,11 @@ Architecture hybride en **2 phases** : - ⚠️ **Gestion certificats APNS** : Renouvellement annuel + configuration - Mitigé par scripts automation (certificats auto-renouvelés) - Documentation complète du processus + - ⚠️ **Tokens push sensibles** : Tokens FCM/APNS stockés côté backend - Chiffrement tokens en base (conformité RGPD) - Rotation automatique des tokens expirés + - ❌ WebSocket nécessite maintien de connexion (charge serveur +10-20%) - ❌ Mode offline non disponible au MVP (déception possible des early adopters) diff --git a/docs/adr/018-librairies-go.md b/docs/adr/018-librairies-go.md index 8ff3362..a90ed21 100644 --- a/docs/adr/018-librairies-go.md +++ b/docs/adr/018-librairies-go.md @@ -6,6 +6,7 @@ ## Contexte Le backend Go de RoadWave nécessite des librairies tierces pour HTTP, base de données, tests, streaming, etc. Le choix doit privilégier : + - **Licences permissives** (MIT, Apache-2.0, BSD) sans restrictions commerciales - **Performance** (10M utilisateurs, 100K RPS, p99 < 100ms) - **Maturité** et maintenance active @@ -55,6 +56,7 @@ Utilisation de **16 librairies open-source** avec licences permissives. ## Alternatives considérées Voir pour comparatifs complets : + - Framework : Fiber vs Gin vs Echo vs Chi - PostgreSQL : pgx vs GORM vs database/sql - Redis : rueidis vs go-redis vs redigo @@ -64,17 +66,20 @@ Voir pour comparatifs complets : ## Justification ### Licences + - **15/16 librairies** : MIT, Apache-2.0, BSD, ISC (permissives) - **1/16** : AGPL-3.0 (k6 load testing, OK usage interne) - **Compatibilité totale** : Aucun conflit de licence ### Performance + - **Fiber** : 36K RPS (5% plus rapide que Gin/Echo) - **pgx** : 30-50% plus rapide que GORM - **rueidis** : Client-side caching automatique - **zerolog** : Zero allocation, benchmarks 2025 ### Maturité + - **Standards** : testify (27% adoption), golang-migrate, viper - **Production** : Fiber (33K stars), pgx (10K stars), pion (13K stars) - **Maintenance** : Toutes actives (commits 2025-2026) @@ -82,12 +87,14 @@ Voir pour comparatifs complets : ## Conséquences ### Positives + - ✅ Aucune restriction licence commerciale - ✅ Stack cohérent avec ADR existants (001, 002, 007, 008, 013, 015, 019) - ✅ Performance validée (benchmarks publics) - ✅ Écosystème mature et documenté ### Négatives + - ⚠️ **k6 (AGPL-3.0)** : Copyleft, mais OK pour tests internes (pas de SaaS k6 prévu) - ⚠️ **Gestion certificats APNS** : Renouvellement annuel, configuration manuelle - ❌ Courbe d'apprentissage : 16 librairies à maîtriser (doc nécessaire) diff --git a/docs/adr/019-geolocalisation-ip.md b/docs/adr/019-geolocalisation-ip.md index f77113a..143180f 100644 --- a/docs/adr/019-geolocalisation-ip.md +++ b/docs/adr/019-geolocalisation-ip.md @@ -8,10 +8,12 @@ RoadWave nécessite un service de géolocalisation par IP pour le mode dégradé (utilisateurs sans GPS activé). Ce service permet de détecter la ville/région de l'utilisateur à partir de son adresse IP et d'afficher du contenu régional même sans permission GPS. **Évolution du marché** : + - **Avant 2019** : MaxMind GeoLite2 était téléchargeable gratuitement (base de données locale) - **Depuis 2019** : MaxMind nécessite un compte + limite 1000 requêtes/jour (gratuit), puis 0.003$/requête au-delà **Usage RoadWave** : + - Mode dégradé : ~10% des utilisateurs (estimation) - Volume : 1000 utilisateurs × 10% = 100 requêtes/jour (MVP) - Critère : Aucune dépendance à un service tiers payant @@ -33,6 +35,7 @@ RoadWave nécessite un service de géolocalisation par IP pour le mode dégradé ### IP2Location Lite (choix retenu) **Avantages** : + - Gratuit (pas de limite de requêtes) - Self-hosted (souveraineté des données, cohérence avec [ADR-004](004-cdn.md)) - Base de données SQLite légère (50-100 MB) @@ -41,12 +44,14 @@ RoadWave nécessite un service de géolocalisation par IP pour le mode dégradé - Pas de compte tiers requis **Inconvénients** : + - Maintenance mensuelle (mise à jour DB) - Précision équivalente à MaxMind (~±50 km) ### MaxMind GeoLite2 API (rejeté) **Pourquoi rejeté** : + - Coût potentiel en cas de dépassement quota (risque faible mais existant) - Dépendance à un service tiers (perte de souveraineté) - Compte requis (friction opérationnelle) @@ -54,6 +59,7 @@ RoadWave nécessite un service de géolocalisation par IP pour le mode dégradé ### Self-hosted MaxMind (rejeté) **Pourquoi rejeté** : + - Compte MaxMind obligatoire pour télécharger la DB (friction) - Complexité identique à IP2Location pour résultat équivalent - IP2Location offre même fonctionnalité sans compte tiers @@ -84,28 +90,33 @@ flowchart TD ### Maintenance **Mise à jour mensuelle** : + - Cron job télécharge nouvelle DB IP2Location (1er du mois) - Backup DB actuelle avant remplacement - Rechargement service GeoIP (hot reload sans downtime) **Monitoring** : + - Alertes si DB > 60 jours (DB obsolète) - Logs requêtes "IP non trouvée" (détection problèmes DB) ## Conséquences ### Positives + - Aucun coût récurrent (gratuit à l'infini) - Souveraineté complète des données (cohérence ADR-004) - Pas de dépendance externe (service tiers) - Latence minimale (lookup local SQLite < 1ms) ### Négatives + - Maintenance mensuelle requise (automatisable) - Précision limitée (±50 km, acceptable pour mode dégradé) - Taille base de données (~50-100 MB sur disque) ### Risques atténués + - **DB obsolète** : Alertes automatiques si > 60 jours - **IP non trouvée** : Fallback "France" par défaut (code pays FR) - **Perte DB** : Backup automatique avant chaque mise à jour diff --git a/docs/adr/020-librairies-flutter.md b/docs/adr/020-librairies-flutter.md index 94e2dff..2401955 100644 --- a/docs/adr/020-librairies-flutter.md +++ b/docs/adr/020-librairies-flutter.md @@ -6,6 +6,7 @@ ## Contexte L'application mobile RoadWave (iOS/Android) nécessite des librairies tierces pour audio HLS, géolocalisation, notifications, state management, etc. Le choix doit privilégier : + - **Licences permissives** (MIT, Apache-2.0, BSD) sans restrictions commerciales - **Maturité** et maintenance active (écosystème Flutter) - **Performance native** (pas de bridge JS) @@ -53,28 +54,33 @@ Utilisation de **9 librairies open-source** Flutter avec licences permissives, d ## Alternatives considérées ### State Management + - **flutter_bloc** (choisi) : Pattern BLoC, testable, reactive - **riverpod** : Plus moderne, moins mature - **provider** : Simple mais limité pour app complexe - **getx** : Performance mais opinions controversées ### Audio + - **just_audio** (choisi) : HLS natif, communauté active - **audioplayers** : Moins mature pour streaming - **flutter_sound** : Orienté recording, pas streaming ### Géolocalisation + - **geolocator** (choisi) : Standard Flutter, 1.2K+ stars - **location** : Moins maintenu - **background_location** : Spécifique background uniquement ### Notifications Push + - **flutter_apns + flutter_fcm** (choisi) : Implémentation directe APNS/FCM, pas de vendor lock-in - **firebase_messaging** : SDK Firebase, vendor lock-in Google - **OneSignal** : Plus cher (500€/mois @ 100K users), vendor lock-in - **Custom WebSocket** : Complexe, toujours besoin APNS/FCM au final (voir ADR-017) ### Geofencing (Phase 2) + - **geofence_service** (choisi) : Natif iOS/Android, économie batterie optimale - **background_geolocation** : Payant (149$/an par app) - **flutter_background_location** : Moins mature @@ -82,17 +88,20 @@ Utilisation de **9 librairies open-source** Flutter avec licences permissives, d ## Justification ### Licences + - **7/9 librairies** : MIT (permissive totale) - **2/9** : BSD-3 (permissive, compatible commercial) - **Compatibilité totale** : Aucun conflit de licence, aucune restriction commerciale ### Maturité + - **flutter_bloc** : 11.6K stars, adoption large (state management standard) - **just_audio** : 900+ stars, utilisé production (podcasts apps) - **geolocator** : 1.2K stars, maintenu BaseFlow (entreprise Flutter) - **dio** : 12K+ stars, client HTTP le plus utilisé Flutter ### Performance + - **Compilation native** : Dart → ARM64 (pas de bridge JS comme React Native) - **just_audio** : Utilise AVPlayer (iOS) et ExoPlayer (Android) natifs - **geolocator** : Accès direct CoreLocation (iOS) et FusedLocation (Android) @@ -100,6 +109,7 @@ Utilisation de **9 librairies open-source** Flutter avec licences permissives, d - **geofence_service** (Phase 2) : Geofencing natif, minimise consommation batterie ### Conformité Stores + - **Permissions progressives** : `permission_handler` + stratégie ADR-010 - **Background modes MVP** : `geolocator` (When In Use) + `firebase_messaging` approuvés stores - **Background modes Phase 2** : `geofence_service` nécessite permission "Always" (taux acceptation ~30%) @@ -171,6 +181,7 @@ graph TB ## Conséquences ### Positives + - ✅ Aucune restriction licence commerciale (100% permissif) - ✅ Stack cohérent avec ADR-010 (Frontend Mobile) - ✅ Performance native (compilation ARM64 directe) @@ -179,6 +190,7 @@ graph TB - ✅ Conformité stores (permissions progressives) ### Négatives + - ⚠️ **CarPlay/Android Auto** : Packages communautaires (pas officiels Flutter) - ⚠️ **Configuration APNS/FCM** : Gestion certificats et OAuth2, configuration manuelle - ⚠️ **Permission "Always" Phase 2** : Taux acceptation ~30% (geofencing local) @@ -190,6 +202,7 @@ graph TB > **Note** : Les versions exactes seront définies lors de l'implémentation. Cette section indique les packages requis, non les versions à utiliser (qui évoluent rapidement dans l'écosystème Flutter). **Core (Phase 1 MVP)** : + - `flutter_bloc` - State management - `just_audio` - Audio HLS streaming - `dio` - HTTP client @@ -197,6 +210,7 @@ graph TB - `cached_network_image` - Cache images **Géolocalisation & Notifications (Phase 1 MVP)** : + - `geolocator` - GPS haute précision, WebSocket position updates - `flutter_apns` - Push notifications APNS natif iOS (ADR-017) - `flutter_fcm` - Push notifications FCM natif Android (ADR-017) @@ -204,10 +218,12 @@ graph TB - `permission_handler` - Gestion permissions **CarPlay/Android Auto (optionnels Phase 1)** : + - `flutter_carplay` - Intégration CarPlay - `android_auto_flutter` - Support Android Auto **Geofencing (Phase 2 Post-MVP)** : + - `geofence_service` - Geofencing local pour mode offline (ADR-017 Phase 2) ### Migration depuis ADR-010 @@ -219,15 +235,18 @@ La section "Packages clés" de l'ADR-010 est désormais obsolète et doit réfé ## Risques et Mitigations ### Risque 1 : CarPlay/Android Auto packages communautaires + - **Impact** : Maintenance non garantie par Flutter team - **Mitigation** : Fork privé si besoin, contribution upstream, ou développement custom si critique ### Risque 2 : Validation App Store (permissions background) + - **Impact** : Taux de rejet ~70% si mal justifié - **Mitigation Phase 1** : Permission "When In Use" seulement (MVP), moins scrutée par Apple - **Mitigation Phase 2** : Stratégie progressive (ADR-010), écrans d'éducation, tests beta TestFlight pour permission "Always" ### Risque 3 : Performance audio HLS en arrière-plan + - **Impact** : Interruptions si OS tue l'app - **Mitigation** : Background audio task iOS, foreground service Android (natif dans `just_audio`) diff --git a/docs/adr/021-solution-cache.md b/docs/adr/021-solution-cache.md index d33033b..414e103 100644 --- a/docs/adr/021-solution-cache.md +++ b/docs/adr/021-solution-cache.md @@ -14,6 +14,7 @@ L'application nécessite un système de cache performant pour plusieurs cas d'us - **Rate limiting** : Protection contre les abus API Les contraintes de performance sont strictes : + - Latence p99 < 5ms pour les requêtes de cache - Support de 100K+ requêtes/seconde en lecture - Persistance optionnelle (données non critiques) @@ -24,6 +25,7 @@ Les contraintes de performance sont strictes : **Redis 7+ en mode Cluster** sera utilisé comme solution de cache principale. Configuration : + - Mode Cluster avec 3 nœuds minimum (haute disponibilité) - Persistence RDB désactivée pour les caches chauds (performance maximale) - AOF activé uniquement pour les sessions utilisateurs (durabilité) @@ -76,6 +78,7 @@ Ces commandes permettent de servir les requêtes de proximité directement depui ### Écosystème Go Librairie `go-redis/redis` (13K+ stars GitHub) : + - Support complet Redis Cluster - Pipeline et transactions - Context-aware (intégration Go idiomatique) @@ -84,6 +87,7 @@ Librairie `go-redis/redis` (13K+ stars GitHub) : ### Pub/Sub pour temps réel Support natif de messaging publish/subscribe pour : + - Notifications push (invalidation de cache) - Événements temps réel (nouveau contenu géolocalisé) - Coordination entre instances API (scaling horizontal) @@ -106,12 +110,14 @@ Support natif de messaging publish/subscribe pour : ### Stratégie de cache **TTL par type de donnée** : + - Métadonnées de contenu : 15 minutes (mise à jour rare) - Résultats géolocalisés : 5 minutes (contenus statiques géographiquement) - Sessions utilisateurs : 24 heures (renouvellement automatique) - Rate limiting : 1 minute (fenêtre glissante) **Invalidation** : + - Publication de contenu → `DEL` métadonnées + publication Pub/Sub - Modification géolocalisation → `GEOREM` puis `GEOADD` - Logout utilisateur → `DEL` session @@ -119,21 +125,25 @@ Support natif de messaging publish/subscribe pour : ### Configuration production **Cluster 3 nœuds** (minimum haute disponibilité) : + - 1 master + 2 replicas - Répartition sur 3 zones de disponibilité (anti-affinité) - `cluster-require-full-coverage no` → lecture dégradée si nœud down **Mémoire** : + - `maxmemory 2gb` par nœud (ajustable selon charge) - `maxmemory-policy allkeys-lru` → éviction automatique anciennes clés **Persistance** : + - RDB désactivé (`save ""`) pour caches chauds - AOF `appendonly yes` uniquement pour sessions (nœud dédié optionnel) ### Monitoring Métriques critiques à suivre : + - Taux de hit/miss par namespace (target >95% hit rate) - Latence p99 par commande (alerter si >10ms) - Fragmentation mémoire (rebalance si >1.5) diff --git a/docs/adr/022-strategie-cicd-monorepo.md b/docs/adr/022-strategie-cicd-monorepo.md index b4a6d26..2d8be8e 100644 --- a/docs/adr/022-strategie-cicd-monorepo.md +++ b/docs/adr/022-strategie-cicd-monorepo.md @@ -8,6 +8,7 @@ RoadWave est organisé en monorepo contenant backend Go, mobile Flutter, documentation et features BDD ([ADR-014](014-organisation-monorepo.md)). Sans optimisation, chaque commit déclencherait **tous** les builds (backend + mobile + docs), même si seul un composant a changé. **Problématique** : + - ❌ Temps de CI/CD inutilement longs (rebuild complet ~15 min) - ❌ Gaspillage de ressources GitHub Actions - ❌ Ralentissement du feedback développeur @@ -44,6 +45,7 @@ RoadWave est organisé en monorepo contenant backend Go, mobile Flutter, documen #### Workflow Backend (`backend.yml`) **Déclencheurs** : + - Branches : `main`, `develop` - Chemins surveillés : - `backend/**` : Code Go, migrations, configuration @@ -52,6 +54,7 @@ RoadWave est organisé en monorepo contenant backend Go, mobile Flutter, documen - `.github/workflows/backend.yml` : Modifications du workflow lui-même **Jobs exécutés** : + - **Tests unitaires** : Exécution `go test` sur tous les packages - **Tests d'intégration** : Utilisation de Testcontainers avec PostgreSQL/PostGIS - **Tests BDD** : Exécution Godog sur features `api/` et `e2e/` @@ -65,6 +68,7 @@ RoadWave est organisé en monorepo contenant backend Go, mobile Flutter, documen #### Workflow Mobile (`mobile.yml`) **Déclencheurs** : + - Branches : `main`, `develop` - Chemins surveillés : - `mobile/**` : Code Flutter/Dart, assets, configuration @@ -73,6 +77,7 @@ RoadWave est organisé en monorepo contenant backend Go, mobile Flutter, documen - `.github/workflows/mobile.yml` : Modifications du workflow lui-même **Jobs exécutés** : + - **Tests unitaires** : Exécution `flutter test` sur widgets et logique métier - **Tests d'intégration** : Tests d'intégration Flutter (interactions UI complexes) - **Lint** : Analyse statique `flutter analyze` @@ -80,6 +85,7 @@ RoadWave est organisé en monorepo contenant backend Go, mobile Flutter, documen - **Build iOS** : Compilation IPA release sans codesign (dépend des tests) **Environnement** : + - Tests/Lint/Build Android : Ubuntu latest - Build iOS : macOS latest (requis pour Xcode) - Flutter 3.16.0+ @@ -89,6 +95,7 @@ RoadWave est organisé en monorepo contenant backend Go, mobile Flutter, documen #### Workflow Shared (`shared.yml`) **Déclencheurs** : + - Branches : `main`, `develop` - Chemins surveillés : - `docs/**` : ADR, règles métier, documentation technique @@ -96,6 +103,7 @@ RoadWave est organisé en monorepo contenant backend Go, mobile Flutter, documen - `.github/workflows/shared.yml` : Modifications du workflow lui-même **Jobs exécutés** : + - **Validation documentation** : Build MkDocs en mode strict (détecte erreurs markdown) - **Vérification liens** : Validation des liens internes/externes dans documentation - **Tests code partagé** : Exécution tests si du code partagé backend-mobile existe @@ -117,6 +125,7 @@ RoadWave est organisé en monorepo contenant backend Go, mobile Flutter, documen | **Commit mixte (backend + mobile + docs)** | ✅ | ✅ | ✅ | ~13 min (parallèle) | **Économie de temps** : + - Commit backend-only : ~5 min (vs 15 min sans path filters) = **67% plus rapide** - Commit docs-only : ~30s (vs 15 min) = **97% plus rapide** @@ -125,6 +134,7 @@ RoadWave est organisé en monorepo contenant backend Go, mobile Flutter, documen Les tests end-to-end dans `/features/e2e/` **déclenchent les deux workflows** (backend ET mobile) car ils testent l'intégration complète : **Exemples de features E2E** : + - `features/e2e/abonnements/` : Formulaire mobile → API Zitadel → API RoadWave → Mangopay → Confirmation UI - `features/e2e/error-handling/` : Perte réseau → Fallback mode offline → Reprise auto après reconnexion @@ -159,6 +169,7 @@ Les tests end-to-end dans `/features/e2e/` **déclenchent les deux workflows** ( ❌ **Complexité initiale** : setup plus complexe que workflow monolithique **Mitigation** : + - Utiliser des **composite actions** pour partager la config commune - Documentation claire dans ce ADR - Coût initial faible (~2h setup) vs gains à long terme importants @@ -177,15 +188,18 @@ Les tests end-to-end dans `/features/e2e/` **déclenchent les deux workflows** ( ### Plan d'Implémentation **Phase 1** : Setup workflows de base (~1h) + - Créer `backend.yml` avec jobs test + lint + build - Créer `mobile.yml` avec jobs test + lint + build - Créer `shared.yml` avec validation docs **Phase 2** : Configuration path filters (~30 min) + - Ajouter `paths:` à chaque workflow - Tester avec commits isolés (backend-only, mobile-only, docs-only) **Phase 3** : Optimisations (~30 min) + - Ajouter caching (Go modules, Flutter dependencies, node_modules) - Créer composite actions pour config partagée - Ajouter badges status dans README @@ -226,6 +240,7 @@ Les tests end-to-end dans `/features/e2e/` **déclenchent les deux workflows** ( ⚠️ **Faux négatifs** : path filter mal configuré → test non exécuté → bug en production **Mitigation** : + - Features E2E déclenchent toujours backend + mobile (safety net) - Tests de validation dans le plan d'implémentation - Review obligatoire des modifications de workflows diff --git a/docs/adr/023-architecture-moderation.md b/docs/adr/023-architecture-moderation.md index 8bcc7bb..03ced8e 100644 --- a/docs/adr/023-architecture-moderation.md +++ b/docs/adr/023-architecture-moderation.md @@ -6,6 +6,7 @@ ## Contexte Le système de modération RoadWave doit traiter des signalements de contenu audio problématique (haine, spam, droits d'auteur, etc.) avec : + - **SLA stricts** : 2h (critique), 24h (haute), 72h (standard) définis dans [Règle 14](../domains/moderation/rules/moderation-flows.md) - **Scalabilité** : 0-10K+ signalements/mois - **Conformité DSA** : transparence, traçabilité, délais garantis @@ -165,12 +166,14 @@ graph TB ### Dépendances **Backend Go** : + - `gofiber/fiber/v3` : API Dashboard - `jackc/pgx/v5` : PostgreSQL + LISTEN/NOTIFY - `redis/rueidis` : Cache priorisation - Whisper : via Python subprocess ou go-whisper bindings **Frontend Dashboard** : + - `react` : Framework UI - `@tanstack/react-table` : Tables performantes - `wavesurfer.js` : Player audio avec waveform diff --git a/docs/adr/024-monitoring-observabilite.md b/docs/adr/024-monitoring-observabilite.md index adf7f57..b28a89f 100644 --- a/docs/adr/024-monitoring-observabilite.md +++ b/docs/adr/024-monitoring-observabilite.md @@ -6,6 +6,7 @@ ## Contexte RoadWave nécessite un système de monitoring pour garantir la disponibilité cible 99.9% (SLO) définie dans : + - **Métriques** : latency p99 < 100ms, throughput API, erreurs - **Alerting** : détection pannes, dégradations performance - **Incident response** : runbooks, escalation, post-mortems @@ -93,16 +94,19 @@ graph TB ### Métriques Clés **API Performance** (requêtes PromQL) : + - Latency p99 : histogramme quantile 99e percentile sur durée requêtes HTTP (fenêtre 5 min) - Error rate : ratio requêtes 5xx / total requêtes (fenêtre 5 min) - Throughput : taux de requêtes par seconde (fenêtre 5 min) **Infrastructure** : + - CPU usage : taux utilisation CPU (mode non-idle, fenêtre 5 min) - Memory usage : ratio mémoire disponible / totale - Disk I/O : temps I/O disque (fenêtre 5 min) **Business** (compteurs custom) : + - Active users (DAU) : `roadwave_active_users_total` - Audio streams actifs : `roadwave_hls_streams_active` - Signalements modération : `roadwave_moderation_reports_total` @@ -182,6 +186,7 @@ graph TB ### Dashboards Grafana **Dashboard principal** : + - Latency p50/p95/p99 API (5 min, 1h, 24h) - Error rate 5xx/4xx (seuil alerte >1%) - Throughput requests/sec @@ -189,12 +194,14 @@ graph TB - Business : DAU, streams actifs, signalements modération **Dashboard PostgreSQL** : + - Slow queries (>100ms) - Connections actives vs max - Cache hit ratio (cible >95%) - Deadlocks count **Dashboard Redis** : + - Memory usage - Evictions count - Commands/sec @@ -203,27 +210,32 @@ graph TB ### Alerting Rules **Alertes critiques** (Telegram + Email immédiat) : + - **API Down** : Job API indisponible pendant >1 min → Notification immédiate - **High Error Rate** : Taux erreurs 5xx >1% pendant >5 min → Notification immédiate - **Database Down** : PostgreSQL indisponible pendant >1 min → Notification immédiate **Alertes warnings** (Email uniquement) : + - **High Latency** : Latency p99 >100ms pendant >10 min → Investigation requise - **Disk Space Running Out** : Espace disque <10% pendant >30 min → Nettoyage requis ### Backup & Disaster Recovery **PostgreSQL WAL-E** : + - Méthode : Backup continu Write-Ahead Log (WAL) - Rétention : 7 jours full + WAL incrémentaux - Stockage : S3 OVH région GRA (France) - Chiffrement : AES-256 server-side **RTO (Recovery Time Objective)** : 1h + - Restore depuis S3 : ~30 min (DB 10 GB) - Validation + relance services : ~30 min **RPO (Recovery Point Objective)** : 15 min + - Fréquence archivage WAL : toutes les 15 min - Perte maximale : 15 min de transactions diff --git a/docs/adr/025-securite-secrets.md b/docs/adr/025-securite-secrets.md index 56dae06..c020cb5 100644 --- a/docs/adr/025-securite-secrets.md +++ b/docs/adr/025-securite-secrets.md @@ -6,6 +6,7 @@ ## Contexte RoadWave manipule des données sensibles nécessitant une protection renforcée : + - **Secrets applicatifs** : JWT signing key, DB credentials, Mangopay API keys - **PII utilisateurs** : Positions GPS précises, emails, données bancaires (via Mangopay) - **Conformité** : RGPD (minimisation données, encryption at rest), PCI-DSS (paiements) @@ -88,11 +89,13 @@ graph TB 3. Login root + activation KV-v2 engine (path : `roadwave/`) **Secrets stockés** : + - **JWT signing key** : Paire RS256 privée/publique - **Database credentials** : Host, port, user, password (généré aléatoire 32 caractères) - **Mangopay API** : Client ID, API key, webhook secret **Récupération depuis Backend Go** : + - Utilisation SDK `hashicorp/vault/api` - Authentification via token Vault (variable env VAULT_TOKEN) - Récupération secrets via KVv2 engine @@ -100,28 +103,33 @@ graph TB ### Encryption PII (Field-level) **Données chiffrées** (AES-256-GCM) : + - **GPS précis** : lat/lon conservés 24h puis réduits à geohash-5 (~5km²) ([Règle 02](../domains/_shared/rules/rgpd.md)) - **Email** : chiffré en base, déchiffré uniquement à l'envoi - **Numéro téléphone** : si ajouté (Phase 2) **Architecture encryption** : + - Utilisation bibliothèque standard Go `crypto/aes` avec mode GCM (AEAD) - Master key 256 bits (32 bytes) récupérée depuis Vault - Chiffrement : génération nonce aléatoire + seal GCM → encodage base64 - Stockage : colonne `email_encrypted` en base PostgreSQL **Contraintes** : + - Index direct sur champ chiffré impossible - Solution : index sur hash SHA-256 de l'email chiffré pour recherche ### HTTPS/TLS Configuration **Let's Encrypt wildcard certificate** : + - Méthode : Certbot avec DNS-01 challenge (API OVH) - Domaines couverts : `roadwave.fr` + `*.roadwave.fr` (wildcard) - Renouvellement : automatique via cron quotidien (30j avant expiration) **Nginx TLS configuration** : + - Protocol : TLS 1.3 uniquement (pas de TLS 1.2 ou inférieur) - Ciphers : TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384 - HSTS : max-age 1 an, includeSubDomains @@ -214,12 +222,14 @@ graph TB ### Rate Limiting (Protection DDoS/Brute-force) **Configuration** : + - Middleware Fiber `limiter` avec backend Redis - Limite : 100 requêtes par minute par IP (global) - Clé de limitation : adresse IP client - Réponse limitation : HTTP 429 "Too many requests" **Rate limits par endpoint** : + - `/auth/login` : 5 req/min/IP (protection brute-force) - `/moderation/report` : 10 req/24h/user (anti-spam) - API générale : 100 req/min/IP @@ -236,6 +246,7 @@ graph TB | **Encryption master key** | Jamais (re-encryption massive) | Backup sécurisé uniquement | **Process rotation DB credentials** : + - Vault génère automatiquement nouveau password - Vault met à jour PostgreSQL avec nouveau password - Application récupère nouveau password au prochain accès Vault diff --git a/docs/adr/README.md b/docs/adr/README.md index fe8347d..4da579a 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -103,10 +103,12 @@ Quelles autres options ont été évaluées ? ## Conséquences ### Positives + - Avantage 1 - Avantage 2 ### Négatives + - Limitation 1 - Compromis accepté diff --git a/docs/compliance/stores-submission.md b/docs/compliance/stores-submission.md index 4cc9e17..14de1b8 100644 --- a/docs/compliance/stores-submission.md +++ b/docs/compliance/stores-submission.md @@ -7,6 +7,7 @@ ## Contexte RoadWave est une app audio géolocalisée utilisée en conduite (CarPlay/Android Auto) avec : + - Contenu généré par utilisateurs (UGC) - Monétisation : publicités géolocalisées + Premium (4.99€ web / 5.99€ IAP) - GPS en arrière-plan @@ -15,6 +16,7 @@ RoadWave est une app audio géolocalisée utilisée en conduite (CarPlay/Android ## Stratégie de conformité **Approche multi-plateforme** avec : + - Modération UGC robuste (IA + humain) - Prix différenciés selon région (US/EU/Monde) - GPS avec disclosure complète @@ -32,6 +34,7 @@ RoadWave est une app audio géolocalisée utilisée en conduite (CarPlay/Android ## Conformité détaillée ### Android Auto / CarPlay ✅ + - 100% audio (pas de vidéo) - Commandes standard au volant - Aucun achat in-car @@ -42,16 +45,19 @@ RoadWave est une app audio géolocalisée utilisée en conduite (CarPlay/Android ### Google Play ⚠️ **UGC (critique)** : + - Modération hybride IA + humain ✅ - 3 premiers contenus validés manuellement ✅ - Système de strikes (4 = ban) ✅ - Signalement + blocage utilisateurs ✅ **GPS Background (critique)** : + - Permission "Always Location" = **OPTIONNELLE** - Demandée uniquement pour mode piéton (notifications arrière-plan audio-guides) - Justification Play Console : > "RoadWave permet aux utilisateurs de recevoir des alertes audio-guides lorsqu'ils passent à pied près de monuments/musées, même quand l'app est en arrière-plan. Cette fonctionnalité est optionnelle et peut être désactivée dans les paramètres." + - In-app disclosure obligatoire (écran dédié avant demande permission) - Si refusée : app fonctionne en mode voiture uniquement - **Action** : Remplir formulaire background location Play Console avec justification @@ -68,19 +74,23 @@ RoadWave est une app audio géolocalisée utilisée en conduite (CarPlay/Android ### App Store ⚠️ **Prix différenciés (légaux depuis 2025-2026)** : + - 🇺🇸 US : Lien externe autorisé (0% commission) - 🇪🇺 EU : Paiement externe DMA (7-20% commission réduite) - 🌍 Monde : IAP obligatoire (30% commission) **UGC** : + - Mode Kids obligatoire (filtrage selon âge) ✅ - Système de modération + signalement ✅ **GPS Background (critique)** : + - Permission "Always Location" = **OPTIONNELLE** - Deux strings Info.plist requises : - `NSLocationWhenInUseUsageDescription` : explication mode voiture - `NSLocationAlwaysAndWhenInUseUsageDescription` : explication mode piéton (optionnel) + - In-app disclosure obligatoire avant demande "Always" - Flux two-step : When In Use → Always (si user active mode piéton) - Si refusée : app fonctionne en mode voiture uniquement @@ -89,6 +99,7 @@ RoadWave est une app audio géolocalisée utilisée en conduite (CarPlay/Android ### Revenus créateurs **Position** : Paiements créateurs = "services" (comme YouTube/Uber), pas IAP + - Paiement via Mangopay Connect (externe) - Commission stores uniquement sur Premium (IAP) - Comparables : YouTube AdSense, TikTok Creator Fund, Uber @@ -110,12 +121,14 @@ RoadWave est une app audio géolocalisée utilisée en conduite (CarPlay/Android ## Stratégie de lancement **Phase 1 - MVP** : + - IAP uniquement (5.99€/mois mondial) - Modération UGC active - GPS avec disclosure - CarPlay/Android Auto basique **Phase 2 - Post-validation** : + - Prix différenciés US (lien externe 4.99€) - Paiement externe EU (DMA) - Monétisation créateurs (Mangopay) diff --git a/docs/domains/README.md b/docs/domains/README.md index 33941b3..c405ae3 100644 --- a/docs/domains/README.md +++ b/docs/domains/README.md @@ -200,13 +200,6 @@ domains// └── features/ # Tests BDD Gherkin (*.feature) ``` -## Navigation - -- *(structure legacy, déprécié)* -- [🏛️ ADR (Architecture Decision Records)](../adr/README.md) -- [⚖️ Documentation légale](../legal/README.md) -- [🔧 Documentation technique](../TECHNICAL.md) - ## Ubiquitous Language Global **Termes transversaux utilisés dans tous les domaines** : diff --git a/docs/domains/_shared/README.md b/docs/domains/_shared/README.md index 16f6081..7295c28 100644 --- a/docs/domains/_shared/README.md +++ b/docs/domains/_shared/README.md @@ -24,6 +24,7 @@ Le domaine **Shared** constitue le **Core Domain** de RoadWave. Il contient les ## Ubiquitous Language **Termes métier du domaine partagé** : + - **User** : Utilisateur de la plateforme (auditeur, créateur, ou les deux) - **Content** : Tout contenu audio diffusé sur la plateforme - **Subscription** : Abonnement d'un utilisateur à un créateur ou une catégorie diff --git a/docs/domains/_shared/entities/account-deletions.md b/docs/domains/_shared/entities/account-deletions.md index 904e6fc..5ca79c4 100644 --- a/docs/domains/_shared/entities/account-deletions.md +++ b/docs/domains/_shared/entities/account-deletions.md @@ -25,6 +25,7 @@ erDiagram ## Légende **Statuts** : + - `pending`: Grace period actif (30j), compte désactivé, annulation possible - `cancelled`: Utilisateur a annulé via lien email - `completed`: Suppression effective réalisée après 30j @@ -36,5 +37,6 @@ erDiagram 4. Si 30j écoulés → job cron supprime données, anonymise contenus **Données supprimées** : + - Profil utilisateur, historique GPS/écoute, sessions - Contenus créés : anonymisés (`créateur = "Utilisateur supprimé"`) diff --git a/docs/domains/_shared/entities/breach-incidents.md b/docs/domains/_shared/entities/breach-incidents.md index d9738d8..932c311 100644 --- a/docs/domains/_shared/entities/breach-incidents.md +++ b/docs/domains/_shared/entities/breach-incidents.md @@ -36,16 +36,19 @@ erDiagram ## Légende **Sévérité** : + - `low`: Pas de notification requise (mesures techniques suffisantes) - `medium`: Notification CNIL uniquement - `high`: Notification CNIL + utilisateurs - `critical`: Notification immédiate tous canaux + SMS fondateur **Timeline 72h** : + - H+0 : Détection, confinement - H+24 : Évaluation gravité - H+48 : Notification CNIL si requis - H+72 : Notification utilisateurs si risque élevé **Catégories de données** : + - `data_categories_affected`: JSON `["gps", "email", "listening_history"]` diff --git a/docs/domains/_shared/entities/consents.md b/docs/domains/_shared/entities/consents.md index 73997f4..f7c5417 100644 --- a/docs/domains/_shared/entities/consents.md +++ b/docs/domains/_shared/entities/consents.md @@ -23,17 +23,20 @@ erDiagram ## Légende **Types de consentement** : + - `geolocation_precise` : Géolocalisation GPS précise (obligatoire pour contenu hyperlocal) - `analytics` : Analytics Matomo (optionnel) - `push_notifications` : Notifications push (optionnel) - `cookies_analytics` : Cookies analytiques (optionnel) **Versioning** : + - Chaque changement de CGU/politique = nouvelle version - Historique complet conservé (preuve légale) - Format version : `v1.0`, `v2.0`, etc. **Conformité RGPD** : + - Granularité : fonctionnel / analytique / marketing - Consentement libre et éclairé - Révocable à tout moment diff --git a/docs/domains/_shared/entities/data-retention-logs.md b/docs/domains/_shared/entities/data-retention-logs.md index 326478e..f801a74 100644 --- a/docs/domains/_shared/entities/data-retention-logs.md +++ b/docs/domains/_shared/entities/data-retention-logs.md @@ -21,11 +21,13 @@ erDiagram ## Légende **Action types** : + - `check_inactive`: Vérification quotidienne comptes inactifs > 5 ans - `send_warnings`: Envoi notifications (90j/30j/7j avant suppression) - `delete_accounts`: Suppression effective comptes inactifs **Règles de conservation** : + - Auditeur : 5 ans inactivité → suppression - Créateur actif : jamais (tant que contenus écoutés) - Créateur inactif : 5 ans + 2 ans sans écoute → suppression diff --git a/docs/domains/_shared/entities/devices.md b/docs/domains/_shared/entities/devices.md index dcd8fd9..7f0a4d8 100644 --- a/docs/domains/_shared/entities/devices.md +++ b/docs/domains/_shared/entities/devices.md @@ -29,17 +29,20 @@ erDiagram ## Légende **Types d'appareil** : + - `mobile` : Smartphone Android/iOS - `tablet` : Tablette - `desktop` : Ordinateur - `car` : Système embarqué (CarPlay/Android Auto) **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 **Sécurité** : + - Détection automatique nouveau device → notification push + email - Localisation suspecte (pays différent) → alerte - Révocation individuelle ou globale possible diff --git a/docs/domains/_shared/entities/exports.md b/docs/domains/_shared/entities/exports.md index d446b0b..03f1918 100644 --- a/docs/domains/_shared/entities/exports.md +++ b/docs/domains/_shared/entities/exports.md @@ -25,11 +25,13 @@ erDiagram ## Légende **Formats d'export** : + - `json` : Machine-readable (données brutes) - `html` : Human-readable (page web stylée) - `zip` : Archive complète (JSON + HTML + audio files) **Contenu de l'export** : + - Profil utilisateur (email, pseudo, date inscription, bio) - Historique d'écoute (titres, dates, durées) - Contenus créés (audio + métadonnées) @@ -38,6 +40,7 @@ erDiagram - Historique consentements RGPD **Statuts** : + - `pending` : Demande en file d'attente - `generating` : Génération en cours (worker background) - `ready` : Export disponible au téléchargement @@ -45,6 +48,7 @@ erDiagram - `expired` : Export expiré (supprimé automatiquement) **Règles** : + - Génération asynchrone (worker background) - Délai max : **48h** (conformité RGPD) - Conservation : **7 jours** après génération diff --git a/docs/domains/_shared/entities/interest-gauges.md b/docs/domains/_shared/entities/interest-gauges.md index 8881ecc..d787d92 100644 --- a/docs/domains/_shared/entities/interest-gauges.md +++ b/docs/domains/_shared/entities/interest-gauges.md @@ -21,6 +21,7 @@ erDiagram ## Légende **Catégories** : + - `automobile` : Voitures, mécanique, course automobile - `travel` : Voyages, tourisme, découverte - `music` : Musique, concerts, artistes @@ -33,12 +34,14 @@ erDiagram - `nature` : Nature, randonnée, écologie **Score** : + - Échelle : **0-100** - Augmentation : +2% par like, +5% par abonnement créateur - Diminution : -1% par skip rapide (<30s), -5% par signalement - Calcul combiné : Distance GPS + matching intérêts **Algorithme recommandation** : + - **70% géolocalisation** : Proximité GPS - **30% centres d'intérêt** : Score jauges - Boost si créateur suivi : +0.3 au score final diff --git a/docs/domains/_shared/entities/location-history.md b/docs/domains/_shared/entities/location-history.md index 534fe55..ea19546 100644 --- a/docs/domains/_shared/entities/location-history.md +++ b/docs/domains/_shared/entities/location-history.md @@ -25,23 +25,27 @@ erDiagram ## Légende **Anonymisation progressive** : + - Données précises conservées **24h** (recommandation personnalisée) - Après 24h : conversion en **geohash précision 5** (~5km²) - Coordonnées originales supprimées définitivement - Job quotidien PostGIS automatique **Exceptions** : + - Historique personnel visible (liste trajets) : conservation intégrale tant que compte actif - Analytics globales : uniquement geohash anonyme - Suppression complète si suppression du compte **Contexte** : + - `listening` : Position pendant écoute de contenu - `search` : Position lors d'une recherche - `background` : Tracking en arrière-plan - `manual` : Position partagée manuellement **Conformité RGPD** : + - Vraie anonymisation (CNIL compliant) - Permet analytics agrégées (heatmaps trafic) - PostGIS natif, 0€ diff --git a/docs/domains/_shared/entities/parental-consents.md b/docs/domains/_shared/entities/parental-consents.md index e19e68e..7060919 100644 --- a/docs/domains/_shared/entities/parental-consents.md +++ b/docs/domains/_shared/entities/parental-consents.md @@ -43,6 +43,7 @@ erDiagram 4. Révocation possible → `revoked_at` renseigné **Restrictions par défaut (13-15 ans)** : + - `gps_enabled`: `false` (GeoIP uniquement) - `messaging_enabled`: `false` - `content_16plus_enabled`: `false` diff --git a/docs/domains/_shared/entities/privacy-policy-versions.md b/docs/domains/_shared/entities/privacy-policy-versions.md index 70f7a15..66d862c 100644 --- a/docs/domains/_shared/entities/privacy-policy-versions.md +++ b/docs/domains/_shared/entities/privacy-policy-versions.md @@ -32,10 +32,12 @@ erDiagram ## Légende **Versioning** : + - `major_change`: `true` → popup obligatoire pour tous les utilisateurs - `major_change`: `false` → notification simple - Fichier source : `docs/legal/politique-confidentialite.md` (versionné Git) **Popup si changement majeur** : + - Utilisateur doit accepter nouvelle version pour continuer - Refus → compte gelé (lecture seule) diff --git a/docs/domains/_shared/entities/reports.md b/docs/domains/_shared/entities/reports.md index eb6c23f..69875b1 100644 --- a/docs/domains/_shared/entities/reports.md +++ b/docs/domains/_shared/entities/reports.md @@ -29,6 +29,7 @@ erDiagram ## Légende **Catégories de signalement** : + - `spam` : Contenu publicitaire non sollicité - `hate_speech` : Discours haineux, discrimination - `violence` : Violence explicite @@ -39,6 +40,7 @@ erDiagram - `other` : Autre raison (commentaire obligatoire) **Statuts** : + - `pending` : En attente de revue - `under_review` : En cours d'examen par modérateur - `actioned` : Action prise (contenu retiré/édité) @@ -46,6 +48,7 @@ erDiagram - `duplicate` : Doublon d'un signalement existant **Actions possibles** : + - `content_removed` : Contenu supprimé - `content_edited` : Métadonnées modifiées (âge, tags) - `warning_sent` : Avertissement au créateur @@ -54,6 +57,7 @@ erDiagram - `no_action` : Aucune action (signalement infondé) **Workflow modération** : + - **3 premiers contenus** : Modération préalable obligatoire - **Après validation** : Modération a posteriori (signalements) - **Priorisation** : Nombre de signalements (>3 = urgent) diff --git a/docs/domains/_shared/entities/sessions.md b/docs/domains/_shared/entities/sessions.md index aaaae4a..db658bc 100644 --- a/docs/domains/_shared/entities/sessions.md +++ b/docs/domains/_shared/entities/sessions.md @@ -30,16 +30,19 @@ erDiagram ## Légende **Durées de vie** : + - Access token : **15 minutes** - Refresh token : **30 jours** (rotatif) - Inactivité : Déconnexion automatique après **30 jours** **Sécurité** : + - Tokens stockés en **SHA256** (jamais en clair) - Rotation automatique des refresh tokens - Détection replay attack **Multi-device** : + - Sessions simultanées **illimitées** - Révocation individuelle ou globale possible - Alertes si connexion depuis nouveau device ou pays différent diff --git a/docs/domains/_shared/entities/user-profile-history.md b/docs/domains/_shared/entities/user-profile-history.md index d2a4ff7..ee31af5 100644 --- a/docs/domains/_shared/entities/user-profile-history.md +++ b/docs/domains/_shared/entities/user-profile-history.md @@ -23,16 +23,19 @@ erDiagram ## Légende **Champs trackés** : + - `email`: Re-vérification requise - `username`: Limite 1 changement/30j - `bio`, `avatar_url`, `date_of_birth` **Change reasons** : + - `user_edit`: Modification self-service utilisateur - `admin_correction`: Correction par admin - `gdpr_request`: Suite demande RGPD formelle **Audit** : + - Historique complet conservé (preuve légale) - Accessible utilisateur : "Historique de mes modifications" - Accessible DPO : investigations diff --git a/docs/domains/_shared/rules/ANNEXE-POST-MVP.md b/docs/domains/_shared/rules/ANNEXE-POST-MVP.md index 2a63ad5..03b6435 100644 --- a/docs/domains/_shared/rules/ANNEXE-POST-MVP.md +++ b/docs/domains/_shared/rules/ANNEXE-POST-MVP.md @@ -19,6 +19,7 @@ ### Contexte du report **Raisons** : + - **Coût modération** : Classification manuelle humaine très coûteuse (~2000€/mois pour 1-2 modérateurs senior full-time) - **Risque juridique** : Accusations de biais éditorial, contentieux DSA - **Complexité technique** : Dashboard audit, logs 3 ans, alertes déséquilibre @@ -26,6 +27,7 @@ - **Pas essentiel MVP** : L'application fonctionne sans ce système **Version MVP** (actuelle) : + - Tag "Politique" simple (comme "Économie", "Sport") - Pas de classification gauche/droite - Pas d'équilibrage imposé @@ -36,6 +38,7 @@ ### Spécifications complètes (future implémentation) **Échelle de classification** (5 niveaux) : + - 🔴 **Extrême gauche** (anticapitalisme radical, révolution) - 🟠 **Gauche** (écologie, social, critique capitalisme modérée) - ⚪ **Centre/Neutre** (pas de positionnement politique clair) @@ -44,11 +47,13 @@ - 🟢 **Non politique** (enfants, musique, fiction, culture générale) **Qui classifie** : + - ❌ Pas de classification automatique IA (outil informatif uniquement, jamais décisionnaire) - ✅ Modérateurs senior après transcription - ✅ Créateur peut contester via processus d'appel **Affichage** : + - Badge politique visible : **au choix de l'utilisateur** (paramètre "Afficher orientation politique") - Par défaut : badges masqués (UX neutre) @@ -62,17 +67,20 @@ | **Masquer politique** | 0% gauche / 0% droite / 100% centre-neutre + non politique | Option apolitique | **Audit et conformité DSA** : + - Rapport hebdomadaire automatique : % gauche/droite/centre diffusé par utilisateur - Alerte si déséquilibre global plateforme (>55% d'un bord) - Logs conservés **3 ans** (exigence Digital Services Act EU) - Dashboard admin : visualisation répartition temps réel **Sanctions mauvaise classification** : + - Classification volontairement incorrecte = Strike 1 - Récidive = Strike 2 (suspension 7j) - Détection via signalements utilisateurs + audit modération **Justification** : + - **Conformité juridique DSA** (obligation neutralité plateforme EU) - Protection contre accusations de biais éditorial - Transparence auditable @@ -90,6 +98,7 @@ 5. Validation juridique du processus de classification **Chronologie estimée** : + - Phase 1 (Post-MVP+3 mois) : Validation demande utilisateurs via sondages - Phase 2 (Post-MVP+6 mois) : Recrutement modérateurs + développement dashboard - Phase 3 (Post-MVP+9 mois) : Tests bêta avec utilisateurs volontaires @@ -104,12 +113,14 @@ ### Contexte du report **Raisons** : + - **Complexité technique** : Intégration Lightning Network, gestion wallets crypto - **Réglementation** : Incertitude juridique crypto en EU (MiCA 2025) - **Focus MVP** : Priorité sur monétisation via abonnements Premium et publicités - **Adoption utilisateurs** : Nécessite éducation et adoption crypto préalables **Version MVP** (actuelle) : + - Monétisation créateurs via : - Partage revenus publicités (3€ CPM) - 70% revenus abonnements Premium @@ -128,6 +139,7 @@ 5. Conversion EUR/BTC automatique (optionnelle) **Avantages Lightning Network** : + - ✅ Frais quasi-nuls (<1%) vs 1.8% Mangopay - ✅ Transactions instantanées (<1 seconde) - ✅ Micropaiements possibles (dès 0.01€) @@ -135,12 +147,14 @@ - ✅ Pas d'intermédiaire (peer-to-peer) **Contraintes** : + - ❌ Adoption crypto limitée (2-5% population EU en 2026) - ❌ Volatilité BTC (nécessite conversion EUR immédiate) - ❌ UX complexe pour utilisateurs non-crypto - ❌ Réglementation MiCA en évolution **Alternatives étudiées** : + - Ko-fi / Buy Me a Coffee : simple mais frais 5% - PayPal/Stripe : frais 2.9% + 0.30€ (non viable pour micropaiements) - Mangopay : déjà utilisé, mais frais élevés pour petits montants @@ -157,6 +171,7 @@ 5. Demande créateurs confirmée via sondages **Chronologie estimée** : + - Phase 1 (Post-MVP+6 mois) : Étude de marché et demande utilisateurs - Phase 2 (Post-MVP+12 mois) : Développement intégration Lightning - Phase 3 (Post-MVP+15 mois) : Tests bêta avec créateurs volontaires @@ -171,6 +186,7 @@ ### Contexte du report **Raisons** : + - **Masse critique requise** : Nécessite pool suffisant d'utilisateurs simultanés (>500) pour matching rapide (<30s) - **Infrastructure WebRTC** : Coût serveurs TURN/STUN supplémentaire (~500€/mois pour 1000 utilisateurs actifs) - **Complexité modération** : Contenu live non enregistré = risques abus, nécessite système de confiance et signalement robuste @@ -178,6 +194,7 @@ - **UX conducteur** : Commandes vocales avancées nécessaires pour sécurité routière **Version MVP** (actuelle) : + - Radio live créateurs uniquement (1 vers N) - Pas de connexion P2P entre auditeurs - Chat textuel limité aux POIs et commentaires @@ -220,12 +237,14 @@ - Badge "En roulette" visible sur profil (transparence) **Avantages** : + - ✅ Sérendipité et découverte (esprit "Chatroulette audio") - ✅ Complémentarité conducteur/piéton (récit route vs récit urbain) - ✅ Fidèle concept RoadWave (usagers de la route connectés) - ✅ Réutilisation infrastructure WebRTC existante (radio live) **Contraintes** : + - ❌ Nécessite pool minimum 500 utilisateurs actifs simultanés - ❌ Modération temps réel complexe (contenu éphémère) - ❌ Coût infrastructure TURN/STUN significatif @@ -233,10 +252,12 @@ - ❌ Commandes vocales avancées requises pour conducteurs **Monétisation** : + - Gratuit avec limitation : 3 sessions/jour de 5 min - Premium : sessions illimitées + matching prioritaire (moins d'attente) **Aspects légaux** : + - Âge minimum : 18 ans pour accès roulette - Charte d'utilisation spécifique (respect, pas de contenu sexuel/violent, pas de sollicitation commerciale) - Anonymat relatif : pseudo + ville visible, pas de photo @@ -254,12 +275,14 @@ 6. Commandes vocales avancées implémentées pour conducteurs **Chronologie estimée** : + - Phase 1 (Post-MVP+3 mois) : Validation demande utilisateurs via sondages, analyse concurrence (Clubhouse, Twitter Spaces) - Phase 2 (Post-MVP+6 mois) : Développement matchmaking + WebRTC P2P renforcé - Phase 3 (Post-MVP+9 mois) : Tests bêta avec 100 utilisateurs volontaires - Phase 4 (Post-MVP+12 mois) : Déploiement progressif si KPI positifs (>70% satisfaction, <5% signalements) **KPI de succès** : + - Temps moyen d'attente matching : <30 secondes - Taux satisfaction post-session : >70% - Taux signalement : <5% @@ -275,12 +298,14 @@ ### Contexte du report **Raisons** : + - **Coût SMS** : ~0.04€/SMS en France via Brevo (400€/mois pour 10K inscriptions) - **Complexité UX** : Étape supplémentaire à l'inscription (friction) - **Focus MVP** : Priorité sur l'expérience utilisateur fluide - **Modération suffisante** : Système de strikes et signalements couvre les cas d'abus initiaux **Version MVP** (actuelle) : + - Inscription par email uniquement (via Zitadel) - Confirmation email obligatoire - Détection basique emails jetables (liste noire publique) @@ -321,28 +346,33 @@ - Au-delà → signalement automatique modération **Affichage** : + - Badge "Vérifié ✓" visible sur profil créateur - Non obligatoire pour auditeurs simples (seulement créateurs) - Option "Vérifier mon compte" dans paramètres **Règles de diffusion** : + - Contenus créateurs non-vérifiés : portée limitée à 10 km pendant 30 premiers jours - Après 30 jours sans signalement : levée restriction - Créateurs vérifiés : aucune restriction **Avantages** : + - ✅ Réduction spam et comptes multiples - ✅ Amélioration confiance plateforme - ✅ Conformité anti-fraude (KYC léger) - ✅ Réutilisation infrastructure Brevo (emails + SMS) **Contraintes** : + - ❌ Coût SMS : ~400€/mois pour 10K inscriptions/mois - ❌ Friction UX (étape supplémentaire) - ❌ Numéros virtuels (Twilio, etc.) contournent vérification - ❌ Certains utilisateurs réticents (vie privée) **Alternatives étudiées** : + - **Captcha reCAPTCHA v3** : efficace mais contournable, pas de coût - **Email reputation API** : ~0.01€/vérification (kickbox.io) - **Vérification bancaire** : trop contraignant pour MVP @@ -359,12 +389,14 @@ 5. Conformité RGPD : consentement stockage numéro mobile **Chronologie estimée** : + - Phase 1 (Post-MVP+3 mois) : Analyse taux spam/abus, validation besoin - Phase 2 (Post-MVP+4 mois) : Développement détection emails temporaires + API Brevo SMS - Phase 3 (Post-MVP+5 mois) : Tests bêta avec créateurs volontaires - Phase 4 (Post-MVP+6 mois) : Déploiement progressif selon catégorie utilisateur (créateurs en priorité) **KPI de succès** : + - Réduction comptes spam : >50% - Taux vérification volontaire (créateurs) : >70% - Friction UX acceptable : taux abandon inscription <10% @@ -379,6 +411,7 @@ ### Contexte du report **Raisons** : + - **Complexité technique** : Intégration API TTS (Text-to-Speech), OCR pour PDF scannés, parsing multi-formats - **Coût infrastructure** : ~0.016€/1000 caractères (Google Cloud TTS) = ~1.60€ par livre moyen (100K caractères) - **Conformité droits d'auteur** : Risque juridique si conversion de contenus protégés sans licence @@ -386,6 +419,7 @@ - **Usage limité** : Cas d'usage minoritaire vs contenu audio créé par la communauté **Version MVP** (actuelle) : + - Contenu audio uniquement créé par les créateurs - Pas de conversion automatique document → audio - Utilisateurs doivent uploader directement fichiers audio @@ -452,12 +486,14 @@ | **Allemand** | Anna, Max | Google Cloud TTS WaveNet | **Avantages** : + - ✅ Différenciation Premium forte (feature exclusive) - ✅ Fidélisation utilisateurs (consommation contenu personnel) - ✅ Réutilisation infrastructure audio existante (HLS, NGINX Cache) - ✅ Cas d'usage trajets longs (livres, articles longs) **Contraintes** : + - ❌ Coût TTS : ~1.60€/livre moyen (Google Cloud TTS WaveNet) - ❌ Coût stockage : ~0.01€/GB/mois (temporaire 90 jours) - ❌ Risque juridique : conversion contenus protégés (livres, articles premium) @@ -502,12 +538,14 @@ 5. Infrastructure existante stable (HLS, CDN, backend Go) **Chronologie estimée** : + - Phase 1 (Post-MVP+6 mois) : Étude de marché, sondage utilisateurs Premium, validation juridique - Phase 2 (Post-MVP+9 mois) : Développement MVP TTS (PDF texte uniquement, FR/EN) - Phase 3 (Post-MVP+10 mois) : Tests bêta avec 100 utilisateurs Premium volontaires - Phase 4 (Post-MVP+12 mois) : Déploiement progressif si KPI positifs + ajout formats (EPUB, OCR) **KPI de succès** : + - Adoption feature : >30% utilisateurs Premium l'utilisent au moins 1 fois/mois - Satisfaction : >75% note positive (4-5/5) - Rétention Premium : augmentation >10% grâce à cette feature @@ -525,6 +563,7 @@ | **Total** | **~650€/mois** | **Rentabilité** : + - Revenus Premium 1000 users : 4990€/mois (4.99€/mois × 1000) - Coût TTS : 650€/mois (13% revenus) - Marge après TTS : 4340€/mois (87%) @@ -539,6 +578,7 @@ ### Contexte du report **Raisons** : + - **Couverture limitée** : ~30-40% du parc automobile EU en 2026 (CarPlay/Android Auto) - **Complexité technique** : Intégration Siri Intents (iOS) + Google Actions (Android) - **Modération vocale** : Signalements vocaux nécessitent enregistrement + transcription audio @@ -546,6 +586,7 @@ - **Accessibilité secondaire** : Like automatique couvre déjà engagement conducteurs **Version MVP** (actuelle) : + - ❌ Pas de commandes vocales - ✅ Like automatique basé sur temps d'écoute (en voiture) - ✅ Actions manuelles disponibles seulement en mode piéton @@ -591,6 +632,7 @@ **Implémentation technique** : **iOS** : + - Siri Intents (framework iOS 12+) - Clés Intent à ajouter dans `Info.plist` : ```xml @@ -602,25 +644,30 @@ ``` + - Paramètres vocaux : détection "like", "abonne", "signale" **Android** : + - Google Actions on Google Assistant (via assistant voice queries) - Intégration avec Android App Actions - Paremeters: Intent extras pour passer contenu actuel - Fallback : repérer contenu par titre + créateur **Limitation importante** : + - ⚠️ **CarPlay/Android Auto requis** : Fonctionalité non disponible sur interface mobile - ⚠️ **Reconnaissance vocale réseau** : Nécessite connexion data - ⚠️ **Latence acceptable** : <2 secondes entre commande et confirmation **UX - Feedback utilisateur** : + - Siri : "✓ J'ai ajouté ce contenu à vos favoris" - Google Assistant : "✓ Vous êtes maintenant abonné à [Créateur]" - Confirmation audio pour signalement : "Signalement envoyé. Catégorie : Spam" **Signalements vocaux** : + - Enregistrement automatique de la voix (tampon 30 secondes) - Transcription audio → texte (via Google Cloud Speech ou similaire) - Catégorie pré-remplie selon réponse vocale ("Spam" → catégorie Spam) @@ -638,12 +685,14 @@ 5. Système de confiance utilisateur en place (éviter abus signalements) **Chronologie estimée** : + - Phase 1 (Post-MVP+2 mois) : Validation demande utilisateurs (CarPlay/Android Auto) - Phase 2 (Post-MVP+4 mois) : Développement Siri Intents + Google Actions - Phase 3 (Post-MVP+6 mois) : Tests bêta avec conducteurs volontaires - Phase 4 (Post-MVP+8 mois) : Déploiement progressif si KPI positifs **KPI de succès** : + - Adoption commandes vocales : >30% utilisateurs CarPlay/Android Auto - Taux erreur reconnaissance vocale : <10% - Satisfaction utilisateurs : >75% (4-5/5) @@ -667,6 +716,7 @@ ### Contexte du report **Raisons** : + - **Masse critique requise** : Partenariats avec organismes officiels nécessitent base utilisateurs solide (>50K MAU) - **Complexité technique** : Intégration APIs externes, système de priorités, TTS automatisé - **Responsabilité légale** : Diffusion alertes sécurité = engagement fort, nécessite infrastructure stable @@ -674,6 +724,7 @@ - **ROI incertain** : Valeur ajoutée forte mais sans revenus directs (service public) **Version MVP** (actuelle) : + - Tous contenus = créateurs classiques - Pas de système de priorité - Pas de comptes officiels vérifiés @@ -696,6 +747,7 @@ | **Compte Officiel** | Validation RoadWave manuelle + contrat partenariat | 🏛️ | **Configurable (0-3)** | **Aucune** | **Exemples comptes officiels** : + - **Gestionnaires autoroutes** : SANEF, Vinci Autoroutes, APRR, ASF - **Services météo** : Météo France, vigilance.gouv.fr - **Sécurité civile** : Préfectures, Plan alerte enlèvement @@ -796,6 +848,7 @@ Podcast reprend automatiquement à position exacte ``` **Paramètres techniques** : + - **Rayon déclenchement** : 500m-2km selon vitesse (calcul dynamique) - **Son d'alerte** : Bip distinctif (pas agressif, mais audible) - **Durée max alerte** : 30 secondes (format court, info essentielle) @@ -803,6 +856,7 @@ Podcast reprend automatiquement à position exacte - **Annulation** : bouton "Ignorer" disponible pendant countdown (mais déconseillé) **Traçabilité** : + - Log : `user_id`, `alert_id`, `action` (played / ignored), `timestamp` - Statistiques : taux d'écoute alertes vs taux ignore (KPI efficacité) @@ -855,12 +909,14 @@ Podcast reprend automatiquement à position exacte ``` **TTS (Text-to-Speech)** : + - **Fournisseur** : Google Cloud TTS WaveNet (voix neurale professionnelle) - **Coût** : ~0.016€/1000 caractères - **Voix** : "Léa" (féminine, française, ton calme mais ferme pour alertes) - **Normalisation audio** : -14 LUFS (comme autres contenus) **Expiration automatique** : + - Alertes météo : 12h après fin vigilance - Obstacles autoroute : 2h après signalement (si non mis à jour) - Alertes enlèvement : 48h ou jusqu'à résolution officielle @@ -909,6 +965,7 @@ Podcast reprend automatiquement à position exacte ``` **Création alerte manuelle** : + - Use case : information non automatisée (événement exceptionnel) - Champs : Texte (TTS auto), Zone (carte), Priorité (1-3), Durée vie - Validation admin RoadWave requise (pas auto-publication) @@ -943,6 +1000,7 @@ Podcast reprend automatiquement à position exacte 5. Tests A/B réussis sur interruption priorité 3 (acceptabilité utilisateurs) **Chronologie estimée** : + - Phase 1 (Post-MVP+6 mois) : Développement système priorités + dashboard admin + TTS - Phase 2 (Post-MVP+9 mois) : Premier partenariat (Météo France, API publique simple) - Phase 3 (Post-MVP+12 mois) : Tests bêta alertes météo avec utilisateurs volontaires @@ -950,6 +1008,7 @@ Podcast reprend automatiquement à position exacte - Phase 5 (Post-MVP+18 mois) : Déploiement complet si KPI positifs **KPI de succès** : + - Taux écoute alertes priorité 3 : >95% (faible taux ignore) - Satisfaction utilisateurs : >80% jugent alertes utiles (sondage post-alerte) - Taux faux positifs : <2% (alerte diffusée à tort ou obsolète) @@ -968,6 +1027,7 @@ Podcast reprend automatiquement à position exacte | **Total** | **~255€/mois** | **ROI** : + - Pas de revenus directs (service public) - Valeur indirecte : **différenciation produit majeure** - Argument commercial : "RoadWave vous protège en temps réel" diff --git a/docs/domains/_shared/rules/authentification.md b/docs/domains/_shared/rules/authentification.md index 8d2b605..86db5fc 100644 --- a/docs/domains/_shared/rules/authentification.md +++ b/docs/domains/_shared/rules/authentification.md @@ -10,11 +10,13 @@ - ✅ 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é) @@ -35,11 +37,13 @@ | **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) @@ -47,11 +51,13 @@ #### 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 @@ -61,22 +67,26 @@ ### 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) @@ -88,22 +98,26 @@ **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 @@ -113,17 +127,20 @@ ### 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) @@ -135,16 +152,19 @@ **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€) @@ -154,16 +174,19 @@ ### 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€) @@ -173,19 +196,23 @@ ### 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 @@ -197,15 +224,18 @@ **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 @@ -224,13 +254,16 @@ 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 diff --git a/docs/domains/_shared/rules/gestion-erreurs.md b/docs/domains/_shared/rules/gestion-erreurs.md index 961bba7..bf49f86 100644 --- a/docs/domains/_shared/rules/gestion-erreurs.md +++ b/docs/domains/_shared/rules/gestion-erreurs.md @@ -23,6 +23,7 @@ | **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 @@ -44,10 +45,12 @@ ``` **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 @@ -67,30 +70,36 @@ **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 @@ -113,19 +122,23 @@ | **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) diff --git a/docs/domains/_shared/rules/rgpd.md b/docs/domains/_shared/rules/rgpd.md index f1d8e9b..c45d9cb 100644 --- a/docs/domains/_shared/rules/rgpd.md +++ b/docs/domains/_shared/rules/rgpd.md @@ -5,21 +5,25 @@ **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 @@ -37,10 +41,12 @@ 4. Job quotidien automatique via cron **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€ @@ -54,6 +60,7 @@ **Format export** : Archive ZIP contenant JSON (machine-readable), HTML (human-readable), fichiers audio, README **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) @@ -68,9 +75,11 @@ 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 @@ -89,6 +98,7 @@ 5. Après 30j sans annulation : suppression effective **Suppression effective** : + - ✅ Compte utilisateur supprimé (données personnelles) - ✅ Historique d'écoute supprimé - ✅ GPS historique supprimé @@ -97,11 +107,13 @@ - ⚠️ 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 @@ -121,16 +133,19 @@ | **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) @@ -150,15 +165,18 @@ | **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 @@ -178,17 +196,20 @@ | `_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 @@ -200,10 +221,12 @@ **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) @@ -212,14 +235,17 @@ - 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€ @@ -240,6 +266,7 @@ | 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 @@ -248,10 +275,12 @@ 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 @@ -263,25 +292,30 @@ **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é @@ -293,6 +327,7 @@ **Décision** : Interface self-service + validation immédiate **Données rectifiables** : + - Email (avec re-vérification) - Pseudo (unique, disponibilité vérifiée) - Bio / description @@ -300,11 +335,13 @@ - Photo de profil **Processus** : + - Changements immédiats (sauf email) - Email : lien vérification → validation sous 24h - Historique modifications conservé (audit trail) **Limitations** : + - Pseudo : max 1 changement/30j (anti-squat) **Justification** : Conformité Article 16 RGPD, self-service 0€ @@ -323,6 +360,7 @@ | **Recommandations personnalisées** | "Mode anonyme" | Reco génériques uniquement | **Mode anonyme** : + - Désactive algorithme (jauges ignorées) - Recommandations = top contenus zone géo uniquement - Historique non utilisé @@ -336,6 +374,7 @@ **Décision** : "Geler mon compte" temporaire **Effets** : + - Compte gelé, contenus cachés, profil invisible - Connexion lecture seule OK - Réactivation à tout moment @@ -349,6 +388,7 @@ **Décision** : Page web + popup in-app + versioning Git **Emplacement** : + - Web : `roadwave.fr/confidentialite` - App : page dédiée paramètres - Popup première connexion (scroll requis) @@ -450,6 +490,7 @@ 4. Validation parent → compte ado activé avec restrictions **Restrictions 13-15 ans** : + - ✅ Écoute contenus autorisés - ✅ Création contenus (modération renforcée) - ⚠️ GPS précis : consentement parental explicite requis @@ -458,6 +499,7 @@ - ⚠️ Profil public limité (pas d'affichage ville précise) **Contrôles parentaux** : + - Dashboard parent : `roadwave.fr/parent/[child_id]` - Visualisation historique écoute - Activation/désactivation GPS précis @@ -466,6 +508,7 @@ - Notification hebdomadaire activité **Vérification légère identité parent** : + - Email parent ≠ email ado (vérification domaine) - Lien expiration 7 jours - Pas de vérification identité forte (MVP) @@ -475,6 +518,7 @@ **App dédiée** : Version séparée avec contrôles renforcés **Caractéristiques** : + - ❌ Pas de GPS précis (GeoIP ville uniquement) - ❌ Pas de création contenu - ❌ Pas de profil public @@ -484,6 +528,7 @@ - ✅ Contrôle parental obligatoire **Contenus autorisés** : + - Contes audio enfants - Guides touristiques famille - Podcasts éducatifs labellisés @@ -496,17 +541,20 @@ 4. Pas de compte autonome enfant **Modération** : + - 100% contenus présélectionnés par équipe éditoriale - Aucun UGC accessible - Whitelist créateurs vérifiés uniquement **Justification** : + - Conformité Article 8 RGPD (13-16 ans selon pays) - 13 ans France = seuil légal avec consentement parental - App Kids = protection renforcée < 13 ans - Alignement marché (YouTube 13+, YouTube Kids) **Roadmap** : + - **MVP** : App principale 16+ uniquement (simplicité) - **Phase 2** : Workflow 13-15 ans + consentement parental - **Phase 3** : RoadWave Kids (app séparée) @@ -537,6 +585,7 @@ **Décision** : DPIA obligatoire (GPS + profilage grande échelle) **Raisons** : + - Traitement grande échelle données GPS sensibles - Profilage automatisé recommandations - Surveillance zones publiques diff --git a/docs/domains/_shared/sequences/anonymisation-gps.md b/docs/domains/_shared/sequences/anonymisation-gps.md index f81fd42..0a4b835 100644 --- a/docs/domains/_shared/sequences/anonymisation-gps.md +++ b/docs/domains/_shared/sequences/anonymisation-gps.md @@ -49,6 +49,7 @@ sequenceDiagram ``` **Légende** : + - **< 24h** : GPS précis conservé (recommandations hyperlocales) - **> 24h** : Conversion automatique en geohash précision 5 (~5km²) - **Exception** : Historique personnel conservé intact tant que compte actif diff --git a/docs/domains/_shared/sequences/authentification.md b/docs/domains/_shared/sequences/authentification.md index 218f633..f90d093 100644 --- a/docs/domains/_shared/sequences/authentification.md +++ b/docs/domains/_shared/sequences/authentification.md @@ -29,14 +29,17 @@ sequenceDiagram ## Légende **Acteurs** : + - Zitadel : Gère l'authentification OAuth2/OIDC - Backend API : Valide les tokens et accède aux données **Tokens** : + - Access token : 15 min (JWT), utilisé pour chaque requête API - Refresh token : 30 jours, permet renouvellement access token **Sécurité** : + - Tokens stockés hashés (SHA256) en DB - Device fingerprinting (OS, navigateur, IP) - Notification si nouveau device diff --git a/docs/domains/_shared/sequences/consentement-parental.md b/docs/domains/_shared/sequences/consentement-parental.md index 73abf72..a0f5dc0 100644 --- a/docs/domains/_shared/sequences/consentement-parental.md +++ b/docs/domains/_shared/sequences/consentement-parental.md @@ -38,6 +38,7 @@ sequenceDiagram ``` **Légende** : + - Délai expiration lien : 7 jours - Restrictions 13-15 ans : GPS précis, messagerie, contenus +16 (configurables par parent) - Dashboard parent : `roadwave.fr/parent/[child_id]` diff --git a/docs/domains/_shared/sequences/export-donnees.md b/docs/domains/_shared/sequences/export-donnees.md index b985382..b042834 100644 --- a/docs/domains/_shared/sequences/export-donnees.md +++ b/docs/domains/_shared/sequences/export-donnees.md @@ -59,6 +59,7 @@ sequenceDiagram ``` **Légende** : + - Limite : 1 export / 30 jours (anti-abus) - Délai génération : 48h maximum (conformité RGPD Article 20) - Expiration lien : 7 jours diff --git a/docs/domains/_shared/sequences/notification-breach.md b/docs/domains/_shared/sequences/notification-breach.md index f314542..5a30b1d 100644 --- a/docs/domains/_shared/sequences/notification-breach.md +++ b/docs/domains/_shared/sequences/notification-breach.md @@ -56,6 +56,7 @@ sequenceDiagram ``` **Légende** : + - **H+0 à H+24** : Détection, confinement, évaluation périmètre - **H+24 à H+48** : Évaluation gravité, préparation rapport - **H+48 à H+72** : Notification CNIL (si risque) + utilisateurs (si risque élevé) diff --git a/docs/domains/_shared/sequences/refresh-token.md b/docs/domains/_shared/sequences/refresh-token.md index 6ac3585..fb0d77d 100644 --- a/docs/domains/_shared/sequences/refresh-token.md +++ b/docs/domains/_shared/sequences/refresh-token.md @@ -29,10 +29,12 @@ sequenceDiagram ## Légende **Rotation** : + - Nouveau refresh_token à chaque refresh - Ancien token invalidé immédiatement - Prévient replay attack **Sécurité** : + - Si ancien token réutilisé → révocation globale - Logs sécurité + notification utilisateur diff --git a/docs/domains/_shared/sequences/suppression-compte.md b/docs/domains/_shared/sequences/suppression-compte.md index f6f564c..d213e4a 100644 --- a/docs/domains/_shared/sequences/suppression-compte.md +++ b/docs/domains/_shared/sequences/suppression-compte.md @@ -46,6 +46,7 @@ sequenceDiagram ``` **Légende** : + - Grace period : 30 jours - Pendant grace period : compte inaccessible, contenus cachés - Après 30j : suppression définitive, contenus anonymisés conservés diff --git a/docs/domains/_shared/states/account-deletion-lifecycle.md b/docs/domains/_shared/states/account-deletion-lifecycle.md index 1e67431..bbb4092 100644 --- a/docs/domains/_shared/states/account-deletion-lifecycle.md +++ b/docs/domains/_shared/states/account-deletion-lifecycle.md @@ -30,12 +30,14 @@ stateDiagram-v2 **Grace period** : 30 jours **Pendant grace period** : + - Compte désactivé (login impossible) - Contenus cachés (non diffusés) - Sessions/tokens révoqués - Email avec token annulation (valide 30j) **Après 30j** : + - Données personnelles supprimées - Contenus créés anonymisés (créateur = "Utilisateur supprimé") - Historique GPS/écoute supprimé diff --git a/docs/domains/_shared/states/compte-utilisateur.md b/docs/domains/_shared/states/compte-utilisateur.md index 5e9833f..d688705 100644 --- a/docs/domains/_shared/states/compte-utilisateur.md +++ b/docs/domains/_shared/states/compte-utilisateur.md @@ -47,6 +47,7 @@ stateDiagram-v2 | Deleted | `deleted` | Données supprimées, contenus anonymisés, irréversible | **Restrictions Active Minor** : + - GPS précis : configurable par parent - Messagerie privée : désactivée par défaut - Contenus +16 : filtrés diff --git a/docs/domains/_shared/states/suppression-compte.md b/docs/domains/_shared/states/suppression-compte.md index 1e67431..bbb4092 100644 --- a/docs/domains/_shared/states/suppression-compte.md +++ b/docs/domains/_shared/states/suppression-compte.md @@ -30,12 +30,14 @@ stateDiagram-v2 **Grace period** : 30 jours **Pendant grace period** : + - Compte désactivé (login impossible) - Contenus cachés (non diffusés) - Sessions/tokens révoqués - Email avec token annulation (valide 30j) **Après 30j** : + - Données personnelles supprimées - Contenus créés anonymisés (créateur = "Utilisateur supprimé") - Historique GPS/écoute supprimé diff --git a/docs/domains/advertising/README.md b/docs/domains/advertising/README.md index f82b462..5027076 100644 --- a/docs/domains/advertising/README.md +++ b/docs/domains/advertising/README.md @@ -22,6 +22,7 @@ Le domaine **Advertising** gère la diffusion de publicités audio ciblées. C'e ## Ubiquitous Language **Termes métier du domaine** : + - **Ad Campaign** : Campagne publicitaire avec budget et durée - **Ad Impression** : Affichage/lecture d'une publicité - **Ad Targeting** : Critères de ciblage (geo + intérêts) diff --git a/docs/domains/advertising/rules/publicites.md b/docs/domains/advertising/rules/publicites.md index 54e1cb3..8af09eb 100644 --- a/docs/domains/advertising/rules/publicites.md +++ b/docs/domains/advertising/rules/publicites.md @@ -63,6 +63,7 @@ if (campaign.hours.includes(userHour)) { **Règle 2 : Ciblage "France" = Métropole + DOM** **France entière inclut** : + - France métropolitaine (96 départements) - Guadeloupe (971) - Martinique (972) @@ -71,6 +72,7 @@ if (campaign.hours.includes(userHour)) { - Mayotte (976) **Publicitaire peut affiner** : + - "Région Provence-Alpes-Côte d'Azur" → Métropole uniquement - "Département 971" → Guadeloupe uniquement - "Ville Pointe-à-Pitre" → Guadeloupe uniquement @@ -102,6 +104,7 @@ if (campaign.hours.includes(userHour)) { ``` Restaurant à Pointe-à-Pitre Campagne : + - Zone : Guadeloupe (département 971) - Horaires : 12h-14h (rush déjeuner) @@ -114,6 +117,7 @@ User Martinique à 12h30 locale → ❌ Pas diffusion (hors zone géo) ``` Assureur national Campagne : + - Zone : France (nationale) - Horaires : 7h-9h + 17h-19h @@ -136,6 +140,7 @@ Filtrage pubs : ``` **Justification** : + - ✅ **UX intuitive pour publicitaires** : "7h-9h" = matin partout (pas besoin comprendre UTC) - ✅ **Équité géographique** : pas de discrimination DOM-TOM, publicitaires locaux peuvent cibler local, campagnes nationales touchent tous Français - ✅ **Simplicité technique** : détection fuseau automatique (GPS ou device), PostgreSQL `AT TIME ZONE` pour calculs backend @@ -144,6 +149,7 @@ Filtrage pubs : **Étalement budget** : ``` Exemple campagne : + - Budget : 300€ - Durée : 14 jours - Zone : Département du Var @@ -156,6 +162,7 @@ Calcul automatique : ``` **Mode de paiement** : + - ✅ Prépaiement obligatoire (évite impayés) - ✅ Carte bancaire uniquement (Mangopay) - ✅ Recharge automatique optionnelle (si budget <10%) @@ -171,6 +178,7 @@ Calcul automatique : 4. Si refusé → email avec raison + remboursement automatique **Contenus interdits en pub** : + - ❌ Alcool, tabac (réglementation française) - ❌ Jeux d'argent - ❌ Contenu politique (pendant campagnes électorales) @@ -194,11 +202,13 @@ Calcul automatique : | **Répartition horaire** | Graphique par heure | Optimisation horaires | **Métriques engagement avancées** : + - **Taux complétion par tranche d'âge** : identifier audience réceptive - **Carte de chaleur GPS** : visualiser zones forte écoute - **Comparatif campagnes** : A/B testing créatifs publicitaires **Export données** : + - ✅ CSV/Excel pour analyse externe - ✅ Graphiques interactifs (Chart.js) - ✅ Rapport PDF automatique fin de campagne @@ -206,6 +216,7 @@ Calcul automatique : #### Gestion budget et alertes **Suivi temps réel** : + - Dashboard : Budget restant, % consommé, jours restants - Projection : "À ce rythme, budget épuisé dans X jours" - Alerte email/push si : @@ -215,6 +226,7 @@ Calcul automatique : - Campagne terminée (rapport final) **Ajustements en cours** : + - ✅ Pause campagne (budget conservé) - ✅ Prolonger campagne (recharge budget) - ✅ Modifier ciblage horaire/géo (si <50% budget consommé) @@ -223,12 +235,14 @@ Calcul automatique : #### Système d'enchères (post-MVP) **Optionnel future** : + - Enchère au CPM (coût pour 1000 impressions) - Priorité selon prix : pub prix élevé → diffusion privilégiée - Floor price : 2€ CPM minimum - Évite surcharge pub : max 1 pub / 5 contenus stricte **Justification décision MVP** : + - Tarif fixe simple : 0.05€/écoute complète - Pas de complexité enchères immédiatement - Scalable : passage enchères ultérieur si demande forte @@ -240,22 +254,26 @@ Calcul automatique : **Décision** : Paramétrable admin + respect expérience utilisateur **Fréquence d'insertion** : + - **Défaut : 1 pub / 5 contenus** (utilisateurs gratuits) - **Paramétrable admin** : curseur 1/3 à 1/10 - **Utilisateurs Premium** : 0 pub (modèle sans publicité) **Règles strictes** : + - ⚠️ **Jamais d'interruption** contenu en cours - Pub s'insère uniquement **entre deux contenus** (pendant délai 2s) - Rotation : même pub max **3 fois/jour** par utilisateur (évite saturation) - Limite : max **6 pubs/heure** par utilisateur (évite spam) **Ciblage intelligent** : + - Géolocalisation prioritaire (point GPS > ville > département > région > national) - Centres d'intérêt secondaires (tags utilisateur) - Horaire (campagne 7h-9h → diffusion uniquement pendant plage **heure locale utilisateur**, voir section 6.1 pour détails fuseaux horaires et DOM-TOM) **Volume audio normalisé** : + - Pub normalisée à **-14 LUFS** (standard broadcast) - Évite effet "pub trop forte" (frustration utilisateur) - Validation automatique via FFmpeg lors encodage @@ -265,21 +283,25 @@ Calcul automatique : ### 6.3 Caractéristiques publicités **Durée** : + - Minimum : **10 secondes** - Maximum : **60 secondes** - Recommandé : **15-30 secondes** (sweet spot engagement) **Skippable** : + - Délai minimum obligatoire : **5 secondes** (paramétrable admin : 3-10s) - Bouton "Passer la publicité" apparaît après délai - Durée minimale comptabilisée pour facturation **Facturation** : + - **Écoute complète** (>80%) : 0.05€ facturé publicitaire - **Skip après délai min** : 0.02€ (exposition partielle) - **Skip immédiat** (<5s) : 0€ (pas d'engagement) **Justification modèle tarif** : + - Incitatif qualité : pub engageante = coût réduit - Équitable : publicitaire paie pour attention réelle - Transparent : dashboard montre écoutes complètes vs skips diff --git a/docs/domains/content/README.md b/docs/domains/content/README.md index dd8f0a5..09c61f8 100644 --- a/docs/domains/content/README.md +++ b/docs/domains/content/README.md @@ -28,6 +28,7 @@ Le domaine **Content** gère toute la création, publication et diffusion des co ## Ubiquitous Language **Termes métier du domaine** : + - **Audio Guide** : Contenu structuré en séquences géolocalisées - **Guide Sequence** : Segment d'un audio-guide déclenché à un point GPS précis - **Live Stream** : Diffusion audio en temps réel diff --git a/docs/domains/content/rules/audio-guides.md b/docs/domains/content/rules/audio-guides.md index 03da311..84addf1 100644 --- a/docs/domains/content/rules/audio-guides.md +++ b/docs/domains/content/rules/audio-guides.md @@ -14,11 +14,13 @@ | **🚌 Transport** | Variable | Auto GPS + Manuel possible | Bus touristiques, trains panoramiques | **Détection automatique** : + - Vitesse moyenne calculée sur 30 secondes - Suggestion mode au démarrage : "Détection : 🚗 Voiture. Est-ce correct ? [Oui] [Changer]" - User peut forcer mode manuellement (settings) **Justification** : + - Flexibilité maximale créateurs et utilisateurs - Expériences optimisées par type de déplacement - Gestion cas limites (vélo lent vs piéton rapide) @@ -93,12 +95,14 @@ | **Zone diffusion** | ✅ | Polygon géographique | **Wizard de création** : + - Étape 1 : Infos générales (titre, description, mode) - Étape 2 : Ajout séquences une par une - Étape 3 : Preview carte (trace + points) - Étape 4 : Validation modération (3 premiers audio-guides) **Justification** : + - Contrôle total créateur sur expérience - Carte preview aide visualiser parcours - Wizard guidé = réduction friction création @@ -133,10 +137,12 @@ Séquence 1 [fin] → PAUSE → User clique → Séquence 2 [fin] → PUB AUTO-P ``` **Fréquence pub** : + - Gratuits : 1 pub toutes les 5 séquences (paramétrable admin 1/3 à 1/10) - Premium : 0 pub **Justification** : + - Pub s'insère naturellement (pas d'attente utilisateur pour déclencher) - User garde contrôle rythme visite (pause après pub) - Monétisation effective créateurs @@ -199,15 +205,18 @@ Séquence 1 [fin] → PAUSE → User clique → Séquence 2 [fin] → PUB AUTO-P ``` **Navigation libre** : + - User peut sauter séquences déjà connues - User peut revenir en arrière à tout moment - User peut aller directement à séquence 8 (même si 4-7 non écoutées) **Sauvegarde progression** : + - Checkmarks ✅ sur séquences écoutées >80% - Position exacte sauvegardée dans séquence en cours **Justification** : + - Utilisateur contrôle 100% son rythme - Adapté musées : visitor peut voir physiquement une œuvre lointaine et vouloir écouter sa description - Pas de frustration (liberté totale) @@ -241,6 +250,7 @@ Séquence 1 [fin] → PAUSE → User clique → Séquence 2 [fin] → PUB AUTO-P 8. Séquence suivante démarre immédiatement (pas de décompte) **Pas de système "7 secondes avant" pour les audio-guides** : + - Contrairement aux contenus géolocalisés simples (voir [../../recommendation/rules/interactions-navigation.md](../../recommendation/rules/interactions-navigation.md#511-file-dattente-et-commande-suivant)) - Les séquences se déclenchent **au point GPS exact** (rayon 30m) - Raison : expérience guidée continue, user sait qu'il suit un parcours @@ -268,6 +278,7 @@ Séquence 1 [fin] → PAUSE → User clique → Séquence 2 [fin] → PUB AUTO-P - Si vitesse **>10 km/h** ET user clique bouton (Suivant/Précédent) : - Toast 3 secondes : "⚠️ Manipulation en conduite détectée. Pour votre sécurité, demandez à un passager." - **Action quand même exécutée** (pas de blocage) + - Justification : sensibilisation sans bloquer (passager peut légitimement manipuler) **Schéma flux** : @@ -278,6 +289,7 @@ Point GPS 1 (30m) → Séquence 1 AUTO → User roule → Distance affichée → ``` **Justification** : + - Flexibilité maximale : GPS optimise expérience MAIS user garde contrôle - Gestion cas limites : routes fermées, détours, embouteillages - Sécurité : warning sensibilise sans bloquer (passager légitime) @@ -361,12 +373,14 @@ Quand une séquence se termine et qu'il reste un point GPS suivant, l'interface ``` **Progress bar dynamique** : + - Se remplit au fur et à mesure qu'on se rapproche du point - Calcul : `progress = 100 - (distance_actuelle / distance_initiale * 100)` - Exemple : distance initiale 500m, distance actuelle 175m → progress = 65% - Couleur : vert (#4CAF50) pour la partie remplie, gris (#E0E0E0) pour le reste **Bouton "Rejouer séq."** : + - Permet de réécouter la séquence qui vient de se terminer - User clique → séquence actuelle redémarre depuis 0:00 - Utile si distraction pendant l'écoute @@ -414,6 +428,7 @@ if (currentSpeed > 5) { ``` **Justification** : + - Distance + ETA = info essentielle sans surcharge visuelle - Direction (flèche) = aide se repérer sans carte complexe - Simplicité = moins distraction conducteur @@ -470,10 +485,12 @@ Popup 5 secondes : | **Faire demi-tour** | Lance navigation GPS externe (Google Maps / Waze) vers point manqué | **Si user au-delà rayon tolérance (>100m)** : + - Aucun popup (point trop loin, probablement hors itinéraire) - User peut naviguer manuellement (bouton Suivant) **Justification** : + - Flexibilité créateur (ajuste selon terrain, vitesse prévue) - Gestion intelligente imprévus (détours, routes fermées) - User pas bloqué (toujours moyen avancer) @@ -489,6 +506,7 @@ Popup 5 secondes : ##### Comportement bouton [▶|] Suivant **1. Premier clic (mode GPS auto actif)** : + - Désactive GPS automatique - Passe à la séquence suivante immédiatement - Bascule en **mode manuel** @@ -496,12 +514,14 @@ Popup 5 secondes : - Timer 10 secondes démarre **2. Deuxième clic (dans les 10 secondes suivantes)** : + - Sort de l'audio-guide - Audio-guide mis en **pause** (historique conservé) - Retour au **flux normal** (algorithme de recommandation) - Toast 2s : "Audio-guide en pause" **3. Clics suivants (après 10 secondes)** : + - Passe à la séquence suivante (comportement standard mode manuel) - Timer 10 secondes redémarre à chaque clic @@ -584,6 +604,7 @@ function onSuivantClick() { ``` **Justification** : + - Résout le problème des embouteillages (30 min sans contenu) - Double intention claire : désactiver GPS puis sortir - User garde toujours le contrôle (peut reprendre audio-guide plus tard) @@ -625,6 +646,7 @@ function onSuivantClick() { - Pub entre séquences **Justification** : + - Vélo : moins de contrôle qu'auto (obstacles, arrêts), nécessite tolérance - Transport : moins de contrôle utilisateur (suit ligne fixe), rayon large compense - Même UX globale = cohérence @@ -677,6 +699,7 @@ Séquence 2 [fin] | **Transport** | Attente GPS OU user clique Suivant | Attente GPS OU user clique Suivant | **Justification** : + - Monétisation équitable créateurs (tous modes participent) - Pub s'insère naturellement (auto-play, pas d'attente utilisateur) - User garde contrôle : piéton clique Suivant, voiture peut skip manuel @@ -697,10 +720,12 @@ Séquence 2 [fin] | **Revenus pub audio-guides** | 3€ / 1000 écoutes complètes (6% CA pub) | **Distinction contenus normaux vs audio-guides** : + - Dashboard sépare : "Revenus contenus classiques" / "Revenus audio-guides" - Permet créateur voir performance par type **Justification** : + - Transparence créateur (comprend revenus) - Incite création audio-guides (nouvelle source revenus) @@ -731,10 +756,12 @@ Séquence 2 [fin] | **Cloud** | PostgreSQL (sync auto) | Multi-device (reprendre sur autre appareil) | **Synchronisation** : + - Sauvegarde locale : chaque fin de séquence + chaque 30s - Sync cloud : à la reconnexion réseau (batch) **Justification** : + - Expérience fluide (pas de perte progression) - Multi-device (démarrer sur iPhone, continuer sur iPad) - Offline-first (fonctionne sans réseau) @@ -744,6 +771,7 @@ Séquence 2 [fin] #### 16.6.2 Interface de reprise **Conditions popup** : + - Dernière écoute **<30 jours** - Progression **>0%** et **<100%** (pas terminé) @@ -776,11 +804,13 @@ Séquence 2 [fin] | **Voir séquences** | Affiche liste complète, user choisit séquence départ | **Expiration progression** : + - Progression conservée **30 jours** - Après 30j : popup "Audio-guide expiré. Recommencez depuis le début ?" - Suppression données progression (mais historique "écouté" préservé) **Justification** : + - Contexte clair : user sait exactement où il en est - Flexibilité : reprendre OU recommencer (choix utilisateur) - 30 jours = raisonnable pour tourisme multi-jours ou retour ultérieur @@ -798,10 +828,12 @@ Séquence 2 [fin] 5. User clique Reprendre → continue séquence 4 **Conflit de version** : + - Si modifications simultanées 2 appareils (rare) : **dernière modification gagne** - Toast : "Progression mise à jour depuis votre autre appareil" **Justification** : + - Confort utilisateur (change d'appareil librement) - Use case réel : planning trajet sur tablette, écoute sur smartphone en voiture diff --git a/docs/domains/content/rules/contenus-geolocalises.md b/docs/domains/content/rules/contenus-geolocalises.md index 9573ee8..83d8743 100644 --- a/docs/domains/content/rules/contenus-geolocalises.md +++ b/docs/domains/content/rules/contenus-geolocalises.md @@ -5,6 +5,7 @@ **Objectif** : Proposer des contenus audio au moment précis où l'utilisateur passe devant un point d'intérêt géographique, pour enrichir son trajet avec des informations contextuelles liées au paysage. **Contrainte principale** : **Sécurité routière** + - Aucune distraction visuelle (pas de texte à lire) - Notification sonore uniquement + icône minimale - Validation par un seul bouton physique au volant ("Suivant") @@ -26,6 +27,7 @@ **Méthode** : API GPS native iOS/Android **Principe** : + - Calcul temps d'arrivée au point GPS basé sur vitesse actuelle et distance - Notification déclenchée **7 secondes avant** d'atteindre le point - Permet au conducteur d'avoir le temps de réagir (2s) + décompte (5s) @@ -118,11 +120,13 @@ class GeoContentDetector(private val fusedLocationClient: FusedLocationProviderC ``` **Cas particulier : vitesse nulle ou très faible** : + - Si vitesse < 5 km/h (1.4 m/s) ET distance < 50m → notification immédiate - Exemple : user arrêté à un feu rouge à 30m du point - Évite notification trop tardive quand user redémarre **Fréquence de vérification** : + - GPS updates : toutes les 1 seconde (balance batterie/précision) - Calcul ETA : à chaque update GPS - Notification : déclenchée immédiatement quand ETA ≤ 7s @@ -134,6 +138,7 @@ class GeoContentDetector(private val fusedLocationClient: FusedLocationProviderC **Philosophie** : **Minimalisme absolu** pour sécurité routière ❌ **Pas de** : + - Titre texte à lire - Description longue - Bouton "Annuler" ou "Plus tard" @@ -141,6 +146,7 @@ class GeoContentDetector(private val fusedLocationClient: FusedLocationProviderC - Image/cover du contenu ✅ **Uniquement** : + - Son bref (notification) - Icône selon tag du contenu - Compteur chiffres (7→1) @@ -179,12 +185,14 @@ class GeoContentDetector(private val fusedLocationClient: FusedLocationProviderC ``` **Évolution du compteur** : + - Affichage pendant 7 secondes - Compteur décrémente : 7 → 6 → 5 → 4 → 3 → 2 → 1 → disparaît - Police grande (72pt), bold, couleur blanche - Background semi-transparent (noir 50% opacity) **Notification sonore** : + - **Son** : bip court (0.5s) ou "ding" doux personnalisé RoadWave - **Volume** : suit le volume système notification (indépendant du volume media) - **Pas de vibration** : inutile en voiture (téléphone sur support) @@ -200,6 +208,7 @@ class GeoContentDetector(private val fusedLocationClient: FusedLocationProviderC **Décision** : Notification sonore uniquement en mode CarPlay/Android Auto **Contexte** : + - [CarPlay Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/carplay) interdisent les overlays qui "takeover" l'écran - [Android Auto Media Apps Guidelines](https://developer.android.com/training/cars/media) imposent des interactions minimales - Sécurité routière maximale = pas de distraction visuelle @@ -207,11 +216,13 @@ class GeoContentDetector(private val fusedLocationClient: FusedLocationProviderC **Comportement en mode CarPlay/Android Auto** : ❌ **Désactivé** : + - Icône overlay - Compteur visuel (7...6...5...) - Tout élément graphique supplémentaire ✅ **Activé uniquement** : + - Notification sonore (bip ou ding) - Bouton "Suivant" standard (déjà présent) @@ -280,12 +291,14 @@ class NotificationManager(private val context: Context) { 6. Contenu géolocalisé démarre après 5s **Justification** : + - ✅ Conformité maximale CarPlay/Android Auto guidelines - ✅ Sécurité routière (pas de distraction visuelle) - ✅ User peut toujours valider via bouton "Suivant" standard - ✅ Apps comparables (Waze, Apple Maps) utilisent alertes sonores similaires **Alternative envisagée** : Mini-badge sur bouton "Suivant" + - Moins invasif qu'un compteur - Mais toujours considéré comme overlay (zone grise) - **Décision** : Privilégier conformité maximale (sonore uniquement) @@ -297,15 +310,18 @@ class NotificationManager(private val context: Context) { **User appuie sur "Suivant"** : **Étape 1 : Transition visuelle (0.3s)** + - Icône + compteur "7" disparaissent avec fade out - Nouveau compteur "5" apparaît (plus grand, centré) **Étape 2 : Décompte 5 secondes** + - Compteur décrémente : 5 → 4 → 3 → 2 → 1 - Contenu actuel continue de jouer **normalement** (pas de baisse volume) - User entend le contenu en cours pendant le décompte **Étape 3 : Fin du décompte** + - Compteur atteint "0" - Fade out 0.3s du contenu actuel - Fade in 0.3s du contenu géolocalisé @@ -327,6 +343,7 @@ T+5s : Décompte atteint 0 ``` **Justification** : + - Évite silence inconfortable pendant décompte - User continue d'écouter du contenu intéressant - Transition naturelle @@ -353,6 +370,7 @@ T+5s : Décompte atteint 0 ### 17.3 Limitation anti-spam **Problème identifié** : + - Routes riches en points d'intérêt (parcours touristiques) - Risque de notifier toutes les 30 secondes - Fatigue utilisateur + distraction conducteur @@ -362,6 +380,7 @@ T+5s : Décompte atteint 0 #### 17.3.1 Quota : 6 contenus géolocalisés par heure **Règle** : + - Maximum **6 contenus géolocalisés** notifiés par heure - Fenêtre glissante : calcul sur les 60 dernières minutes (pas réinitialisation à 0h) - Si quota atteint : notifications suivantes ignorées silencieusement @@ -380,6 +399,7 @@ T+5s : Décompte atteint 0 ``` **Exception : audio-guides multi-séquences** : + - Un audio-guide avec N séquences compte comme **1 seul contenu** dans le quota - Une fois démarré, toutes ses séquences sont jouables (pas de limite) - Exemple : audio-guide 8 séquences = 1 quota, contenus simples restants = 5 @@ -422,12 +442,14 @@ func RecordNotification(userID string, contentID string) { #### 17.3.2 Cooldown : 10 minutes après notification ignorée **Règle** : + - Si user ne clique pas sur "Suivant" pendant les 7 secondes - → Cooldown de **10 minutes** activé - → Aucune nouvelle notification pendant ce délai - → Même si quota non atteint **Justification** : + - User a probablement une raison de ne pas vouloir de contenu géolocalisé maintenant - Évite harcèlement (notifications répétées ignorées) - Respecte choix implicite de l'utilisateur @@ -458,6 +480,7 @@ func ActivateCooldown(userID string) { ``` **Exception : notification validée (user a cliqué)** : + - Pas de cooldown si user a cliqué sur "Suivant" - Même si user skip le contenu ensuite (pendant le décompte ou après) - Cooldown = pénalité uniquement pour notification complètement ignorée @@ -503,6 +526,7 @@ Timeline : 6. User appuie "Précédent" → **retour au contenu géolocalisé à 42s** **Règle** : Comme décrit dans [../../recommendation/rules/interactions-navigation.md](../../recommendation/rules/interactions-navigation.md#52-commande-précédent) : + - Si temps écouté ≥ 10 secondes → replay contenu actuel depuis début - Si temps écouté < 10 secondes → retour contenu précédent (position exacte) @@ -567,6 +591,7 @@ if (avgSpeedKmh < 5) { ``` **Hysteresis (éviter basculements intempestifs)** : + - Nouvelle vitesse doit être stable pendant **10 secondes** avant basculement - Exemple : user passe de 20 km/h à 3 km/h (arrêt feu rouge) - Si vitesse remonte à 20 km/h après 8s → pas de basculement @@ -595,6 +620,7 @@ if (avgSpeedKmh < 5) { | **Type contenu** | Audio-guides uniquement | Tous contenus géolocalisés | **Transition fluide** : + - Pas de popup ou message à l'utilisateur - Basculement invisible et automatique - Permissions ajustées automatiquement (si déjà accordées) @@ -608,6 +634,7 @@ if (avgSpeedKmh < 5) { **Scénario** : Autoroute A6, vitesse 130 km/h, contenu géolocalisé détecté. **Calcul** : + - Vitesse : 130 km/h = 36.1 m/s - ETA 7s → distance notification : 7 × 36.1 = **252 mètres** avant le point - User a 7s pour cliquer "Suivant" @@ -618,6 +645,7 @@ if (avgSpeedKmh < 5) { **Conclusion** : Le système fonctionne même à très haute vitesse ✅ **Cas extrême : 180 km/h** (illégal mais théoriquement possible) : + - Vitesse : 180 km/h = 50 m/s - ETA 7s → distance notification : 350m avant le point - Décompte 5s : user parcourt 250m @@ -655,6 +683,7 @@ T+57s : User clique "Suivant" → contenu Château B démarre **Solution proposée** : **Ajuster le cooldown selon validation précédente** Nouvelle règle : + - Notification validée (user a cliqué) : pas de cooldown - Notification ignorée (user n'a pas cliqué) : cooldown 10 min - Exception : si 2+ notifications validées consécutives, cooldown réduit à 5 min @@ -687,18 +716,21 @@ func CalculateCooldown(userID string) time.Duration { **Scénario** : User se gare à 30m d'un château, sort de voiture, visite 1h, revient. **Problème** : + - Vitesse < 5 km/h + distance < 50m → notification immédiate - Mais user en mode "stationnement", pas en mode "conduite" **Solution** : **Détection mode stationnement** Règle : + - Si vitesse < 1 km/h pendant **2 minutes** consécutives - → Mode "stationnement" activé - → Pas de notification de contenus géolocalisés - → Basculement automatique en mode piéton (push arrière-plan) **Reprise conduite** : + - Vitesse > 5 km/h pendant 10s - → Mode "voiture" réactivé - → Notifications reprennent (si quota non atteint) diff --git a/docs/domains/content/rules/creation-publication.md b/docs/domains/content/rules/creation-publication.md index 51fee6c..6628843 100644 --- a/docs/domains/content/rules/creation-publication.md +++ b/docs/domains/content/rules/creation-publication.md @@ -5,6 +5,7 @@ **Décision** : Formats universels avec encodage asynchrone **Formats acceptés** : + - ✅ MP3 (`.mp3`) - ✅ AAC (`.aac`, `.m4a`) - ❌ WAV, FLAC (trop lourds, inutiles en voiture) @@ -31,6 +32,7 @@ ``` **Temps d'encodage estimé** : + - Contenu 5 min → ~30 secondes - Podcast 1h → ~5 minutes - Podcast 4h → ~20 minutes @@ -54,11 +56,13 @@ | 2.0x | Survol rapide (modérateurs) | **Disponible pour** : + - ✅ Modérateurs (validation rapide : 30s → 15s à 2x) - ✅ Auditeurs (tous les contenus) - ✅ Standard industrie (YouTube, Spotify, Apple Podcasts) **Justification** : + - **Simplicité** : 2 formats couvrent 95% des cas d'usage - **Coût optimisé** : pas de conversion WAV/FLAC lourds - **Stockage réduit** : suppression original après encodage @@ -84,6 +88,7 @@ **Zone de diffusion (obligatoire)** : Options mutuellement exclusives : + - **Point GPS** : latitude + longitude + rayon (100m à 10km) - **Ville** : sélection dans référentiel INSEE - **Département** : sélection liste @@ -91,6 +96,7 @@ Options mutuellement exclusives : - **National** : France entière **Tags disponibles** (1 à 3 obligatoires) : + - Automobile - Voyage - Famille @@ -105,12 +111,14 @@ Options mutuellement exclusives : - Santé **Champs optionnels** : + - ❌ Description (ajout ultérieur) - ❌ Image couverture (génération auto) **Image de couverture par défaut** : Génération automatique selon règles : + - Icône selon type géo : 📍 Ancré / 🌍 Contextuel / 🎧 Neutre - Couleur selon tag principal : bleu (Auto), vert (Voyage), rouge (Musique), etc. - Format 800×800px, PNG @@ -127,6 +135,7 @@ Classification : Tout public ``` **Justification** : + - **Friction minimale** : 5 champs max = 2 min de publication - **Publication rapide** : pas de blocage sur description/image - **Coût 0** : pas de génération IA au MVP @@ -161,6 +170,7 @@ Classification : Tout public | **Zone diffusion** | Cohérente (pas "Tour Eiffel" avec zone "National") | **Délai de validation** : + - Objectif : **24-48h** (jours ouvrés) - Priorité : FIFO (First In First Out) - Weekend : délai peut atteindre 72h @@ -169,11 +179,13 @@ Classification : Tout public **Notification créateur** : **Si accepté** : + - Email + push : "✅ Votre contenu '[Titre]' est en ligne !" - Lien direct vers le contenu - Compteur : "2/3 contenus validés pour devenir créateur vérifié" **Si refusé** : + - Email + push : "❌ Contenu '[Titre]' refusé" - Raison détaillée : "Qualité audio insuffisante" / "Tags non pertinents" / "Classification incorrecte" / etc. - Lien vers règles de publication @@ -182,11 +194,13 @@ Classification : Tout public **Après 3 validations** : Créateur obtient **statut "Vérifié"** : + - Badge ✓ visible sur profil - Contenus futurs publiés **immédiatement** (modération a posteriori uniquement) - Modération seulement si signalé par utilisateurs **Outils modérateur** : + - Écoute accélérée (1.5x ou 2x) = double productivité - Interface dédiée : queue de contenus à valider - Raccourcis clavier : A (Accepter), R (Rejeter), Espace (Pause) @@ -197,6 +211,7 @@ Créateur obtient **statut "Vérifié"** : ⚠️ **Non implémenté au MVP** (complexité juridique) Vision future (envisageable) : + - Créateurs établis peuvent opt-in "Modérateur communautaire" - Formation obligatoire (30 min) + quiz (80%) - Pré-validation uniquement (validation finale toujours par équipe RoadWave) @@ -204,6 +219,7 @@ Vision future (envisageable) : - Attribution aléatoire (pas de collusion) **Justification décision MVP** : + - **Responsabilité juridique** : plateforme reste responsable (DSA EU) - **Qualité garantie** : modérateurs formés et mandatés - **Anti-spam efficace** : bloque 95% des abus dès le début @@ -233,18 +249,22 @@ Vision future (envisageable) : **Raisons restrictions** : **Audio non modifiable** : + - Évite fraude : uploader contenu validé → remplacer par spam - Intégrité : auditeurs doivent écouter ce qui a été validé **Zone/Type non modifiables** : + - Évite manipulation : créer "Local Paris" → changer en "National" pour boost visibilité - Évite abus : créer "Neutre" (faible pondération géo) → changer en "Ancré" (forte pondération) **Classification non modifiable** : + - Évite contournement : uploader "Tout public" → passer en "18+" sans revalidation - Sécurité : garantit que classification a été vérifiée **Si besoin de changer audio/zone/classification** : + - Action : **Supprimer contenu + republier** - Si créateur <3 contenus validés : retourne en file validation - Si créateur ≥3 contenus validés : publication immédiate @@ -269,11 +289,13 @@ Créateur supprime podcast écouté par 1000 personnes ``` **Notifications suppression** : + - Pas de notification aux auditeurs (pour éviter effet Streisand) - Historique reste consultable : "Vous avez écouté ce contenu le [date]" - Si auditeur tente de réécouter : "Ce contenu n'est plus disponible" **Justification** : + - **Simplicité** : règles claires et non-ambiguës - **Sécurité** : évite manipulations algorithme et contournements modération - **Contrôle créateur** : liberté totale de supprimer (RGPD) diff --git a/docs/domains/content/rules/detection-contenu-protege.md b/docs/domains/content/rules/detection-contenu-protege.md index 71afc5f..ddcb95a 100644 --- a/docs/domains/content/rules/detection-contenu-protege.md +++ b/docs/domains/content/rules/detection-contenu-protege.md @@ -60,6 +60,7 @@ 4. Mention titre + artiste dans métadonnées (recommandé) **Justification juridique** : + - Directive UE 2019/790 : exception citation à des fins de critique - Jurisprudence FR : citation courte autorisée si justifiée - 30s = standard industrie (YouTube, TikTok) @@ -108,6 +109,7 @@ Validation normale continue - ✅ Modération **a posteriori uniquement** (si signalé) **Justification** : + - **Coût 0€** : réutilise écoute 30s déjà effectuée - **Scalable** : pas de validation pour créateurs établis - **Pragmatique** : détecte violations évidentes (90% des cas) @@ -175,6 +177,7 @@ Validation normale continue **Détail sanctions** : **Avertissement (1ère fois)** : + - Suppression contenu immédiate - Email + push + in-app : "⚠️ Contenu retiré pour violation droits d'auteur" - Explication pédagogique : règles musique, lien vers CGU @@ -182,22 +185,26 @@ Validation normale continue - Créateur peut republier version corrigée **Strike 1 (2e fois)** : + - Suppression contenu - Strike ajouté au compteur (visible profil créateur) - Suspension upload **3 jours** - Email détaillé : titre détecté, timestamp, règle violée **Strike 2 (3e fois)** : + - Idem Strike 1 - Suspension upload **7 jours** - Warning : "Strike 2/4 - Vous approchez du seuil critique" **Strike 3 (4e fois)** : + - Idem Strike 2 - Suspension upload **30 jours** - Warning : "Strike 3/4 - Prochaine violation = ban définitif" **Strike 4 - Ban définitif (5e fois)** : + - Désactivation compte créateur - Tous contenus dépubliés - Pas de création nouveau compte (email/téléphone blacklisté) @@ -226,6 +233,7 @@ Créateur a Strike 2 (7 jours de suspension) ``` **Justification** : + - **Tolérance 1ère fois** : évite punir erreurs honnêtes - **Escalade progressive** : dissuasion sans brutalité - **4 strikes avant ban** : cohérent avec système global (sections 9, 14) @@ -239,6 +247,7 @@ Créateur a Strike 2 (7 jours de suspension) **Décision** : Réutilise système existant section 14.3.3 **Accès** : + - Bouton "Contester cette décision" dans notification sanction - Délai : **7 jours** après notification @@ -266,11 +275,13 @@ Champs standards (voir section 14) **+** champs spécifiques : **Cas particulier : Musique libre mal détectée** Si créateur prouve musique = licence Epidemic Sound / Artlist : + - ✅ Appel automatiquement accepté - ✅ Ajout titre à **whitelist interne** (évite futures erreurs) - ✅ Excuse + compensation (ex: 1 mois Premium offert) **Justification** : + - Réutilise processus éprouvé (section 14) - Preuve licence = résout 90% des cas - Délai 72h acceptable (pas de suspension immédiate sur appel) @@ -309,6 +320,7 @@ Interdit : ``` **Justification** : + - Prévention > sanction (économie modération) - Créateurs informés = moins de violations - Coût : 0€ (documentation statique) @@ -382,12 +394,14 @@ Modérateur humain vérifie : **Coût total MVP** : **0€** (validation manuelle intégrée) **Conformité juridique** : + - ✅ Directive UE 2019/790 (droit d'auteur + exception citation) - ✅ DSA (Digital Services Act) : modération réactive + droit d'appel - ✅ SACEM/SDRM : protection ayants droit + processus contentieux - ✅ Fair use : tolérance 30s conforme jurisprudence FR/UE **Scalabilité** : + - 0-1000 contenus/mois : validation manuelle suffisante (3h/mois modération) - 1000-10K contenus/mois : fingerprinting open-source requis - 10K+ contenus/mois : API commerciale à considérer (ACRCloud) @@ -404,6 +418,7 @@ Modérateur humain vérifie : --- **Lien avec autres sections** : + - Section 4.3 : Validation des 3 premiers contenus (workflow intégré) - Section 7.2 : Interdictions lives + fingerprinting post-MVP - Section 14 : Système modération (signalements, sanctions, appels) diff --git a/docs/domains/content/rules/radio-live.md b/docs/domains/content/rules/radio-live.md index 5298aa9..14c6114 100644 --- a/docs/domains/content/rules/radio-live.md +++ b/docs/domains/content/rules/radio-live.md @@ -18,12 +18,14 @@ 4. Après 15s → **Live public**, auditeurs peuvent rejoindre **Notification abonnés** : + - ✅ **Push notification immédiate** à tous les abonnés dans la zone géographique - Message : "🔴 [Nom créateur] est en direct : [Titre live]" - Tap notification → ouverture app + lecture live immédiate - **Filtrage géographique** : si abonné hors zone, pas de notif (évite frustration) **Limite de durée** : + - **Maximum 8 heures** par session live - Warning créateur à 7h30 : "Votre live se terminera dans 30 min" - Si besoin continuer → arrêt + redémarrage nouveau live (évite abus ressources serveur) @@ -56,12 +58,14 @@ ``` **Détection violations** : + - **Signalement utilisateurs** : bouton "Signaler" accessible pendant live - **IA audio fingerprint** : détection musique protégée en arrière-plan (post-MVP, voir [Section 18](detection-contenu-protege.md)) - **Modération réactive** : modérateurs peuvent écouter lives signalés en temps réel - **Coupure immédiate** : modérateur peut arrêter live si contenu illégal évident **Justification** : + - **Buffer 15s** : équilibre entre test qualité et friction minimale - **Notification abonnés** : engagement maximal, valeur ajoutée live - **8h max** : couvre 99% cas usage (podcasts longs, émissions radio) sans abus @@ -117,11 +121,13 @@ | **Modifier replay** | ❌ Non | Intégrité enregistrement | **Conservation fichier source** : + - Opus raw conservé **7 jours** après fin live (backup) - Suppression automatique après 7j (économie stockage) - Si replay supprimé par créateur → fichier raw supprimé immédiatement **Justification** : + - **Compte à rebours 5s** : outro propre, pas de coupure brutale - **Tolérance 60s** : évite arrêts intempestifs (tunnel, changement cellule) - **Enregistrement auto** : valorisation contenu éphémère, génération contenu pérenne @@ -172,6 +178,7 @@ **Décision ferme** : ❌ **Aucun chat en direct, ni maintenant ni dans le futur** **Raisons** : + - **Sécurité routière** : pas de distraction en voiture (focus UX) - **Harcèlement** : évite contenu haineux, insultes, trolling - **Modération** : pas de coût modération temps réel (impossible à scale) @@ -189,9 +196,11 @@ | **Réactions emoji** | ❌ | Jamais implémenté (décision définitive) | **Messages utilisateur** : + - "💬 Les discussions ne sont pas disponibles sur RoadWave pour garantir votre sécurité en voiture et éviter le harcèlement." **Justification décision définitive** : + - **UX cohérente** : RoadWave = écoute en conduisant, pas réseau social interactif - **Bien-être** : évite toxicité, harcèlement, haine (fléau réseaux sociaux) - **Juridique** : pas de risque contentieux modération chat (DSA EU) @@ -223,6 +232,7 @@ Auditeurs (App mobile, HLS natif) 6. **Post-live** → Job async : Opus → MP3 256 kbps → Publication replay **Dépendances** : + - ✅ **Pion WebRTC** (Go library, open source, MIT license) - ✅ **FFmpeg** (conversion audio, LGPL/GPL) - ✅ **NGINX** (cache et distribution HLS, open source) @@ -230,6 +240,7 @@ Auditeurs (App mobile, HLS natif) - ✅ **PostgreSQL + Redis** (métadonnées live + cache) **Avantages** : + - ✅ Pas de dépendance Google/Facebook/Cloudflare (souveraineté) - ✅ WebRTC standard ouvert (Pion = lib Go pure) - ✅ Réutilise infra HLS existante (pas de doublon) @@ -245,6 +256,7 @@ Auditeurs (App mobile, HLS natif) | **Scale** | 1M-10M | Kubernetes auto-scale (2000+ lives) | +1K€ + bande passante | **Bande passante** : + - Live : 48 kbps × nb_auditeurs (via NGINX Cache, segments) - Exemple : 100 auditeurs = 4.8 Mbps = ~2 Go/heure via cache - Coût estimé : ~0.02€/heure pour 100 auditeurs diff --git a/docs/domains/moderation/README.md b/docs/domains/moderation/README.md index dda49a0..da5e78a 100644 --- a/docs/domains/moderation/README.md +++ b/docs/domains/moderation/README.md @@ -35,6 +35,7 @@ Le domaine **Moderation** gère la modération des contenus et des utilisateurs, ## Ubiquitous Language **Termes métier du domaine** : + - **Report** : Signalement d'un contenu ou utilisateur problématique - **Strike** : Avertissement comptabilisé (3 strikes = ban) - **Sanction** : Mesure disciplinaire (warning, suspension, ban) diff --git a/docs/domains/moderation/flows/moderation-signalement.md b/docs/domains/moderation/flows/moderation-signalement.md index 5a6765a..57fd5b4 100644 --- a/docs/domains/moderation/flows/moderation-signalement.md +++ b/docs/domains/moderation/flows/moderation-signalement.md @@ -67,6 +67,7 @@ flowchart TD ## Légende **Priorités de traitement** : + - 🔴 **CRITIQUE** (score ≥90) : <2h - Violence, suicide, danger immédiat - 🟠 **HAUTE** (70-89) : <24h - Haine, harcèlement - 🟡 **MOYENNE** (40-69) : <24h - Spam, contenu inapproprié diff --git a/docs/domains/moderation/rules/autres-comportements.md b/docs/domains/moderation/rules/autres-comportements.md index 59f1a6f..87c06d8 100644 --- a/docs/domains/moderation/rules/autres-comportements.md +++ b/docs/domains/moderation/rules/autres-comportements.md @@ -9,6 +9,7 @@ **Disponibilité** : Partout dans l'application **Emplacements** : + - Player en lecture (bouton dans contrôles) - Page profil créateur (sur chaque contenu) - Liste de recherche (menu contextuel) @@ -17,6 +18,7 @@ **Icône** : ⬆️ (universelle iOS/Android) **Menu options** : + - Copier le lien - WhatsApp - Email @@ -24,6 +26,7 @@ - Plus... (sheet natif OS) **Justification** : + - Viralité = croissance organique gratuite - Aucune friction, partage universel @@ -93,11 +96,13 @@ Page web responsive ``` **Deep linking** : + - iOS : Universal Links (configuration `apple-app-site-association`) - Android : App Links (configuration `assetlinks.json`) - URL scheme : `roadwave://content/[content_id]` **Justification** : + - Meilleure viralité (partage social optimisé) - SEO (contenus indexés Google) - UX optimale (web + app) @@ -137,10 +142,12 @@ Page web responsive - Rejouer les 30 premières secondes (illimité) **Tracking** : + - Métriques créateur : "Partages Premium" + "Conversions Premium" - Créateur touche sa part si conversion (70%) **Justification** : + - Équilibre viralité / monétisation - 30s = assez pour donner envie, pas assez pour satisfaire - Protège revenus créateurs @@ -219,10 +226,12 @@ Page web responsive | **Par tag** | Filtre multi-sélection tags | **Recherche locale** : + - Barre recherche dans profil : "Rechercher dans les contenus de @pseudo" - Recherche full-text sur titres + descriptions **Actions menu [•••]** : + - Partager profil - Signaler profil (spam, usurpation) - Bloquer créateur (masque tous ses contenus) @@ -254,6 +263,7 @@ Page web responsive | **Démographie** | Âge / zone géo (agrégée, anonymisée) | **Justification** : + - Arrondi = évite comparaisons anxiogènes - Preuve sociale pour nouveaux auditeurs (trust) - Gamification douce (motivation créateurs) @@ -272,6 +282,7 @@ Page web responsive 3. **Communauté significative** : ≥10K abonnés + compte actif >6 mois **Affichage** : + - Badge bleu **✓** accolé au pseudo (partout : profil, player, recherche) - Tooltip au survol/appui long : "Compte vérifié" @@ -284,11 +295,13 @@ Page web responsive | **Automatique (10K)** | Badge attribué automatiquement à 10K abonnés si compte >6 mois | **Retrait du badge** : + - Suspension monétisation → badge retiré temporairement - Strikes multiples → badge retiré définitivement - Usurpation identité détectée → ban + retrait **Justification** : + - Combat usurpations d'identité - Trust auditeurs (surtout pour médias/personnalités) - Simplicité (1 seul badge, pas de gamification excessive) @@ -332,6 +345,7 @@ LIMIT 20; ``` **Champs indexés** : + - Titre du contenu (poids × 3) - Description (poids × 1) - Pseudo créateur (poids × 2) @@ -350,10 +364,12 @@ LIMIT 20; **Coût** : 0€ (PostgreSQL natif) **Migration future** : + - Si >100K contenus : Meilisearch (typo-tolerance avancée, ~20-50€/mois) - Si >1M contenus : Elasticsearch cluster **Justification** : + - PostgreSQL full-text = performant jusqu'à 500K contenus - Stemming français natif - 0€, aucune dépendance externe @@ -411,15 +427,18 @@ ORDER BY distance ASC; ``` **Affichage résultats** : + - Tri par défaut : distance croissante - Indication distance : "À 2.3 km" / "À 15 km" / "À 142 km" - Option carte : markers cliquables (clustering si >50 résultats) **Coût** : + - MVP : 0€ (Nominatim public) - Scale : 20-50€/mois (Nominatim self-hosted Docker) **Justification** : + - Essentiel pour tourisme / planification trajet - OpenStreetMap = pas de dépendance Google - PostGIS = performant (index GIST natif) @@ -520,6 +539,7 @@ CREATE INDEX idx_content_tags ON contents USING GIN(tags); **Coût** : 0€ (PostgreSQL + index standards) **Justification** : + - Filtres essentiels pour découvrabilité - Combinables = puissance maximale - Sauvegarde = gain temps utilisateurs réguliers @@ -575,17 +595,20 @@ CREATE INDEX idx_content_tags ON contents USING GIN(tags); | **Distance** | Si recherche géo : "À 2.3 km" | **Actions contextuelles [⋮]** : + - Partager - Ajouter à une playlist (future feature) - Télécharger (offline) - Signaler **Pagination** : + - **20 résultats** par page - Infinite scroll (charger automatiquement si scroll >80%) - Bouton "Charger 20 suivants" en bas (fallback si scroll auto désactivé) **Vue carte (alternative)** : + - Bouton toggle "Liste / Carte" - Map Leaflet (OpenStreetMap) - Markers cliquables → popup avec preview @@ -594,6 +617,7 @@ CREATE INDEX idx_content_tags ON contents USING GIN(tags); **Coût** : 0€ (Leaflet open source + OSM tiles gratuit) **Justification** : + - Équilibre information / compacité - Lazy loading = performances - Infinite scroll = UX moderne diff --git a/docs/domains/moderation/rules/moderation-communautaire.md b/docs/domains/moderation/rules/moderation-communautaire.md index b460a46..e989595 100644 --- a/docs/domains/moderation/rules/moderation-communautaire.md +++ b/docs/domains/moderation/rules/moderation-communautaire.md @@ -3,6 +3,7 @@ **Contexte** : Système de gamification pour encourager les utilisateurs à signaler du contenu inapproprié de manière pertinente et qualitative. **Objectifs** : + - Améliorer la qualité des signalements (réduire les signalements abusifs) - Réduire la charge de travail des modérateurs (priorisation automatique) - Récompenser les contributeurs actifs et fiables @@ -22,6 +23,7 @@ | 🥇 | **Contributeur Or** | 50 signalements validés + 90% taux pertinence | Signalements prioritaires (+30 points) + Badge visible + Réduction Premium | **Règles d'éligibilité** : + - Minimum **10 signalements envoyés** pour être éligible aux badges - Les signalements "En cours" ne comptent pas dans le calcul - Les signalements rejetés font baisser le taux de pertinence @@ -32,10 +34,12 @@ Taux de pertinence = (Signalements validés / Total signalements envoyés) × 10 ``` **Période de calcul** : + - Seuls les **6 derniers mois** comptent (période glissante) - Évite que les utilisateurs se reposent sur leurs lauriers **Justification** : + - **Simple** : 3 niveaux seulement (pas d'over-engineering) - **Gratuit** : logique backend + affichage frontend - **Efficace** : incite la qualité plutôt que la quantité @@ -52,6 +56,7 @@ Taux de pertinence = (Signalements validés / Total signalements envoyés) × 10 | **Argent → Or** | 60 jours | **Justification** : + - Évite la montée en badge trop rapide (anti-farming) - Force une contribution régulière sur la durée - Détecte les patterns suspects (audit modérateur si trop rapide) @@ -63,6 +68,7 @@ Taux de pertinence = (Signalements validés / Total signalements envoyés) × 10 **IMPORTANT** : L'utilisateur doit être informé du système de récompenses **dès son premier signalement**. **Moment d'affichage** : + - Après avoir envoyé le **premier signalement** - Juste après le toast de confirmation standard - **2 secondes de délai** avant affichage de la modal @@ -102,6 +108,7 @@ Taux de pertinence = (Signalements validés / Total signalements envoyés) × 10 ``` **Lien "En savoir plus"** : + - Redirection vers page dédiée expliquant : - Calcul détaillé du taux de pertinence - Critères d'obtention pour chaque badge @@ -116,6 +123,7 @@ Taux de pertinence = (Signalements validés / Total signalements envoyés) × 10 #### 19.1.4 Affichage badges et statistiques **Badge visible** : + - **Profil utilisateur** : visible par tous les autres utilisateurs - **Historique signalements** : visible uniquement par l'utilisateur lui-même - **Toast après obtention** : @@ -136,10 +144,12 @@ Prochain palier : 🥇 Contributeur Or (30 signalements validés restants) ``` **Toast après traitement signalement** : + - Si validé : "✅ Bravo ! Votre signalement a aidé la communauté. Progression : 3/5 pour badge Bronze 🥉" - Si rejeté : "❌ Signalement non retenu. Taux de pertinence : 60%. Continuez vos efforts !" **Justification** : + - **Transparence totale** : l'utilisateur voit sa progression en temps réel - **Motivation** : gamification saine (pas de pression, juste encouragement) - **Gratifiant** : messages positifs valorisant la contribution @@ -157,6 +167,7 @@ Score fiabilité = min(100, (Validés × 10 - Rejetés × 5 + Bonus_Or × 20)) ``` **Détails** : + - **Validés** : nombre de signalements validés par modérateurs - **Rejetés** : nombre de signalements rejetés - **Bonus_Or** : +20 points si badge Or actif @@ -181,10 +192,12 @@ Priorité = (Score_IA × 0.7) + (Signalements_cumulés × 0.2) + (Fiabilité_sig ``` **Intégration** : + - **Fiabilité_signaleur** = Score fiabilité / 100 (normalisé 0-1) - Les signalements des utilisateurs avec badge Argent/Or passent automatiquement devant les autres (même score IA) **Affichage à l'utilisateur** : + - **NON affiché** publiquement (risque de gamification abusive) - **Visible** uniquement dans les stats personnelles : ``` @@ -201,6 +214,7 @@ Priorité = (Score_IA × 0.7) + (Signalements_cumulés × 0.2) + (Fiabilité_sig **Décision** : Statut automatique pour utilisateurs Badge Argent ou Or **Critère** : + - Badge **Argent OU Or** actif = automatiquement "Utilisateur de confiance" **Avantages** : @@ -209,6 +223,7 @@ Priorité = (Score_IA × 0.7) + (Signalements_cumulés × 0.2) + (Fiabilité_sig 3. **Notification différée** : résultats sous 12h (au lieu de 24-48h standards) **Révocation** : + - Perte badge Argent/Or → perte statut confiance automatique - Retour au statut normal, aucune sanction supplémentaire @@ -259,10 +274,12 @@ Merci de contribuer à rendre RoadWave meilleur chaque jour ! ``` **Rappels** : + - Email + Push J-7 : "Il vous reste 7 jours pour profiter de votre réduction Premium -50%" - Email + Push J-1 : "Dernière chance ! Votre réduction Premium -50% expire demain" **Si non activée après 30 jours** : + - Offre expirée (notification : "Votre offre Premium -50% a expiré") - Badge Or conservé (seule l'offre expire, pas le badge) @@ -271,16 +288,19 @@ Merci de contribuer à rendre RoadWave meilleur chaque jour ! #### 19.4.3 Perte du badge Or **Conditions** : + - Taux de pertinence descend sous **90%** après audit trimestriel - Signalements abusifs détectés (voir Section 19.5) **Conséquences** : + - **Badge Or révoqué** immédiatement - **Abonnement Premium en cours** reste actif jusqu'à sa fin normale - **Nouvelle souscription** à prix normal (4.99€/mois) - **Pas de nouvelle offre -50%** même si badge Or réobtenu ultérieurement **Justification** : + - Maintien qualité badges sur le long terme - Évite abus système @@ -291,11 +311,13 @@ Merci de contribuer à rendre RoadWave meilleur chaque jour ! **Coût maximum** : **200€/mois** (si 50 utilisateurs Or simultanés avec réduction active) **ROI attendu** : + - **1 utilisateur Or** = économie ~5-10h modération/mois = 75-150€ économisés (taux horaire modérateur ~15€/h) - **10 utilisateurs Or actifs** = 750-1500€ économisés > 200€ coût réductions - **ROI positif dès 2-3 utilisateurs Or actifs** **Justification** : + - **Incitation forte** pour meilleurs contributeurs uniquement - **Conversion** : utilisateurs gratuits très engagés → Premium payant après 3 mois - **Risque limité** : coût max plafonné, largement compensé par économie modération @@ -311,11 +333,13 @@ Merci de contribuer à rendre RoadWave meilleur chaque jour ! **Décision** : Maximum 10 signalements / 24h par utilisateur **Règles** : + - Au-delà de 10 signalements/24h → signalements automatiquement rejetés - Alerte modérateur automatique (enquête manuelle) - Message utilisateur : "Limite quotidienne atteinte (10 signalements/24h). Réessayez demain." **Justification** : + - Évite signalement massif (farming) - 10/jour = largement suffisant pour usage légitime - Coût : 0€ @@ -336,10 +360,12 @@ HAVING COUNT(*) > 30 ``` **Action** : + - Enquête manuelle modérateur - Révocation badge si abus confirmé **Patterns détectés** : + - Signalement massif (>30/semaine) - Taux de pertinence <50% malgré volume élevé - Signalements tous rejetés sur période 7 jours @@ -368,10 +394,12 @@ HAVING COUNT(*) > 30 ``` **Après audit** : + - Email résultat : "Badge conservé ✓" ou "Badge révoqué ✗" - Possibilité de réobtenir badge ultérieurement (pas de ban) **Justification** : + - Maintien qualité badges sur le long terme - Évite repos sur lauriers - Coût : 0€ (script automatique) @@ -387,6 +415,7 @@ HAVING COUNT(*) > 30 | **Grave** | Signalements massifs coordonnés (farming) | Ban permanent fonctionnalité signalement + révocation tous badges | **Notification sanction** : + - Email + Push + In-app - Explication détaillée de l'abus détecté - Durée sanction @@ -416,11 +445,13 @@ HAVING COUNT(*) > 30 --- **Conformité** : + - ✅ RGPD : données modération anonymisées après 3 ans - ✅ Transparence : utilisateur informé dès le 1er signalement - ✅ Anti-discrimination : système accessible à tous, basé uniquement sur pertinence **Scalabilité** : + - 0-100 utilisateurs actifs : système automatique, 0€ - 100-1000 utilisateurs actifs : 0-50€/mois (quelques badges Or) - 1000+ utilisateurs actifs : 50-200€/mois (max 50 badges Or simultanés) diff --git a/docs/domains/moderation/rules/moderation-flows.md b/docs/domains/moderation/rules/moderation-flows.md index 4dfd288..1540814 100644 --- a/docs/domains/moderation/rules/moderation-flows.md +++ b/docs/domains/moderation/rules/moderation-flows.md @@ -19,6 +19,7 @@ Liste déroulante avec 7 options : | 🔧 **Autre** | Champ texte obligatoire si sélectionné | **Justification** : + - Équilibre entre simplicité (pas trop de choix) et précision (aide les modérateurs) - Coût : 0€ (liste déroulante standard) @@ -33,6 +34,7 @@ Liste déroulante avec 7 options : - Non bloquant : le signalement peut être envoyé sans commentaire **Justification** : + - Encourage la qualité des signalements sans créer de friction - Aide les modérateurs à comprendre le contexte - Pas de risque d'abandon du processus @@ -44,16 +46,19 @@ Liste déroulante avec 7 options : **Décision** : Toast in-app avec lien historique **Affichage** : + - Toast notification : "✓ Signalement envoyé. Nous l'examinerons sous 24-48h." - Durée affichage : 5 secondes - Bouton optionnel "Voir mes signalements" (accès historique) **Historique personnel** : + - Liste des signalements envoyés par l'utilisateur - Statut : En cours / Traité / Rejeté - Notification in-app si action prise (contenu retiré, signalement rejeté) **Justification** : + - Transparence maximale - Coût : 0€ (aucun email automatique) - Bonne UX @@ -85,15 +90,18 @@ Liste déroulante avec 7 options : 4. Priorisation automatique selon score **Délais** : + - Audio <5 min : 1-3 minutes - Audio 5-30 min : 3-10 minutes - Audio >30 min : 10-20 minutes **Coût** : + - **MVP** : 0€ (CPU standard, processing asynchrone) - **Scale** : 50-200€/mois (GPU VPS si >1000 signalements/jour) **Justification** : + - 100% open source, pas de dépendance GAFAM - Coût maîtrisé (scaling progressif) - Gain productivité modérateurs ×3-5 @@ -112,10 +120,12 @@ Liste déroulante avec 7 options : | **BASSE** | <72h (jours ouvrés) | Qualité audio, tags incorrects → Modérateur junior | **Traitement automatique** : + - Score IA >95% + catégorie évidente (ex: spam répété) → Action automatique immédiate - Notification créateur + possibilité d'appel **Justification** : + - Réaliste et conforme DSA (Digital Services Act) - Scalable : priorisation automatique - Ressources humaines optimisées @@ -133,17 +143,20 @@ Priorité = (Score_IA × 0.7) + (Signalements_cumulés × 0.2) + (Fiabilité_sig ``` **Détails** : + - **Score_IA** : 0-100% (confiance analyse automatique) - **Signalements_cumulés** : nombre de signalements du même contenu (boost priorité) - **Fiabilité_signaleur** : score utilisateur (historique signalements pertinents) **Classification résultante** : + - Priorité ≥90 → **CRITIQUE** (traitement immédiat) - Priorité 70-89 → **HAUTE** (file prioritaire) - Priorité 40-69 → **MOYENNE** (file normale) - Priorité <40 → **BASSE** (file différée) **Justification** : + - Optimise le temps des modérateurs - Traite les cas graves en priorité - Coût : 0€ (algorithme simple) @@ -186,11 +199,13 @@ L'équipe RoadWave ``` **Coût** : + - Email : ~0.001€/notification (Brevo, Resend) - Push : 0€ (APNS / FCM natifs) - In-app : 0€ **Justification** : + - Conformité DSA (transparence obligatoire) - Multi-canal garantit réception - Coût négligeable @@ -232,6 +247,7 @@ L'équipe RoadWave ``` **Justification** : + - Transparence maximale (obligation DSA) - Créateur comprend l'erreur → amélioration future - Réduit les appels non fondés @@ -243,6 +259,7 @@ L'équipe RoadWave **Décision** : Formulaire in-app structuré **Accès** : + - Bouton "Contester cette décision" dans notification - Section "Mes sanctions" dans profil créateur @@ -256,15 +273,18 @@ L'équipe RoadWave | **Preuves** | Upload fichiers (max 5, 10 MB total) | ❌ | **Après soumission** : + - Génération numéro de ticket unique (ex: `#MOD-2026-00142`) - Email confirmation : "Votre appel sera traité sous 72h" - Statut visible dans l'app : "En cours d'examen" **Délai de soumission** : + - Maximum **7 jours** après notification de sanction - Après 7 jours : appel automatiquement refusé **Justification** : + - Professionnel et traçable - Intégration complète avec système modération - Coût : 0€ (formulaire custom backend) @@ -284,6 +304,7 @@ L'équipe RoadWave | **Critique** | 24h (cas suspension longue/ban) | Admin modération | **Notification intermédiaire** (si délai >72h) : + - Email J+3 : "Votre appel #MOD-XXX est en cours d'examen approfondi. Réponse sous 2 jours." **Réponse finale** : @@ -295,10 +316,12 @@ Email détaillé avec : 4. **Définitif** : mention "Cette décision est définitive" (pas de second appel) **Suivi in-app** : + - Mise à jour statut : "Appel accepté ✓" ou "Appel rejeté ✗" - Badge notification **Justification** : + - Équilibre entre rapidité et qualité de traitement - Conforme pratiques industrie (YouTube, TikTok : 5-7 jours) - Ressources humaines réalistes @@ -329,6 +352,7 @@ Email détaillé avec : 5. **Fil d'activité** : actions récentes équipe (temps réel) **Coût infrastructure** : + - MVP : 0-50€/mois (serveur CPU) - Scale : 50-200€/mois (GPU + Redis Cluster) @@ -337,20 +361,24 @@ Email détaillé avec : ### 14.5 Modération préventive (rappel) **Nouveaux créateurs** : + - Validation manuelle des **3 premiers contenus** - Délai : 24-48h (jours ouvrés) - Transcription automatique pour aide modérateur **Score de confiance** : + - Évolution dynamique selon historique - Créateur fiable (0 strike depuis 6 mois) → validation automatique - Créateur suspect (strikes récents) → validation manuelle systématique **Publicités** : + - Validation manuelle obligatoire 24-48h (responsabilité juridique) - Transcription + analyse métadonnées (ciblage, durée, volume) **Justification** : + - Prévention > réaction (économie modération) - Qualité plateforme préservée dès le début @@ -375,11 +403,13 @@ Email détaillé avec : **Coût total MVP** : **0-200€/mois** (infrastructure IA optionnelle) **Conformité** : + - ✅ DSA (Digital Services Act) : transparence, traçabilité, délais - ✅ RGPD : données modération anonymisées après 3 ans - ✅ Logs audit : toutes actions tracées (obligation légale plateforme) **Scalabilité** : + - 0-1000 signalements/mois : équipe 1-2 modérateurs junior + 1 senior - 1000-10K signalements/mois : équipe 5-10 modérateurs + IA GPU - 10K+ signalements/mois : équipe dédiée + IA optimisée + modération communautaire diff --git a/docs/domains/moderation/states/signalement-lifecycle.md b/docs/domains/moderation/states/signalement-lifecycle.md index 49711c0..dc66fa3 100644 --- a/docs/domains/moderation/states/signalement-lifecycle.md +++ b/docs/domains/moderation/states/signalement-lifecycle.md @@ -64,6 +64,7 @@ stateDiagram-v2 ## Légende **États principaux** : + - **Reçu** : Signalement initial (<1s) - **EnTranscription** : Whisper large-v3 (1-20 min) - **EnAnalyseIA** : Score confiance 0-100% (<1 min) diff --git a/docs/domains/monetization/README.md b/docs/domains/monetization/README.md index bfacbf0..fcf126d 100644 --- a/docs/domains/monetization/README.md +++ b/docs/domains/monetization/README.md @@ -22,6 +22,7 @@ Le domaine **Monetization** gère la monétisation des créateurs de contenu via ## Ubiquitous Language **Termes métier du domaine** : + - **Creator Monetization** : Activation de la monétisation pour un créateur - **KYC Verification** : Vérification d'identité requise pour versements - **Revenue Share** : Partage de revenus (70% créateur / 30% plateforme) diff --git a/docs/domains/monetization/rules/monetisation-createurs.md b/docs/domains/monetization/rules/monetisation-createurs.md index 172d7a7..ba6d435 100644 --- a/docs/domains/monetization/rules/monetisation-createurs.md +++ b/docs/domains/monetization/rules/monetisation-createurs.md @@ -5,6 +5,7 @@ **Décision** : ❌ Fonctionnalité abandonnée pour le MVP **Raisons** : + - Complexité juridique (collecte pour compte de tiers, TVA variable) - Frais de transaction élevés sur petits montants (Mangopay ~1.8% + 0.18€) - UX additionnelle à développer (wallet, transactions, confirmations) @@ -29,11 +30,13 @@ **Vérification** : Automatique via requêtes SQL lors de la demande d'activation **Affichage** : + - Bouton "Demander la monétisation" dans profil créateur - Si critères non remplis → affichage progression vers objectifs - Si critères remplis → redirection vers KYC Mangopay **Justification** : + - **Anti-fraude** : Le délai de 3 mois permet de détecter les comptes suspects - **Qualité** : Seuls les créateurs sérieux avec audience réelle sont monétisés - **Coût administratif** : Réduit le nombre de comptes à gérer (KYC, comptabilité, virements) @@ -46,6 +49,7 @@ **Décision** : Statut juridique professionnel obligatoire **Statuts acceptés** : + - Auto-entrepreneur (micro-BNC pour artistes/créateurs de contenu) - SARL/SAS/SASU (sociétés) @@ -64,17 +68,20 @@ **Délai** : 24-72h si documents conformes **Rejet possible si** : + - Documents invalides/illisibles - Identité ne correspond pas au compte RoadWave - Liste noire anti-blanchiment (vérification automatique Mangopay) - RIB non professionnel (particulier) **Base légale** : + - **Conformité fiscale** : L'État français impose déclaration revenus >1200€/an (DAS2) - **Anti-blanchiment** : Directive EU 2018/843 (5ème directive LCB-FT) - **RGPD** : Données hébergées EU via Mangopay (conforme) **Justification** : + - **Responsabilité légale** : RoadWave doit pouvoir prouver identité réelle créateurs monétisés - **Automatisation** : Mangopay gère tout (KYC, vérifications, conformité, e-wallets) - **KYC gratuit** : inclus dans l'offre Mangopay (vs 1.20€ chez Stripe) @@ -101,16 +108,19 @@ Publicité facturée par RoadWave : 0.05€/écoute complète = 50€ CPM ``` **Exemple concret** : + - 10 000 écoutes/mois → créateur touche **30€** - 50 000 écoutes/mois → créateur touche **150€** - 100 000 écoutes/mois → créateur touche **300€** **Comparaison industrie** : + - YouTube : 3-5€/1000 vues - Spotify : 3-4€/1000 écoutes - RoadWave : 3€/1000 écoutes (aligné) **Règles comptabilisation** : + - ✅ Écoute complète = ≥80% du contenu écouté - ✅ Utilisateur gratuit uniquement - ❌ Écoutes Premium ne comptent pas ici (autre système) @@ -130,6 +140,7 @@ Utilisateur Premium = 4.99€/mois └─ 1.50€ gardés par plateforme (30%) Si l'utilisateur écoute 3 créateurs ce mois : + - Créateur A : 10h d'écoute (50%) → 1.75€ - Créateur B : 6h d'écoute (30%) → 1.05€ - Créateur C : 4h d'écoute (20%) → 0.70€ @@ -151,12 +162,14 @@ GROUP BY creator_id; ``` **Comparaison industrie** : + - YouTube Premium : 70/30 - Spotify : 70/30 - Apple Music : 52/48 (moins avantageux) - RoadWave : 70/30 (standard) **Justification** : + - **Standard industrie** : ratio équitable éprouvé - **Incitation qualité** : créateurs les plus écoutés gagnent plus - **Équité** : pas de "winner takes all", chaque créateur écouté reçoit sa part @@ -178,6 +191,7 @@ GROUP BY creator_id; - Solde conservé **indéfiniment** SI créateur actif - Critère activité : >0 écoute/mois OU connexion dashboard/mois + - Solde visible en temps réel dans dashboard créateur **Créateur inactif** (0 écoute/mois + 0 connexion dashboard) : @@ -191,11 +205,13 @@ GROUP BY creator_id; | **18 mois + 37j** | Purge données comptables | (Conservation logs 10 ans RGPD) | **Exception soldes <10€** : + - Si solde <10€ après 18 mois → Frais bancaires (0.36€) > 3.6% du montant - Proposition email : "Don association ou conservation jusqu'à 50€" - Si don refusé + inactivité continue → versement forcé quand même (équité) **Frais bancaires assumés par créateur** : + - Mangopay SEPA : 1.8% + 0.18€ - Exemple : 45€ → versement **44.64€** net - Transparence totale dans email préavis @@ -215,6 +231,7 @@ Votre solde actuel : XX.XX€ → Montant net estimé : XX.XX€ 💡 Pour éviter le versement anticipé : + - Publiez un nouveau contenu, OU - Connectez-vous à votre dashboard créateur @@ -234,6 +251,7 @@ L'équipe RoadWave | **Frais bancaires** | ❓ Non documenté | Déduits + annoncés | ✅ RoadWave transparent | **Justification** : + - **Plus équitable que Twitch** : versement forcé au lieu de forfeiture (créateur récupère son argent) - **Emails préventifs** : 3 relances (12 mois, 18 mois, 18 mois + 30j) avant action - **Transparence** : frais bancaires annoncés clairement dans emails @@ -253,6 +271,7 @@ L'équipe RoadWave | **16-18 du mois suivant** | Réception virement (1-3 jours ouvrés SEPA) | **Virement via Mangopay** : + - SEPA pour comptes EU (gratuit, 1-3 jours) - Virement international hors EU (frais variables selon pays, rare en pratique) - **E-wallets automatiques** : chaque créateur possède un wallet Mangopay où ses revenus sont transférés automatiquement @@ -281,27 +300,32 @@ L'équipe RoadWave **Décision** : Créateur décide individuellement pour chaque contenu **Fonctionnement** : + - Toggle "Réservé Premium" lors création/édition contenu - **Aucune limite imposée** : créateur peut mettre 0%, 50% ou 100% en premium - Badge 👑 visible sur interface utilisateur **Comportement utilisateurs gratuits** : + - Contenu premium visible dans liste/algo - Tentative lecture → overlay bloquant - Message : "Ce contenu est réservé aux abonnés Premium" - CTA : "Passez Premium pour 4.99€/mois" **Comportement algorithme** : + - Contenus premium inclus dans recommandations - Si user gratuit → contenu skippé automatiquement (ne consomme pas de slot) - Si user premium → diffusé normalement **Métadonnées** : + - Champ `is_premium` (boolean) en base - Index sur ce champ pour requêtes rapides - Cache Redis : `content:{id}:premium` (TTL 1h) **Justification** : + - **Liberté créateur** : chaque créateur choisit sa stratégie (freemium, tout gratuit, tout premium) - **Incitation Premium** : contenu exclusif = argument fort pour s'abonner - **Équité** : un petit créateur peut tout mettre en premium, un gros peut tout offrir gratuitement @@ -330,6 +354,7 @@ L'équipe RoadWave > Bien que le seuil légal DAS2 soit 1200€/an, rien n'interdit de déclarer les montants inférieurs. Au contraire, cela renforce la transparence et protège RoadWave en cas de contrôle fiscal. **Avantages** : + - ✅ **Conformité maximale** : aucune zone grise - ✅ **Protection juridique RoadWave** : traçabilité totale - ✅ **Simplicité technique** : même processus pour tous @@ -344,6 +369,7 @@ Objet : Votre déclaration fiscale 2026 RoadWave Bonjour [Créateur], Vos revenus RoadWave 2026 ont été déclarés aux impôts (DAS2) : + - Revenus publicité : XXX.XX€ - Revenus Premium : XXX.XX€ - Total déclaré : XXX.XX€ @@ -358,12 +384,14 @@ L'équipe RoadWave ``` **Créateur responsable de** : + - Déclarer ses revenus à l'URSSAF (cotisations sociales auto-entrepreneur ou IS/IR) - Déclarer ses revenus aux impôts (IR ou IS selon statut) - Gérer sa TVA si applicable (franchise en base jusqu'à ~37K€/an en micro-BNC) - Conserver justificatifs **10 ans** (obligation légale comptable) **Mangopay transmet automatiquement** : + - Données aux autorités fiscales EU via **DAC7** (directive 2021/514) - Justificatif de chaque virement (preuve bancaire pour comptabilité créateur) @@ -376,6 +404,7 @@ Si créateur a touché 2500€ en 2026 : ``` **Justification** : + - **Conformité légale** : RoadWave doit déclarer revenus versés (DAS2, DAC7) - **Responsabilité fiscale** : Le créateur reste responsable de sa déclaration (impossible de gérer pour lui) - **Automatisation** : Minimise charge administrative côtés créateur et plateforme @@ -385,6 +414,7 @@ Si créateur a touché 2500€ en 2026 : ### 9.8 Désactivation et suspension monétisation **Créateur peut** : + - Désactiver temporairement (vacances, pause création) - Réactiver sans refaire KYC si données à jour (<2 ans) - Solde conservé pendant désactivation @@ -399,16 +429,19 @@ Si créateur a touché 2500€ en 2026 : | **Fraude détectée** | Suspension immédiate + enquête | Cas par cas | **Suppression définitive si** : + - Demande du créateur (solde versé sous 30 jours) - Inactivité 24 mois + solde <50€ (purge RGPD) - Ban définitif compte (Strike 4) **Notification** : + - Email + in-app pour toute suspension - Raison explicite fournie - Procédure de réactivation indiquée **Justification** : + - **Flexibilité** : créateur peut faire pause sans perdre statut - **Sécurité** : plateforme doit pouvoir suspendre en cas problème légal/technique - **RGPD** : suppression auto données inactives après délai raisonnable diff --git a/docs/domains/premium/README.md b/docs/domains/premium/README.md index 321d074..5fe18c6 100644 --- a/docs/domains/premium/README.md +++ b/docs/domains/premium/README.md @@ -24,6 +24,7 @@ Le domaine **Premium** gère les abonnements payants et les fonctionnalités exc ## Ubiquitous Language **Termes métier du domaine** : + - **Premium Subscription** : Abonnement payant mensuel ou annuel - **Offline Download** : Téléchargement pour écoute hors-ligne - **Sync Queue** : File d'attente de synchronisation offline diff --git a/docs/domains/premium/rules/abonnements-notifications.md b/docs/domains/premium/rules/abonnements-notifications.md index 4aa2268..8481725 100644 --- a/docs/domains/premium/rules/abonnements-notifications.md +++ b/docs/domains/premium/rules/abonnements-notifications.md @@ -5,6 +5,7 @@ **Décision** : Boost +30% au score + reste dans le mix **Boost de score abonnements** : + - **+30% au score final** pour contenus d'un créateur suivi - Application : multiplicateur sur le score calculé @@ -13,6 +14,7 @@ score_final_avec_boost = score_final × 1.3 ``` **Reste dans le mix** : + - ❌ **Pas de priorité absolue** (pas de file dédiée abonnements) - ✅ Contenu suivi entre en **compétition avec autres contenus** - ✅ Si créateur suivi publie contenu faible engagement → peut être battu par contenu viral non-suivi @@ -22,12 +24,14 @@ score_final_avec_boost = score_final × 1.3 Utilisateur à Paris, 2 contenus disponibles : Contenu A (créateur NON suivi) : + - Score géo : 0.9 (très proche) - Score intérêts : 0.8 - Score engagement : 0.7 → Score final : 0.80 Contenu B (créateur suivi) : + - Score géo : 0.5 (moyennement proche) - Score intérêts : 0.6 - Score engagement : 0.5 @@ -45,6 +49,7 @@ Contenu B (suivi) : score 0.60 → avec boost 0.78 ``` **Justification** : + - **Équilibre** : valorise abonnements sans enfermer utilisateur - **Découverte** : contenus viraux/locaux peuvent toujours émerger - **Prévisible** : boost fixe, pas de logique opaque @@ -104,16 +109,19 @@ Tap pour explorer ``` **Filtrage géographique** : + - Si contenu/live hors zone utilisateur → **pas de notification** - Évite frustration : "notification pour contenu que je ne peux pas écouter" - Exception : contenu national → notifie tous les abonnés **Fréquence maximale** : + - **Maximum 10 notifications push/jour** par utilisateur (tous types confondus) - Si dépassement : notifications regroupées - Message groupé : "🎧 3 nouveaux contenus de créateurs suivis" **Plages horaires** : + - **Mode silencieux** : 22h-8h (pas de push, sauf live) - Paramétrable utilisateur (désactivation totale possible) - Option "Notifications importantes uniquement" (lives uniquement) @@ -129,6 +137,7 @@ Tap pour explorer | **Limite quotidienne** | 10 | Modifiable 5-20 | **Justification** : + - **Sécurité routière** : pas de push en conduite (distraction) - **Engagement piéton** : push actifs pour audio-guides (valeur ajoutée tourisme) - **Pas de spam** : limite 10/jour + mode silencieux @@ -207,10 +216,12 @@ Liste des séquences : | **Quitter** | Tap "×" | Sauvegarde progression, sortie guide | **Guidage vocal automatique** : + - Entre 2 séquences : "Vous avez terminé la séquence 2. Dirigez-vous vers la Vénus de Milo pour la séquence 3." - Si utilisateur s'éloigne (>50m de la prochaine pièce) : "Vous vous éloignez de la prochaine étape. Consultez le plan." **Sauvegarde progression** : + - Position dans guide sauvegardée automatiquement - Retour ultérieur : "Reprendre à la séquence 5 ?" ou "Recommencer depuis le début" - Historique : guide marqué "Terminé" si toutes séquences écoutées @@ -251,6 +262,7 @@ Liste des séquences : ``` **Justification** : + - **UX piéton** : navigation tactile adaptée (pas de commandes volant) - **Autonomie** : utilisateur maître de son rythme (pas d'enchaînement forcé) - **Choix** : plusieurs guides = diversité styles (famille, expert, rapide) @@ -264,6 +276,7 @@ Liste des séquences : **Décision** : 200 abonnements max + désabonnement -5% jauges **Nombre maximum d'abonnements** : + - **200 créateurs maximum** par utilisateur - Raisons : - **Évite spam** : au-delà de 200, notifications ingérables @@ -271,16 +284,19 @@ Liste des séquences : - **Performance** : requêtes SQL optimisées (index sur 200 max) **Si limite atteinte** : + - Message : "Vous suivez déjà 200 créateurs. Désabonnez-vous d'un créateur pour en suivre un nouveau." - Liste triable : par date abonnement, nb contenus écoutés, dernière activité - Suggestion : "Vous n'avez pas écouté [Créateur X] depuis 6 mois, le désabonner ?" **Abonnement initial** : + - Impact : **+5% toutes jauges tags du créateur** (voir [Règle 05 - Section 5.3](../../recommendation/rules/interactions-navigation.md#actions-complémentaires-mode-piéton-uniquement)) - Action : Bouton "S'abonner" dans profil créateur (interface mobile) - Immédiat à l'action **Désabonnement** : + - Impact : **-5% toutes jauges tags du créateur** (symétrique) - Action : Bouton "Se désabonner" dans profil créateur - Immédiat à l'action @@ -300,15 +316,18 @@ Abonnement : ``` **Gestion multi-tags** : + - Si créateur a 3 tags → **+5% sur chacun des 3 tags** - Logique : abonnement = signal fort d'affinité à TOUS les sujets du créateur **Abonnements réciproques** : + - ❌ **Pas d'abonnement mutuel visible** - Créateur ne voit pas qui est abonné (privacy) - Créateur voit uniquement : nombre total abonnés (métrique globale) **Justification** : + - **Limite 200** : équilibre entre liberté et gestion spam - **Symétrie +5%/-5%** : cohérence mathématique, prévisibilité - **Privacy** : pas de liste publique abonnés (évite stalking) diff --git a/docs/domains/premium/rules/mode-offline.md b/docs/domains/premium/rules/mode-offline.md index 583eb47..f2765f4 100644 --- a/docs/domains/premium/rules/mode-offline.md +++ b/docs/domains/premium/rules/mode-offline.md @@ -5,6 +5,7 @@ **Zone géographique** : Choix manuel utilisateur **Options prédéfinies** : + - "Autour de moi" (rayon 50 km position actuelle) - "Ma ville" (limite administrative détectée) - "Mon département" (sélection liste) @@ -19,6 +20,7 @@ | **Premium** | Illimité | "245 contenus (3.2 GB)" | **Calcul temps disponible** : + - 50 contenus × 5 min moyenne = 250 min = **4h d'écoute** (suffisant pour gratuits) - Premium illimité = limité uniquement par espace disque device @@ -47,6 +49,7 @@ Exemple : 20 contenus × 5 min × 48 kbps = ~72 MB | **Haute** | 64 kbps | ~30 MB/h | **Premium uniquement** | **Justification** : + - Standard = bon compromis qualité/taille (Opus 48 kbps = très correct pour voix) - Haute réservée Premium = incitation upgrade - User peut réduire à "basse" si espace limité @@ -58,6 +61,7 @@ Exemple : 20 contenus × 5 min × 48 kbps = ~72 MB **Durée de validité** : 30 jours après téléchargement **Standard industrie** : + - Spotify : 30 jours - YouTube Music : 30 jours - Deezer : 30 jours @@ -77,11 +81,13 @@ App détecte WiFi + contenus >25 jours ``` **Notification avant expiration** : + - **J-3** : "X contenus expirent dans 3 jours. Connectez-vous en WiFi pour les renouveler" - **J-0** : Suppression automatique - **J+0** : Toast "15 contenus expirés ont été supprimés" **Justification** : + - **Force reconnexion** : vérifier abonnement actif, contenus légaux - **Évite stockage obsolète** : contenus supprimés/modérés ne restent pas - **UX transparente** : renouvellement silencieux si WiFi régulier @@ -91,6 +97,7 @@ App détecte WiFi + contenus >25 jours ### 11.3 Synchronisation actions offline **Actions stockées localement (SQLite)** : + - Likes/unlikes - Abonnements/désabonnements - Signalements @@ -108,11 +115,13 @@ App détecte WiFi + contenus >25 jours ``` **Gestion erreurs sync** : + - Si échec après 3 tentatives → notification : "Impossible de synchroniser. Réessayez plus tard" - Actions conservées jusqu'à sync réussie (pas de perte) - **Rétention max 7 jours** : après = purge (évite queue infinie) **Justification** : + - **Pas de conflit possible** : actions unilatérales user (likes/abonnements) - **UX fluide** : pas de blocage offline - **Batch = économie** : requêtes HTTP groupées @@ -187,17 +196,20 @@ User se reconnecte (WiFi détecté) ``` **Bouton "Voir la liste"** : + - Affiche titres + créateurs des contenus supprimés - Permet comprendre ce qui a disparu - Historique conservé 7 jours (puis purge) **Justification KISS** : + - ✅ **Simplicité technique** : pas de grace period complexe, pas de gestion d'états intermédiaires - ✅ **Respect créateur** : si créateur supprime = volonté claire immédiate, pas de diffusion prolongée - ✅ **Conformité légale** : contenu modéré (illégal, violation CGU) retiré immédiatement, pas de risque juridique - ✅ **Cas rare** : peu de créateurs suppriment contenus après publication, impact user limité **Post-MVP** : Si feedback négatifs users ("J'étais en train d'écouter et ça s'est coupé brutalement !"), ajouter grace period UNIQUEMENT pour suppression créateur volontaire : + - Motif suppression = "modération RoadWave" → Suppression immédiate (sécurité/légalité) - Motif suppression = "créateur volontaire" → Grace period 7 jours + badge "Bientôt retiré" - Motif suppression = "passage Premium" → Si user Premium : conserve accès, si gratuit : grace period 7j diff --git a/docs/domains/premium/rules/premium.md b/docs/domains/premium/rules/premium.md index 690c480..4413211 100644 --- a/docs/domains/premium/rules/premium.md +++ b/docs/domains/premium/rules/premium.md @@ -12,6 +12,7 @@ **❌ Pas d'essai gratuit** **Raisons** : + - **Anti-abus vacances** : évite inscriptions opportunistes (essai 14j avant road trip vacances, puis annulation) - **Protection revenus créateurs** : les écoutes Premium rémunèrent créateurs dès jour 1 - **Simplicité** : pas de gestion période trial + conversion @@ -20,6 +21,7 @@ **❌ Pas de partage familial (MVP)** **Raisons** : + - Complexité technique (gestion invitations, validation liens, limite devices) - Risque abus ("familles" de 6 inconnus) - Coût dev/support élevé pour ROI incertain @@ -27,6 +29,7 @@ - **Post-MVP** : Si forte demande, offre "Famille" à 9.99€/mois pour 5 comptes **Justification tarif** : + - **Aligné marché bas** : Spotify = 10.99€, YouTube Premium = 11.99€, Apple Music = 10.99€ - **Prix accessible** : cible conducteurs quotidiens (budget raisonnable) - **Incitation annuel** : 2 mois offerts = engagement long terme + réduction churn @@ -100,6 +103,7 @@ Device 1 vraiment offline (mode avion, tunnel) ``` **Boutons** : + - **Reprendre ici** : Coupe l'autre device, reprend lecture sur ce device - **Sécuriser mon compte** : Lien vers changement mot de passe + déconnexion tous devices @@ -119,6 +123,7 @@ Contenus téléchargés valides 30 jours #### Détection abus (post-MVP) Monitoring patterns suspects (backend analytics) : + - >10 changements devices/jour (suspect) - Connexions alternées 2 villes éloignées répétées - Signalements users : "je n'ai jamais été à Marseille" @@ -131,6 +136,7 @@ Action : **Pas d'action automatique** (évite faux positifs), juste flag modération manuelle. **Justification KISS** : + - ✅ **Simplicité technique** : pas de tracking GPS précis, pas de calcul distances, pas de faux positifs (TGV Paris→Lyon = légitime) - ✅ **Assume bonne foi** : majorité users honnêtes, partage compte = minorité, gestion réactive suffit - ✅ **Message dissuasif clair** : avertissement CGU dans message coupure, possibilité "Sécuriser compte" si suspicion piratage @@ -144,12 +150,14 @@ Action : **Décision** : Créateur décide (déjà couvert section 9.6) **Rappel règles** : + - Toggle "Réservé Premium" par contenu - Aucune limite de ratio gratuit/premium - Badge 👑 visible - Users gratuits : lecture bloquée avec CTA "Passez Premium" **Impact algorithme** : + - Contenus premium inclus dans recommandations - Si user gratuit → skip automatique (ne consomme pas slot) - Si user premium → diffusé normalement selon score @@ -169,10 +177,12 @@ Action : | **Historique écoute** | 100 derniers | Illimité | **Qualité audio** : + - Gratuit : 48 kbps Opus (~20 MB/h) = très correct pour voix - Premium : 64 kbps Opus (~30 MB/h) = excellente qualité **Justification différences** : + - **0 pub** = argument principal (confort écoute) - **Qualité audio** = avantage tangible audiophiles - **Offline illimité** = use case road trips longs @@ -191,23 +201,27 @@ Action : | **Android App** | Google Play Billing | 5.99€ | 30% (Google) | **Majoration mobile (5.99€)** : + - Apple/Google prennent 30% de commission - RoadWave majore prix de 20% pour compenser - **Incitation web** : Email aux users "Abonnez-vous sur roadwave.com pour 4.99€/mois" (38% moins cher en frais !) **Renouvellement automatique** : + - Email rappel **7 jours avant** renouvellement - Email confirmation **après** renouvellement réussi - Retry automatique si échec paiement (3 tentatives sur 7 jours) - Annulation automatique après 3 échecs **Annulation** : + - Self-service dans Settings app : "Abonnement > Annuler" - Accès Premium maintenu jusqu'à **fin période payée** - Pas de remboursement prorata (standard industrie) - Email confirmation annulation avec date fin d'accès **Réabonnement** : + - Possibilité immédiate - ❌ Pas de nouvelle période d'essai (pas d'essai du tout) @@ -235,6 +249,7 @@ CREATE TABLE subscriptions ( ``` Cache Redis : premium:{user_id} → boolean (TTL 1h) Refresh via webhooks : + - Mangopay : PAYIN_NORMAL_SUCCEEDED, PAYIN_NORMAL_FAILED - Apple : App Store Server Notifications - Google : Real-time Developer Notifications diff --git a/docs/domains/recommendation/README.md b/docs/domains/recommendation/README.md index a6b6887..d3266a5 100644 --- a/docs/domains/recommendation/README.md +++ b/docs/domains/recommendation/README.md @@ -31,6 +31,7 @@ Le domaine **Recommendation** gère le système de recommandation de contenus ba ## Ubiquitous Language **Termes métier du domaine** : + - **Interest Gauge** : Jauge de centre d'intérêt (score de 0 à 100) - **Interest Category** : Catégorie d'intérêt (automobile, voyage, musique, etc.) - **Recommendation Score** : Score combinant distance géographique et affinité d'intérêt diff --git a/docs/domains/recommendation/features/recommendation/README.md b/docs/domains/recommendation/features/recommendation/README.md index 524a0e3..ddc1cde 100644 --- a/docs/domains/recommendation/features/recommendation/README.md +++ b/docs/domains/recommendation/features/recommendation/README.md @@ -204,6 +204,7 @@ godog run features/recommendation/scoring-recommandation.feature --tags=@calcul ## CI/CD Ces tests sont exécutés : + - ✅ Avant chaque release - ✅ Sur les PRs modifiant l'algorithme de recommandation - ✅ Nightly builds (tous les tests) diff --git a/docs/domains/recommendation/rules/algorithme-recommandation.md b/docs/domains/recommendation/rules/algorithme-recommandation.md index d593de7..43e4643 100644 --- a/docs/domains/recommendation/rules/algorithme-recommandation.md +++ b/docs/domains/recommendation/rules/algorithme-recommandation.md @@ -11,11 +11,13 @@ | **Géo-neutre** | Universel, pas de lien géo | Podcast philosophie, musique | 20% | **Qui décide** : + - ✅ Créateur choisit le type à la publication - ✅ Modération peut reclassifier après validation - ✅ Modification possible après publication (tout le monde a le droit de se tromper) **Justification** : + - Différencie audio-guide (hyper-local) des podcasts génériques - Algorithme adapte automatiquement la pondération - Coût : champ supplémentaire en DB + règle algo @@ -33,6 +35,7 @@ score_final = (score_geo * poids_geo_type) + (bonus_aleatoire) où : + - score_geo = 1 - (distance_km / distance_max_km) - score_interets = moyenne des jauges utilisateur pour les tags du contenu - score_engagement = (taux_completion * 0.5) + (ratio_likes * 0.3) + (ratio_abonnements * 0.2) @@ -42,6 +45,7 @@ où : #### Calcul détaillé du score_interets **Domaine des données** : + - Jauges utilisateur : stockées en pourcentage [0-100] - score_interets : normalisé dans l'intervalle [0.0-1.0] pour pondération @@ -50,6 +54,7 @@ où : score_interets = (SUM(gauge_values_for_tags) / NB_TAGS) / 100 où : + - gauge_values_for_tags = valeurs des jauges correspondant aux tags du contenu - NB_TAGS = nombre de tags du contenu (minimum 1, maximum 3) - Division par 100 pour normaliser [0-100] → [0.0-1.0] @@ -61,6 +66,7 @@ Contenu : "Visite du Louvre" Tags : ["Musique", "Tourisme"] Utilisateur : + - Jauge "Musique" = 75% - Jauge "Tourisme" = 60% - Jauge "Automobile" = 40% (non pertinente, ignorée) @@ -79,6 +85,7 @@ score_final = (score_geo * 0.5) + (score_interets * 0.3) + (score_engagement * 0 ``` **Cas limites** : + - Utilisateur n'a aucune jauge pour les tags du contenu → score_interets = 0.5 (valeur neutre par défaut) - Contenu avec 1 seul tag → score_interets = gauge_value / 100 - Jauges multiples → moyenne arithmétique simple (pas de pondération différente par tag) @@ -93,6 +100,7 @@ score_final = (score_geo * 0.5) + (score_interets * 0.3) + (score_engagement * 0 | Géo-neutre | 0.2 | 0.6 | **Paramètres** : + - Distance max recommandée : **200 km** - Dégradation : **linéaire** (1 - distance/200km) - Rayon point GPS : **500m** (adapté au volume de contenu local) @@ -100,6 +108,7 @@ score_final = (score_geo * 0.5) + (score_interets * 0.3) + (score_engagement * 0 **Tous ces paramètres sont configurables à chaud via interface admin.** **Justification** : + - Flexibilité totale selon type de contenu - Linéaire = rattrapage naturel du contenu viral ancien - Auditable via métriques engagement (moyenne/médiane) @@ -111,6 +120,7 @@ score_final = (score_geo * 0.5) + (score_interets * 0.3) + (score_engagement * 0 **Décision** : Intégration popularité avec poids 0.2 **Métriques** : + - **Taux de complétion** : écoutes >80% / total écoutes pertinentes (poids 0.5) - **Ratio likes** : likes / écoutes (poids 0.3) - **Ratio abonnements** : nouveaux abonnés après écoute / écoutes (poids 0.2) @@ -145,19 +155,23 @@ GROUP BY content_id; ``` **Seuil minimum** : + - Minimum **50 écoutes pertinentes** avant de considérer l'engagement - Contenu <50 écoutes : score engagement = 0.5 (neutre) **Contenu viral** : + - Un contenu viral à Paris **peut** être proposé à Marseille - Score géo faible compensé par score engagement élevé - Paramétrable admin **Dépréciation temporelle** : + - Pas de dépréciation automatique - Ratio linéaire = contenu ancien mais toujours apprécié reste pertinent **Justification** : + - Équilibre découverte / qualité - **Protection créateur** : abonnés fidèles ne pénalisent pas les métriques - **Anti-raid naturel** : skips via search/direct_link ne comptent pas (raid inefficace) @@ -172,16 +186,19 @@ GROUP BY content_id; **Décision** : 10% par défaut, paramétrable utilisateur **Fonctionnement** : + - 1 contenu sur 10 = tirage aléatoire (hors historique déjà écouté) - Utilisateur peut ajuster : curseur 0% (aucun aléatoire) à 50% (exploration max) **Curseur utilisateur** : + - 🎯 **0%** : Personnalisé max (recommandations strictes) - ⚖️ **10%** : Équilibré (défaut) - 🎲 **30%** : Découverte élevée - 🌍 **50%** : Découverte max (équivaut à national = découverte) **Justification** : + - Évite la bulle de filtre - Laisse l'utilisateur maître de son expérience - Coût : variable aléatoire en algo @@ -195,23 +212,27 @@ GROUP BY content_id; **Décision MVP** : Tag simple "Politique" sans classification idéologique **Tagging** : + - Créateur peut taguer son contenu comme "Politique" (optionnel) - Tag "Politique" au même niveau que "Économie", "Sport", "Culture", etc. - **Pas de classification gauche/droite** - **Pas d'équilibrage imposé** **Filtrage utilisateur** : + - Option paramètres : **"Masquer contenu politique"** - Si activé → 0% de contenus tagués "Politique" dans le feed - Par défaut : désactivé (tous contenus visibles) **Justification MVP** : + - **Simplicité** : Pas de modération politique coûteuse (~2000€/mois économisés) - **Neutralité technique** : Aucun jugement éditorial sur orientation - **Risque minimal** : Évite controverses et contentieux DSA au lancement - **Fonctionnel** : Utilisateurs peuvent filtrer si souhaité **Post-MVP** : + - Classification avancée possible si forte demande utilisateurs - Nécessite ressources modération dédiées et audit DSA @@ -230,22 +251,26 @@ GROUP BY content_id; | **13-15 ans** | Collège | Contenus "Tous publics" uniquement | Filtrage 16+ et 18+ | **Activation** : + - ❌ **Pas d'activation automatique** (tous les utilisateurs ont ≥13 ans) - ✅ **Activation manuelle** via toggle paramètres - ✅ Parents peuvent activer pour leurs enfants 13-15 ans - ✅ Utilisateur peut désactiver à tout moment **Filtrage quand Mode Kids activé** : + - ✅ Contenus "Tous publics" uniquement - ❌ Exclusion contenus 16+ et 18+ - ❌ Pas de contenu politique (automatiquement filtré) - ❌ Pas de publicité (ou uniquement pub validée manuellement) **Interface** : + - Interface standard (pas d'interface dédiée enfants pour MVP) - Filtrage algorithmique des contenus inappropriés **Justification** : + - **Conformité légale** : Âge minimum 13 ans (RGPD, DSA) - **Simplicité MVP** : Un seul mode optionnel vs 4 tranches d'âge - **Protection mineurs** : Filtrage contenus adultes pour 13-15 ans @@ -266,15 +291,18 @@ GROUP BY content_id; 6. Si ignoré → contenu proposé normalement en file d'attente **Publicités** : + - ⚠️ **Jamais d'interruption** de contenu en cours - Pub s'intercale **entre deux séquences** uniquement - Notification pub : son différent (facultatif selon paramètres) **Gestion demi-tour** : + - Si utilisateur repart du point après notification → pas de nouvelle notification (déjà proposé) - Réinitialisation après 24h **Justification** : + - Respect écoute en cours (pas de coupure brutale) - UX fluide (utilisateur garde contrôle) - Simplicité technique (pas de prédiction trajectoire) @@ -295,17 +323,20 @@ GROUP BY content_id; | **Partiellement écouté** | 10-80% | Peu importe | ✅ Reproposer avec reprise position (`last_position_seconds`) | **Stockage historique** : + - Table `user_content_history` (user_id, content_id, creator_id, **is_subscribed**, completion_rate, last_position, listened_at) - Historique **illimité** (PostgreSQL) - Algorithme considère les **100 derniers** pour optimisation requêtes - Export complet disponible (RGPD) **Colonne `is_subscribed`** : + - Booléen stockant si l'utilisateur était abonné au créateur **au moment de l'écoute** - Permet de distinguer les skips d'abonnés (contextuels) des skips de non-abonnés (désintérêt) - Utilisé pour décisions de reproposition et calculs d'engagement **Justification** : + - Découverte maximale (pas de redites) - **Cohérence abonnement** : un skip ponctuel d'un abonné ≠ rejet du créateur (peut être contextuel : "pas maintenant", "pas ce sujet", "mauvais timing") - Respect erreurs de clic (contenu partiel = 2nde chance) @@ -331,23 +362,27 @@ GROUP BY content_id; | `seuil_min_ecoutes_engagement` | 10 - 200 | 50 | nb | **Application changements** : + - Immédiat : nouveaux calculs utilisent nouvelle config - Aucun recalcul batch (coût CPU) - Version config trackée (git-like) - Rollback 1 clic **A/B Testing** : + - Création variantes (Config A vs Config B) - Split utilisateurs 50/50 aléatoire - Métriques comparatives : taux complétion, engagement, session duration - Dashboard graphique temps réel **Audit engagement** : + - Métriques clés : moyenne/médiane temps d'écoute par session - Graphiques : évolution engagement selon config - Export CSV pour analyse externe **Justification** : + - Optimisation continue sans redéploiement - Data-driven decisions (métriques objectives) - Coût : dashboard admin à développer (one-time) @@ -361,26 +396,31 @@ GROUP BY content_id; **Niveaux de personnalisation** : **Curseurs disponibles** : + - 📍 **Géolocalisation** : Local ← slider → National (découverte = national) - 🎲 **Découverte** : 0% ← slider → 50% (part aléatoire) - ⚖️ **Politique** : Masquer / Équilibré / Mes préférences **Profils sauvegardables** : + - 🚗 Trajet quotidien (boulot) : géo local, découverte 5%, politique masqué - 🛣️ Road trip : géo régional, découverte 30%, politique équilibré - 👶 Enfants : Mode Kids activé **Synchronisation** : + - ✅ Sync profils entre devices (cloud PostgreSQL) - ❌ Pas de partage profils entre utilisateurs (famille) - Auto-switch selon context (détection trajet récurrent via GPS) **Sécurité conduite** : + - ⚠️ **Blocage modification si vitesse GPS >10 km/h** - Warning au lancement app : "Configurez avant de prendre la route" - Modifications uniquement app arrêtée/passager **Justification** : + - Utilisateur maître de son expérience - Contextes d'usage différents (quotidien vs voyage) - Sécurité routière (pas de distraction) @@ -392,25 +432,30 @@ GROUP BY content_id; **Décision** : Ouverture aux médias établis **Médias autorisés** : + - Presse nationale : Le Monde, Le Parisien, Libération, Le Figaro, etc. - Radios : France Inter, RTL, Europe 1, etc. - Médias régionaux : Ouest-France, Sud-Ouest, etc. **Format contenus** : + - Flashs info géolocalisés (actualité régionale) - Chroniques thématiques (culture, économie, sport) - Éditos et débats (classification politique appliquée) **Validation** : + - Compte média vérifié (badge ✓) - Pas de validation 3 premiers contenus (confiance établie) - Modération a posteriori uniquement **Monétisation** : + - Partage revenus pub standard (même conditions créateurs) - Possibilité sponsoring direct (pas via plateforme) **Justification** : + - Crédibilité plateforme (contenus professionnels) - Diversité éditoriale - Attractivité grand public (noms reconnus) diff --git a/docs/domains/recommendation/rules/centres-interet-jauges.md b/docs/domains/recommendation/rules/centres-interet-jauges.md index c3305ed..33fa61b 100644 --- a/docs/domains/recommendation/rules/centres-interet-jauges.md +++ b/docs/domains/recommendation/rules/centres-interet-jauges.md @@ -17,6 +17,7 @@ **Note importante** : Les pourcentages indiqués sont des **points de pourcentage absolus**, **PAS des pourcentages relatifs**. **Calcul** : + - Si jauge "Automobile" = 45% - Like renforcé (+2%) → 45 + 2 = **47%** ✅ - **NOT** 45 × 1.02 = 45.9% ❌ @@ -24,6 +25,7 @@ Cette approche garantit une **progression linéaire** et **équitable** pour tous les utilisateurs, indépendamment de leur niveau actuel dans une jauge. **Paramètres techniques** : + - Les jauges sont bornées strictement entre **0% et 100%** - Calcul immédiat à chaque action (pas de batch différé) - Les tags du contenu sont définis par le créateur à la publication @@ -61,6 +63,7 @@ Scénario 5 : Skip après 5s (ABONNÉ au créateur) ``` **Justification** : + - **Like automatique** : Reflète l'engagement réel (voir [Règle 05 - Section 5.3](interactions-navigation.md#53-interactions-au-volant--like-automatique-et-engagement)) - **Sécurité routière** : Pas d'action complexe en conduite - **Prévisibilité** : Règles claires et déterministes @@ -78,11 +81,13 @@ Scénario 5 : Skip après 5s (ABONNÉ au créateur) **Décision** : Démarrage neutre à 50%, pas de questionnaire **À l'inscription** : + - Toutes les jauges d'intérêt sont initialisées à **50%** - Pas de questionnaire onboarding (friction zéro) - L'algorithme apprend naturellement via les premières écoutes **Catégories disponibles** : + - Automobile - Voyage - Famille @@ -104,12 +109,14 @@ Scénario 5 : Skip après 5s (ABONNÉ au créateur) 4. Après 10-15 écoutes, profil commence à se dessiner clairement **Alternative optionnelle (post-MVP)** : + - Questionnaire **optionnel** proposé après 3 écoutes (in-app) - Message : "Améliorez vos recommandations en sélectionnant vos centres d'intérêt" - Si rempli : jauges sélectionnées passent à 70%, non sélectionnées à 30% - Si skip : conserve 50% partout **Justification** : + - **Inscription ultra-rapide** : pas de questionnaire = moins de churn - **Découverte naturelle** : l'algorithme apprend en quelques écoutes - **Équitable** : pas de biais initial vers certains créateurs @@ -125,6 +132,7 @@ Scénario 5 : Skip après 5s (ABONNÉ au créateur) Les jauges **ne diminuent jamais** avec le temps de manière automatique. **Règle** : + - Une jauge ne change **que par les actions utilisateur** (like, écoute, skip) - Pas de cron job de dégradation périodique - Pas de "rafraîchissement" artificiel @@ -138,16 +146,19 @@ Utilisateur aimait "Économie" (jauge 80%) il y a 1 an ``` **Si utilisateur inactif longtemps** : + - Utilisateur part en vacances 6 mois → jauges conservées - Au retour : ses jauges reflètent toujours ses goûts d'avant - Comportement cohérent et prévisible **Alternative utilisateur (contrôle explicite)** : + - Bouton "Réinitialiser mes centres d'intérêt" dans paramètres - Action manuelle : remet toutes les jauges à 50% - Permet nouveau départ si souhaité (changement de vie, etc.) **Justification** : + - **Principe KISS** (Keep It Simple, Stupid) - **Coût 0** : pas de batch nocturne, pas de calculs temporels - **Fiabilité maximale** : pas de bugs de fuseaux horaires, dates, etc. diff --git a/docs/domains/recommendation/rules/interactions-navigation.md b/docs/domains/recommendation/rules/interactions-navigation.md index 24297e4..76cc771 100644 --- a/docs/domains/recommendation/rules/interactions-navigation.md +++ b/docs/domains/recommendation/rules/interactions-navigation.md @@ -5,6 +5,7 @@ **Décision** : Pré-calcul 5 contenus avec insertion prioritaire pour points géographiques **File d'attente** : + - **5 contenus pré-calculés** en cache (Redis) - Recalcul automatique si : - Déplacement >10km @@ -14,12 +15,14 @@ **Insertion prioritaire géo-ancrée (mode voiture uniquement)** : **Détection** : + - Calcul ETA (Estimated Time of Arrival) via API GPS native iOS/Android - Notification déclenchée **7 secondes avant** d'arriver au point GPS - Si vitesse < 5 km/h ET distance < 50m → notification immédiate - ⚠️ **App doit être ouverte** (pas de détection en arrière-plan en mode voiture) **Notification** : + - **Sonore uniquement** : bip court ou son personnalisé RoadWave - **Visuelle minimale** : icône selon type de contenu (🏛️ culture, 👨‍👩‍👧 famille, 🎵 musique, etc.) - **Compteur visible** : 7...6...5...4...3...2...1 (décompte des secondes) @@ -34,19 +37,23 @@ 5. À la fin du décompte → contenu géolocalisé démarre (fade out/in 0.3s) **Si user n'appuie pas sur "Suivant"** : + - Notification disparaît après 7 secondes - Contenu géolocalisé est perdu (pas d'insertion dans file) - Pas de nouveau contenu géolocalisé pendant **10 minutes** (éviter spam) **Limitation anti-spam** : + - Maximum **6 contenus géolocalisés par heure** - Timer reset toutes les heures (rolling window) - Exception : séquences d'un même audio-guide multi-séquences (comptent comme 1) - Si quota atteint : notifications suivantes ignorées jusqu'à libération du quota **Invalidation immédiate** : + - Utilisateur change ses préférences (curseurs géo/découverte/politique) - ⚠️ **Modification bloquée si vitesse GPS >10 km/h** (sécurité routière) + - Live démarre d'un créateur suivi dans la zone **Implémentation** : @@ -76,6 +83,7 @@ Cooldown après ignorance (Redis) : ``` **Justification** : + - **Expérience fluide** : pas de latence au clic "Suivant" - **Réactivité géo** : contenu local inséré immédiatement - **Coût optimisé** : recalcul uniquement si nécessaire @@ -88,12 +96,14 @@ Cooldown après ignorance (Redis) : **Décision** : Notifications push en arrière-plan avec rayon large **Contexte** : + - Mode piéton détecté automatiquement si vitesse moyenne < 5 km/h - Cas d'usage : visites à pied, musées, monuments, quartiers historiques - User n'a pas besoin d'avoir l'app ouverte - ⚠️ **Fonctionnalité optionnelle** : requiert permission "localisation en arrière-plan" (activée par user) **Détection** : + - App peut être en arrière-plan (si permission accordée) - Rayon de détection : **200 mètres** autour du point GPS - Geofencing iOS/Android pour minimiser consommation batterie @@ -119,12 +129,14 @@ Musée du Louvre : La Joconde - @paris_museum ⚠️ **Important** : RoadWave utilise une **stratégie de permissions progressive** pour maximiser l'acceptation utilisateur et la validation stores. **Étape 1 - Permission de base (tous utilisateurs)** : + - iOS : "Allow While Using App" (`locationWhenInUse`) - Android : `ACCESS_FINE_LOCATION` - **Demandée** : Au premier lancement (onboarding) - **Permet** : Mode voiture complet ✅ **Étape 2 - Permission arrière-plan (optionnelle, mode piéton uniquement)** : + - iOS : "Allow Always" (`locationAlways`) - Android : `ACCESS_BACKGROUND_LOCATION` - **Demandée** : Uniquement si user active "Notifications audio-guides piéton" dans settings @@ -132,6 +144,7 @@ Musée du Louvre : La Joconde - @paris_museum - **Permet** : Mode piéton avec notifications push en arrière-plan ✅ **Si permission arrière-plan refusée** : + - Mode piéton **désactivé** (toggle grisé dans settings) - Mode voiture reste **pleinement fonctionnel** - Audio-guides accessibles en mode **manuel** (user ouvre app, lance contenu) @@ -188,6 +201,7 @@ Android (`AndroidManifest.xml`) : ``` **Si user refuse** : + - Mode piéton désactivé (uniquement mode voiture disponible) - App fonctionne normalement avec permission "When In Use" - Audio-guides accessibles en mode manuel (user ouvre app, sélectionne contenu) @@ -201,6 +215,7 @@ Android (`AndroidManifest.xml`) : **Basculement automatique voiture ↔ piéton** : Détection par vitesse GPS moyenne sur 30 secondes : + - Vitesse < 5 km/h (stable 10s) → mode piéton - Vitesse ≥ 5 km/h (stable 10s) → mode voiture @@ -212,15 +227,18 @@ Changements de mode : | Voiture | < 5 km/h | Piéton | Notifications sonores → push arrière-plan | **Pas de popup confirmation** : + - Basculement transparent et automatique - User n'a rien à faire - Hysteresis (10s) pour éviter basculements intempestifs **Quota anti-spam mode piéton** : + - Même limitation que mode voiture : **6 contenus/heure** - Cooldown 10 min si notification ignorée (app pas ouverte après tap) **Justification** : + - ✅ Expérience adaptée aux visites à pied (rayon large, pas de timing précis) - ✅ Économie batterie (geofencing natif iOS/Android) - ✅ User peut garder téléphone en poche @@ -241,6 +259,7 @@ Changements de mode : | **Premier de session** | N/A | Replay depuis début (rien avant) | **Historique de navigation** : + - **10 contenus maximum** en mémoire (Redis List) - Structure : `[{content_id, position_seconds, listened_at}, ...]` - FIFO : au-delà de 10, suppression du plus ancien @@ -257,11 +276,13 @@ Utilisateur écoute : ``` **Interface (responsabilité front)** : + - ❌ Pas de message UI - ✅ Progress bar revient au début ou à position exacte - ✅ Animation fluide (transition 0.3s) **Justification** : + - **UX intuitive** : comportement standard Spotify/YouTube - **Pas de frustration** : si début, vraiment revenir en arrière - **Simplicité** : règle unique (seuil 10s) @@ -273,6 +294,7 @@ Utilisateur écoute : **Décision** : Like automatique basé sur le temps d'écoute **Problème technique identifié** : + - iOS et Android ne supportent **pas nativement** les appuis longs ou doubles-appuis sur les commandes média - Les commandes physiques au volant varient selon les véhicules (pas de bouton "Pause" dédié sur beaucoup de modèles) - Système de double-appui/appui long = **non-intuitif** et **risques sécurité** (regarder écran pour feedback) @@ -309,12 +331,14 @@ Utilisateur écoute : **Exemples concrets** : ``` Contenu de 3 minutes (180s) : + - Écoute 2min30 (83%) → Like renforcé (+2 points) - Écoute 1min15 (42%) → Like standard (+1 point) - Écoute 30s (17%) puis skip → Pas de like - Skip après 5s → Signal négatif (-0.5 point) Contenu de 15 minutes (900s) : + - Écoute 13min (87%) → Like renforcé (+2 points) - Écoute 6min (40%) → Like standard (+1 point) ``` @@ -334,11 +358,13 @@ Contenu de 15 minutes (900s) : | **Signalement** | Menu contextuel "⋮" | Ouverture flux modération | **Feedback visuel** : + - **Like automatique** : Badge discret "♥ Ajouté à vos favoris" (2s, bas de l'écran) - **Like explicite** : Animation cœur rouge + vibration courte - **Abonnement** : Animation étoile dorée + badge "Abonné ✓" **Disponibilité** : + - ✅ Mode piéton (vitesse < 5 km/h) : toutes les actions disponibles - ❌ Mode voiture (vitesse ≥ 5 km/h) : aucune de ces actions (sauf like automatique) @@ -347,17 +373,20 @@ Contenu de 15 minutes (900s) : #### Gestion impacts jauges (algorithme) **Like automatique** : + - Like renforcé (≥80%) → **+2% jauges** de tous les tags du contenu - Like standard (30-79%) → **+1% jauges** des tags du contenu - Signal négatif (skip <10s) → **-0.5% jauges** des tags du contenu **Actions explicites** : + - Like manuel → **+2% jauges** (cumulable avec like auto) - Unlike → **-2% jauges** - Abonnement → **+5% toutes jauges** tags créateur - Désabonnement → **-5% toutes jauges** **Persistance** : + - Événements stockés en base (table `listen_events`) - Mise à jour jauges : **immédiate** (Redis) + **async batch** (PostgreSQL) @@ -431,6 +460,7 @@ class AudioPlayerManager { #### Justification **Avantages** : + - ✅ **Sécurité routière maximale** : aucune action complexe au volant - ✅ **UX intuitive** : comportement standard industrie (Spotify, YouTube Music, Deezer) - ✅ **Compatibilité 100%** : fonctionne sur tous véhicules, tous OS @@ -439,6 +469,7 @@ class AudioPlayerManager { - ✅ **Simplicité développement** : pas de workarounds complexes iOS/Android **Inconvénients mitigés** : + - ⚠️ Pas de like explicite en conduite → **Mitigation** : like automatique + vocal (CarPlay/Android Auto) - ⚠️ Pas d'abonnement en conduite → **Mitigation** : liste "Créateurs à découvrir" dans app - ⚠️ Like automatique peut surprendre → **Mitigation** : onboarding clair + unlike possible @@ -502,6 +533,7 @@ Utilisez les boutons au volant : - Persiste : Redis (immédiat) + PostgreSQL (batch async) **Séparation des responsabilités** : + - ✅ **Calculation** : Logique métier pure (réutilisable pour auto-like, skip, actions manuelles) - ✅ **Update** : Persistance et contraintes techniques @@ -516,6 +548,7 @@ newValue := currentValue * (1 + adjustment/100) // NE PAS FAIRE ``` **Persistance** : + - **Redis** : Mise à jour immédiate (latence <10ms) - **PostgreSQL** : Batch async toutes les 5 minutes (cohérence finale) - Raison : Jauges consultées fréquemment (recommandations temps réel) @@ -541,12 +574,14 @@ newValue := currentValue * (1 + adjustment/100) // NE PAS FAIRE | **Live** | 0 seconde | Enchaînement immédiat | **Insertion publicité** : + - Pub s'insère **pendant le délai de 2s** (transition naturelle) - Fréquence : **paramétrable admin** (défaut : 1 pub / 5 contenus) - Message : "Publicité (15s)" puis lecture pub - ⚠️ **Jamais d'interruption** d'un contenu en cours **Publicité skippable** : + - Durée minimale visionnage : **paramétrable** (défaut : 5 secondes) - Bouton "Passer" apparaît après délai - Métriques engagement : taux skip, durée écoute moyenne @@ -559,11 +594,13 @@ newValue := currentValue * (1 + adjustment/100) // NE PAS FAIRE 4. Sinon → lecture en pause, attente action utilisateur **Gestion erreurs** : + - Échec chargement contenu suivant → **retry 3× avec backoff exponentiel** - Si 3 échecs → message "Connexion instable, basculement mode offline" - Mode offline → lecture contenus téléchargés uniquement **Justification** : + - **Fluidité** : enchaînement naturel sans action utilisateur - **Contrôle** : possibilité annuler pendant délai - **Paramétrabilité pub** : évite frustration excès publicité diff --git a/docs/legal/cgu.md b/docs/legal/cgu.md index 0c3e754..b4d7e74 100644 --- a/docs/legal/cgu.md +++ b/docs/legal/cgu.md @@ -23,6 +23,7 @@ Les présentes Conditions Générales d'Utilisation (CGU) régissent l'utilisation de la plateforme RoadWave, réseau social audio géolocalisé. RoadWave permet aux utilisateurs : + - **Auditeurs** : écouter du contenu audio contextuel géolocalisé - **Créateurs** : publier du contenu audio géolocalisé @@ -39,11 +40,13 @@ L'utilisation de la Plateforme implique l'acceptation pleine et entière des pr RoadWave se réserve le droit de modifier les CGU à tout moment. **Notification** : + - Email à tous les utilisateurs **14 jours avant** l'entrée en vigueur - Notification in-app au lancement suivant la modification - Version mise à jour disponible sur roadwave.fr/cgu **Refus des nouvelles CGU** : + - Utilisateur peut supprimer son compte dans les 14 jours - Utilisation continue = acceptation tacite @@ -67,6 +70,7 @@ RoadWave se réserve le droit de modifier les CGU à tout moment. ### 4.3 Responsabilité du compte L'utilisateur est responsable de : + - La confidentialité de ses identifiants - Toutes actions effectuées depuis son compte - Signalement immédiat en cas d'accès non autorisé @@ -74,6 +78,7 @@ L'utilisateur est responsable de : ### 4.4 Un compte par personne Création de comptes multiples interdite, sauf : + - Compte test (développeurs autorisés) - Demande explicite auprès de RoadWave @@ -84,6 +89,7 @@ Création de comptes multiples interdite, sauf : ### 5.1 Licence d'utilisation RoadWave accorde une licence **non exclusive, révocable, non transférable** pour : + - Accéder à la Plateforme - Écouter du contenu - Publier du contenu (créateurs) @@ -91,6 +97,7 @@ RoadWave accorde une licence **non exclusive, révocable, non transférable** po ### 5.2 Interdictions générales Il est interdit de : + - Utiliser la Plateforme à des fins illégales - Tenter de contourner les mesures de sécurité - Utiliser des bots, scripts ou outils automatisés @@ -113,6 +120,7 @@ Il est interdit de : Voir **[Charte Créateur](charte-createur.md)** pour règles détaillées. **Résumé** : + - Contenus originaux ou droits acquis - Pas de contenu haineux, violent, illégal - Pas de musique protégée >30 secondes sans licence @@ -132,6 +140,7 @@ Voir **[Charte Créateur](charte-createur.md)** pour règles détaillées. ### 6.4 Responsabilité du créateur Le créateur garantit : + - Détenir tous les droits nécessaires - Ne pas violer de droits tiers (musique, marques, image) - Respecter les classifications d'âge @@ -146,44 +155,52 @@ Le créateur garantit : Sont strictement interdits : #### **Haine et violence** (Article 7.1.1) + - Incitation à la haine raciale, ethnique, religieuse - Discrimination sexiste, homophobe, transphobe - Apologie de crimes contre l'humanité - Menaces de violence physique #### **Contenu sexuel** (Article 7.1.2) + - Pornographie ou contenu sexuellement explicite - Contenu impliquant des mineurs (strictement interdit) - Sollicitation sexuelle #### **Illégalité** (Article 7.1.3) + - Apologie du terrorisme - Incitation aux actes criminels - Vente de produits illégaux (drogues, armes) - Pédopornographie → **ban immédiat + signalement autorités** #### **Droits d'auteur** (Article 7.1.4) + - Musique protégée en intégrale ou extraits >30 secondes - Films, séries, livres audio protégés - Diffusion de concerts, événements sportifs payants (lives) - **Exception** : extraits ≤30s pour critique/analyse (fair use) #### **Désinformation dangereuse** (Article 7.1.5) + - Fausses informations sur la santé (COVID, vaccins, traitements) - Fausses informations sur la sécurité routière - Manipulation électorale #### **Harcèlement** (Article 7.1.6) + - Menaces répétées envers une personne - Doxxing (publication informations privées) - Intimidation, chantage #### **Fraude** (Article 7.1.7) + - Arnaques, escroqueries - Pyramides de Ponzi, MLM illégaux - Phishing, vol d'identité #### **Spam** (Article 7.1.8) + - Publicité non autorisée (hors système pub RoadWave) - Répétition de contenus identiques - Liens vers sites externes de spam @@ -191,6 +208,7 @@ Sont strictement interdits : ### 7.2 Modération **Délais de traitement** : + - CRITIQUE (violence, suicide) : <2h (24/7) - HAUTE (haine, harcèlement) : <24h - MOYENNE (spam) : <48h @@ -212,10 +230,12 @@ Sont strictement interdits : ### 8.2 Exceptions **Tolérance 1ère fois (droits d'auteur uniquement)** : + - Avertissement sans strike si première violation musique protégée - Explication pédagogique + lien vers règles **Violations graves (pas de tolérance)** : + - Haine, violence → Strike 1 immédiat - Contenu illégal (terrorisme, pédopornographie) → Strike 4 (ban) + signalement autorités @@ -243,6 +263,7 @@ Créateur a Strike 2 ### 8.5 Notification des sanctions **Multi-canal** (email + push + in-app) : + - Catégorie violée (référence article CGU) - Raison détaillée (langage clair) - Extrait audio concerné (timestamp) @@ -297,6 +318,7 @@ Tout utilisateur sanctionné peut contester la décision. Voir **[CGV Publicités](cgv-publicites.md)** **Résumé** : + - Interface self-service - Budget minimum : 50€ - Validation manuelle obligatoire (24-48h) @@ -309,6 +331,7 @@ Voir **[CGV Publicités](cgv-publicites.md)** Voir **[CGV Premium](cgv-premium.md)** **Résumé** : + - Prix : 4.99€/mois OU 49.99€/an - Avantages : 0 pub, contenus exclusifs 👑, qualité 64 kbps, offline illimité - Résiliation : à tout moment (effet fin période en cours) @@ -328,6 +351,7 @@ Voir **[CGV Premium](cgv-premium.md)** ### 12.2 KYC (Know Your Customer) Vérification obligatoire via Mangopay : + - SIRET, numéro TVA, RIB professionnel - Pièce d'identité - Kbis <3 mois (entreprises) @@ -335,10 +359,12 @@ Vérification obligatoire via Mangopay : ### 12.3 Revenus **Publicités** : + - 3€ / 1000 écoutes complètes - Représente ~6% du CA publicitaire **Premium** : + - 70% créateur, 30% plateforme - Proportionnel au temps d'écoute @@ -381,6 +407,7 @@ Voir **[Politique de confidentialité](politique-confidentialite.md)** pour dét ### 14.1 Propriété de la Plateforme RoadWave et tous ses éléments (code, design, logo, marque) sont protégés par : + - Droit d'auteur - Droit des marques - Droit sui generis des bases de données @@ -398,12 +425,14 @@ RoadWave et tous ses éléments (code, design, logo, marque) sont protégés par ### 14.3 Utilisation des contenus par RoadWave RoadWave peut : + - Diffuser les contenus aux auditeurs - Transcrire automatiquement (modération IA) - Générer segments HLS (streaming) - Promouvoir la Plateforme (captures d'écran, extraits marketing) RoadWave **ne peut pas** : + - Revendre les contenus à des tiers - Modifier substantiellement les contenus (hors transcoding technique) @@ -420,6 +449,7 @@ RoadWave **ne peut pas** : ### 15.2 Résiliation par RoadWave RoadWave peut suspendre ou supprimer un compte en cas de : + - Violation grave des CGU - Strike 4 (ban définitif) - Activité frauduleuse @@ -428,15 +458,18 @@ RoadWave peut suspendre ou supprimer un compte en cas de : ### 15.3 Conséquences de la résiliation **Contenus créateurs** : + - Dépubliés immédiatement - Marqués "Utilisateur supprimé" (anonymisation) - Fichiers audio supprimés sous 48h **Abonnement Premium** : + - Pas de remboursement au prorata - Accès jusqu'à fin période payée **Revenus créateurs** : + - Solde <50€ → perdu - Solde ≥50€ → virement final sous 30 jours @@ -447,6 +480,7 @@ RoadWave peut suspendre ou supprimer un compte en cas de : ### 16.1 Disponibilité de la Plateforme RoadWave s'efforce d'assurer une disponibilité 24/7 mais : + - **Aucune garantie** de disponibilité continue - Maintenances programmées notifiées 48h avant - Interruptions d'urgence possibles sans préavis @@ -456,6 +490,7 @@ RoadWave s'efforce d'assurer une disponibilité 24/7 mais : RoadWave n'est **pas responsable** des contenus publiés par les créateurs. **Modération** : + - Validation 3 premiers contenus (nouveaux créateurs) - Modération a posteriori (créateurs vérifiés) - Réactivité <24-48h après signalement @@ -463,11 +498,13 @@ RoadWave n'est **pas responsable** des contenus publiés par les créateurs. ### 16.3 Limitation de dommages RoadWave ne peut être tenu responsable de : + - Perte de données (sauvegardes régulières recommandées) - Perte de revenus créateurs (indisponibilité temporaire) - Dommages indirects ou consécutifs **Plafond** : + - Responsabilité limitée aux **12 derniers mois d'abonnement Premium** (auditeurs) - Responsabilité limitée aux **revenus perçus sur 12 derniers mois** (créateurs) @@ -482,6 +519,7 @@ Les présentes CGU sont régies par le **droit français**. ### 17.2 Médiation Avant toute action judiciaire, l'utilisateur doit tenter une **médiation** : + - Médiateur de la consommation : [NOM MÉDIATEUR] - Plateforme européenne ODR : https://ec.europa.eu/consumers/odr @@ -508,6 +546,7 @@ L'absence d'exercice d'un droit par RoadWave ne constitue pas une renonciation. --- **Contact** : + - Email : support@roadwave.fr - Adresse : [ADRESSE SIÈGE SOCIAL] - SIRET : [SIRET] diff --git a/docs/legal/cgv-premium.md b/docs/legal/cgv-premium.md index 9472a46..129ef87 100644 --- a/docs/legal/cgv-premium.md +++ b/docs/legal/cgv-premium.md @@ -23,6 +23,7 @@ Complète les **[CGU](cgu.md)** (Article 11). | **Annuel** | 49.99€/an | ~17% (4.16€/mois effectif) | **Tarif IAP (In-App Purchase iOS/Android)** : + - Mensuel : 5.99€/mois (+20% commission Apple/Google) - Annuel : 59.99€/an @@ -50,11 +51,13 @@ Complète les **[CGU](cgu.md)** (Article 11). ### 3.1 Modalités **Via web (Mangopay)** : + - Carte bancaire (Visa, Mastercard, Amex) - Prélèvement SEPA (si mensuel) - Paiement sécurisé 3D Secure **Via mobile (IAP)** : + - App Store (iOS) : Apple Pay, carte bancaire - Google Play (Android) : Google Pay, carte bancaire @@ -64,6 +67,7 @@ Complète les **[CGU](cgu.md)** (Article 11). - **Annuel** : renouvellement 1 an après souscription **Notification avant renouvellement** : + - Email **7 jours avant** renouvellement - Rappel : résiliation possible à tout moment @@ -88,17 +92,20 @@ Résiliation : 15 janvier ### 4.2 Par RoadWave RoadWave peut résilier si : + - Échec paiement (3 tentatives) - Violation grave CGU (Strike 4 = ban) - Fraude détectée (carte volée, etc.) **Notification** : + - Email **48h avant** résiliation - Possibilité mise à jour moyen paiement ### 4.3 Remboursement **Aucun remboursement** sauf : + - Bug empêchant utilisation service >7 jours consécutifs - Résiliation par RoadWave (erreur de notre part) @@ -133,6 +140,7 @@ RoadWave peut résilier si : - **Droit de résiliation** sans frais pendant ces 30 jours **Protection abonnés annuels** : + - Tarif gelé jusqu'à fin période annuelle - Nouveau tarif appliqué au prochain renouvellement annuel @@ -156,6 +164,7 @@ RoadWave peut résilier si : 5. Si échec final → **suspension Premium** **Suspension** : + - Accès Premium désactivé - Passage compte gratuit (avec pubs) - Réactivation possible sous 30 jours (mise à jour carte) @@ -165,11 +174,13 @@ RoadWave peut résilier si : ## 8. Rétractation (14 jours) **Droit de rétractation UE** : + - **14 jours** après souscription - Demande via : support@roadwave.fr - Remboursement intégral sous 14 jours **Exception** : + - Si utilisation service pendant 14 jours = renonciation au droit de rétractation - Acceptation explicite à la souscription diff --git a/docs/legal/cgv-publicites.md b/docs/legal/cgv-publicites.md index 503a25a..c30c731 100644 --- a/docs/legal/cgv-publicites.md +++ b/docs/legal/cgv-publicites.md @@ -51,6 +51,7 @@ Complète les **[CGU](cgu.md)** (Article 10). - **Critères** : conformité CGU, pas de contenu trompeur, respect ARPP **Refus si** : + - Contenu trompeur, illégal - Alcool, tabac (interdits) - Produits santé non autorisés @@ -106,6 +107,7 @@ Complète les **[CGU](cgu.md)** (Article 10). Accessible 24/7 : roadwave.fr/pub/dashboard **Métriques** : + - Impressions totales (nombre diffusions) - Taux d'écoute complète (%) - Taux de skip (%) @@ -128,6 +130,7 @@ Accessible 24/7 : roadwave.fr/pub/dashboard ### 7.2 Budget non consommé **Si campagne terminée avec budget restant** : + - <10€ : crédit conservé pour prochaine campagne - ≥10€ : remboursement automatique sous 14 jours @@ -154,6 +157,7 @@ Accessible 24/7 : roadwave.fr/pub/dashboard ### 9.1 Contenus prohibés Strictement interdits : + - Alcool, tabac, cannabis - Jeux d'argent (casinos, paris sportifs) - Produits pharmaceutiques sans autorisation @@ -174,6 +178,7 @@ Strictement interdits : ### 10.1 Annonceur L'annonceur garantit : + - Détenir droits sur contenu publicitaire (musique, voix, marques) - Conformité légale (ARPP, DGCCRF) - Véracité des informations (pas de publicité mensongère) @@ -181,6 +186,7 @@ L'annonceur garantit : ### 10.2 RoadWave RoadWave n'est pas responsable de : + - Performance commerciale de la pub (pas de garantie ventes) - Avis négatifs utilisateurs sur la pub diff --git a/docs/legal/charte-createur.md b/docs/legal/charte-createur.md index 6d044b4..a5304fa 100644 --- a/docs/legal/charte-createur.md +++ b/docs/legal/charte-createur.md @@ -25,11 +25,13 @@ Cette Charte complète les **[CGU](cgu.md)** (Articles 6 et 7) et détaille les ### 1.2 Critères de validation **Accepté si** : + - Qualité audio compréhensible - Métadonnées cohérentes (zone géo, tags, classification âge) - Pas de contenu prohibé évident **Refusé si** : + - Audio incompréhensible (grésillement excessif) - Musique protégée évidente en intégrale - Contenu haineux, violent, illégal @@ -62,16 +64,19 @@ Cette Charte complète les **[CGU](cgu.md)** (Articles 6 et 7) et détaille les | **Classification âge** | Tout public / 13+ / 16+ / 18+ | Obligatoire | **Tags disponibles** : + - Automobile, Voyage, Famille, Amour, Musique, Économie, Cryptomonnaie, Politique, Culture générale, Sport, Technologie, Santé ### 2.3 Cohérence métadonnées **Exemples incohérents** : + - "Histoire Tour Eiffel" en zone "National" (devrait être "Point GPS Paris") - Podcast enfants 3-6 ans classé "18+" (incohérent) - Contenu politique non tagué "Politique" **Exemples cohérents** : + - "Visite château Versailles" → Type Ancré, Point GPS Versailles, Tags Voyage + Culture - "Podcast auto route A7" → Type Contextuel, Zone Région Auvergne-Rhône-Alpes, Tag Automobile @@ -82,6 +87,7 @@ Cette Charte complète les **[CGU](cgu.md)** (Articles 6 et 7) et détaille les ### 3.1 Musique autorisée **Vous pouvez utiliser** : + - Votre propre musique originale (vous êtes compositeur/interprète) - Musique libre de droits (Epidemic Sound, Artlist, YouTube Audio Library, Creative Commons CC0) - Musique domaine public (>70 ans après mort auteur, ex: classique pré-1950) @@ -90,6 +96,7 @@ Cette Charte complète les **[CGU](cgu.md)** (Articles 6 et 7) et détaille les ### 3.2 Musique interdite **Strictement interdit** : + - Musique protégée en intégrale (titre complet) - Musique protégée en fond >30 secondes - Compilation DJ sans droits @@ -104,16 +111,19 @@ Cette Charte complète les **[CGU](cgu.md)** (Articles 6 et 7) et détaille les 4. Mention titre + artiste recommandée **Exemples OK** : + - Review album : extrait 20s + commentaire analyse musicale - Podcast histoire musique : extrait 25s + contexte historique **Exemples KO** : + - Fond musical hit radio 2 minutes (>30s) - Extrait 15s sans commentaire (pas d'usage transformatif) ### 3.4 Preuves licence Si vous utilisez musique payante (Epidemic Sound, Artlist) : + - Conservez factures/contrats - En cas de signalement, upload preuve via processus d'appel - Musique sera ajoutée à whitelist interne (évite futures erreurs) @@ -125,6 +135,7 @@ Si vous utilisez musique payante (Epidemic Sound, Artlist) : ### 4.1 Règles spécifiques **Interdictions strictes en live** : + - Diffusion concert/spectacle depuis la salle → Strike 2 immédiat (7 jours) - Événement sportif payant (match, compétition droits TV) → Strike 2 immédiat - Film, série, musique fond sans droits → Strike 1 (3 jours) @@ -177,6 +188,7 @@ Si vous utilisez musique payante (Epidemic Sound, Artlist) : ### 6.2 Si besoin de changer audio/zone/classification → **Supprimer contenu + republier** + - Si <3 contenus validés : retourne en file validation - Si ≥3 contenus validés : publication immédiate @@ -201,11 +213,13 @@ Si vous utilisez musique payante (Epidemic Sound, Artlist) : ### 7.2 Suspension monétisation **Suspension immédiate si** : + - Strike 3+ actif - Inactivité (aucun contenu publié depuis 6 mois) - Échec virement (RIB invalide, 3 tentatives) **Réactivation** : + - Après résolution strikes (réhabilitation 6 mois) - Après mise à jour RIB - Après publication nouveau contenu @@ -213,11 +227,13 @@ Si vous utilisez musique payante (Epidemic Sound, Artlist) : ### 7.3 Fermeture compte monétisé **Solde perdu si** : + - <50€ au moment de la fermeture - Ban définitif (Strike 4) - Inactivité 24 mois + solde <50€ **Virement final si** : + - ≥50€ → virement sous 30 jours après fermeture --- @@ -227,6 +243,7 @@ Si vous utilisez musique payante (Epidemic Sound, Artlist) : ### 8.1 Spam **Interdit** : + - Publier 10+ contenus identiques/similaires - Répéter contenu dans zones différentes (ex: même podcast publié 50 fois dans 50 villes) - Auto-promotion excessive (ex: "Abonnez-vous !" répété 20 fois) @@ -234,6 +251,7 @@ Si vous utilisez musique payante (Epidemic Sound, Artlist) : ### 8.2 Manipulation **Interdit** : + - Acheter des abonnés, likes, écoutes - Utiliser bots pour gonfler métriques - S'abonner massivement puis se désabonner (follow/unfollow spam) @@ -241,6 +259,7 @@ Si vous utilisez musique payante (Epidemic Sound, Artlist) : ### 8.3 Harcèlement **Interdit** : + - Créer contenu ciblant nommément une personne (harcèlement) - Publier informations privées d'un tiers (doxxing) - Menaces répétées @@ -262,12 +281,14 @@ Si vous utilisez musique payante (Epidemic Sound, Artlist) : ### 9.2 Conséquences strike **Suspension upload** : + - Strike 1 : **3 jours** sans possibilité de publier - Strike 2 : **7 jours** - Strike 3 : **30 jours** - Strike 4 : **Permanent** (ban définitif) **Pas d'impact sur** : + - Contenus déjà publiés (restent en ligne sauf si violents/illégaux) - Revenus en cours (virement mensuel maintenu) - Radio live (suspension upload = suspension live aussi) @@ -295,5 +316,6 @@ Si vous utilisez musique payante (Epidemic Sound, Artlist) : --- **Contact** : + - Email créateurs : createurs@roadwave.fr - Email général : support@roadwave.fr diff --git a/docs/legal/politique-confidentialite.md b/docs/legal/politique-confidentialite.md index d51ef61..86e4572 100644 --- a/docs/legal/politique-confidentialite.md +++ b/docs/legal/politique-confidentialite.md @@ -40,10 +40,12 @@ Email : dpo@roadwave.fr | **Geohash 5 (~5km²)** | Auto | Recommandations après 24h | Intérêt légitime | **Durée conservation GPS précis** : + - Historique personnel : **24h** puis agrégé en geohash 5 - Geohash : **conservé** pour analytics (anonymisé) **Révocation consentement** : + - Désactivation GPS dans paramètres → effet immédiat - Mode dégradé : contenus nationaux + neutres uniquement @@ -57,6 +59,7 @@ Email : dpo@roadwave.fr | **Logs techniques** (IP, user-agent) | Sécurité, anti-fraude | Intérêt légitime | **IP anonymisée** : + - Dernier octet masqué (ex: 192.168.1.XXX) - Conservation : 7 jours (sécurité) puis suppression @@ -122,6 +125,7 @@ RoadWave **ne vend jamais** vos données à des tiers. ### 4.4 Autorités Données transmises uniquement si : + - **Obligation légale** (réquisition judiciaire) - **Signalement contenu illégal** (terrorisme, pédopornographie) → autorités compétentes @@ -163,6 +167,7 @@ Données transmises uniquement si : - Après 30 jours : suppression définitive **Exceptions** (conservation nécessaire) : + - Logs modération : 3 ans (obligation DSA) - KYC créateurs : 5 ans (obligation fiscale) - Analytics agrégés (anonymisés) @@ -174,6 +179,7 @@ Données transmises uniquement si : - Lien téléchargement expire après **7 jours** **Contenu export** : + - Profil (pseudo, bio, stats) - Historique écoute complet - Centres d'intérêt (jauges) @@ -194,6 +200,7 @@ Données transmises uniquement si : ### 6.7 Réclamation CNIL Si désaccord avec RoadWave : + - **CNIL** (Commission Nationale de l'Informatique et des Libertés) - Site : https://www.cnil.fr/fr/plaintes - Adresse : 3 Place de Fontenoy, 75007 Paris @@ -218,6 +225,7 @@ Si désaccord avec RoadWave : ### 7.3 Violation de données En cas de fuite de données : + - Notification CNIL sous **72h** - Notification utilisateurs concernés (email) si risque élevé - Mesures correctives immédiates @@ -273,6 +281,7 @@ En cas de fuite de données : ### 10.1 Principe Données hébergées **exclusivement UE** : + - Serveurs : Hetzner (Allemagne) ou OVH (France) - Storage : OVH Object Storage (France) - Paiements : Mangopay (Luxembourg) @@ -280,6 +289,7 @@ Données hébergées **exclusivement UE** : ### 10.2 Exceptions **API tierces potentielles** (post-MVP) : + - Si transfert hors UE → clauses contractuelles types (CCT) - Notification utilisateurs avant activation @@ -296,6 +306,7 @@ Données hébergées **exclusivement UE** : ## 12. Contact DPO **Délégué à la Protection des Données** : + - Email : dpo@roadwave.fr - Délai réponse : **1 mois** (RGPD) diff --git a/docs/mobile/permissions-strategy.md b/docs/mobile/permissions-strategy.md index d1db4db..95e95b5 100644 --- a/docs/mobile/permissions-strategy.md +++ b/docs/mobile/permissions-strategy.md @@ -14,18 +14,21 @@ La géolocalisation est **critique** pour RoadWave, mais les permissions arrièr ### Problématiques Identifiées #### iOS App Store + - **Taux de rejet ~70%** si permission "Always Location" mal justifiée - Apple exige que l'app soit **pleinement utilisable** sans "Always Location" - Textes `Info.plist` scrutés manuellement par reviewers humains - Rejection si suspicion de tracking publicitaire ou vente de données #### Android Play Store + - Depuis Android 10 : `ACCESS_BACKGROUND_LOCATION` nécessite **déclaration justifiée** - Vidéo démo **obligatoire** montrant le flow de demande (< 30s) - Google vérifie que la permission est **réellement optionnelle** - Foreground service notification **obligatoire** en arrière-plan (Android 12+) #### RGPD (Règle 02) + - Permissions doivent être **optionnelles** - Utilisateur doit pouvoir **refuser sans pénalité** - App doit fonctionner en **mode dégradé acceptable** @@ -62,6 +65,7 @@ La géolocalisation est **critique** pour RoadWave, mais les permissions arrièr ## Étape 1 : Permission de Base (Onboarding) ### Quand + - **Premier lancement** de l'app - Avant de pouvoir utiliser les fonctionnalités principales @@ -109,6 +113,7 @@ La géolocalisation est **critique** pour RoadWave, mais les permissions arrièr ### Si Permission Refusée **Mode dégradé (IP2Location)** : + - Détection pays/ville via adresse IP (IP2Location Lite, voir [ADR-019](../adr/019-geolocalisation-ip.md)) - Contenus nationaux et régionaux disponibles - Pas de contenus hyperlocaux (< 10km) @@ -246,6 +251,7 @@ class LocationOnboardingScreen extends StatelessWidget { ## Étape 2 : Permission Arrière-Plan (Optionnelle) ### Quand + - User **active explicitement** "Notifications audio-guides piéton" dans Settings - **Jamais au premier lancement** @@ -547,6 +553,7 @@ class _NotificationsSettingsScreenState extends State85% - Taux acceptation permission "Always" : cible >40% - Taux rejet App Review : cible 0% @@ -785,10 +800,12 @@ void main() { **Durée** : 1 semaine **Checklist** : + - [ ] Upload build vers Play Console (Internal Testing) - [ ] Compléter déclaration permissions : - [ ] `ACCESS_BACKGROUND_LOCATION` justification - [ ] Upload vidéo démo (< 30s) + - [ ] Tester sur Android 10, 11, 12, 13, 14, 15 - [ ] Vérifier foreground notification visible (Android 12+) @@ -800,6 +817,7 @@ void main() { 5. Vérifier notification foreground service visible dans panneau notifications **Métriques collectées** : + - Consommation batterie mode piéton : cible <5% par heure - Taux crash background service : cible <0.1% @@ -843,6 +861,7 @@ void main() { ### Q4 : Combien de temps pour validation TestFlight/Play Store ? **R** : + - TestFlight : 24-48h (review Apple) - Play Console Internal Testing : Immédiat (pas de review) - Play Console Production : 3-7 jours (review Google) diff --git a/docs/mobile/testflight-validation-plan.md b/docs/mobile/testflight-validation-plan.md index 50f35f5..1988c1e 100644 --- a/docs/mobile/testflight-validation-plan.md +++ b/docs/mobile/testflight-validation-plan.md @@ -39,11 +39,13 @@ Semaine 6 : Validation finale + go/no-go production - [ ] `NSLocationAlwaysAndWhenInUseUsageDescription` ≤ 200 caractères - [ ] Pas de mention tracking/publicité - [ ] Mention explicite "optionnel" + - [ ] Vérifier `UIBackgroundModes` contient `location` - [ ] Build & Archive (Xcode) - [ ] Version : `1.0.0 (1)` (beta) - [ ] Bundle ID : `com.roadwave.app` - [ ] Signing : Distribution certificate + - [ ] Upload vers App Store Connect - [ ] Attendre processing (15-30 min) @@ -55,11 +57,13 @@ Semaine 6 : Validation finale + go/no-go production - [ ] `ACCESS_BACKGROUND_LOCATION` - [ ] `FOREGROUND_SERVICE` - [ ] `FOREGROUND_SERVICE_LOCATION` + - [ ] Vérifier foreground service déclaration - [ ] Build AAB (Android App Bundle) - [ ] Version : `1.0.0 (1)` - [ ] Package : `com.roadwave.app` - [ ] Signing : Release keystore + - [ ] Upload vers Play Console (Internal Testing) ### Documentation App Store Connect @@ -79,10 +83,12 @@ Users can use RoadWave fully without enabling background location - they will simply use the "car mode" which only requires location "while using". Background location is ONLY used for: + - Detecting proximity to audio-guide points of interest (200m radius) - Sending a single push notification to alert the user Background location is NEVER used for: + - Advertising or tracking - Selling data to third parties - Analytics beyond core functionality @@ -116,11 +122,13 @@ notifications push géolocalisées aux utilisateurs en mode piéton (touristes à pied). Usage précis : + - Geofencing radius 200m autour des points d'intérêt (monuments, musées) - Notification push unique lorsque l'utilisateur entre dans la zone - Permet découverte de contenus audio-guides sans ouvrir l'app Cette fonctionnalité est OPTIONNELLE : + - Demandée uniquement si utilisateur active "Mode piéton" dans Settings - Écran explicatif affiché AVANT demande permission système - L'app fonctionne pleinement sans cette permission (mode voiture disponible) @@ -128,12 +136,14 @@ Cette fonctionnalité est OPTIONNELLE : Foreground service notification visible (Android 12+) lorsque geofencing actif. Données de localisation : + - JAMAIS vendues ou partagées avec tiers - JAMAIS utilisées pour publicité ciblée - Anonymisées après 24h (conformité RGPD) ``` **Vidéo démo** (requis) : + - [ ] Enregistrer screen recording (25-30s) - [ ] Montrer activation mode piéton depuis Settings - [ ] Montrer écran d'éducation @@ -157,6 +167,7 @@ Données de localisation : | **External 2** | 20-30 | Grand public varié | Tests UX/acceptation réelle | **Configuration** : + - [ ] Créer groupe "Internal Testers" (accès immédiat) - [ ] Créer groupe "External Beta 1" (review Apple requise, 24-48h) - [ ] Créer groupe "External Beta 2" (après succès Beta 1) @@ -168,6 +179,7 @@ Données de localisation : **Durée** : 2-3 jours **Devices** : + - iPhone 12 (iOS 15) - iPhone 13 Pro (iOS 16) - iPhone 14 (iOS 17) @@ -325,10 +337,13 @@ analytics.logEvent( - Taux acceptation "When In Use" : `granted / requested` - Cible : >85% + - Taux activation mode piéton : `toggle_attempted / total_users` - Cible : >30% + - Taux acceptation "Always" : `always_granted / education_continued` - Cible : >40% + - Taux abandon education : `education_dismissed / education_shown` - Cible : <60% @@ -355,11 +370,13 @@ Si Apple **rejette** External Beta : ### Configuration Play Console Internal Testing **Testeurs** : + - [ ] Ajouter emails testeurs (max 100 pour Internal Testing) - [ ] Créer "testers list" dans Play Console - [ ] Share lien installation (pas de review Google pour Internal) **Devices** : + - Google Pixel 5 (Android 12) - Samsung Galaxy S21 (Android 13) - OnePlus 9 (Android 14) @@ -415,6 +432,7 @@ Then: ### Vidéo Démo Play Store **Enregistrement** : + - [ ] Device : Pixel 8 (Android 15, UI stock) - [ ] Screen recorder : Android natif (Game Toolbar) - [ ] Durée : 25-30s @@ -430,6 +448,7 @@ Then: 6. (22-25s) Retour Settings, toggle ON confirmé **Post-production** : + - [ ] Ajouter text overlays : "Utilisateur active mode piéton", "Écran explicatif affiché", etc. - [ ] Exporter MP4 < 50MB - [ ] Upload Play Console > Permissions > Background Location > Video demo @@ -462,6 +481,7 @@ Then: ### Décision Go/No-Go Production **Critères GO** (tous doivent être ✅) : + - [ ] Apple a approuvé External Beta TestFlight - [ ] Taux acceptation permission base iOS ≥ 80% - [ ] Taux acceptation permission base Android ≥ 80% @@ -488,6 +508,7 @@ Then: ### iOS App Store **Checklist soumission** : + - [ ] Build production uploadé (même code que TestFlight validé) - [ ] Version : `1.0.0 (1)` - [ ] Screenshots stores (5 minimum, incluant permissions flow) @@ -500,6 +521,7 @@ Then: **App Privacy (obligatoire iOS 14+)** : Location Data Collection : + - [ ] "Precise Location" : Yes - [ ] Purpose : "App Functionality" + "Product Personalization" - [ ] Linked to user : Yes @@ -507,6 +529,7 @@ Location Data Collection : - [ ] "Coarse Location" : No **Timing** : + - Review Apple : 24-48h (généralement) - Si rejet : corrections + re-soumission (24h) - **Total prévu** : 3-7 jours @@ -514,6 +537,7 @@ Location Data Collection : ### Android Play Store **Checklist soumission** : + - [ ] Build production (Release AAB) - [ ] Version : `1.0.0 (1)` - [ ] Screenshots (8 minimum) @@ -527,6 +551,7 @@ Location Data Collection : **Data Safety Form** : Location Data : + - [ ] "Approximate location" : No - [ ] "Precise location" : Yes - [ ] Purpose : "App functionality" + "Personalization" @@ -535,6 +560,7 @@ Location Data : - [ ] User can request deletion : Yes **Timing** : + - Review Google : 3-7 jours - Si rejet : corrections + re-soumission (1-2 jours) - **Total prévu** : 5-10 jours diff --git a/mkdocs.yml b/mkdocs.yml index d6b384a..3dc6810 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -96,89 +96,90 @@ nav: - Domaines DDD: - 'Context Map': domains/README.md - 'Core Domain': - - '🔐 Shared': domains/_shared/README.md - - Règles: - - Authentification: domains/_shared/rules/authentification.md - - RGPD: domains/_shared/rules/rgpd.md - - Gestion Erreurs: domains/_shared/rules/gestion-erreurs.md - - 'Annexe Post-MVP': domains/_shared/rules/ANNEXE-POST-MVP.md - - Features BDD: - - 'Authentication': - - Appareil de confiance et 2FA: generated/bdd/_shared/features/authentication/appareil-confiance-2fa.md - - Classification par âge: generated/bdd/_shared/features/authentication/classification-age.md - - Connexion: generated/bdd/_shared/features/authentication/connexion.md - - Gestion de compte: generated/bdd/_shared/features/authentication/gestion-compte.md - - Inscription: generated/bdd/_shared/features/authentication/inscription.md - - Limite de tentatives de connexion: generated/bdd/_shared/features/authentication/limite-tentatives-connexion.md - - Sessions multi-devices: generated/bdd/_shared/features/authentication/multi-device-sessions.md - - Récupération de compte: generated/bdd/_shared/features/authentication/recuperation-compte.md - - Récupération de mot de passe avancée: generated/bdd/_shared/features/authentication/recuperation-mot-passe-avancee.md - - Sessions et tokens: generated/bdd/_shared/features/authentication/sessions-tokens.md - - Authentification à deux facteurs: generated/bdd/_shared/features/authentication/two-factor-authentication.md - - Validation mot de passe: generated/bdd/_shared/features/authentication/validation-mot-passe.md - - Vérification email: generated/bdd/_shared/features/authentication/verification-email.md - - 'Profil': - - Badge vérifié: generated/bdd/_shared/features/profil/badge-verifie.md - - Profil créateur: generated/bdd/_shared/features/profil/profil-createur.md - - Statistiques arrondies: generated/bdd/_shared/features/profil/statistiques-arrondies.md - - 'Partage': - - Partage de contenu: generated/bdd/_shared/features/partage/partage-contenu.md - - Partage de contenu Premium: generated/bdd/_shared/features/partage/partage-contenu-premium.md - - 'Error Handling': - - Aucun contenu disponible: generated/bdd/_shared/features/error-handling/aucun-contenu-disponible.md - - Contenu supprimé pendant écoute: generated/bdd/_shared/features/error-handling/contenu-supprime-pendant-ecoute.md - - Géolocalisation désactivée: generated/bdd/_shared/features/error-handling/geolocalisation-desactivee.md - - Perte réseau: generated/bdd/_shared/features/error-handling/perte-reseau.md - - 'RGPD & Conformité': - - Consentement: generated/bdd/_shared/features/rgpd-compliance/consentement.md - - Anonymisation GPS: generated/bdd/_shared/features/rgpd-compliance/anonymisation-gps.md - - Portabilité Données: generated/bdd/_shared/features/rgpd-compliance/portabilite-donnees.md - - Suppression Compte: generated/bdd/_shared/features/rgpd-compliance/suppression-compte.md - - Conservation Données: generated/bdd/_shared/features/rgpd-compliance/conservation-donnees.md - - Cookies & Analytics: generated/bdd/_shared/features/rgpd-compliance/cookies-analytics.md - - Mode Dégradé GeoIP: generated/bdd/_shared/features/rgpd-compliance/mode-degrade-geoip.md - - Compliance Administrative: generated/bdd/_shared/features/rgpd-compliance/compliance-administrative.md - - Protection Mineurs: generated/bdd/_shared/features/rgpd-compliance/minors-protection.md - - Sécurité Données: generated/bdd/_shared/features/rgpd-compliance/data-security.md - - Politique Confidentialité: generated/bdd/_shared/features/rgpd-compliance/privacy-policy.md - - Droits Utilisateurs: generated/bdd/_shared/features/rgpd-compliance/user-rights.md - - Entités: - - "Vue d'ensemble": domains/_shared/entities/vue-ensemble.md - - 'Auth & Sécurité': - - Sessions: domains/_shared/entities/sessions.md - - Devices: domains/_shared/entities/devices.md - - 'RGPD & Conformité': - - Consentements: domains/_shared/entities/consents.md - - Historique GPS: domains/_shared/entities/location-history.md - - Exports Données: domains/_shared/entities/exports.md - - Consentements Parentaux: domains/_shared/entities/parental-consents.md - - Politique Confidentialité: domains/_shared/entities/privacy-policy-versions.md - - Suppressions Compte: domains/_shared/entities/account-deletions.md - - Incidents Breach: domains/_shared/entities/breach-incidents.md - - Historique Profil: domains/_shared/entities/user-profile-history.md - - Logs Rétention Données: domains/_shared/entities/data-retention-logs.md - - 'Recommandation & Modération': - - Jauges Intérêt: domains/_shared/entities/interest-gauges.md - - Signalements: domains/_shared/entities/reports.md - - 'États (Lifecycles)': - - Compte Utilisateur: domains/_shared/states/compte-utilisateur.md - - Contenu: domains/_shared/states/contenu.md - - Session: domains/_shared/states/session.md - - Signalement: domains/_shared/states/signalement.md - - Export Données: domains/_shared/states/export-donnees.md - - Consentement Parental: domains/_shared/states/consentement-parental.md - - Suppression Compte: domains/_shared/states/suppression-compte.md - - Incident Breach: domains/_shared/states/incident-breach.md - - Séquences: - - Authentification: domains/_shared/sequences/authentification.md - - Refresh Token: domains/_shared/sequences/refresh-token.md - - Modération Contenu: domains/_shared/sequences/moderation-contenu.md - - Signalement: domains/_shared/sequences/signalement.md - - Export Données: domains/_shared/sequences/export-donnees.md - - Suppression Compte: domains/_shared/sequences/suppression-compte.md - - Consentement Parental: domains/_shared/sequences/consentement-parental.md - - Anonymisation GPS: domains/_shared/sequences/anonymisation-gps.md - - Notification Breach: domains/_shared/sequences/notification-breach.md + - '🔐 Shared': + - Vue d'ensemble: domains/_shared/README.md + - Règles: + - Authentification: domains/_shared/rules/authentification.md + - RGPD: domains/_shared/rules/rgpd.md + - Gestion Erreurs: domains/_shared/rules/gestion-erreurs.md + - 'Annexe Post-MVP': domains/_shared/rules/ANNEXE-POST-MVP.md + - Features BDD: + - 'Authentication': + - Appareil de confiance et 2FA: generated/bdd/_shared/features/authentication/appareil-confiance-2fa.md + - Classification par âge: generated/bdd/_shared/features/authentication/classification-age.md + - Connexion: generated/bdd/_shared/features/authentication/connexion.md + - Gestion de compte: generated/bdd/_shared/features/authentication/gestion-compte.md + - Inscription: generated/bdd/_shared/features/authentication/inscription.md + - Limite de tentatives de connexion: generated/bdd/_shared/features/authentication/limite-tentatives-connexion.md + - Sessions multi-devices: generated/bdd/_shared/features/authentication/multi-device-sessions.md + - Récupération de compte: generated/bdd/_shared/features/authentication/recuperation-compte.md + - Récupération de mot de passe avancée: generated/bdd/_shared/features/authentication/recuperation-mot-passe-avancee.md + - Sessions et tokens: generated/bdd/_shared/features/authentication/sessions-tokens.md + - Authentification à deux facteurs: generated/bdd/_shared/features/authentication/two-factor-authentication.md + - Validation mot de passe: generated/bdd/_shared/features/authentication/validation-mot-passe.md + - Vérification email: generated/bdd/_shared/features/authentication/verification-email.md + - 'Profil': + - Badge vérifié: generated/bdd/_shared/features/profil/badge-verifie.md + - Profil créateur: generated/bdd/_shared/features/profil/profil-createur.md + - Statistiques arrondies: generated/bdd/_shared/features/profil/statistiques-arrondies.md + - 'Partage': + - Partage de contenu: generated/bdd/_shared/features/partage/partage-contenu.md + - Partage de contenu Premium: generated/bdd/_shared/features/partage/partage-contenu-premium.md + - 'Error Handling': + - Aucun contenu disponible: generated/bdd/_shared/features/error-handling/aucun-contenu-disponible.md + - Contenu supprimé pendant écoute: generated/bdd/_shared/features/error-handling/contenu-supprime-pendant-ecoute.md + - Géolocalisation désactivée: generated/bdd/_shared/features/error-handling/geolocalisation-desactivee.md + - Perte réseau: generated/bdd/_shared/features/error-handling/perte-reseau.md + - 'RGPD & Conformité': + - Consentement: generated/bdd/_shared/features/rgpd-compliance/consentement.md + - Anonymisation GPS: generated/bdd/_shared/features/rgpd-compliance/anonymisation-gps.md + - Portabilité Données: generated/bdd/_shared/features/rgpd-compliance/portabilite-donnees.md + - Suppression Compte: generated/bdd/_shared/features/rgpd-compliance/suppression-compte.md + - Conservation Données: generated/bdd/_shared/features/rgpd-compliance/conservation-donnees.md + - Cookies & Analytics: generated/bdd/_shared/features/rgpd-compliance/cookies-analytics.md + - Mode Dégradé GeoIP: generated/bdd/_shared/features/rgpd-compliance/mode-degrade-geoip.md + - Compliance Administrative: generated/bdd/_shared/features/rgpd-compliance/compliance-administrative.md + - Protection Mineurs: generated/bdd/_shared/features/rgpd-compliance/minors-protection.md + - Sécurité Données: generated/bdd/_shared/features/rgpd-compliance/data-security.md + - Politique Confidentialité: generated/bdd/_shared/features/rgpd-compliance/privacy-policy.md + - Droits Utilisateurs: generated/bdd/_shared/features/rgpd-compliance/user-rights.md + - Entités: + - "Vue d'ensemble": domains/_shared/entities/vue-ensemble.md + - 'Auth & Sécurité': + - Sessions: domains/_shared/entities/sessions.md + - Devices: domains/_shared/entities/devices.md + - 'RGPD & Conformité': + - Consentements: domains/_shared/entities/consents.md + - Historique GPS: domains/_shared/entities/location-history.md + - Exports Données: domains/_shared/entities/exports.md + - Consentements Parentaux: domains/_shared/entities/parental-consents.md + - Politique Confidentialité: domains/_shared/entities/privacy-policy-versions.md + - Suppressions Compte: domains/_shared/entities/account-deletions.md + - Incidents Breach: domains/_shared/entities/breach-incidents.md + - Historique Profil: domains/_shared/entities/user-profile-history.md + - Logs Rétention Données: domains/_shared/entities/data-retention-logs.md + - 'Recommandation & Modération': + - Jauges Intérêt: domains/_shared/entities/interest-gauges.md + - Signalements: domains/_shared/entities/reports.md + - 'États (Lifecycles)': + - Compte Utilisateur: domains/_shared/states/compte-utilisateur.md + - Contenu: domains/_shared/states/contenu.md + - Session: domains/_shared/states/session.md + - Signalement: domains/_shared/states/signalement.md + - Export Données: domains/_shared/states/export-donnees.md + - Consentement Parental: domains/_shared/states/consentement-parental.md + - Suppression Compte: domains/_shared/states/suppression-compte.md + - Incident Breach: domains/_shared/states/incident-breach.md + - Séquences: + - Authentification: domains/_shared/sequences/authentification.md + - Refresh Token: domains/_shared/sequences/refresh-token.md + - Modération Contenu: domains/_shared/sequences/moderation-contenu.md + - Signalement: domains/_shared/sequences/signalement.md + - Export Données: domains/_shared/sequences/export-donnees.md + - Suppression Compte: domains/_shared/sequences/suppression-compte.md + - Consentement Parental: domains/_shared/sequences/consentement-parental.md + - Anonymisation GPS: domains/_shared/sequences/anonymisation-gps.md + - Notification Breach: domains/_shared/sequences/notification-breach.md - 'Supporting Subdomains': - '🎯 Recommendation': - Vue d'ensemble: domains/recommendation/README.md diff --git a/scripts/fix-markdown-lists.sh b/scripts/fix-markdown-lists.sh new file mode 100755 index 0000000..c59a8f7 --- /dev/null +++ b/scripts/fix-markdown-lists.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# Script pour ajouter des lignes vides avant les listes markdown +# qui n'en ont pas, pour un rendu correct dans mkdocs + +set -e + +echo "🔍 Recherche des fichiers markdown dans docs/..." + +# Compteur de fichiers modifiés +modified=0 + +# Trouver tous les fichiers .md dans docs/ +find docs -name "*.md" -type f | while read -r file; do + echo " Traitement de $file..." + + # Utiliser awk pour ajouter une ligne vide avant les listes si nécessaire + awk ' + BEGIN { + prev = "" + prev_empty = 1 + } + { + current = $0 + # Si la ligne courante commence par "- " et que la ligne précédente n'\''est pas vide + # et ne commence pas déjà par "- " (déjà dans une liste) + if (current ~ /^- / && prev !~ /^$/ && prev !~ /^- /) { + print prev + print "" # Ajouter une ligne vide + prev = current + } + # Sinon, imprimer la ligne précédente normalement + else if (NR > 1) { + print prev + prev = current + } + else { + prev = current + } + } + END { + # Imprimer la dernière ligne + if (prev != "") print prev + } + ' "$file" > "$file.tmp" + + # Vérifier si le fichier a changé + if ! cmp -s "$file" "$file.tmp"; then + mv "$file.tmp" "$file" + echo " ✅ $file modifié" + modified=$((modified + 1)) + else + rm "$file.tmp" + fi +done + +echo "" +echo "✨ Terminé ! $modified fichier(s) modifié(s)" diff --git a/scripts/generate-bdd-docs.py b/scripts/generate-bdd-docs.py index 6ed40f0..ce54087 100644 --- a/scripts/generate-bdd-docs.py +++ b/scripts/generate-bdd-docs.py @@ -195,7 +195,8 @@ def get_keyword_color(keyword: str) -> str: def format_step(step: Step, indent: str = "") -> str: """Formate une étape Gherkin avec couleur""" color = get_keyword_color(step.keyword) - result = f'{indent}**{step.keyword}** {step.text}' + # Ajouter deux espaces à la fin pour forcer un line break en markdown + result = f'{indent}**{step.keyword}** {step.text} ' if step.table: result += "\n\n"