docs: améliorer rendu markdown et navigation mkdocs

- Ajouter ADR-018 (librairies Go) dans TECHNICAL.md
- Transformer Shared en menu dépliable dans mkdocs (cohérence avec autres domaines)
- Corriger listes markdown (ajout lignes vides avant listes)
- Corriger line breaks dans génération BDD (étapes "Et" sur nouvelles lignes)
- Ajouter script fix-markdown-lists.sh pour corrections futures

Impacte 86 fichiers de documentation et 164 fichiers BDD générés.
This commit is contained in:
jpgiannetti
2026-02-09 20:49:52 +01:00
parent 95c65b8be1
commit 35aaa105d0
87 changed files with 1044 additions and 91 deletions

View File

@@ -200,13 +200,6 @@ domains/<domain>/
└── 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** :

View File

@@ -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

View File

@@ -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é"`)

View File

@@ -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"]`

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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€

View File

@@ -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`

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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 @@
</dict>
</array>
```
- 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"

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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]`

View File

@@ -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

View File

@@ -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é)

View File

@@ -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

View File

@@ -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

View File

@@ -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é

View File

@@ -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

View File

@@ -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é

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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é

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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.

View File

@@ -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é