Initial commit

This commit is contained in:
jpgiannetti
2026-01-31 11:45:11 +01:00
commit f99fb3c614
166 changed files with 115155 additions and 0 deletions

View File

@@ -0,0 +1,233 @@
## 1. Authentification & Inscription
### 1.1 Méthodes d'inscription
**Décision** : Email/Password uniquement (pas d'OAuth tiers)
- ❌ Pas de Google, Apple, Facebook OAuth (dépendance services US/Chine)
- ✅ Email + mot de passe
- ✅ 2FA (Two-Factor Authentication) disponible
- ✅ Option "Appareil de confiance" (skip 2FA pour 30 jours)
**Justification** :
- Souveraineté : pas de dépendance externe
- RGPD : données 100% contrôlées
- Coût : 0€ (Zitadel intégré)
---
### 1.2 Vérification email
**Décision** : Différenciée selon le rôle utilisateur
#### Pour les auditeurs (écoute uniquement)
| État | Capacités |
|------|-----------|
| **Email non vérifié** | Lecture illimitée + création max 5 contenus |
| **Email vérifié** | Toutes fonctionnalités débloquées |
**Paramètres** :
- Lien de vérification expire après **7 jours**
- Possibilité de renvoyer le lien (max 3 fois/jour)
- Rappel in-app après création du 3ème contenu
**Justification** :
- Friction minimale à l'inscription
- Anti-spam sans bloquer l'essai du produit
- Incitation naturelle à vérifier (déblocage)
#### Pour les créateurs (monétisation)
**Vérification obligatoire sous 7 jours** pour :
- Accès au programme de monétisation
- KYC et reversement des revenus (conformité Mangopay)
- Publication illimitée de contenus
**Justification** :
- **Conformité légale** : KYC obligatoire pour transferts financiers
- **Anti-fraude** : Vérification identité réelle pour paiements
- **Responsabilité** : RoadWave doit pouvoir prouver identité créateurs monétisés
---
### 1.3 Données requises à l'inscription
**Obligatoires** :
- ✅ Email (format validé)
- ✅ Mot de passe (voir règles ci-dessous)
- ✅ Pseudo (3-30 caractères, alphanumérique + underscore)
- ✅ Date de naissance (vérification âge minimum)
**Optionnelles** :
- ❌ Nom complet (privacy by design)
- ❌ Photo de profil (avatar par défaut généré)
- ❌ Bio (ajout ultérieur)
**Âge minimum** :
- **13 ans minimum** (conformité réglementation réseaux sociaux EU)
- Vérification à l'inscription via date de naissance
- Blocage inscription si <13 ans avec message explicite
**Justification** :
- RGPD minimal data
- Friction réduite (4 champs max)
- Protection mineurs (obligation légale)
---
### 1.4 Tranches d'âge des contenus
**Décision** : Classification obligatoire des contenus
**Catégories** :
- 🟢 **Tout public** (défaut)
- 🟡 **13+** : contenu mature léger (débats, actualité sensible)
- 🟠 **16+** : contenu mature (violence verbale, sujets sensibles)
- 🔴 **18+** : contenu adulte (langage explicite, sujets réservés)
**Règles de diffusion** :
- Utilisateur 13-15 ans → contenus 🟢 uniquement
- Utilisateur 16-17 ans → contenus 🟢 🟡
- Utilisateur 18+ → tous contenus
**Modération** :
- Vérification obligatoire de la classification lors de la validation
- Reclassification possible par modérateurs
- Strike si classification volontairement incorrecte
**Justification** :
- Protection mineurs (obligation légale)
- Responsabilité plateforme
- Coût : champ supplémentaire + règle algo
---
### 1.5 Validation mot de passe
**Règles** :
- ✅ Minimum **8 caractères**
- ✅ Au moins **1 majuscule**
- ✅ Au moins **1 chiffre**
- ❌ Pas de symbole obligatoire (simplicité)
**Validation** :
- Côté client (feedback temps réel)
- Côté backend (sécurité)
- Message d'erreur explicite par règle non respectée
**Justification** :
- Standard industrie
- Bloque 95% des mots de passe faibles
- UX acceptable (pas trop restrictif)
---
### 1.6 Two-Factor Authentication (2FA)
**Décision** : Optionnel mais recommandé
**Méthodes disponibles** :
- ✅ TOTP (Time-based One-Time Password) via app (Google Authenticator, Authy)
- ✅ Email (code 6 chiffres, expire 10 min)
- ❌ SMS (coût élevé ~0.05€/SMS)
**Appareil de confiance** :
- Option "Ne plus demander sur cet appareil" → bypass 2FA pendant **30 jours**
- Révocable depuis paramètres compte
- Liste des appareils de confiance visible
**Justification** :
- Sécurité renforcée sans coût SMS
- UX : appareil de confiance évite friction quotidienne
- Zitadel natif (0€)
---
### 1.7 Tentatives de connexion
**Règles** :
- Maximum **5 tentatives** par période de **15 minutes**
- Blocage temporaire après 5 échecs
- Compteur reset automatique après 15 min
- Notification email si blocage (tentative suspecte)
**Déblocage** :
- Automatique après 15 min
- Ou via lien "Mot de passe oublié"
**Justification** :
- Anti brute-force
- Standard industrie (équilibre sécurité/UX)
- Zitadel natif (0€)
---
### 1.8 Sessions et refresh tokens
**Durée de vie** :
- **Access token** : 15 minutes
- **Refresh token** : 30 jours
**Rotation** :
- Refresh token rotatif (nouveau token à chaque refresh)
- Ancien token invalidé immédiatement
- Détection token replay attack
**Extension automatique** :
- Si app utilisée, session prolongée automatiquement
- Inactivité 30 jours → déconnexion
**Justification** :
- Sécurité (token court-vie)
- UX (pas de reconnexion fréquente)
- Standard OAuth2/OIDC
---
### 1.9 Multi-device
**Décision** : Sessions simultanées illimitées
**Gestion** :
- Liste des devices connectés visible (OS, navigateur, dernière connexion, IP/ville)
- Révocation individuelle possible
- Révocation globale "Déconnecter tous les appareils"
**Alertes** :
- Notification push + email si connexion depuis nouveau device
- Détection localisation suspecte (IP pays différent)
**Justification** :
- UX maximale (écoute voiture + tablette maison + web)
- Sécurité via transparence (utilisateur voit tout)
- Coût : table sessions PostgreSQL
---
### 1.10 Récupération de compte
**Méthode** : Email uniquement
**Processus** :
1. Utilisateur clique "Mot de passe oublié"
2. Email avec lien de reset envoyé
3. Lien expire après **1 heure**
4. Page de reset : nouveau mot de passe (validation règles)
5. Confirmation + déconnexion tous devices (sauf celui en cours)
**Notifications** :
- Email immédiat si changement mot de passe
- Push si changement depuis appareil non reconnu
**Limite** :
- Maximum **3 demandes/heure** (anti-spam)
**Justification** :
- Standard sécurité
- Pas de coût SMS
- Protection contre attaque sociale
---
## Récapitulatif Section 1

View File

@@ -0,0 +1,336 @@
## 13. Conformité RGPD
### 13.1 Gestion du consentement
**Décision** : Tarteaucitron.js + PostgreSQL backend
**Implémentation web** :
- ✅ Tarteaucitron.js (opensource, self-hosted)
- ✅ Banner RGPD français, customisable
- ✅ Granularité : fonctionnel / analytique / marketing
**Implémentation backend** :
- Table `user_consents` avec versioning
- Champs : user_id, consent_type, version, accepted, timestamp
- Historique complet conservé (preuve légale)
**Consentements requis** :
- **Géolocalisation précise** : obligatoire (banner + permission OS)
- **Analytics** : optionnel (Matomo)
- **Notifications push** : optionnel (permission OS)
**Justification** :
- Opensource, 0€, conformité RGPD garantie
- Historique backend = preuve légale en cas de contrôle
- Granularité conforme recommandations CNIL
---
### 13.2 Anonymisation des données GPS
**Décision** : Geohash après 24h
**Processus** :
1. Données précises conservées **24h** (recommandation personnalisée)
2. Après 24h : conversion en geohash précision 5 (~5km²)
3. Coordonnées originales supprimées définitivement
**Implémentation PostGIS** :
```sql
-- Job quotidien
UPDATE location_history
SET location = ST_SetSRID(ST_GeomFromGeoHash(ST_GeoHash(location::geography, 5)), 4326)::geography,
anonymized = true
WHERE created_at < NOW() - INTERVAL '24 hours' AND anonymized = false;
```
**Exceptions** :
- ✅ Historique personnel visible (liste trajets) : conservation intégrale tant que compte actif
- ❌ Analytics globales : uniquement geohash anonyme
**Justification** :
- Vraie anonymisation RGPD (CNIL compliant)
- Permet analytics agrégées (heatmaps trafic)
- PostGIS natif, 0€
---
### 13.3 Export des données (portabilité)
**Décision** : JSON + HTML + ZIP, génération asynchrone
**Contenu de l'export** :
```
export-roadwave-[user_id]-[date].zip
├── export.json # Machine-readable
├── index.html # Human-readable (stylé)
├── audio/
│ ├── content-123.opus
│ ├── content-456.opus
│ └── ...
└── README.txt # Instructions
```
**Données exportées** :
- Profil utilisateur (email, pseudo, date inscription, bio)
- Historique d'écoute (titres, dates, durées)
- Contenus créés (audio + métadonnées)
- Abonnements et likes
- Centres d'intérêt (jauges)
- Historique consentements
**Processus** :
1. Demande via paramètres compte
2. Génération asynchrone (worker background)
3. Email avec lien download (expire **7 jours**)
4. Délai : **48h maximum** (conformité RGPD)
**Limite** :
- Maximum **1 export/mois** (anti-abus)
**Justification** :
- Conformité article 20 RGPD (portabilité)
- Double format (human + machine)
- Worker asynchrone évite timeout
---
### 13.4 Suppression du compte
**Décision** : Grace period 30j + anonymisation contenus
**Processus** :
1. Utilisateur clique "Supprimer mon compte"
2. Compte désactivé immédiatement (login impossible)
3. Contenus cachés pendant 30 jours (non diffusés)
4. Email confirmation + lien annulation (valide 30j)
5. Après 30j sans annulation : suppression effective
**Suppression effective** :
- ✅ Compte utilisateur supprimé (données personnelles)
- ✅ Historique d'écoute supprimé
- ✅ GPS historique supprimé
- ✅ Sessions et tokens révoqués
- ⚠️ Contenus créés **anonymisés** (créateur = "Utilisateur supprimé")
- ⚠️ Likes et abonnements supprimés (mais compteurs préservés)
**Contenus conservés anonymement** :
- Audio files (CDN)
- Métadonnées (titre, description, tags, géolocalisation)
- Statistiques d'écoute
**Justification** :
- Grace period évite suppressions impulsives
- Anonymisation contenus = intérêt légitime communauté
- Conforme RGPD si créateur = donnée supprimée
---
### 13.5 Mode dégradé (sans GPS précis)
**Décision** : GeoIP par défaut, GPS optionnel
**Niveaux de précision** :
| Niveau | Technologie | Contenus accessibles | Consentement |
|--------|-------------|---------------------|--------------|
| **Pays** | Aucune géoloc | Contenus nationaux uniquement | ❌ Non requis |
| **Ville** | GeoIP (MaxMind) | Contenus régionaux/ville | ❌ Non requis |
| **Précis** | GPS | Tous contenus (hyperlocaux inclus) | ✅ Requis |
**Implémentation** :
- Démarrage app : GeoIP automatique (IP → ville)
- Banner in-app : "Activez la géolocalisation pour découvrir du contenu près de chez vous"
- Upgrade volontaire vers GPS
**API GeoIP** :
- MaxMind GeoLite2 (gratuit, self-hosted)
- Update DB mensuelle automatique
- Précision ~80% au niveau ville
**Justification** :
- RGPD : pas de consentement requis pour GeoIP (pas de donnée personnelle)
- UX dégradée acceptable (contenus disponibles)
- Progressive disclosure (upgrade optionnel)
---
### 13.6 Durée de conservation des données
**Décision** : 5 ans inactivité → purge automatique
**Règles** :
| Type de compte | Seuil inactivité | Action |
|----------------|------------------|--------|
| **Auditeur uniquement** | 5 ans sans connexion | Suppression automatique |
| **Créateur avec contenus actifs** | Jamais (tant qu'écoutes) | Conservation indéfinie |
| **Créateur inactif** | 5 ans sans connexion + 2 ans sans écoute | Suppression automatique |
**Notifications avant suppression** :
- Email + push : **90 jours** avant
- Email + push : **30 jours** avant
- Email + push : **7 jours** avant
- Toute connexion = reset compteur inactivité
**Contenu conservé** :
- Contenus créés par comptes supprimés (anonymisés) : conservation indéfinie
**Justification** :
- Conformité principe minimisation RGPD
- 5 ans = équilibre raisonnable (standard industrie)
- Exception créateurs actifs = intérêt légitime plateforme
---
### 13.7 Cookies et trackers web
**Décision** : Matomo self-hosted, zéro cookie tiers
**Cookies utilisés** :
| Cookie | Type | Durée | Finalité | Consentement |
|--------|------|-------|----------|--------------|
| `session` | Technique | 30j | Authentification | ❌ Non requis |
| `refresh_token` | Technique | 30j | Session persistante | ❌ Non requis |
| `_pk_id` | Analytique | 13 mois | Matomo (IP anonyme) | ✅ Requis |
**Analytics : Matomo self-hosted** :
- Hébergé sur nos serveurs (Docker)
- IP anonymisées automatiquement (2 derniers octets)
- Pas de cookie si consentement refusé
- Alternative : Plausible (SaaS EU, 9€/mois)
**Trackers interdits** :
- ❌ Google Analytics
- ❌ Facebook Pixel
- ❌ Hotjar, Mixpanel, etc.
**Justification** :
- Souveraineté données (pas de transfert US)
- Conformité RGPD max (CNIL compatible)
- Matomo = opensource, 0€ infra
---
### 13.8 Registre des traitements
**Décision** : Document Markdown versionné Git (MVP)
**Emplacement** :
- `docs/rgpd/registre-traitements.md`
- Versionné Git (historique modifications)
**Contenu obligatoire par traitement** :
- Nom et finalité du traitement
- Catégories de données collectées
- Base légale (consentement / contrat / intérêt légitime)
- Durée de conservation
- Destinataires (sous-traitants, CDN, etc.)
- Transferts hors UE (aucun prévu)
**Responsable** :
- DPO / Fondateur
- Review trimestrielle obligatoire
- Update immédiate si nouveau traitement
**Migration future** :
- Si > 100K utilisateurs : interface admin PostgreSQL
**Justification** :
- Obligation RGPD Article 30
- Markdown = simple, versionné, auditable
- 0€
---
### 13.9 Notification violations de données (breach)
**Décision** : Monitoring + alertes + runbook
**Détection automatique** :
| Événement | Outil | Alerte |
|-----------|-------|--------|
| Erreurs backend critiques | Sentry | Discord/Slack immédiat |
| Pic requêtes anormal | Grafana | Email équipe |
| Accès non autorisé DB | PostgreSQL logs | SMS fondateur |
| Authentification suspecte | Zitadel alerts | Email équipe |
**Procédure breach** :
- Runbook : `docs/rgpd/procedure-breach.md`
- Checklist 72h CNIL :
1. H+0 : Détection et confinement
2. H+24 : Évaluation gravité (données concernées, utilisateurs impactés)
3. H+48 : Notification CNIL si risque pour utilisateurs
4. H+72 : Notification utilisateurs si risque élevé
**Contact CNIL** :
- Email pré-rédigé (template)
- Formulaire en ligne (account CNIL créé)
**Justification** :
- Obligation RGPD Article 33 (notification 72h)
- Monitoring proactif évite découverte tardive
- Sentry gratuit < 5K events/mois
---
### 13.10 DPO (Délégué à la Protection des Données)
**Décision** : Fondateur = DPO temporaire (MVP)
**Raison légale** :
- Non obligatoire si :
- < 250 employés
- Pas de traitement à grande échelle de données sensibles
- RoadWave : données localisation = sensible MAIS échelle MVP
**Formation** :
- CNIL : formation gratuite en ligne (4h)
- Certification CNIL "Atelier RGPD" (gratuit)
**Contact** :
- Email : dpo@roadwave.fr
- Publié dans CGU et mentions légales
- Délai réponse : **1 mois** (RGPD)
**Migration future** :
- Si > 100K utilisateurs : DPO externe mutualisé (~200€/mois)
- Ou recrutement DPO interne si > 10 employés
**Justification** :
- Conforme RGPD (non obligatoire en phase MVP)
- 0€, contrôle total
- Bonne pratique : avoir un contact identifié
---
## Récapitulatif Section 13
| Mesure | Implémentation | Coût |
|--------|----------------|------|
| **Consentement** | Tarteaucitron.js + PostgreSQL | 0€ |
| **Anonymisation GPS** | Geohash PostGIS (24h) | 0€ |
| **Export données** | JSON+HTML+ZIP asynchrone | 0€ |
| **Suppression compte** | Grace period 30j + anonymisation | 0€ |
| **Mode dégradé** | GeoIP MaxMind + GPS optionnel | 0€ |
| **Conservation** | Purge auto 5 ans inactivité | 0€ |
| **Analytics** | Matomo self-hosted | ~5€/mois |
| **Registre traitements** | Markdown Git | 0€ |
| **Breach detection** | Sentry + Grafana + runbook | 0€ |
| **DPO** | Fondateur formé CNIL | 0€ |
**Coût total RGPD : ~5€/mois**
---
## Points d'attention pour Gherkin
- Tester consentement géolocalisation (accept/refuse → contenus différents)
- Tester anonymisation GPS après 24h (job cron)
- Tester export données (génération complète + vérification contenu)
- Tester grace period suppression (annulation possible)
- Tester mode GeoIP (ville détectée correctement)
- Tester purge automatique (5 ans inactivité)
- Tester notifications avant purge (90j/30j/7j)

View File

@@ -0,0 +1,141 @@
## 3. Centres d'intérêt et jauges
### 3.1 Évolution des jauges
**Décision** : Système simple avec valeurs fixes
| Action | Impact jauge | Justification |
|--------|--------------|---------------|
| **Like automatique renforcé (≥80% écoute)** | +2% | Signal fort d'intérêt (écoute quasi-complète) |
| **Like automatique standard (30-79% écoute)** | +1% | Signal modéré d'intérêt |
| **Like explicite (manuel)** | +2% | Signal fort, cumulable avec auto |
| **Abonnement créateur** | +5% sur tous ses tags | Signal très fort d'affinité |
| **Skip rapide (<10s)** | -0.5% | Désintérêt marqué |
| **Skip tardif (≥30%)** | 0% | Neutre (contenu essayé suffisamment) |
**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
- Si un contenu a plusieurs tags, chaque jauge correspondante est impactée
**Exemple de calcul** :
```
Contenu de 5 minutes tagué "Automobile" + "Voyage"
Scénario 1 : Écoute 4min30 (90%)
→ Like automatique renforcé (+2%)
→ Jauge Automobile : 45% → 47%
→ Jauge Voyage : 60% → 62%
Scénario 2 : Écoute 2min30 (50%)
→ Like automatique standard (+1%)
→ Jauge Automobile : 45% → 46%
→ Jauge Voyage : 60% → 61%
Scénario 3 : Écoute 2min30 (50%) + Like manuel
→ Like auto +1% puis like manuel +2% = +3% total
→ Jauge Automobile : 45% → 48%
→ Jauge Voyage : 60% → 63%
Scénario 4 : Skip après 5s
→ Signal négatif (-0.5%)
→ Jauge Automobile : 45% → 44.5%
→ Jauge Voyage : 60% → 59.5%
```
**Justification** :
- **Like automatique** : Reflète l'engagement réel (voir [ADR-010](../adr/010-commandes-volant.md))
- **Sécurité routière** : Pas d'action complexe en conduite
- **Prévisibilité** : Règles claires et déterministes
- **Coût minimal** : Calculs simples en backend
- **Fiabilité** : Pas d'edge cases complexes
- **Ajustable** : Valeurs modifiables via dashboard admin si besoin
---
### 3.2 Jauge initiale
**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
- Amour
- Musique
- Économie
- Cryptomonnaie
- Politique
- Culture générale
- Sport
- Technologie
- Santé
- *... (extensible)*
**Cold start (premiers jours)** :
1. Nouvel utilisateur s'inscrit → toutes jauges à 50%
2. Écoute premier podcast "Automobile" → jauge Auto monte à 51%
3. Skip un contenu "Économie" → jauge Éco descend à 48%
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
- **Comportement déterministe** : facile à tester et débugger
- **Cold start acceptable** : à 50%, tous les contenus ont une chance égale initialement
---
### 3.3 Dégradation temporelle
**Décision** : Pas de dégradation automatique
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
**Scénario illustratif** :
```
Utilisateur aimait "Économie" (jauge 80%) il y a 1 an
→ Depuis, skip tous les contenus Éco
→ Jauge descend naturellement à 40% via les skips
→ Pas besoin de dégradation temporelle
```
**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.
- **UX prévisible** : jauge = reflet des actions, pas d'automatisme caché
- **Respect historique** : si utilisateur aimait X depuis 2 ans, pourquoi "oublier" ?
- **Évolution naturelle** : les actions récentes suffisent à faire évoluer les jauges
---
## Récapitulatif Section 3

View File

@@ -0,0 +1,336 @@
## 2. Algorithme de recommandation
### 2.1 Classification de géo-pertinence
**Décision** : 3 types de contenus selon leur pertinence géographique
| Type | Description | Exemple | Pondération géo |
|------|-------------|---------|-----------------|
| **Géo-ancré** | Contenu lié à un lieu précis | Audio-guide monument, pub restaurant local | 70% |
| **Géo-contextuel** | Pertinent dans une zone | Actualité régionale, événement local | 50% |
| **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
---
### 2.2 Formule de scoring
**Décision** : Score combiné dynamique selon type de contenu
```
score_final = (score_geo * poids_geo_type)
+ (score_interets * poids_interets_type)
+ (score_engagement * 0.2)
+ (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)
- bonus_aleatoire = 10% des recommandations tirées aléatoirement
```
**Pondérations par type** :
| Type | Poids géo | Poids intérêts |
|------|-----------|----------------|
| Géo-ancré | 0.7 | 0.1 |
| Géo-contextuel | 0.5 | 0.3 |
| 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)
**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)
---
### 2.3 Score d'engagement et popularité
**Décision** : Intégration popularité avec poids 0.2
**Métriques** :
- **Taux de complétion** : écoutes >80% / total écoutes (poids 0.5)
- **Ratio likes** : likes / écoutes (poids 0.3)
- **Ratio abonnements** : nouveaux abonnés après écoute / écoutes (poids 0.2)
**Seuil minimum** :
- Minimum **50 écoutes** 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é
- Pas de pénalisation arbitraire des contenus anciens
- Coût : calculs sur métriques existantes
---
### 2.4 Part d'aléatoire (exploration)
**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
---
### 2.5 Contenu politique (version MVP simplifiée)
> ⚠️ **Note** : La classification politique avancée (échelle gauche/droite, équilibrage imposé) a été reportée post-MVP. Voir [ANNEXE-POST-MVP.md](ANNEXE-POST-MVP.md) pour la version complète.
**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
---
### 2.6 Mode Kids (13-15 ans)
**Décision** : Mode optionnel pour adolescents 13-15 ans uniquement
> ⚠️ **Note** : Âge minimum d'inscription = **13 ans** (obligation légale EU). Pas d'utilisateurs <13 ans sur la plateforme.
**Tranche concernée** :
| Tranche | Description | Contenus autorisés | Restrictions |
|---------|-------------|-------------------|--------------|
| **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
- **Flexibilité** : Parents décident d'activer ou non
---
### 2.7 Déclenchement géographique
**Décision** : Notification au passage, pas d'anticipation
**Fonctionnement** :
1. Utilisateur passe à <500m d'un point GPS (contenu géo-ancré)
2. **Notification sonore** (bip court) + **visuelle** (logo selon type)
3. Types de logos : 📍 Info, 🏛️ Culturel, 🍴 Commercial, 🎭 Événement
4. Délai réaction utilisateur : **5 secondes** pour accepter (bouton volant ou commande vocale)
5. Si accepté → lecture immédiate
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)
---
### 2.8 Historique et repropositon
**Décision** : Pas de reproposition sauf contenu partiel
**Règles** :
| État écoute | Completion | Action |
|-------------|------------|--------|
| **Écouté complètement** | >80% | ❌ Ne jamais reproposer (sauf flag `replayable = true` pour audio-guides) |
| **Skippé rapidement** | <10s | ❌ Ne pas reproposer |
| **Partiellement écouté** | 10-80% | ✅ Reproposer avec reprise position (`last_position_seconds`) |
**Stockage historique** :
- Table `user_content_history` (user_id, content_id, completion_rate, last_position, listened_at)
- Historique **illimité** (PostgreSQL)
- Algorithme considère les **100 derniers** pour optimisation requêtes
- Export complet disponible (RGPD)
**Justification** :
- Découverte maximale (pas de redites)
- Respect erreurs de clic (contenu partiel = 2nde chance)
- Coût stockage négligeable (PostgreSQL scalable)
---
### 2.9 Paramétrabilité admin (interface dashboard)
**Décision** : Tous paramètres scoring exposés + A/B testing
**Paramètres configurables à chaud** :
| Paramètre | Plage | Défaut | Unité |
|-----------|-------|--------|-------|
| `poids_geo_ancre` | 0.5 - 1.0 | 0.7 | % |
| `poids_geo_contextuel` | 0.3 - 0.7 | 0.5 | % |
| `poids_geo_neutre` | 0.0 - 0.4 | 0.2 | % |
| `poids_engagement` | 0.0 - 0.5 | 0.2 | % |
| `part_aleatoire_global` | 0.0 - 0.3 | 0.1 | % |
| `distance_max_km` | 50 - 500 | 200 | km |
| `rayon_gps_point_m` | 100 - 2000 | 500 | m |
| `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)
---
### 2.10 Paramétrabilité utilisateur
**Décision** : Curseurs avancés avec profils sauvegardables
**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)
---
### 2.11 Médias traditionnels
**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)
---
## Récapitulatif Section 2

View File

@@ -0,0 +1,516 @@
## 5. Interactions et navigation
### 5.1 File d'attente et commande "Suivant"
**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
- Toutes les 10 minutes (rafraîchissement contenu)
- File d'attente <3 contenus restants
**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)
- **Pas de texte affiché** (éviter distraction conducteur)
- **Pas de bouton "Annuler"** : seul le bouton "Suivant" permet validation
**Actions utilisateur** :
1. User entend notification sonore + voit icône et compteur
2. User appuie "Suivant" dans les 7 secondes → décompte 5s démarre
3. Pendant décompte : contenu actuel continue, compteur visible (5...4...3...2...1)
4. Si contenu actuel se termine pendant décompte → contenu suivant du buffer démarre
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** :
```
Redis cache :
- Clé : user:{user_id}:queue
- Structure : [content_1, content_2, ..., content_5]
- Métadonnées : {last_lat, last_lon, computed_at, mode: "voiture"|"pieton"}
- TTL : 15 minutes
Tracking GPS temps réel (mobile) :
- Vérification toutes les 1 seconde
- Calcul ETA vers points géolocalisés proches (rayon 500m)
- Si ETA ≤ 7s → trigger notification
- Historique GPS : 30 derniers points pour calcul vitesse moyenne
Quota anti-spam (Redis) :
- Clé : user:{user_id}:geo_quota
- Structure : sorted set avec timestamps des 6 derniers contenus
- TTL : 1 heure
- Vérification avant notification : ZCOUNT pour compter contenus dernière heure
Cooldown après ignorance (Redis) :
- Clé : user:{user_id}:geo_cooldown
- TTL : 10 minutes
- Set après notification ignorée
```
**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
- **Sécurité** : pas de modification en conduite
---
### 5.1.2 Mode piéton (audio-guides)
**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
- Permission demandée uniquement si user active "Notifications audio-guides piéton" dans settings
**Notification push système** :
Format :
```
Titre : "Audio-guide à proximité"
Body : "[Nom du contenu] - [Nom créateur]"
Action : Tap → ouvre app sur le contenu
```
Exemple :
```
Audio-guide à proximité
Musée du Louvre : La Joconde - @paris_museum
```
**Permissions requises** :
⚠️ **Important** : Permission "Always Location" est **optionnelle** et demandée uniquement si user active le mode piéton dans settings.
iOS (`Info.plist`) :
```xml
<key>NSLocationWhenInUseUsageDescription</key>
<string>RoadWave utilise votre position pour vous proposer des contenus audio géolocalisés adaptés à votre trajet en temps réel.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Si vous activez les notifications audio-guides piéton, RoadWave peut vous alerter lorsque vous passez près d'un monument ou musée, même quand l'app est en arrière-plan. Cette fonctionnalité est optionnelle et peut être désactivée à tout moment dans les réglages.</string>
```
Android (`AndroidManifest.xml`) :
```xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
```
**Disclosure avant demande permission** (Android requis, iOS recommandé) :
Écran affiché avant demande permission "Always Location" :
```
┌────────────────────────────────────────┐
│ 📍 Notifications audio-guides piéton │
├────────────────────────────────────────┤
│ Pour vous alerter d'audio-guides à │
│ proximité même quand vous marchez avec │
│ l'app fermée, RoadWave a besoin de │
│ votre position en arrière-plan. │
│ │
│ Votre position sera utilisée pour : │
│ ✅ Détecter monuments à 200m │
│ ✅ Vous envoyer une notification │
│ │
│ Votre position ne sera jamais : │
│ ❌ Vendue à des tiers │
│ ❌ Utilisée pour de la publicité │
│ │
│ Cette fonctionnalité est optionnelle. │
│ Vous pouvez utiliser RoadWave sans │
│ cette permission. │
│ │
│ [Continuer] [Non merci] │
│ │
│ Plus d'infos : Politique confidentialité│
└────────────────────────────────────────┘
```
**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)
**Comportement après tap sur notification** :
1. User tap notification push
2. App s'ouvre sur la page du contenu
3. User peut démarrer la lecture manuellement
4. Navigation libre (voir section 16.2 pour audio-guides piéton)
**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
Changements de mode :
| Mode actuel | Vitesse détectée | Nouveau mode | Effet |
|-------------|------------------|--------------|-------|
| Piéton | ≥ 5 km/h | Voiture | Notifications push → sonores + icône (app ouverte requise) |
| 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
- ✅ Basculement automatique = pas de friction
---
### 5.2 Commande "Précédent"
**Décision** : Comportement smart selon progression écoute
**Règles** :
| Situation | Temps écouté | Action "Précédent" |
|-----------|--------------|-------------------|
| **Début de contenu** | <10 secondes | Retour au contenu précédent (position exacte) |
| **Milieu/fin** | ≥10 secondes | Replay contenu actuel depuis le début |
| **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
**Exemple scénario** :
```
Utilisateur écoute :
1. Contenu A → écoute 5s → "Suivant"
2. Contenu B → écoute 2min30 → "Suivant"
3. Contenu C → écoute 5s → "Précédent"
→ Retour Contenu B à 2min30 (car >10s)
4. Sur Contenu B → "Précédent"
→ Retour Contenu A à 5s (position exacte)
```
**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)
---
### 5.3 Interactions au volant : Like automatique et engagement
> ⚠️ **Architecture Decision Record** : Voir [ADR-010](../adr/010-commandes-volant.md) pour les détails techniques complets
**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)
---
#### Commandes au volant simplifiées
**Actions disponibles** (100% compatibles tous véhicules) :
| Commande physique | Action RoadWave |
|-------------------|-----------------|
| **Suivant** | Passer au contenu suivant |
| **Précédent** | Revenir au contenu précédent (règle 10s, voir section 5.2) |
| **Play/Pause** | Pause/reprise lecture (fade out 0.3s) |
**Aucune action complexe au volant** → Sécurité routière maximale.
---
#### Like automatique implicite
**Principe** : Le système détecte automatiquement l'intérêt utilisateur selon le temps d'écoute.
**Règles d'attribution** :
| Durée écoutée | Action automatique | Points jauge | Justification |
|---------------|-------------------|--------------|---------------|
| **≥ 80% du contenu** | Like renforcé | +2.0 | Écoute quasi-complète = fort intérêt |
| **30-79% du contenu** | Like standard | +1.0 | Écoute significative = intérêt |
| **< 30% du contenu** | Pas de like | 0 | Écoute trop courte |
| **Skip après <10s** | Signal négatif | -0.5 | Désintérêt marqué |
**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)
```
---
#### Actions complémentaires (mode piéton uniquement)
**Interface mobile** (vitesse < 5 km/h) :
| Action | Moyen | Effet |
|--------|-------|-------|
| **Like explicite** | Bouton cœur | +2 points jauge (même si déjà liké auto) |
| **Unlike** | Re-clic cœur (toggle) | -2 points jauge |
| **Abonnement** | Bouton "S'abonner" profil créateur | +5 points toutes jauges tags créateur |
| **Désabonnement** | Bouton "Se désabonner" | -5 points |
| **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)
---
#### 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)
---
#### Implémentation technique
**Backend** (Go) :
```go
type ListenEvent struct {
UserID string
ContentID string
StartedAt time.Time
StoppedAt time.Time
Duration int // secondes écoutées
ContentTotal int // durée totale contenu
Percentage float64 // duration / contentTotal * 100
Action string // "completed", "skipped", "paused"
}
func ProcessListenEvent(event ListenEvent) {
percentage := event.Percentage
// Signal négatif fort
if event.Action == "skipped" && event.Duration < 10 {
UpdateJauges(event.UserID, event.ContentID, -0.5)
return
}
// Like automatique
if percentage >= 80 {
AutoLike(event.UserID, event.ContentID, 2.0) // Renforcé
} else if percentage >= 30 {
AutoLike(event.UserID, event.ContentID, 1.0) // Standard
}
// < 30% : pas de like
}
```
**Mobile** (iOS/Android) :
```swift
// iOS - Tracking écoute
class AudioPlayerManager {
var startTime: Date?
let contentDuration: TimeInterval
func onPlay() {
startTime = Date()
}
func onStop(action: String) { // "completed" | "skipped" | "paused"
guard let start = startTime else { return }
let duration = Date().timeIntervalSince(start)
let percentage = (duration / contentDuration) * 100
// API call
API.track(ListenEvent(
contentId: currentContentId,
duration: Int(duration),
percentage: percentage,
action: action
))
}
}
```
---
#### 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
-**Engagement amélioré** : tous les contenus écoutés génèrent des signaux
-**Algorithme plus précis** : données granulaires (30%, 50%, 80%, 100%)
-**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
---
#### Communication utilisateurs (onboarding)
**Écran onboarding 1** :
```
🚗 Conduite sécurisée
RoadWave détecte automatiquement vos goûts
selon vos écoutes.
Plus vous écoutez longtemps, plus
l'algorithme s'améliore !
[Suivant]
```
**Écran onboarding 2** :
```
❤️ Likes automatiques
Pas besoin de liker manuellement :
si vous écoutez >50% d'un contenu,
on comprend que vous aimez !
[Suivant]
```
**Écran onboarding 3** :
```
⏸️ Commandes simples
Utilisez les boutons au volant :
• Suivant → Prochain contenu
• Précédent → Contenu d'avant
• Pause → Mettre en pause
[Commencer]
```
---
### 5.4 Lecture en boucle et enchaînement
**Décision** : Passage automatique après 2s + insertion pub paramétrable
**Fin de contenu** :
1. Audio termine → **Timer 2 secondes** démarre
2. UI overlay : "Contenu suivant dans 2s..." + barre décompte
3. Possibilité annuler : bouton "Rester sur ce contenu" (optionnel)
4. Timer atteint 0 → passage automatique au contenu suivant
**Délai selon contexte** :
| Mode | Délai | Justification |
|------|-------|---------------|
| **Standard** | 2 secondes | Temps réaction confortable |
| **Mode Kids** | 1 seconde | Attention courte enfants |
| **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
- **Like et abonnement autorisés sur pub** (engagement créateur pub)
**Si aucun contenu disponible** :
1. Message : "Aucun contenu disponible dans cette zone"
2. Proposition : "Élargir la zone de recherche ?" (bouton)
3. Si accepté → relance algo avec rayon +50km
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é
- **Engagement pub** : like/abonnement autorisé = monétisation créateurs pub
---
## Récapitulatif Section 5

View File

@@ -0,0 +1,736 @@
## 16. Audio-guides multi-séquences
### 16.1 Types d'audio-guides et modes de déplacement
**Décision** : 4 modes distincts avec détection automatique
#### 16.1.1 Classification par mode
| Mode | Vitesse détection | Déclenchement | Use case |
|------|-------------------|---------------|----------|
| **🚶 Piéton** | <5 km/h | Manuel (bouton "Suivant") | Musées, visites urbaines, monuments |
| **🚗 Voiture** | >10 km/h | Auto GPS + Manuel possible | Safari-parc, routes touristiques, circuits auto |
| **🚴 Vélo** | 5-25 km/h | Auto GPS + Manuel possible | Pistes cyclables, circuits vélo, parcours nature |
| **🚌 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)
---
#### 16.1.2 Création d'un audio-guide (côté créateur)
**Formulaire création** :
```
┌────────────────────────────────────────┐
│ Nouvel audio-guide multi-séquences │
├────────────────────────────────────────┤
│ Titre : [Safari du Paugre] │
│ Description : [Découvrez les animaux │
│ du parc en voiture...] │
│ │
│ Mode de déplacement : *obligatoire │
│ ○ 🚶 Piéton (navigation manuelle) │
│ ● 🚗 Voiture (GPS auto + manuel) │
│ ○ 🚴 Vélo (GPS auto + manuel) │
│ ○ 🚌 Transport (GPS auto + manuel) │
│ │
│ Vitesse recommandée : 30-50 km/h │
│ (si voiture/vélo/transport) │
│ │
│ ──────────────────────────────────── │
│ │
│ Séquences (ordre lecture) : │
│ │
│ 1. [📍] Introduction - Point d'accueil │
│ Lat: 43.1234, Lon: 2.5678 │
│ Rayon déclenchement : 30m │
│ Durée : 2:15 │
│ [🎵 Audio uploadé] [✏️] [🗑️] │
│ │
│ 2. [📍] Enclos des lions │
│ Lat: 43.1245, Lon: 2.5690 │
│ Rayon déclenchement : 30m │
│ Durée : 3:42 │
│ [📤 Upload audio] [✏️] [🗑️] │
│ │
│ 3. [📍] Enclos des girafes │
│ [+ Ajouter point GPS] │
│ │
│ [+ Ajouter séquence] │
│ │
│ 📊 Statistiques : │
│ · 2 séquences complètes │
│ · 5:57 durée totale │
│ · 320m distance totale │
│ │
│ [🗺️ Aperçu sur carte] │
│ [✅ Publier audio-guide] │
└────────────────────────────────────────┘
```
**Métadonnées obligatoires** :
| Champ | Requis | Détails |
|-------|--------|---------|
| **Titre audio-guide** | ✅ | 5-100 caractères |
| **Description** | ✅ | 10-500 caractères |
| **Mode déplacement** | ✅ | Piéton / Voiture / Vélo / Transport |
| **Nombre séquences** | ✅ | Minimum 2, maximum 50 |
| **Point GPS par séquence** | ✅ (sauf piéton) | Latitude, longitude (WGS84) |
| **Rayon déclenchement** | ✅ (sauf piéton) | 10-100m selon mode |
| **Vitesse recommandée** | ❌ | Optionnel, affichée utilisateur |
| **Tags** | ✅ | 1-3 parmi liste prédéfinie |
| **Classification âge** | ✅ | Tout public / 13+ / 16+ / 18+ |
| **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
---
### 16.2 Mode Piéton (manuel)
**Décision** : Navigation manuelle avec pub auto-play
#### 16.2.1 Passage entre séquences
**Séquence normale (sans pub)** :
1. Séquence 1 se termine
2. Player se met en **pause automatique**
3. Message affiché : "Séquence 1 terminée. Appuyez sur Suivant quand vous êtes prêt."
4. User appuie sur [▶|] → Séquence 2 démarre immédiatement
**Séquence avec publicité** (1 pub / 5 séquences) :
1. Séquence 2 se termine
2. **Publicité s'enchaîne automatiquement** (pas d'attente bouton)
3. Pub se lit (skippable après 5s)
4. Pub se termine → Player se met en **pause automatique**
5. Message : "Séquence 3 prête. Appuyez sur Suivant."
6. User appuie sur [▶|] → Séquence 3 démarre
**Schéma flux** :
```
Séquence 1 [fin] → PAUSE → User clique → Séquence 2 [fin] → PUB AUTO-PLAY → PAUSE → User clique → Séquence 3
```
**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
- Premium reste attractif (0 interruption)
---
#### 16.2.2 Navigation et contrôles
**Décision** : Liberté totale utilisateur
**Contrôles disponibles** :
| Bouton | Fonction | Comportement |
|--------|----------|--------------|
| **[▶\|] Suivant** | Passe séquence suivante | Immédiat, même si séquence actuelle pas terminée |
| **[\|◀] Précédent** | Retour séquence précédente | Saut direct séquence avant (pas de logique "replay si >10s") |
| **[⏸️] Pause** | Pause temporaire | Reprend à position exacte |
| **[▶️] Play** | Reprend lecture | Continue position actuelle |
| **Liste séquences** | Navigation libre | Tap séquence → saut direct (même séquences non écoutées) |
**Interface liste séquences** :
```
┌────────────────────────────────────────┐
│ 🚶 Audio-guide Piéton │
│ Musée du Louvre │
├────────────────────────────────────────┤
│ [Cover image] │
│ │
│ ▶️ 0:00 ──●────────── 3:42 │
│ │
│ Séquence 3/12 : La Joconde │
│ │
│ [|◀] [⏸️] [▶|] │
│ │
│ ──────────────────────────────────── │
│ │
│ 📋 Liste des séquences │
│ │
│ ✅ 1. Introduction (2:15) │
│ Écouté le 15/01/2026 │
│ │
│ ✅ 2. Pyramide du Louvre (1:48) │
│ Écouté le 15/01/2026 │
│ │
│ ▶️ 3. La Joconde (3:42) - EN COURS │
│ ──●──────────── 1:22/3:42 │
│ │
│ ⭕ 4. Vénus de Milo (2:58) │
│ │
│ ⭕ 5. Code d'Hammurabi (4:12) │
│ │
│ ⭕ 6. Victoire de Samothrace (3:25) │
│ │
│ ... +6 séquences │
│ │
│ [Tout afficher ▼] │
└────────────────────────────────────────┘
```
**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)
---
### 16.3 Mode Voiture (GPS automatique)
**Décision** : GPS auto avec navigation manuelle conservée
#### 16.3.1 Déclenchement et contrôles
**Distinction audio-guides vs contenus géolocalisés simples** :
⚠️ **Important** : Les audio-guides multi-séquences fonctionnent différemment des contenus géolocalisés simples.
| Type | Séquences | Déclenchement | Notification | Enchaînement | Comptabilité quota |
|------|-----------|---------------|--------------|--------------|-------------------|
| **Contenu géolocalisé simple** | 1 séquence unique | Notification 7s avant (temps ETA) | Sonore + icône | Fin → retour buffer normal | 1 contenu = 1 quota |
| **Audio-guide multi-séquences** | 2 à 50 séquences | Au point GPS exact (distance 30m) | Ding + toast 2s | Séquences s'enchaînent auto | 1 audio-guide = 1 quota (toutes séquences) |
**Fonctionnement GPS automatique** :
1. User démarre audio-guide en voiture (voir section 16.1 pour démarrage)
2. Séquence 1 démarre automatiquement au point GPS défini (rayon 30m)
3. Séquence 1 se termine
4. **Affichage progress bar** : distance temps réel + ETA jusqu'au prochain point
5. User roule vers point GPS suivant
6. Arrivée au point GPS suivant (rayon 30m) → **déclenchement automatique** séquence suivante
7. Notification sonore discrète : "Ding" (0.3s) + toast 2s : "Enclos des girafes"
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 [05-interactions-navigation.md](05-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
**Navigation manuelle CONSERVÉE** :
| Bouton | État | Comportement |
|--------|------|--------------|
| **[▶\|] Suivant** | ✅ Toujours actif | Passe séquence suivante immédiatement (même hors point GPS) |
| **[\|◀] Précédent** | ✅ Toujours actif | Retour séquence précédente (même hors point GPS) |
| **[⏸️] Pause** | ✅ | Pause temporaire |
| **Liste séquences** | ✅ | Saut direct possible |
**Use cases navigation manuelle** :
| Situation | Solution manuelle |
|-----------|-------------------|
| Embouteillage (séquence finie, point GPS loin) | User clique Suivant → avance manuellement |
| Point GPS inaccessible (route fermée) | User clique Suivant → skip point |
| Envie réécouter séquence précédente | User clique Précédent → retour |
| Passager manipule l'app | Passager navigue librement |
**Avertissement sécurité** :
- 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** :
```
Point GPS 1 (30m) → Séquence 1 AUTO → User roule → Distance affichée → Point GPS 2 (30m) → Séquence 2 AUTO
User clique Suivant (manuel) → Séquence 2 immédiate
```
**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)
---
#### 16.3.2 Affichage distance et guidage
**Décision** : Distance + direction (PAS de carte miniature)
**Interface en conduite** :
```
┌────────────────────────────────────────┐
│ 🚗 Audio-guide Voiture │
│ Safari du Paugre │
├────────────────────────────────────────┤
│ │
│ ▶️ 0:00 ──●────────── 2:15 │
│ │
│ Séquence 2/8 : Les lions │
│ │
│ ──────────────────────────────────── │
│ │
│ 📍 Prochain point │
│ │
│ Enclos des girafes │
│ │
│ ┌────────────────────────────────┐ │
│ │ │ │
│ │ ↗️ │ │
│ │ (direction) │ │
│ │ │ │
│ │ 320 mètres │ │
│ │ ≈ 40 secondes │ │
│ │ │ │
│ └────────────────────────────────┘ │
│ │
│ Vitesse actuelle : 28 km/h │
│ Vitesse recommandée : 20-30 km/h │
│ │
│ [|◀] [⏸️] [▶|] [📋 Liste] │
└────────────────────────────────────────┘
```
**Affichage entre deux séquences** :
Quand une séquence se termine et qu'il reste un point GPS suivant, l'interface bascule en mode "attente prochain point" :
```
┌────────────────────────────────────────┐
│ 🚗 Audio-guide Voiture │
│ Safari du Paugre │
├────────────────────────────────────────┤
│ │
│ ✅ Séquence 2/8 terminée │
│ Les lions │
│ │
│ ──────────────────────────────────── │
│ │
│ 📍 Prochain point │
│ │
│ Enclos des girafes │
│ │
│ ┌────────────────────────────────┐ │
│ │ [Progress bar] │ │
│ │ ████████░░░░░░░░░ 65% │ │
│ │ │ │
│ │ ↗️ │ │
│ │ (direction) │ │
│ │ │ │
│ │ 320 mètres │ │
│ │ ≈ 40 secondes │ │
│ │ │ │
│ └────────────────────────────────┘ │
│ │
│ Vitesse actuelle : 28 km/h │
│ │
│ [|◀] [▶️ Rejouer séq.] [▶|] │
└────────────────────────────────────────┘
```
**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
---
**Informations affichées** :
| Info | Mise à jour | Format |
|------|-------------|--------|
| **Distance** | Chaque seconde | "320 m" / "1.2 km" |
| **ETA** | Chaque seconde | "≈ 40 secondes" / "≈ 2 minutes" |
| **Direction** | Chaque 5s | Flèche indique direction (8 directions : ↑ ↗ → ↘ ↓ ↙ ← ↖) |
| **Vitesse actuelle** | Chaque seconde | "28 km/h" |
| **Vitesse recommandée** | Statique | "20-30 km/h" (définie par créateur) |
| **Progress bar** | Chaque seconde | Pourcentage parcouru vers prochain point |
**Calcul direction** :
```javascript
// Calcul angle entre position actuelle et prochain point
const currentGPS = getCurrentLocation();
const nextPoint = audioGuide.sequences[currentIndex + 1].location;
const angle = calculateBearing(currentGPS, nextPoint); // 0-360°
// Conversion en flèche (8 directions)
const arrows = ['↑', '↗', '→', '↘', '↓', '↙', '←', '↖'];
const index = Math.round(angle / 45) % 8;
const direction = arrows[index];
```
**Calcul ETA** :
```javascript
const distance = calculateDistance(currentGPS, nextPoint); // mètres
const currentSpeed = getCurrentSpeed(); // km/h
if (currentSpeed > 5) {
const eta = (distance / 1000) / currentSpeed * 3600; // secondes
return formatETA(eta); // "≈ 40 secondes" ou "≈ 2 minutes"
} else {
return "En attente de déplacement";
}
```
**Justification** :
- Distance + ETA = info essentielle sans surcharge visuelle
- Direction (flèche) = aide se repérer sans carte complexe
- Simplicité = moins distraction conducteur
- Économie batterie (pas de rendu carte)
---
#### 16.3.3 Rayon de déclenchement et tolérance
**Décision** : Rayon configurable créateur avec défauts intelligents
**Rayons par défaut** :
| Mode | Rayon déclenchement | Rayon "point manqué" | Justification |
|------|---------------------|----------------------|---------------|
| **🚗 Voiture** | 30 mètres | 100 mètres | Vitesse élevée = anticipation |
| **🚴 Vélo** | 50 mètres | 75 mètres | Vitesse variable, arrêts fréquents |
| **🚌 Transport** | 100 mètres | 150 mètres | Arrêts bus/train, moins précis |
**Configuration créateur** :
- Curseur rayon : **10m → 200m**
- Défaut pré-sélectionné selon mode choisi
- Preview visuel : cercle sur carte (lors création)
- Suggestion auto : "Recommandé : 30m pour voiture à 30 km/h"
**Gestion point manqué** :
```
User passe à 110m du point GPS
(hors rayon déclenchement 30m MAIS dans rayon tolérance 100m)
Toast : "⚠️ Point manqué : Enclos des girafes"
Popup 5 secondes :
┌────────────────────────────────────┐
│ Point manqué │
│ │
│ "Enclos des girafes" │
│ Vous êtes passé à 110m du point │
│ │
│ [🔊 Écouter quand même] │
│ [⏭️ Passer au suivant] │
│ [🔙 Faire demi-tour] │
└────────────────────────────────────┘
```
**Actions popup** :
| Bouton | Comportement |
|--------|--------------|
| **Écouter quand même** | Lance séquence immédiatement (même hors zone) |
| **Passer au suivant** | Skip séquence, continue vers prochain point |
| **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)
---
### 16.4 Modes Vélo et Transport
**Décision** : Même logique voiture avec tolérances ajustées
**Différences par rapport à mode voiture** :
| Paramètre | Voiture | Vélo | Transport |
|-----------|---------|------|-----------|
| **Rayon déclenchement** | 30m | 50m | 100m |
| **Rayon tolérance "point manqué"** | 100m | 75m | 150m |
| **Vitesse recommandée affichée** | 20-50 km/h | 10-25 km/h | Variable (selon ligne) |
| **Warning sécurité** | >10 km/h | >5 km/h | Désactivé |
**Mode Vélo spécificités** :
- Rayon plus large : vitesse variable, nombreux arrêts (feux, piétons)
- Warning sécurité dès 5 km/h (vélo en mouvement)
- Tolérance GPS moins stricte (tracé moins prévisible qu'auto)
**Mode Transport spécificités** :
- Rayon très large : arrêts fréquents (bus, train), ligne fixe
- Pas de warning sécurité (user = passager, pas conducteur)
- Vitesse recommandée = "Selon ligne" (pas de valeur fixe)
- Tolérance horaire : si bus en retard, point peut se déclencher avec 2-3 min de délai
**Comportement identique voiture** :
- Navigation manuelle conservée (boutons actifs)
- Affichage distance + ETA + direction
- Gestion point manqué
- 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
---
### 16.5 Publicités dans audio-guides
**Décision** : Pub auto-play entre séquences TOUS modes
#### 16.5.1 Règles universelles
**Insertion publicité** :
- Fréquence : **1 pub toutes les 5 séquences** (paramétrable admin 1/3 à 1/10)
- Gratuits uniquement, **Premium 0 pub**
- Pub s'enchaîne **automatiquement** après séquence
- Skippable après **5 secondes** (règle standard RoadWave)
- Volume normalisé -14 LUFS (comme pubs normales)
**Comportement MODE PIÉTON** :
```
Séquence 2 [fin]
→ Pub AUTO-PLAY
→ Pub se termine
→ PAUSE AUTO
→ Message "Séquence 3 prête. Appuyez sur Suivant."
→ User clique [▶|]
→ Séquence 3 démarre
```
**Comportement MODE VOITURE/VÉLO/TRANSPORT** :
```
Séquence 2 [fin]
→ Pub AUTO-PLAY
→ Pub se termine
→ ATTENTE point GPS suivant OU user clique Suivant
→ Séquence 3 démarre
```
**Schéma complet** :
| Mode | Après séquence normale | Après pub |
|------|------------------------|-----------|
| **Piéton** | Pause + attente user | Pause + attente user |
| **Voiture** | Attente GPS OU user clique Suivant | Attente GPS OU user clique Suivant |
| **Vélo** | Attente GPS OU user clique Suivant | Attente GPS OU user clique Suivant |
| **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
- Premium reste attractif (expérience 0 interruption)
- Modèle économique viable
---
#### 16.5.2 Métriques pub audio-guides
**Dashboard créateur** :
| Métrique | Affichage |
|----------|-----------|
| **Impressions pub** | Nombre de pubs insérées dans audio-guides |
| **Écoutes complètes pub** | Nombre de pubs écoutées >80% |
| **Taux skip pub** | % pubs skippées avant 5s vs après |
| **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)
---
### 16.6 Reprise et sauvegarde progression
**Décision** : Sauvegarde complète automatique avec popup intelligente
#### 16.6.1 Sauvegarde automatique
**Données sauvegardées** :
| Info | Détail | Utilité |
|------|--------|---------|
| **Audio-guide ID** | Identifiant unique | Retrouver audio-guide |
| **Séquence actuelle** | Index (ex: 3/12) | Reprise position |
| **Position dans séquence** | Timestamp exact (ex: 1:42/3:20) | Reprise exacte |
| **Séquences écoutées** | Liste avec checkmarks ✅ | Historique progression |
| **Date dernière écoute** | Timestamp | Proposer reprise si <30j |
| **GPS dernière position** | Coordonnées optionnelles | Info contextuelle (non utilisée pour reprise) |
**Stockage** :
| Environnement | Technologie | Utilité |
|---------------|-------------|---------|
| **Local** | SQLite mobile | Fonctionnement offline |
| **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)
---
#### 16.6.2 Interface de reprise
**Conditions popup** :
- Dernière écoute **<30 jours**
- Progression **>0%** et **<100%** (pas terminé)
**Popup reprise** :
```
┌────────────────────────────────────────┐
│ Reprendre l'audio-guide ? │
├────────────────────────────────────────┤
│ 🚗 Safari du Paugre │
│ @safari_createur │
│ │
│ Progression : 3/8 séquences écoutées │
│ Dernière écoute : il y a 2 jours │
│ │
│ Vous étiez à : │
│ "Les lions" (1:42/3:20) │
│ │
│ [▶️ Reprendre] [🔄 Recommencer] │
│ [📋 Voir toutes les séquences] │
└────────────────────────────────────────┘
```
**Actions** :
| Bouton | Comportement |
|--------|--------------|
| **Reprendre** | Continue séquence 3 à position 1:42 exacte |
| **Recommencer** | Reset progression, démarre séquence 1 depuis 0:00 |
| **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
---
#### 16.6.3 Multi-device
**Scénario** :
1. User démarre audio-guide sur iPhone (séquences 1-3)
2. Progression sync cloud
3. Lendemain : user ouvre app sur iPad
4. Popup : "Reprendre Safari du Paugre sur cet appareil ?"
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
---
## Récapitulatif Section 16
| Point | Décision | Coût | Complexité |
|-------|----------|------|------------|
| **16.1** Types audio-guides | 4 modes (piéton/voiture/vélo/transport) avec détection auto | 0€ | Moyenne |
| **16.1.2** Création | Formulaire séquences + GPS + rayon + wizard guidé | 0€ | Moyenne |
| **16.2.1** Piéton - Passages | Manuel AVEC pub auto-play entre séquences, pause après | 0€ | Faible |
| **16.2.2** Piéton - Navigation | Liberté totale (skip, retour, saut direct liste) | 0€ | Faible |
| **16.3.1** Voiture - Déclenchement | GPS auto + boutons manuels actifs (warning sécurité si >10 km/h) | 0€ | Moyenne |
| **16.3.2** Voiture - Affichage | Distance + ETA + direction (flèche) + vitesse (PAS de carte) | 0€ | Faible |
| **16.3.3** Voiture - Rayon | Configurable créateur (défauts 30m/50m/100m selon mode) | 0€ | Faible |
| **16.4** Vélo & Transport | Mêmes règles avec tolérances ajustées + warning adapté | 0€ | Faible |
| **16.5** Publicités | 1/5 séquences, auto-play TOUS modes, skippable 5s | 0€ | Faible |
| **16.6.1** Sauvegarde | Complète (séquence + position + historique) local + cloud | 0€ | Faible |
| **16.6.2** Reprise | Popup intelligente avec choix (reprendre/recommencer), expiration 30j | 0€ | Faible |
| **16.6.3** Multi-device | Sync cloud PostgreSQL (reprendre sur autre appareil) | 0€ | Faible |
**Coût total MVP : 0€** (GPS natif, calcul distance PostGIS)
---
## Points d'attention pour Gherkin
- Tester 4 modes audio-guides (détection vitesse auto)
- Tester création séquences avec points GPS + rayon configurable
- Tester mode piéton : pause après séquence + pub auto-play + pause après pub + clic Suivant
- Tester navigation libre piéton (skip, retour, saut direct liste)
- Tester mode voiture : déclenchement GPS auto rayon 30m
- Tester navigation manuelle voiture : boutons actifs + warning si vitesse >10 km/h
- Tester affichage distance + ETA + direction (flèche 8 directions)
- Tester rayon tolérance "point manqué" (popup 3 actions)
- Tester mode vélo (rayon 50m) et transport (rayon 100m)
- Tester insertion pub 1/5 séquences tous modes avec auto-play
- Tester sauvegarde progression locale + sync cloud
- Tester popup reprise (3 boutons : reprendre/recommencer/voir liste)
- Tester expiration progression 30 jours
- Tester multi-device : démarrer iPhone, continuer iPad
- Tester gestion conflit progression simultanée 2 appareils

View File

@@ -0,0 +1,757 @@
## 17. Contenus géolocalisés en mode voiture
### 17.1 Principe général
**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")
- App doit être ouverte (premier plan)
**Distinction avec audio-guides** :
| Type | Description | Use case |
|------|-------------|----------|
| **Contenu géolocalisé simple** (cette section) | 1 point GPS unique, 1 contenu audio | Monument, panneau historique, point de vue |
| **Audio-guide multi-séquences** (section 16) | Plusieurs points GPS, séquences enchaînées | Safari-parc, circuit touristique, parcours urbain |
---
### 17.2 Détection et notification
#### 17.2.1 Calcul ETA (Estimated Time of Arrival)
**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)
**Implémentation iOS (Swift)** :
```swift
import CoreLocation
class GeoContentDetector {
let locationManager = CLLocationManager()
var geoContents: [GeoContent] = [] // Points GPS proches
func calculateETA(to targetLocation: CLLocation) -> TimeInterval? {
guard let currentLocation = locationManager.location,
let currentSpeed = currentLocation.speed, // m/s
currentSpeed > 0 else { return nil }
let distance = currentLocation.distance(from: targetLocation) // mètres
let eta = distance / currentSpeed // secondes
return eta
}
func checkTriggers() {
// Appelé toutes les 1 seconde
for geoContent in geoContents {
let targetLocation = CLLocation(
latitude: geoContent.latitude,
longitude: geoContent.longitude
)
// Cas particulier : vitesse très faible
if let speed = locationManager.location?.speed,
speed < 1.4, // < 5 km/h
let distance = locationManager.location?.distance(from: targetLocation),
distance < 50 {
triggerNotification(for: geoContent)
continue
}
// Cas normal : calcul ETA
if let eta = calculateETA(to: targetLocation),
eta <= 7.0 && eta > 0 {
triggerNotification(for: geoContent)
}
}
}
}
```
**Implémentation Android (Kotlin)** :
```kotlin
import android.location.Location
import com.google.android.gms.location.FusedLocationProviderClient
class GeoContentDetector(private val fusedLocationClient: FusedLocationProviderClient) {
private var geoContents: List<GeoContent> = emptyList()
fun calculateETA(targetLocation: Location, currentLocation: Location): Double? {
val speed = currentLocation.speed // m/s
if (speed <= 0) return null
val distance = currentLocation.distanceTo(targetLocation) // mètres
return distance / speed // secondes
}
fun checkTriggers(currentLocation: Location) {
for (geoContent in geoContents) {
val targetLocation = Location("").apply {
latitude = geoContent.latitude
longitude = geoContent.longitude
}
// Cas particulier : vitesse très faible (< 5 km/h)
if (currentLocation.speed < 1.4 &&
currentLocation.distanceTo(targetLocation) < 50) {
triggerNotification(geoContent)
continue
}
// Cas normal : calcul ETA
val eta = calculateETA(targetLocation, currentLocation)
if (eta != null && eta <= 7.0 && eta > 0) {
triggerNotification(geoContent)
}
}
}
}
```
**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
---
#### 17.2.2 Format de la notification
**Philosophie** : **Minimalisme absolu** pour sécurité routière
**Pas de** :
- Titre texte à lire
- Description longue
- Bouton "Annuler" ou "Plus tard"
- Popup bloquante
- Image/cover du contenu
**Uniquement** :
- Son bref (notification)
- Icône selon tag du contenu
- Compteur chiffres (7→1)
**Icônes par tag** :
| Tag | Icône | Couleur |
|-----|-------|---------|
| Culture générale | 🏛️ | Bleu |
| Histoire | 📜 | Marron |
| Voyage | ✈️ | Vert |
| Famille | 👨‍👩‍👧 | Orange |
| Musique | 🎵 | Rose |
| Sport | ⚽ | Rouge |
| Technologie | 💻 | Gris |
| Automobile | 🚗 | Noir |
| Politique | 🏛️ | Bleu foncé |
| Économie | 📈 | Vert foncé |
| Cryptomonnaie | ₿ | Or |
| Santé | 🏥 | Rouge clair |
| Amour | ❤️ | Rose vif |
**Interface visuelle (minimaliste)** :
```
┌────────────────────────────────────────┐
│ [Player actuel] │
│ ▶️ Podcast en cours... │
│ 0:00 ────●──────────── 12:34 │
│ │
│ [|◀] [⏸️] [▶|] │
├────────────────────────────────────────┤
│ 🏛️ │
│ 7 │
└────────────────────────────────────────┘
```
**É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)
- **Configurable** : user peut choisir dans settings :
- Bip système
- Son RoadWave personnalisé
- Muet (visuel uniquement)
---
#### 17.2.2b Conformité CarPlay / Android Auto
**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
**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)
**Détection automatique** :
```swift
// iOS - Détection CarPlay
import MediaPlayer
class NotificationManager {
var isCarPlayActive: Bool {
if #available(iOS 14.0, *) {
return MPNowPlayingInfoCenter.default().playbackState == .playing &&
MPPlayableContentManager.shared().context != nil
}
return false
}
func showGeoNotification(content: GeoContent) {
if isCarPlayActive {
// CarPlay : sonore uniquement
AudioServicesPlaySystemSound(1052) // Notification beep
// Pas d'overlay visuel
} else {
// Mode normal : sonore + icône + compteur
showFullNotification(content)
}
}
}
```
```kotlin
// Android - Détection Android Auto
import android.car.Car
class NotificationManager(private val context: Context) {
private fun isAndroidAutoActive(): Boolean {
val carManager = context.getSystemService(Context.CAR_SERVICE) as? Car
return carManager?.isConnected == true
}
fun showGeoNotification(content: GeoContent) {
if (isAndroidAutoActive()) {
// Android Auto : sonore uniquement
val notification = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setSound(defaultSoundUri)
.setCategory(NotificationCompat.CATEGORY_NAVIGATION)
.build()
notificationManager.notify(NOTIFICATION_ID, notification)
} else {
// Mode normal : sonore + overlay visuel
showFullNotification(content)
}
}
}
```
**Expérience utilisateur en CarPlay/Android Auto** :
1. User roule, app connectée à CarPlay/Android Auto
2. ETA 7s atteint → notification sonore uniquement (bip)
3. User entend le bip, sait qu'un contenu géolocalisé est disponible
4. User appuie sur bouton "Suivant" physique au volant
5. Décompte 5s démarre (audio continue normalement)
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)
---
#### 17.2.3 Décompte après validation
**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é
- Transition audio fluide (pas de silence)
**Cas particulier : contenu actuel se termine pendant le décompte**
Exemple : User clique "Suivant", décompte démarre à 5s, mais contenu actuel se termine après 2s.
```
Timeline :
T+0s : User clique "Suivant", décompte démarre (5...4...3...)
T+2s : Contenu actuel se termine
→ Contenu suivant du buffer démarre immédiatement
→ Décompte continue (2...1...)
T+5s : Décompte atteint 0
→ Fade out du contenu buffer (celui qui a démarré à T+2s)
→ Fade in du contenu géolocalisé
```
**Justification** :
- Évite silence inconfortable pendant décompte
- User continue d'écouter du contenu intéressant
- Transition naturelle
**Interface pendant décompte** :
```
┌────────────────────────────────────────┐
│ [Player actuel] │
│ ▶️ Podcast en cours... │
│ 0:00 ────●──────────── 12:34 │
│ │
│ [|◀] [⏸️] [▶|] │
├────────────────────────────────────────┤
│ │
│ 3 │
│ │
│ Contenu géolocalisé arrive │
└────────────────────────────────────────┘
```
---
### 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
**Solution : quota horaire + cooldown**
#### 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
**Exemple** :
```
10h05 : Contenu 1 notifié ✅ (quota : 1/6)
10h12 : Contenu 2 notifié ✅ (quota : 2/6)
10h18 : Contenu 3 notifié ✅ (quota : 3/6)
10h25 : Contenu 4 notifié ✅ (quota : 4/6)
10h33 : Contenu 5 notifié ✅ (quota : 5/6)
10h41 : Contenu 6 notifié ✅ (quota : 6/6)
10h52 : Contenu 7 détecté mais ignoré ❌ (quota atteint)
11h06 : Contenu 1 expire (>60 min) → quota libéré (5/6)
11h08 : Contenu 8 notifié ✅ (quota : 6/6)
```
**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
**Implémentation backend (Redis)** :
```go
// Structure quota (sorted set avec timestamps)
// Clé : user:{user_id}:geo_quota
// Valeur : ZADD avec timestamp
func CanNotify(userID string) bool {
key := fmt.Sprintf("user:%s:geo_quota", userID)
now := time.Now().Unix()
oneHourAgo := now - 3600
// Supprimer entrées > 1h
redis.ZRemRangeByScore(key, "-inf", oneHourAgo)
// Compter entrées restantes
count := redis.ZCard(key)
return count < 6
}
func RecordNotification(userID string, contentID string) {
key := fmt.Sprintf("user:%s:geo_quota", userID)
now := time.Now().Unix()
// Ajouter entrée avec timestamp actuel
redis.ZAdd(key, now, contentID)
// TTL 1h (sécurité)
redis.Expire(key, 3600)
}
```
---
#### 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
**Timeline exemple** :
```
10h00 : Notification contenu A (7s)
10h00+7s : User n'a pas cliqué → cooldown activé
10h05 : Contenu B détecté → ignoré (cooldown actif)
10h08 : Contenu C détecté → ignoré (cooldown actif)
10h10 : Cooldown expire
10h11 : Contenu D détecté → notification affichée ✅
```
**Implémentation (Redis)** :
```go
func IsInCooldown(userID string) bool {
key := fmt.Sprintf("user:%s:geo_cooldown", userID)
exists := redis.Exists(key)
return exists == 1
}
func ActivateCooldown(userID string) {
key := fmt.Sprintf("user:%s:geo_cooldown", userID)
redis.Set(key, "1", 10*time.Minute)
}
```
**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
---
### 17.4 Navigation avec contenus géolocalisés
#### 17.4.1 Historique de navigation
**Structure** (voir [05-interactions-navigation.md](05-interactions-navigation.md#52-commande-précédent)) :
- **10 contenus maximum** en mémoire (Redis List)
- Structure : `[{content_id, position_seconds, listened_at, type}, ...]`
- FIFO : au-delà de 10, suppression du plus ancien
**Comportement avec contenus géolocalisés** :
Les contenus géolocalisés s'intègrent dans l'historique comme des contenus normaux :
```
Historique :
[
{id: "buffer_1", position: 180, type: "contextuel"},
{id: "geo_tour_eiffel", position: 42, type: "geo_anchored"},
{id: "buffer_2", position: 90, type: "neutre"},
{id: "buffer_3", position: 0, type: "contextuel"}
]
```
---
#### 17.4.2 Commande "Précédent" avec contenu géolocalisé
**Cas A : User écoute contenu géolocalisé, puis skip**
Timeline :
1. Contenu buffer_1 joue (position 3:00)
2. Notification contenu géolocalisé
3. User clique "Suivant" → décompte 5s → contenu géolocalisé démarre
4. User écoute 42 secondes du contenu géolocalisé
5. User appuie "Suivant" (skip) → contenu buffer_2 démarre
6. User appuie "Précédent" → **retour au contenu géolocalisé à 42s**
**Règle** : Comme décrit dans [05-interactions-navigation.md](05-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)
Dans ce cas : 42s ≥ 10s → le contenu géolocalisé reprend à 42s (où user l'avait arrêté)
---
**Cas B : User ne clique pas pendant notification (ignore)**
Timeline :
1. Contenu buffer_1 joue
2. Notification contenu géolocalisé (7s)
3. User ne clique pas → notification disparaît
4. Contenu buffer_1 continue
5. User appuie "Précédent" → **retour contenu avant buffer_1**
**Règle** : Contenu géolocalisé ignoré n'entre PAS dans l'historique.
---
**Cas C : User skip pendant le décompte**
Timeline :
1. Notification contenu géolocalisé
2. User clique "Suivant" → décompte 5s démarre (5...4...3...)
3. User re-clique "Suivant" pendant le décompte → **annule le décompte**
4. Contenu suivant du buffer démarre
5. Contenu géolocalisé n'entre PAS dans l'historique
**Justification** : User a explicitement annulé, pas d'intérêt pour ce contenu.
---
### 17.5 Basculement automatique voiture ↔ piéton
**Principe** : Détection automatique du mode selon vitesse GPS, sans action utilisateur.
#### 17.5.1 Calcul vitesse moyenne
**Méthode** : Moyenne glissante sur 30 secondes
```javascript
// Historique GPS : 30 derniers points (1 point/seconde)
const gpsHistory = [
{lat: 48.8584, lon: 2.2945, speed: 8.3, timestamp: 1642861200},
{lat: 48.8585, lon: 2.2946, speed: 8.5, timestamp: 1642861201},
// ... 28 autres points
];
// Calcul vitesse moyenne
const avgSpeed = gpsHistory
.reduce((sum, point) => sum + point.speed, 0) / gpsHistory.length;
// km/h = m/s × 3.6
const avgSpeedKmh = avgSpeed * 3.6;
if (avgSpeedKmh < 5) {
mode = "piéton";
} else {
mode = "voiture";
}
```
**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
- Si vitesse reste à 3 km/h pendant 10s → basculement piéton
---
#### 17.5.2 Effets du basculement
**Passage voiture → piéton** :
| Paramètre | Avant (voiture) | Après (piéton) |
|-----------|----------------|----------------|
| **App requise** | Premier plan | Arrière-plan OK |
| **Notification** | Sonore + icône + compteur | Push système standard |
| **Rayon détection** | ETA 7s (distance variable) | 200 mètres fixes |
| **Type contenu** | Tous contenus géolocalisés | Audio-guides uniquement |
**Passage piéton → voiture** :
| Paramètre | Avant (piéton) | Après (voiture) |
|-----------|---------------|----------------|
| **App requise** | Arrière-plan OK | Premier plan |
| **Notification** | Push système standard | Sonore + icône + compteur |
| **Rayon détection** | 200 mètres fixes | ETA 7s (distance variable) |
| **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)
---
### 17.6 Edge cases
#### 17.6.1 User passe trop vite devant le point (>130 km/h)
**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"
- Décompte 5s démarre
- À 130 km/h, user parcourt : 5 × 36.1 = 180m pendant décompte
- Distance restante au démarrage contenu : 252 - 180 = **72 mètres avant le point**
**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
- Distance restante : 350 - 250 = **100m avant le point**
- Contenu démarre encore avant le point ✅
---
#### 17.6.2 Multiples points géolocalisés proches
**Scénario** : Route départementale avec 3 châteaux espacés de 800m chacun.
```
Château A ----800m---- Château B ----800m---- Château C
```
À 50 km/h (13.9 m/s), user met 57 secondes pour parcourir 800m.
**Timeline** :
```
T+0s : Notification Château A (7s avant)
T+7s : User clique "Suivant" → décompte 5s
T+12s : Contenu Château A démarre
T+30s : Contenu Château A se termine (durée 18s)
T+30s : Retour buffer normal (contenu contextuel)
T+50s : Notification Château B devrait se déclencher
MAIS : quota 1/6 utilisé, pas de cooldown (user a validé A)
→ Notification affichée ✅
T+57s : User clique "Suivant" → contenu Château B démarre
...
```
**Problème** : Si user ignore une notification, cooldown 10 min bloque les suivantes.
**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
**Implémentation** :
```go
func CalculateCooldown(userID string) time.Duration {
// Récupérer historique dernières notifications
history := getNotificationHistory(userID, 3) // 3 dernières
validatedCount := 0
for _, notif := range history {
if notif.Validated {
validatedCount++
}
}
if validatedCount >= 2 {
return 5 * time.Minute // Cooldown réduit
}
return 10 * time.Minute // Cooldown standard
}
```
---
#### 17.6.3 User arrêté longtemps près d'un point (parking)
**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)
---
### 17.7 Récapitulatif
| Point | Décision | Justification |
|-------|----------|---------------|
| **Détection** | ETA 7s avant point (API GPS native) | Précis, fiable, adapté à toutes vitesses |
| **Notification** | Sonore + icône + compteur (pas de texte) | Sécurité routière, minimalisme |
| **Validation** | Bouton "Suivant" uniquement | Un seul geste, simple, pas de distraction |
| **Décompte** | 5s avec contenu actuel qui continue | Évite silence, fluidité |
| **Quota** | 6 contenus/heure, fenêtre glissante | Anti-spam efficace |
| **Cooldown** | 10 min après notification ignorée | Respecte choix utilisateur |
| **Exception audio-guides** | Toutes séquences comptent comme 1 | Encourage création audio-guides |
| **Basculement auto** | Vitesse < 5 km/h = piéton, ≥ 5 km/h = voiture | Transparent, pas de friction |
| **Mode stationnement** | Vitesse < 1 km/h pendant 2 min → piéton | Évite notifications inutiles |
---
## Récapitulatif Section 17
| Point | Décision | Coût | Complexité |
|-------|----------|------|------------|
| **17.1** Principe général | Notification 7s avant, app ouverte requise | 0€ | Faible |
| **17.2.1** Calcul ETA | API GPS native iOS/Android | 0€ | Faible |
| **17.2.2** Format notification | Sonore + icône + compteur (minimaliste) | 0€ | Faible |
| **17.2.3** Décompte 5s | Contenu actuel continue, transition fluide | 0€ | Faible |
| **17.3.1** Quota 6/h | Redis sorted set, fenêtre glissante | 0€ | Moyenne |
| **17.3.2** Cooldown 10 min | Redis TTL après ignorance | 0€ | Faible |
| **17.4** Historique navigation | 10 contenus max, FIFO, comme contenus normaux | 0€ | Faible |
| **17.5** Basculement auto | Vitesse moyenne 30s, hysteresis 10s | 0€ | Moyenne |
| **17.6** Edge cases | Haute vitesse, points multiples, stationnement | 0€ | Moyenne |
**Coût total MVP : 0€** (GPS natif, Redis existant)
---
## Points d'attention pour Gherkin
- Tester calcul ETA à différentes vitesses (10 km/h, 50 km/h, 130 km/h)
- Tester cas vitesse < 5 km/h ET distance < 50m (notification immédiate)
- Tester affichage notification (icône + compteur, pas de texte)
- Tester validation "Suivant" → décompte 5s → contenu démarre
- Tester contenu actuel se termine pendant décompte → buffer démarre
- Tester quota 6/h : 7e notification ignorée
- Tester cooldown 10 min après notification ignorée
- Tester exception audio-guides (toutes séquences = 1 quota)
- Tester navigation "Précédent" après skip contenu géolocalisé (position sauvegardée)
- Tester basculement voiture → piéton (vitesse < 5 km/h stable 10s)
- Tester basculement piéton → voiture (vitesse ≥ 5 km/h stable 10s)
- Tester mode stationnement (vitesse < 1 km/h pendant 2 min)
- Tester multiples points proches (notifications successives si quota OK)
- Tester haute vitesse (130 km/h) : notification 252m avant, contenu démarre au bon moment

View File

@@ -0,0 +1,150 @@
## 11. Mode offline
### 11.1 Téléchargement
**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)
- "Ma région" (sélection liste)
- Recherche manuelle : "Paris", "Lyon", "Marseille", etc.
**Nombre de contenus téléchargeables** :
| Statut | Limite | Affichage |
|--------|--------|-----------|
| **Gratuit** | 50 contenus max | "12/50 contenus téléchargés" |
| **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
**Connexion WiFi/Mobile** :
**Par défaut** : WiFi uniquement
**Sur données mobiles** :
1. User clique "Télécharger"
2. Détection : pas de WiFi
3. Popup : "Vous n'êtes pas connecté en WiFi. Télécharger via données mobiles consommera environ **X MB**. Continuer ?"
4. Boutons : "Attendre WiFi" / "Continuer"
**Calcul estimation** :
```
Nombre contenus × durée moyenne × bitrate qualité
Exemple : 20 contenus × 5 min × 48 kbps = ~72 MB
```
**Qualité audio téléchargement** :
| Qualité | Bitrate | Taille | Disponibilité |
|---------|---------|--------|---------------|
| **Basse** | 24 kbps | ~10 MB/h | Gratuit + Premium |
| **Standard** | 48 kbps | ~20 MB/h | Gratuit + Premium (défaut) |
| **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é
---
### 11.2 Validité et renouvellement
**Durée de validité** : 30 jours après téléchargement
**Standard industrie** :
- Spotify : 30 jours
- YouTube Music : 30 jours
- Deezer : 30 jours
**Renouvellement automatique** :
```
App détecte WiFi + contenus >25 jours
→ Requête API : GET /offline/contents/refresh
→ Backend vérifie pour chaque contenu :
- Abonnement Premium toujours actif ?
- Contenu pas modéré/supprimé ?
- Métadonnées à jour ?
→ Renouvelle validité à 30 jours supplémentaires
→ Mise à jour métadonnées (titre, créateur, statut)
→ Pas de re-téléchargement audio (sauf si fichier corrompu)
```
**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
---
### 11.3 Synchronisation actions offline
**Actions stockées localement (SQLite)** :
- Likes/unlikes
- Abonnements/désabonnements
- Signalements
- Progression audio-guides
**Sync automatique à la reconnexion** :
```
1. App détecte reconnexion Internet
2. Récupération queue locale : SELECT * FROM pending_actions ORDER BY created_at
3. Envoi batch API : POST /sync/actions
4. Backend traite chaque action
5. Confirmation réception : DELETE FROM pending_actions WHERE id IN (...)
6. Toast : "3 likes et 1 abonnement synchronisés"
```
**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)
**Conflits contenus supprimés** :
```
Backend retourne : {deleted_content_ids: [123, 456]}
→ App supprime fichiers locaux
→ Si contenu 123 en cours d'écoute :
- Attendre fin lecture actuelle
- Passage auto suivant après 2s
→ Toast : "1 contenu téléchargé a été retiré (violation règles)"
```
**Justification** :
- **Pas de conflit possible** : actions unilatérales user (likes/abonnements)
- **UX fluide** : pas de blocage offline
- **Batch = économie** : requêtes HTTP groupées
- **Conformité modération** : contenu illégal disparaît même offline
---
## Récapitulatif Section 11
| Aspect | Décision | Valeur |
|--------|----------|--------|
| **Zone téléchargement** | Choix | Manuel (autour/ville/département/région/recherche) |
| **Limite gratuit** | Contenus | 50 max |
| **Limite Premium** | Contenus | Illimité (espace disque) |
| **Connexion** | Par défaut | WiFi (mobile avec confirmation) |
| **Qualité Standard** | Bitrate | 48 kbps Opus |
| **Qualité Haute** | Bitrate | 64 kbps (Premium uniquement) |
| **Validité** | Durée | 30 jours |
| **Renouvellement** | Mode | Automatique si WiFi |
| **Notification expiration** | Délai | J-3 |
| **Sync actions** | Mode | Batch automatique reconnexion |
| **Rétention queue** | Durée | 7 jours max |
---

View File

@@ -0,0 +1,319 @@
## 8. Abonnements et notifications
### 8.1 Impact sur l'algorithme
**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é
```
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
**Exemple concret** :
```
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
→ Score final : 0.53
→ Score avec boost : 0.53 × 1.3 = 0.69
→ Contenu A proposé en premier (0.80 > 0.69)
```
**Cas où abonnement fait la différence** :
```
Contenu A (non suivi) : score 0.70
Contenu B (suivi) : score 0.60 → avec boost 0.78
→ Contenu B proposé (boost fait pencher la balance)
```
**Justification** :
- **Équilibre** : valorise abonnements sans enfermer utilisateur
- **Découverte** : contenus viraux/locaux peuvent toujours émerger
- **Prévisible** : boost fixe, pas de logique opaque
- **Coût 0** : multiplicateur simple dans l'algo
---
### 8.2 Notifications contextuelles
**Décision** : Push adapté selon contexte (voiture vs à pied) + limite 10/jour
**Détection contexte utilisateur** :
| Contexte | Détection | Comportement |
|----------|-----------|--------------|
| **En voiture** | Vitesse GPS >10 km/h | Notifications silencieuses (in-app uniquement) + commandes volant |
| **À pied** | Vitesse GPS <5 km/h | Notifications push actives + interface tactile/vocale |
**Notifications activées** :
#### En voiture (mode conduite)
| Événement | Notification | Comportement |
|-----------|--------------|--------------|
| **Nouveau contenu créateur suivi** | In-app uniquement | Badge compteur, pas de push (sécurité) |
| **Live créateur suivi** | In-app uniquement | Badge compteur, pas de push |
| **Point d'intérêt proche** | Audio notification | Bip + annonce vocale : "Audio-guide disponible" |
#### À pied (mode piéton)
| Événement | Notification | Comportement |
|-----------|--------------|--------------|
| **Nouveau contenu créateur suivi** | ✅ Push | Si utilisateur dans zone géo du contenu |
| **Live créateur suivi** | ✅ Push | Si utilisateur dans zone géo |
| **Audio-guide disponible** | ✅ Push | "📍 Audio-guide disponible : [Lieu]" |
| **Séquence suivante suggérée** | Audio notification | Annonce vocale : "Pièce suivante disponible" |
**Format notifications** :
**Nouveau contenu** :
```
🎧 [Nom créateur] a publié : "[Titre contenu]"
Tap pour écouter
```
**Live en direct** :
```
🔴 [Nom créateur] est en direct : "[Titre live]"
Tap pour rejoindre
```
**Audio-guide à pied** :
```
📍 Audio-guide disponible : [Nom du lieu]
Choisissez parmi 3 guides pour [Musée du Louvre]
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)
**Gestion préférences** :
| Préférence | Défaut | Description |
|------------|--------|-------------|
| **Nouveaux contenus** | ✅ Activé | Push à chaque nouveau contenu (à pied uniquement) |
| **Lives** | ✅ Activé | Push au démarrage live (à pied uniquement) |
| **Audio-guides proximité** | ✅ Activé | Push quand audio-guide détecté à <100m |
| **Mode silencieux** | ✅ Activé (22h-8h) | Pas de push nocturne |
| **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
- **Filtrage géo** : pertinence maximale (pas de notif inutiles)
- **Coût** : Firebase Cloud Messaging (gratuit jusqu'à volume élevé)
---
### 8.3 Mode Audio-guide (piéton)
**Décision** : Navigation manuelle multiséquence + choix parmi plusieurs guides
**Fonctionnement** :
#### Détection et proposition
1. Utilisateur à pied (<5 km/h) passe à <**100m** d'un lieu avec audio-guides
2. **Notification push** : "📍 Audio-guide disponible : [Musée du Louvre]"
3. Tap notification → **Page de sélection** audio-guides
#### Page de sélection
**Affichage** :
```
📍 Musée du Louvre
Choisissez votre guide :
┌─────────────────────────────────┐
│ 🎨 Visite complète (45 min) │
│ Par [Créateur A] • 12 séquences│
│ ⭐ 4.8 • 1.2K écoutes │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ 🏛️ Œuvres majeures (20 min) │
│ Par [Créateur B] • 5 séquences │
│ ⭐ 4.9 • 3.5K écoutes │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ 👶 Visite famille (30 min) │
│ Par [Créateur C] • 8 séquences │
│ ⭐ 4.7 • 850 écoutes │
└─────────────────────────────────┘
```
#### Interface audio-guide
**Après sélection** :
```
🎨 Visite complète • Musée du Louvre
Piste actuelle : 2/12
"La Joconde - Histoire et mystères"
[████████────────────] 3:24 / 6:50
Liste des séquences :
✅ 1. Introduction et architecture
▶️ 2. La Joconde - Histoire et mystères
⏸️ 3. Vénus de Milo
⏸️ 4. Victoire de Samothrace
⏸️ 5. Peintures Renaissance
...
⏸️ 12. Conclusion et boutique
```
**Navigation** :
| Action | Geste | Effet |
|--------|-------|-------|
| **Séquence suivante** | Tap "Suivant" ou commande vocale "Suivant" | Passe à séquence N+1 |
| **Séquence précédente** | Tap "Précédent" ou commande vocale "Précédent" | Revient à séquence N-1 |
| **Saut direct** | Tap séquence dans liste | Lecture séquence choisie |
| **Pause** | Tap bouton pause | Met en pause, reprise position exacte |
| **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
**Création audio-guide multiséquence** :
**Processus créateur** :
1. Créateur upload **plusieurs fichiers audio** (1 par séquence)
2. Numérote les séquences : "Séquence 1", "Séquence 2", etc.
3. Titre chaque séquence : "Introduction", "La Joconde", etc.
4. Définit **point GPS unique** pour tout le guide (centre du lieu)
5. Métadonnées : durée totale calculée automatiquement
**Format stockage** :
```json
{
"guide_id": "abc123",
"title": "Visite complète Musée du Louvre",
"location": {"lat": 48.8606, "lon": 2.3376, "radius": 200},
"sequences": [
{
"sequence_number": 1,
"title": "Introduction et architecture",
"audio_url": "https://cdn.../seq1.mp3",
"duration_seconds": 180
},
{
"sequence_number": 2,
"title": "La Joconde - Histoire et mystères",
"audio_url": "https://cdn.../seq2.mp3",
"duration_seconds": 410
},
...
],
"total_duration_seconds": 2700,
"creator_id": "creator_xyz"
}
```
**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)
- **Engagement** : sauvegarde progression = incitation terminer
- **Coût** : réutilise infra contenu standard (juste métadonnées séquences)
---
### 8.4 Limites et désabonnement
**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
- **Usage réaliste** : 200 créateurs = déjà énorme (vs 100-150 sur YouTube/Twitter)
- **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** (défini en [ADR-010](../adr/010-commandes-volant.md))
- 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
- Pas de confirmation (action réversible)
**Exemple** :
```
Créateur tague ses contenus : Automobile, Voyage
Abonnement :
→ Jauge Automobile : 60% → 65% (+5%)
→ Jauge Voyage : 55% → 60% (+5%)
3 mois plus tard, désabonnement :
→ Jauge Automobile : 65% → 60% (-5%)
→ Jauge Voyage : 60% → 55% (-5%)
```
**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)
- **Coût** : table abonnements PostgreSQL standard
---
## Récapitulatif Section 8

View File

@@ -0,0 +1,135 @@
## 12. Gestion des erreurs
### 12.1 Aucun contenu disponible
**Stratégie** : Élargissement automatique progressif
**Flow** :
```
1. Recherche rayon 50 km → aucun résultat
2. Élargissement auto 100 km
3. Si toujours rien → département
4. Si toujours rien → région
5. Dernier recours → contenu national (toujours disponible)
```
**Messages adaptatifs** :
| Cas | Message |
|-----|---------|
| **Trouvé à 100 km** | "Aucun contenu dans votre zone immédiate. Voici du contenu à proximité (100 km)" |
| **Trouvé département** | "Aucun contenu local disponible. Voici du contenu dans votre département" |
| **Contenu national** | "Aucun contenu local disponible. Voici du contenu national qui pourrait vous intéresser" |
**Justification** :
- **UX fluide** : pas de message d'erreur bloquant "Aucun contenu"
- **User ne reste jamais sans contenu**
- **Contenu national = filet de sécurité** : actualités Le Monde, podcasts génériques
---
### 12.2 Contenu signalé/supprimé pendant l'écoute
**Décision** : Pas d'interruption brutale
**Flow** :
```
1. Contenu supprimé côté backend (modération)
2. Si contenu en écoute → laisser terminer lecture en cours
3. Après fin lecture → désactiver bouton "Précédent" pour ce contenu
4. Passage automatique suivant après 2s
5. Toast notification discrète : "Contenu précédent retiré (violation règles)"
```
**Si tentative "Précédent" manuellement** :
- Message : "Ce contenu n'est plus disponible"
- Retour au contenu actuel
**Justification** :
- **Sécurité routière** : pas d'interruption brutale pendant conduite
- **User informé mais pas alarmé** : message discret
- **Empêche réécoute** : contenu modéré inaccessible
---
### 12.3 Perte de réseau
**Buffer adaptatif** (cf. TECHNICAL.md) :
| Réseau | Buffer min | Buffer cible | Buffer max |
|--------|------------|--------------|------------|
| **WiFi** | 5s | 30s | 120s |
| **4G/5G** | 10s | 45s | 120s |
| **3G** | 30s | 90s | 300s |
**Comportement détaillé** :
**Phase 1 : Connexion instable** (latence élevée, paquets perdus)
- Aucun message immédiat
- Lecture continue sur buffer
- Si > 10s latence : toast discret "Connexion instable"
**Phase 2 : Perte totale réseau**
- Lecture continue jusqu'à épuisement buffer
- Toast : "Hors ligne, lecture sur buffer (30s restantes)"
- Compte à rebours visible
**Phase 3 : Buffer épuisé sans reconnexion**
- Pause automatique
- Overlay : "Connexion perdue. Reconnexion en cours..."
- Retry automatique toutes les 5s (max 6 tentatives = 30s)
**Phase 4 : Basculement mode offline** (après 30s échec)
- Popup : "Voulez-vous continuer avec vos contenus téléchargés ?"
- Boutons : "Réessayer" / "Mode offline"
- Si "Mode offline" → lecture contenus téléchargés
**Reconnexion réussie** :
- Reprise automatique lecture au point d'arrêt exact
- Toast : "Connexion rétablie"
**Justification** :
- **Expérience fluide zones blanches** (tunnels, campagne)
- **Buffer généreux** : absorbe fluctuations réseau mobile
- **Mode offline secours** : si coupure prolongée
---
### 12.4 Géolocalisation désactivée
**Mode dégradé automatique**
**Contenu disponible** :
| Type contenu | Disponible |
|--------------|-----------|
| **Contenu national** (podcasts, actualités) | ✅ |
| **Contenu téléchargé** (offline) | ✅ |
| **Contenus "Neutre"** géographiquement | ✅ |
| **Contenu géolocalisé** (Ancré/Contextuel) | ❌ |
| **Audio-guides** | ❌ |
| **Notifications push géo-déclenchées** | ❌ |
**Popup au lancement** :
- **Apparition** : Premier lancement après refus géolocalisation
- **Message** : "RoadWave fonctionne mieux avec la géolocalisation activée. Sans elle, seul le contenu national sera disponible."
- **Boutons** :
- "Activer" → Redirection paramètres OS
- "Continuer sans" → Mode dégradé
- **Checkbox** : "Ne plus me demander"
**Banner permanent si refus** :
- Bandeau haut écran : "Mode limité : géolocalisation désactivée. [Activer]"
- Pas intrusif mais rappel constant
- Disparaît si géolocalisation réactivée
**Justification** :
- **App reste fonctionnelle** sans GPS (pas de blocage)
- **Incitation forte** à activer (meilleure UX)
- **Respecte choix user** (RGPD : consentement libre)
---
## Récapitulatif Section 12

View File

@@ -0,0 +1,285 @@
## 4. Création et publication de contenu
### 4.1 Upload et encodage
**Décision** : Formats universels avec encodage asynchrone
**Formats acceptés** :
- ✅ MP3 (`.mp3`)
- ✅ AAC (`.aac`, `.m4a`)
- ❌ WAV, FLAC (trop lourds, inutiles en voiture)
**Limites** :
| Paramètre | Valeur | Justification |
|-----------|--------|---------------|
| **Taille maximale** | 200 MB | ~4h de podcast à 128 kbps |
| **Durée maximale** | 4 heures | Suffisant pour podcasts longs |
| **Validation format** | Client + backend | Double sécurité |
**Pipeline d'encodage** :
```
1. Upload fichier (MP3/AAC) → OVH Object Storage temporaire
2. Job asynchrone (worker Go + FFmpeg) :
- Validation format et intégrité
- Réencodage Opus 3 profils (24/48/64 kbps)
- Génération segments HLS (.m3u8 + .ts)
- Génération image couverture par défaut
3. Suppression fichier original (économie stockage)
4. Notification créateur : "Contenu prêt à publier"
```
**Temps d'encodage estimé** :
- Contenu 5 min → ~30 secondes
- Podcast 1h → ~5 minutes
- Podcast 4h → ~20 minutes
**Profils Opus générés** :
| Qualité | Bitrate | Usage |
|---------|---------|-------|
| Basse | 24 kbps | 2G/Edge |
| Standard | 48 kbps | 3G (défaut) |
| Haute | 64 kbps | 4G/5G |
**Écoute accélérée** :
| Vitesse | Usage |
|---------|-------|
| 0.75x | Compréhension difficile (accent, technique) |
| 1.0x | Normal (défaut) |
| 1.25x | Gain léger |
| 1.5x | Podcasts longs |
| 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
- **Scalabilité** : workers horizontalement (Kubernetes jobs)
- **Productivité** : écoute accélérée = double productivité modération
---
### 4.2 Métadonnées obligatoires
**Décision** : Minimaliste pour réduire friction
**Champs obligatoires** :
| Champ | Format | Validation |
|-------|--------|------------|
| **Titre** | 5-100 caractères | Alphanumérique + ponctuation basique |
| **Type géo** | Enum | Ancré / Contextuel / Neutre |
| **Zone diffusion** | Composite | Voir détails ci-dessous |
| **Tags** | Enum | 1 à 3 parmi liste prédéfinie |
| **Classification âge** | Enum | Tout public / 13+ / 16+ / 18+ |
**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
- **Région** : sélection liste
- **National** : France entière
**Tags disponibles** (1 à 3 obligatoires) :
- Automobile
- Voyage
- Famille
- Amour
- Musique
- Économie
- Cryptomonnaie
- Politique
- Culture générale
- Sport
- Technologie
- 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
- Personnalisable ultérieurement (post-MVP)
**Exemple de publication** :
```
Titre : "Histoire de la Tour Eiffel"
Type géo : Ancré
Zone : Point GPS (48.8584, 2.2945, rayon 500m)
Tags : Voyage, Culture générale
Classification : Tout public
→ Image auto : 📍 fond bleu-vert (Voyage)
```
**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
- **Évolutif** : champs optionnels ajoutables ultérieurement
---
### 4.3 Validation des 3 premiers contenus
**Décision** : Validation manuelle par équipe modération RoadWave
**Processus nouveau créateur** :
1. Créateur upload ses 3 premiers contenus
2. Contenus passent en **file d'attente modération**
3. Modérateur junior RoadWave :
- Écoute 30 secondes (ou 15s à 2x)
- Vérifie métadonnées
- Valide ou rejette avec raison
4. Si accepté : contenu publié + notification créateur
5. Si refusé : notification avec raison détaillée + lien vers règles
6. Après 3 contenus validés : créateur passe en **statut vérifié**
**Critères de validation** :
| Critère | Détails |
|---------|---------|
| **Qualité audio** | Compréhensible (pas de grésillement excessif) |
| **Respect règles** | Pas de contenu prohibé évident (haine, spam, illégal) |
| **Classification âge** | Cohérente avec contenu écouté |
| **Tags pertinents** | Correspondance minimale avec contenu |
| **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
- Message au créateur : "Validation en cours, délai estimé 24-48h"
**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
- Possibilité de correction + resoumission
**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)
- Historique créateur visible (si déjà 1-2 contenus validés)
**Modération communautaire (post-MVP)** :
⚠️ **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)
- Compensation : badges, premium offert
- 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
- **Coût raisonnable** : 30s × 3 contenus = 1.5 min/créateur
- **UX acceptable** : délai 24-48h expliqué clairement
- **Pas de validation par pairs** au MVP = évite risques juridiques (collusion, compétence, conflits)
---
### 4.4 Modification et suppression
**Décision** : Modification métadonnées uniquement, suppression immédiate
**Modification autorisée** :
| Élément | Modifiable | Justification |
|---------|------------|---------------|
| **Titre** | ✅ | Correction coquilles |
| **Description** | ✅ | Si ajoutée ultérieurement |
| **Tags** | ✅ | Ajustement pertinence |
| **Image couverture** | ✅ | Personnalisation |
| **Audio** | ❌ | Intégrité contenu |
| **Zone diffusion** | ❌ | Évite manipulation algo |
| **Type géo** | ❌ | Évite manipulation algo |
| **Classification âge** | ❌ | Sécurité mineurs |
**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
**Suppression de contenu** :
| Aspect | Comportement |
|--------|--------------|
| **Délai** | Immédiat | Suppression BDD + cache sous 5 min |
| **Réversibilité** | Non | Suppression définitive |
| **Historique auditeurs** | Marqué "Contenu supprimé par créateur" | Conserve écoute dans historique |
| **Analytics plateforme** | Anonymisé et conservé | Métriques globales (RGPD compliant) |
| **Fichiers cache** | Supprimés sous 24h | Purge NGINX Cache (OVH VPS) et OVH Object Storage |
**Exemple scénario suppression** :
```
Créateur supprime podcast écouté par 1000 personnes
→ Cache/Storage : fichiers purgés sous 24h (NGINX Cache + OVH Object Storage)
→ BDD : entrée marquée "deleted", auteur anonymisé
→ Historique auditeurs : "Contenu supprimé" (conserve durée écoute pour stats)
→ Analytics : métriques globales conservées (anonymes, RGPD OK)
```
**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)
- **Traçabilité** : historique conservé pour analytics (anonymisé)
- **Coût 0** : pas de revalidation métadonnées
---
## Récapitulatif Section 4

View File

@@ -0,0 +1,254 @@
## 7. Radio live
### 7.1 Démarrage d'un live
**Décision** : Buffer 15s + notification abonnés + limite 8h
**Processus de démarrage** :
1. Créateur appuie "Démarrer live" dans l'app
2. **Vérification pré-live** :
- Connexion ≥1 Mbps upload (warning si insuffisant)
- Micro autorisé
- Zone diffusion déjà définie (ville, département, région, national)
3. **Buffer initial 15 secondes** avant diffusion publique
- Créateur parle pendant 15s → accumulation buffer serveur
- Message créateur : "Live démarre dans 15s... Testez votre micro"
- Permet vérifier qualité audio avant diffusion
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)
**Métadonnées obligatoires** :
| Champ | Format | Validation |
|-------|--------|------------|
| **Titre** | 5-100 caractères | Ex: "Discussion politique en direct" |
| **Tags** | 1-3 centres d'intérêt | Sélection liste prédéfinie |
| **Classification âge** | Enum | Tout public / 13+ / 16+ / 18+ |
| **Zone diffusion** | Geo | Ville / Département / Région / National |
**Contenus interdits en live** :
| Type | Description | Sanction |
|------|-------------|----------|
| **Concert/spectacle** | Diffusion concert en direct depuis la salle | Strike 2 immédiat + suspension 7 jours |
| **Événement sportif payant** | Match, compétition avec droits TV | Strike 2 immédiat + suspension 7 jours |
| **Œuvre protégée** | Film, série, musique en fond sans droits | Strike 1 + suspension 3 jours + suppression live |
| **Contenu violent** | Agression, violence physique | Strike 3 immédiat + suspension 30 jours |
| **Contenu illégal** | Apologie terrorisme, pédopornographie | Strike 4 (ban définitif) + signalement autorités |
**Exemple usecase interdit** :
```
❌ Utilisateur dans salle de concert diffuse live performance
→ Violation droits d'auteur + droits de diffusion
→ Détection : modération réactive (signalements) + IA audio fingerprint
→ Sanction : Strike 2 (suspension 7 jours) + suppression live + suppression replay
```
**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](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
- **Interdictions strictes** : protection juridique plateforme (DSA EU, droits d'auteur)
- **Coût** : WebRTC ingestion + HLS distribution (réutilise infra existante)
---
### 7.2 Arrêt du live
**Décision** : Compte à rebours 5s + tolérance déconnexion 60s + enregistrement auto
**Fin manuelle créateur** :
1. Créateur appuie "Arrêter live"
2. **Compte à rebours 5 secondes** affiché
- Message audio : "Ce live se termine dans 5... 4... 3... 2... 1"
- Permet au créateur de faire un outro propre
- Annulable pendant décompte (bouton "Annuler")
3. Timer atteint 0 → arrêt diffusion
4. **Traitement post-live automatique** démarre (voir ci-dessous)
**Fin automatique si déconnexion** :
| Durée coupure | Comportement |
|---------------|--------------|
| **<60 secondes** | Message auditeurs : "Connexion créateur perdue, reconnexion en cours..." |
| **≥60 secondes** | Arrêt automatique live + message : "Le live est terminé suite à une coupure de connexion" |
**Enregistrement automatique** :
**Obligatoire et automatique** (valeur ajoutée énorme)
**Processus** :
1. Pendant live : enregistrement continu serveur (format Opus raw)
2. Fin live → **job asynchrone** (worker Go + FFmpeg) :
- Conversion MP3 256 kbps (qualité optimale)
- Génération segments HLS (comme contenu classique)
- Normalisation volume -14 LUFS
- Détection silences prolongés (nettoyage)
3. **Publication automatique** du replay :
- Titre : "[REPLAY] [Titre live original]"
- Même zone diffusion, tags, classification
- Disponible sous **5-10 minutes** après fin live
- Type géo : automatiquement "Géo-neutre" (replay = contenu pérenne)
**Options créateur** :
| Option | Défaut | Description |
|--------|--------|-------------|
| **Publier replay automatiquement** | ✅ OUI | Désactivable avant démarrage live |
| **Supprimer replay après coup** | ✅ Possible | Suppression standard contenu |
| **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
- **MP3 256 kbps** : qualité optimale pour replay (vs 48 kbps live)
- **Coût** : stockage minimal (Opus → MP3 1× par live, puis suppression raw après 7j)
---
### 7.3 Comportement auditeur
**Décision** : Buffer 15s + continuation hors zone + reconnexion au live actuel + écoute passive uniquement
**Buffer de synchronisation** :
- **15 secondes** entre créateur et auditeurs
- Raisons :
- Stabilité réseau mobile (3G/4G fluctuant)
- Synchronisation approximative acceptable (pas besoin temps réel strict)
- Permet buffering anticiper coupures courtes (tunnels)
**Comparaison buffers** :
| Buffer | Avantages | Inconvénients | Décision |
|--------|-----------|---------------|----------|
| 5s | Quasi temps réel | Instable 3G, coupures fréquentes | ❌ |
| 10s | Bon compromis | Légèrement juste pour 3G | ❌ |
| **15s** | **Stabilité optimale 3G/4G** | Léger décalage acceptable | ✅ |
| 20s+ | Très stable | Décalage trop perceptible | ❌ |
**Zone géographique pendant live** :
-**Continuation si sortie de zone**
- Scénario : auditeur écoute live régional → sort du département → **live continue**
- Raisons :
- Pas de coupure brutale (mauvaise UX)
- Écoute engagée = terminer naturellement
- Après fin live → algo normal (pas de contenus hors zone)
**Reconnexion après coupure réseau** :
| Durée coupure | Comportement |
|---------------|--------------|
| **<90 secondes** | Reprend au live actuel (pas au buffer ancien) + saut temporel transparent |
| **≥90 secondes** | Message : "Live en cours perdu, passage au contenu suivant" + algo propose contenu normal |
**Interactions disponibles** :
**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)
- **Simplicité** : écoute passive = expérience uniforme
**Actions autorisées pendant live** :
| Action | Disponible | Effet |
|--------|------------|-------|
| **Like** | ✅ | Bouton cœur interface mobile (véhicule arrêté) |
| **Abonnement créateur** | ✅ | Bouton profil créateur (interface mobile) |
| **Skip** | ✅ | Passe au contenu suivant, sort du live |
| **Précédent** | ❌ | Pas de sens sur live (flux temps réel) |
| **Chat** | ❌ | Jamais implémenté (décision définitive) |
| **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)
- **Coût** : 0€ infra chat, 0€ modération temps réel
- **Différenciation** : positionnement "audio safe" vs plateformes toxiques
---
### 7.4 Architecture technique
**Stack** :
```
Créateur (App mobile)
↓ WebRTC (OPUS 48 kbps)
Serveur Ingestion (Go + Pion WebRTC)
↓ Conversion temps réel
Serveur HLS (segments .ts)
↓ NGINX Cache (OVH VPS)
Auditeurs (App mobile, HLS natif)
```
**Flux détaillé** :
1. **Créateur** → WebRTC OPUS 48 kbps vers serveur Go
2. **Serveur Go** → Conversion temps réel OPUS → segments HLS (.m3u8 + .ts)
3. **NGINX Cache (OVH VPS)** → Distribution HLS avec cache
4. **Auditeurs** → Lecture HLS native iOS/Android (buffer 15s)
5. **Enregistrement parallèle** → Opus raw stocké temporairement
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)
-**OVH Object Storage** (stockage origin, compatible S3)
-**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)
- ✅ NGINX Cache (OVH VPS) optimise la distribution (coût réduit)
- ✅ Scalable horizontalement (workers Go)
**Coût estimé infrastructure** :
| Phase | Utilisateurs | Infra live | Coût/mois |
|-------|--------------|------------|-----------|
| **MVP** | 0-100K | 1 instance Go (ingestion 100 lives simultanés) | +50€ (serveur) + bande passante |
| **Growth** | 100K-1M | 3-5 instances Go (500 lives simultanés) | +200€ + bande passante |
| **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
---
## Récapitulatif Section 7

View File

@@ -0,0 +1,411 @@
## 18. Détection de contenu protégé par droits d'auteur
### 18.1 Périmètre et objectifs
**Décision** : Focus musique uniquement, approche minimaliste MVP
**Contenu protégé couvert** :
| Type | Couvert MVP | Justification |
|------|-------------|---------------|
| **Musique** | ✅ OUI | Risque principal (80% violations), détectable auditivement |
| **Films/séries** | ❌ NON | Rare dans podcasts audio, complexité technique élevée |
| **Livres audio** | ❌ NON | Difficile à distinguer de lecture légitime |
| **Jingles/pubs** | ❌ NON | Usage souvent transformatif, faible risque juridique |
**Objectifs** :
1. **Juridique** : Conformité droits d'auteur UE (directive 2019/790)
2. **Protection plateforme** : Éviter contentieux avec ayants droit (SACEM, labels)
3. **Qualité** : Encourager contenu original créateurs
4. **Pragmatisme** : Coût 0€ au MVP, scalable post-MVP
**Non-objectifs MVP** :
- ❌ Détection automatisée (fingerprinting audio)
- ❌ Intégration bases de données commerciales (ACRCloud, etc.)
- ❌ Détection temps réel sur lives (voir section 7)
- ❌ Système de licences musicales
---
### 18.2 Règles d'utilisation de musique
**Décision** : Tolérance 30 secondes pour extraits (fair use)
**Cas autorisés** :
| Cas d'usage | Durée max | Condition | Exemple |
|-------------|-----------|-----------|---------|
| **Citation/critique** | 30 secondes | Commentaire ajouté, contexte éditorial | Review album, analyse musicale |
| **Musique libre de droits** | Illimitée | Preuve licence si demandée | Epidemic Sound, Artlist, CC0 |
| **Musique originale** | Illimitée | Créateur = compositeur/interprète | Podcast musical créateur |
| **Domaine public** | Illimitée | Œuvre >70 ans après mort auteur | Classique pré-1950 |
**Cas interdits** :
| Violation | Description | Détection |
|-----------|-------------|-----------|
| **Musique intégrale** | Titre complet en fond ou standalone | Écoute modérateur (évident) |
| **Compilation DJ** | Mix de titres protégés sans droits | Écoute modérateur |
| **Extrait >30s** | Citation longue sans transformation | Chronométrage manuel si signalé |
| **Karaoké** | Instrumental protégé + voix créateur | Écoute modérateur (reconnaissable) |
**Exception fair use (30 secondes)** :
**Conditions cumulatives** :
1. Extrait ≤30 secondes **ET**
2. Usage transformatif : commentaire, critique, analyse **ET**
3. Pas de substitution à l'œuvre originale **ET**
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)
---
### 18.3 Processus de détection MVP
**Décision** : Validation manuelle lors des 3 premiers contenus uniquement
**Workflow intégré à la validation existante** (voir section 4.3) :
```
Upload contenu (créateur <3 validés)
File d'attente modération
Modérateur écoute 30s (déjà existant)
Vérification AJOUTÉE :
├─ Musique en fond détectée ?
│ ├─ OUI → Musique reconnaissable (titre connu) ?
│ │ ├─ OUI → Durée >30s ?
│ │ │ ├─ OUI → REFUS (violation droits)
│ │ │ └─ NON → ACCEPTÉ (fair use)
│ │ └─ NON → ACCEPTÉ (musique libre probable)
│ └─ NON → ACCEPTÉ (pas de musique)
└─
Validation normale continue
```
**Critères de détection manuelle** :
| Indicateur | Action modérateur |
|------------|-------------------|
| **Musique reconnaissable** (hit radio, classique célèbre) | Chronométrer l'extrait |
| **Extrait >30s** | Refus automatique |
| **Extrait ≤30s** | Vérifier usage transformatif (commentaire ?) |
| **Musique d'ambiance inconnue** | Accepter (probable musique libre) |
| **Doute** | Demander preuve licence au créateur |
**Après 3 contenus validés** :
- ✅ Créateur = statut "Vérifié"
- ✅ Publication immédiate sans validation préalable
- ✅ 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)
- **Humain nécessaire** : fair use impossible à automatiser fiablement
---
### 18.4 Signalement et modération a posteriori
**Décision** : Réutilise système existant section 14
**Signalement utilisateur** :
- Catégorie existante : **🎵 Droits d'auteur**
- Formulaire : identique autres signalements
- Commentaire optionnel : "Quelle musique ? À quel timestamp ?"
**Traitement modérateur** :
1. Signalement reçu → file d'attente priorité MOYENNE (délai 24-48h)
2. Modérateur écoute le timestamp indiqué
3. Vérification :
- Musique identifiable ? → Recherche Shazam/SoundHound (outil externe)
- Durée extrait ?
- Usage transformatif (commentaire/critique) ?
4. Décision :
- **Violation confirmée** → Application sanctions (voir 18.5)
- **Fair use** → Rejet signalement
- **Doute** → Escalade modérateur senior
**Outils modérateur** :
| Outil | Usage | Coût |
|-------|-------|------|
| **Écoute manuelle** | Détection présence musique | 0€ |
| **Shazam/SoundHound** | Identification titre (externe, outil perso modérateur) | 0€ |
| **Chronomètre** | Mesure durée extrait | 0€ |
| **Notes** | Documentation décision (audit DSA) | 0€ |
**Priorité traitement** :
- Score IA : NON APPLICABLE (pas d'IA au MVP)
- Priorité : **MOYENNE** (délai 24-48h jours ouvrés)
- Escalade senior si :
- Créateur conteste avec preuve licence
- Doute fair use complexe
- Récidive (>2 violations)
---
### 18.5 Sanctions
**Décision** : Échelle progressive avec tolérance première violation
**Grille de sanctions** :
| Occurrence | Sanction | Durée | Justification |
|------------|----------|-------|---------------|
| **1ère violation** | ⚠️ Avertissement + Suppression contenu | - | Tolérance erreur bonne foi |
| **2e violation** | 🟡 Strike 1 + Suppression + Suspension upload | 3 jours | Négligence confirmée |
| **3e violation** | 🟠 Strike 2 + Suppression + Suspension upload | 7 jours | Récidive caractérisée |
| **4e violation** | 🟠 Strike 3 + Suppression + Suspension upload | 30 jours | Abus répété |
| **5e violation** | 🔴 Strike 4 + Ban définitif compte créateur | Permanent | Abus délibéré |
**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
- **Pas de strike** (tolérance)
- 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é)
**Exceptions - Pas de sanction si** :
- ✅ Créateur prouve licence acquise (facture, abonnement Epidemic Sound, etc.)
- ✅ Musique = domaine public vérifié
- ✅ Musique = œuvre originale créateur (preuve registre SACEM si demandée)
- ✅ Extrait ≤30s + usage transformatif évident (critique musicale)
**Réhabilitation** :
- **-1 strike automatique** tous les **6 mois** sans nouvelle violation
- Conditions : aucun signalement validé pendant la période
- Minimum : 0 strikes (pas de valeur négative)
- Avertissement (1ère fois) ne compte pas pour la réhabilitation
**Exemple** :
```
Créateur a Strike 2 (7 jours de suspension)
→ 6 mois sans incident
→ Strike 2 devient Strike 1
→ 6 mois additionnels sans incident
→ Strike 1 effacé, compte propre
```
**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)
- **Réhabilitation 6 mois** : encourage bon comportement long terme
- **Conforme DSA** : sanctions proportionnées + droit d'appel
---
### 18.6 Processus d'appel
**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
**Formulaire d'appel** :
Champs standards (voir section 14) **+** champs spécifiques :
| Champ additionnel | Type | Obligatoire |
|-------------------|------|-------------|
| **Preuve licence** | Upload PDF/image (facture, contrat) | ❌ Optionnel |
| **Lien source musique libre** | URL (YouTube Audio Library, etc.) | ❌ Optionnel |
| **Déclaration œuvre originale** | Checkbox | ❌ Optionnel |
**Traitement appel** :
1. Modérateur senior examine :
- Preuves fournies (licence, facture)
- Réécoute contenu (usage transformatif ?)
- Recherche musique (domaine public ?)
2. Délai : **72h** (standard section 14)
3. Décision finale :
- **Appel accepté** → Strike retiré + Contenu rétabli + Excuse formelle
- **Appel rejeté** → Sanction maintenue + Explication détaillée
**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)
---
### 18.7 Éducation créateurs
**Décision** : Prévention via documentation + tooltips
**Ressources disponibles** :
| Ressource | Contenu | Accès |
|-----------|---------|-------|
| **Page CGU dédiée** | Règles musique détaillées + exemples | Lien dans CGU + FAQ |
| **Tooltip upload** | "⚠️ Pas de musique protégée >30s" | Interface upload contenu |
| **Liste musique libre** | Liens Epidemic, Artlist, YouTube Audio Library | Page aide créateurs |
| **Exemples fair use** | Cas OK : review 20s + commentaire / Cas KO : hit complet en fond | FAQ illustrée |
**Messages préventifs** :
**Lors du premier upload** (popup) :
```
🎵 Attention aux droits d'auteur
Vous pouvez utiliser :
✅ Votre propre musique originale
✅ Musique libre de droits (Epidemic Sound, etc.)
✅ Extraits courts ≤30s pour critique/analyse
Interdit :
❌ Musique populaire en intégrale ou fond prolongé
❌ Compilation de hits sans droits
[J'ai compris] [En savoir plus]
```
**Justification** :
- Prévention > sanction (économie modération)
- Créateurs informés = moins de violations
- Coût : 0€ (documentation statique)
---
### 18.8 Évolution post-MVP
**Décision** : Audio fingerprinting open-source si besoin scalabilité
**Déclencheurs réintégration** :
1. Volume signalements "Droits d'auteur" >50/mois
2. Temps modération musique >20h/mois
3. Contentieux avec ayants droit (SACEM, labels)
**Solution technique prévue** :
| Composant | Technologie | Fonction | Coût |
|-----------|-------------|----------|------|
| **Fingerprinting** | Chromaprint (open-source) | Génération empreinte audio | 0€ |
| **Base de référence** | MusicBrainz + AcoustID | Comparaison empreintes | 0€ |
| **Matching** | Python + PostgreSQL | Détection similarité >85% | 0€ |
| **Infrastructure** | VPS 8GB RAM + 4 vCPU | Processing async | 50-100€/mois |
**Workflow automatisé** :
```
Upload contenu
Job async : extraction empreinte audio (Chromaprint)
Comparaison avec base MusicBrainz
Match >95% → FLAG automatique "Musique détectée : [Titre]"
Modérateur humain vérifie :
├─ Durée extrait ?
├─ Usage transformatif ?
└─ Décision finale (accept/reject)
```
**Limites connues** :
- ❌ Précision ~70% (vs 95%+ API commerciales)
- ❌ Base MusicBrainz incomplète (surtout hits récents)
- ❌ Faux positifs possibles (musique libre similaire)
- ✅ Mais : **gratuit** + **self-hosted** + **scalable**
**Alternative commerciale** (si budget disponible) :
- ACRCloud : 300-800€/mois, précision 95%+, base exhaustive
- Audible Magic : 500-1000€/mois, musique + films/TV
- **Décision différée** post-MVP selon besoins réels
---
## Récapitulatif Section 18
| Point | Décision | Coût |
|-------|----------|------|
| **Périmètre MVP** | Musique uniquement (80% des violations) | 0€ |
| **Tolérance** | 30 secondes pour extraits (fair use) | 0€ |
| **Détection MVP** | Manuelle lors des 3 premiers contenus | 0€ |
| **Outils modérateur** | Écoute + Shazam externe + Chronomètre | 0€ |
| **Sanctions** | Progressive : Avertissement → Strike 1 (3j) → Strike 2 (7j) → Strike 3 (30j) → Strike 4 (ban) | 0€ |
| **Appel** | Réutilise processus section 14 (délai 72h) | 0€ |
| **Éducation** | CGU + Tooltips + FAQ musique libre | 0€ |
| **Post-MVP** | Chromaprint + MusicBrainz (si >50 signalements/mois) | 50-100€/mois |
**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)
**Risques identifiés** :
| Risque | Probabilité | Impact | Mitigation |
|--------|-------------|--------|------------|
| **Contentieux ayant droit** | Faible | Élevé | Réactivité suppression (<24h) + CGU claires |
| **Faux négatifs** (violation non détectée) | Moyenne | Moyen | Signalements utilisateurs + modération a posteriori |
| **Faux positifs** (musique libre bloquée) | Faible | Faible | Processus d'appel 72h + whitelist |
| **Volume signalements** | Faible | Moyen | Évolution fingerprinting si >50/mois |
---
**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)
**Prochaine section à clarifier** : Section 11 (Mode offline) ou Section 12 (Gestion des erreurs)

View File

@@ -0,0 +1,393 @@
## 14. Modération - Flows opérationnels
### 14.1 Signalement
**Décision** : Formulaire simple avec 7 catégories prédéfinies
#### 14.1.1 Catégories de signalement
Liste déroulante avec 7 options :
| Catégorie | Description |
|-----------|-------------|
| 🚫 **Haine & violence** | Incitation à la haine, discrimination, menaces |
| 🔞 **Contenu sexuel** | Pornographie, contenu explicite |
| ⚖️ **Illégalité** | Terrorisme, apologie de crimes |
| 🎵 **Droits d'auteur** | Musique/contenu protégé non autorisé (voir [Section 18](18-detection-contenu-protege.md) pour règles détaillées) |
| 📧 **Spam** | Publicité non sollicitée, répétition |
| ❌ **Fausse information** | Désinformation sur santé, sécurité routière |
| 🔧 **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)
---
#### 14.1.2 Commentaire du signaleur
**Décision** : Optionnel avec incitation
- Champ texte libre (0-500 caractères)
- Placeholder : "Décrivez le problème (optionnel mais recommandé)"
- 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
---
#### 14.1.3 Confirmation après signalement
**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
---
### 14.2 Traitement des signalements
#### 14.2.1 IA pré-filtre (transcription + analyse)
**Décision** : OpenAI Whisper open source + NLP
**Stack technique** :
| Composant | Technologie | Hébergement |
|-----------|-------------|-------------|
| **Transcription** | Whisper large-v3 | Self-hosted (CPU MVP, GPU scale) |
| **Analyse sentiment** | distilbert-base-uncased | Self-hosted |
| **Détection haine** | facebook/roberta-hate-speech | Self-hosted |
| **Mots-clés** | Liste noire FR/EN + regex | PostgreSQL |
**Processus** :
1. Signalement reçu → ajout file d'attente asynchrone
2. Transcription audio (1-10 minutes selon durée)
3. Analyse automatique :
- Score de confiance : 0-100%
- Catégorie détectée
- Timestamps des passages problématiques
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
---
#### 14.2.2 Délais de traitement (SLA)
**Décision** : SLA progressif selon priorité
| Priorité | Délai cible | Traitement |
|----------|-------------|------------|
| **CRITIQUE** | <2h (24/7) | Violence, suicide, mise en danger → Astreinte modérateur senior |
| **HAUTE** | <24h (jours ouvrés) | Haine, harcèlement, désinformation → Modérateur junior/senior |
| **MOYENNE** | <24h (jours ouvrés) | Spam, contenu inapproprié → Modérateur junior |
| **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
---
#### 14.2.3 Priorisation automatique
**Décision** : File d'attente intelligente basée sur score IA
**Calcul de priorité** :
```
Priorité = (Score_IA × 0.7) + (Signalements_cumulés × 0.2) + (Fiabilité_signaleur × 0.1)
```
**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)
---
### 14.3 Sanctions
#### 14.3.1 Notification au créateur
**Décision** : Multi-canal (email + push + in-app)
**Canaux utilisés** :
| Canal | Timing | Contenu |
|-------|--------|---------|
| **Push notification** | Immédiat | Alerte courte : "Votre contenu a été modéré" |
| **In-app** | Au prochain lancement | Popup détaillée avec bouton "Voir détails" |
| **Email** | Dans l'heure | Notification complète avec lien vers formulaire d'appel |
**Contenu email** :
```
Objet : Modération de votre contenu "[Titre du contenu]"
Bonjour [Pseudo],
Votre contenu "[Titre]" publié le [Date] a été modéré.
Catégorie violée : [Catégorie]
Raison : [Explication détaillée]
Sanction : [Strike X / Suspension X jours / Suppression contenu]
Extrait audio concerné : [Timestamp]
Transcription : "[Passage problématique surligné]"
Vous pouvez contester cette décision sous 7 jours :
[Lien formulaire d'appel]
L'équipe RoadWave
```
**Coût** :
- Email : ~0.001€/notification (Brevo, Resend)
- Push : 0€ (Firebase Cloud Messaging / APNs)
- In-app : 0€
**Justification** :
- Conformité DSA (transparence obligatoire)
- Multi-canal garantit réception
- Coût négligeable
---
#### 14.3.2 Détail de la sanction
**Décision** : Notification complète avec preuves
**Éléments inclus obligatoirement** :
1. **Catégorie violée** : référence précise CGU (ex: "Article 3.2 - Haine & violence")
2. **Raison détaillée** : explication en langage clair (non juridique)
3. **Extrait audio** : timestamp exact du passage problématique (ex: "3:42-4:15")
4. **Transcription** : texte problématique surligné en rouge
5. **Gravité** : Strike actuel + conséquences (ex: "Strike 2/4 - Suspension 7 jours")
6. **Recours** : lien direct vers formulaire d'appel + délai (7 jours)
**Exemple visuel in-app** :
```
┌─────────────────────────────────────┐
│ ⚠️ Contenu modéré │
├─────────────────────────────────────┤
│ Titre : "Mon podcast #42" │
│ Publié le : 15/01/2026 │
│ │
│ Catégorie violée : │
│ 🚫 Haine & violence (Article 3.2) │
│ │
│ Passage problématique : 3:42-4:15 │
│ "[Transcription surlignée]" │
│ │
│ Sanction : Strike 2/4 │
│ Suspension : 7 jours │
│ │
│ [Contester cette décision] │
└─────────────────────────────────────┘
```
**Justification** :
- Transparence maximale (obligation DSA)
- Créateur comprend l'erreur → amélioration future
- Réduit les appels non fondés
---
#### 14.3.3 Processus d'appel
**Décision** : Formulaire in-app structuré
**Accès** :
- Bouton "Contester cette décision" dans notification
- Section "Mes sanctions" dans profil créateur
**Formulaire d'appel** :
| Champ | Type | Obligatoire |
|-------|------|-------------|
| **Sanction contestée** | Pré-rempli (non modifiable) | ✅ |
| **Raison de l'appel** | Texte libre (50-1000 caractères) | ✅ |
| **Arguments** | Zone texte enrichie | ✅ |
| **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)
---
#### 14.3.4 Délai de réponse pour appel
**Décision** : SLA 72h garanti
**Délais** :
| Type d'appel | Délai | Responsable |
|--------------|-------|-------------|
| **Standard** | 72h max (3 jours ouvrés) | Modérateur senior |
| **Complexe** | 5 jours ouvrés + notification intermédiaire J+3 | Modérateur senior + Admin modération |
| **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** :
Email détaillé avec :
1. **Décision** : Maintien / Annulation / Réduction de sanction
2. **Justification** : explication de la décision d'appel
3. **Actions** : Strike retiré / Suspension annulée / Contenu rétabli (si applicable)
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
---
### 14.4 Outils modérateurs
**Stack technique complète** :
| Outil | Technologie | Fonction |
|-------|-------------|----------|
| **Dashboard** | React + TanStack Table | Interface modération |
| **File signalements** | PostgreSQL + Redis | Priorisation temps réel |
| **Player audio** | Wavesurfer.js | Lecture avec waveform + annotations |
| **Transcription** | Whisper large-v3 | Conversion audio → texte |
| **Historique créateur** | Vue 360° | Contenus, strikes, appels, métriques |
| **Actions rapides** | Shortcuts clavier | Approuver (A), Rejeter (R), Escalade (E) |
| **Logs audit** | PostgreSQL + export | Traçabilité complète (DSA) |
| **Collaboration** | Système de commentaires | Modérateurs peuvent s'entraider sur cas complexes |
**Fonctionnalités clés** :
1. **Lecture accélérée** : 0.75x à 2x (gain productivité)
2. **Marqueurs temporels** : annotation directe sur waveform
3. **Historique créateur** : vue rapide contenus précédents + strikes
4. **Statistiques** : signalements traités/jour, temps moyen, précision
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)
---
### 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
---
## Récapitulatif Section 14
| Point | Décision | Coût |
|-------|----------|------|
| **Catégories signalement** | 7 catégories prédéfinies + champ libre | 0€ |
| **Commentaire signaleur** | Optionnel avec incitation | 0€ |
| **Confirmation** | Toast in-app + historique personnel | 0€ |
| **IA pré-filtre** | Whisper (CPU MVP, GPU scale) + NLP open source | 0-200€/mois |
| **Délais traitement** | SLA progressif : 2h/24h/72h selon priorité | Dépend équipe |
| **Priorisation** | File intelligente basée score IA | 0€ |
| **Notification sanction** | Email + push + in-app (multi-canal) | ~0.001€/notif |
| **Détail sanction** | Complet : raison + extrait + transcription | 0€ |
| **Processus appel** | Formulaire in-app structuré | 0€ |
| **Délai appel** | 72h garanti (standard) | Dépend équipe |
| **Outils modérateurs** | Dashboard React + Whisper + Wavesurfer.js | 0-200€/mois |
**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
---
**🎯 Modération communautaire** : Voir [Section 19](19-moderation-communautaire.md) pour le système complet de badges, récompenses et priorisation des signalements pertinents.
---
**Section suivante** : [Section 19 - Modération Communautaire](19-moderation-communautaire.md)

View File

@@ -0,0 +1,430 @@
## 19. Modération Communautaire - Badges et Récompenses
**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
---
### 19.1 Système de badges
**Décision** : 3 niveaux de badges selon l'historique de signalements validés
#### 19.1.1 Badges et critères
| Badge | Nom | Critères | Avantages |
|-------|-----|----------|-----------|
| 🥉 | **Contributeur Bronze** | 5 signalements validés + 70% taux pertinence | Signalements prioritaires (+10 points algorithme) |
| 🥈 | **Contributeur Argent** | 20 signalements validés + 80% taux pertinence | Signalements prioritaires (+20 points) + Badge visible profil |
| 🥇 | **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
**Calcul du taux de pertinence** :
```
Taux de pertinence = (Signalements validés / Total signalements envoyés) × 100
```
**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é
---
#### 19.1.2 Délai entre obtention badges
**Décision** : Délai minimum entre niveaux
| Transition | Délai minimum |
|------------|---------------|
| **Bronze → Argent** | 30 jours |
| **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)
---
#### 19.1.3 Découverte du système
**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
**Modal d'information** (affichage unique, ne se réaffiche jamais) :
```
┌─────────────────────────────────────────────┐
│ 🎯 Bravo ! Vous contribuez à une │
│ communauté plus saine │
├─────────────────────────────────────────────┤
│ │
│ En signalant ce contenu, vous participez │
│ activement à améliorer l'expérience de │
│ tous les utilisateurs RoadWave. │
│ │
│ Vos contributions de qualité sont │
│ valorisées et récompensées : │
│ │
│ 🥉 Bronze : 5 signalements validés │
│ → Signalements prioritaires │
│ │
│ 🥈 Argent : 20 signalements validés │
│ → Badge visible + priorité accrue │
│ │
│ 🥇 Or : 50 signalements validés │
│ → Réduction Premium -50% pendant 3 mois │
│ │
│ 💡 Votre taux de pertinence compte ! │
│ Signalements validés ÷ Total × 100 │
│ │
│ Continuez à nous aider, chaque │
│ signalement pertinent compte ! 🙏 │
│ │
│ [En savoir plus] [J'ai compris] │
└─────────────────────────────────────────────┘
```
**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
- Avantages détaillés de chaque niveau
- Règles anti-abus (limite 10 signalements/24h)
- Durée de validité des badges (audit trimestriel)
**Coût** : **0€** (modal one-time, logique backend simple)
---
#### 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** :
- 🥉 Bronze : "🎉 Félicitations ! Vous êtes désormais Contributeur Bronze. Merci de rendre RoadWave meilleur !"
- 🥈 Argent : "🎉 Impressionnant ! Badge Contributeur Argent obtenu. Votre engagement fait la différence !"
- 🥇 Or : "🎉 Exceptionnel ! Vous êtes Contributeur Or. La communauté vous remercie pour votre aide précieuse !"
**Statistiques personnelles** (page Profil > Mes signalements) :
```
📊 Vos statistiques de modération
Signalements envoyés : 27
Validés : 23 ✅
Rejetés : 4 ❌
Taux de pertinence : 85%
Badge actuel : 🥈 Contributeur Argent
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
---
### 19.2 Score de fiabilité
**Décision** : Score interne utilisé pour prioriser les signalements dans l'algorithme
#### 19.2.1 Formule
```
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
- **Plafond** : maximum 100 points
**Exemples** :
| Cas | Validés | Rejetés | Badge | Score |
|-----|---------|---------|-------|-------|
| Nouvel utilisateur fiable | 10 | 1 | Aucun | 95 |
| Utilisateur moyen | 15 | 8 | Bronze | 70 |
| Contributeur Or | 50 | 3 | Or | 100 (plafonné) |
| Signaleur abusif | 2 | 20 | Aucun | 0 (min 0) |
---
#### 19.2.2 Utilisation dans l'algorithme de priorisation
**Rappel formule Section 14.2.3** :
```
Priorité = (Score_IA × 0.7) + (Signalements_cumulés × 0.2) + (Fiabilité_signaleur × 0.1)
```
**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 :
```
Votre score de fiabilité : 85/100
→ Vos signalements sont traités en priorité
```
**Coût** : **0€** (calcul automatique lors du traitement)
---
### 19.3 Statut "Utilisateur de confiance"
**Décision** : Statut automatique pour utilisateurs Badge Argent ou Or
**Critère** :
- Badge **Argent OU Or** actif = automatiquement "Utilisateur de confiance"
**Avantages** :
1. **Priorisation signalements** : traités avant signalements standards (même score IA)
2. **Badge visible** : affichage "Utilisateur de confiance" sur profil public
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
**Coût** : **0€** (simple flag booléen calculé automatiquement)
---
### 19.4 Réduction Premium pour badge Or
**Décision** : Seuls les utilisateurs **Contributeur Or** (top contributeurs) obtiennent une réduction Premium
#### 19.4.1 Conditions
| Critère | Valeur |
|---------|--------|
| **Montant** | **-50% pendant 3 mois** (2.49€/mois au lieu de 4.99€) |
| **Éligibilité** | Badge Or actif + pas déjà Premium |
| **Durée** | 3 mois à partir de l'activation |
| **Renouvellement** | Prix normal (4.99€/mois) après 3 mois |
| **Cumul** | Non cumulable avec offre annuelle |
| **Délai activation** | 30 jours après obtention badge Or |
---
#### 19.4.2 Notification
**Email + Push + In-app** dès obtention badge Or :
```
🎉 Exceptionnel ! Vous avez obtenu le badge Contributeur Or
Vous faites partie des meilleurs contributeurs de RoadWave.
Grâce à votre engagement et votre vigilance, vous aidez
des milliers d'utilisateurs à profiter d'une expérience
audio de qualité.
La communauté vous remercie ! 🙏
En reconnaissance de votre aide précieuse, vous bénéficiez de :
✨ 3 mois d'abonnement Premium à -50%
→ 2.49€/mois au lieu de 4.99€
[Profiter de l'offre]
Cette offre est valable pendant 30 jours.
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)
---
#### 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
---
#### 19.4.4 ROI et justification
**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
---
### 19.5 Anti-abus
**CRITIQUE** : Système de protection contre les comportements abusifs
#### 19.5.1 Limite temporelle
**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€
---
#### 19.5.2 Détection patterns suspects
**Audit automatique hebdomadaire** :
```sql
-- Détection signaleurs suspects
SELECT user_id, COUNT(*) as total
FROM reports
WHERE created_at > NOW() - INTERVAL '7 days'
GROUP BY user_id
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
- Signalements ciblant toujours même créateur (harcèlement)
---
#### 19.5.3 Audit trimestriel automatique
**Décision** : Tous les 3 mois, recalcul badges et révocation si critères non respectés
**Processus** :
1. Recalcul taux pertinence sur période glissante 6 mois
2. Vérification critères :
- Bronze : minimum 70% pertinence
- Argent : minimum 80% pertinence
- Or : minimum 90% pertinence
3. Révocation badge si taux insuffisant
4. Email notification **7 jours avant audit** :
```
Votre badge Contributeur Argent sera audité dans 7 jours.
Taux de pertinence actuel : 78%
Minimum requis : 80%
Continuez à signaler du contenu pertinent pour conserver votre badge !
```
**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)
---
#### 19.5.4 Sanctions abus détecté
| Gravité | Abus détecté | Sanction |
|---------|--------------|----------|
| **Mineur** | >10 signalements/jour pendant 1 jour | Avertissement + limite 5/jour pendant 7 jours |
| **Modéré** | >30 signalements/semaine avec <50% pertinence | Révocation badge + interdiction signalement 30 jours |
| **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
- **Pas de recours** pour sanctions graves (farming confirmé)
---
## Récapitulatif Section 19
| Point | Décision | Coût |
|-------|----------|------|
| **Badges (3 niveaux)** | Bronze (5), Argent (20), Or (50) signalements validés | 0€ |
| **Modal découverte** | Affichage unique au 1er signalement | 0€ |
| **Score fiabilité** | Calcul automatique pour priorisation | 0€ |
| **Utilisateurs de confiance** | Statut auto Argent/Or | 0€ |
| **Réduction Premium Or** | -50% pendant 3 mois (Post-MVP) | 0-200€/mois |
| **Limite temporelle** | Max 10 signalements/24h | 0€ |
| **Audit trimestriel** | Révocation si critères non respectés | 0€ |
| **Sanctions abus** | Mineur/Modéré/Grave selon pattern | 0€ |
**Coût total MVP** : **0€**
**Coût total Post-MVP** : **0-200€/mois** (réductions Premium Or)
**ROI** : **Positif dès 2-3 utilisateurs Or actifs** (économie modération > coût réductions)
---
**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)
---
**Prochaine section à clarifier** : Section 20 (si nécessaire) ou validation complète règles métier

View File

@@ -0,0 +1,167 @@
## 6. Publicités
### 6.1 Système de campagnes publicitaires
**Décision** : Interface self-service avec maîtrise budget et métriques détaillées
**Fonctionnalités publicitaire** :
#### Création de campagne
**Paramètres configurables** :
| Paramètre | Options | Justification |
|-----------|---------|---------------|
| **Budget total** | Montant libre (min 50€) | Maîtrise coût total |
| **Durée campagne** | Date début/fin + étalement | Ex: 300€ sur 2 semaines |
| **Ciblage géographique** | Point GPS / Ville / Département / Région / National | Précision selon besoin |
| **Ciblage horaire** | Plages horaires (ex: 7h-9h, 17h-19h) | Optimisation trajet domicile-travail |
| **Centres d'intérêt** | Tags (ex: Automobile, Voyage) | Ciblage thématique |
| **Tranche d'âge** | Tout public / 13+ / 16+ / 18+ | Respect classifications |
**Étalement budget** :
```
Exemple campagne :
- Budget : 300€
- Durée : 14 jours
- Zone : Département du Var
- Horaires : 7h-9h + 17h-19h (rush)
Calcul automatique :
→ Budget/jour = 300€ / 14 = 21.43€/jour
→ Diffusions/jour estimées : ~430 (0.05€/écoute)
→ Alerte si budget épuisé avant fin (réajustement possible)
```
**Mode de paiement** :
- ✅ Prépaiement obligatoire (évite impayés)
- ✅ Carte bancaire uniquement (Mangopay)
- ✅ Recharge automatique optionnelle (si budget <10%)
#### Validation et modération
**Processus** :
1. Publicitaire upload audio pub (formats : MP3, AAC)
2. **Validation manuelle obligatoire** (modérateur RoadWave)
- Délai : 24-48h ouvrées
- Critères : respect réglementation, qualité audio, classification correcte
3. Si accepté → campagne démarre à la date choisie
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)
- ❌ Contenu sexuel ou violence
- ✅ Tous commerces/services légaux
#### Dashboard métriques engagement
**Indicateurs temps réel** :
| Métrique | Description | Utilité |
|----------|-------------|---------|
| **Impressions** | Nombre de diffusions | Volume exposition |
| **Écoutes complètes** | Pub écoutée >80% | Engagement réel |
| **Taux de skip** | % skip après délai min | Qualité contenu |
| **Durée moyenne écoute** | Secondes écoutées | Rétention attention |
| **Likes** | Nombre de likes | Appréciation contenu |
| **Abonnements** | Abonnements au créateur pub | Conversion forte |
| **Coût par écoute** | Budget / écoutes complètes | ROI campagne |
| **Répartition géographique** | Heatmap diffusions | Validation ciblage |
| **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
#### 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 :
- Budget consommé à 80%
- Budget consommé à 90%
- Budget épuisé
- 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é)
- ❌ Modifier audio (nécessite nouvelle validation)
#### 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
---
### 6.2 Insertion et fréquence
**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)
**Volume audio normalisé** :
- Pub normalisée à **-14 LUFS** (standard broadcast)
- Évite effet "pub trop forte" (frustration utilisateur)
- Validation automatique via FFmpeg lors encodage
---
### 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
---
## Récapitulatif Section 6

View File

@@ -0,0 +1,176 @@
## 10. Premium
### 10.1 Offre et tarification
**Décision** : Deux formules sans essai gratuit
| Formule | Prix | Économie | Prix effectif |
|---------|------|----------|---------------|
| **Mensuel** | 4.99€/mois | - | 4.99€/mois |
| **Annuel** | 49.99€/an | 2 mois offerts | 4.16€/mois |
**❌ 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
- **Engagement** : utilisateur qui paie dès début = plus engagé
**❌ 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
- La plupart des users RoadWave sont individuels (conducteurs)
- **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
---
### 10.2 Multi-devices et détection simultanée
**Décision** : 1 seul stream actif par compte à tout moment
**Détection connexion simultanée** :
```
User A écoute sur iPhone
→ User A lance sur iPad
→ Détection : session active iPhone existe
→ Action : Arrêt lecture iPhone (WebSocket close)
→ Message iPhone : "Lecture interrompue : votre compte est utilisé sur un autre appareil"
→ Lecture démarre iPad
```
**Implémentation technique** :
```
Redis : active_streams:{user_id} → {device_id, started_at}
TTL : 5 minutes (refresh à chaque heartbeat)
Heartbeat toutes les 30s depuis app :
→ Si autre device détecté : kill session actuelle
→ Si pas de heartbeat pendant 5 min : considérer session morte
```
**Exceptions** :
- Contenus téléchargés (offline) ne comptent pas comme stream actif
- Transition rapide device (<10s) tolérée (changement voiture → maison)
**Justification** :
- **Anti-partage compte** : empêche 2 personnes d'utiliser même compte Premium
- **Protection revenus créateurs** : 1 abonnement = 1 personne = 1 écoute
- **UX claire** : message explicite, pas de coupure brutale
---
### 10.3 Contenus exclusifs Premium
**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
---
### 10.4 Avantages Premium
**Inclus dans l'abonnement** :
| Avantage | Gratuit | Premium |
|----------|---------|---------|
| **Publicités** | 1/5 contenus | 0 (aucune) |
| **Contenus exclusifs** | ❌ Bloqués | ✅ Accès complet |
| **Qualité audio** | 48 kbps Opus | 64 kbps Opus |
| **Mode offline** | 50 contenus max | Illimité |
| **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
- **Pas d'over-engineering** : pas de badges cosmétiques, fonctionnalités sociales, etc. (focus essentiel)
---
### 10.5 Gestion abonnement
**Souscription** :
| Canal | Prestataire | Prix | Commission |
|-------|-------------|------|------------|
| **Web (desktop/mobile)** | Mangopay | 4.99€ | 1.8% + 0.18€ = 0.27€ |
| **iOS App** | Apple In-App Purchase | 5.99€ | 30% (Apple) |
| **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)
**Architecture données** :
```sql
CREATE TABLE subscriptions (
id UUID PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id) UNIQUE,
mangopay_recurring_payin_id VARCHAR(255), -- Null si IAP
mangopay_user_id VARCHAR(255), -- Null si IAP
apple_transaction_id VARCHAR(255), -- Null si Mangopay
google_purchase_token VARCHAR(255), -- Null si Mangopay
status VARCHAR(50) NOT NULL, -- 'active', 'cancelled', 'expired', 'past_due'
plan VARCHAR(50) NOT NULL, -- 'monthly', 'yearly'
current_period_start TIMESTAMP NOT NULL,
current_period_end TIMESTAMP NOT NULL,
cancelled_at TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
```
**Vérification Premium en temps réel** :
```
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
```
---
## Récapitulatif Section 10

View File

@@ -0,0 +1,308 @@
## 9. Monétisation créateurs
### 9.1 Pourboires
**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)
- Charge comptable importante pour la plateforme
**Post-MVP** : Possible réintégration avec crypto (Bitcoin/Lightning Network) si législation UE l'autorise clairement (régulation MiCA en cours).
---
### 9.2 Conditions d'activation de la monétisation
**Décision** : 5 critères cumulatifs obligatoires
| Critère | Seuil | Justification |
|---------|-------|---------------|
| **Ancienneté** | Compte créé depuis ≥ 3 mois | Anti-fraude : temps de détecter comportements suspects |
| **Popularité** | ≥ 500 abonnés | Garantit audience réelle et engagée |
| **Engagement** | ≥ 10 000 écoutes complètes cumulées | Créateurs produisant du contenu de qualité |
| **Fiabilité** | Aucun strike actif, 0 contenu modéré dans les 6 derniers mois | Historique propre requis |
| **Régularité** | ≥ 5 contenus publiés dans les 90 derniers jours | Activité constante |
**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)
- **Légitimité** : Audience organique prouvée
---
### 9.3 KYC (Know Your Customer) et inscription
**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)
**Documents requis** :
| Document | Obligatoire | Format | Validité |
|----------|-------------|--------|----------|
| **SIRET** | ✅ | 14 chiffres | Permanent |
| **RIB professionnel** | ✅ | IBAN FR | Permanent |
| **Pièce d'identité** | ✅ | CNI/Passeport | En cours de validité |
| **Numéro TVA intracommunautaire** | ⚠️ Si applicable | FR + 11 chiffres | Permanent |
| **Kbis <3 mois** | ⚠️ Si société | PDF | <3 mois |
**Vérification** : Via Mangopay (KYC intégré + vérification bancaire)
**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)
- **Souveraineté EU** : Mangopay est européen (France/Luxembourg), régulé ACPR
---
### 9.4 Sources de revenus créateurs
#### A) Publicités (utilisateurs gratuits)
**Formule** : **3€ / 1000 écoutes complètes** (CPM créateur)
**Répartition économique** :
```
Publicité facturée par RoadWave : 0.05€/écoute complète = 50€ CPM
├─ Créateur touche : 3€ (6% du CA pub)
└─ Plateforme garde : 47€ (94%)
├─ CDN + infrastructure : ~10-15€
├─ Modération + support : ~5-10€
├─ Développement + R&D : ~10-15€
└─ Marge opérationnelle : ~10-15€
```
**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)
- ❌ Bots détectés exclus (rate limiting + analyse patterns)
---
#### B) Abonnés Premium
**Formule** : **70% au créateur, 30% à la plateforme**
**Répartition proportionnelle au temps d'écoute effectif** :
```
Utilisateur Premium = 4.99€/mois
├─ 3.49€ reversés aux créateurs (70%)
└─ 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€
```
**Calcul technique** :
```sql
-- Pour chaque utilisateur Premium
SELECT
creator_id,
SUM(listen_duration_seconds) AS total_seconds,
(SUM(listen_duration_seconds) / total_user_seconds) AS ratio,
(4.99 * 0.70 * ratio) AS revenue_euros
FROM premium_listens
WHERE user_id = :user_id
AND month = :current_month
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
- **Marge plateforme** : 30% couvre absence revenus pub sur Premium
---
### 9.5 Paiement des créateurs
**Seuil minimum** : 50€
- En dessous → solde reporté mois suivant
- Évite frais bancaires sur micro-sommes
- Standard industrie (YouTube/Twitch/Spotify = 50-100€)
**Fréquence** : Mensuelle
| Date | Action |
|------|--------|
| **Dernier jour du mois** (ex: 31 janvier) | Calcul revenus du mois via SQL |
| **1-14 du mois suivant** | Traitement contestations/fraudes éventuelles |
| **15 du mois suivant** (ex: 15 février) | Virement SEPA via Mangopay (Payout) |
| **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
**Tableau de bord créateur** (temps réel) :
| Métrique | Description | Mise à jour |
|----------|-------------|-------------|
| **Revenus pub** | Écoutes × CPM | Temps réel |
| **Revenus premium** | Abonnés actifs × ratio écoute | Temps réel |
| **Solde disponible** | Total revenus mois en cours | Temps réel |
| **Solde en attente** | Revenus mois précédent (paiement le 15) | Figé fin de mois |
| **Historique virements** | Liste des paiements reçus | Permanent |
| **Export comptable CSV** | Données pour expert-comptable | Téléchargement |
**Gestion échecs virement** :
1. Tentative 1 (15 du mois) → échec
2. Retry automatique J+3
3. Retry automatique J+7
4. Si 3 échecs → suspension monétisation + email créateur (RIB invalide)
---
### 9.6 Contenus Premium exclusifs
**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
---
### 9.7 Obligations fiscales
**RoadWave génère automatiquement** :
| Document | Fréquence | Destinataire | Base légale |
|----------|-----------|--------------|-------------|
| **Relevé mensuel PDF** | Chaque mois | Créateur | Transparence |
| **Export CSV comptable** | À la demande | Créateur + expert-comptable | Facilitation déclarations |
| **DAS2 annuel** | Si >1200€/an | Impôts (DGFIP) | Obligation légale France |
**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)
**Exemple DAS2** :
```
Si créateur a touché 2500€ en 2026 :
→ RoadWave envoie DAS2 aux impôts en janvier 2027
→ Créateur reçoit copie par email
→ Créateur doit déclarer ces 2500€ dans sa déclaration annuelle
```
**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
---
### 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
**Plateforme suspend automatiquement si** :
| Motif | Action | Réversible |
|-------|--------|------------|
| **Strike 3+ actif** | Suspension immédiate | Oui, après résolution strikes |
| **Compte bancaire invalide** | Suspension après 3 échecs virement | Oui, après mise à jour RIB |
| **Documents KYC expirés** | Suspension avec préavis 30j | Oui, après renouvellement docs |
| **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
---
## Récapitulatif Section 9

View File

@@ -0,0 +1,633 @@
## 15. Autres comportements
### 15.1 Partage de contenu
**Décision** : Système de partage complet avec web player
#### 15.1.1 Bouton "Partager"
**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)
- Historique personnel
**Icône** : ⬆️ (universelle iOS/Android)
**Menu options** :
- Copier le lien
- WhatsApp
- Email
- SMS
- Plus... (sheet natif OS)
**Justification** :
- Viralité = croissance organique gratuite
- Aucune friction, partage universel
---
#### 15.1.2 Comportement du lien partagé
**Format URL** : `https://roadwave.fr/share/c/[content_id]`
**Comportement multi-plateforme** :
```
User clique lien partagé
Page web responsive
┌─────────────────────────────────┐
│ Si app installée │
│ → Deep link (ouverture directe) │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ Si app non installée │
│ → Web player + CTA téléchargement│
└─────────────────────────────────┘
```
**Contenu de la page web** :
```html
┌───────────────────────────────────────┐
│ RoadWave │
├───────────────────────────────────────┤
│ [Image cover 16:9] │
│ │
│ 📻 Titre du contenu │
│ Par @créateur · 12 min · 🎧 2.3K │
│ │
│ 📍 Paris 5e · Ancré │
│ 🏷️ #Voyage #Histoire │
│ │
│ Description : Lorem ipsum... │
│ │
│ [▶️ Écouter maintenant] │
│ (Player HTML5 si contenu public) │
│ │
│ ────────────────────────────────── │
│ │
│ 📱 Télécharger l'app RoadWave │
│ [App Store] [Google Play] │
│ │
│ [Voir le profil de @créateur] │
└───────────────────────────────────────┘
```
**Métadonnées Open Graph (SEO)** :
```html
<meta property="og:title" content="[Titre contenu] - RoadWave">
<meta property="og:description" content="[Description ou extrait]">
<meta property="og:image" content="[URL cover image]">
<meta property="og:audio" content="[URL audio si public]">
<meta property="og:type" content="music.song">
<meta property="og:site_name" content="RoadWave">
<meta name="twitter:card" content="player">
<meta name="twitter:player" content="https://roadwave.fr/player/[content_id]">
```
**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)
- Coût : 0€ (backend simple + CDN existant)
---
#### 15.1.3 Contenus Premium partagés
**Décision** : Preview 30 secondes + paywall
**Comportement** :
1. User clique lien contenu Premium partagé
2. Page web affiche badge "👑 Contenu Premium"
3. Player démarre automatiquement
4. Après **30 secondes exactement** :
- Fade out audio (2 secondes)
- Overlay apparaît :
```
┌─────────────────────────────────┐
│ 👑 Contenu réservé Premium │
│ │
│ Profitez de ce contenu complet │
│ et de milliers d'autres │
│ sans publicité │
│ │
│ [Passer Premium - 4.99€/mois] │
│ [Télécharger l'app] │
└─────────────────────────────────┘
```
5. Utilisateur peut :
- S'abonner Premium (redirection web Mangopay)
- Télécharger l'app (redirection stores)
- 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
---
### 15.2 Profil créateur
**Décision** : Profil public complet et transparent
#### 15.2.1 Structure de la page profil
**URL** : `https://roadwave.fr/@[pseudo]`
**Layout** :
```
┌────────────────────────────────────────┐
│ [Photo profil 120×120] │
│ @pseudo ✓ │
│ [Badge vérifié si applicable] │
│ │
│ Bio : Lorem ipsum dolor sit amet... │
│ (300 caractères max) │
│ │
│ 🎧 1.2K abonnés │
│ 📻 42 contenus │
│ ⏱️ 18h de contenu créé │
│ 🔊 54K écoutes totales │
│ │
│ [S'abonner] [Partager profil] [•••] │
│ │
│ ──────────────────────────────────── │
│ │
│ Contenus ▼ [Plus récents ▼] │
│ │
│ ┌──────────────────────────────────┐ │
│ │ [Cover] Titre contenu 1 │ │
│ │ 12 min · 🎧 2.3K · 📍 Paris │ │
│ │ [▶️] │ │
│ └──────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────┐ │
│ │ [Cover] Titre contenu 2 │ │
│ │ 8 min · 🎧 5.1K · 📍 Lyon │ │
│ │ [▶️] │ │
│ └──────────────────────────────────┘ │
│ │
│ [Charger plus] │
└────────────────────────────────────────┘
```
**Informations affichées** :
| Élément | Visibilité | Détails |
|---------|------------|---------|
| **Photo + pseudo** | ✅ Public | Identité visuelle |
| **Badge vérifié ✓** | ✅ Public (si applicable) | Compte authentique |
| **Bio** | ✅ Public | 0-300 caractères, markdown basique (gras, italique, liens) |
| **Nombre abonnés** | ✅ Public | Arrondi si >1000 (ex: 1.2K, 54K) |
| **Nombre contenus** | ✅ Public | Exact |
| **Durée totale créée** | ✅ Public | Arrondi en heures (ex: 18h, 142h) |
| **Écoutes totales** | ✅ Public | Arrondi (ex: 54K, 1.2M) |
| **Liste abonnés** | ❌ Privé | Protection vie privée (RGPD) |
| **Revenus** | ❌ Privé | Confidentialité financière |
| **Localisation précise** | ❌ Privé | Sécurité |
| **Email** | ❌ Privé | Anti-spam |
**Tri des contenus** :
| Option | Comportement |
|--------|--------------|
| **Plus récents** | Date publication DESC (défaut) |
| **Plus populaires** | Écoutes complètes × (1 + (date_publication - now) / 90 jours) |
| **Plus anciens** | Date publication ASC |
| **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)
---
#### 15.2.2 Statistiques publiques
**Décision** : Stats arrondies et motivantes
**Affichage public** :
| Métrique | Format affichage | Exemple |
|----------|------------------|---------|
| **Abonnés** | Exact si <1000, arrondi sinon | 342 / 1.2K / 54K / 1.2M |
| **Écoutes totales** | Arrondi dès 1000 | 842 / 5.4K / 142K / 2.1M |
| **Contenus publiés** | Exact | 42 contenus |
| **Durée totale** | Arrondi en heures | 18h / 142h de contenu |
**Métriques PRIVÉES (créateur uniquement)** :
| Métrique | Disponible dans dashboard créateur |
|----------|-------------------------------------|
| **Taux complétion moyen** | 78% (écoutes >80% / écoutes totales) |
| **Évolution abonnés** | Graphique 30j / 90j / 1 an |
| **Écoutes par contenu** | Tableau détaillé |
| **Revenus** | Dashboard monétisation dédié |
| **Taux conversion Premium** | Partages → conversions |
| **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)
- Privacy by design
---
#### 15.2.3 Badge vérifié
**Décision** : Badge unique ✓ (vérifié officiel)
**Critères d'attribution** (au moins UN des critères) :
1. **KYC monétisation validé** : identité vérifiée via Mangopay KYC
2. **Célébrité / Média officiel** : validation manuelle équipe RoadWave
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é"
**Processus d'obtention** :
| Type | Processus |
|------|-----------|
| **Automatique (KYC)** | Badge attribué dès validation documents Mangopay |
| **Manuel (célébrité)** | Formulaire demande → équipe vérifie identité → validation 48-72h |
| **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)
- Coût : 0€ (champ boolean `verified` en DB)
---
### 15.3 Recherche
**Décision** : Recherche full-text + géo + filtres avancés
#### 15.3.1 Recherche par mot-clé
**Implémentation** : PostgreSQL full-text search (français)
**Configuration technique** :
```sql
-- Index full-text optimisé français
CREATE INDEX idx_content_search ON contents
USING GIN(
to_tsvector('french',
coalesce(title, '') || ' ' ||
coalesce(description, '') || ' ' ||
coalesce(creator_pseudo, '')
)
);
-- Recherche avec ranking
SELECT
c.*,
ts_rank(
to_tsvector('french', c.title || ' ' || c.description),
plainto_tsquery('french', $search_query)
) AS rank
FROM contents c
WHERE to_tsvector('french', c.title || ' ' || c.description)
@@ plainto_tsquery('french', $search_query)
ORDER BY rank DESC, listen_count DESC
LIMIT 20;
```
**Champs indexés** :
- Titre du contenu (poids × 3)
- Description (poids × 1)
- Pseudo créateur (poids × 2)
- Tags (poids × 1.5)
**Fonctionnalités** :
| Feature | Description |
|---------|-------------|
| **Stemming français** | "voyages" trouve "voyage", "voyager", etc. |
| **Correction auto** | Suggestion si 0 résultat |
| **Recherches populaires** | "Essayez plutôt : balade paris, audio-guide louvre" |
| **Historique personnel** | 10 dernières recherches sauvegardées |
| **Autocomplete** | Suggestions pendant frappe (top 5) |
**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
---
#### 15.3.2 Recherche géographique
**Décision** : Recherche lieu + rayon paramétrable
**Interface utilisateur** :
```
┌─────────────────────────────────────┐
│ 🔍 Recherche contenu... │
├─────────────────────────────────────┤
<20><> Lieu │
│ [Paris, France ▼] │
│ · Autour de moi (GPS actuel) │
│ · Entrer une adresse/ville │
│ │
│ 📏 Rayon de recherche │
│ [●─────────────────] 50 km │
│ (curseur 5 km → 500 km) │
│ │
│ 🗺️ [Afficher sur carte] │
└─────────────────────────────────────┘
```
**Géocodage** :
| Service | Usage | Coût |
|---------|-------|------|
| **Nominatim (OSM)** | MVP (API publique) | 0€ (rate limit 1 req/s) |
| **Nominatim self-hosted** | Scale (Docker) | 20-50€/mois VPS |
| **Mapbox Geocoding** | Fallback premium | 0.50€ / 1000 requêtes |
**Processus de recherche géo** :
1. User tape "Louvre" ou "Paris"
2. Autocomplete via Nominatim → liste suggestions
3. User sélectionne → récupération coordonnées (lat, lon)
4. Requête PostGIS :
```sql
SELECT c.*,
ST_Distance(c.location::geography, ST_Point($lon, $lat)::geography) AS distance
FROM contents c
WHERE ST_DWithin(
c.location::geography,
ST_Point($lon, $lat)::geography,
$radius_meters
)
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)
---
#### 15.3.3 Filtres avancés
**Décision** : 7 catégories de filtres combinables
**Interface filtres** :
```
┌─────────────────────────────────────┐
│ Filtres [×] │
├─────────────────────────────────────┤
│ Type de contenu │
│ ☐ Contenu court (<5 min) │
│ ☐ Podcast (>5 min) │
│ ☐ Radio live │
│ ☐ Audio-guide │
│ │
│ Durée │
│ ○ Toutes durées │
│ ○ <5 min │
│ ○ 5-15 min │
│ ○ 15-30 min │
│ ○ >30 min │
│ │
│ Classification âge │
│ ☐ Tout public │
│ ☐ 13+ │
│ ☐ 16+ │
│ ☐ 18+ │
│ │
│ Géo-pertinence │
│ ☐ Ancré (lieu précis) │
│ ☐ Contextuel (zone large) │
│ ☐ Neutre (national) │
│ │
│ Tags (multi-sélection) │
│ ☐ Automobile ☐ Voyage │
│ ☐ Famille ☐ Histoire │
│ ☐ Économie ☐ Sciences │
│ ... (liste complète tags) │
│ │
│ Date de publication │
│ ○ Toutes dates │
│ ○ Dernières 24h │
│ ○ Cette semaine │
│ ○ Ce mois │
│ ○ Cette année │
│ │
│ Abonnement │
│ ○ Tous les contenus │
│ ○ Gratuits uniquement │
│ ○ Premium uniquement 👑 │
│ │
│ ────────────────────────────── │
│ [Réinitialiser] [Appliquer] │
└─────────────────────────────────────┘
```
**Options de tri** :
| Tri | Algorithme |
|-----|-----------|
| **Pertinence** | Score recherche × (1 + log(listen_count + 1)) |
| **Popularité** | Écoutes complètes derniers 30j DESC |
| **Récent** | Date publication DESC |
| **Proximité** | Distance GPS ASC (si recherche géo active) |
| **Durée** | Durée audio ASC ou DESC |
**Sauvegarde de recherches** :
- Bouton "💾 Sauvegarder cette recherche"
- Nom personnalisable : "Podcasts voyage Paris"
- Maximum **5 recherches sauvegardées**
- Accès rapide : onglet "Recherches sauvegardées" dans page recherche
- Notifications optionnelles : "3 nouveaux contenus dans 'Podcasts voyage Paris'"
**Performances** :
```sql
-- Index composites pour filtres
CREATE INDEX idx_content_filters ON contents (
content_type,
duration,
age_rating,
geo_type,
published_at
);
-- Index GIN pour tags
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
---
#### 15.3.4 Page de résultats
**Décision** : Liste avec previews enrichies
**Layout résultats** :
```
┌─────────────────────────────────────────┐
│ 🔍 "voyage paris" │
│ 42 résultats · Tri : Pertinence ▼ │
│ [Filtres] [Carte] │
├─────────────────────────────────────────┤
│ ┌─────────────────────────────────────┐ │
│ │ [Cover ] Balade à Paris │ │
│ │ [16:9 ] @paris_stories ✓ │ │
│ │ [Image ] 12 min · 🎧 2.3K │ │
│ │ 📍 Paris 5e · Ancré │ │
│ │ 🏷️ #Voyage #Histoire │ │
│ │ [▶️ Écouter] [⋮] │ │
│ └─────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ [Cover ] Secrets Montmartre │ │
│ │ [16:9 ] @explore_paris │ │
│ │ [Image ] 8 min · 🎧 5.1K │ │
│ │ 📍 Paris 18e · Guide │ │
│ │ 🏷️ #Voyage #Art │ │
│ │ [▶️ Écouter] [⋮] │ │
│ └─────────────────────────────────────┘ │
│ │
│ [Charger plus] (20 suivants) │
└─────────────────────────────────────────┘
```
**Informations par résultat** :
| Élément | Affichage |
|---------|-----------|
| **Cover image** | 16:9, 120×68 px, lazy loading |
| **Titre** | Tronqué 2 lignes max |
| **Créateur** | @pseudo + badge ✓ si vérifié, cliquable → profil |
| **Durée** | Format : "3 min" / "12 min" / "1h 24 min" |
| **Écoutes** | Arrondi : "2.3K" / "54K" / "1.2M" |
| **Localisation** | Ville + type géo (Ancré/Contextuel/Neutre) |
| **Tags** | Maximum 3 premiers tags |
| **Badge Premium** | 👑 si contenu premium |
| **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
- Clustering si >50 résultats proches
**Coût** : 0€ (Leaflet open source + OSM tiles gratuit)
**Justification** :
- Équilibre information / compacité
- Lazy loading = performances
- Infinite scroll = UX moderne
---
## Récapitulatif Section 15
| Point | Décision | Coût | Complexité |
|-------|----------|------|------------|
| **15.1.1** Bouton partager | Disponible partout (⬆️), menu natif OS | 0€ | Faible |
| **15.1.2** Lien partagé | Web player + deep link + Open Graph SEO | 0€ | Moyenne |
| **15.1.3** Premium partagé | Preview 30s + paywall overlay | 0€ | Faible |
| **15.2.1** Page profil | Profil public complet (stats + bio + contenus + tri) | 0€ | Faible |
| **15.2.2** Stats publiques | Arrondies (abonnés, écoutes, durée totale) | 0€ | Faible |
| **15.2.3** Badge vérifié | ✓ si KYC/célébrité/>10K abonnés | 0€ | Faible |
| **15.3.1** Recherche texte | PostgreSQL full-text french + stemming | 0€ | Moyenne |
| **15.3.2** Recherche géo | Lieu + rayon (Nominatim OSM) | 0-50€/mois | Moyenne |
| **15.3.3** Filtres | 7 catégories combinables + sauvegarde recherches | 0€ | Moyenne |
| **15.3.4** Page résultats | Liste enrichie + vue carte Leaflet + infinite scroll | 0€ | Moyenne |
**Coût total MVP : 0-50€/mois** (Nominatim self-hosted optionnel)
---
## Points d'attention pour Gherkin
- Tester partage contenu public vs Premium (preview 30s)
- Tester deep linking iOS/Android (ouverture app si installée)
- Tester Open Graph (aperçu correct sur WhatsApp, Twitter, Facebook)
- Tester profil public (stats arrondies, badge vérifié)
- Tester recherche full-text français (stemming, accents)
- Tester recherche géo + rayon (PostGIS distance)
- Tester combinaison filtres multiples (AND logic)
- Tester sauvegarde recherches (max 5)
- Tester pagination infinite scroll + fallback bouton
- Tester vue carte Leaflet (clustering, markers cliquables)

View File

@@ -0,0 +1,687 @@
# Annexe : Fonctionnalités reportées Post-MVP
**Date** : 2026-01-19
**Statut** : Fonctionnalités validées mais reportées après le MVP
---
## Sommaire
1. [Classification politique et équilibre éditorial](#1-classification-politique-et-équilibre-éditorial)
2. [Système de pourboires créateurs](#2-système-de-pourboires-créateurs)
---
## 1. Classification politique et équilibre éditorial
> ⚠️ **Reporté post-MVP** pour raisons de coût, complexité et risques juridiques.
### 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
- **Controverse** : Peut créer polémique dès le lancement
- **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é
- Option utilisateur "Masquer politique" → 0% contenus politiques
---
### 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)
- 🔵 **Droite** (sécurité, tradition, économie libérale)
- 🟣 **Extrême droite** (nationalisme radical, conservatisme extrême)
- 🟢 **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)
**Règles de diffusion (équilibre imposé)** :
| Préférence utilisateur | Répartition | Justification |
|------------------------|-------------|---------------|
| **Équilibré** (défaut) | 35% gauche / 35% droite / 30% centre-neutre | Neutralité plateforme |
| **Plutôt gauche** | 50% gauche / 20% droite / 30% centre-neutre | Préférence respectée avec minimum opposition |
| **Plutôt droite** | 50% droite / 20% gauche / 30% centre-neutre | Préférence respectée avec minimum opposition |
| **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
- Coût : temps modération humaine (incompressible)
---
### Conditions de réintégration
**Prérequis** :
1. Base utilisateurs stable et revenus suffisants pour financer modération
2. Équipe modération dédiée (2+ modérateurs senior formés)
3. Dashboard admin audit DSA opérationnel
4. Système de logs et archivage 3 ans en place
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
- Phase 4 (Post-MVP+12 mois) : Déploiement progressif si résultats positifs
---
## 2. Système de pourboires créateurs
> ⚠️ **Reporté post-MVP** - Fonctionnalité crypto (Lightning Network) prévue ultérieurement.
### 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
---
### Spécifications complètes (future implémentation)
**Système prévu** : Micro-dons via Lightning Network (Bitcoin Layer 2)
**Fonctionnement** :
1. Auditeur peut envoyer pourboire pendant ou après écoute
2. Montants suggérés : 0.10€, 0.50€, 1€, 5€ (personnalisable)
3. Transaction instantanée via Lightning Network (frais <0.01€)
4. Créateur reçoit directement dans wallet Lightning
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€)
- ✅ International sans frais supplémentaires
- ✅ 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
---
### Conditions de réintégration
**Prérequis** :
1. Réglementation MiCA stabilisée et conforme
2. Adoption crypto suffisante dans la base utilisateurs (>10%)
3. Intégration Lightning Network validée techniquement
4. UX simplifiée pour utilisateurs non-crypto (onboarding dédié)
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
- Phase 4 (Post-MVP+18 mois) : Déploiement public si résultats positifs
---
## 3. Roulette de connexion live aléatoire
> ⚠️ **Reporté post-MVP** - Feature sociale avancée nécessitant masse critique d'utilisateurs et infrastructure WebRTC renforcée.
### 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
- **Focus MVP** : Priorité sur le contenu asynchrone (radios, POIs audio) avant le live P2P
- **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
---
### Spécifications complètes (future implémentation)
**Concept** : Permettre aux utilisateurs (conducteurs ou piétons) de se connecter aléatoirement en live audio avec d'autres utilisateurs pour des conversations spontanées de découverte.
**Fonctionnement** :
1. **Matching algorithmique** :
- Pool unifié conducteurs + piétons (pas de séparation)
- Matching pondéré : 70% centres d'intérêt communs + 30% aléatoire
- Proximité géographique : préférence régionale (même région/département)
- Temps d'attente cible : <30 secondes
2. **Format session** :
- Durée initiale : 5 minutes
- Prolongation par consentement mutuel (5 min supplémentaires, illimitée)
- Skip limité : 3 skips/heure pour éviter abus
- Audio uniquement (pas de vidéo, pas de texte pendant session)
3. **UX différenciée** :
- **Conducteur** : Commandes vocales uniquement ("Roulette", "Suivant", "Terminer")
- **Piéton** : Bouton dédié "Roulette" dans interface principale
- Badges contextuels : "🚗 En voiture" / "🚶 À pied" visibles dès connexion
- Message pré-session : "Vous parlez avec un conducteur. Soyez concis."
4. **Sécurité et modération** :
- Score de confiance minimum requis : 50/100 (nouveaux utilisateurs exclus)
- Enregistrement tampon 5 min glissantes (sauvegardé uniquement si signalement)
- Signalement immédiat pendant session → déconnexion + revue modération
- Sanctions progressives : avertissement → suspension 1 semaine → ban définitif
5. **Transition post-session** :
- Option s'abonner mutuellement après bonne conversation
- Statistiques personnelles : nombre sessions, durée totale, rencontres
- 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
- ❌ Risque dérive (trolls, contenu inapproprié)
- ❌ 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
---
### Conditions de réintégration
**Prérequis** :
1. Base utilisateurs active : >10 000 MAU (Monthly Active Users) dont >500 utilisateurs simultanés en heures pleines
2. Infrastructure WebRTC stable : serveurs TURN/STUN dimensionnés, latence <500ms
3. Système de confiance opérationnel : score utilisateur basé sur comportement, signalements
4. Équipe modération : capacité traiter signalements en <2h
5. Budget infrastructure : 500-1000€/mois selon volume
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%
- Durée moyenne session : >5 minutes (signe d'engagement)
- Taux conversion abonnements mutuels : >10%
---
## 4. Vérification SMS anti-spam
> ⚠️ **Reporté post-MVP** - Ajout d'une vérification par SMS pour éviter les comptes créés avec des emails temporaires.
### 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)
- Modération réactive via signalements
---
### Spécifications complètes (future implémentation)
**Problématique** : Comptes créés avec emails temporaires (Yopmail, 10minutemail, etc.) pour contourner bans ou spammer du contenu.
**Solution** : Vérification numéro mobile par SMS lors de l'inscription.
**Fonctionnement** :
1. **Inscription initiale** :
- Utilisateur crée compte avec email (Zitadel)
- Email de confirmation envoyé (standard)
2. **Détection email suspect** :
- Regex patterns emails temporaires (`.disposable.com`, `tempmail`, etc.)
- API externe (kickbox.io, mailcheck.ai) pour validation domaine
- Score confiance email < 50% → vérification SMS obligatoire
3. **Vérification SMS** :
- Demande numéro mobile (+33, +32, etc.)
- Envoi code 6 chiffres via Brevo SMS API
- Expiration : 10 minutes
- Maximum 3 tentatives/jour/numéro (anti-abus)
4. **Validation** :
- Code correct → compte activé, badge "Vérifié ✓"
- Code incorrect (3 fois) → blocage temporaire 24h
5. **Sanctions doublon** :
- Détection numéro déjà utilisé pour autre compte
- Limite : 3 comptes/numéro maximum
- 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
---
### Conditions de réintégration
**Prérequis** :
1. Base utilisateurs >10K avec taux spam/abus significatif (>5% comptes signalés)
2. Budget SMS disponible (~400-800€/mois selon volume)
3. Intégration Brevo SMS API opérationnelle
4. UX optimisée (onboarding fluide)
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%
- Coût SMS : <2% revenus utilisateurs vérifiés
---
## 5. Synthèse vocale de documents (Text-to-Speech)
> ⚠️ **Reporté post-MVP** - Fonctionnalité Premium permettant aux utilisateurs d'écouter des documents (PDF, articles web, ebooks) convertis en audio.
### 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
- **Focus MVP** : Priorité sur contenu audio natif géolocalisé (podcasts, audio-guides, radios live)
- **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
---
### Spécifications complètes (future implémentation)
**Problématique** : Utilisateurs Premium veulent écouter des documents (articles, PDF, ebooks) pendant leurs trajets sans les lire.
**Solution** : Conversion Text-to-Speech (TTS) de documents en audio avec voix neurale haute qualité.
**Fonctionnement** :
1. **Upload document** :
- Formats supportés : PDF, EPUB, TXT, DOCX, URLs articles web
- Taille max : 50 MB par fichier
- Détection automatique langue (FR, EN, ES, DE, IT)
- OCR automatique si PDF scanné (Tesseract ou Google Vision API)
2. **Traitement et conversion** :
- Nettoyage texte (enlever headers/footers, numéros page, notes de bas de page)
- Détection structure (chapitres, sections) pour navigation
- Génération audio via TTS (Google Cloud TTS ou AWS Polly)
- Voix neurale professionnelle (qualité proche voix humaine)
- Génération chapitres audio distincts (navigation facilitée)
3. **Stockage et synchronisation** :
- Audio généré stocké sur OVH Object Storage (comme autres contenus)
- Ajouté automatiquement à la bibliothèque utilisateur
- Synchronisation multi-device (reprendre écoute où elle s'est arrêtée)
- Conservation : 90 jours après génération, puis suppression automatique
4. **Lecture en voiture** :
- Navigation par chapitres (suivant/précédent)
- Vitesse de lecture ajustable (0.75x, 1x, 1.25x, 1.5x, 2x)
- Signets audio (marquer un passage pour y revenir)
- Reprise automatique au dernier point d'écoute
5. **Limitations et quotas** :
- **Premium uniquement** (pas disponible en gratuit)
- Quota mensuel : 10 documents ou 500K caractères/mois (soit ~5 livres moyens)
- File d'attente : traitement sous 5-10 minutes selon longueur
- Conservation temporaire (90 jours) pour limiter coûts stockage
**Formats supportés** :
| Format | Support | Limitations |
|--------|---------|-------------|
| **PDF texte** | ✅ Natif | Max 50 MB, extraction texte directe |
| **PDF scanné** | ✅ OCR | Max 50 MB, nécessite OCR (plus lent) |
| **EPUB** | ✅ Natif | Ebooks sans DRM uniquement |
| **TXT** | ✅ Natif | UTF-8, max 10 MB |
| **DOCX** | ✅ Natif | Max 20 MB |
| **URLs web** | ✅ Parsing | Articles uniquement (pas de paywall) |
**Voix TTS disponibles** :
| Langue | Voix | Fournisseur |
|--------|------|-------------|
| **Français** | Léa (féminine), Thomas (masculine) | Google Cloud TTS WaveNet |
| **Anglais** | Emily, James | Google Cloud TTS WaveNet |
| **Espagnol** | Carmen, Diego | Google Cloud TTS WaveNet |
| **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)
- ❌ Qualité variable selon format source (PDF mal structurés)
- ❌ Pas de géolocalisation (contenu personnel, pas communautaire)
**Conformité droits d'auteur** :
| Contenu | Autorisé | Restrictions |
|---------|----------|--------------|
| **Documents personnels** | ✅ Oui | Aucun problème légal |
| **Articles web publics** | ✅ Oui | Fair use personnel uniquement |
| **Ebooks DRM-free** | ✅ Oui | Usage privé uniquement (pas de partage) |
| **Ebooks DRM** | ❌ Non | Violation DRM interdite |
| **Livres sous copyright** | ⚠️ Tolérance | Usage strictement privé, pas de redistribution |
| **Articles paywall** | ❌ Non | Bypass paywall interdit |
**Disclaimer utilisateur** :
> "La conversion de documents en audio est réservée à un usage privé uniquement. Vous êtes responsable de vous assurer que vous possédez les droits nécessaires pour convertir et écouter ce contenu. RoadWave ne peut être tenu responsable de toute violation de droits d'auteur."
**Alternatives étudiées** :
| Solution | Coût | Qualité voix | Contraintes |
|----------|------|--------------|-------------|
| **Google Cloud TTS WaveNet** | 0.016€/1K caractères | ⭐⭐⭐⭐⭐ Excellente | API stable, voix neurales |
| **AWS Polly Neural** | 0.016€/1K caractères | ⭐⭐⭐⭐⭐ Excellente | Similar à Google |
| **Azure Cognitive Services** | 0.014€/1K caractères | ⭐⭐⭐⭐ Très bonne | Moins cher, voix correctes |
| **Elevenlabs** | 0.30€/1K caractères | ⭐⭐⭐⭐⭐ Ultra-réaliste | Trop cher pour MVP |
| **OpenAI TTS** | 0.015€/1K caractères | ⭐⭐⭐⭐ Très bonne | Nouveau (2024), à tester |
**Recommandation** : Google Cloud TTS WaveNet (équilibre coût/qualité, voix neurales professionnelles).
---
### Conditions de réintégration
**Prérequis** :
1. Base utilisateurs Premium >1000 abonnés (justifier développement feature)
2. Demande utilisateurs confirmée via sondages (>40% intérêt)
3. Budget TTS + stockage disponible (~500-1000€/mois selon volume)
4. Validation juridique : conformité droits d'auteur, disclaimer clair
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
- Coût TTS : <5% revenus Premium
- Taux d'erreur conversion : <5% (PDF mal structurés, OCR raté)
**Budget estimé** :
| Composant | Coût mensuel (1000 utilisateurs Premium actifs) |
|-----------|--------------------------------------------------|
| **Google Cloud TTS** | ~500€ (10 documents/user/mois, 30K caractères/document) |
| **OCR (PDF scannés)** | ~100€ (30% documents nécessitent OCR) |
| **Stockage** | ~50€ (documents audio temporaires 90 jours) |
| **Bande passante** | Inclus dans infrastructure existante |
| **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%)
- **Rentable si** adoption >30% et rétention +10% (soit +100 abonnés = +499€/mois)
---
## 6. Commandes vocales (CarPlay / Android Auto)
> ⚠️ **Reporté post-MVP** - Permettre aux conducteurs d'utiliser les actions complémentaires via assistants vocaux.
### 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
- **Focus MVP** : Priorité sur like automatique et mode piéton avec actions manuelles
- **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
---
### Spécifications complètes (future implémentation)
**Objectif** : Permettre conducteurs d'effectuer actions complémentaires via commandes vocales sans regarder écran.
**Commandes vocales supportées** :
**iOS (Apple Siri)** :
```
"Hey Siri, like ce contenu"
→ Ajoute +2% jauge (like explicite)
"Hey Siri, abonne-moi à ce créateur"
→ Ajoute +5% toutes jauges du créateur
"Hey Siri, signale ce contenu"
→ Siri demande catégorie vocalement ("Spam", "Haine", etc.)
"Hey Siri, passe au contenu suivant"
→ Même que bouton physique (déjà supporté)
```
**Android (Google Assistant)** :
```
"OK Google, like ce podcast"
→ Ajoute +2% jauge
"OK Google, abonne-moi au créateur"
→ Ajoute +5% toutes jauges du créateur
"OK Google, signale ce contenu"
→ Assistant demande catégorie vocalement
"OK Google, passe au suivant"
→ Même que bouton physique
```
**Implémentation technique** :
**iOS** :
- Siri Intents (framework iOS 12+)
- Clés Intent à ajouter dans `Info.plist` :
```xml
<key>INUserConfirmationConfiguration</key>
<array>
<dict>
<key>INIntentClassName</key>
<string>RoadWaveAddLikeIntent</string>
</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)
- Commentaire optionnel supplémentaire (enregistrement audio conservé)
---
### Conditions de réintégration
**Prérequis** :
1. MVP stabilis en production avec base utilisateurs
2. Données télémétrie : >10K utilisateurs actifs CarPlay/Android Auto
3. Intégration Siri Intents iOS et Google Actions validée
4. Transcription vocale fiable (coût ~0.01€/minute)
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)
- Taux signalements abusifs : <2% (via détection anomalies)
**Budget estimé** :
| Composant | Coût mensuel (10K utilisateurs actifs) |
|-----------|----------------------------------------|
| **Siri Intents** | Inclus iOS SDK |
| **Google Actions** | Inclus Android SDK |
| **Transcription vocale** | ~300€ (30K minutes/mois) |
| **Modération signalements audio** | ~500€ (équipe part-time) |
| **Total** | **~800€/mois** |
---
## Autres fonctionnalités candidates Post-MVP
Liste non exhaustive de fonctionnalités évoquées mais non encore spécifiées :
- **Mode offline avancé** : Téléchargement automatique zones fréquentes
- **Playlists collaboratives** : Co-création de playlists géolocalisées
- **API publique créateurs** : Intégration RSS, podcasts existants
- **Gamification** : Badges, défis géolocalisés, leaderboards
- **Mode nuit** : Interface sombre automatique
- **Statistiques avancées créateurs** : Démographie, retention, heatmaps GPS
Ces fonctionnalités seront spécifiées et priorisées selon les retours utilisateurs MVP.
---
## Suivi et validation
**Responsable** : Product Owner
**Révision** : Trimestrielle
**Critères de priorisation** :
1. Demande utilisateurs (votes, sondages)
2. Impact business (revenus, rétention)
3. Faisabilité technique (complexité, ressources)
4. Conformité légale (RGPD, DSA, MiCA)
5. Différenciation concurrentielle

View File

@@ -0,0 +1,296 @@
# Règles métier RoadWave
> Documentation complète des règles métier validées pour l'application RoadWave.
> Chaque section détaille les comportements, flux et décisions techniques.
---
## 📋 Table des matières
---
## 🏗️ Fondations & Compte utilisateur
### [01. Authentification & Inscription](01-authentification-inscription.md)
**Contenu** : Inscription, connexion, récupération de compte
- Inscription : email/password uniquement (pas d'OAuth tiers)
- Vérification email : optionnelle auditeurs (limite 5 contenus), obligatoire créateurs (lien expire 7j)
- Connexion : 5 tentatives max, blocage 15 min, refresh token 30j
- Récupération mot de passe : email, lien expire 1h
---
### [02. Conformité RGPD](02-conformite-rgpd.md)
**Contenu** : Consentements, anonymisation, export, suppression
- Consentement : Tarteaucitron.js + PostgreSQL versioning
- GPS précis : 24h puis geohash 5 (~5km²)
- Export : JSON + HTML + audio → ZIP, génération asynchrone sous 48h, expire 7j
- Suppression : grace period 30j, contenus créés anonymisés (créateur = "Utilisateur supprimé")
- Analytics : Matomo self-hosted, IP anonymisées, 0 cookie tiers
- DPO : fondateur formé CNIL (non obligatoire <250 employés)
---
## 🎧 Consommation de contenu (Auditeur)
### [03. Centres d'intérêt et jauges](03-centres-interet-jauges.md)
**Contenu** : Évolution jauges, valeurs initiales
- Like automatique : écoute ≥80% → +2%, écoute 30-79% → +1%
- Like explicite (manuel) : +2% (cumulable avec auto)
- Abonnement : +5%
- Skip rapide (<10s) : -0.5%
- Valeur initiale : 50% (neutre)
- Limites : 0-100% stricte, pas de dégradation temporelle
---
### [04. Algorithme de recommandation](04-algorithme-recommandation.md)
**Contenu** : Scoring, géolocalisation, orientation politique, mode Kids
- Classification géo : Ancré (70%) / Contextuel (50%) / Neutre (20%)
- Engagement : 20%, Aléatoire : 10%
- Orientation politique : 5 niveaux, équilibre imposé (40/40/20)
- Mode Kids : 4 tranches (3-6 / 6-9 / 9-12 / 13-15 ans), activation auto <13 ans
- Historique : >80% jamais reproposer, <10s ne pas reproposer
---
### [05. Interactions et navigation](05-interactions-navigation.md)
**Contenu** : Commandes Suivant/Précédent, interactions volant, lecture en boucle
- Suivant : pré-calcul 5 contenus, recalcul >10km ou 10 min
- Précédent : <10s → contenu avant, ≥10s → replay début
- Commandes volant : Suivant, Précédent, Play/Pause uniquement
- Like automatique : ≥80% écoute → +2 points, 30-79% → +1 point
- Actions manuelles : bouton cœur (arrêt véhicule) ou vocal (CarPlay/Android Auto)
- Passage auto après 2s (1s mode Kids)
---
### [06. Audio-guides multi-séquences](06-audio-guides-multi-sequences.md)
**Contenu** : Modes déplacement, navigation, déclenchement GPS, publicités
- **4 modes** : 🚶 Piéton (manuel) / 🚗 Voiture (GPS auto + manuel) / 🚴 Vélo / 🚌 Transport
- **Mode Piéton** : pause auto après chaque séquence, user clique Suivant, navigation libre
- **Mode Voiture** : déclenchement GPS auto (rayon 30m), boutons manuels actifs, warning sécurité >10 km/h
- **Affichage voiture** : distance temps réel + ETA + direction (flèche) + vitesse
- **Rayons** : Voiture 30m, Vélo 50m, Transport 100m (configurable créateur 10-200m)
- **Publicités** : 1/5 séquences tous modes, auto-play, skippable 5s
- **Reprise** : sauvegarde auto (séquence + position exacte), popup si <30j, multi-device (sync cloud)
---
### [07. Contenus géolocalisés voiture](07-contenus-geolocalises-voiture.md)
**Contenu** : Expérience voiture, UI minimaliste, sécurité
- Interface voiture : minimaliste, boutons larges (80×80px min), lecture auto-play
- Commandes vocales : OK Google/Siri + CarPlay/Android Auto
- Notifications : in-app uniquement (pas de push), badge discret
- Sécurité : warning si interaction manuelle >10 km/h
- Mode nuit : automatique selon luminosité GPS ou heure (22h-6h)
---
### [08. Mode offline](08-mode-offline.md)
**Contenu** : Téléchargement, validité, synchronisation
- Zone géographique : choix manuel (autour de moi / ville / département / région)
- Nombre contenus : gratuit 50 max, Premium illimité
- WiFi par défaut, mobile avec confirmation + estimation volume
- Validité : 30 jours, renouvellement auto si WiFi (contenus >25 jours)
- Sync : likes/abonnements batch auto à reconnexion, queue actions 7j max
---
### [09. Abonnements et notifications](09-abonnements-notifications.md)
**Contenu** : Impact algorithme, notifications, audio-guides, limites
- Boost +30% au score final (pas priorité absolue)
- Détection contexte : <5 km/h piéton, >10 km/h voiture
- Voiture : in-app uniquement, Piéton : push actives
- Limite 10 notifications push/jour (5-20), mode silencieux 22h-8h
- Audio-guide piéton : détection <100m lieu, page sélection, navigation manuelle
- Max 200 abonnements, +5% jauges tous tags créateur
---
### [10. Gestion des erreurs](10-gestion-erreurs.md)
**Contenu** : Aucun contenu, contenu supprimé, perte réseau, GPS désactivé
- Aucun contenu : élargissement auto 50km → 100km → département → région → national
- Contenu supprimé : laisser terminer, passage auto suivant après 2s
- Perte réseau : buffer adaptatif (WiFi 5-120s, 4G 10-120s, 3G 30-300s), retry 5s max 6×
- GPS désactivé : mode dégradé (contenu national + neutre + téléchargé)
---
## 🎙️ Création de contenu (Créateur)
### [11. Création et publication de contenu](11-creation-publication-contenu.md)
**Contenu** : Upload, métadonnées, validation, modification
- Formats : MP3, AAC (.mp3, .aac, .m4a), max 200 MB, 4h
- Métadonnées obligatoires : titre, type géo, zone, tags (1-3), classification âge
- Validation 3 premiers contenus : 24-48h (modération RoadWave)
- Modification : métadonnées uniquement, pas audio/zone/classification
---
### [12. Radio live](12-radio-live.md)
**Contenu** : Démarrage, arrêt, comportement auditeur
- Buffer 15s avant diffusion publique, durée max 8h
- Notification push abonnés dans zone géo uniquement
- Arrêt : compte à rebours 5s (manuel) ou auto si déco ≥60s
- Enregistrement auto MP3 256 kbps → replay sous 5-10 min
- Auditeur : buffer 15s, continuation si sortie zone, AUCUN chat
---
### [13. Détection de contenu protégé](13-detection-contenu-protege.md)
**Contenu** : Droits d'auteur, détection musique, sanctions, fair use
- Périmètre MVP : musique uniquement (films/livres exclus)
- Fair use : extraits ≤30s autorisés si usage transformatif (critique/analyse)
- Détection : manuelle lors des 3 premiers contenus (coût 0€)
- Sanctions progressives : Avertissement → Strike 1 (3j) → Strike 2 (7j) → Strike 3 (30j) → Strike 4 (ban)
- Réhabilitation : -1 strike tous les 6 mois sans incident
- Appel : réutilise processus section 14, délai 72h, preuve licence acceptée
- Post-MVP : Chromaprint + MusicBrainz si >50 signalements/mois (50-100€/mois)
---
## 🛡️ Modération & Sécurité
### [14. Modération - Flows opérationnels](14-moderation-flows.md)
**Contenu** : Signalement, traitement, sanctions
- Signalement : 7 catégories (haine, sexuel, illégalité, droits auteur, spam, fake news, autre)
- IA pré-filtre : Whisper large-v3 (transcription) + NLP open source (1-10 min)
- SLA : Critique <2h (24/7), Haute/Moyenne <24h, Basse <72h
- Notification sanction : email + push + in-app (détail complet : catégorie, timestamp, transcription)
- Appel : formulaire in-app, délai 7j max, réponse 72h garanti (standard)
---
### [15. Modération Communautaire - Badges et Récompenses](15-moderation-communautaire.md)
**Contenu** : Système badges, score fiabilité, récompenses, anti-abus
- **3 niveaux badges** : 🥉 Bronze (5 validés), 🥈 Argent (20 validés), 🥇 Or (50 validés)
- **Modal découverte** : affichage unique au 1er signalement, message gratifiant
- **Score fiabilité** : calcul auto pour priorisation algorithme (0-100 points)
- **Utilisateurs de confiance** : statut auto Argent/Or, traitement prioritaire <12h
- **Réduction Premium Or** : -50% pendant 3 mois (2.49€ au lieu de 4.99€), Post-MVP
- **Anti-abus** : limite 10 signalements/24h, audit trimestriel, révocation badges
- **ROI** : positif dès 2-3 utilisateurs Or (économie modération > coût réductions)
- **Coût MVP** : 0€ / **Coût Post-MVP** : 0-200€/mois
---
## 💰 Monétisation & Business
### [16. Publicités](16-publicites.md)
**Contenu** : Campagnes, fréquence, insertion, facturation
- Interface self-service, budget min 50€, étalement paramétrable
- Fréquence : 1/5 contenus (gratuits uniquement)
- Durée : 10-60s (recommandé 15-30s), skippable après 5s
- Validation manuelle 24-48h, prépaiement Mangopay
- Facturation : écoute complète 0.05€, skip après 5s : 0.02€, skip immédiat : 0€
---
### [17. Premium](17-premium.md)
**Contenu** : Offre, multi-devices, avantages, gestion abonnement
- Prix : 4.99€/mois OU 49.99€/an (4.16€/mois effectif)
- Pas d'essai gratuit, pas de partage familial (MVP)
- Multi-devices : 1 seul stream actif, détection connexion simultanée
- Avantages : 0 pub, contenus exclusifs 👑, qualité 64 kbps Opus, offline illimité
- Paiement : Mangopay (web) ou IAP iOS/Android 5.99€/mois (+30% commission)
---
### [18. Monétisation créateurs](18-monetisation-createurs.md)
**Contenu** : Activation, KYC, sources revenus, paiement
- Conditions : compte ≥3 mois, ≥500 abonnés, ≥10K écoutes, 0 strike, ≥5 contenus/90j
- KYC via Mangopay Connect : SIRET, TVA, RIB pro, pièce ID, Kbis <3 mois
- Revenus pub : 3€ / 1000 écoutes complètes (6% CA pub)
- Revenus Premium : 70% créateur, 30% plateforme (proportionnel temps écoute)
- Paiement : seuil 50€, mensuel (15 du mois suivant), SEPA Mangopay
---
## 🔧 Fonctionnalités transverses
### [19. Autres comportements](19-autres-comportements.md)
**Contenu** : Partage, profil créateur, recherche
- Partage : bouton partout, lien `roadwave.fr/share/c/[id]`, web player + deep link
- Profil créateur : @pseudo, bio (300 car), stats publiques arrondies, badge vérifié ✓
- Badge vérifié : KYC validé OU célébrité OU >10K abonnés
- Recherche : full-text PostgreSQL (français, stemming), recherche géo (Nominatim OSM)
- Filtres : type, durée, âge, géo, tags, date, premium (combinables)
- Affichage : liste enrichie (20/page, infinite scroll) + vue carte Leaflet
---
## 🗂️ Organisation
Chaque fichier de règles métier suit la structure :
1. **Décisions** : choix validés avec justifications
2. **Comportements détaillés** : flux utilisateur, cas limites
3. **Paramètres** : valeurs exactes, seuils, durées
4. **Points d'attention Gherkin** : éléments à tester
---
## 🚀 Utilisation
Ces documents servent de **référence unique** pour :
- ✅ Développement backend/frontend
- ✅ Écriture des tests Gherkin (BDD)
- ✅ Validation QA
- ✅ Documentation produit
**Prochaine étape** : Création des fichiers `.feature` Gherkin dans `features/` basés sur ces règles.
---
## 📊 Statistiques
- **19 sections** validées
- **~14 500 lignes** de spécifications détaillées
- **Coût infrastructure MVP** : ~50-250€/mois (hors salaires)
- **Coût Post-MVP** : +0-200€/mois (réductions Premium contributeurs Or)
- **Technologies** : 100% open source (sauf Mangopay paiements)
---
**Dernière mise à jour** : Janvier 2026
**Statut** : ✅ Toutes sections validées + Modération communautaire ajoutée