1.4 MiB
Documentation RoadWave
Table des matières
- RoadWave
- RoadWave - Architecture Technique
- ADR-001 : Langage Backend
- ADR-002 : Protocole de Streaming
- ADR-003 : Codec Audio
- ADR-004 : CDN
- ADR-005 : Base de Données
- ADR-006 : Chiffrement
- ADR-007 : Tests et Spécifications Exécutables
- ADR-008 : Authentification et Gestion d'Identité
- ADR-009 : Solution de Paiement et Gestion des Abonnements
- ADR-010 : Commandes au volant et likes
- ADR-011 : Conformité App Stores et Plateformes Auto
- ADR-012 : Architecture Backend
- ADR-013 : ORM et Accès Données
- ADR-014 : Frontend Mobile
- ADR-015 : Stratégie Tests
- Règles métier RoadWave
- Annexe : Fonctionnalités reportées Post-MVP
- Audio-guides multi-séquences pour piétons
- Impact des abonnements sur l'algorithme
- Limites d'abonnements et désabonnement
- Notifications contextuelles selon le mode de déplacement
- Création d'audio-guide multi-séquences
- Intégration audio-guides avec autres fonctionnalités
- Audio-guide mode piéton (navigation manuelle)
- Audio-guide mode voiture (GPS automatique)
- Audio-guides modes vélo et transport
- Audio-guides Premium et monétisation
- Sauvegarde et reprise de progression audio-guide
- Classification des contenus par âge
- Connexion utilisateur
- Inscription utilisateur
- Récupération de compte
- Gestion des sessions et tokens
- Authentification à deux facteurs (2FA)
- Vérification d'email
- Métadonnées et publication de contenu
- Modification et suppression de contenu
- Upload et encodage de contenu audio
- Validation des 3 premiers contenus
- Élargissement automatique de zone quand aucun contenu n'est disponible
- Gestion d'un contenu supprimé pendant l'écoute
- Mode dégradé sans géolocalisation
- Gestion de la perte de réseau et buffering adaptatif
- Tests BDD - Documentation des fonctionnalités
- Pas de dégradation temporelle des jauges
- Évolution des jauges d'intérêt
- Jauge initiale et cold start
- Synchronisation actions offline
- Téléchargement de contenus offline
- Validité et renouvellement contenus offline
- Modération préventive
- Sanctions et notifications de modération
- Signalement de contenu inapproprié
- Traitement des signalements par l'IA et les modérateurs
- Conditions d'activation de la monétisation
- Contenus Premium exclusifs
- Désactivation et suspension monétisation
- KYC et inscription à la monétisation
- Obligations fiscales
- Paiement des créateurs
- Sources de revenus créateurs
- Actions complémentaires à l'arrêt
- Commande "Précédent"
- Commandes vocales CarPlay et Android Auto
- Commandes au volant et interactions simplifiées
- File d'attente et commande "Suivant"
- Lecture en boucle et enchaînement automatique
- Partage de contenu
- Avantages Premium
- Gestion abonnement Premium
- Multi-devices et détection simultanée
- Offre et tarification Premium
- Profil créateur
- Création de campagnes publicitaires
- Caractéristiques et facturation des publicités
- Gestion du budget et alertes publicitaires
- Insertion et fréquence des publicités
- Métriques d'engagement et dashboard publicitaire
- Validation et modération des publicités
- Architecture technique radio live
- Arrêt du live
- Comportement auditeur pendant un live
- Démarrage d'un live
- Recherche de contenu
- Classification de géo-pertinence des contenus
- Gestion du contenu politique (MVP simplifié)
- Contenus géolocalisés en mode voiture
- Gestion de l'historique et reproposition
- Médias traditionnels sur RoadWave
- Mode Kids pour utilisateurs 13-15 ans
- Paramétrabilité admin et A/B testing
- Paramétrabilité utilisateur et profils
- Formule de scoring et recommandation
- Anonymisation des données GPS après 24h
- Conformité administrative RGPD (Registre, Breach, DPO)
- Gestion du consentement RGPD
- Durée de conservation des données et purge automatique
- Cookies et analytics avec Matomo self-hosted
- Mode dégradé avec GeoIP (sans GPS précis)
- Portabilité des données (Article 20 RGPD)
- Suppression du compte utilisateur (Article 17 RGPD - Droit à l'effacement)
RoadWave
Réseau social audio géolocalisé pour les usagers de la route.
Concept
RoadWave permet aux conducteurs d'écouter du contenu audio contextuel pendant leurs trajets. La navigation se fait par commandes au volant (suivant/précédent), inspirée des réseaux à scroll infini.
Le contenu est diffusé en fonction de la position géographique de l'utilisateur et de ses centres d'intérêt.
Cas d'usage
| Utilisateur | Scénario |
|---|---|
| Conducteur | Écoute contenu audio en conduisant, navigation par commandes au volant (suivant/précédent), reçoit notifications géolocalisées en passant près de points d'intérêt |
| Routier | Écoute podcasts et radios live pendant ses trajets longue distance |
| Touriste à pied | Visite guidée audio d'un musée, monument ou ville : choisit parmi plusieurs guides, navigue entre séquences à son rythme (tactile/vocal), reçoit notification push quand un audio-guide est disponible à proximité |
| Commerçant | Diffuse une publicité audio ciblée GPS devant son commerce |
| Passionné auto | Découvre du contenu automobile près de circuits ou concessionnaires |
| Habitant local | Partage anecdotes ou bons plans géolocalisés dans son quartier |
| Média traditionnel | Le Monde, Le Parisien diffusent actualités géolocalisées ou nationales |
Utilisateurs
Tout utilisateur peut écouter et créer du contenu (rôle flexible).
| Rôle | Description |
|---|---|
| Auditeur | Écoute, like, s'abonne à des créateurs, signale des contenus |
| Créateur | Publie du contenu audio géolocalisé (individus, médias traditionnels) |
| Publicitaire | Diffuse des publicités ciblées géographiquement |
| Modérateur | Valide et modère les contenus signalés |
Types de contenu
| Type | Description |
|---|---|
| Contenu court | Audio de quelques secondes à quelques minutes |
| Podcast | Épisodes plus longs, séries thématiques |
| Radio live | Diffusion en direct avec synchronisation approximative entre auditeurs |
| Audio-guide | Visite guidée multiséquence (musée, monument, ville) : plusieurs séquences numérotées, navigation manuelle entre pistes, liste complète visible, guidage vocal entre points d'intérêt |
Géolocalisation
Le créateur définit la zone de diffusion de son contenu :
| Niveau | Portée |
|---|---|
| Point GPS | Rayon précis autour d'une coordonnée |
| Ville | Diffusion dans une ville |
| Département | Diffusion départementale |
| Région | Diffusion régionale |
| Pays | Diffusion nationale |
Priorité de diffusion : plus la zone est précise, plus le contenu a de chances d'être diffusé (GPS > ville > département > région > pays).
Algorithme de recommandation
Le contenu proposé est calculé via un score combiné :
- Proximité géographique : distance entre l'utilisateur et la zone du contenu
- Pertinence des intérêts : correspondance avec les centres d'intérêt de l'utilisateur
Lorsque plusieurs contenus sont disponibles dans une zone, seul le plus pertinent est diffusé.
Centres d'intérêt
Chaque utilisateur possède des jauges d'intérêt qui évoluent dynamiquement :
Catégories
- Automobile
- Voyage
- Famille
- Amour
- Musique
- Économie
- Cryptomonnaie
- Politique
- ... (extensible)
Évolution des jauges
| Action | Effet |
|---|---|
| Temps d'écoute long | Augmente la jauge |
| Like | Augmente la jauge |
| Abonnement | Augmente fortement la jauge |
| Skip rapide | Diminue la jauge |
Les créateurs taguent leur contenu avec des centres d'intérêt. L'algorithme privilégie les correspondances mais n'exclut pas les utilisateurs sans correspondance.
Interactions
Commandes au volant (conduite)
Interactions simplifiées pour sécurité routière maximale :
| Commande | Action |
|---|---|
| Suivant | Passer au contenu suivant |
| Précédent | Revenir au contenu précédent |
| Play/Pause | Mettre en pause / reprendre la lecture |
Like automatique : Le système détecte automatiquement vos préférences selon votre temps d'écoute :
- Écoute ≥80% du contenu → Like renforcé (+2 points jauge)
- Écoute 30-79% du contenu → Like standard (+1 point jauge)
- Skip après <10s → Signal négatif (-0.5 point)
Voir ADR-010 pour les détails techniques
Actions complémentaires (application à l'arrêt)
| Action | Description |
|---|---|
| Like explicite | Bouton cœur pour liker manuellement |
| S'abonner | Suivre un créateur |
| Signaler | Signaler un contenu inapproprié |
| Unlike | Retirer un like |
Publicités
- Insertion entre deux contenus uniquement (jamais d'interruption)
- Ciblage géographique : point GPS, ville, département, région ou national
- Interface dédiée pour les publicitaires
Radio live
- Diffusion en direct par des créateurs
- Buffering pour garantir une écoute fluide
- Synchronisation approximative entre les auditeurs (quelques secondes de décalage possible)
Modération
Approche hybride combinant participation communautaire, IA et modérateurs dédiés.
Contenus prohibés
| Catégorie | Description |
|---|---|
| Haine et violence | Incitation à la haine, violence, discrimination |
| Contenu sexuel | Pornographie ou contenu sexuellement explicite |
| Illégalité | Apologie du terrorisme, actes criminels |
| Désinformation dangereuse | Fausses informations sur la santé, sécurité routière |
| Harcèlement | Menaces, intimidation, doxxing |
| Droits d'auteur | Violation de propriété intellectuelle |
| Fraude | Arnaques, escroqueries |
Rôles de modération
| Rôle | Capacités |
|---|---|
| Auditeur lambda | Signaler un contenu (1 clic) |
| Auditeur de confiance | Signalements priorisés après historique positif |
| Modérateur junior | Traiter signalements simples (spam, contenu évident) |
| Modérateur senior | Cas complexes, appels, décisions de ban |
| Admin modération | Définir les règles, superviser l'équipe |
Flux de modération
1. Auditeur signale → File d'attente
2. IA pré-filtre → Cas évidents traités automatiquement
3. Modérateur junior → Traite 80% des cas restants
4. Modérateur senior → Cas complexes + recours
Outils de modération automatique
| Outil | Fonction |
|---|---|
| Transcription audio | Conversion automatique en texte pour analyse |
| Analyse vocale IA | Détection de ton agressif, cris, insultes |
| Empreinte audio | Détection de contenus déjà modérés (réupload) |
| Détection droits d'auteur | Identification automatique de musique protégée |
| Filtrage mots-clés | Liste noire de termes inappropriés |
Modération préventive
- Nouveaux créateurs : validation manuelle des 3 premiers contenus
- Score de confiance : évolution selon l'historique du créateur
- Publicités : validation manuelle obligatoire avant diffusion
Système de strikes
| Strike | Sanction |
|---|---|
| Strike 1 | Avertissement + formation modération |
| Strike 2 | Suspension 7 jours + contenu supprimé |
| Strike 3 | Suspension 30 jours |
| Strike 4 | Ban définitif |
- Réhabilitation : -1 strike tous les 6 mois sans incident
Priorisation des signalements
| Priorité | Type de contenu |
|---|---|
| CRITIQUE | Violence, suicide, mise en danger immédiate |
| HAUTE | Harcèlement, haine, désinformation |
| MOYENNE | Spam, contenu inapproprié |
| BASSE | Qualité audio, tags incorrects |
Transparence et recours
- Notification explicite lors de suppression (raison détaillée)
- Processus d'appel : le créateur peut contester une décision
- Délai de traitement : 48-72h pour les recours
- Historique : tableau de bord des sanctions pour le créateur
Modération communautaire
- Utilisateurs de confiance : signalements priorisés après historique positif
- Récompenses : badges, réduction premium pour signalements pertinents
- Lutte contre les signalements abusifs (sanctions possibles)
Modèle économique
Offres
| Formule | Description |
|---|---|
| Gratuit | Accès complet avec publicités entre les contenus |
| Premium | Sans publicité + accès aux contenus exclusifs |
Monétisation créateurs
- Partage des revenus pub : rémunération basée sur le nombre d'écoutes
- Pourboires : les auditeurs peuvent faire des dons aux créateurs
Conformité RGPD
Données collectées
| Donnée | Finalité | Base légale |
|---|---|---|
| Position GPS | Diffusion de contenu géolocalisé | Consentement |
| Historique d'écoute | Personnalisation des recommandations | Intérêt légitime |
| Centres d'intérêt | Algorithme de recommandation | Consentement |
| Identité créateur | Publication de contenu | Exécution du contrat |
Droits des utilisateurs
- Accès : consulter toutes ses données personnelles
- Rectification : modifier ses informations
- Suppression : supprimer son compte et toutes ses données
- Portabilité : exporter ses données dans un format standard
- Opposition : désactiver le profilage publicitaire
Mesures techniques
- Consentement explicite requis pour la géolocalisation
- Anonymisation des données de localisation après 24h (sauf historique personnel)
- Possibilité d'utiliser l'app en mode dégradé (sans géolocalisation précise)
- Données hébergées dans l'UE
RoadWave - Architecture Technique
Les décisions techniques sont documentées dans docs/adr/
Stack Technologique
| Composant | Technologie | ADR |
|---|---|---|
| Backend | Go + Fiber | ADR-001 |
| Architecture Backend | Monolithe Modulaire | ADR-012 |
| Authentification | Zitadel | ADR-008 |
| Streaming | HLS | ADR-002 |
| Codec | Opus | ADR-003 |
| CDN | Bunny CDN | ADR-004 |
| Base de données | PostgreSQL + PostGIS | ADR-005 |
| ORM/Accès données | sqlc | ADR-013 |
| Cache | Redis Cluster | ADR-005 |
| Chiffrement | TLS 1.3 | ADR-006 |
| Live | WebRTC | ADR-002 |
| Frontend Mobile | Flutter | ADR-014 |
| Tests | Testify + Godog (Gherkin) | ADR-015, ADR-007 |
| Paiements | Mangopay | ADR-009 |
| Commandes volant | Like automatique | ADR-010 |
| Conformité stores | CarPlay, Android Auto, App/Play Store | ADR-011 |
Streaming Audio
Protocole : HLS (HTTP Live Streaming)
- Fonctionne à travers firewalls et réseaux mobiles instables
- Cache CDN natif (réduction des coûts)
- Bitrate adaptatif automatique (tunnels, zones rurales)
- Support natif iOS/Android
Codec : Opus
Optimisé pour la voix en environnement bruyant (voiture).
| Qualité | Bitrate | Usage |
|---|---|---|
| Basse | 24 kbps | 2G/Edge |
| Standard | 48 kbps | 3G |
| Haute | 64 kbps | 4G/5G |
Fallback AAC-LC pour appareils legacy.
Buffering Adaptatif
| Réseau | Buffer min | Buffer cible | Buffer max |
|---|---|---|---|
| WiFi | 5s | 30s | 120s |
| 4G/5G | 10s | 45s | 120s |
| 3G | 30s | 90s | 300s |
Sécurité
Chiffrement
- TLS 1.3 sur tous les endpoints (overhead ~1-2%)
- DTLS-SRTP pour WebRTC (radio live)
- Pas de DRM initialement (ajout si licences l'exigent)
Authentification
- Zitadel (self-hosted) pour IAM
- JWT validation locale (zitadel-go SDK)
- OAuth2 PKCE pour mobile (iOS/Android)
- MFA et passkeys disponibles
- Rate limiting par IP et par utilisateur (Nginx + Zitadel)
Base de Données
PostgreSQL + PostGIS
-- Requête géolocalisée typique
SELECT id, ST_Distance(location::geography, ST_MakePoint($lon, $lat)::geography) as distance
FROM contents
WHERE ST_DWithin(location::geography, ST_MakePoint($lon, $lat)::geography, 50000)
ORDER BY distance
LIMIT 20;
Redis Geospatial (Cache)
GEOADD contents:geo longitude latitude content_id
GEORADIUS contents:geo user_lon user_lat 50 km WITHDIST COUNT 20 ASC
TTL cache : 5 minutes (le contenu ne bouge pas).
Architecture Services
┌─────────────────┐
│ Bunny CDN │ Cache HLS, distribution globale
└────────┬────────┘
│
┌────────┴────────┐
│ Nginx │ SSL, rate limiting, reverse proxy
└────────┬────────┘
│
┌────────┴────────┐
│ API Gateway │ Go + Fiber
└────────┬────────┘
│
┌────┴────┬─────────────┐
│ │ │
┌───▼───┐ ┌───▼───┐ ┌───────▼───────┐
│ Auth │ │ User │ │ Content/Geo │
│Service│ │Service│ │ Service │
└───────┘ └───────┘ └───────────────┘
│ │ │
└─────────┴─────────────┘
│
┌─────────┴─────────┐
│ │
┌───▼───┐ ┌─────▼─────┐
│ Redis │ │ PostgreSQL│
│Cluster│ │ + PostGIS │
└───────┘ └───────────┘
Scaling 10M Utilisateurs
Stratégie par phase
| Phase | Utilisateurs | Infra | Coût estimé |
|---|---|---|---|
| MVP | 0-100K | Monolithe Go, PostgreSQL managé + Zitadel, Bunny CDN/Storage | 50-150€/mois |
| Growth | 100K-1M | Kubernetes managé, replicas multi-région | 2-5K€/mois |
| Scale | 1M-10M | Multi-région, Nginx origin shield, Bunny CDN | 20-50K€/mois |
Métriques cibles
| Métrique | Objectif |
|---|---|
| Latence API p99 | < 100ms |
| Temps de démarrage audio | < 3s |
| Disponibilité | 99.9% |
| Connexions/serveur | 100K+ |
Points de vigilance
- Buffering mobile : Pré-chargement agressif avant tunnels (détection GPS)
- Handoff réseau : Buffer suffisant pour survivre aux changements de cellule
- Mode offline : Téléchargement complet sur WiFi
- Bande passante : 48 kbps Opus = ~20 MB/heure (faible consommation data)
Pourquoi pas UDP brut ?
| UDP | HLS/TCP |
|---|---|
| Latence minimale | Latence acceptable (5-30s) |
| Problèmes NAT/firewall | Passe partout |
| Perte de paquets = artefacts | Retransmission automatique |
| Pas de cache CDN | Cache CDN = économies |
| Complexité++ | Standard de l'industrie |
Pour du contenu non-interactif (podcasts, audio-guides), la latence HLS est acceptable. WebRTC réservé à la radio live uniquement.
ADR-001 : Langage Backend
Statut : Accepté Date : 2025-01-17
Contexte
RoadWave doit gérer 10M d'utilisateurs avec des connexions concurrentes massives pour le streaming audio géolocalisé.
Décision
Go avec le framework Fiber.
Alternatives considérées
| Option | Performance | Simplicité | Écosystème |
|---|---|---|---|
| Go + Fiber | 1M+ conn/serveur | Élevée | Excellent cloud-native |
| Rust + Tokio | 2M+ conn/serveur | Faible | Bon |
| Node.js | 100-500K conn | Élevée | Excellent |
| Elixir/Phoenix | 2M+ conn | Moyenne | Bon temps réel |
Justification
- Performance : Go gère 1M+ connexions par serveur avec ~10KB/connexion
- Simplicité : Syntaxe claire, compilation rapide, facile à recruter
- Écosystème : First-class Kubernetes, tooling natif (profiling, race detection)
- Équilibre : Meilleur compromis performance/simplicité pour une startup
Conséquences
- Formation équipe sur Go si nécessaire
- Utilisation des bibliothèques : Fiber (HTTP), pgx (PostgreSQL), go-redis
ADR-002 : Protocole de Streaming
Statut : Accepté Date : 2025-01-17
Contexte
Streaming audio vers des utilisateurs mobiles en voiture, avec réseaux instables (tunnels, zones rurales, handoff cellulaire).
Décision
HLS (HTTP Live Streaming) pour le contenu à la demande. WebRTC réservé à la radio live.
Alternatives considérées
| Option | Latence | Fiabilité mobile | Cache CDN | Complexité |
|---|---|---|---|---|
| HLS | 5-30s | Excellente | Oui | Faible |
| DASH | 5-30s | Bonne | Oui | Moyenne |
| WebRTC | <500ms | Moyenne | Non | Élevée |
| UDP brut | Minimale | Faible | Non | Très élevée |
Justification
- Réseaux mobiles : HLS gère les coupures et changements de cellule nativement
- Cache CDN : Segments .ts cachables = réduction des coûts
- Compatibilité : Support natif iOS/Android
- Bitrate adaptatif : Ajustement automatique selon la qualité réseau
Pourquoi pas UDP ?
- Problèmes NAT/firewall sur réseaux mobiles
- Perte de paquets = artefacts audio
- Impossible à cacher sur CDN
- Complexité sans bénéfice pour du contenu non-interactif
Conséquences
- Latence de 5-30s acceptable pour podcasts/audio-guides
- WebRTC à implémenter séparément pour la radio live
ADR-003 : Codec Audio
Statut : Accepté Date : 2025-01-17
Contexte
Audio diffusé en voiture : environnement bruyant, réseau mobile variable, qualité studio non nécessaire.
Décision
Opus comme codec principal, AAC-LC en fallback.
Profils d'encodage
| Qualité | Bitrate | Usage |
|---|---|---|
| Basse | 24 kbps | 2G/Edge |
| Standard | 48 kbps | 3G |
| Haute | 64 kbps | 4G/5G |
Alternatives considérées
| Codec | Bitrate | Qualité voix | Support mobile |
|---|---|---|---|
| Opus | 24-64 kbps | Excellente | Android natif, iOS via libs |
| AAC-LC | 64-128 kbps | Bonne | Universel |
| AAC-HE v2 | 32-64 kbps | Très bonne | Bon |
| MP3 | 128-320 kbps | Correcte | Universel (legacy) |
Justification
- Environnement bruyant : Opus intègre des algorithmes de résilience au bruit
- Bande passante : 48 kbps Opus ≈ qualité 96 kbps AAC pour la voix
- Consommation data : ~20 MB/heure à 48 kbps
- Latence : 2.5-60ms, idéal pour streaming adaptatif
Conséquences
- Fallback AAC-LC pour appareils legacy
- Pipeline d'encodage à prévoir côté ingestion
ADR-004 : CDN
Statut : Accepté Date : 2025-01-17
Contexte
Distribution audio HLS à 10M d'utilisateurs, besoin de performance, coût maîtrisé, et indépendance vis-à-vis des géants du cloud.
Décision
Bunny CDN comme CDN principal.
Alternatives considérées
| Solution | Coût/mois (100TB) | Setup | Performance | Dépendance |
|---|---|---|---|---|
| Bunny CDN | ~1 000€ | 15 min | Très bon | Faible |
| Cloudflare | 0-5 000€ | 5 min | Excellent | Moyenne |
| CloudFront | ~9 750€ | 1h | Excellent | Forte (AWS) |
| Fastly | ~12-20 000€ | 2h | Exceptionnel | Moyenne |
| Nginx self-hosted | ~2-5 000€ | 1 jour | Excellent | Aucune |
Justification
- Coût : 10x moins cher que CloudFront
- HLS natif : Support optimisé pour le streaming
- Simplicité : Setup en 15 minutes, zéro maintenance
- Européen : Conforme RGPD, 114 PoPs
- Pas de lock-in : Migration facile si besoin
Évolution prévue
- Phase 1 (0-1M users) : Bunny CDN seul
- Phase 2 (1-5M users) : Ajout Nginx origin shield si nécessaire
- Phase 3 (5M+) : Évaluation multi-CDN
Conséquences
- Configuration des règles de cache pour
.m3u8(TTL court) et.ts(TTL long) - Token authentication pour protéger les segments
ADR-005 : Base de Données
Statut : Accepté Date : 2025-01-17
Contexte
Requêtes géolocalisées intensives (contenus à proximité), données utilisateurs, historiques d'écoute.
Décision
- PostgreSQL + PostGIS : Données persistantes et requêtes géospatiales
- Redis Cluster : Cache géolocalisation et sessions
Architecture
Requête → Redis Cache → [HIT] → Réponse
↓
[MISS]
↓
PostGIS → Cache → Réponse
Alternatives considérées
| Usage | Option choisie | Alternatives |
|---|---|---|
| Données utilisateurs | PostgreSQL | MySQL, MongoDB |
| Géolocalisation | PostGIS | MongoDB Geo, Elasticsearch |
| Cache | Redis | Memcached, KeyDB |
| Analytics (futur) | ClickHouse | TimescaleDB |
Justification
PostgreSQL + PostGIS
- Requêtes géospatiales complexes et précises
- Index GIST pour performance
- ACID, fiabilité éprouvée
- Écosystème mature
Redis
- Cache géo natif (
GEORADIUS) : 100K+ requêtes/sec - Sessions utilisateurs
- Pub/sub pour temps réel
Exemple de requête
SELECT id, name,
ST_Distance(location::geography, ST_MakePoint($lon, $lat)::geography) as distance
FROM contents
WHERE ST_DWithin(location::geography, ST_MakePoint($lon, $lat)::geography, 50000)
ORDER BY distance
LIMIT 20;
Conséquences
- TTL cache Redis : 5 minutes (le contenu géolocalisé ne bouge pas)
- Index GIST sur colonnes géométriques
- Réplication read replicas pour scaling lecture
ADR-006 : Chiffrement
Statut : Accepté Date : 2025-01-17
Contexte
Streaming audio sur réseaux mobiles, conformité RGPD, protection du contenu.
Décision
- TLS 1.3 sur tous les endpoints
- DTLS-SRTP pour WebRTC (radio live)
- Pas de DRM au lancement
Alternatives considérées
| Méthode | Overhead | Usage |
|---|---|---|
| TLS 1.3 | ~1-2% CPU | HTTPS streaming |
| DTLS-SRTP | ~3-5% CPU | WebRTC temps réel |
| AES-128-CBC | Minimal | Chiffrement segments HLS |
| Widevine/FairPlay | Modéré | DRM (si licences l'exigent) |
Justification
Pourquoi chiffrer ?
- RGPD : Protection des données utilisateurs obligatoire
- Confiance : Standard attendu en 2025
- Intégrité : Empêche injection de contenu par opérateurs
- Overhead minimal : TLS 1.3 optimisé, impact négligeable
Pourquoi pas de DRM ?
- Contenu généré par utilisateurs (pas de licences)
- Complexité et coût d'intégration Widevine/FairPlay
- À reconsidérer si partenariats avec labels/éditeurs
Conséquences
- Certificats SSL gérés par Bunny CDN ou Let's Encrypt
- Configuration TLS 1.3 sur Nginx/API
- DTLS-SRTP à implémenter pour le module radio live
ADR-007 : Tests et Spécifications Exécutables
Statut : Accepté Date : 2025-01-17
Contexte
RoadWave nécessite une documentation des use cases qui soit à la fois lisible par tous les stakeholders et vérifiable automatiquement. Les scénarios utilisateurs (touriste, routier, commerçant) doivent être validés en continu.
Décision
Gherkin pour les spécifications avec Godog comme runner de tests.
Alternatives considérées
| Option | Lisibilité | Intégration Go | Maintenance |
|---|---|---|---|
| Gherkin + Godog | Excellente | Native | Faible |
| Gauge (Markdown) | Bonne | Plugin | Moyenne |
| Tests Go natifs | Faible (devs only) | Native | Faible |
| Concordion | Bonne | Java-centric | Élevée |
Justification
- Living Documentation : Les fichiers
.featureservent de documentation ET de tests - Accessibilité : Syntaxe Given/When/Then lisible par PO, devs, testeurs
- Cohérence stack : Godog est le standard BDD pour Go
- CI/CD : Intégration simple dans les pipelines
Structure
features/
├── recommendation/
│ ├── geolocalisation.feature
│ └── interets.feature
├── streaming/
│ ├── lecture.feature
│ └── buffering.feature
├── moderation/
│ └── signalement.feature
└── steps/
└── steps.go
Exemple
Feature: Recommandation géolocalisée
Scenario: Touriste près d'un monument
Given un utilisateur avec l'intérêt "tourisme" à 80%
And une position GPS à 100m de la Tour Eiffel
When le système calcule les recommandations
Then l'audio guide "Histoire de la Tour Eiffel" est en première position
Conséquences
- Dépendance :
github.com/cucumber/godog - Les use cases du README doivent être traduits en
.feature - CI exécute
godog runavant chaque merge
ADR-008 : Authentification et Gestion d'Identité
Statut : Accepté Date : 2025-01-18
Contexte
RoadWave nécessite un système d'authentification sécurisé pour mobile (iOS/Android), scalable jusqu'à 10M utilisateurs, avec contraintes de coût réduit et conformité RGPD.
Décision
Zitadel (self-hosted) pour l'IAM avec validation JWT locale côté API Go.
Alternatives considérées
| Solution | Coût (10M users) | Performance | Simplicité | Intégration Go |
|---|---|---|---|---|
| Zitadel | 200-500€/mois | Excellente | Élevée | SDK natif |
| Supabase Auth | 32K€/mois | Excellente | Élevée | REST API |
| Keycloak | 200-800€/mois | Bonne | Faible | Lib tierce |
| Auth0 | 50K€+/mois | Excellente | Élevée | SDK natif |
| JWT Custom | 0€ (dev) | Excellente | Moyenne | Natif |
Justification
- Coût maîtrisé : 100x moins cher que Supabase/Auth0 à 10M users
- Performance : JWT validation locale = 0 latence auth sur chaque requête API
- Stack alignée : Go + PostgreSQL + Redis (déjà dans RoadWave)
- Scalabilité prouvée : Clients avec 2.3M tenants, architecture event-sourced
- RGPD natif : Entreprise suisse, data residency EU, DPA fourni
- Standards ouverts : OpenID Connect certifié (pas de vendor lock-in)
Architecture
┌─────────────────┐
│ Mobile Apps │ OAuth2 PKCE + Refresh tokens
└────────┬────────┘
│
┌────────▼────────┐
│ Zitadel IdP │ PostgreSQL + Redis
│ (self-hosted) │ MFA, passkeys, SSO
└────────┬────────┘
│ JWT token
┌────────▼────────┐
│ Go + Fiber API │ Validation JWT locale
│ (RoadWave) │ github.com/zitadel/zitadel-go
└─────────────────┘
Exemple d'intégration
import "github.com/zitadel/zitadel-go/v3/pkg/authorization/oauth"
// Validation JWT locale haute performance
verifier := oauth.WithJWT(config)
app.Use(verifier.Middleware())
// Accès aux claims
userID := ctx.Locals("sub").(string)
Conséquences
- Déploiement Docker Compose pour MVP
- Migration vers Kubernetes HA en production
- Gestion refresh tokens (rotation automatique)
- MFA et passkeys disponibles out-of-the-box
- Rate limiting intégré à Zitadel
ADR-009 : Solution de Paiement et Gestion des Abonnements
Statut : Accepté Date : 2025-01-19
Contexte
RoadWave nécessite une solution de paiement pour gérer les abonnements Premium (4.99€/mois) et reverser 70% des revenus aux créateurs de contenu. Besoin de marketplace natif (split payments), KYC automatique, conformité RGPD, et coûts maîtrisés.
Décision
Mangopay (France/Luxembourg) comme solution unique pour paiements, marketplace et abonnements.
Alternatives considérées
| Solution | Coût transaction | Marketplace | KYC | Souveraineté |
|---|---|---|---|---|
| Mangopay | 1.8% + 0.18€ | ✅ Natif | ✅ Gratuit | 🇪🇺 France/LU |
| Stripe Connect | 2.9% + 0.30€ | ✅ Natif | ❌ 1.20€ | 🇺🇸 USA |
| Mollie | 2.9% + 0.29€ | ❌ Non | ❌ Non | 🇪🇺 Pays-Bas |
| Paddle | 5% + 0.50€ | ✅ Natif | ✅ Inclus | 🇬🇧 UK |
Justification
- 38% moins cher que Stripe (1.8% vs 2.9%)
- Marketplace natif : E-wallets automatiques, split payments 70/30, payouts SEPA gratuits
- KYC gratuit : vérification d'identité incluse (vs 1.20€/créateur chez Stripe)
- Souveraineté EU : France/Luxembourg, régulé ACPR, RGPD natif
- Conformité DAC7 : reporting fiscal automatique
- Spécialisé marketplace : utilisé par Vinted, Ulule, ManoMano
Architecture
┌────────────────────────┐
│ Utilisateurs Premium │ 4.99€/mois
└───────────┬────────────┘
│
┌───────▼───────┐
│ Mangopay │ - Abonnements récurrents
│ │ - KYC créateurs (gratuit)
│ │ - E-wallets automatiques
└───────┬───────┘ - Payouts SEPA (gratuits)
│
┌─────────┼─────────┐
│ │ │
┌─▼───┐ ┌─▼───┐ ┌─▼────┐
│Créa │ │Créa │ │Plate-│
│teur │ │teur │ │forme │
│ A │ │ B │ │(30%) │
│(70%)│ │(70%)│ │ │
└─────┘ └─────┘ └──────┘
Exemple intégration
// Abonnement récurrent
POST /v2.01/{ClientId}/recurringpayinregistrations
{
"AuthorId": "{UserId}",
"FirstTransactionDebitedFunds": {"Currency": "EUR", "Amount": 499}
}
// Transfer vers créateur (70%)
POST /v2.01/{ClientId}/transfers
{
"DebitedWalletId": "{PlatformWalletId}",
"CreditedWalletId": "{CreatorWalletId}",
"DebitedFunds": {"Currency": "EUR", "Amount": 349}
}
// Payout SEPA gratuit
POST /v2.01/{ClientId}/payouts/bankwire
Conséquences
- Solution tout-en-un : 1 seul prestataire vs 2-3
- Économie de 2160€/an sur 1000 abonnés (vs Stripe)
- Délai activation compte : 2-5 jours
- Intégration Go via REST API (pas de SDK Go officiel)
- Apple/Google IAP gérés séparément (comme toute solution de paiement)
ADR-010 : Commandes au volant et likes
Statut : Accepté Date : 2026-01-20
Contexte
RoadWave est utilisée en conduisant. Les utilisateurs doivent pouvoir liker du contenu pour améliorer les recommandations, mais les commandes au volant ont des limitations :
- 40% des véhicules n'ont que Suivant/Précédent/Mute
- iOS/Android ne supportent pas nativement les appuis longs ou doubles-appuis
- La sécurité impose des interactions minimales
Décision
Like automatique basé sur le temps d'écoute.
Règles :
- ≥80% d'écoute → Like renforcé (+2 points)
- 30-79% d'écoute → Like standard (+1 point)
- <30% d'écoute → Pas de like
- Skip <10s → Signal négatif (-0.5 point)
Alternatives considérées
| Option | Compatibilité | Sécurité | Complexité |
|---|---|---|---|
| Like automatique | 100% | Maximale | Faible |
| Double-tap Pause | ~80% | Moyenne | Moyenne |
| Appui long Suivant | ~95% | Faible | Élevée |
| Configuration paramétrable | 100% | Variable | Très élevée |
Justification
- Sécurité maximale : Aucune action complexe en conduite
- Compatibilité universelle : Fonctionne sur 100% des véhicules
- UX intuitive : Comportement standard (Spotify, YouTube Music)
- Engagement : Tous les contenus génèrent des signaux
- Simplicité : Une seule logique à implémenter et maintenir
Conséquences
- Tracking du temps d'écoute via le player audio
- Calcul du score côté backend basé sur
completion_rate - Communication onboarding : "Vos likes sont automatiques selon votre temps d'écoute"
- Possibilité de like manuel depuis l'app (à l'arrêt)
- Métriques à suivre : taux de complétion, distribution des scores, feedbacks utilisateurs
ADR-011 : Conformité App Stores et Plateformes Auto
Statut : Accepté avec actions requises Date : 2026-01-20
Contexte
RoadWave est une app audio géolocalisée utilisée en conduite (CarPlay/Android Auto) avec :
- Contenu généré par utilisateurs (UGC)
- Monétisation : publicités géolocalisées + Premium (4.99€ web / 5.99€ IAP)
- GPS en arrière-plan
- Partage de revenus avec créateurs (70/30)
Décision
Stratégie de conformité multi-plateforme avec :
- Modération UGC robuste (IA + humain)
- Prix différenciés selon région (US/EU/Monde)
- GPS avec disclosure complète
- Paiements créateurs externes (Mangopay)
Plateformes analysées
| Plateforme | Conformité | Points critiques |
|---|---|---|
| Android Auto | ✅ Conforme | API Level 35+ (Android 15+) |
| CarPlay | ✅ Conforme | Entitlement audio à demander |
| Google Play | ⚠️ Actions requises | Déclaration GPS + UGC modération |
| App Store | ⚠️ Actions requises | Prix différenciés US/EU |
Conformité détaillée
Android Auto / CarPlay ✅
- 100% audio (pas de vidéo)
- Commandes standard au volant
- Aucun achat in-car
- Like automatique = sécurité maximale
- Notifications géolocalisées : sonore uniquement en mode CarPlay/Android Auto (pas d'overlay visuel)
- Action : Demander CarPlay Audio Entitlement (Apple)
Google Play ⚠️
UGC (critique) :
- Modération hybride IA + humain ✅
- 3 premiers contenus validés manuellement ✅
- Système de strikes (4 = ban) ✅
- Signalement + blocage utilisateurs ✅
GPS Background (critique) :
- Permission "Always Location" = OPTIONNELLE
- Demandée uniquement pour mode piéton (notifications arrière-plan audio-guides)
- Justification Play Console :
"RoadWave permet aux utilisateurs de recevoir des alertes audio-guides lorsqu'ils passent à pied près de monuments/musées, même quand l'app est en arrière-plan. Cette fonctionnalité est optionnelle et peut être désactivée dans les paramètres."
- In-app disclosure obligatoire (écran dédié avant demande permission)
- Si refusée : app fonctionne en mode voiture uniquement
- Action : Remplir formulaire background location Play Console avec justification
Réponses formulaire Play Console :
| Question | Réponse |
|---|---|
| Why does your app need background location? | "RoadWave offers optional pedestrian mode: users receive push notifications when passing near audio-guide points (museums, monuments) even when app is in background. This feature is opt-in and can be disabled in settings." |
| Is this feature core to your app? | "No. This is an optional feature. Users can use RoadWave without background location permission (in-car mode works with foreground location only)." |
| What user value does this provide? | "Pedestrian users (tourists, museum visitors) can keep phone in pocket and receive audio-guide alerts automatically without opening the app." |
| Does a less invasive alternative exist? | "Yes. Users can use manual navigation (open app, select audio-guide). Background location is a convenience feature for hands-free experience." |
App Store ⚠️
Prix différenciés (légaux depuis 2025-2026) :
- 🇺🇸 US : Lien externe autorisé (0% commission)
- 🇪🇺 EU : Paiement externe DMA (7-20% commission réduite)
- 🌍 Monde : IAP obligatoire (30% commission)
UGC :
- Mode Kids obligatoire (filtrage selon âge) ✅
- Système de modération + signalement ✅
GPS Background (critique) :
- Permission "Always Location" = OPTIONNELLE
- Deux strings Info.plist requises :
NSLocationWhenInUseUsageDescription: explication mode voitureNSLocationAlwaysAndWhenInUseUsageDescription: explication mode piéton (optionnel)
- In-app disclosure obligatoire avant demande "Always"
- Flux two-step : When In Use → Always (si user active mode piéton)
- Si refusée : app fonctionne en mode voiture uniquement
- Action : Voir strings détaillés dans 05-interactions-navigation.md
Revenus créateurs
Position : Paiements créateurs = "services" (comme YouTube/Uber), pas IAP
- Paiement via Mangopay Connect (externe)
- Commission stores uniquement sur Premium (IAP)
- Comparables : YouTube AdSense, TikTok Creator Fund, Uber
Actions bloquantes avant soumission
| Action | Plateforme | Deadline | Complexité |
|---|---|---|---|
| Demander CarPlay Audio Entitlement | Apple | Avant soumission iOS | Faible |
| Remplir formulaire background location avec justification | Google Play | Avant soumission Android | Faible |
| Implémenter disclosure GPS (écran dédié mode piéton) | iOS + Android | MVP | Moyenne |
| Rendre permission "Always Location" optionnelle | iOS + Android | MVP | Moyenne |
| Désactiver overlay visuel notification en CarPlay/Android Auto | iOS + Android | MVP | Moyenne |
| Mettre à jour strings Info.plist avec justifications détaillées | iOS | MVP | Faible |
| Finaliser système modération UGC | Google + Apple | MVP | Élevée |
Estimation totale : +5 jours développement avant soumission stores
Stratégie de lancement
Phase 1 - MVP :
- IAP uniquement (5.99€/mois mondial)
- Modération UGC active
- GPS avec disclosure
- CarPlay/Android Auto basique
Phase 2 - Post-validation :
- Prix différenciés US (lien externe 4.99€)
- Paiement externe EU (DMA)
- Monétisation créateurs (Mangopay)
Conséquences
- Formation équipe sur politiques stores
- Suivi des métriques modération (% rejet, SLA)
- Migration iOS 26 SDK (Avril 2026)
- API Level 35 Android (2026)
- Communication transparente GPS/publicités
Sources
- Android Auto Media Apps
- CarPlay Developer Guide
- Google Play UGC Policy
- App Store Guidelines
- Apple DMA Update EU
- Google Background Location 2026
ADR-012 : Architecture Backend
Statut : Accepté Date : 2025-01-20
Contexte
RoadWave nécessite une architecture backend évolutive tout en gardant la simplicité opérationnelle pour un MVP. Le système doit supporter une croissance progressive de 0 à 10M utilisateurs.
Décision
Monolithe modulaire avec séparation claire en modules internes.
Alternatives considérées
| Architecture | Complexité | Coûts infra | Time to market | Évolutivité |
|---|---|---|---|---|
| Monolithe modulaire | Faible | Faible | Rapide | 0-1M users |
| Microservices | Élevée | Élevée | Lent | 1M+ users |
| Hybrid (Mono + Workers) | Moyenne | Moyenne | Moyen | 100K-5M users |
Justification
- Simplicité : 1 seul binaire Go, déploiement trivial
- Transactions : Communications inter-modules en mémoire (pas de latence réseau)
- Debugging : Stack traces complètes, profiling unifié
- Coûts : 1 serveur suffit pour 100K users (vs N services)
- Refactoring : Modules internes bien séparés facilitent migration vers microservices si nécessaire
Structure modulaire
internal/
├── auth/ # Validation JWT, intégration Zitadel
├── user/ # Profils, centres d'intérêt
├── content/ # CRUD contenus, métadonnées
├── geo/ # Recherche géospatiale, algorithme
├── streaming/ # Génération HLS, transcoding
├── moderation/ # Signalements, workflow
├── payment/ # Intégration Mangopay
└── analytics/ # Métriques écoute, jauges
Chaque module suit : handler.go → service.go → repository.go.
Conséquences
- Scaling horizontal : réplication complète du binaire (acceptable jusqu'à 1M users)
- Transition vers microservices possible en phase 2 (extraction progressive des modules)
- Importance de maintenir découplage fort entre modules (interfaces claires)
ADR-013 : ORM et Accès Données
Statut : Accepté Date : 2025-01-20
Contexte
RoadWave nécessite des requêtes SQL complexes (PostGIS géospatiales) avec performance optimale et type safety. Le choix entre ORM, query builder ou SQL brut impacte maintenabilité et performance.
Décision
sqlc pour génération de code Go type-safe depuis SQL.
Alternatives considérées
| Solution | Performance | Type Safety | Contrôle SQL | Courbe apprentissage |
|---|---|---|---|---|
| sqlc | Excellente | Très haute | Total | Faible |
| GORM | Moyenne | Moyenne | Limité | Faible |
| pgx + SQL brut | Excellente | Faible | Total | Moyenne |
| sqlx | Bonne | Faible | Total | Faible |
Justification
- Performance : Génération compile-time, zero overhead runtime
- Type safety : Structs Go générées automatiquement, erreurs détectées à la compilation
- Contrôle SQL : Requêtes PostGIS complexes écrites en pur SQL (pas de limitations ORM)
- Maintenabilité : Modifications SQL →
sqlc generate→ code mis à jour - Simplicité : Pas de magic, code généré lisible et debuggable
Workflow
-- queries/content.sql
-- name: GetContentNearby :many
SELECT id, title, ST_Distance(location, $1::geography) as distance
FROM contents
WHERE ST_DWithin(location, $1::geography, $2)
ORDER BY distance
LIMIT $3;
sqlc generate
// Code Go type-safe généré automatiquement
contents, err := q.GetContentNearby(ctx, location, radius, limit)
Conséquences
- Dépendance :
github.com/sqlc-dev/sqlc - Fichier
sqlc.yamlà la racine pour configuration - Migrations gérées séparément avec
golang-migrate - CI doit exécuter
sqlc generatepour valider cohérence SQL/Go
ADR-014 : Frontend Mobile
Statut : Accepté Date : 2025-01-20
Contexte
RoadWave nécessite applications iOS et Android avec support CarPlay/Android Auto, lecture audio HLS avancée, géolocalisation temps réel. Le choix du framework impacte vélocité développement et performances.
Décision
Flutter pour iOS et Android avec codebase unique.
Alternatives considérées
| Framework | Codebase | Performance | Audio/CarPlay | Communauté |
|---|---|---|---|---|
| Flutter | Unique | Native | Excellente | Large |
| React Native | Unique | Bonne | Modules natifs requis | Très large |
| Native (Swift+Kotlin) | Double | Excellente | Native | Large |
| Ionic/Capacitor | Unique | Moyenne | Limitée | Moyenne |
Justification
- Codebase unique : iOS + Android maintenus ensemble, vélocité développement x2
- Performance : Dart compilé en code natif (pas de bridge JS)
- Audio HLS : Package
just_audiomature avec support HLS, buffering adaptatif - CarPlay/Android Auto : Support via packages communautaires (
flutter_carplay,android_auto_flutter) - Géolocalisation :
geolocatorrobuste avec gestion permissions - Écosystème : Widgets riches (Material/Cupertino), state management mature (Bloc, Riverpod)
Packages clés
dependencies:
flutter_bloc: ^8.1.3 # State management
just_audio: ^0.9.36 # Lecture audio HLS
geolocator: ^11.0.0 # GPS temps réel (mode voiture)
geofence_service: ^5.2.0 # Geofencing arrière-plan (mode piéton)
flutter_local_notifications: ^17.0.0 # Notifications géolocalisées
dio: ^5.4.0 # HTTP client
flutter_secure_storage: ^9.0.0 # Tokens JWT
cached_network_image: ^3.3.1 # Cache images
Nouveaux packages (contenus géolocalisés) :
-
geofence_service: Détection entrée/sortie rayon 200m en arrière-plan (mode piéton)- Geofencing natif iOS/Android
- Minimise consommation batterie
- Supporte notifications push même app fermée
-
flutter_local_notifications: Notifications locales avec compteur dynamique- Notification avec compteur décroissant (7→1) en mode voiture
- Icônes personnalisées selon type contenu
- Désactivation overlay en mode CarPlay/Android Auto (conformité)
Structure application
lib/
├── core/ # Config, DI, routes
├── data/ # Repositories, API clients
├── domain/ # Models, business logic
├── presentation/ # UI (screens, widgets, blocs)
└── main.dart
Conséquences
- Équipe doit apprendre Dart (syntaxe proche Java/TypeScript)
- Taille binaire : 8-15 MB (acceptable)
- Tests :
flutter_testpour widgets,integration_testpour E2E - CI/CD : Fastlane pour déploiement stores
ADR-015 : Stratégie Tests
Statut : Accepté Date : 2025-01-20
Contexte
RoadWave nécessite une couverture tests robuste avec documentation vivante des use cases. La stratégie doit équilibrer vélocité développement et qualité.
Décision
Approche multi-niveaux : unitaires, intégration, BDD (Gherkin), E2E, load testing.
Stratégie par type
| Type | Framework | Cible | Fréquence |
|---|---|---|---|
| Unitaires | Testify | 80%+ couverture | Chaque commit |
| Intégration DB | Testify + Testcontainers | Repositories critiques | Avant merge PR |
| BDD (Gherkin) | Godog | User stories | Avant release |
| E2E Mobile | Flutter integration_test | Parcours critiques | Nightly |
| Load | k6 | N/A | Avant mise en prod |
Tests unitaires (Testify)
// internal/user/service_test.go
func TestGetUserByID(t *testing.T) {
mockRepo := new(MockRepository)
service := NewService(mockRepo)
mockRepo.On("FindByID", "123").Return(&User{ID: "123"}, nil)
user, err := service.GetByID("123")
assert.NoError(t, err)
assert.Equal(t, "123", user.ID)
mockRepo.AssertExpectations(t)
}
Couverture minimale : 80% sur packages internal/*/service.go
Tests BDD (Gherkin + Godog)
Voir ADR-007 pour contexte complet.
# features/recommendation.feature
Feature: Recommandation géolocalisée
Scenario: Contenu proche prioritaire
Given je suis à Paris (48.8566, 2.3522)
And un contenu existe à 500m avec tag "tourisme"
And mon intérêt "tourisme" est à 85%
When je demande des recommandations
Then le contenu est en première position
And le score de pertinence est supérieur à 0.8
Couverture : Tous les cas d'usage du README.md traduits en .feature.
Tests intégration (Testcontainers)
// internal/geo/repository_integration_test.go
func TestFindContentNearby(t *testing.T) {
container := testcontainers.RunPostGISContainer(t)
defer container.Terminate()
repo := NewRepository(container.DB())
// Insert test data
repo.CreateContent(testContent)
// Query
results := repo.FindNearby(48.8566, 2.3522, 5000)
assert.Len(t, results, 1)
}
Tests E2E Mobile (Flutter)
// integration_test/player_test.dart
testWidgets('Play audio and skip', (tester) async {
await tester.pumpWidget(MyApp());
await tester.tap(find.byIcon(Icons.play_arrow));
await tester.pumpAndSettle();
expect(find.text('Now Playing'), findsOneWidget);
await tester.tap(find.byIcon(Icons.skip_next));
expect(find.text('Next Content'), findsOneWidget);
});
Load testing (k6)
// tests/load/streaming.js
import http from 'k6/http';
import { check } from 'k6';
export let options = {
stages: [
{ duration: '2m', target: 1000 },
{ duration: '5m', target: 10000 },
],
};
export default function () {
let res = http.get('https://api.roadwave.com/v1/content/nearby');
check(res, { 'status is 200': (r) => r.status === 200 });
}
Objectif : API p99 < 100ms à 10K RPS.
CI/CD Pipeline
# .github/workflows/ci.yml
- name: Unit tests
run: go test -race -coverprofile=coverage.out ./...
- name: BDD tests
run: godog run features/
- name: Integration tests
run: go test -tags=integration ./...
- name: Coverage gate
run: |
coverage=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
if (( $(echo "$coverage < 80" | bc -l) )); then
echo "Coverage $coverage% < 80%"
exit 1
fi
Conséquences
- Dépendances :
github.com/stretchr/testifygithub.com/cucumber/godoggithub.com/testcontainers/testcontainers-gografana/k6
- Temps CI : ~3-5 min (tests unitaires + BDD)
- Tests intégration/E2E : nightly builds (15-30 min)
- Load tests : avant chaque release majeure
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
01. Authentification & Inscription
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. Algorithme de recommandation
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
03. Centres d'intérêt et jauges
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. Création et publication de contenu
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
05. Interactions et navigation
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. Publicités
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€
07. Radio live
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
08. Abonnements et notifications
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
09. Monétisation créateurs
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
10. Premium
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)
11. Mode offline
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
12. Gestion des erreurs
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é)
13. Conformité RGPD
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)
14. Modération - Flows opérationnels
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. Autres comportements
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
16. Audio-guides multi-séquences
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)
🗂️ Organisation
Chaque fichier de règles métier suit la structure :
- Décisions : choix validés avec justifications
- Comportements détaillés : flux utilisateur, cas limites
- Paramètres : valeurs exactes, seuils, durées
- 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
- 16 sections validées
- ~12 000 lignes de spécifications détaillées
- Coût infrastructure MVP : ~50-250€/mois (hors salaires)
- Technologies : 100% open source (sauf Mangopay paiements)
Dernière mise à jour : Janvier 2026 Statut : ✅ Toutes sections validées
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 :
- Utilisateur clique "Mot de passe oublié"
- Email avec lien de reset envoyé
- Lien expire après 1 heure
- Page de reset : nouveau mot de passe (validation règles)
- 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
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 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 :
- Utilisateur passe à <500m d'un point GPS (contenu géo-ancré)
- Notification sonore (bip court) + visuelle (logo selon type)
- Types de logos : 📍 Info, 🏛️ Culturel, 🍴 Commercial, 🎭 Événement
- Délai réaction utilisateur : 5 secondes pour accepter (bouton volant ou commande vocale)
- Si accepté → lecture immédiate
- 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
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)
- 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) :
- Nouvel utilisateur s'inscrit → toutes jauges à 50%
- Écoute premier podcast "Automobile" → jauge Auto monte à 51%
- Skip un contenu "Économie" → jauge Éco descend à 48%
- 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
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) → Bunny 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 :
- Créateur upload ses 3 premiers contenus
- Contenus passent en file d'attente modération
- Modérateur junior RoadWave :
- Écoute 30 secondes (ou 15s à 2x)
- Vérifie métadonnées
- Valide ou rejette avec raison
- Si accepté : contenu publié + notification créateur
- Si refusé : notification avec raison détaillée + lien vers règles
- 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 |
| Réversibilité | Non |
| Historique auditeurs | Marqué "Contenu supprimé par créateur" |
| Analytics plateforme | Anonymisé et conservé |
| Fichiers CDN | Supprimés sous 24h |
Exemple scénario suppression :
Créateur supprime podcast écouté par 1000 personnes
→ CDN : fichiers purgés sous 24h
→ 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
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 :
- User entend notification sonore + voit icône et compteur
- User appuie "Suivant" dans les 7 secondes → décompte 5s démarre
- Pendant décompte : contenu actuel continue, compteur visible (5...4...3...2...1)
- Si contenu actuel se termine pendant décompte → contenu suivant du buffer démarre
- À 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) :
<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) :
<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 :
- User tap notification push
- App s'ouvre sur la page du contenu
- User peut démarrer la lecture manuellement
- 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 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 (app à l'arrêt)
Interface mobile (véhicule arrêté uniquement) :
| 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é ✓"
Commandes vocales (optionnel, si CarPlay/Android Auto)
Disponible uniquement avec :
- Apple CarPlay (Siri)
- Android Auto (Google Assistant)
- ~30-40% du parc automobile EU (2026)
Exemples de commandes :
"Hey Siri, like ce podcast"
"OK Google, abonne-moi à ce créateur"
"Hey Siri, passe au contenu suivant"
"OK Google, signale ce contenu"
Implémentation : Intents iOS/Android personnalisés (Sprint 5, post-MVP)
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) :
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) :
// 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 :
- Audio termine → Timer 2 secondes démarre
- UI overlay : "Contenu suivant dans 2s..." + barre décompte
- Possibilité annuler : bouton "Rester sur ce contenu" (optionnel)
- 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 :
- Message : "Aucun contenu disponible dans cette zone"
- Proposition : "Élargir la zone de recherche ?" (bouton)
- Si accepté → relance algo avec rayon +50km
- 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
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 :
- Publicitaire upload audio pub (formats : MP3, AAC)
- Validation manuelle obligatoire (modérateur RoadWave)
- Délai : 24-48h ouvrées
- Critères : respect réglementation, qualité audio, classification correcte
- Si accepté → campagne démarre à la date choisie
- 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
7. Radio live
7.1 Démarrage d'un live
Décision : Buffer 15s + notification abonnés + limite 8h
Processus de démarrage :
- Créateur appuie "Démarrer live" dans l'app
- 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)
- 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
- 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 + ban temporaire |
| Événement sportif payant | Match, compétition avec droits TV | Strike 2 immédiat |
| Œuvre protégée | Film, série, musique en fond sans droits | Strike 1 + suppression live |
| Contenu violent | Agression, violence physique | Ban immédiat |
| Contenu illégal | Apologie terrorisme, pédopornographie | 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)
- 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 :
- Créateur appuie "Arrêter live"
- 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")
- Timer atteint 0 → arrêt diffusion
- 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 :
- Pendant live : enregistrement continu serveur (format Opus raw)
- 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)
- 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)
↓ CDN (Bunny)
Auditeurs (App mobile, HLS natif)
Flux détaillé :
- Créateur → WebRTC OPUS 48 kbps vers serveur Go
- Serveur Go → Conversion temps réel OPUS → segments HLS (.m3u8 + .ts)
- Bunny CDN → Distribution HLS avec cache
- Auditeurs → Lecture HLS native iOS/Android (buffer 15s)
- Enregistrement parallèle → Opus raw stocké temporairement
- 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)
- ✅ Bunny CDN (distribution HLS, pas Google/Cloudflare)
- ✅ 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)
- ✅ CDN cache les segments (coût réduit)
- ✅ Scalable horizontalement (workers Go)
Coût estimé :
| Phase | Utilisateurs | Infra live | Coût/mois |
|---|---|---|---|
| MVP | 0-100K | 1 instance Go (ingestion 100 lives simultanés) | +50€ (serveur) + bande passante CDN |
| 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 CDN, cache segments)
- Exemple : 100 auditeurs = 4.8 Mbps = ~2 Go/heure via CDN
- Coût Bunny : ~0.01€/GB = 0.02€/heure pour 100 auditeurs
Récapitulatif Section 7
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
- Utilisateur à pied (<5 km/h) passe à <100m d'un lieu avec audio-guides
- Notification push : "📍 Audio-guide disponible : [Musée du Louvre]"
- 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 :
- Créateur upload plusieurs fichiers audio (1 par séquence)
- Numérote les séquences : "Séquence 1", "Séquence 2", etc.
- Titre chaque séquence : "Introduction", "La Joconde", etc.
- Définit point GPS unique pour tout le guide (centre du lieu)
- Métadonnées : durée totale calculée automatiquement
Format stockage :
{
"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)
- 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
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é | <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 :
-- 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 :
- Tentative 1 (15 du mois) → échec
- Retry automatique J+3
- Retry automatique J+7
- 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
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 :
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
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 :
- User clique "Télécharger"
- Détection : pas de WiFi
- Popup : "Vous n'êtes pas connecté en WiFi. Télécharger via données mobiles consommera environ X MB. Continuer ?"
- 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 |
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
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_consentsavec 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 :
- Données précises conservées 24h (recommandation personnalisée)
- Après 24h : conversion en geohash précision 5 (~5km²)
- Coordonnées originales supprimées définitivement
Implémentation PostGIS :
-- 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 :
- Demande via paramètres compte
- Génération asynchrone (worker background)
- Email avec lien download (expire 7 jours)
- 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 :
- Utilisateur clique "Supprimer mon compte"
- Compte désactivé immédiatement (login impossible)
- Contenus cachés pendant 30 jours (non diffusés)
- Email confirmation + lien annulation (valide 30j)
- 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 :
- H+0 : Détection et confinement
- H+24 : Évaluation gravité (données concernées, utilisateurs impactés)
- H+48 : Notification CNIL si risque pour utilisateurs
- 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)
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é |
| 📧 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 :
- Signalement reçu → ajout file d'attente asynchrone
- Transcription audio (1-10 minutes selon durée)
- Analyse automatique :
- Score de confiance : 0-100%
- Catégorie détectée
- Timestamps des passages problématiques
- 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" |
| 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 :
- Catégorie violée : référence précise CGU (ex: "Article 3.2 - Haine & violence")
- Raison détaillée : explication en langage clair (non juridique)
- Extrait audio : timestamp exact du passage problématique (ex: "3:42-4:15")
- Transcription : texte problématique surligné en rouge
- Gravité : Strike actuel + conséquences (ex: "Strike 2/4 - Suspension 7 jours")
- 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 :
- Décision : Maintien / Annulation / Réduction de sanction
- Justification : explication de la décision d'appel
- Actions : Strike retiré / Suspension annulée / Contenu rétabli (si applicable)
- 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 :
- Lecture accélérée : 0.75x à 2x (gain productivité)
- Marqueurs temporels : annotation directe sur waveform
- Historique créateur : vue rapide contenus précédents + strikes
- Statistiques : signalements traités/jour, temps moyen, précision
- 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
Prochaine section à clarifier : Section 11 (Mode offline) ou Section 12 (Gestion des erreurs)
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
- 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 :
┌───────────────────────────────────────┐
│ 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) :
<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 :
- User clique lien contenu Premium partagé
- Page web affiche badge "👑 Contenu Premium"
- Player démarre automatiquement
- 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] │
└─────────────────────────────────┘
- 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é |
| ❌ 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) :
- KYC monétisation validé : identité vérifiée via Mangopay KYC
- Célébrité / Média officiel : validation manuelle équipe RoadWave
- 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
verifieden 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 :
-- 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 :
- User tape "Louvre" ou "Paris"
- Autocomplete via Nominatim → liste suggestions
- User sélectionne → récupération coordonnées (lat, lon)
- Requête PostGIS :
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 :
-- 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)
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) :
- Séquence 1 se termine
- Player se met en pause automatique
- Message affiché : "Séquence 1 terminée. Appuyez sur Suivant quand vous êtes prêt."
- User appuie sur [▶|] → Séquence 2 démarre immédiatement
Séquence avec publicité (1 pub / 5 séquences) :
- Séquence 2 se termine
- Publicité s'enchaîne automatiquement (pas d'attente bouton)
- Pub se lit (skippable après 5s)
- Pub se termine → Player se met en pause automatique
- Message : "Séquence 3 prête. Appuyez sur Suivant."
- 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 :
- User démarre audio-guide en voiture (voir section 16.1 pour démarrage)
- Séquence 1 démarre automatiquement au point GPS défini (rayon 30m)
- Séquence 1 se termine
- Affichage progress bar : distance temps réel + ETA jusqu'au prochain point
- User roule vers point GPS suivant
- Arrivée au point GPS suivant (rayon 30m) → déclenchement automatique séquence suivante
- Notification sonore discrète : "Ding" (0.3s) + toast 2s : "Enclos des girafes"
- 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)
- 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 :
// 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 :
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 :
- User démarre audio-guide sur iPhone (séquences 1-3)
- Progression sync cloud
- Lendemain : user ouvre app sur iPad
- Popup : "Reprendre Safari du Paugre sur cet appareil ?"
- 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
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
⚠️ 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 :
- Base utilisateurs stable et revenus suffisants pour financer modération
- Équipe modération dédiée (2+ modérateurs senior formés)
- Dashboard admin audit DSA opérationnel
- Système de logs et archivage 3 ans en place
- 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 :
- Auditeur peut envoyer pourboire pendant ou après écoute
- Montants suggérés : 0.10€, 0.50€, 1€, 5€ (personnalisable)
- Transaction instantanée via Lightning Network (frais <0.01€)
- Créateur reçoit directement dans wallet Lightning
- 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 :
- Réglementation MiCA stabilisée et conforme
- Adoption crypto suffisante dans la base utilisateurs (>10%)
- Intégration Lightning Network validée techniquement
- UX simplifiée pour utilisateurs non-crypto (onboarding dédié)
- 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
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 :
- Demande utilisateurs (votes, sondages)
- Impact business (revenus, rétention)
- Faisabilité technique (complexité, ressources)
- Conformité légale (RGPD, DSA, MiCA)
- Différenciation concurrentielle
Audio-guides multi-séquences pour piétons
En tant qu'auditeur à pied Je veux profiter d'audio-guides structurés lors de mes visites Afin de découvrir des lieux de manière autonome et à mon rythme
29 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis connecté en tant qu'auditeur Et que je suis en mode piéton (vitesse <5 km/h)
1. Détection d'audio-guide à proximité
Étant donné que je me trouve à 80 mètres du Musée du Louvre Et que 3 audio-guides sont disponibles pour ce lieu
Quand le système détecte ma position
Alors je reçois une notification push:
2. Rayon de détection de 100m
Étant donné qu'un audio-guide est centré aux coordonnées GPS du Louvre
Quand je suis à exactement 100m du centre
Alors la notification est déclenchée Et quand je suis à 101m, aucune notification n'est envoyée
3. Page de sélection des audio-guides
Étant donné que j'ai tapé sur la notification audio-guide
Quand la page de sélection s'affiche
Alors je vois une liste de guides disponibles:
| titre | créateur | nb_sequences | durée | note | écoutes |
|---|---|---|---|---|---|
| Visite complète | Créateur A | 12 | 45 min | 4.8 | 1.2K |
| Œuvres majeures | Créateur B | 5 | 20 min | 4.9 | 3.5K |
| Visite famille | Créateur C | 8 | 30 min | 4.7 | 850 |
4. Sélection d'un audio-guide
Étant donné que je suis sur la page de sélection
Quand je tape sur "Visite complète (45 min)"
Alors l'interface de lecture d'audio-guide s'ouvre Et la séquence 1 commence automatiquement Et je vois la liste complète des 12 séquences
5. Interface de lecture audio-guide
Étant donné que j'ai sélectionné un audio-guide de 12 séquences
Quand l'interface s'affiche
Alors je vois:
| élément | exemple |
|---|---|
| Titre guide | 🎨 Visite complète • Musée du Louvre |
| Piste actuelle | Piste 2/12 |
| Titre séquence | "La Joconde - Histoire et mystères" |
| Barre de progression | 3:24 / 6:50 |
| Liste séquences | ✅ 1. Intro, ▶️ 2. Joconde, ⏸️ 3. Vénus... |
| Boutons navigation | Précédent, Play/Pause, Suivant |
6. Navigation vers séquence suivante
Étant donné que j'écoute la séquence 2
Quand je tape sur "Suivant"
Alors la séquence 3 commence immédiatement Et le titre de la séquence s'affiche: "Vénus de Milo" Et la barre de progression se réinitialise
7. Navigation vers séquence précédente
Étant donné que j'écoute la séquence 5
Quand je tape sur "Précédent"
Alors la séquence 4 recommence depuis le début Et je peux réécouter cette séquence
8. Saut direct à une séquence spécifique
Étant donné que j'écoute la séquence 2 Et que la liste des séquences est affichée
Quand je tape sur "7. Peintures Renaissance"
Alors la séquence 7 démarre immédiatement Et je passe directement de la séquence 2 à la 7
9. Commande vocale "Suivant"
Étant donné que j'écoute la séquence 3
Quand je dis "Suivant" via la commande vocale
Alors la séquence 4 démarre Et la commande vocale fonctionne même si l'écran est verrouillé
10. Commande vocale "Précédent"
Étant donné que j'écoute la séquence 6
Quand je dis "Précédent" via la commande vocale
Alors la séquence 5 démarre depuis le début
11. Pause et reprise à la position exacte
Étant donné que j'écoute la séquence 4 à la position 2:30
Quand je mets en pause Et que j'attends 5 minutes Et que je reprends la lecture
Alors la séquence reprend exactement à 2:30 Et aucune donnée n'est perdue
12. Guidage vocal automatique entre séquences
Étant donné que la séquence 2 se termine
Quand la transition vers la séquence 3 se produit
Alors j'entends un message vocal: Et la séquence 3 ne démarre pas automatiquement (navigation manuelle)
13. Avertissement si éloignement du point d'intérêt
Étant donné que je suis dans le guide du Louvre Et que je devrais être devant la Vénus de Milo (séquence 3)
Quand je m'éloigne de plus de 50m de ce point
Alors j'entends un message vocal: Et un bouton "Voir le plan" apparaît dans l'interface
14. Sauvegarde automatique de la progression
Étant donné que j'écoute la séquence 5 à la position 1:45
Quand je ferme l'application brutalement Et que je la rouvre 10 minutes plus tard
Alors je vois une popup "Reprendre la visite du Musée du Louvre ?" Et si je choisis "Reprendre", je retourne à la séquence 5 à 1:45
15. Option de recommencer depuis le début
Étant donné que j'ai une progression sauvegardée à la séquence 7
Quand je rouvre le guide
Alors je vois 2 options:
| option | action |
|---|---|
| Reprendre à la séquence 7 | Reprend à la position exacte |
| Recommencer depuis le début | Retourne à la séquence 1 |
16. Expiration de la sauvegarde après 30 jours
Étant donné que j'ai une progression sauvegardée depuis 30 jours
Quand j'essaie de reprendre le guide
Alors la sauvegarde est considérée comme expirée Et je recommence depuis la séquence 1 Et je vois le message "Votre précédente visite date de plus de 30 jours. Recommençons depuis le début."
17. Synchronisation multi-device de la progression
Étant donné que j'écoute un guide sur mon iPhone à la séquence 4
Quand je ferme l'app et ouvre sur mon iPad
Alors je vois la progression synchronisée Et je peux reprendre à la séquence 4 sur l'iPad
18. Marquage "Terminé" après toutes les séquences
Étant donné que j'écoute la dernière séquence (12/12)
Quand cette séquence se termine
Alors le guide est marqué "✅ Terminé" dans mon historique Et je vois un message de félicitation: Et le créateur gagne les statistiques d'écoute complète
19. Création d'audio-guide par un créateur
Étant donné que je suis un créateur
Quand je crée un nouvel audio-guide
Alors je dois:
| étape | détail |
|---|---|
| Uploader plusieurs fichiers | 1 fichier MP3 par séquence |
| Numéroter les séquences | Séquence 1, Séquence 2, etc. |
| Titrer chaque séquence | "Introduction", "La Joconde", etc. |
| Définir point GPS unique | Centre du lieu (ex: Louvre) |
| Définir rayon de détection | Par défaut 100m |
Et la durée totale est calculée automatiquement
20. Structure JSON de stockage audio-guide
Étant donné qu'un créateur publie un audio-guide du Louvre
Quand les métadonnées sont stockées en base
Alors le format JSON contient:
21. Limitation du nombre de séquences
Étant donné que je crée un audio-guide
Quand j'essaie d'ajouter plus de 50 séquences
Alors je vois le message "Maximum 50 séquences par audio-guide" Et je dois structurer mon contenu différemment ou créer plusieurs guides
22. Quitter le guide et sauvegarder
Étant donné que j'écoute la séquence 6
Quand je tape sur le bouton "×" (fermer)
Alors je vois une confirmation: Et si je confirme, la progression est enregistrée Et je retourne à l'écran principal
23. Statistiques créateur pour audio-guides
Étant donné que je suis créateur d'un audio-guide
Quand je consulte mes statistiques
Alors je vois:
| métrique | exemple valeur |
|---|---|
| Nombre de démarrages | 1250 |
| Nombre de complétions (100%) | 387 (31%) |
| Séquence la plus skippée | Séquence 8 |
| Durée moyenne d'écoute | 28 min (sur 45) |
24. Audio-guide multilingue (post-MVP)
Étant donné qu'un créateur peut publier plusieurs versions linguistiques
Quand un touriste anglophone visite le Louvre
Alors il voit les guides disponibles en anglais Et peut choisir parmi les guides traduits Mais cette fonctionnalité n'est pas disponible en MVP
25. Publicité entre séquences d'audio-guide
Étant donné que je suis un utilisateur gratuit Et que j'écoute un audio-guide
Quand je passe de la séquence 5 à la séquence 6
Alors une publicité peut être insérée (1 pub toutes les 5 séquences) Et la publicité est skippable après 5 secondes Et les utilisateurs Premium ne voient pas de publicité
26. Audio-guide en mode offline
Étant donné que j'ai téléchargé un audio-guide complet
Quand je visite le lieu sans connexion internet
Alors toutes les séquences sont disponibles hors ligne Et la navigation fonctionne normalement Et seule la sauvegarde cloud est différée jusqu'à reconnexion
27. Notation d'un audio-guide après écoute
Étant donné que j'ai terminé un audio-guide
Quand je ferme l'interface
Alors je vois une popup "Notez cette visite" Et je peux donner une note de 1 à 5 étoiles Et cette note contribue à la note globale visible par les autres utilisateurs
28. Filtrage par langue dans la page de sélection
Étant donné que plusieurs audio-guides sont disponibles en différentes langues
Quand j'accède à la page de sélection
Alors je peux filtrer par langue Et par défaut, les guides dans ma langue système sont affichés en premier
29. Réutilisation de l'infrastructure existante
Étant donné qu'un audio-guide est techniquement un contenu structuré
Alors il réutilise:
| composant | usage |
|---|---|
| Stockage Bunny | Hébergement fichiers MP3 séquences |
| Streaming HLS | Diffusion audio adaptative |
| Cache Redis | Métadonnées guides + progressions |
| PostgreSQL | Stockage structure JSON guides |
Et aucune infrastructure dédiée n'est nécessaire
Impact des abonnements sur l'algorithme
En tant qu'auditeur Je veux que les contenus de mes créateurs suivis soient favorisés Afin de ne pas rater leurs publications tout en découvrant de nouveaux contenus
16 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis connecté en tant qu'auditeur Et que je suis abonné au créateur "JeanDupont"
1. Boost de +30% appliqué au score final
Étant donné un contenu du créateur "JeanDupont" avec:
| score_geo | 0.5 |
|---|---|
| score_interet | 0.6 |
| score_engage | 0.5 |
Quand le score final est calculé
Alors le score de base est 0.53 Et le boost abonnement de +30% est appliqué Et le score final avec boost est 0.69
2. Contenu non-suivi peut battre contenu suivi
Étant donné que je suis à Paris Et que 2 contenus sont disponibles:
| contenu | createur_suivi | score_geo | score_interet | score_engage | score_final_base | score_avec_boost |
|---|---|---|---|---|---|---|
| Contenu A | Non | 0.9 | 0.8 | 0.7 | 0.80 | 0.80 |
| Contenu B | Oui | 0.5 | 0.6 | 0.5 | 0.53 | 0.69 |
Quand l'algorithme sélectionne le prochain contenu
Alors le Contenu A est proposé en premier
3. Contenu suivi remporte grâce au boost
Étant donné que je suis à Paris Et que 2 contenus sont disponibles:
| contenu | createur_suivi | score_final_base | score_avec_boost |
|---|---|---|---|
| Contenu A | Non | 0.70 | 0.70 |
| Contenu B | Oui | 0.60 | 0.78 |
Quand l'algorithme sélectionne le prochain contenu
Alors le Contenu B est proposé en premier
4. Contenu suivi avec faible engagement ne domine pas
Étant donné que je suis abonné au créateur "CreateurMoyen" Et qu'il publie un contenu avec très faible engagement (score 0.30) Et qu'un contenu viral d'un créateur non-suivi a un score de 0.85
Quand l'algorithme sélectionne le prochain contenu
Alors le contenu viral est proposé en premier (0.85)
5. Pas de file dédiée aux abonnements
Étant donné que je suis abonné à 50 créateurs
Quand l'algorithme génère ma file d'attente de 5 contenus
Alors les contenus suivis et non-suivis sont mélangés Et tous entrent en compétition selon leurs scores (avec boost si abonnement) Et il n'y a pas de section séparée "Contenus de vos abonnements"
6. Vérification du calcul du boost
Étant donné un contenu d'un créateur suivi Et que le score final de base est calculé à 0.65
Quand le boost abonnement est appliqué
Alors le multiplicateur utilisé est exactement 1.3 Et le score final avec boost est 0.845 (0.65 × 1.3) Et le résultat est arrondi à 2 décimales: 0.85
7. Boost appliqué à tous les contenus du créateur suivi
Étant donné que je suis abonné au créateur "JeanDupont" Et qu'il a publié 10 contenus différents
Quand l'algorithme évalue chacun de ces contenus
Alors le boost de +30% est appliqué à tous les 10 contenus Et chaque contenu bénéficie du même multiplicateur 1.3
8. Plusieurs créateurs suivis en compétition
Étant donné que je suis abonné à "Créateur A" et "Créateur B" Et que les 2 ont des contenus disponibles dans ma zone:
| createur | score_base | score_avec_boost |
|---|---|---|
| Créateur A | 0.70 | 0.91 |
| Créateur B | 0.65 | 0.85 |
Quand l'algorithme sélectionne le prochain contenu
Alors le contenu du Créateur A est proposé en premier (0.91 > 0.85) Et les 2 bénéficient du boost, mais le meilleur score gagne
9. Contenu national d'un créateur suivi
Étant donné que je suis abonné à "MediaNational" Et qu'il publie un contenu de type "National" (score_geo 0.2)
Quand le score est calculé avec:
| score_geo | score_interet | score_engage |
|---|---|---|
| 0.2 | 0.7 | 0.6 |
Alors le score de base est environ 0.50 Et avec le boost abonnement, le score devient 0.65 Et le contenu peut être proposé malgré son score géo faible
10. Transparence du boost dans les paramètres
Quand j'accède aux paramètres de l'algorithme de recommandation
Alors je vois l'information: "Les contenus de vos créateurs suivis bénéficient d'un boost de +30%" Et je comprends que ce n'est pas une priorité absolue Et que la découverte de nouveaux contenus reste possible
11. Boost désactivé si désabonnement
Étant donné que je suis abonné au créateur "JeanDupont" Et qu'un de ses contenus bénéficiait du boost +30%
Quand je me désabonne de "JeanDupont"
Alors ses contenus n'ont plus le boost Et leur score revient au score de base sans multiplicateur
12. Contenu d'un créateur nouvellement suivi
Étant donné que je viens de m'abonner à "NouveauCreateur" Et qu'il a publié un contenu il y a 2 jours
Quand l'algorithme recalcule les scores
Alors le boost de +30% est immédiatement appliqué à ce contenu Et il peut apparaître dans ma prochaine file d'attente
13. Impact sur le taux de contenu suivi dans le feed
Étant donné que je suis abonné à 30 créateurs Et que j'écoute 100 contenus sur une semaine
Quand j'analyse la répartition
Alors environ 40-50% des contenus proviennent de créateurs suivis Et 50-60% proviennent de créateurs non-suivis (découverte)
14. Contenu suivi hors zone géographique
Étant donné que je suis à Paris Et que je suis abonné à un créateur de Marseille Et qu'il publie un contenu ancré à Marseille (hors de portée)
Quand l'algorithme évalue ce contenu
Alors le score géo est quasi nul (0.05) Et même avec boost +30%, le score reste très faible Et le contenu n'est probablement pas proposé
15. Performance de calcul du boost
Étant donné que je suis abonné à 100 créateurs Et que l'algorithme évalue 1000 contenus potentiels
Quand le calcul des scores avec boost est effectué
Alors le temps de calcul reste inférieur à 50ms Et la requête SQL utilise un JOIN sur la table abonnements
16. Boost combiné avec d'autres facteurs
Étant donné un contenu d'un créateur suivi Et que le contenu bénéficie aussi de:
| facteur | impact |
|---|---|
| Score d'engagement élevé | +20% |
| Contenu récent (<24h) | +10% |
| Boost abonnement | +30% |
Quand le score final est calculé
Alors le boost abonnement s'applique au score final (après tous les autres calculs) Et les boosts ne s'additionnent pas, le boost abonnement est un multiplicateur final
Limites d'abonnements et désabonnement
En tant qu'auditeur Je veux gérer mes abonnements de manière équilibrée Afin de suivre mes créateurs préférés sans être submergé
27 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis connecté en tant qu'auditeur
1. Limite maximale de 200 abonnements
Étant donné que je suis abonné à 199 créateurs
Quand j'essaie de m'abonner à un 200ème créateur
Alors l'abonnement réussit Et je suis maintenant abonné à 200 créateurs
2. Impossible de dépasser 200 abonnements
Étant donné que je suis déjà abonné à 200 créateurs
Quand j'essaie de m'abonner à un nouveau créateur
Alors l'action échoue Et je vois le message:
3. Suggestion de désabonnement de créateurs inactifs
Étant donné que je suis abonné à 200 créateurs Et que j'essaie de m'abonner à un nouveau créateur
Quand je vois le message de limite atteinte
Alors je vois aussi une suggestion: Et un bouton "Désabonner" est proposé pour ce créateur
4. Liste triable des abonnements
Étant donné que je suis abonné à 150 créateurs
Quand j'accède à ma liste d'abonnements
Alors je peux trier par:
| critère | ordre |
|---|---|
| Date d'abonnement | Plus récent / Plus ancien |
| Nombre de contenus écoutés | Plus écoutés / Moins écoutés |
| Dernière activité créateur | Plus récent / Plus ancien |
| Ordre alphabétique | A-Z / Z-A |
5. Abonnement initial augmente les jauges de +5%
Étant donné que mes jauges d'intérêt sont:
| catégorie | valeur initiale |
|---|---|
| Automobile | 60% |
| Voyage | 55% |
Et qu'un créateur tague ses contenus "Automobile" et "Voyage"
Quand je m'abonne à ce créateur
Alors mes jauges évoluent:
| catégorie | nouvelle valeur |
|---|---|
| Automobile | 65% (+5%) |
| Voyage | 60% (+5%) |
6. Abonnement avec créateur ayant 3 tags
Étant donné qu'un créateur tague ses contenus:
| tags |
|---|
| Automobile, Voyage, Technologie |
Et que mes jauges sont toutes à 50%
Quand je m'abonne à ce créateur
Alors les 3 jauges augmentent de +5%:
| catégorie | nouvelle valeur |
|---|---|
| Automobile | 55% |
| Voyage | 55% |
| Technologie | 55% |
7. Désabonnement diminue les jauges de -5%
Étant donné que je suis abonné à un créateur avec tags "Politique" et "Économie" Et que mes jauges sont:
| catégorie | valeur actuelle |
|---|---|
| Politique | 70% |
| Économie | 65% |
Quand je me désabonne de ce créateur
Alors mes jauges évoluent:
| catégorie | nouvelle valeur |
|---|---|
| Politique | 65% (-5%) |
| Économie | 60% (-5%) |
8. Désabonnement sans confirmation
Étant donné que je consulte le profil d'un créateur suivi
Quand je clique sur "Se désabonner"
Alors le désabonnement est immédiat Et aucune popup de confirmation n'apparaît
9. Réabonnement possible immédiatement
Étant donné que je viens de me désabonner d'un créateur
Quand je consulte à nouveau son profil
Alors le bouton "S'abonner" est affiché Et je peux me réabonner immédiatement Et mes jauges augmentent à nouveau de +5%
10. Effet symétrique abonnement/désabonnement
Étant donné qu'un créateur a les tags "Musique" et "Culture" Et que ma jauge Musique est à 50%
Quand je m'abonne puis me désabonne immédiatement
Alors ma jauge revient exactement à 50% Et il n'y a pas de perte ou gain net
11. Abonnement ne dépasse pas 100% de jauge
Étant donné que ma jauge Automobile est à 97% Et qu'un créateur tague ses contenus "Automobile"
Quand je m'abonne à ce créateur
Alors ma jauge Automobile passe à 100% (limite max) Et l'augmentation effective est de +3% seulement
12. Désabonnement ne descend pas sous 0%
Étant donné que ma jauge Politique est à 3% Et que je suis abonné à un créateur avec tag "Politique"
Quand je me désabonne de ce créateur
Alors ma jauge Politique passe à 0% (limite min) Et la diminution effective est de -3% seulement
13. Créateur ne voit pas qui est abonné (privacy)
Étant donné que je suis abonné au créateur "JeanDupont"
Quand "JeanDupont" consulte ses statistiques
Alors il voit le nombre total d'abonnés (ex: "1,247 abonnés") Mais il ne voit pas la liste des utilisateurs abonnés Et mon identité reste privée
14. Créateur voit uniquement le nombre total d'abonnés
Étant donné que je suis créateur Et que j'ai 523 abonnés
Quand je consulte mes statistiques
Alors je vois "523 abonnés" Mais je ne peux pas:
| action interdite |
|---|
| Voir la liste des abonnés |
| Contacter mes abonnés individuellement |
| Voir leurs profils |
15. Pas d'abonnement mutuel visible
Étant donné que je suis abonné au créateur "Alice" Et qu'"Alice" est abonnée à mon compte créateur
Quand je consulte le profil d'"Alice"
Alors je ne vois pas d'indication qu'elle est abonnée à moi Et il n'y a pas de badge "Abonné mutuellement"
16. Performance avec 200 abonnements
Étant donné que je suis abonné à 200 créateurs
Quand l'algorithme calcule ma recommandation
Alors la requête SQL utilise un JOIN sur la table abonnements Et la table est indexée sur user_id et creator_id Et le temps de calcul reste inférieur à 50ms
17. Impact sur la recommandation avec beaucoup d'abonnements
Étant donné que je suis abonné à 150 créateurs très actifs Et qu'ils publient collectivement 100 contenus par jour
Quand l'algorithme génère ma file de 5 contenus
Alors environ 60-70% des contenus proviennent de créateurs suivis (grâce au boost +30%) Mais 30-40% proviennent de nouveaux créateurs (découverte)
18. Notification de désabonnement au créateur (non implémenté)
Étant donné que je me désabonne d'un créateur
Alors le créateur ne reçoit aucune notification Et il ne peut pas savoir qui s'est désabonné
19. Statistiques d'abonnements pour l'utilisateur
Étant donné que je suis abonné à 87 créateurs
Quand j'accède à mes statistiques d'abonnements
Alors je vois:
| métrique | exemple valeur |
|---|---|
| Nombre total d'abonnements | 87 / 200 |
| Créateurs les plus écoutés | Top 10 avec % écoute |
| Créateurs non écoutés depuis 6 mois | 12 créateurs |
| Nouveaux contenus non écoutés | 23 contenus |
20. Recherche dans la liste d'abonnements
Étant donné que je suis abonné à 120 créateurs
Quand j'accède à ma liste d'abonnements
Alors je peux chercher par nom de créateur Et les résultats sont filtrés en temps réel Et je trouve rapidement un créateur spécifique
21. Export de la liste d'abonnements (RGPD)
Étant donné que je demande l'export de mes données
Quand l'export est généré
Alors la liste de mes abonnements est incluse:
22. Suppression compte utilisateur et impact sur abonnements
Étant donné que je suis abonné à 50 créateurs
Quand je supprime définitivement mon compte
Alors tous mes abonnements sont supprimés Et le compteur d'abonnés de chaque créateur est décrémenté de -1 Et les jauges n'existent plus (données supprimées)
23. Suppression compte créateur et impact sur abonnés
Étant donné que je suis abonné au créateur "Bob"
Quand "Bob" supprime son compte créateur
Alors je suis automatiquement désabonné Et mes jauges diminuent de -5% pour les tags de "Bob" Et je ne vois plus "Bob" dans ma liste d'abonnements
24. Limite 200 justifiée par usage réaliste
Étant donné que la moyenne d'abonnements sur YouTube est de ~50-100 chaînes Et que Twitter limite à 5000 follows (mais moyenne ~150)
Quand RoadWave fixe la limite à 200
Alors cela couvre largement 99% des utilisateurs Et évite les abus (comptes spam suivant tout le monde)
25. Table PostgreSQL optimisée pour abonnements
Étant donné la structure de table subscriptions:
Alors les requêtes d'abonnements sont O(1) avec index Et le count d'abonnés par créateur est rapide Et la vérification "est abonné ?" est instantanée
26. Détection d'abonnements abusifs
Étant donné qu'un utilisateur s'abonne à 200 créateurs en moins de 5 minutes
Quand le système détecte cette activité suspecte
Alors un rate limiting est appliqué (max 10 abonnements/minute) Et l'utilisateur voit "Trop d'actions rapides. Veuillez réessayer dans 1 minute" Et cela prévient les bots de spam
27. Badge créateur vérifié visible dans abonnements
Étant donné que je suis abonné à 3 créateurs dont 1 vérifié
Quand je consulte ma liste d'abonnements
Alors le créateur vérifié a un badge ✓ bleu Et les créateurs non vérifiés n'ont pas de badge
Notifications contextuelles selon le mode de déplacement
En tant qu'auditeur Je veux recevoir des notifications adaptées à mon contexte Afin d'être informé sans être distrait en conduisant
28 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis connecté en tant qu'auditeur Et que j'ai activé les notifications
1. Détection automatique du contexte en voiture
Étant donné que ma vitesse GPS est de 50 km/h
Quand le système détecte mon contexte
Alors je suis identifié comme "En voiture" Et les notifications push sont désactivées Et seules les notifications in-app sont actives
2. Détection automatique du contexte à pied
Étant donné que ma vitesse GPS est de 3 km/h
Quand le système détecte mon contexte
Alors je suis identifié comme "À pied" Et les notifications push sont activées Et l'interface tactile et vocale sont disponibles
3. Zone de transition 5-10 km/h
Étant donné que ma vitesse GPS varie entre 5 et 10 km/h
Quand le système détecte mon contexte
Alors un algorithme de lissage est appliqué sur 30 secondes Et le mode est déterminé selon la vitesse moyenne Et les changements de mode ne sont pas trop fréquents
4. Nouveau contenu créateur suivi - Mode voiture
Étant donné que je suis en voiture (vitesse >10 km/h) Et que je suis abonné au créateur "JeanDupont"
Quand "JeanDupont" publie un nouveau contenu dans ma zone
Alors je ne reçois pas de notification push Mais je vois un badge compteur in-app Et le contenu apparaît dans ma file avec boost +30%
5. Nouveau contenu créateur suivi - Mode piéton
Étant donné que je suis à pied (vitesse <5 km/h) Et que je suis abonné au créateur "JeanDupont" Et que je suis situé en Île-de-France
Quand "JeanDupont" publie un contenu géolocalisé en Île-de-France
Alors je reçois une notification push:
6. Live créateur suivi - Mode voiture
Étant donné que je suis en voiture Et que je suis abonné au créateur "RadioLive"
Quand "RadioLive" démarre un live dans ma zone
Alors je ne reçois pas de notification push Mais je vois un badge compteur in-app Et le live peut apparaître dans ma recommandation automatiquement
7. Live créateur suivi - Mode piéton
Étant donné que je suis à pied Et que je suis abonné au créateur "RadioLive" Et que je suis situé dans la zone du live
Quand "RadioLive" démarre un live
Alors je reçois une notification push:
8. Audio-guide disponible à proximité - Mode piéton
Étant donné que je suis à pied
Quand je passe à moins de 100m d'un lieu avec audio-guides
Alors je reçois une notification push:
9. Audio-guide disponible à proximité - Mode voiture
Étant donné que je suis en voiture
Quand je passe à moins de 100m d'un lieu avec audio-guides
Alors je reçois une notification audio (bip) Et une annonce vocale: "Audio-guide disponible" Mais pas de notification push (sécurité)
10. Filtrage géographique des notifications
Étant donné que je suis abonné au créateur "CreateurMarseille" Et que je suis situé à Paris
Quand "CreateurMarseille" publie un contenu ancré à Marseille
Alors je ne reçois pas de notification Et cela évite la frustration de contenus non écoutables
11. Contenu national notifie tous les abonnés
Étant donné que je suis abonné au créateur "MediaNational" Et que je suis situé n'importe où en France
Quand "MediaNational" publie un contenu de type "National"
Alors je reçois une notification (si mode piéton)
12. Limite de 10 notifications push par jour
Étant donné que je suis abonné à 50 créateurs actifs Et que j'ai déjà reçu 10 notifications push aujourd'hui
Quand un 11ème contenu est publié
Alors je ne reçois pas de notification push individuelle Mais une notification groupée: "🎧 3 nouveaux contenus de créateurs suivis"
13. Paramétrage de la limite quotidienne
Étant donné que la limite par défaut est de 10 notifications/jour
Quand j'accède aux paramètres de notifications
Alors je peux modifier la limite entre 5 et 20 Et si je choisis 15, je recevrai jusqu'à 15 notifications/jour
14. Mode silencieux nocturne par défaut
Étant donné que le mode silencieux est activé de 22h à 8h par défaut Et qu'il est 23h30
Quand un créateur suivi publie un contenu
Alors je ne reçois pas de notification push Mais les notifications sont empilées Et je les vois le lendemain matin à 8h01
15. Exception du mode silencieux pour les lives
Étant donné que le mode silencieux est activé (22h-8h) Et qu'il est 23h00 Et que j'ai activé "Notifications importantes uniquement" (lives uniquement)
Quand un créateur suivi démarre un live
Alors je reçois quand même la notification push du live
16. Désactivation complète des notifications
Étant donné que j'accède aux paramètres de notifications
Quand je désactive toutes les notifications
Alors je ne reçois plus aucune notification push Et les badges in-app sont également désactivés Et seule la recommandation algorithmique reste active
17. Notification "Nouveaux contenus" activée par défaut
Étant donné que je crée un nouveau compte Et que je m'abonne à mon premier créateur
Quand je consulte les préférences de notifications
Alors "Nouveaux contenus" est activé par défaut Et "Lives" est activé par défaut Et "Audio-guides proximité" est activé par défaut
18. Désactivation sélective par type de notification
Étant donné que j'ai activé toutes les notifications
Quand je désactive uniquement "Nouveaux contenus"
Alors je ne reçois plus de notifications pour nouveaux contenus Mais je reçois toujours les notifications de lives Et les notifications d'audio-guides restent actives
19. Notification groupée après limite dépassée
Étant donné que j'ai reçu 10 notifications push aujourd'hui Et que 5 nouveaux contenus sont publiés dans l'heure suivante
Quand la 11ème notification devrait être envoyée
Alors les 5 contenus sont regroupés en une seule notification:
20. Détail de la notification groupée
Étant donné que j'ai reçu une notification groupée "3 nouveaux contenus"
Quand je tape sur la notification
Alors l'app s'ouvre sur une liste des 3 contenus:
| créateur | titre |
|---|---|
| JeanDupont | "Actualité du jour" |
| MarieDurand | "Podcast économie" |
| PaulMartin | "Anecdote historique" |
Et je peux choisir lequel écouter en premier
21. Personnalisation des plages horaires du mode silencieux
Étant donné que le mode silencieux est 22h-8h par défaut
Quand j'accède aux paramètres
Alors je peux modifier les heures: par exemple 23h-7h Et le mode silencieux s'applique dans la nouvelle plage horaire
22. Format notification nouveau contenu complet
Étant donné que je suis à pied Et qu'un créateur suivi publie un contenu
Quand je reçois la notification push
Alors elle contient:
| élément | exemple |
|---|---|
| Emoji | 🎧 |
| Créateur | JeanDupont |
| Action | a publié |
| Titre | "Les secrets du Louvre" |
| CTA | Tap pour écouter |
23. Format notification live complet
Étant donné que je suis à pied Et qu'un créateur suivi démarre un live
Quand je reçois la notification push
Alors elle contient:
| élément | exemple |
|---|---|
| Emoji | 🔴 |
| Créateur | RadioLive |
| Action | est en direct |
| Titre | "Débat politique ce soir" |
| CTA | Tap pour rejoindre |
24. Notification disparaît si contenu supprimé
Étant donné que j'ai reçu une notification pour un contenu Et que je n'ai pas encore tapé dessus
Quand le créateur supprime le contenu
Alors la notification est automatiquement retirée de mon centre de notifications Et si je tape dessus par erreur, je vois "Contenu non disponible"
25. Badge compteur in-app en mode voiture
Étant donné que je suis en voiture Et que 5 créateurs suivis publient des contenus
Quand j'ouvre l'application
Alors je vois un badge "5" sur l'onglet "Nouveautés" Et en consultant l'onglet, je vois les 5 nouveaux contenus Et le badge disparaît après consultation
26. Coût des notifications push Firebase
Étant donné que je reçois 10 notifications push par jour Et que je suis actif 365 jours par an
Quand le système calcule le coût
Alors 3650 notifications/an sont envoyées Et Firebase Cloud Messaging est gratuit jusqu'à plusieurs millions de notifications Et le coût reste 0€ pour le volume MVP/Growth
27. Deep link depuis notification push
Étant donné que je reçois une notification push pour un contenu
Quand je tape sur la notification
Alors l'app s'ouvre directement sur le contenu Et la lecture démarre automatiquement (si j'étais à pied)
28. Notification refusée si permissions désactivées au niveau OS
Étant donné que j'ai désactivé les notifications dans les paramètres iOS/Android
Quand un créateur suivi publie un contenu
Alors aucune notification push n'est envoyée Et l'app propose de réactiver les permissions dans les paramètres Mais les badges in-app continuent de fonctionner
Création d'audio-guide multi-séquences
En tant que créateur de contenu Je veux créer des audio-guides avec plusieurs séquences géolocalisées Afin d'offrir des expériences guidées adaptées aux différents modes de déplacement
35 scénarios (32 standards, 3 plans)
Contexte commun à tous les scénarios
Étant donné que l'application RoadWave est démarrée Et que le créateur "guide@example.com" est connecté Et que son compte est vérifié
1. 📋 Plan: Détection automatique du mode selon la vitesse
Étant donné que l'utilisateur se déplace à km/h
Quand la vitesse est calculée sur 30 secondes
Alors le mode est suggéré automatiquement
📊 Exemples de données:
| vitesse | mode |
|---|---|
| 3 | Piéton |
| 15 | Vélo |
| 35 | Voiture |
| 50 | Voiture |
2. Suggestion de mode au démarrage avec confirmation
Étant donné qu'un audio-guide "Safari du Paugre" est disponible Et que l'utilisateur se déplace à 35 km/h
Quand l'audio-guide démarre
Alors une popup s'affiche:
3. Changement manuel du mode détecté
Étant donné que le mode "Voiture" est suggéré automatiquement
Quand l'utilisateur clique sur "Changer"
Alors les 4 modes sont proposés:
| mode | emoji |
|---|---|
| Piéton | 🚶 |
| Voiture | 🚗 |
| Vélo | 🚴 |
| Transport | 🚌 |
4. 📋 Plan: Caractéristiques par mode de déplacement
Étant donné un audio-guide configuré en mode
Alors les paramètres suivants sont appliqués:
| paramètre | valeur |
|---|---|
| Vitesse détection | <vitesse_detection> |
| Déclenchement | <declenchement> |
📊 Exemples de données:
| mode | vitesse_detection | declenchement |
|---|---|---|
| Piéton | <5 km/h | Manuel (bouton Suivant) |
| Voiture | >10 km/h | Auto GPS + Manuel |
| Vélo | 5-25 km/h | Auto GPS + Manuel |
| Transport | Variable | Auto GPS + Manuel |
5. Accès au formulaire de création d'audio-guide
Étant donné que le créateur est sur son dashboard
Quand il clique sur "Créer un audio-guide"
Alors le formulaire de création s'affiche Et le wizard guidé en 4 étapes est visible:
| étape | description |
|---|---|
| 1 | Infos générales |
| 2 | Ajout séquences |
| 3 | Preview carte |
| 4 | Validation modération |
6. Étape 1 - Informations générales obligatoires
Étant donné que le créateur est sur l'étape 1 du wizard
Quand il complète le formulaire
Alors les champs suivants sont obligatoires:
| champ | contrainte |
|---|---|
| Titre | 5-100 caractères |
| Description | 10-500 caractères |
| Mode de déplacement | Choix parmi 4 |
| Tags | 1-3 tags |
| Classification âge | Tout public/13+/16+/18+ |
7. Sélection du mode de déplacement
Étant donné que le créateur crée un audio-guide
Quand il sélectionne le mode "🚗 Voiture (GPS auto + manuel)"
Alors le champ "Vitesse recommandée" s'affiche Et la plage suggérée est "30-50 km/h"
8. Validation du titre
Étant donné que le créateur entre un titre
Quand le titre contient moins de 5 caractères
Alors un message d'erreur "Minimum 5 caractères" s'affiche Et le bouton "Suivant" est désactivé
9. Validation de la description
Étant donné que le créateur entre une description
Quand la description contient 520 caractères
Alors un message d'erreur "Maximum 500 caractères" s'affiche Et les 20 caractères en trop sont surlignés en rouge
10. Étape 2 - Ajout de la première séquence
Étant donné que le créateur est sur l'étape 2 "Ajout séquences"
Quand il clique sur "Ajouter séquence"
Alors le formulaire de séquence s'affiche avec:
| champ | requis | note |
|---|---|---|
| Titre séquence | ✅ | 5-80 caractères |
| Audio | ✅ | Upload MP3/AAC, max 200 MB |
| Point GPS | ✅* | *Sauf mode piéton |
| Rayon déclenchement | ✅* | *Sauf mode piéton, 10-200m |
11. Ajout du point GPS pour une séquence
Étant donné que le créateur ajoute une séquence en mode "Voiture"
Quand il clique sur "📍 Ajouter point GPS"
Alors une carte s'affiche Et il peut:
| action |
|---|
| Cliquer sur la carte |
| Entrer coordonnées manuelles |
| Utiliser sa position actuelle |
12. Configuration du rayon de déclenchement avec preview
Étant donné qu'un point GPS est défini à (43.1234, 2.5678)
Quand le créateur ajuste le curseur de rayon
Alors le rayon varie de 10m à 200m Et un cercle visuel est affiché sur la carte Et la valeur actuelle s'affiche "30m"
13. 📋 Plan: Rayon par défaut selon le mode
Étant donné un audio-guide en mode
Quand le créateur ajoute un point GPS
Alors le rayon par défaut est <rayon_defaut>
📊 Exemples de données:
| mode | rayon_defaut |
|---|---|
| Voiture | 30m |
| Vélo | 50m |
| Transport | 100m |
14. Suggestion intelligente du rayon
Étant donné un audio-guide en mode "Voiture" avec vitesse recommandée 30 km/h
Quand le créateur ajoute un point GPS
Alors une suggestion s'affiche: "Recommandé : 30m pour voiture à 30 km/h"
15. Upload audio pour une séquence
Étant donné que le créateur crée une séquence "Introduction"
Quand il upload un fichier audio de 5 MB
Alors le fichier est vérifié:
| vérification | règle |
|---|---|
| Format | MP3, AAC, M4A |
| Taille max | 200 MB |
| Durée max | 15 minutes |
16. Ordre des séquences modifiable
Étant donné un audio-guide avec 5 séquences:
| ordre | titre |
|---|---|
| 1 | Introduction |
| 2 | Les lions |
| 3 | Les girafes |
| 4 | Les éléphants |
| 5 | Conclusion |
Quand le créateur glisse "Les éléphants" en position 2
Alors l'ordre devient:
| ordre | titre |
|---|---|
| 1 | Introduction |
| 2 | Les éléphants |
| 3 | Les lions |
| 4 | Les girafes |
| 5 | Conclusion |
17. Nombre minimum de séquences requis
Étant donné un audio-guide avec seulement 1 séquence
Quand le créateur tente de passer à l'étape suivante
Alors un message d'erreur s'affiche: "Minimum 2 séquences requis" Et le bouton "Suivant" est désactivé
18. Nombre maximum de séquences
Étant donné un audio-guide avec 50 séquences
Quand le créateur tente d'ajouter une 51ème séquence
Alors un message d'erreur s'affiche: "Maximum 50 séquences par audio-guide" Et le bouton "+ Ajouter séquence" est désactivé
19. Étape 3 - Preview carte avec tracé et points
Étant donné un audio-guide avec 5 séquences géolocalisées
Quand le créateur accède à l'étape 3 "Preview carte"
Alors une carte Leaflet s'affiche Et les éléments suivants sont visibles:
| élément | description |
|---|---|
| Markers numérotés | 1, 2, 3, 4, 5 sur chaque point |
| Tracé entre points | Ligne pointillée connectant les points |
| Cercles de déclenchement | Rayon visuel autour de chaque point |
20. Statistiques du parcours
Étant donné un audio-guide avec les séquences suivantes:
| séquence | durée | distance_au_suivant |
|---|---|---|
| 1 | 2:15 | 150m |
| 2 | 3:42 | 200m |
| 3 | 4:10 | 320m |
Quand les statistiques sont calculées
Alors le résumé suivant est affiché:
| métrique | valeur |
|---|---|
| Séquences | 3 complètes |
| Durée totale | 10:07 |
| Distance totale | 670m |
21. Modification d'une séquence depuis la carte
Étant donné que la preview carte est affichée
Quand le créateur clique sur le marker "2"
Alors une popup s'affiche avec:
| information |
|---|
| Titre: "Les lions" |
| Durée: 3:42 |
| Rayon: 30m |
| [✏️ Modifier] |
| [🗑️ Supprimer] |
22. Zone de diffusion géographique
Étant donné un audio-guide avec des points dans Paris
Quand le créateur définit la zone de diffusion
Alors il peut choisir:
| type | exemple |
|---|---|
| Polygon | Tracé manuel sur carte |
| Ville | Paris (API Nominatim) |
| Département | 75 - Paris |
| Région | Île-de-France |
23. Étape 4 - Publication et validation modération
Étant donné un créateur qui publie ses 3 premiers audio-guides
Quand il clique sur "✅ Publier audio-guide"
Alors un message s'affiche:
24. Publication directe pour créateurs expérimentés
Étant donné un créateur ayant publié 5 audio-guides validés Et aucun strike actif
Quand il publie un nouvel audio-guide
Alors l'audio-guide est publié immédiatement Et il devient visible pour les utilisateurs Et aucune validation manuelle n'est requise
25. Mode piéton sans points GPS obligatoires
Étant donné un audio-guide en mode "🚶 Piéton"
Quand le créateur ajoute une séquence
Alors le champ "Point GPS" est optionnel Et le champ "Rayon déclenchement" est masqué Et un message info s'affiche: "Mode manuel : les séquences se déclenchent au clic utilisateur"
26. Sauvegarde brouillon automatique
Étant donné que le créateur édite un audio-guide depuis 5 minutes
Quand il ajoute une nouvelle séquence
Alors l'audio-guide est sauvegardé en brouillon automatiquement Et un toast "Brouillon sauvegardé" s'affiche brièvement
27. Reprise d'un brouillon
Étant donné un audio-guide en brouillon "Safari du Paugre" Et qu'il contient 3 séquences complètes
Quand le créateur retourne sur son dashboard
Alors le brouillon est visible avec le statut "📝 Brouillon" Et un bouton "Continuer" est disponible Et la progression "3/5 séquences" est affichée
28. Suppression d'un brouillon
Étant donné un audio-guide en brouillon
Quand le créateur clique sur "🗑️ Supprimer"
Alors une confirmation s'affiche:
29. Modification d'un audio-guide publié
Étant donné un audio-guide publié "Safari du Paugre"
Quand le créateur clique sur "✏️ Modifier"
Alors il peut modifier:
| élément modifiable | élément non modifiable |
|---|---|
| Titre | Mode de déplacement |
| Description | Points GPS |
| Tags | Rayons déclenchement |
| Séquences (ordre) | |
Et un avertissement s'affiche: "Les modifications structurelles nécessitent une nouvelle publication"
30. Duplication d'un audio-guide existant
Étant donné un audio-guide publié "Visite Paris"
Quand le créateur clique sur "📋 Dupliquer"
Alors une copie est créée avec le titre "Visite Paris (copie)" Et toutes les séquences sont copiées Et le statut est "📝 Brouillon" Et le créateur peut modifier avant publication
31. Upload audio échoue (format non supporté)
Étant donné que le créateur upload un fichier "audio.wav"
Quand le format est vérifié
Alors un message d'erreur s'affiche: "Format non supporté. Utilisez MP3, AAC ou M4A" Et le fichier est rejeté
32. Upload audio échoue (taille trop grande)
Étant donné que le créateur upload un fichier de 250 MB
Quand la taille est vérifiée
Alors un message d'erreur s'affiche: "Fichier trop volumineux. Maximum 200 MB" Et le fichier est rejeté
33. Points GPS trop éloignés (alerte cohérence)
Étant donné un audio-guide en mode "Piéton" Et une séquence au Louvre (Paris)
Quand le créateur ajoute une séquence à Lyon
Alors un avertissement s'affiche:
34. Pas de connexion lors de la sauvegarde
Étant donné que le créateur édite un audio-guide Et que la connexion réseau est perdue
Quand il tente de sauvegarder
Alors le brouillon est sauvegardé localement Et un message s'affiche: "Sauvegarde locale. Sera synchronisée à la reconnexion" Et une icône "☁️ Hors ligne" s'affiche
35. Reprise après perte de connexion
Étant donné un brouillon sauvegardé localement
Quand la connexion réseau est rétablie
Alors le brouillon est synchronisé automatiquement Et un toast "✅ Audio-guide synchronisé" s'affiche
Intégration audio-guides avec autres fonctionnalités
En tant qu'utilisateur Je veux utiliser les audio-guides avec toutes les fonctionnalités de l'app Afin d'avoir une expérience complète et cohérente
39 scénarios (38 standards, 1 plan)
Contexte commun à tous les scénarios
Étant donné que l'application RoadWave est démarrée Et que l'utilisateur "jean@example.com" est connecté
1. Téléchargement complet d'un audio-guide
Étant donné un audio-guide "Visite du Louvre" avec 12 séquences
Quand l'utilisateur clique sur "⬇️ Télécharger pour écouter hors ligne"
Alors toutes les 12 séquences sont téléchargées Et les métadonnées (titres, descriptions, GPS) sont sauvegardées Et les images (cover, miniatures) sont mises en cache
2. Affichage de la progression du téléchargement
Étant donné qu'un téléchargement d'audio-guide est en cours
Quand l'utilisateur consulte l'état
Alors la progression s'affiche:
3. Téléchargement uniquement en WiFi (par défaut)
Étant donné que l'option "Télécharger uniquement en WiFi" est activée
Quand l'utilisateur lance un téléchargement sur réseau mobile
Alors un avertissement s'affiche:
4. Gestion de l'espace de stockage
Étant donné que l'appareil a 500 MB d'espace libre Et qu'un audio-guide pèse 380 MB
Quand l'utilisateur lance le téléchargement
Alors un avertissement s'affiche:
5. Liste des audio-guides téléchargés
Étant donné que l'utilisateur a téléchargé 3 audio-guides
Quand il accède à "Bibliothèque > Téléchargés"
Alors il voit:
| audio_guide | taille | date_telechargement |
|---|---|---|
| Visite du Louvre | 380 MB | 2026-01-20 |
| Safari du Paugre | 245 MB | 2026-01-18 |
| Circuit Loire à Vélo | 520 MB | 2026-01-15 |
6. Lecture hors connexion complète
Étant donné qu'un audio-guide est téléchargé Et que l'utilisateur active le mode avion
Quand il lance l'audio-guide
Alors toutes les séquences sont lisibles Et les métadonnées sont accessibles Et les images s'affichent normalement Et la progression est sauvegardée localement
7. GPS fonctionne en mode avion (mode voiture)
Étant donné qu'un audio-guide voiture est téléchargé Et que le mode avion est activé (avec GPS actif)
Quand l'utilisateur se déplace
Alors les déclenchements GPS fonctionnent normalement Et la distance/ETA sont calculés
8. Suppression d'audio-guide téléchargé
Étant donné qu'un audio-guide téléchargé pèse 380 MB
Quand l'utilisateur clique sur "🗑️ Supprimer téléchargement"
Alors une confirmation s'affiche Et si confirmé, les 380 MB sont libérés Et l'audio-guide reste accessible en streaming
9. Mise à jour automatique si nouvelle version
Étant donné qu'un audio-guide téléchargé a été mis à jour par le créateur
Quand l'utilisateur se connecte en WiFi
Alors une notification s'affiche:
10. Ajout d'audio-guide à une playlist
Étant donné que l'utilisateur consulte un audio-guide
Quand il clique sur "➕ Ajouter à une playlist"
Alors ses playlists s'affichent:
| playlist |
|---|
| 🗺️ Voyages en France |
| 🏛️ Musées parisiens |
| + Créer nouvelle playlist |
11. Comportement audio-guide dans une playlist
Étant donné une playlist contenant 2 audio-guides et 1 podcast
Quand la lecture atteint un audio-guide
Alors l'audio-guide démarre à la séquence 1 (ou progression sauvegardée) Et les séquences se jouent normalement
Quand l'audio-guide se termine (dernière séquence)
Alors le contenu suivant de la playlist démarre
12. Audio-guide marqué comme "Favori"
Étant donné qu'un utilisateur aime un audio-guide
Quand il clique sur "⭐ Ajouter aux favoris"
Alors l'audio-guide est ajouté à la section "Favoris" Et il est facilement accessible depuis le menu principal
13. Collections thématiques d'audio-guides
Étant donné que RoadWave propose des collections éditoriales
Quand l'utilisateur accède à "Collections"
Alors il voit des collections comme:
| collection | nombre_audio_guides |
|---|---|
| 🏛️ Musées de France | 12 |
| 🦁 Parcs animaliers | 8 |
| 🚴 Circuits vélo | 15 |
| 🚗 Routes touristiques | 10 |
14. Bouton partager sur page audio-guide
Étant donné qu'un utilisateur consulte un audio-guide
Quand il clique sur "⬆️ Partager"
Alors le menu de partage natif s'ouvre Et le lien généré est "https://roadwave.fr/share/ag/louvre_123"
15. Page web de partage pour audio-guide
Étant donné qu'un lien d'audio-guide partagé est ouvert sur le web
Quand la page se charge
Alors elle affiche:
| élément | exemple |
|---|---|
| Cover image 16:9 | Photo du Louvre |
| Titre | "Visite du Louvre" |
| Créateur | "@art_guide ✓" |
| Badge type | "🎧 Audio-guide • 12 séquences" |
| Durée totale | "45 minutes" |
| Mode | "🚶 Piéton" |
| Description | Texte complet |
| Preview séquence 1 | Player HTML5 (séquence intro) |
| Carte avec points GPS | Leaflet avec 12 markers |
| CTA téléchargement | Boutons App Store / Google Play |
16. Deep link vers audio-guide spécifique
Étant donné que l'app est installée Et qu'un lien "https://roadwave.fr/share/ag/louvre_123" est cliqué
Quand le système détecte l'app
Alors l'app s'ouvre directement sur l'audio-guide Et l'utilisateur peut démarrer immédiatement
17. Partage avec séquence spécifique
Étant donné qu'un utilisateur est sur la séquence 5 "La Joconde"
Quand il partage l'audio-guide
Alors le lien généré est "https://roadwave.fr/share/ag/louvre_123?seq=5" Et le destinataire est dirigé vers la séquence 5 directement
18. Note globale de l'audio-guide
Étant donné qu'un utilisateur termine un audio-guide
Quand la dernière séquence se termine
Alors une popup de notation s'affiche:
19. Note moyenne affichée sur la page
Étant donné qu'un audio-guide a reçu 150 notes Et que la moyenne est 4.3/5
Quand la page est affichée
Alors la note "⭐ 4.3 (150 avis)" est visible
20. Commentaires triés par pertinence
Étant donné qu'un audio-guide a 50 commentaires
Quand l'utilisateur consulte les avis
Alors les commentaires sont triés par défaut selon:
| critère | poids |
|---|---|
| Note élevée | 30% |
| Récent | 30% |
| Likes reçus | 40% |
21. Réponse du créateur aux commentaires
Étant donné qu'un utilisateur laisse un commentaire négatif
Quand le créateur consulte son dashboard
Alors il peut répondre au commentaire Et sa réponse apparaît en dessous avec badge "Créateur"
22. Audio-guides similaires recommandés
Étant donné qu'un utilisateur termine "Visite du Louvre"
Quand il consulte les recommandations
Alors l'algorithme suggère des audio-guides basés sur:
| critère | exemple |
|---|---|
| Tags similaires | #Art #Histoire #Musée |
| Créateur identique | Autres audio-guides de @art_guide |
| Localisation proche | Autres musées parisiens |
| Mode de déplacement | Autres audio-guides piéton |
23. Suggestion géographique contextuelle
Étant donné qu'un utilisateur est à Paris (GPS détecté)
Quand il ouvre l'onglet "Audio-guides"
Alors les audio-guides parisiens sont mis en avant Et un filtre "🗺️ Autour de moi" est pré-appliqué
24. Badge "Populaire dans votre région"
Étant donné qu'un audio-guide a >100 écoutes dans la région Île-de-France Et que l'utilisateur est en Île-de-France
Quand l'audio-guide est affiché
Alors un badge "🔥 Populaire près de chez vous" est visible
25. Préchargement de la séquence suivante
Étant donné que la séquence 3 est en cours à 2:30/3:42
Quand il reste 60 secondes de lecture
Alors la séquence 4 est préchargée en arrière-plan Et la transition est instantanée (0 latence)
26. Buffer adaptatif selon connexion
Étant donné qu'un utilisateur est sur réseau 4G
Quand la séquence démarre
Alors 30 secondes d'audio sont bufferisées initialement Et le buffering continue en arrière-plan
27. 📋 Plan: Buffer selon qualité réseau
Étant donné qu'un utilisateur est sur réseau
Quand une séquence démarre
Alors <buffer_secondes> secondes sont bufferisées
📊 Exemples de données:
| reseau | buffer_secondes |
|---|---|
| WiFi | 60 |
| 5G | 45 |
| 4G | 30 |
| 3G | 20 |
28. Compression audio adaptative
Étant donné qu'un utilisateur est sur connexion lente (3G)
Quand une séquence est streamée
Alors le CDN sert la version 64 kbps (au lieu de 128 kbps) Et la qualité reste acceptable pour la voix
29. Cache intelligent des séquences jouées
Étant donné qu'un utilisateur a écouté les séquences 1-5
Quand il clique sur "Précédent" pour réécouter la séquence 4
Alors la séquence 4 est chargée depuis le cache local Et le chargement est instantané (pas de stream)
30. Nettoyage automatique du cache
Étant donné que le cache audio occupe 500 MB Et que la limite configurée est 300 MB
Quand le nettoyage automatique s'exécute
Alors les séquences les plus anciennes (non téléchargées) sont supprimées Et le cache revient à 280 MB
31. Tracking des événements clés
Étant donné qu'un utilisateur écoute un audio-guide
Quand il interagit avec l'application
Alors les événements suivants sont trackés:
| événement | données |
|---|---|
| audio_guide_started | audio_guide_id, mode, user_id |
| sequence_completed | sequence_id, completion_rate, duration |
| audio_guide_completed | audio_guide_id, total_time, sequences_count |
| point_gps_triggered | point_id, distance, auto_or_manual |
| point_gps_missed | point_id, distance, action_taken |
| paywall_displayed | audio_guide_id, sequence_number |
| premium_conversion | source: audio_guide_paywall |
32. Heatmap des abandons par séquence
Étant donné qu'un audio-guide a été écouté 1000 fois
Quand le créateur consulte la heatmap
Alors il voit pour chaque séquence:
| sequence | starts | completions | abandon_rate |
|---|---|---|---|
| 1 | 1000 | 950 | 5% |
| 2 | 950 | 920 | 3% |
| 3 | 920 | 850 | 8% |
| ... | ... | ... | ... |
| 12 | 650 | 580 | 11% |
33. Attribution GPS auto vs manuel
Étant donné un audio-guide voiture avec 8 points GPS
Quand les statistiques sont calculées
Alors le créateur voit:
| mode_declenchement | nombre |
|---|---|
| GPS automatique | 542 |
| Manuel | 123 |
| Point manqué | 89 |
34. Audio-guide avec une seule séquence (edge case)
Étant donné un audio-guide avec seulement 1 séquence
Quand il est publié
Alors un avertissement s'affiche:
35. Séquence manquante ou corrompue
Étant donné qu'une séquence 5 a un fichier audio corrompu
Quand l'utilisateur tente de la lire
Alors un message d'erreur s'affiche Et un bouton "⏭️ Passer à la suivante" est disponible Et le créateur reçoit une notification de l'erreur
36. GPS désactivé puis réactivé en cours de route
Étant donné un audio-guide voiture en cours Et que l'utilisateur désactive le GPS
Quand il le réactive 10 minutes plus tard
Alors le déclenchement automatique reprend Et les points GPS manqués entre-temps ne déclenchent pas de popup
37. Modification d'audio-guide avec utilisateurs en cours
Étant donné qu'un audio-guide a 50 utilisateurs en cours d'écoute
Quand le créateur modifie une séquence
Alors les utilisateurs actuels conservent l'ancienne version Et les nouveaux utilisateurs obtiennent la nouvelle version Et un message informe les utilisateurs lors de la prochaine ouverture
38. Suppression d'audio-guide par le créateur
Étant donné qu'un audio-guide a 20 utilisateurs avec progression
Quand le créateur supprime l'audio-guide
Alors une confirmation stricte est demandée Et si confirmé, les progressions utilisateurs sont archivées (30 jours) Et l'audio-guide devient inaccessible
39. Signalement d'audio-guide pour contenu inapproprié
Étant donné qu'un utilisateur signale un audio-guide
Quand le signalement est modéré Et jugé valide
Alors l'audio-guide est dépublié temporairement Et le créateur reçoit une notification d'explication Et il peut corriger puis republier
Audio-guide mode piéton (navigation manuelle)
En tant qu'utilisateur à pied Je veux naviguer manuellement entre les séquences d'un audio-guide Afin de contrôler mon rythme de visite
29 scénarios (28 standards, 1 plan)
Contexte commun à tous les scénarios
Étant donné que l'application RoadWave est démarrée Et que l'utilisateur "jean@example.com" est connecté (gratuit) Et qu'un audio-guide piéton "Visite du Louvre" est disponible avec 12 séquences
1. Fin de séquence normale avec pause automatique
Étant donné que la séquence 1 "Introduction" est en cours de lecture
Quand la séquence se termine à 2:15
Alors le player se met en pause automatiquement Et le message suivant s'affiche: "Séquence 1 terminée. Appuyez sur Suivant quand vous êtes prêt." Et la barre de progression indique "1/12 complétée"
2. Passage manuel à la séquence suivante
Étant donné que la séquence 1 est terminée et le player en pause
Quand l'utilisateur appuie sur le bouton [▶|] "Suivant"
Alors la séquence 2 "Pyramide du Louvre" démarre immédiatement Et aucune latence n'est observée
3. Séquence avec publicité (1/5 séquences)
Étant donné que la séquence 5 se termine Et que c'est la 5ème séquence (1 pub toutes les 5)
Quand la séquence se termine
Alors la publicité s'enchaîne automatiquement (sans attente bouton) Et la publicité se lit normalement Et elle est skippable après 5 secondes
4. Fin de publicité avec pause automatique
Étant donné qu'une publicité est en cours de lecture
Quand la publicité se termine
Alors le player se met en pause automatiquement Et le message suivant s'affiche: "Séquence 6 prête. Appuyez sur Suivant." Et l'utilisateur doit cliquer sur [▶|] pour continuer
5. Flux complet séquence → pub → séquence
Étant donné que la séquence 5 démarre
Quand la séquence 5 se termine
Alors la publicité démarre automatiquement
Quand la publicité se termine
Alors le player se met en pause
Quand l'utilisateur clique sur [▶|]
Alors la séquence 6 démarre
6. 📋 Plan: Fréquence de publicité configurable
Étant donné que l'utilisateur gratuit écoute un audio-guide Et que la fréquence pub est configurée à
Quand il termine la séquence <numero_sequence>
Alors une publicité est insérée : <pub_inseree>
📊 Exemples de données:
| frequence | numero_sequence | pub_inseree |
|---|---|---|
| 1/5 | 5 | Oui |
| 1/5 | 10 | Oui |
| 1/5 | 4 | Non |
| 1/3 | 3 | Oui |
| 1/3 | 6 | Oui |
7. Utilisateur Premium sans publicités
Étant donné que l'utilisateur "premium@example.com" est abonné Premium Et qu'il écoute un audio-guide piéton
Quand il termine la séquence 5
Alors aucune publicité n'est insérée Et le player se met en pause immédiatement Et le message "Séquence 6 prête. Appuyez sur Suivant." s'affiche
8. Boutons de contrôle disponibles en mode piéton
Étant donné qu'un audio-guide piéton est en lecture
Quand l'utilisateur consulte les contrôles
Alors les boutons suivants sont visibles:
| bouton | fonction |
|---|---|
| [▶\ | ] Suivant | Passe à la séquence suivante |
| [\ | ◀] Précédent | Retour à la séquence précédente |
| [⏸️] Pause | Pause temporaire |
| [▶️] Play | Reprend la lecture |
| [📋] Liste | Affiche toutes les séquences |
9. Passage à la séquence suivante pendant la lecture
Étant donné que la séquence 3 "La Joconde" est en cours à 1:42/3:42
Quand l'utilisateur clique sur [▶|] "Suivant"
Alors la séquence 4 "Vénus de Milo" démarre immédiatement Et la séquence 3 n'est pas marquée comme écoutée (car <80%)
10. Retour à la séquence précédente (saut direct)
Étant donné que la séquence 5 est en cours de lecture
Quand l'utilisateur clique sur [|◀] "Précédent"
Alors la séquence 4 démarre depuis le début (0:00) Et il n'y a pas de logique "replay si >10s" (contrairement au contenu classique)
11. Pause et reprise pendant une séquence
Étant donné que la séquence 2 est en cours à 1:15/1:48
Quand l'utilisateur clique sur [⏸️] "Pause"
Alors la lecture se met en pause Et la position 1:15 est conservée
Quand l'utilisateur clique sur [▶️] "Play"
Alors la lecture reprend exactement à 1:15
12. Interface liste des séquences
Étant donné qu'un audio-guide de 12 séquences est en cours
Quand l'utilisateur clique sur [📋] "Liste séquences"
Alors une liste complète s'affiche avec:
| élément | exemple |
|---|---|
| Numéro et titre | "3. La Joconde" |
| Durée | (3:42) |
| État | ✅ Écouté / ▶️ En cours / ⭕ À écouter |
| Date écoute (si écouté) | "Écouté le 15/01/2026" |
13. Séquence en cours dans la liste
Étant donné que la séquence 3 est en cours à 1:22/3:42
Quand la liste des séquences est affichée
Alors la séquence 3 affiche:
14. Navigation libre vers séquence non encore écoutée
Étant donné que l'utilisateur est sur la séquence 3 Et que les séquences 4 à 12 n'ont pas été écoutées
Quand l'utilisateur clique sur "8. Les Appartements de Napoléon"
Alors la séquence 8 démarre immédiatement depuis 0:00 Et les séquences 4 à 7 restent marquées ⭕ "À écouter"
15. Retour à une séquence déjà écoutée
Étant donné que la séquence 2 "Pyramide du Louvre" a été écoutée à 100% Et qu'elle est marquée ✅ "Écouté"
Quand l'utilisateur clique dessus dans la liste
Alors la séquence 2 démarre depuis 0:00 Et le statut ✅ est conservé
16. Checkmarks sur séquences écoutées >80%
Étant donné que l'utilisateur écoute la séquence 2 de durée 1:48
Quand il écoute jusqu'à 1:30 (83% de complétion) Et qu'il passe à la séquence suivante
Alors la séquence 2 est marquée ✅ "Écouté" Et la date d'écoute est enregistrée
17. Pas de checkmark si séquence écoutée <80%
Étant donné que l'utilisateur écoute la séquence 3 de durée 3:42
Quand il écoute jusqu'à 1:30 (40% de complétion) Et qu'il passe à la séquence suivante
Alors la séquence 3 reste marquée ⭕ "À écouter"
18. Bouton "Tout afficher" si plus de 6 séquences
Étant donné un audio-guide avec 12 séquences
Quand la liste est affichée
Alors seules les 6 premières séquences sont visibles initialement Et un bouton "Tout afficher ▼" est présent
Quand l'utilisateur clique sur "Tout afficher ▼"
Alors les 6 séquences restantes sont affichées
19. Saut vers séquence spécifique depuis la barre de progression
Étant donné qu'un audio-guide est en cours
Quand l'utilisateur clique sur "3/12" dans la barre de progression
Alors la liste des séquences s'ouvre Et la séquence en cours (3) est mise en surbrillance
20. Position exacte sauvegardée automatiquement
Étant donné que la séquence 5 est en cours à 2:34/4:10
Quand l'utilisateur quitte l'application
Alors la position 2:34 dans la séquence 5 est sauvegardée Et la sauvegarde est effectuée localement (SQLite) Et la sauvegarde est synchronisée sur le cloud (PostgreSQL)
21. Reprise après fermeture de l'application
Étant donné que l'utilisateur a quitté l'app à la séquence 5 position 2:34
Quand il rouvre l'audio-guide
Alors une popup de reprise s'affiche
Quand il clique sur "▶️ Reprendre"
Alors la lecture reprend à la séquence 5 position 2:34 exacte
22. Visiteur qui connaît déjà certaines œuvres
Étant donné qu'un visiteur du Louvre démarre l'audio-guide Et qu'il connaît déjà "La Joconde" (séquence 3)
Quand il arrive à la séquence 3 Et qu'il clique sur [▶|] "Suivant" après 10 secondes
Alors la séquence 4 démarre immédiatement Et la séquence 3 n'est pas marquée comme écoutée
23. Visiteur qui veut voir une œuvre éloignée
Étant donné qu'un visiteur est à la séquence 2 Et qu'il aperçoit "La Victoire de Samothrace" (séquence 8) physiquement
Quand il ouvre la liste et clique sur la séquence 8
Alors la séquence 8 démarre immédiatement Et il peut écouter la description même si les séquences 3-7 ne sont pas écoutées
24. Visiteur qui prend une pause café
Étant donné qu'un visiteur écoute la séquence 6
Quand il clique sur [⏸️] "Pause" Et qu'il ferme l'application pendant 30 minutes Quand il rouvre l'application
Alors la séquence 6 reprend à la position exacte où il s'était arrêté
25. Visiteur qui revient le lendemain
Étant donné qu'un visiteur a écouté les séquences 1-5 hier Et qu'il revient au musée aujourd'hui
Quand il ouvre l'audio-guide
Alors une popup propose "▶️ Reprendre" (séquence 6) Et les séquences 1-5 sont marquées ✅ "Écouté"
26. Séquence audio corrompue ou indisponible
Étant donné que la séquence 7 a un fichier audio corrompu
Quand l'utilisateur tente de la lire
Alors un message d'erreur s'affiche:
27. Perte de connexion pendant le chargement
Étant donné que l'utilisateur lance la séquence 4 Et que la connexion réseau est perdue
Quand le chargement échoue
Alors un message s'affiche: "Connexion perdue. Vérifiez votre réseau." Et un bouton "🔄 Réessayer" est disponible
28. Batterie faible en cours de visite
Étant donné que la batterie de l'appareil est à 5%
Quand l'utilisateur écoute une séquence
Alors une notification système s'affiche: "Batterie faible. Progression sauvegardée." Et la position est sauvegardée localement toutes les 10 secondes
29. Mode piéton sans points GPS (pas d'alerte localisation)
Étant donné un audio-guide en mode piéton Et que le GPS est désactivé
Quand l'utilisateur démarre l'audio-guide
Alors aucune alerte GPS ne s'affiche Et l'audio-guide fonctionne normalement (navigation 100% manuelle)
Audio-guide mode voiture (GPS automatique)
En tant qu'utilisateur en voiture Je veux que les séquences se déclenchent automatiquement selon ma position GPS Afin de profiter d'une expérience guidée hands-free
45 scénarios (40 standards, 5 plans)
Contexte commun à tous les scénarios
Étant donné que l'application RoadWave est démarrée Et que l'utilisateur "jean@example.com" est connecté (gratuit) Et qu'un audio-guide voiture "Safari du Paugre" est disponible avec 8 séquences Et que le GPS est activé
1. Distinction audio-guides vs contenus géolocalisés simples
Étant donné que l'utilisateur est en mode voiture
Quand il écoute un contenu géolocalisé simple (1 séquence unique)
Alors une notification avec compteur 7→1 est affichée 7s avant le point Et il doit valider avec "Suivant" + décompte 5s Et ce contenu compte 1/6 dans le quota horaire
Quand il démarre un audio-guide multi-séquences
Alors les séquences se déclenchent au point GPS exact (rayon 30m) Et aucun compteur 7s n'est affiché (juste notification "Ding" + toast 2s) Et l'audio-guide entier compte 1/6 dans le quota
2. Démarrage automatique au premier point GPS
Étant donné que l'utilisateur démarre l'audio-guide "Safari du Paugre" Et que le point de départ est à (43.1234, 2.5678) avec rayon 30m
Quand l'utilisateur entre dans le rayon de 30m
Alors la séquence 1 "Introduction - Point d'accueil" démarre automatiquement Et une notification sonore "Ding" est jouée (non intrusif) Et un toast s'affiche brièvement pendant 2s: "Introduction - Point d'accueil" Et aucun compteur 7→1 n'est affiché (contrairement aux contenus géolocalisés simples)
3. Déclenchement automatique séquence suivante
Étant donné que la séquence 1 est terminée Et que l'utilisateur se déplace vers le point GPS 2 (43.1245, 2.5690)
Quand l'utilisateur entre dans le rayon de 30m du point 2
Alors la séquence 2 "Enclos des lions" démarre automatiquement Et une notification "Ding" + toast "Enclos des lions" s'affiche
4. Navigation manuelle conservée (bouton Suivant actif)
Étant donné que la séquence 1 est en cours Et que l'utilisateur est encore loin du point GPS 2 (distance 500m)
Quand l'utilisateur clique sur [▶|] "Suivant"
Alors la séquence 2 démarre immédiatement Et aucune vérification GPS n'est effectuée
5. Navigation manuelle conservée (bouton Précédent actif)
Étant donné que la séquence 3 est en cours
Quand l'utilisateur clique sur [|◀] "Précédent"
Alors la séquence 2 démarre depuis le début Et aucune vérification GPS n'est effectuée
6. Tous les boutons de contrôle restent actifs
Étant donné qu'un audio-guide voiture est en cours
Quand l'utilisateur consulte les contrôles
Alors les boutons suivants sont actifs:
| bouton | état | comportement |
|---|---|---|
| [▶\ | ] Suivant | ✅ | Passe séquence suivante immédiate |
| [\ | ◀] Précédent | ✅ | Retour séquence précédente |
| [⏸️] Pause | ✅ | Pause temporaire |
| [📋] Liste | ✅ | Saut direct possible |
7. Use case - Embouteillage (séquence finie, point GPS loin)
Étant donné que la séquence 3 "Enclos des girafes" est terminée Et que le point GPS 4 est à 2 km de distance (embouteillage)
Quand l'utilisateur clique manuellement sur [▶|] "Suivant"
Alors la séquence 4 démarre immédiatement Et l'utilisateur peut continuer l'expérience sans attendre d'atteindre le point GPS
8. Use case - Route fermée (point GPS inaccessible)
Étant donné que le point GPS 5 est sur une route fermée Et que l'utilisateur ne peut pas s'en approcher
Quand l'utilisateur clique sur [▶|] "Suivant"
Alors la séquence 5 démarre quand même Et l'audio-guide continue normalement
9. Use case - Passager manipule l'application
Étant donné que l'utilisateur est passager (non conducteur) Et que la vitesse du véhicule est 45 km/h
Quand le passager clique sur [▶|] "Suivant"
Alors la séquence suivante démarre Et un avertissement s'affiche pendant 3 secondes
10. Avertissement sécurité si vitesse >10 km/h
Étant donné que la vitesse actuelle est 35 km/h
Quand l'utilisateur clique sur un bouton (Suivant ou Précédent)
Alors l'action est exécutée immédiatement (pas de blocage) Et un toast s'affiche pendant 3 secondes:
11. 📋 Plan: Avertissement selon la vitesse
Étant donné que la vitesse actuelle est km/h
Quand l'utilisateur clique sur un bouton de navigation
Alors l'avertissement est affiché :
📊 Exemples de données:
| vitesse | avertissement |
|---|---|
| 5 | Non |
| 10 | Non |
| 11 | Oui |
| 35 | Oui |
| 90 | Oui |
12. Affichage entre deux séquences avec progress bar
Étant donné que la séquence 2 "Les lions" vient de se terminer Et que le prochain point GPS 3 "Enclos des girafes" est à 500m
Quand l'interface bascule en mode "attente prochain point"
Alors l'écran affiche:
| élément | description |
|---|---|
| Statut séquence | "✅ Séquence 2/8 terminée" |
| Nom séquence | "Les lions" |
| Progress bar | Barre dynamique remplie selon distance (0%) |
| Distance prochain point | "500 mètres" |
| ETA | "≈ 1 minute 30" |
| Direction | ↗️ |
| Vitesse actuelle | "28 km/h" |
| Bouton "Rejouer séq." | Permet de réécouter la séquence qui vient de finir |
13. Progress bar dynamique vers le prochain point
Étant donné que la distance initiale vers le prochain point était 500m Et que la séquence précédente est terminée
Quand l'utilisateur se rapproche du prochain point Et que la distance actuelle est 175m
Alors la progress bar affiche "65%" remplie Et le calcul est: 100 - (175 / 500 * 100) = 65% Et la barre se met à jour chaque seconde
14. Bouton "Rejouer séq." pour réécouter
Étant donné que la séquence 3 vient de se terminer Et que l'interface "attente prochain point" est affichée
Quand l'utilisateur clique sur [▶️ Rejouer séq.]
Alors la séquence 3 redémarre depuis 0:00 Et l'utilisateur peut la réécouter (utile si distraction)
15. Interface en conduite avec distance et ETA
Étant donné que la séquence 2 est en cours Et que le prochain point GPS 3 "Enclos des girafes" est à 320m Et que la vitesse actuelle est 28 km/h
Quand l'interface est affichée
Alors les informations suivantes sont visibles:
| information | valeur |
|---|---|
| Nom prochain point | "Enclos des girafes" |
| Distance | "320 mètres" |
| ETA | "≈ 40 secondes" |
| Direction | ↗️ (flèche direction) |
| Vitesse actuelle | "28 km/h" |
| Vitesse recommandée | "20-30 km/h" |
16. Mise à jour de la distance en temps réel
Étant donné que la distance au prochain point est 500m
Quand 10 secondes s'écoulent et que l'utilisateur se rapproche
Alors la distance est mise à jour chaque seconde Et la nouvelle distance "450m" s'affiche
17. Mise à jour de l'ETA en temps réel
Étant donné que l'ETA est "≈ 2 minutes" Et que la vitesse est constante à 30 km/h
Quand l'utilisateur se rapproche du point
Alors l'ETA est recalculé chaque seconde Et il diminue progressivement: "≈ 1 minute 50", "≈ 1 minute 40", etc.
18. 📋 Plan: Format d'affichage de la distance
Étant donné que la distance au prochain point est <distance_metres>
Quand l'interface est mise à jour
Alors la distance affichée est ""
📊 Exemples de données:
| distance_metres | affichage |
|---|---|
| 50 | 50 m |
| 320 | 320 m |
| 980 | 980 m |
| 1200 | 1.2 km |
| 5400 | 5.4 km |
19. 📋 Plan: Format d'affichage de l'ETA
Étant donné que l'ETA calculé est secondes
Quand l'interface est mise à jour
Alors l'ETA affiché est ""
📊 Exemples de données:
| secondes | affichage |
|---|---|
| 30 | ≈ 30 secondes |
| 75 | ≈ 1 minute |
| 150 | ≈ 2 minutes |
| 400 | ≈ 6 minutes |
20. Calcul de la direction (flèche 8 directions)
Étant donné que la position actuelle est (43.1234, 2.5678) Et que le prochain point est au nord-est (angle 45°)
Quand la direction est calculée
Alors la flèche "↗" est affichée
21. 📋 Plan: Flèches de direction selon l'angle
Étant donné que l'angle vers le prochain point est °
Quand la direction est calculée
Alors la flèche "" est affichée
📊 Exemples de données:
| angle | fleche |
|---|---|
| 0 | ↑ |
| 45 | ↗ |
| 90 | → |
| 135 | ↘ |
| 180 | ↓ |
| 225 | ↙ |
| 270 | ← |
| 315 | ↖ |
22. Mise à jour de la direction toutes les 5 secondes
Étant donné que la direction actuelle est ↑ (nord) Et que l'utilisateur tourne vers l'est
Quand 5 secondes s'écoulent
Alors la direction est recalculée Et la nouvelle flèche ↗ (nord-est) s'affiche
23. Message "En attente de déplacement" si vitesse <5 km/h
Étant donné que la vitesse actuelle est 2 km/h (arrêté)
Quand l'ETA est calculé
Alors le message "En attente de déplacement" s'affiche Et l'ETA n'est pas calculé (car vitesse insuffisante)
24. Simplicité de l'interface (pas de carte miniature)
Étant donné qu'un audio-guide voiture est en cours
Quand l'interface est affichée
Alors aucune carte miniature n'est présente Et seuls les éléments essentiels sont affichés:
| élément |
|---|
| Distance |
| ETA |
| Direction (flèche) |
| Vitesse |
| Contrôles audio |
25. Rayon de déclenchement par défaut en mode voiture
Étant donné un audio-guide voiture
Quand un point GPS est défini
Alors le rayon de déclenchement est 30 mètres par défaut Et le rayon de tolérance "point manqué" est 100 mètres
26. Déclenchement dans le rayon (30m)
Étant donné que le point GPS 3 est défini avec rayon 30m
Quand l'utilisateur entre à 25m du point
Alors la séquence 3 se déclenche automatiquement
27. Pas de déclenchement hors rayon
Étant donné que le point GPS 3 a un rayon de 30m
Quand l'utilisateur passe à 45m du point
Alors la séquence 3 ne se déclenche pas automatiquement
28. Point manqué dans rayon de tolérance (100m)
Étant donné que l'utilisateur passe à 60m du point GPS 4 (hors rayon 30m) Et que 60m < 100m (rayon tolérance)
Quand le point est détecté comme manqué
Alors un toast s'affiche: "⚠️ Point manqué : Enclos des éléphants" Et une popup s'affiche pendant 5 secondes avec 3 options
29. Popup "Point manqué" avec 3 actions
Étant donné qu'un point GPS a été manqué (distance 60m)
Quand la popup s'affiche
Alors les options suivantes sont disponibles:
| bouton | icône | 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 | 🔙 | Ouvre GPS externe (Google Maps/Waze) vers point |
30. Action "Écouter quand même"
Étant donné qu'un point GPS est manqué
Quand l'utilisateur clique sur "🔊 Écouter quand même"
Alors la séquence correspondante démarre immédiatement Et l'utilisateur peut continuer sa route
31. Action "Passer au suivant"
Étant donné qu'un point GPS 5 est manqué
Quand l'utilisateur clique sur "⏭️ Passer au suivant"
Alors la séquence 5 est ignorée (non écoutée) Et l'application attend le point GPS 6 Et la distance vers le point 6 s'affiche
32. Action "Faire demi-tour"
Étant donné qu'un point GPS est manqué à (43.1250, 2.5700)
Quand l'utilisateur clique sur "🔙 Faire demi-tour"
Alors l'application détecte l'app GPS installée (Google Maps ou Waze) Et ouvre la navigation GPS externe vers (43.1250, 2.5700)
33. Point manqué au-delà du rayon de tolérance (>100m)
Étant donné que l'utilisateur passe à 150m du point GPS 6
Quand la distance est détectée
Alors aucune popup ne s'affiche (point trop loin) Et l'utilisateur peut naviguer manuellement avec [▶|]
34. 📋 Plan: Gestion selon la distance au point
Étant donné un point GPS avec rayon 30m et tolérance 100m
Quand l'utilisateur passe à du point
Alors le comportement est
📊 Exemples de données:
| distance | comportement |
|---|---|
| 20m | Déclenchement automatique séquence |
| 40m | Rien (hors rayon, pas encore tolérance) |
| 60m | Popup "Point manqué" avec 3 options |
| 110m | Rien (trop loin, hors tolérance) |
35. Configuration rayon personnalisé par le créateur
Étant donné qu'un créateur définit un rayon de 50m (au lieu de 30m)
Quand un utilisateur entre à 45m du point
Alors la séquence se déclenche automatiquement Et le rayon personnalisé est respecté
36. Rayon minimum et maximum configurables
Étant donné qu'un créateur configure un rayon
Quand il ajuste le curseur
Alors les valeurs disponibles sont de 10m à 200m Et le rayon par défaut suggéré est 30m pour la voiture
37. Safari-parc avec déclenchement automatique fluide
Étant donné qu'un utilisateur roule dans un safari à 20 km/h
Quand il passe devant "Enclos des lions" (point GPS 2)
Alors la séquence 2 démarre automatiquement sans intervention Et il peut se concentrer sur la conduite et l'observation
38. Détour imprévu (travaux sur la route)
Étant donné qu'un utilisateur prend un détour à cause de travaux Et que le point GPS 4 devient inaccessible
Quand il est loin du point (>100m) Et qu'il clique manuellement sur [▶|]
Alors la séquence 4 démarre quand même Et l'expérience continue sans blocage
39. Passager qui navigue librement
Étant donné qu'un passager utilise l'application Et que le conducteur roule à 50 km/h
Quand le passager clique sur "Précédent" pour réécouter
Alors l'action est exécutée immédiatement Et un warning apparaît brièvement (sensibilisation)
40. Embouteillage prolongé
Étant donné que la séquence 3 est terminée depuis 10 minutes Et que l'utilisateur est bloqué dans un embouteillage Et que le point GPS 4 est encore à 1.5 km
Quand l'utilisateur clique sur [▶|]
Alors la séquence 4 démarre immédiatement Et l'utilisateur peut passer le temps en écoutant
41. GPS désactivé en mode voiture
Étant donné qu'un audio-guide voiture est démarré Et que le GPS est désactivé
Quand l'application détecte l'absence de GPS
Alors une alerte s'affiche:
42. Action "Passer en mode Manuel"
Étant donné que le GPS est désactivé
Quand l'utilisateur clique sur "Passer en mode Manuel"
Alors l'audio-guide bascule en navigation 100% manuelle Et les boutons [▶|] et [|◀] permettent de naviguer Et aucun déclenchement GPS n'est tenté
43. Précision GPS insuffisante
Étant donné que le signal GPS a une précision de ±150m
Quand l'utilisateur approche d'un point GPS avec rayon 30m
Alors un avertissement s'affiche:
44. Perte signal GPS en cours de route
Étant donné qu'un audio-guide voiture est en cours
Quand le signal GPS est perdu (tunnel, parking souterrain)
Alors un toast s'affiche: "Signal GPS perdu. Navigation manuelle active." Et les boutons de navigation restent actifs
Quand le signal GPS revient
Alors un toast s'affiche: "Signal GPS rétabli" Et le déclenchement automatique est réactivé
45. Dépassement de la vitesse recommandée
Étant donné qu'un audio-guide recommande 20-30 km/h Et que l'utilisateur roule à 65 km/h
Quand la vitesse est détectée
Alors l'affichage vitesse est en orange: "⚠️ 65 km/h" Et un message info s'affiche: "Vitesse élevée. Risque de manquer des points."
Audio-guides modes vélo et transport
En tant qu'utilisateur à vélo ou en transport en commun Je veux profiter d'un guidage GPS adapté à mon mode de déplacement Afin d'avoir une expérience optimisée avec tolérances appropriées
27 scénarios (24 standards, 3 plans)
Contexte commun à tous les scénarios
Étant donné que l'application RoadWave est démarrée Et que l'utilisateur "jean@example.com" est connecté Et que le GPS est activé
1. 📋 Plan: Paramètres par mode de déplacement
Étant donné un audio-guide configuré en mode
Alors les paramètres suivants sont appliqués:
| paramètre | valeur |
|---|---|
| Rayon déclenchement | <rayon_declenchement> |
| Rayon tolérance "point manqué" | <rayon_tolerance> |
| Vitesse recommandée | <vitesse_recommandee> |
| Seuil warning sécurité | <seuil_warning> |
📊 Exemples de données:
| mode | rayon_declenchement | rayon_tolerance | vitesse_recommandee | seuil_warning |
|---|---|---|---|---|
| Voiture | 30m | 100m | 20-50 km/h | >10 km/h |
| Vélo | 50m | 75m | 10-25 km/h | >5 km/h |
| Transport | 100m | 150m | Variable | Désactivé |
2. Déclenchement automatique avec rayon 50m (mode vélo)
Étant donné un audio-guide vélo "Circuit des châteaux de la Loire" Et que le point GPS 3 a un rayon de 50m
Quand l'utilisateur à vélo entre à 45m du point
Alors la séquence 3 "Château de Chambord" se déclenche automatiquement
3. Rayon plus large justifié pour le vélo
Étant donné qu'un cycliste roule sur piste cyclable Et que sa vitesse varie entre 8 et 22 km/h (arrêts fréquents) Et que le tracé est moins prévisible qu'en voiture
Quand un point GPS avec rayon 50m est défini
Alors le rayon plus large compense la variabilité de trajectoire
4. Warning sécurité dès 5 km/h en vélo
Étant donné un audio-guide vélo en cours Et que la vitesse actuelle est 12 km/h
Quand l'utilisateur clique sur [▶|] "Suivant"
Alors l'action est exécutée Et un warning s'affiche: "⚠️ Manipulation en déplacement détecté. Pour votre sécurité, arrêtez-vous."
5. 📋 Plan: Warning vélo selon la vitesse
Étant donné que la vitesse actuelle à vélo est km/h
Quand l'utilisateur clique sur un bouton de navigation
Alors le warning est affiché :
📊 Exemples de données:
| vitesse | warning |
|---|---|
| 0 | Non |
| 4 | Non |
| 6 | Oui |
| 15 | Oui |
| 25 | Oui |
6. Tolérance GPS moins stricte en vélo
Étant donné qu'un cycliste passe à 65m du point GPS 4 Et que le rayon de déclenchement est 50m Et que le rayon de tolérance est 75m
Quand la distance est détectée
Alors la popup "Point manqué" s'affiche avec 3 options Et le système tolère l'écart (trajectoire vélo moins prévisible)
7. Affichage adapté au vélo
Étant donné un audio-guide vélo en cours
Quand l'interface est affichée
Alors les informations suivantes sont visibles:
| information | valeur |
|---|---|
| Icône mode | 🚴 |
| Distance prochain point | "450 m" |
| ETA | "≈ 2 minutes" |
| Direction | ↗️ |
| Vitesse actuelle | "18 km/h" |
| Vitesse recommandée | "10-25 km/h" |
8. Cas d'usage - Piste cyclable avec arrêts fréquents
Étant donné qu'un cycliste suit un circuit nature Et qu'il s'arrête régulièrement (feux, photos, fatigue)
Quand il s'arrête à 40m d'un point GPS (rayon 50m)
Alors la séquence se déclenche automatiquement Et le rayon large permet le déclenchement malgré l'arrêt
9. Cas d'usage - Circulation mixte piétons/vélos
Étant donné qu'un cycliste roule sur voie partagée Et qu'il doit ralentir fréquemment pour éviter les piétons
Quand sa vitesse varie entre 5 et 20 km/h
Alors le système s'adapte avec le rayon 50m Et le déclenchement reste fiable
10. Déclenchement automatique avec rayon 100m (mode transport)
Étant donné un audio-guide transport "Ligne touristique Paris" Et que le point GPS "Tour Eiffel" a un rayon de 100m
Quand le bus touristique entre à 85m du point
Alors la séquence "Tour Eiffel" se déclenche automatiquement
11. Rayon très large justifié pour le transport
Étant donné qu'un bus touristique suit une ligne fixe Et qu'il effectue des arrêts fréquents (stations) Et que l'utilisateur n'a aucun contrôle sur la trajectoire
Quand un point GPS avec rayon 100m est défini
Alors le rayon large compense les arrêts et la ligne fixe
12. Pas de warning sécurité en mode transport
Étant donné un audio-guide transport en cours Et que le bus roule à 50 km/h
Quand l'utilisateur clique sur [▶|] "Suivant"
Alors l'action est exécutée immédiatement Et aucun warning n'est affiché
13. Vitesse recommandée "Selon ligne"
Étant donné un audio-guide transport
Quand l'interface est affichée
Alors la vitesse recommandée indique "Selon ligne" Et aucune valeur fixe n'est affichée (car ligne de transport varie)
14. Tolérance horaire pour retards
Étant donné qu'un bus touristique est en retard de 3 minutes Et qu'il arrive au point GPS "Musée du Louvre" avec retard
Quand il entre dans le rayon de 100m
Alors la séquence se déclenche normalement Et le système tolère le retard (pas de pénalité temporelle)
15. Tolérance spatiale très large (150m)
Étant donné qu'un bus passe à 120m du point GPS "Arc de Triomphe" Et que le rayon de déclenchement est 100m Et que le rayon de tolérance est 150m
Quand la distance est détectée
Alors la popup "Point manqué" s'affiche avec 3 options
16. Affichage adapté au transport
Étant donné un audio-guide transport en cours
Quand l'interface est affichée
Alors les informations suivantes sont visibles:
| information | valeur |
|---|---|
| Icône mode | 🚌 |
| Distance prochain point | "1.2 km" |
| ETA | "≈ 3 minutes" |
| Direction | → |
| Vitesse actuelle | "35 km/h" |
| Vitesse recommandée | "Selon ligne" |
17. Cas d'usage - Bus touristique hop-on hop-off
Étant donné un bus touristique "Paris Open Tour" Et qu'il suit un circuit fixe avec 15 arrêts
Quand il approche de chaque arrêt
Alors la séquence correspondante se déclenche automatiquement Et l'utilisateur n'a rien à faire (expérience passive)
18. Cas d'usage - Train panoramique
Étant donné un train touristique "Ligne des Alpes" Et qu'il roule à vitesse variable (20-80 km/h)
Quand il passe près de points d'intérêt
Alors les séquences se déclenchent avec rayon 100m Et le système compense la vitesse élevée
19. Navigation manuelle conservée (vélo et transport)
Étant donné un audio-guide en mode
Quand l'utilisateur clique sur [▶|] ou [|◀]
Alors les boutons manuels fonctionnent normalement Et aucune vérification GPS n'est effectuée
20. Affichage distance + ETA + direction (tous modes)
Étant donné un audio-guide en mode
Quand l'interface est affichée
Alors les informations distance, ETA et direction sont affichées Et le format est identique au mode voiture
21. Gestion "Point manqué" identique
Étant donné un audio-guide en mode
Quand un point GPS est manqué (dans rayon tolérance)
Alors la popup avec 3 options s'affiche:
| option |
|---|
| 🔊 Écouter quand même |
| ⏭️ Passer au suivant |
| 🔙 Faire demi-tour |
22. 📋 Plan: Insertion publicité dans tous les modes
Étant donné un utilisateur gratuit écoute un audio-guide en mode
Quand la séquence 5 se termine (1 pub / 5 séquences)
Alors la publicité s'enchaîne automatiquement Et elle est skippable après 5 secondes
📊 Exemples de données:
| mode |
|---|
| Voiture |
| Vélo |
| Transport |
| Piéton |
23. GPS imprécis en forêt (vélo)
Étant donné un cycliste dans une forêt dense Et que la précision GPS est ±80m
Quand il approche d'un point GPS avec rayon 50m
Alors un avertissement s'affiche:
24. Bus dévié de son itinéraire (transport)
Étant donné un bus touristique avec déviation Et que plusieurs points GPS deviennent inaccessibles
Quand l'utilisateur est informé
Alors un message s'affiche:
25. Changement de mode en cours de route
Étant donné un audio-guide démarré en mode "Vélo"
Quand l'utilisateur décide de continuer à pied Et qu'il ouvre les paramètres
Alors il peut changer le mode vers "Piéton" Et les rayons sont reconfigurés automatiquement Et une confirmation s'affiche:
26. Détection automatique incohérente
Étant donné qu'un utilisateur marche rapidement (7 km/h) Et que le système détecte "Vélo" par erreur
Quand la suggestion s'affiche
Alors l'utilisateur peut cliquer sur "Changer" Et sélectionner manuellement "Piéton"
27. Batterie en mode vélo longue distance
Étant donné un circuit vélo de 50 km avec 20 séquences Et que l'utilisateur roule pendant 3 heures
Quand la batterie atteint 15%
Alors une notification suggère:
Audio-guides Premium et monétisation
En tant que créateur Je veux pouvoir proposer des audio-guides Premium Afin de monétiser mon contenu de qualité
31 scénarios
Contexte commun à tous les scénarios
Étant donné que l'application RoadWave est démarrée Et que le créateur "guide@example.com" est connecté et vérifié
1. Création d'un audio-guide Premium
Étant donné que le créateur crée un audio-guide "Visite VIP Versailles"
Quand il accède aux paramètres de monétisation (étape 4)
Alors il peut choisir:
| option | description |
|---|---|
| Gratuit | Accessible à tous (avec pubs) |
| Premium | Réservé abonnés Premium |
2. Badge Premium visible sur l'audio-guide
Étant donné un audio-guide configuré en Premium
Quand il est affiché dans les résultats de recherche
Alors un badge "👑 Premium" est visible Et la cover image a un cadre doré subtil
3. Preview 3 premières séquences pour utilisateurs gratuits
Étant donné un audio-guide Premium "Visite VIP Versailles" avec 15 séquences Et qu'un utilisateur gratuit ouvre l'audio-guide
Quand il consulte la liste des séquences
Alors les séquences affichent:
| séquence | état |
|---|---|
| 1 | ✅ Accessible (preview) |
| 2 | ✅ Accessible (preview) |
| 3 | ✅ Accessible (preview) |
| 4 | 🔒 Réservé Premium |
| 5-15 | 🔒 Réservé Premium |
4. Écoute des 3 premières séquences sans blocage
Étant donné un utilisateur gratuit Et un audio-guide Premium avec preview
Quand il écoute les séquences 1, 2 et 3
Alors aucune publicité n'est insérée (preview = teasing) Et l'écoute est fluide
5. Paywall après la 3ème séquence
Étant donné qu'un utilisateur gratuit termine la séquence 3
Quand la séquence se termine
Alors un overlay paywall s'affiche immédiatement:
6. Bouton "Passer Premium" vers tunnel d'abonnement
Étant donné que l'overlay paywall Premium est affiché
Quand l'utilisateur clique sur "Passer Premium"
Alors il est redirigé vers la page d'abonnement Mangopay Et l'audio-guide actuel est marqué en "pending" (reprise après souscription)
7. Reprise automatique après souscription Premium
Étant donné qu'un utilisateur s'est abonné Premium depuis un paywall audio-guide
Quand l'abonnement est activé
Alors il est redirigé vers l'audio-guide automatiquement Et la séquence 4 démarre immédiatement Et un toast de bienvenue s'affiche: "✨ Bienvenue Premium ! Profitez de votre audio-guide"
8. Utilisateur Premium - Accès complet immédiat
Étant donné qu'un utilisateur Premium ouvre un audio-guide Premium
Quand il consulte la liste des séquences
Alors toutes les 15 séquences sont accessibles Et aucun paywall ne s'affiche Et aucune publicité n'est insérée
9. Pas de preview si l'audio-guide a <3 séquences
Étant donné un audio-guide Premium avec seulement 2 séquences
Quand un utilisateur gratuit tente de l'ouvrir
Alors un paywall s'affiche immédiatement (avant lecture) Et aucune preview n'est disponible
10. Rémunération créateur pour audio-guide Premium
Étant donné un créateur avec un audio-guide Premium Et que 50 utilisateurs Premium ont écouté l'audio-guide ce mois
Quand la répartition des revenus est calculée
Alors le créateur reçoit 70% des revenus proportionnels Et la formule est: (Écoutes créateur / Total écoutes Premium) × 70% pool Premium
11. Dashboard revenus par audio-guide
Étant donné qu'un créateur a 3 audio-guides Premium publiés
Quand il consulte son dashboard revenus
Alors il voit pour chaque audio-guide:
| audio_guide | ecoutes_mois | revenus_estime |
|---|---|---|
| Visite VIP Versailles | 142 | 45.20 € |
| Secrets du Louvre | 89 | 28.50 € |
| Châteaux de la Loire | 203 | 64.80 € |
12. Comparaison gratuit vs Premium
Étant donné qu'un créateur a publié 2 audio-guides:
| titre | type | ecoutes_mois | revenus |
|---|---|---|---|
| Tour de Paris | Gratuit | 1200 | 12.50 € |
| Visite VIP Versailles | Premium | 142 | 45.20 € |
Quand il consulte son dashboard
Alors il peut comparer les performances Et constater que Premium génère plus de revenus par écoute
13. Seuil minimum de paiement (20€)
Étant donné qu'un créateur a généré 18€ de revenus ce mois
Quand le paiement mensuel est traité
Alors le montant est reporté au mois suivant Et un message s'affiche: "Seuil minimum non atteint (20€). Montant reporté."
14. Paiement automatique mensuel
Étant donné qu'un créateur a généré 138.50€ de revenus en janvier
Quand le 5 février arrive
Alors le paiement est initié automatiquement via Mangopay Et le créateur reçoit une notification: "Paiement de 138.50€ en cours" Et les fonds arrivent sous 2-3 jours ouvrés
15. Insertion publicité toutes les 5 séquences (gratuit)
Étant donné un audio-guide gratuit avec 12 séquences Et un utilisateur gratuit
Quand il termine la séquence 5
Alors une publicité démarre automatiquement
Quand il termine la séquence 10
Alors une deuxième publicité démarre
16. Publicité après séquence en mode piéton (avec pause)
Étant donné un audio-guide piéton gratuit
Quand la séquence 5 se termine
Alors la publicité démarre automatiquement (pas d'attente bouton) Et la pub est skippable après 5 secondes
Quand la publicité se termine
Alors le player se met en pause Et l'utilisateur doit cliquer sur [▶|] pour continuer
17. Publicité en mode voiture/vélo/transport (automatique)
Étant donné un audio-guide voiture gratuit
Quand la séquence 5 se termine
Alors la publicité démarre automatiquement
Quand la publicité se termine
Alors la séquence 6 démarre automatiquement (pas de pause)
18. Publicités géolocalisées dans audio-guides
Étant donné un audio-guide dans la région "Île-de-France"
Quand une publicité doit être insérée
Alors l'API publicitaire filtre par:
| critère | valeur |
|---|---|
| Géolocalisation | Île-de-France |
| Catégorie | Tourisme, Culture |
| Langue | Français |
19. Comptabilisation des impressions pub pour créateur
Étant donné qu'un audio-guide gratuit génère 200 écoutes complètes Et que chaque écoute complète = 2 publicités (séq. 5 et 10)
Quand les revenus pub sont calculés
Alors 400 impressions sont comptabilisées Et le créateur reçoit 0.80€ (400 × 0.002€)
20. CTA Premium après audio-guide gratuit complété
Étant donné qu'un utilisateur gratuit complète un audio-guide gratuit
Quand il termine la dernière séquence
Alors un overlay s'affiche:
21. Recommandations d'audio-guides Premium après gratuit
Étant donné qu'un utilisateur termine un audio-guide gratuit "Tour de Paris"
Quand l'overlay de fin s'affiche
Alors 3 audio-guides Premium similaires sont suggérés:
| titre | type | créateur |
|---|---|---|
| Secrets de Montmartre | Premium | @paris_stories |
| Visite VIP Musée d'Orsay | Premium | @art_guide |
| Paris hors des sentiers | Premium | @explore_paris |
22. Badge "Premium recommandé" sur audio-guides populaires
Étant donné un audio-guide Premium avec >500 écoutes et note >4.5/5
Quand il est affiché dans les résultats de recherche
Alors un badge "⭐ Premium recommandé" est visible Et il est mis en avant dans les résultats
23. Conversion tracking pour attribution créateur
Étant donné qu'un utilisateur découvre Premium via un audio-guide créateur
Quand il s'abonne
Alors la conversion est trackée:
| donnée | valeur |
|---|---|
| source_conversion | audio_guide_paywall |
| audio_guide_id | visite_vip_versailles_123 |
| creator_id | guide_versailles_456 |
Et le créateur bénéficie d'un bonus de conversion
24. Essai gratuit 7 jours Premium via audio-guide
Étant donné qu'un utilisateur gratuit atteint le paywall d'un audio-guide Premium Et qu'il n'a jamais essayé Premium
Quand l'overlay s'affiche
Alors une offre d'essai est proposée:
25. Activation immédiate après essai gratuit
Étant donné qu'un utilisateur démarre un essai gratuit 7 jours
Quand l'essai est activé
Alors l'audio-guide Premium démarre immédiatement Et toutes les séquences sont débloquées Et aucune publicité n'est insérée
26. Rappel 2 jours avant fin d'essai
Étant donné qu'un utilisateur a démarré un essai gratuit le 15/01
Quand le 20/01 arrive (J-2)
Alors une notification est envoyée:
27. Créateur mix gratuit + Premium
Étant donné qu'un créateur a publié 5 audio-guides:
| titre | type |
|---|---|
| Découverte de Paris | Gratuit |
| Visite VIP Louvre | Premium |
| Balade Montmartre | Gratuit |
| Secrets Versailles | Premium |
| Visite express Orsay | Gratuit |
Quand un utilisateur découvre son profil
Alors les audio-guides gratuits servent de teasing Et les audio-guides Premium sont mis en avant avec badge
28. Utilisateur hésite à s'abonner
Étant donné qu'un utilisateur atteint le paywall d'un audio-guide Premium Et qu'il clique sur "Découvrir d'autres audio-guides gratuits"
Quand il revient 2 jours plus tard sur le même audio-guide
Alors le paywall s'affiche à nouveau Et une réduction temporaire est proposée: "Offre spéciale : -20% premier mois"
29. Échec du paiement Premium via paywall
Étant donné qu'un utilisateur tente de s'abonner Premium
Quand le paiement Mangopay échoue
Alors un message d'erreur s'affiche:
30. Abonnement Premium expiré pendant écoute
Étant donné qu'un utilisateur Premium écoute un audio-guide Premium Et que son abonnement expire pendant l'écoute (séquence 8/15)
Quand l'expiration est détectée
Alors l'écoute continue jusqu'à la fin de la séquence en cours Et un overlay s'affiche ensuite:
31. Créateur change audio-guide de gratuit à Premium
Étant donné qu'un audio-guide gratuit a 50 utilisateurs avec progression
Quand le créateur le passe en Premium
Alors les utilisateurs ayant déjà commencé gardent l'accès complet Et seuls les nouveaux utilisateurs sont soumis au paywall Et un message de transparence s'affiche:
Sauvegarde et reprise de progression audio-guide
En tant qu'utilisateur Je veux que ma progression soit sauvegardée automatiquement Afin de pouvoir reprendre mon audio-guide là où je me suis arrêté
32 scénarios (31 standards, 1 plan)
Contexte commun à tous les scénarios
Étant donné que l'application RoadWave est démarrée Et que l'utilisateur "jean@example.com" est connecté
1. Sauvegarde automatique toutes les 10 secondes
Étant donné qu'un audio-guide "Visite du Louvre" est en cours Et que la séquence 3 est à la position 1:24
Quand 10 secondes s'écoulent
Alors la progression est sauvegardée automatiquement:
| donnée | valeur |
|---|---|
| audio_guide_id | louvre_123 |
| sequence_actuelle | 3 |
| position_audio | 1:24 |
| timestamp | 2026-01-22 14:35:42 |
| sequences_ecoutees | [1, 2] |
2. Sauvegarde locale (SQLite) pour rapidité
Étant donné qu'une sauvegarde est déclenchée
Quand la progression est enregistrée
Alors les données sont écrites en SQLite local Et l'écriture prend moins de 50ms Et l'application reste fluide
3. Synchronisation cloud en arrière-plan
Étant donné qu'une sauvegarde locale est effectuée
Quand 30 secondes s'écoulent
Alors la progression est synchronisée vers PostgreSQL cloud Et la synchronisation s'effectue en arrière-plan Et elle n'impacte pas les performances
4. Sauvegarde immédiate lors de la fermeture
Étant donné qu'un audio-guide est en cours à la séquence 4 position 2:15
Quand l'utilisateur ferme l'application
Alors la progression est sauvegardée immédiatement (local + cloud) Et les données sont écrites avant la fermeture complète
5. Sauvegarde des séquences complétées
Étant donné qu'un audio-guide de 12 séquences est en cours Et que les séquences 1, 2, 4, 5 ont été écoutées à >80%
Quand la progression est sauvegardée
Alors les séquences complétées sont enregistrées:
6. Historique des écoutes pour statistiques
Étant donné qu'un utilisateur a écouté 3 séquences d'un audio-guide
Quand les données sont sauvegardées
Alors l'historique d'écoute inclut:
| sequence_id | started_at | completed_at | completion_rate |
|---|---|---|---|
| 1 | 2026-01-22 14:10:00 | 2026-01-22 14:12:15 | 100% |
| 2 | 2026-01-22 14:12:20 | 2026-01-22 14:14:08 | 100% |
| 3 | 2026-01-22 14:14:15 | 2026-01-22 14:17:45 | 92% |
7. Popup de reprise au redémarrage
Étant donné que l'utilisateur a quitté l'app à la séquence 6 position 2:34
Quand il rouvre l'audio-guide "Visite du Louvre"
Alors une popup s'affiche:
8. Action "Reprendre" - Position exacte restaurée
Étant donné qu'une popup de reprise est affichée
Quand l'utilisateur clique sur "▶️ Reprendre"
Alors la séquence 6 "Vénus de Milo" se charge Et la position exacte 2:34 est restaurée Et la lecture démarre automatiquement après 1 seconde
9. Action "Recommencer" - Réinitialisation complète
Étant donné qu'une popup de reprise est affichée
Quand l'utilisateur clique sur "🔄 Recommencer"
Alors l'audio-guide redémarre depuis la séquence 1 position 0:00 Et toutes les séquences sont marquées ⭕ "À écouter" Et l'historique d'écoute est réinitialisé pour cette session
10. Reprise après 7 jours d'inactivité
Étant donné qu'un utilisateur a arrêté un audio-guide le 15/01/2026 Et qu'il le rouvre le 22/01/2026 (7 jours plus tard)
Quand l'audio-guide se charge
Alors la popup de reprise s'affiche normalement Et toutes les données de progression sont conservées
11. Reprise sur un autre appareil (synchronisation cloud)
Étant donné qu'un utilisateur écoute un audio-guide sur iPhone Et qu'il quitte à la séquence 4 position 1:20
Quand il ouvre le même audio-guide sur iPad
Alors la popup de reprise s'affiche avec la progression iPhone Et il peut reprendre exactement où il s'était arrêté
12. Conflit de synchronisation (dernier appareil gagne)
Étant donné qu'un utilisateur écoute sur iPhone à la séquence 3 Et simultanément sur iPad à la séquence 7
Quand les deux appareils synchronisent
Alors la progression la plus récente (timestamp) est conservée Et l'appareil avec ancienne progression affiche une notification:
13. Mode hors-ligne - Sauvegarde locale uniquement
Étant donné qu'un utilisateur écoute un audio-guide hors connexion Et qu'il atteint la séquence 5
Quand la progression est sauvegardée
Alors les données sont écrites localement (SQLite) Et une icône "☁️ Non synchronisé" s'affiche discrètement
14. Synchronisation automatique à la reconnexion
Étant donné que l'utilisateur a écouté hors ligne jusqu'à la séquence 8 Et que 5 progressions locales ne sont pas synchronisées
Quand la connexion réseau est rétablie
Alors les 5 progressions sont synchronisées automatiquement Et un toast s'affiche brièvement: "✅ Progression synchronisée"
15. Suppression de la progression (recommencer proprement)
Étant donné qu'un utilisateur est à la séquence 10/12
Quand il ouvre les paramètres de l'audio-guide Et qu'il clique sur "🔄 Réinitialiser progression"
Alors une confirmation s'affiche: Et si confirmé, la progression est effacée
16. Taux de complétion global de l'audio-guide
Étant donné un audio-guide de 12 séquences Et que l'utilisateur a écouté complètement 8 séquences Et partiellement 1 séquence (45%)
Quand les statistiques sont calculées
Alors le taux de complétion affiché est "67%" (8/12)
17. Badge "Audio-guide complété" à 100%
Étant donné un audio-guide de 12 séquences
Quand l'utilisateur écoute la 12ème séquence à 100%
Alors un badge "✅ Audio-guide complété" s'affiche Et une notification de félicitations est envoyée Et le statut "Complété le 22/01/2026" est visible dans l'historique
18. Temps total passé sur l'audio-guide
Étant donné qu'un utilisateur a écouté un audio-guide sur 2 sessions:
| session | durée |
|---|---|
| 1 | 25 min |
| 2 | 18 min |
Quand les statistiques sont calculées
Alors le temps total est "43 minutes" Et il est affiché dans l'historique personnel
19. Liste des audio-guides "En cours" dans le profil
Étant donné qu'un utilisateur a 3 audio-guides en cours:
| audio_guide | progression |
|---|---|
| Visite du Louvre | 6/12 |
| Safari du Paugre | 3/8 |
| Circuit Loire à Vélo | 12/15 |
Quand il consulte son profil "Audio-guides"
Alors la section "📍 En cours" affiche les 3 audio-guides Et chaque élément montre la progression sous forme de barre
20. Liste des audio-guides "Complétés" dans le profil
Étant donné qu'un utilisateur a complété 2 audio-guides:
| audio_guide | date_completion |
|---|---|
| Tour de Paris | 2026-01-15 |
| Découverte de Lyon | 2026-01-20 |
Quand il consulte son profil "Audio-guides"
Alors la section "✅ Complétés" affiche les 2 audio-guides Et la date de complétion est visible
21. Badge "Complétiste" pour 10 audio-guides complétés
Étant donné qu'un utilisateur complète son 10ème audio-guide
Quand la complétion est enregistrée
Alors un badge "🏆 Complétiste" est débloqué Et il apparaît sur son profil Et une notification est envoyée:
22. 📋 Plan: Niveaux de badges selon nombre d'audio-guides complétés
Étant donné qu'un utilisateur complète audio-guides
Quand le badge est attribué
Alors il reçoit le badge ""
📊 Exemples de données:
| nombre | badge |
|---|---|
| 1 | 🎧 Premier audio-guide |
| 5 | 🗺️ Explorateur |
| 10 | 🏆 Complétiste |
| 25 | 🌟 Expert |
| 50 | 💎 Maître audio-guideur |
23. Dashboard créateur - Statistiques par audio-guide
Étant donné qu'un créateur a publié l'audio-guide "Visite du Louvre"
Quand il consulte son dashboard
Alors les métriques suivantes sont affichées:
| métrique | valeur |
|---|---|
| Écoutes totales | 1542 |
| Écoutes complètes (>80%) | 892 |
| Taux de complétion moyen | 58% |
| Temps d'écoute total | 423h |
| Séquence la plus écoutée | Séq. 3 |
| Séquence la moins écoutée | Séq. 11 |
24. Graphique de complétion par séquence
Étant donné un audio-guide de 12 séquences
Quand le créateur consulte les statistiques détaillées
Alors un graphique en barres affiche:
| séquence | taux_completion |
|---|---|
| 1 | 100% |
| 2 | 95% |
| 3 | 89% |
| ... | ... |
| 12 | 58% |
25. Détection des points d'abandon
Étant donné qu'un audio-guide a un taux de complétion de 58% Et que 35% des utilisateurs abandonnent à la séquence 7
Quand le créateur consulte les insights
Alors un avertissement s'affiche:
26. Heatmap géographique des écoutes
Étant donné un audio-guide géolocalisé
Quand le créateur consulte la heatmap
Alors une carte affiche:
| élément | description |
|---|---|
| Densité d'écoutes | Zones rouge/orange/jaune selon écoutes |
| Points GPS | Marqueurs sur chaque point |
| Statistiques par point | Nombre d'écoutes par zone |
27. Temps moyen par séquence
Étant donné qu'un créateur analyse son audio-guide
Quand il consulte les statistiques temporelles
Alors il voit pour chaque séquence:
| séquence | durée_audio | temps_ecoute_moyen | ecart |
|---|---|---|---|
| 1 | 2:15 | 2:10 | -5s |
| 2 | 1:48 | 1:30 | -18s |
| 3 | 3:42 | 3:40 | -2s |
28. Notification créateur pour milestone
Étant donné qu'un audio-guide atteint 1000 écoutes
Quand le seuil est franchi
Alors une notification est envoyée au créateur:
29. Corruption de données de sauvegarde
Étant donné qu'une sauvegarde locale (SQLite) est corrompue
Quand l'application tente de charger la progression
Alors une récupération depuis le cloud est tentée Et si réussie, les données cloud sont restaurées Et la base locale est reconstruite
30. Échec de synchronisation cloud
Étant donné que l'API cloud est indisponible
Quand une tentative de synchronisation est effectuée
Alors l'application continue avec sauvegarde locale uniquement Et un retry automatique est programmé dans 5 minutes Et l'icône "☁️ Non synchronisé" reste affichée
31. Suppression accidentelle de progression (récupération)
Étant donné qu'un utilisateur réinitialise un audio-guide par erreur
Quand il contacte le support dans les 7 jours
Alors l'équipe peut restaurer la progression depuis les backups Et les données sont récupérables (backup quotidien conservé 30 jours)
32. Nettoyage automatique des vieilles progressions
Étant donné qu'une progression n'a pas été mise à jour depuis 6 mois
Quand le nettoyage automatique s'exécute
Alors la progression est archivée (mais pas supprimée) Et l'utilisateur peut la restaurer via l'historique
Classification des contenus par âge
En tant que plateforme responsable Je veux classifier les contenus par tranche d'âge Afin de protéger les mineurs et respecter les obligations légales
13 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible
1. Créateur doit classifier son contenu à la publication
Étant donné que je suis un créateur connecté
Quand je crée un nouveau contenu audio
Alors je dois obligatoirement choisir une classification d'âge parmi:
| classification | description |
|---|---|
| Tout public | Contenu adapté à tous les âges |
| 13+ | Contenu mature léger |
| 16+ | Contenu mature |
| 18+ | Contenu adulte |
2. Publication impossible sans classification
Étant donné que je crée un contenu audio
Quand j'essaie de publier sans sélectionner de classification
Alors la publication échoue Et je vois le message "Vous devez sélectionner une classification d'âge"
3. Utilisateur 13-15 ans voit uniquement du contenu "Tout public"
Étant donné que je suis un utilisateur de 14 ans Et qu'il existe des contenus avec les classifications suivantes:
| classification | nombre |
|---|---|
| Tout public | 20 |
| 13+ | 15 |
| 16+ | 10 |
| 18+ | 5 |
Quand je demande des recommandations
Alors je vois uniquement les 20 contenus "Tout public" Et les autres contenus ne sont jamais proposés
4. Utilisateur 16-17 ans voit "Tout public" et "13+"
Étant donné que je suis un utilisateur de 17 ans Et qu'il existe des contenus avec les classifications suivantes:
| classification | nombre |
|---|---|
| Tout public | 20 |
| 13+ | 15 |
| 16+ | 10 |
| 18+ | 5 |
Quand je demande des recommandations
Alors je vois 35 contenus (Tout public + 13+) Et les contenus 16+ et 18+ ne sont pas proposés
5. Utilisateur 18+ voit tous les contenus
Étant donné que je suis un utilisateur de 25 ans Et qu'il existe des contenus avec toutes les classifications
Quand je demande des recommandations
Alors je vois tous les contenus sans restriction Et aucun filtre d'âge n'est appliqué
6. Mode Kids activé automatiquement pour les moins de 13 ans
Étant donné que je m'inscris avec une date de naissance "2013-01-21"
Alors le mode Kids est activé automatiquement Et je vois uniquement du contenu "Tout public" Et des protections supplémentaires sont appliquées
7. Modérateur reclassifie un contenu mal catégorisé
Étant donné qu'un contenu est publié avec la classification "Tout public" Et que ce contenu contient du langage inapproprié détecté en modération
Quand le modérateur reclassifie ce contenu en "16+"
Alors la nouvelle classification est appliquée immédiatement Et le contenu n'est plus visible pour les utilisateurs de moins de 16 ans Et le créateur reçoit une notification de reclassification
8. Strike si classification volontairement incorrecte
Étant donné qu'un créateur a publié un contenu "18+" classifié comme "Tout public" Et que ce contenu a été signalé
Quand le modérateur confirme la mauvaise classification volontaire
Alors le créateur reçoit 1 strike Et le contenu est reclassifié en "18+" Et le créateur reçoit une notification explicative
9. Créateur peut voir la distribution d'âge de son audience
Étant donné que je suis un créateur Et que j'ai publié des contenus avec différentes classifications
Quand je consulte mes statistiques
Alors je vois la répartition des âges de mes auditeurs:
| tranche_age | pourcentage |
|---|---|
| 13-15 ans | 15% |
| 16-17 ans | 20% |
| 18+ ans | 65% |
10. Recherche filtrée par classification d'âge
Étant donné que je suis un utilisateur de 16 ans
Quand je recherche des contenus
Alors les résultats incluent uniquement:
| classification |
|---|
| Tout public |
| 13+ |
Et je ne vois pas les contenus 16+ et 18+ dans les résultats
11. Notification si tentative d'accès à contenu non autorisé
Étant donné que je suis un utilisateur de 14 ans Et qu'un contenu "16+" est partagé avec moi via un lien direct
Quand j'essaie d'accéder au contenu
Alors l'accès est refusé Et je vois le message "Ce contenu est réservé aux utilisateurs de 16 ans et plus"
12. Validation obligatoire des 3 premiers contenus inclut la classification
Étant donné que je suis un nouveau créateur Et que je publie mon premier contenu classifié "18+"
Quand le modérateur valide mon contenu
Alors il vérifie que la classification "18+" est appropriée Et peut la modifier si nécessaire avant validation
13. Statistiques de classification dans l'interface créateur
Étant donné que je suis un créateur
Quand je consulte mes contenus publiés
Alors je vois pour chaque contenu:
| information | exemple |
|---|---|
| Classification actuelle | 13+ |
| Nombre de signalements | 2 |
| Reclassifications | Aucune / 1× par modérateur |
Connexion utilisateur
En tant qu'utilisateur existant Je veux me connecter à mon compte Afin d'accéder à mes contenus et paramètres
11 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un utilisateur existe avec: | email | mot_de_passe | |---|---| | user@test.fr | Password123 |
1. Connexion réussie avec identifiants valides
Quand je me connecte avec:
| email | mot_de_passe |
|---|---|
| user@test.fr | Password123 |
Alors je suis connecté avec succès Et je reçois un access token valide pour 15 minutes Et je reçois un refresh token valide pour 30 jours
2. Connexion échouée avec email inexistant
Quand je me connecte avec l'email "inexistant@test.fr"
Alors la connexion échoue Et je vois le message "Email ou mot de passe incorrect"
3. Connexion échouée avec mot de passe incorrect
Quand je me connecte avec:
| email | mot_de_passe |
|---|---|
| user@test.fr | MauvaisPass1 |
Alors la connexion échoue Et je vois le message "Email ou mot de passe incorrect"
4. Blocage après 5 tentatives échouées
Étant donné que j'ai échoué 4 tentatives de connexion
Quand j'échoue une 5ème tentative de connexion
Alors mon compte est temporairement bloqué Et je vois le message "Compte bloqué pour 15 minutes après 5 tentatives échouées" Et je reçois un email de notification de blocage
5. Tentative de connexion pendant le blocage
Étant donné que mon compte est bloqué suite à 5 tentatives échouées Et que seulement 5 minutes se sont écoulées
Quand j'essaie de me connecter avec les bons identifiants
Alors la connexion échoue Et je vois le message "Compte bloqué. Réessayez dans 10 minutes"
6. Déblocage automatique après 15 minutes
Étant donné que mon compte est bloqué suite à 5 tentatives échouées Et que 15 minutes se sont écoulées
Quand je me connecte avec les bons identifiants
Alors je suis connecté avec succès Et le compteur de tentatives est réinitialisé
7. Reset du compteur après connexion réussie
Étant donné que j'ai échoué 3 tentatives de connexion
Quand je me connecte avec les bons identifiants
Alors je suis connecté avec succès Et le compteur de tentatives est remis à 0
8. Reset automatique du compteur après 15 minutes sans blocage
Étant donné que j'ai échoué 3 tentatives de connexion Et que 15 minutes se sont écoulées sans nouvelle tentative
Quand je consulte mon compteur de tentatives
Alors le compteur est réinitialisé à 0
9. Déblocage via lien "Mot de passe oublié"
Étant donné que mon compte est bloqué suite à 5 tentatives échouées
Quand j'utilise la fonction "Mot de passe oublié" Et que je réinitialise mon mot de passe
Alors le blocage est levé immédiatement Et je peux me connecter avec le nouveau mot de passe
10. Email de notification lors d'un blocage
Étant donné que j'ai échoué 5 tentatives de connexion
Alors je reçois un email avec:
| sujet | Tentatives de connexion suspectes détectées |
|---|---|
| contenu_contient | Votre compte a été temporairement bloqué |
| lien_mot_de_passe | présent |
11. Connexion multi-device simultanée autorisée
Étant donné que je suis connecté sur un appareil iOS
Quand je me connecte également sur un appareil Android
Alors les deux sessions sont actives simultanément Et je peux utiliser l'application sur les deux appareils
Inscription utilisateur
En tant que nouvel utilisateur Je veux créer un compte avec email et mot de passe Afin d'accéder à l'application RoadWave
15 scénarios (14 standards, 1 plan)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que Zitadel est configuré
1. Inscription réussie avec données valides
Étant donné que l'email "nouveau@example.com" n'existe pas
Quand je m'inscris avec les données suivantes:
| champ | valeur |
|---|---|
| email | nouveau@example.com |
| mot_de_passe | Password123 |
| pseudo | nouveau_user |
| date_naissance | 1995-06-15 |
Alors mon compte est créé avec succès Et je reçois un email de vérification Et le lien de vérification expire dans 7 jours Et je suis redirigé vers l'application
2. Inscription avec email déjà existant
Étant donné qu'un utilisateur existe avec l'email "existant@example.com"
Quand je m'inscris avec l'email "existant@example.com"
Alors l'inscription échoue Et je vois le message "Cet email est déjà utilisé"
3. Inscription avec mot de passe invalide - trop court
Quand je m'inscris avec un mot de passe de moins de 8 caractères "Pass1"
Alors l'inscription échoue Et je vois le message "Le mot de passe doit contenir au moins 8 caractères"
4. Inscription avec mot de passe invalide - sans majuscule
Quand je m'inscris avec un mot de passe sans majuscule "password123"
Alors l'inscription échoue Et je vois le message "Le mot de passe doit contenir au moins une majuscule"
5. Inscription avec mot de passe invalide - sans chiffre
Quand je m'inscris avec un mot de passe sans chiffre "Password"
Alors l'inscription échoue Et je vois le message "Le mot de passe doit contenir au moins un chiffre"
6. Inscription avec pseudo invalide - trop court
Quand je m'inscris avec un pseudo de 2 caractères "ab"
Alors l'inscription échoue Et je vois le message "Le pseudo doit contenir entre 3 et 30 caractères"
7. Inscription avec pseudo invalide - caractères spéciaux
Quand je m'inscris avec un pseudo contenant des caractères spéciaux "user@123"
Alors l'inscription échoue Et je vois le message "Le pseudo ne peut contenir que des lettres, chiffres et underscores"
8. Inscription avec email invalide
Quand je m'inscris avec un email invalide "email.invalide"
Alors l'inscription échoue Et je vois le message "Format d'email invalide"
9. 📋 Plan: Inscription avec âge minimum non respecté
Étant donné la date du jour est "2026-01-21"
Quand je m'inscris avec une date de naissance "<date_naissance>"
Alors l'inscription échoue Et je vois le message "Vous devez avoir au moins 13 ans pour créer un compte"
📊 Exemples de données:
| date_naissance | age |
|---|---|
| 2013-01-22 | 12 |
| 2015-06-15 | 10 |
| 2020-01-01 | 6 |
10. Inscription avec âge limite acceptable (13 ans)
Étant donné la date du jour est "2026-01-21"
Quand je m'inscris avec une date de naissance "2013-01-21"
Alors mon compte est créé avec succès Et le mode Kids est activé automatiquement
11. Inscription avec âge supérieur à 18 ans
Étant donné la date du jour est "2026-01-21"
Quand je m'inscris avec une date de naissance "1990-06-15"
Alors mon compte est créé avec succès Et j'ai accès à tous les contenus sans restriction d'âge
12. Données minimales requises à l'inscription
Quand je m'inscris sans fournir de nom complet Et sans fournir de photo de profil Et sans fournir de bio
Alors mon compte est créé avec succès Et un avatar par défaut est généré Et les champs optionnels sont vides
13. Renvoyer l'email de vérification
Étant donné que je me suis inscrit avec l'email "nouveau@example.com" Et que je n'ai pas vérifié mon email
Quand je demande à renvoyer l'email de vérification
Alors un nouvel email de vérification est envoyé Et le précédent lien est invalidé
14. Limite de renvoi d'email de vérification
Étant donné que je me suis inscrit avec l'email "nouveau@example.com" Et que j'ai déjà renvoyé l'email de vérification 3 fois aujourd'hui
Quand je demande à renvoyer l'email de vérification une 4ème fois
Alors la demande échoue Et je vois le message "Vous avez atteint la limite de 3 renvois par jour"
15. Expiration du lien de vérification
Étant donné que je me suis inscrit il y a 8 jours Et que je n'ai pas vérifié mon email
Quand j'essaie d'utiliser le lien de vérification
Alors la vérification échoue Et je vois le message "Ce lien a expiré" Et je peux demander un nouveau lien
Récupération de compte
En tant qu'utilisateur ayant oublié son mot de passe Je veux pouvoir réinitialiser mon mot de passe via email Afin de récupérer l'accès à mon compte
14 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un utilisateur existe avec l'email "user@test.fr"
1. Demander la réinitialisation du mot de passe
Quand je clique sur "Mot de passe oublié" Et que je saisis mon email "user@test.fr"
Alors je reçois un email avec un lien de réinitialisation Et le lien expire dans 1 heure Et je vois le message "Email de réinitialisation envoyé"
2. Email inexistant lors de la demande de réinitialisation
Quand je demande une réinitialisation pour l'email "inexistant@test.fr"
Alors je vois le même message "Email de réinitialisation envoyé" Mais aucun email n'est envoyé (sécurité - pas d'énumération d'emails)
3. Réinitialiser le mot de passe avec un lien valide
Étant donné que j'ai demandé une réinitialisation de mot de passe Et que j'ai reçu le lien de réinitialisation
Quand je clique sur le lien Et que je saisis un nouveau mot de passe "NouveauPass123" Et que je confirme le nouveau mot de passe "NouveauPass123"
Alors mon mot de passe est modifié avec succès Et je suis déconnecté de tous mes appareils sauf celui en cours Et je reçois un email de confirmation de changement
4. Lien de réinitialisation expiré
Étant donné que j'ai demandé une réinitialisation il y a 2 heures
Quand j'essaie d'utiliser le lien
Alors je vois le message "Ce lien a expiré" Et je peux demander un nouveau lien
5. Nouveau mot de passe ne respecte pas les règles
Étant donné que j'ai un lien de réinitialisation valide
Quand je saisis un nouveau mot de passe "faible"
Alors la réinitialisation échoue Et je vois le message "Le mot de passe doit contenir au moins 8 caractères, 1 majuscule et 1 chiffre"
6. Confirmation du mot de passe ne correspond pas
Étant donné que j'ai un lien de réinitialisation valide
Quand je saisis un nouveau mot de passe "NouveauPass123" Et que je confirme avec un mot de passe différent "AutrePass123"
Alors la réinitialisation échoue Et je vois le message "Les mots de passe ne correspondent pas"
7. Limite de demandes de réinitialisation
Étant donné que j'ai déjà demandé 3 réinitialisations dans la dernière heure
Quand je demande une 4ème réinitialisation
Alors la demande échoue Et je vois le message "Maximum 3 demandes par heure. Réessayez plus tard."
8. Compteur de demandes se réinitialise après 1 heure
Étant donné que j'ai demandé 3 réinitialisations Et que 1 heure s'est écoulée
Quand je demande une nouvelle réinitialisation
Alors la demande réussit Et je reçois un email avec un nouveau lien
9. Email de notification de changement de mot de passe
Étant donné que je viens de réinitialiser mon mot de passe
Alors je reçois un email de confirmation avec:
| sujet | Votre mot de passe a été modifié |
|---|---|
| contenu_contient | Votre mot de passe a été modifié |
| date_heure | présente |
| appareil | présent |
| localisation | présente |
| action_urgence | Lien si ce n'était pas vous |
10. Notification push si changement depuis appareil non reconnu
Étant donné que je me suis toujours connecté depuis mon iPhone Et que je réinitialise mon mot de passe depuis un PC Windows
Alors je reçois une notification push sur mon iPhone avec:
| titre | Mot de passe modifié |
|---|---|
| message | Depuis Windows - Paris, France |
| action | Sécuriser le compte si ce n'est pas vous |
11. Déconnexion de tous les appareils après réinitialisation
Étant donné que je suis connecté sur 4 appareils différents Et que je réinitialise mon mot de passe depuis un navigateur web
Alors les 3 autres appareils sont déconnectés immédiatement Et seule la session du navigateur web reste active Et je vois le message "Vous avez été déconnecté des autres appareils par sécurité"
12. Lien de réinitialisation invalide si déjà utilisé
Étant donné que j'ai réinitialisé mon mot de passe avec un lien
Quand j'essaie de réutiliser le même lien
Alors je vois le message "Ce lien a déjà été utilisé" Et je peux demander un nouveau lien si nécessaire
13. Nouveau lien invalide l'ancien
Étant donné que j'ai demandé une réinitialisation et reçu un lien
Quand je demande une nouvelle réinitialisation
Alors l'ancien lien est invalidé Et seul le nouveau lien fonctionne
14. Réinitialisation débloque un compte bloqué
Étant donné que mon compte est bloqué après 5 tentatives de connexion
Quand je réinitialise mon mot de passe via email
Alors le blocage est levé immédiatement Et je peux me connecter avec le nouveau mot de passe Et le compteur de tentatives est remis à 0
Gestion des sessions et tokens
En tant qu'utilisateur connecté Je veux que mes sessions soient sécurisées et gérées automatiquement Afin de maintenir l'accès à l'application sans friction
13 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis connecté avec succès
1. Access token expire après 15 minutes
Étant donné que j'ai reçu un access token Et que 15 minutes se sont écoulées
Quand je fais une requête API avec cet access token
Alors la requête échoue avec le code 401 Et je vois le message "Token expiré"
2. Refresh automatique du token avec refresh token
Étant donné que mon access token a expiré Et que mon refresh token est valide
Quand l'application demande un nouveau access token
Alors je reçois un nouvel access token valide pour 15 minutes Et je reçois un nouveau refresh token (rotation) Et l'ancien refresh token est invalidé
3. Refresh token expire après 30 jours d'inactivité
Étant donné que je me suis connecté il y a 30 jours Et que je n'ai pas utilisé l'application depuis
Quand j'essaie d'utiliser mon refresh token
Alors la requête échoue Et je dois me reconnecter avec email/password
4. Prolongation automatique de la session si l'app est utilisée
Étant donné que je me suis connecté il y a 25 jours Et que j'utilise l'application régulièrement
Quand je fais une requête API
Alors ma session est automatiquement prolongée Et mon refresh token reste valide
5. Détection de token replay attack
Étant donné que j'ai rafraîchi mon token Et que j'ai reçu un nouveau refresh token
Quand j'essaie de réutiliser l'ancien refresh token
Alors la requête échoue Et je vois le message "Token invalide ou révoqué" Et toutes mes sessions sont révoquées par sécurité
6. Voir la liste des appareils connectés
Étant donné que je suis connecté sur 3 appareils différents
Quand je consulte la liste de mes appareils connectés
Alors je vois 3 appareils avec les informations suivantes:
| information | exemple |
|---|---|
| OS | iOS 17.1 |
| Navigateur | Safari |
| Dernière connexion | Il y a 2 heures |
| Localisation | Paris, France (IP visible) |
7. Révoquer un appareil spécifique
Étant donné que je suis connecté sur mon iPhone et mon iPad
Quand je révoque la session de mon iPad depuis les paramètres
Alors la session iPad est immédiatement déconnectée Et ma session iPhone reste active
8. Déconnecter tous les appareils sauf celui en cours
Étant donné que je suis connecté sur 4 appareils
Quand je clique sur "Déconnecter tous les appareils"
Alors les 3 autres appareils sont déconnectés Et seul l'appareil actuel reste connecté
9. Alerte de connexion depuis nouveau device
Étant donné que je me suis toujours connecté depuis Paris
Quand je me connecte depuis un nouvel appareil à Lyon
Alors je reçois une notification push sur mes autres appareils Et je reçois un email avec:
| sujet | Nouvelle connexion détectée |
|---|---|
| localisation | Lyon, France |
| appareil | Android 14 - Chrome |
| action | Lien pour révoquer la session |
10. Alerte de connexion suspecte depuis pays différent
Étant donné que je me suis toujours connecté depuis la France
Quand je me connecte depuis un appareil aux États-Unis
Alors je reçois une notification push immédiate Et je reçois un email d'alerte de sécurité Et la nouvelle session nécessite une validation 2FA même si désactivée
11. Déconnexion après 30 jours d'inactivité totale
Étant donné que je ne me suis pas connecté depuis 30 jours
Quand j'ouvre l'application
Alors je suis automatiquement déconnecté Et je dois me reconnecter avec email/password Et je vois le message "Session expirée après 30 jours d'inactivité"
12. Sessions multiples simultanées autorisées
Étant donné que je suis connecté sur:
| appareil |
|---|
| iPhone |
| iPad |
| PC Windows (Web) |
Quand je fais des actions sur les 3 appareils simultanément
Alors toutes les sessions fonctionnent sans conflit Et chaque appareil maintient sa propre session
13. Validation de JWT via Zitadel
Étant donné que j'ai reçu un access token JWT
Quand l'API RoadWave valide le token
Alors la validation est faite localement avec la clé publique Zitadel Et aucune requête externe n'est effectuée (performance) Et le token contient les claims suivants:
| claim | valeur_exemple |
|---|---|
| sub | user-id-123 |
| email | user@test.fr |
| exp | timestamp + 15 minutes |
| iss | zitadel.roadwave.com |
Authentification à deux facteurs (2FA)
En tant qu'utilisateur soucieux de sécurité Je veux activer la 2FA sur mon compte Afin de protéger mon accès même si mon mot de passe est compromis
16 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis connecté à mon compte
1. Activer la 2FA TOTP (Time-based One-Time Password)
Étant donné que la 2FA n'est pas activée sur mon compte
Quand je choisis d'activer la 2FA TOTP
Alors je vois un QR code à scanner Et je vois le secret partagé en texte clair (backup) Et je dois entrer un code de vérification depuis mon app authenticator
Quand je saisis un code TOTP valide
Alors la 2FA TOTP est activée avec succès Et je reçois des codes de backup (10 codes)
2. Connexion avec 2FA TOTP activée
Étant donné que la 2FA TOTP est activée sur mon compte
Quand je me connecte avec email/password
Alors je suis redirigé vers la page de saisie du code 2FA
Quand je saisis un code TOTP valide de mon authenticator
Alors je suis connecté avec succès
3. Connexion échouée avec code TOTP invalide
Étant donné que la 2FA TOTP est activée
Quand je me connecte avec email/password Et que je saisis un code TOTP invalide "000000"
Alors la connexion échoue Et je vois le message "Code d'authentification invalide" Et je peux réessayer
4. Utiliser un code de backup pour 2FA
Étant donné que la 2FA TOTP est activée Et que j'ai perdu l'accès à mon authenticator
Quand je me connecte avec email/password Et que je clique sur "Utiliser un code de backup" Et que je saisis un code de backup valide
Alors je suis connecté avec succès Et le code de backup utilisé est invalidé Et il me reste 9 codes de backup
5. Activer la 2FA par email
Étant donné que la 2FA n'est pas activée
Quand je choisis d'activer la 2FA par email
Alors la 2FA email est activée immédiatement Et je vois le message "2FA email activée. Vous recevrez un code à chaque connexion"
6. Connexion avec 2FA email
Étant donné que la 2FA email est activée
Quand je me connecte avec email/password
Alors je reçois un email avec un code à 6 chiffres Et le code expire dans 10 minutes Et je dois saisir ce code pour terminer la connexion
7. Code 2FA email expiré
Étant donné que la 2FA email est activée Et que je me suis connecté avec email/password Et que j'ai reçu un code 2FA par email il y a 11 minutes
Quand je saisis ce code
Alors la connexion échoue Et je vois le message "Code expiré. Demandez un nouveau code."
8. Renvoyer le code 2FA email
Étant donné que la 2FA email est activée Et que je suis sur la page de saisie du code 2FA
Quand je clique sur "Renvoyer le code"
Alors je reçois un nouveau code par email Et l'ancien code est invalidé
9. Ajouter un appareil de confiance (skip 2FA pendant 30 jours)
Étant donné que la 2FA TOTP est activée
Quand je me connecte avec email/password et code TOTP Et que je coche "Ne plus demander sur cet appareil"
Alors je suis connecté avec succès Et cet appareil est enregistré comme "appareil de confiance"
Quand je me reconnecte dans les 30 jours suivants sur ce même appareil
Alors je ne dois pas saisir de code 2FA
10. Appareil de confiance expire après 30 jours
Étant donné que j'ai enregistré un appareil de confiance il y a 31 jours
Quand je me connecte depuis cet appareil
Alors je dois saisir un code 2FA Et je vois le message "Appareil de confiance expiré. Veuillez vous authentifier"
11. Voir la liste des appareils de confiance
Étant donné que j'ai enregistré 3 appareils de confiance
Quand je consulte mes paramètres de sécurité
Alors je vois la liste de mes 3 appareils de confiance avec:
| information | exemple |
|---|---|
| Nom | iPhone 13 - Safari |
| Date ajout | 15 janvier 2026 |
| Dernière vue | Il y a 2 heures |
| Expire le | 14 février 2026 |
12. Révoquer un appareil de confiance
Étant donné que j'ai un iPhone enregistré comme appareil de confiance
Quand je révoque cet appareil depuis les paramètres
Alors l'appareil est supprimé de la liste
Quand je me reconnecte depuis cet iPhone
Alors je dois saisir un code 2FA
13. Révoquer tous les appareils de confiance
Étant donné que j'ai 5 appareils de confiance enregistrés
Quand je clique sur "Révoquer tous les appareils de confiance"
Alors tous les appareils sont révoqués Et je vois le message "Tous les appareils de confiance ont été révoqués"
14. 2FA forcée pour connexion suspecte malgré appareil de confiance
Étant donné que j'ai un appareil de confiance enregistré en France Et que je me connecte depuis ce même appareil mais avec une IP américaine
Quand je tente de me connecter
Alors la 2FA est requise malgré l'appareil de confiance Et je vois le message "Connexion suspecte détectée. Authentification requise."
15. Désactiver la 2FA
Étant donné que la 2FA TOTP est activée
Quand je désactive la 2FA depuis mes paramètres Et que je confirme avec mon mot de passe
Alors la 2FA est désactivée Et tous les codes de backup sont invalidés Et tous les appareils de confiance sont révoqués
16. Régénérer les codes de backup
Étant donné que la 2FA est activée Et que j'ai utilisé 8 codes de backup sur 10
Quand je demande à régénérer les codes de backup
Alors je reçois 10 nouveaux codes Et tous les anciens codes (utilisés ou non) sont invalidés
Vérification d'email
En tant qu'utilisateur inscrit Je veux vérifier mon adresse email Afin d'accéder à toutes les fonctionnalités selon mon rôle
10 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible
1. Auditeur avec email non vérifié - lecture illimitée
Étant donné que je suis un auditeur avec email non vérifié
Quand j'essaie d'écouter du contenu
Alors je peux écouter tous les contenus sans limite
2. Auditeur avec email non vérifié - création limitée à 5 contenus
Étant donné que je suis un auditeur avec email non vérifié Et que j'ai créé 4 contenus
Quand je crée un 5ème contenu
Alors le contenu est créé avec succès Mais quand j'essaie de créer un 6ème contenu Alors la création échoue Et je vois le message "Vérifiez votre email pour créer plus de contenus"
3. Rappel de vérification après le 3ème contenu créé
Étant donné que je suis un auditeur avec email non vérifié Et que j'ai créé 2 contenus
Quand je crée mon 3ème contenu
Alors le contenu est créé avec succès Et je vois une notification in-app "Vérifiez votre email pour débloquer la création illimitée"
4. Auditeur vérifie son email
Étant donné que je suis un auditeur avec email non vérifié Et que j'ai reçu un lien de vérification
Quand je clique sur le lien de vérification dans l'email
Alors mon email est marqué comme vérifié Et je vois le message "Email vérifié avec succès" Et toutes les fonctionnalités sont débloquées
5. Créateur doit vérifier son email sous 7 jours pour monétisation
Étant donné que je suis inscrit comme créateur Et que mon email n'est pas vérifié Et que je remplis les conditions de monétisation
Quand j'essaie d'accéder au programme de monétisation
Alors l'accès est refusé Et je vois le message "Vérifiez votre email pour accéder à la monétisation"
6. Créateur ne peut pas publier de contenus illimités sans vérification
Étant donné que je suis un créateur avec email non vérifié Et que j'ai créé 5 contenus
Quand j'essaie de créer un 6ème contenu
Alors la création échoue Et je vois le message "Vérifiez votre email pour publier des contenus illimités"
7. Créateur vérifie son email et déboque tout
Étant donné que je suis un créateur avec email non vérifié Et que j'ai reçu un lien de vérification
Quand je clique sur le lien de vérification
Alors mon email est marqué comme vérifié Et je peux publier des contenus illimités Et je peux accéder au programme de monétisation si j'en remplis les conditions
8. KYC impossible sans email vérifié
Étant donné que je suis un créateur avec email non vérifié
Quand j'essaie de compléter le KYC via Mangopay
Alors l'accès au KYC est refusé Et je vois le message "Vérifiez votre email avant de procéder au KYC"
9. Tentative de vérification avec un lien déjà utilisé
Étant donné que j'ai déjà vérifié mon email avec un lien
Quand j'essaie de réutiliser le même lien de vérification
Alors la vérification échoue Et je vois le message "Ce lien a déjà été utilisé"
10. Auditeur vérifié peut créer plus de 5 contenus
Étant donné que je suis un auditeur avec email vérifié Et que j'ai créé 10 contenus
Quand je crée un 11ème contenu
Alors le contenu est créé avec succès Et il n'y a pas de limite de création
Métadonnées et publication de contenu
En tant que créateur Je veux remplir les métadonnées de mon contenu Afin de le publier sur RoadWave
34 scénarios (32 standards, 2 plans)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis un créateur connecté Et que mon fichier audio est encodé et prêt
1. Publication avec toutes les métadonnées obligatoires
Quand je remplis les métadonnées suivantes:
| champ | valeur |
|---|---|
| Titre | Histoire de la Tour Eiffel |
| Type géo | Ancré |
| Zone | Point GPS (48.8584, 2.2945, 500m) |
| Tags | Voyage, Culture générale |
| Classification âge | Tout public |
Alors la publication réussit Et mon contenu est soumis pour validation
2. Titre valide entre 5 et 100 caractères
Quand je saisis un titre de 50 caractères
Alors le titre est accepté Et la validation passe
3. Titre trop court (<5 caractères)
Quand je saisis un titre de 4 caractères "Test"
Alors la publication échoue Et je vois le message "Le titre doit contenir entre 5 et 100 caractères"
4. Titre trop long (>100 caractères)
Quand je saisis un titre de 101 caractères
Alors la publication échoue Et je vois le message "Le titre doit contenir entre 5 et 100 caractères"
5. Titre à exactement 5 caractères accepté
Quand je saisis un titre de exactement 5 caractères "Titre"
Alors le titre est accepté
6. Titre à exactement 100 caractères accepté
Quand je saisis un titre de exactement 100 caractères
Alors le titre est accepté
7. Sélectionner type géo "Ancré"
Quand je sélectionne le type géo "Ancré"
Alors le système applique une pondération géo de 0.7 Et je dois définir une zone de diffusion précise
8. Sélectionner type géo "Contextuel"
Quand je sélectionne le type géo "Contextuel"
Alors le système applique une pondération géo de 0.5 Et je peux définir une zone ville/département/région
9. Sélectionner type géo "Neutre"
Quand je sélectionne le type géo "Neutre"
Alors le système applique une pondération géo de 0.2 Et je peux définir une zone nationale
10. Zone diffusion - Point GPS avec rayon
Quand je choisis "Point GPS" Et que je définis les coordonnées (48.8584, 2.2945) Et que je définis un rayon de 500 mètres
Alors la zone est validée Et le contenu sera diffusé dans un rayon de 500m autour du point
11. Zone diffusion - Rayon minimum 100m
Quand je définis un rayon de 50 mètres (< 100m)
Alors la validation échoue Et je vois le message "Le rayon doit être entre 100m et 10km"
12. Zone diffusion - Rayon maximum 10km
Quand je définis un rayon de 15 km (> 10km)
Alors la validation échoue Et je vois le message "Le rayon doit être entre 100m et 10km"
13. Zone diffusion - Ville depuis référentiel INSEE
Quand je choisis "Ville"
Alors je vois une liste de villes du référentiel INSEE
Quand je sélectionne "Paris (75000)"
Alors la zone est définie sur toute la ville de Paris
14. Zone diffusion - Département
Quand je choisis "Département" Et que je sélectionne "Ille-et-Vilaine (35)"
Alors la zone couvre tout le département 35
15. Zone diffusion - Région
Quand je choisis "Région" Et que je sélectionne "Bretagne"
Alors la zone couvre toute la région Bretagne
16. Zone diffusion - National
Quand je choisis "National"
Alors la zone couvre toute la France Et aucune restriction géographique n'est appliquée
17. Zones mutuellement exclusives
Étant donné que j'ai sélectionné "Point GPS"
Quand j'essaie de sélectionner également "Ville"
Alors la première sélection est remplacée Et seule "Ville" reste active
18. Sélectionner 1 tag minimum
Quand je sélectionne 1 tag "Voyage"
Alors la validation passe Et le contenu est tagué "Voyage"
19. Sélectionner 3 tags maximum
Quand je sélectionne 3 tags "Automobile", "Technologie", "Sport"
Alors la validation passe Et le contenu est tagué avec les 3 tags
20. Impossible de sélectionner 0 tag
Quand j'essaie de publier sans sélectionner de tag
Alors la publication échoue Et je vois le message "Vous devez sélectionner entre 1 et 3 tags"
21. Impossible de sélectionner 4 tags
Quand j'essaie de sélectionner 4 tags
Alors le 4ème tag ne peut pas être ajouté Et je vois le message "Maximum 3 tags"
22. Tags disponibles dans la liste
Quand je consulte la liste des tags
Alors je vois les tags suivants:
| tag |
|---|
| Automobile |
| Voyage |
| Famille |
| Amour |
| Musique |
| Économie |
| Cryptomonnaie |
| Politique |
| Culture générale |
| Sport |
| Technologie |
| Santé |
23. Classification âge obligatoire
Quand j'essaie de publier sans classification âge
Alors la publication échoue Et je vois le message "Vous devez sélectionner une classification d'âge"
24. 📋 Plan: Sélectionner classification âge
Quand je sélectionne la classification ""
Alors le contenu sera visible pour "<public_cible>"
📊 Exemples de données:
| classification | public_cible |
|---|---|
| Tout public | Tous les utilisateurs |
| 13+ | Utilisateurs 13 ans et plus |
| 16+ | Utilisateurs 16 ans et plus |
| 18+ | Utilisateurs 18 ans et plus |
25. Image de couverture auto-générée selon type géo
Étant donné que je choisis le type géo "Ancré" Et que mon tag principal est "Voyage"
Quand la publication est soumise
Alors une image de couverture est générée automatiquement:
| paramètre | valeur |
|---|---|
| Icône | 📍 (Ancré) |
| Couleur | Bleu-vert (Voyage) |
| Format | 800×800px PNG |
26. Image de couverture type Contextuel
Étant donné que je choisis "Contextuel"
Quand l'image est générée
Alors l'icône est 🌍 (Contextuel)
27. Image de couverture type Neutre
Étant donné que je choisis "Neutre"
Quand l'image est générée
Alors l'icône est 🎧 (Neutre)
28. 📋 Plan: Couleur selon tag principal
Étant donné que mon tag principal est ""
Quand l'image est générée
Alors la couleur de fond est ""
📊 Exemples de données:
| tag | couleur |
|---|---|
| Automobile | Bleu |
| Voyage | Vert |
| Musique | Rouge |
| Économie | Gris |
| Sport | Orange |
29. Champs optionnels non obligatoires
Quand je publie sans description Et sans image de couverture personnalisée
Alors la publication réussit Et les champs optionnels restent vides Et une image par défaut est générée
30. Temps de publication estimé 2 minutes
Étant donné que mon fichier audio est prêt
Quand je commence à remplir les métadonnées
Alors je peux publier en environ 2 minutes
31. Publication rapide sans friction
Quand je publie mon premier contenu
Alors aucun champ complexe n'est demandé Et je ne suis pas bloqué sur description ou image Et la publication est fluide
32. Prévisualisation avant publication
Étant donné que j'ai rempli toutes les métadonnées
Quand je clique sur "Prévisualiser"
Alors je vois un aperçu de mon contenu:
| élément | affiché |
|---|---|
| Titre | ✅ |
| Image couverture | ✅ |
| Tags | ✅ |
| Zone diffusion | ✅ |
| Durée audio | ✅ |
| Classification | ✅ |
33. Enregistrer brouillon
Étant donné que j'ai commencé à remplir les métadonnées
Quand je clique sur "Enregistrer brouillon"
Alors mes métadonnées sont sauvegardées Et je peux reprendre la publication plus tard
34. Reprendre brouillon
Étant donné que j'ai un brouillon sauvegardé
Quand j'accède à mes contenus
Alors je vois le brouillon avec statut "📝 Brouillon" Et je peux reprendre la publication
Modification et suppression de contenu
En tant que créateur Je veux pouvoir modifier ou supprimer mes contenus Afin de garder le contrôle sur mes publications
30 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis un créateur connecté Et que j'ai publié un contenu
1. Modifier le titre d'un contenu
Étant donné que mon contenu a le titre "Histoire de Paris"
Quand je modifie le titre en "Histoire fascinante de Paris"
Alors la modification est enregistrée immédiatement Et je vois le message "Titre modifié avec succès"
2. Correction de coquilles dans le titre
Étant donné que mon titre contient une faute "Histoore de Paris"
Quand je corrige en "Histoire de Paris"
Alors la modification est acceptée Et le titre corrigé est affiché
3. Ajouter une description ultérieurement
Étant donné que j'ai publié sans description
Quand j'ajoute une description "Découvrez l'histoire de la capitale"
Alors la description est enregistrée Et elle est visible sur la page du contenu
4. Modifier la description existante
Étant donné que mon contenu a déjà une description
Quand je modifie la description
Alors la nouvelle description remplace l'ancienne Et la modification est immédiate
5. Modifier les tags pour ajuster pertinence
Étant donné que mon contenu est tagué "Sport", "Musique"
Quand je change les tags en "Sport", "Santé"
Alors les nouveaux tags sont appliqués Et l'algorithme utilise les nouveaux tags pour recommandations
6. Personnaliser l'image de couverture
Étant donné que mon contenu a une image auto-générée
Quand j'uploade une image personnalisée 800×800px
Alors l'image personnalisée remplace l'image par défaut Et elle est visible sur le contenu
7. Impossible de modifier l'audio
Étant donné que mon contenu audio est publié
Quand j'essaie de remplacer le fichier audio
Alors la modification est refusée Et je vois le message "L'audio ne peut pas être modifié après publication"
8. Raison - Éviter fraude audio
Étant donné que je veux changer l'audio après validation
Quand j'essaie de modifier
Alors le système refuse pour éviter:
| risque |
|---|
| Uploader contenu validé puis remplacer spam |
| Fraude sur l'intégrité du contenu |
9. Impossible de modifier la zone de diffusion
Étant donné que mon contenu est diffusé à Paris
Quand j'essaie de changer la zone en "National"
Alors la modification est refusée Et je vois le message "La zone de diffusion ne peut pas être modifiée"
10. Raison - Éviter manipulation algorithme
Étant donné que je veux changer ma zone
Quand j'essaie de modifier
Alors le système refuse pour éviter:
| manipulation |
|---|
| Créer "Local Paris" puis changer en "National" |
| Boost artificiel de visibilité |
11. Impossible de modifier le type géo
Étant donné que mon contenu est type "Neutre" (pondération 0.2)
Quand j'essaie de changer en "Ancré" (pondération 0.7)
Alors la modification est refusée Et je vois le message "Le type géographique ne peut pas être modifié"
12. Raison - Éviter abus de pondération
Étant donné que je veux changer le type géo
Quand j'essaie de modifier
Alors le système refuse pour éviter:
| abus |
|---|
| Créer "Neutre" puis passer en "Ancré" |
| Manipulation de la pondération algorithme |
13. Impossible de modifier la classification âge
Étant donné que mon contenu est classé "Tout public"
Quand j'essaie de changer en "18+"
Alors la modification est refusée Et je vois le message "La classification d'âge ne peut pas être modifiée"
14. Raison - Sécurité mineurs
Étant donné que je veux changer la classification
Quand j'essaie de modifier
Alors le système refuse pour garantir:
| protection |
|---|
| Classification vérifiée en modération |
| Pas de contournement validation |
| Sécurité des mineurs |
15. Solution si besoin de changer audio/zone/classification
Étant donné que je veux absolument changer l'audio
Quand je consulte les options
Alors je vois "Supprimer et republier le contenu" Et c'est la seule solution disponible
16. Republication après suppression - créateur <3 validations
Étant donné que je suis un nouveau créateur (2 contenus validés) Et que je supprime puis republie un contenu
Quand je republie avec les modifications
Alors le contenu repasse en file de validation Et une nouvelle validation est effectuée
17. Republication après suppression - créateur vérifié
Étant donné que je suis créateur vérifié (≥3 contenus validés) Et que je supprime puis republie un contenu
Quand je republie avec les modifications
Alors le contenu est publié immédiatement Et aucune validation préalable n'est requise
18. Suppression de contenu immédiate
Quand je clique sur "Supprimer le contenu" Et que je confirme la suppression
Alors le contenu est supprimé immédiatement Et disparaît de la liste publique
19. Confirmation avant suppression
Quand je clique sur "Supprimer"
Alors je vois un message de confirmation:
| titre | Êtes-vous sûr ? |
|---|---|
| message | Cette action est définitive |
| warning | Le contenu sera supprimé définitivement |
| actions | Confirmer / Annuler |
20. Suppression définitive et non réversible
Étant donné que j'ai supprimé un contenu
Quand j'essaie de le récupérer
Alors la récupération est impossible Et le contenu est définitivement perdu
21. Suppression BDD + CDN sous 5 minutes
Quand je supprime un contenu
Alors l'entrée en base de données est marquée "deleted" Et les fichiers CDN sont marqués pour suppression Et la suppression effective a lieu sous 5 minutes
22. Historique auditeurs conservé anonymisé
Étant donné que 1000 personnes ont écouté mon contenu
Quand je supprime le contenu
Alors leur historique est conservé Mais marqué "Contenu supprimé par créateur" Et la durée d'écoute est conservée pour leurs stats
23. Analytics plateforme anonymisées conservées
Étant donné que mon contenu a généré 10K écoutes
Quand je supprime le contenu
Alors les métriques globales sont conservées anonymement:
| métrique | conservée |
|---|---|
| Total écoutes | ✅ (anonyme) |
| Durée totale | ✅ (anonyme) |
| Catégorie | ✅ (anonyme) |
| Auteur | ❌ (anonymisé) |
Et c'est conforme RGPD
24. Fichiers CDN supprimés sous 24h
Étant donné que mon contenu est supprimé
Quand 24 heures s'écoulent
Alors tous les fichiers audio sont purgés du CDN Bunny Et l'espace de stockage est libéré
25. Pas de notification aux auditeurs
Étant donné que 500 utilisateurs ont écouté mon contenu
Quand je supprime le contenu
Alors aucune notification n'est envoyée aux auditeurs Et il n'y a pas d'effet Streisand
26. Auditeur tente de réécouter contenu supprimé
Étant donné qu'un auditeur a écouté mon contenu Et que j'ai supprimé ce contenu
Quand l'auditeur tente de le réécouter depuis son historique
Alors il voit le message "Ce contenu n'est plus disponible" Et la lecture est impossible
27. Historique auditeur conserve trace
Étant donné qu'un auditeur a écouté mon contenu le 15 janvier Et que je supprime le contenu le 20 janvier
Quand l'auditeur consulte son historique
Alors il voit "Vous avez écouté ce contenu le 15 janvier 2026" Et le titre est remplacé par "Contenu supprimé" Et la date d'écoute est conservée
28. Statistiques créateur après suppression
Étant donné que j'ai publié 10 contenus Et que je supprime 2 contenus
Quand je consulte mes statistiques globales
Alors je vois:
| métrique | valeur |
|---|---|
| Contenus publiés | 8 (actifs) |
| Total historique | 10 |
| Suppressions | 2 |
Et l'historique des suppressions est visible
29. Limite de modifications par contenu
Étant donné que j'ai modifié un titre 10 fois
Quand j'essaie de modifier une 11ème fois
Alors la modification est acceptée
30. Historique des modifications visible
Étant donné que j'ai modifié un contenu plusieurs fois
Quand je consulte l'historique
Alors je vois:
| date | modification |
|---|---|
| 21/01/2026 | Titre changé |
| 20/01/2026 | Tags modifiés |
| 19/01/2026 | Description ajoutée |
Et je peux tracer toutes les modifications
Upload et encodage de contenu audio
En tant que créateur Je veux uploader mon contenu audio Afin qu'il soit encodé et disponible pour les auditeurs
29 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis un créateur connecté
1. Upload fichier MP3 valide
Quand j'uploade un fichier MP3 de 50 MB et 30 minutes
Alors l'upload réussit Et le fichier est envoyé vers Bunny Storage temporaire Et un job d'encodage asynchrone est lancé
2. Upload fichier AAC valide (.aac)
Quand j'uploade un fichier AAC de 80 MB et 1 heure
Alors l'upload réussit Et le fichier est accepté Et l'encodage démarre
3. Upload fichier M4A valide
Quand j'uploade un fichier M4A de 100 MB et 2 heures
Alors l'upload réussit Et le fichier est traité comme AAC Et l'encodage démarre
4. Rejet fichier WAV (non supporté)
Quand j'essaie d'uploader un fichier WAV
Alors l'upload échoue Et je vois le message "Format non supporté. Utilisez MP3 ou AAC (.mp3, .aac, .m4a)"
5. Rejet fichier FLAC (non supporté)
Quand j'essaie d'uploader un fichier FLAC
Alors l'upload échoue Et je vois le message "Format non supporté. Utilisez MP3 ou AAC (.mp3, .aac, .m4a)"
6. Validation taille maximale 200 MB
Quand j'essaie d'uploader un fichier MP3 de 201 MB
Alors l'upload échoue Et je vois le message "Fichier trop volumineux (max 200 MB)"
7. Upload à la limite de 200 MB accepté
Quand j'uploade un fichier MP3 de exactement 200 MB
Alors l'upload réussit Et le fichier est accepté
8. Validation durée maximale 4 heures
Quand j'essaie d'uploader un fichier de 4h 10min
Alors l'upload échoue Et je vois le message "Durée trop longue (max 4 heures)"
9. Upload à la limite de 4h accepté
Quand j'uploade un fichier de exactement 4 heures
Alors l'upload réussit Et le fichier est accepté
10. Validation format côté client
Quand je sélectionne un fichier dans l'interface
Alors la validation du format est faite immédiatement côté client Et je suis informé avant même de lancer l'upload si le format est invalide
11. Double validation côté backend
Étant donné qu'un fichier a passé la validation client
Quand le backend reçoit le fichier
Alors une validation supplémentaire est effectuée Et le format et l'intégrité sont vérifiés
12. Pipeline d'encodage - étape 1 upload
Quand j'uploade un fichier MP3 valide
Alors le fichier est stocké temporairement dans Bunny Storage Et un job d'encodage est mis en file d'attente
13. Pipeline d'encodage - validation format
Étant donné qu'un job d'encodage est lancé
Quand le worker Go traite le fichier
Alors le format est validé avec FFmpeg Et l'intégrité du fichier est vérifiée
14. Pipeline d'encodage - génération 3 profils Opus
Étant donné qu'un fichier audio est validé
Quand l'encodage démarre
Alors 3 profils Opus sont générés:
| qualité | bitrate | usage |
|---|---|---|
| Basse | 24 kbps | 2G/Edge |
| Standard | 48 kbps | 3G |
| Haute | 64 kbps | 4G/5G |
15. Pipeline d'encodage - génération segments HLS
Étant donné que les profils Opus sont générés
Quand l'encodage continue
Alors un fichier manifest .m3u8 est créé Et des segments .ts sont générés Et le contenu est prêt pour streaming HLS
16. Pipeline d'encodage - génération image par défaut
Étant donné que l'encodage est en cours
Quand les métadonnées sont traitées
Alors une image de couverture par défaut est générée Et l'image fait 800×800px au format PNG
17. Pipeline d'encodage - suppression fichier original
Étant donné que l'encodage est terminé avec succès
Quand tous les fichiers de sortie sont générés
Alors le fichier original MP3/AAC est supprimé Et seuls les profils Opus et HLS sont conservés Et l'espace de stockage est économisé
18. Temps d'encodage contenu 5 minutes
Étant donné qu'un fichier de 5 minutes est uploadé
Quand l'encodage démarre
Alors l'encodage prend environ 30 secondes Et je reçois une notification "Contenu prêt à publier"
19. Temps d'encodage podcast 1 heure
Étant donné qu'un fichier de 1 heure est uploadé
Quand l'encodage démarre
Alors l'encodage prend environ 5 minutes Et une barre de progression est affichée
20. Temps d'encodage podcast 4 heures
Étant donné qu'un fichier de 4 heures est uploadé
Quand l'encodage démarre
Alors l'encodage prend environ 20 minutes Et je peux fermer l'app (traitement asynchrone)
21. Notification "Contenu prêt à publier"
Étant donné que mon contenu est en cours d'encodage
Quand l'encodage se termine avec succès
Alors je reçois une notification push "✅ Votre contenu est prêt à publier" Et je peux accéder à l'interface de publication
22. Échec d'encodage - fichier corrompu
Étant donné qu'un fichier MP3 corrompu est uploadé
Quand l'encodage démarre
Alors l'encodage échoue Et je reçois une notification "❌ Erreur d'encodage: fichier corrompu" Et le fichier temporaire est supprimé
23. Écoute accélérée - vitesses disponibles
Étant donné qu'un contenu est publié
Quand un auditeur écoute le contenu
Alors il peut choisir parmi les vitesses:
| vitesse | usage |
|---|---|
| 0.75x | Compréhension difficile |
| 1.0x | Normal (défaut) |
| 1.25x | Gain léger |
| 1.5x | Podcasts longs |
| 2.0x | Survol rapide |
24. Écoute accélérée pour modérateurs
Étant donné que je suis un modérateur Et qu'un contenu de 30 secondes est à valider
Quand je l'écoute à 2.0x
Alors je termine l'écoute en 15 secondes Et ma productivité est doublée
25. Écoute accélérée pour auditeurs
Étant donné que je suis un auditeur Et qu'un podcast de 1 heure est disponible
Quand je configure la vitesse à 1.5x
Alors j'écoute le podcast en 40 minutes Et je gagne 20 minutes
26. Sauvegarde préférence vitesse d'écoute
Étant donné que je configure la vitesse à 1.5x
Quand j'écoute plusieurs contenus
Alors tous les contenus sont lus à 1.5x par défaut Et ma préférence est sauvegardée
27. Scalabilité horizontale des workers
Étant donné que 100 contenus sont uploadés simultanément
Quand les jobs d'encodage sont distribués
Alors plusieurs workers Go traitent les jobs en parallèle Et Kubernetes scale automatiquement les pods Et tous les contenus sont encodés sans délai excessif
28. Statut d'encodage visible
Étant donné que mon contenu est en cours d'encodage
Quand je consulte mes contenus
Alors je vois le statut:
| état | affichage |
|---|---|
| En attente | ⏳ File d'attente |
| En cours | ⚙️ Encodage en cours (45%) |
| Terminé | ✅ Prêt à publier |
| Échec | ❌ Erreur - Réessayer |
29. Réessayer après échec d'encodage
Étant donné que l'encodage de mon contenu a échoué
Quand je clique sur "Réessayer"
Alors un nouveau job d'encodage est lancé Et je peux tenter à nouveau
Validation des 3 premiers contenus
En tant que nouveau créateur Je veux que mes 3 premiers contenus soient validés Afin de devenir créateur vérifié
30 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis un nouveau créateur
1. Premier contenu passe en file de validation
Quand je publie mon premier contenu
Alors le contenu passe en file d'attente modération Et je vois le message "Votre contenu est en cours de validation (24-48h)" Et le contenu n'est pas encore visible publiquement
2. Deuxième contenu passe également en validation
Étant donné que mon premier contenu a été validé
Quand je publie mon deuxième contenu
Alors le contenu passe en file d'attente modération Et le délai estimé est 24-48h
3. Troisième contenu - dernière validation
Étant donné que mes 2 premiers contenus ont été validés
Quand je publie mon troisième contenu
Alors le contenu passe en file d'attente modération Et je vois "Dernière validation avant statut vérifié ✓"
4. Modérateur écoute 30 secondes du contenu
Étant donné qu'un contenu est en file de validation
Quand le modérateur junior l'examine
Alors il écoute les 30 premières secondes Et il vérifie les métadonnées
5. Validation - Qualité audio acceptable
Étant donné qu'un contenu a une qualité audio claire
Quand le modérateur l'écoute
Alors il vérifie que l'audio est compréhensible Et qu'il n'y a pas de grésillement excessif
6. Rejet - Qualité audio insuffisante
Étant donné qu'un contenu a un audio très grésillant
Quand le modérateur l'écoute
Alors le contenu est rejeté Et la raison est "Qualité audio insuffisante"
7. Validation - Respect des règles
Étant donné qu'un contenu respecte les règles
Quand le modérateur l'examine
Alors il vérifie qu'il n'y a pas de contenu prohibé:
| type prohibé |
|---|
| Haine |
| Violence |
| Spam |
| Illégalité |
8. Rejet - Contenu haineux détecté
Étant donné qu'un contenu contient des propos haineux
Quand le modérateur l'écoute
Alors le contenu est rejeté immédiatement Et la raison est "Contenu haineux (violation des règles)" Et le créateur peut recevoir un strike
9. Validation - Classification âge cohérente
Étant donné qu'un contenu familial est classé "Tout public"
Quand le modérateur l'écoute
Alors il vérifie que la classification correspond au contenu Et le contenu est accepté
10. Rejet - Classification incorrecte
Étant donné qu'un contenu adulte est classé "Tout public"
Quand le modérateur détecte l'incohérence
Alors le contenu est rejeté Et la raison est "Classification d'âge incorrecte"
11. Validation - Tags pertinents
Étant donné qu'un contenu sur l'automobile est tagué "Automobile", "Technologie"
Quand le modérateur vérifie les tags
Alors il confirme que les tags correspondent au contenu Et le contenu est accepté
12. Rejet - Tags non pertinents
Étant donné qu'un contenu musical est tagué "Automobile", "Sport"
Quand le modérateur détecte l'incohérence
Alors le contenu est rejeté Et la raison est "Tags non pertinents avec le contenu"
13. Validation - Zone diffusion cohérente
Étant donné qu'un audio-guide de la Tour Eiffel est en "Point GPS" Paris
Quand le modérateur vérifie la cohérence
Alors la zone est appropriée Et le contenu est accepté
14. Rejet - Zone incohérente
Étant donné qu'un audio-guide de la Tour Eiffel est en zone "National"
Quand le modérateur détecte l'incohérence
Alors le contenu est rejeté Et la raison est "Zone de diffusion incohérente (devrait être Point GPS)"
15. Délai de validation 24-48h jours ouvrés
Étant donné que je publie un contenu un lundi
Quand le contenu entre en file de validation
Alors le délai estimé est 24-48h (mercredi maximum)
16. Délai étendu le weekend
Étant donné que je publie un contenu un vendredi soir
Quand le contenu entre en file de validation
Alors le délai peut atteindre 72h (lundi) Et je vois "Validation en cours, délai 24-72h (weekend)"
17. Priorité FIFO (First In First Out)
Étant donné que 10 contenus sont en file de validation
Quand les modérateurs traitent la file
Alors les contenus sont traités dans l'ordre d'arrivée Et pas de traitement prioritaire
18. Notification acceptation
Étant donné que mon contenu est validé et accepté
Alors je reçois un email "✅ Votre contenu '[Titre]' est en ligne !" Et je reçois une notification push Et je vois un lien direct vers le contenu
19. Compteur de validation
Étant donné que mon premier contenu est accepté
Alors je vois "1/3 contenus validés pour devenir créateur vérifié"
Quand mon deuxième contenu est accepté
Alors je vois "2/3 contenus validés pour devenir créateur vérifié"
20. Notification refus avec raison détaillée
Étant donné que mon contenu est rejeté
Alors je reçois un email "❌ Contenu '[Titre]' refusé" Et je reçois une notification push Et je vois la raison exacte: "Qualité audio insuffisante" Et je vois un lien vers les règles de publication
21. Possibilité de correction et resoumission
Étant donné que mon contenu a été rejeté pour "Tags non pertinents"
Quand je corrige les tags Et que je resoumets le contenu
Alors le contenu repasse en file de validation Et une nouvelle validation est effectuée
22. Après 3 validations - Statut vérifié obtenu
Étant donné que mes 3 premiers contenus ont été validés
Alors j'obtiens le statut "Créateur Vérifié" Et je reçois une notification "🎉 Vous êtes maintenant créateur vérifié !" Et un badge ✓ apparaît sur mon profil
23. Badge vérifié visible publiquement
Étant donné que j'ai le statut vérifié
Quand un utilisateur consulte mon profil
Alors il voit le badge ✓ à côté de mon pseudo Et une mention "Créateur vérifié"
24. Contenus futurs publiés immédiatement
Étant donné que je suis créateur vérifié
Quand je publie un 4ème contenu
Alors le contenu est publié immédiatement Et il n'y a pas de validation préalable Et je vois "✅ Contenu publié"
25. Modération a posteriori uniquement
Étant donné que je suis créateur vérifié Et que je publie un contenu
Quand le contenu est en ligne
Alors il peut être signalé par les utilisateurs Et sera modéré uniquement si signalé
26. Interface modérateur - Queue de contenus
Étant donné que je suis un modérateur junior
Quand j'accède à l'interface de modération
Alors je vois la file des contenus à valider Et je vois le nombre total en attente Et les contenus sont triés par ordre FIFO
27. Interface modérateur - Écoute accélérée
Étant donné que je suis un modérateur
Quand j'écoute un contenu de 30 secondes
Alors je peux choisir la vitesse 1.5x ou 2.0x Et je termine l'écoute en 15 secondes à 2x Et ma productivité est doublée
28. Interface modérateur - Raccourcis clavier
Étant donné que je modère un contenu
Quand j'utilise les raccourcis clavier
Alors je peux:
| touche | action |
|---|---|
| A | Accepter |
| R | Rejeter |
| Espace | Play/Pause |
Et la modération est accélérée
29. Historique créateur visible
Étant donné qu'un créateur soumet son 2ème contenu
Quand le modérateur examine le contenu
Alors il voit l'historique:
| contenu | statut |
|---|---|
| Contenu 1 | Validé |
| Contenu 2 | En cours |
Et il peut juger la cohérence du créateur
30. Temps de modération estimé 1.5 min/créateur
Étant donné qu'un créateur soumet 3 contenus
Quand les modérateurs traitent ces contenus
Alors le temps total est environ:
| action | temps |
|---|---|
| Écoute 30s × 3 | 90s |
| Vérification metadata | 15s |
| Décision | 5s |
| Total | 110s |
Élargissement automatique de zone quand aucun contenu n'est disponible
9 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis un utilisateur connecté Et que la géolocalisation est activée Et que je suis en mode écoute
1. Aucun contenu dans rayon 50km - élargissement à 100km
Étant donné que je suis situé à la position GPS 48.8566, 2.3522 Et qu'aucun contenu n'existe dans un rayon de 50 km autour de ma position Mais qu'au moins 1 contenu existe dans un rayon de 100 km
Quand le système recherche du contenu à me proposer
Alors le système élargit automatiquement la zone de recherche à 100 km Et je reçois un message "Aucun contenu dans votre zone immédiate. Voici du contenu à proximité (100 km)" Et un contenu dans le rayon de 100 km m'est proposé
2. Aucun contenu dans rayon 100km - élargissement au département
Étant donné que je suis situé dans le département "75" (Paris) Et qu'aucun contenu n'existe dans un rayon de 100 km autour de ma position Mais qu'au moins 1 contenu existe avec la zone "département" pour "75"
Quand le système recherche du contenu à me proposer
Alors le système élargit automatiquement la zone de recherche au département Et je reçois un message "Aucun contenu local disponible. Voici du contenu dans votre département" Et un contenu départemental m'est proposé
3. Aucun contenu départemental - élargissement à la région
Étant donné que je suis situé dans la région "Île-de-France" Et qu'aucun contenu n'existe dans un rayon de 100 km autour de ma position Et qu'aucun contenu départemental n'existe pour mon département Mais qu'au moins 1 contenu existe avec la zone "région" pour "Île-de-France"
Quand le système recherche du contenu à me proposer
Alors le système élargit automatiquement la zone de recherche à la région Et je reçois un message "Aucun contenu local disponible. Voici du contenu dans votre région" Et un contenu régional m'est proposé
4. Aucun contenu régional - basculement sur contenu national
Étant donné que je suis situé en France Et qu'aucun contenu n'existe dans un rayon de 100 km autour de ma position Et qu'aucun contenu départemental n'existe pour mon département Et qu'aucun contenu régional n'existe pour ma région
Quand le système recherche du contenu à me proposer
Alors le système bascule automatiquement sur du contenu national Et je reçois un message "Aucun contenu local disponible. Voici du contenu national qui pourrait vous intéresser" Et un contenu national m'est proposé Et je ne reste jamais sans contenu disponible
5. Élargissement progressif avec plusieurs étapes
Étant donné que je suis situé dans une zone rurale isolée Et qu'aucun contenu n'existe dans un rayon de 50 km Et qu'aucun contenu n'existe dans un rayon de 100 km Et qu'aucun contenu départemental n'existe Et qu'aucun contenu régional n'existe
Quand le système recherche du contenu à me proposer
Alors le système essaie d'abord 50 km Et tout ce processus se fait de manière transparente et automatique Et je reçois le message correspondant au dernier niveau trouvé
6. Message personnalisé selon la distance trouvée
Étant donné que je suis situé à la position GPS 43.6047, 1.4442 Et que <niveau_geo> contenu(s) est/sont trouvé(s)
Quand le système me propose du contenu
Alors je reçois le message "<message_attendu>"
7. Le contenu national sert de filet de sécurité
Étant donné que le système a épuisé toutes les zones géographiques locales
Quand le système bascule sur du contenu national
Alors je dois toujours avoir au moins 1 contenu disponible Et ce contenu peut être:
| type_contenu |
|---|
| Actualités Le Monde |
| Podcasts génériques |
| Contenu éducatif national |
| Contenu culturel national |
8. Pas d'écran d'erreur "Aucun contenu"
Étant donné que je lance l'application Et qu'aucun contenu local n'est disponible dans ma zone
Quand le système recherche du contenu
Alors je ne dois jamais voir un message d'erreur "Aucun contenu disponible" Et je ne dois jamais voir un écran vide Et un contenu doit toujours m'être proposé, même si c'est du contenu national
9. Élargissement avec prise en compte des centres d'intérêt
Étant donné que je suis situé dans une zone rurale Et qu'aucun contenu n'existe dans un rayon de 50 km Et que mes centres d'intérêt incluent "Automobile" à 80% et "Voyage" à 70% Et qu'un contenu national existe avec le tag "Automobile" Et qu'un contenu national existe avec le tag "Politique"
Quand le système bascule sur du contenu national
Alors le contenu national proposé prend en compte mes centres d'intérêt Et le contenu "Automobile" a un score supérieur au contenu "Politique"
Gestion d'un contenu supprimé pendant l'écoute
11 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis un utilisateur connecté Et que je suis en mode écoute Et qu'un contenu "C123" est en cours de lecture
1. Contenu supprimé pendant lecture - fin de lecture sans interruption
Étant donné que j'écoute le contenu "C123" depuis 30 secondes Et que la durée totale du contenu est de 120 secondes
Quand le contenu est supprimé par la modération côté backend
Alors la lecture du contenu continue sans interruption Et je peux écouter le contenu jusqu'à la fin Et aucune interruption brutale ne se produit
2. Passage automatique après fin du contenu supprimé
Étant donné que le contenu "C123" a été supprimé pendant ma lecture Et que j'ai écouté le contenu jusqu'à la fin
Quand le contenu se termine
Alors le système attend 2 secondes Et passe automatiquement au contenu suivant Et je reçois une notification toast discrète "Contenu précédent retiré (violation règles)"
3. Bouton Précédent désactivé après suppression
Étant donné que le contenu "C123" a été supprimé pendant ma lecture Et que je suis passé au contenu suivant "C456"
Quand j'essaie d'appuyer sur le bouton "Précédent"
Alors le bouton "Précédent" ne me ramène pas au contenu supprimé Et je reçois un message "Ce contenu n'est plus disponible" Et la lecture du contenu actuel "C456" continue
4. Tentative de retour manuel au contenu supprimé
Étant donné que je suis sur le contenu "C456" Et que le contenu précédent "C123" a été supprimé
Quand j'appuie sur le bouton "Précédent" pour revenir au contenu supprimé
Alors je reçois un message "Ce contenu n'est plus disponible" Et la lecture reste sur le contenu actuel "C456" Et aucune action n'est effectuée
5. Notification discrète pendant la conduite
Étant donné que je conduis à une vitesse de 60 km/h Et que le contenu "C123" est supprimé pendant ma lecture
Quand le contenu se termine
Alors la notification "Contenu précédent retiré (violation règles)" s'affiche en toast discret Et la notification disparaît automatiquement après 5 secondes Et aucune popup modale n'interrompt ma conduite Et le contenu suivant démarre automatiquement après 2 secondes
6. Message informatif mais non alarmiste
Étant donné que le contenu "C123" a été supprimé Et que je passe au contenu suivant
Quand la notification s'affiche
Alors le message doit être informatif: "Contenu précédent retiré (violation règles)" Et le ton ne doit pas être alarmiste Et le message doit être bref et compréhensible Et aucun détail technique n'est affiché pendant la conduite
7. Contenu supprimé retiré de l'historique
Étant donné que le contenu "C123" a été supprimé
Quand je consulte mon historique d'écoute
Alors le contenu "C123" n'apparaît plus dans mon historique Et je ne peux pas relancer la lecture de ce contenu Et l'historique affiche "[Contenu retiré]" à la place du titre
8. Contenu supprimé non accessible via lien direct
Étant donné que le contenu "C123" a été supprimé Et que j'ai un lien de partage "roadwave.fr/share/c/C123"
Quand je clique sur le lien de partage
Alors je reçois un message "Ce contenu a été retiré pour violation des règles de la communauté" Et je suis redirigé vers l'accueil de l'application Et aucune lecture n'est possible
9. Plusieurs contenus supprimés dans l'historique récent
Étant donné que j'ai écouté les contenus suivants:
| id | statut |
|---|---|
| C123 | supprimé |
| C456 | actif |
| C789 | supprimé |
Et que je suis actuellement sur le contenu "C456"
Quand j'appuie plusieurs fois sur "Précédent"
Alors je ne peux pas revenir aux contenus "C123" ou "C789" Et le système saute automatiquement les contenus supprimés Et je reviens au dernier contenu actif disponible avant "C456"
10. Consultation détaillée du contenu supprimé à l'arrêt
Étant donné que je suis à l'arrêt Et que le contenu "C123" a été supprimé pendant ma session
Quand j'ouvre les détails de la notification de suppression
Alors je peux voir les informations suivantes:
| information |
|---|
| Titre du contenu |
| Créateur |
| Raison de suppression |
| Date de suppression |
Et je peux signaler une erreur de modération si je pense qu'elle est injustifiée
11. Pas d'impact sur les jauges d'intérêt lors de la suppression
Étant donné que j'ai écouté le contenu "C123" pendant 80 secondes (66%) Et que mes jauges d'intérêt ont été mises à jour pendant l'écoute
Quand le contenu est supprimé après mon écoute
Alors les modifications de mes jauges d'intérêt sont conservées Et l'écoute déjà effectuée reste comptabilisée Et seules les futures écoutes de ce contenu sont bloquées
Mode dégradé sans géolocalisation
19 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis un utilisateur connecté Et que j'ai refusé ou désactivé l'accès à la géolocalisation
1. Types de contenu disponibles sans géolocalisation
Étant donné que la géolocalisation est désactivée
Quand j'ouvre l'application
Alors les types de contenu suivants sont disponibles:
| type_contenu | disponible |
|---|---|
| Contenu national | oui |
| Contenu téléchargé (offline) | oui |
| Contenus "Neutre" géographiquement | oui |
| Contenu géolocalisé Ancré | non |
| Contenu géolocalisé Contextuel | non |
| Audio-guides | non |
| Notifications push géo-déclenchées | non |
2. Popup d'information au premier lancement sans GPS
Étant donné que c'est mon premier lancement de l'application Et que j'ai refusé l'accès à la géolocalisation
Quand l'application détecte que le GPS est désactivé
Alors une popup s'affiche avec le message: Et la popup contient les boutons suivants:
| bouton | action |
|---|---|
| Activer | Redirection vers paramètres OS |
| Continuer sans | Ferme popup et lance en mode dégradé |
Et une checkbox "Ne plus me demander" est disponible
3. Popup non affichée si case "Ne plus me demander" cochée
Étant donné que j'ai déjà vu la popup de géolocalisation Et que j'ai coché "Ne plus me demander"
Quand je lance l'application avec le GPS désactivé
Alors la popup de géolocalisation ne s'affiche pas Et l'application démarre directement en mode dégradé Et le banner permanent de rappel s'affiche
4. Redirection vers paramètres OS lors du clic sur "Activer"
Étant donné que la popup de géolocalisation est affichée
Quand je clique sur "Activer"
Alors je suis redirigé vers les paramètres de géolocalisation de mon OS Et sur iOS, j'arrive dans "Réglages > RoadWave > Localisation" Et sur Android, j'arrive dans "Paramètres > Applications > RoadWave > Autorisations > Position"
5. Banner de rappel permanent sans GPS
Étant donné que j'ai cliqué sur "Continuer sans" géolocalisation
Quand l'application s'affiche
Alors un bandeau s'affiche en haut de l'écran Et le bandeau contient le texte: "Mode limité : géolocalisation désactivée. [Activer]" Et le bandeau a un fond de couleur avertissement (jaune/orange) Et le bandeau n'est pas intrusif mais reste visible Et le bandeau reste affiché sur toutes les pages de l'application
6. Clic sur le bouton "Activer" du banner
Étant donné que le banner "Mode limité" est affiché
Quand je clique sur le lien "[Activer]" dans le banner
Alors je suis redirigé vers les paramètres de géolocalisation de mon OS
7. Disparition du banner après activation GPS
Étant donné que le banner "Mode limité" est affiché Et que je reviens dans l'application après avoir activé le GPS dans les paramètres
Quand l'application détecte que la géolocalisation est maintenant active
Alors le banner disparaît automatiquement Et l'application bascule en mode normal avec contenu géolocalisé Et un toast de confirmation s'affiche: "Géolocalisation activée"
8. Lecture de contenu national sans GPS
Étant donné que la géolocalisation est désactivée Et que du contenu national existe (actualités Le Monde, podcasts génériques)
Quand je lance la lecture
Alors je peux écouter le contenu national sans restriction Et l'algorithme de recommandation se base uniquement sur:
| critère |
|---|
| Mes centres d'intérêt |
| Mon historique d'écoute |
| Popularité générale |
Et la proximité géographique n'est pas prise en compte
9. Lecture de contenu téléchargé sans GPS
Étant donné que la géolocalisation est désactivée Et que j'ai téléchargé 30 contenus quand j'avais le GPS activé
Quand j'accède à mes contenus téléchargés
Alors je peux lire tous mes contenus téléchargés normalement Et les contenus géolocalisés téléchargés restent accessibles Et le filtre géographique n'est pas appliqué pour les contenus offline
10. Contenu "Neutre" géographiquement disponible
Étant donné que la géolocalisation est désactivée Et qu'un créateur a publié du contenu avec la classification géographique "Neutre"
Quand je recherche du contenu
Alors les contenus "Neutre" sont inclus dans les résultats Et ils sont mélangés avec le contenu national Et l'algorithme les priorise selon mes centres d'intérêt
11. Audio-guides inaccessibles sans GPS
Étant donné que la géolocalisation est désactivée
Quand je recherche un audio-guide spécifique
Alors les audio-guides apparaissent dans les résultats de recherche Mais un badge "GPS requis" est affiché sur chaque audio-guide Et quand je clique sur un audio-guide, un message s'affiche: Et je peux choisir "Activer" ou "Annuler"
12. Notifications push géo-déclenchées désactivées
Étant donné que la géolocalisation est désactivée Et que je suis abonné à un créateur qui diffuse du contenu géolocalisé
Quand le créateur publie un nouveau contenu géolocalisé
Alors je ne reçois pas de notification push géo-déclenchée Mais je reçois une notification push standard (non géo-déclenchée) si le créateur publie du contenu national Et la notification précise: "Nouveau contenu national de [Créateur]"
13. Contenu géolocalisé non proposé dans le feed
Étant donné que la géolocalisation est désactivée
Quand le système génère mon feed de contenu
Alors aucun contenu "Ancré" ou "Contextuel" n'est inclus Et seuls les contenus "Neutre" et "National" sont proposés Et mon feed contient au minimum 20 contenus disponibles
14. Application fonctionnelle sans GPS (pas de blocage)
Étant donné que la géolocalisation est désactivée
Quand j'utilise l'application
Alors je ne suis jamais bloqué par un écran "GPS requis" Et toutes les fonctionnalités non-géolocalisées restent accessibles:
| fonctionnalité |
|---|
| Écoute contenu national |
| Gestion profil |
| Abonnements créateurs |
| Recherche textuelle |
| Historique d'écoute |
| Paramètres |
| Mode offline |
Et je peux créer et publier du contenu national
15. Respect du choix utilisateur de ne pas activer GPS
Étant donné que j'ai coché "Ne plus me demander" pour la géolocalisation
Quand j'utilise l'application pendant plusieurs semaines
Alors la popup de demande GPS ne s'affiche plus jamais automatiquement Et seul le banner permanent reste affiché Et l'application ne force jamais l'activation du GPS
16. Bascule automatique en mode normal après activation GPS
Étant donné que j'utilise l'application en mode dégradé depuis 1 semaine Et que je décide d'activer la géolocalisation
Quand l'application détecte que le GPS est maintenant actif
Alors le mode dégradé est désactivé automatiquement Et le banner "Mode limité" disparaît Et le contenu géolocalisé devient disponible immédiatement Et mon feed se rafraîchit avec du contenu local pertinent Et un toast de confirmation s'affiche: "Géolocalisation activée - Contenu local disponible"
17. Demande de permission GPS lors de l'utilisation d'une fonctionnalité géo
Étant donné que la géolocalisation est désactivée
Quand j'essaie d'accéder à une fonctionnalité nécessitant le GPS (ex: audio-guide)
Alors une popup contextuelle s'affiche: Et je peux accepter ou refuser Et si j'accepte, je suis redirigé vers les paramètres OS Et si je refuse, je reste en mode dégradé sans message d'erreur répétitif
18. Statistiques de contenu local disponible non affiché
Étant donné que la géolocalisation est désactivée
Quand je navigue dans l'application
Alors le banner peut afficher occasionnellement: Et ce message incitatif change tous les 3 jours Et il reste non intrusif (pas de popup, juste le banner)
19. Onboarding différent pour utilisateurs sans GPS
Étant donné que c'est ma première utilisation de RoadWave Et que j'ai refusé la géolocalisation
Quand l'onboarding se termine
Alors un écran explicatif s'affiche: Et je peux continuer avec un bouton "Compris"
Gestion de la perte de réseau et buffering adaptatif
17 scénarios (16 standards, 1 plan)
Contexte commun à tous les scénarios
Étant donné que je suis un utilisateur connecté Et que je suis en mode écoute Et qu'un contenu est en cours de lecture
1. 📋 Plan: Paramètres de buffer selon le type de réseau
Étant donné que je suis connecté en "<type_reseau>"
Quand le système initialise le buffer audio
Alors le buffer minimum est de <buffer_min> secondes Et le buffer cible est de <buffer_cible> secondes Et le buffer maximum est de <buffer_max> secondes
📊 Exemples de données:
| type_reseau | buffer_min | buffer_cible | buffer_max |
|---|---|---|---|
| WiFi | 5 | 30 | 120 |
| 4G | 10 | 45 | 120 |
| 5G | 10 | 45 | 120 |
| 3G | 30 | 90 | 300 |
2. Connexion instable avec latence élevée - aucun message immédiat
Étant donné que je suis connecté en 4G Et que le buffer contient 45 secondes de contenu
Quand la latence réseau dépasse 500ms
Alors aucun message n'est affiché immédiatement Et la lecture continue normalement sur le buffer Et le système tente de continuer le téléchargement en arrière-plan
3. Connexion instable pendant plus de 10 secondes - toast discret
Étant donné que je suis connecté en 4G Et que la latence réseau dépasse 500ms depuis 10 secondes
Quand le système détecte la latence prolongée
Alors un toast discret s'affiche: "Connexion instable" Et le toast disparaît automatiquement après 3 secondes Et la lecture continue normalement
4. Perte totale de réseau - lecture sur buffer
Étant donné que je suis connecté en WiFi Et que le buffer contient 30 secondes de contenu
Quand je perds totalement la connexion réseau
Alors la lecture continue sur le buffer disponible Et un toast s'affiche: "Hors ligne, lecture sur buffer (30s restantes)" Et un compte à rebours du temps de buffer restant est visible
5. Buffer qui s'épuise pendant la perte réseau
Étant donné que je suis hors ligne Et que le buffer contient 30 secondes de contenu
Quand le contenu continue de jouer
Alors le compte à rebours diminue en temps réel Et le toast affiche "Hors ligne, lecture sur buffer (15s restantes)" après 15 secondes Et le toast affiche "Hors ligne, lecture sur buffer (5s restantes)" après 25 secondes
6. Pause automatique après épuisement du buffer
Étant donné que je suis hors ligne depuis 30 secondes Et que le buffer est complètement épuisé
Quand il n'y a plus de contenu audio à lire
Alors la lecture se met en pause automatiquement Et un overlay s'affiche: "Connexion perdue. Reconnexion en cours..." Et le système tente de se reconnecter automatiquement
7. Tentatives de reconnexion automatique
Étant donné que la lecture est en pause suite à l'épuisement du buffer
Quand le système tente de se reconnecter
Alors une tentative de reconnexion est effectuée toutes les 5 secondes Et un maximum de 6 tentatives sont effectuées (30 secondes au total) Et l'overlay affiche "Tentative de reconnexion... (X/6)"
8. Proposition du mode offline après 30 secondes d'échec
Étant donné que 6 tentatives de reconnexion ont échoué Et que cela fait 30 secondes que je suis déconnecté
Quand la 6ème tentative échoue
Alors une popup s'affiche: "Voulez-vous continuer avec vos contenus téléchargés ?" Et la popup contient deux boutons:
| bouton | action |
|---|---|
| Réessayer | Nouvelle série de 6 tentatives |
| Mode offline | Bascule sur contenus téléchargés |
9. Basculement réussi vers le mode offline
Étant donné que la popup de mode offline est affichée Et que j'ai téléchargé 20 contenus dans ma zone géographique
Quand je clique sur "Mode offline"
Alors le système bascule sur les contenus téléchargés Et un nouveau contenu téléchargé démarre automatiquement Et un bandeau permanent indique "Mode hors ligne - Contenus téléchargés"
10. Aucun contenu téléchargé disponible
Étant donné que la popup de mode offline est affichée Et que je n'ai aucun contenu téléchargé
Quand je clique sur "Mode offline"
Alors un message s'affiche: "Aucun contenu téléchargé disponible" Et je suis invité à me connecter en WiFi pour télécharger du contenu Et le bouton "Réessayer" reste la seule option
11. Reprise automatique après reconnexion
Étant donné que la lecture est en pause depuis 15 secondes Et que j'étais à 02:35 du contenu en cours
Quand la connexion réseau est rétablie
Alors la lecture reprend automatiquement au point d'arrêt exact (02:35) Et un toast s'affiche: "Connexion rétablie" Et le toast disparaît après 3 secondes Et le buffer se remplit progressivement selon le type de réseau
12. Reconnexion avec changement de type de réseau
Étant donné que j'étais connecté en WiFi Et que j'ai perdu la connexion
Quand je me reconnecte en 4G
Alors le système ajuste automatiquement les paramètres de buffer Et le buffer minimum passe de 5s à 10s Et le buffer cible passe de 30s à 45s Et la lecture reprend normalement
13. Passage dans un tunnel avec perte de signal
Étant donné que je conduis à 90 km/h sur autoroute Et que je suis connecté en 4G avec un buffer de 45 secondes
Quand j'entre dans un tunnel et perds le signal
Alors la lecture continue sur le buffer pendant 45 secondes maximum Et aucune notification n'est affichée pendant les 10 premières secondes Et un toast discret s'affiche après 10 secondes: "Connexion instable"
14. Sortie du tunnel avant épuisement du buffer
Étant donné que je suis dans un tunnel depuis 30 secondes Et qu'il reste 15 secondes de buffer
Quand je sors du tunnel et récupère le signal 4G
Alors la lecture continue sans interruption Et le buffer se remplit à nouveau Et un toast s'affiche: "Connexion rétablie"
15. Changement de cellule 4G pendant la lecture
Étant donné que je conduis et change de cellule mobile toutes les 5-10 minutes Et que le buffer contient 45 secondes de contenu
Quand un handoff de cellule se produit
Alors la lecture continue sans interruption grâce au buffer Et la connexion à la nouvelle cellule se fait de manière transparente Et aucune notification n'est affichée si le handoff réussit en moins de 5 secondes
16. Téléchargement préventif en WiFi avant trajet
Étant donné que je suis connecté en WiFi Et que j'ai activé le téléchargement automatique
Quand le système détecte que je suis à l'arrêt en WiFi
Alors le système me propose de télécharger du contenu pour mon trajet Et je peux sélectionner une zone géographique à télécharger Et le téléchargement se fait en arrière-plan
17. Tracking des événements de perte réseau pour amélioration
Étant donné que je perds la connexion réseau
Quand l'événement de perte est détecté
Alors le système enregistre les métriques suivantes:
| métrique |
|---|
| Type de réseau avant perte |
| Durée de la coupure |
| Buffer disponible |
| Position GPS approximative |
| Heure de la journée |
Et ces métriques sont anonymisées et envoyées en batch lors de la prochaine connexion WiFi Et les données servent à améliorer les paramètres de buffer
Tests BDD - Documentation des fonctionnalités
Cette documentation est générée automatiquement à partir des fichiers Gherkin (.feature).
Vue d'ensemble
| Métrique | Valeur |
|---|---|
| Fonctionnalités | 83 |
| Scénarios | 2112 |
| Domaines métier | 18 |
🔔 Abonnements
4 fonctionnalités • 100 scénarios
🎧 Audio Guides
7 fonctionnalités • 238 scénarios
🔐 Authentication
| Fonctionnalité | Scénarios |
|---|---|
| Authentification à deux facteurs (2FA) | 16 |
| Classification des contenus par âge | 13 |
| Connexion utilisateur | 11 |
| Gestion des sessions et tokens | 13 |
| Inscription utilisateur | 15 |
| Récupération de compte | 14 |
| Vérification d'email | 10 |
7 fonctionnalités • 92 scénarios
🎨 Content Creation
| Fonctionnalité | Scénarios |
|---|---|
| Modification et suppression de contenu | 30 |
| Métadonnées et publication de contenu | 34 |
| Upload et encodage de contenu audio | 29 |
| Validation des 3 premiers contenus | 30 |
4 fonctionnalités • 123 scénarios
⚠️ Error Handling
4 fonctionnalités • 56 scénarios
📊 Interest Gauges
| Fonctionnalité | Scénarios |
|---|---|
| Jauge initiale et cold start | 15 |
| Pas de dégradation temporelle des jauges | 16 |
| Évolution des jauges d'intérêt | 21 |
3 fonctionnalités • 52 scénarios
📴 Mode Offline
| Fonctionnalité | Scénarios |
|---|---|
| Synchronisation actions offline | 45 |
| Téléchargement de contenus offline | 49 |
| Validité et renouvellement contenus offline | 38 |
3 fonctionnalités • 132 scénarios
🛡️ Moderation
| Fonctionnalité | Scénarios |
|---|---|
| Modération préventive | 22 |
| Sanctions et notifications de modération | 27 |
| Signalement de contenu inapproprié | 23 |
| Traitement des signalements par l'IA et les modérateurs | 25 |
4 fonctionnalités • 97 scénarios
💰 Monetisation
7 fonctionnalités • 233 scénarios
🧭 Navigation
6 fonctionnalités • 135 scénarios
🔗 Partage
| Fonctionnalité | Scénarios |
|---|---|
| Partage de contenu | 22 |
1 fonctionnalités • 22 scénarios
⭐ Premium
| Fonctionnalité | Scénarios |
|---|---|
| Avantages Premium | 37 |
| Gestion abonnement Premium | 41 |
| Multi-devices et détection simultanée | 30 |
| Offre et tarification Premium | 31 |
4 fonctionnalités • 139 scénarios
👤 Profil
| Fonctionnalité | Scénarios |
|---|---|
| Profil créateur | 31 |
1 fonctionnalités • 31 scénarios
📢 Publicites
6 fonctionnalités • 179 scénarios
📻 Radio Live
| Fonctionnalité | Scénarios |
|---|---|
| Architecture technique radio live | 24 |
| Arrêt du live | 19 |
| Comportement auditeur pendant un live | 27 |
| Démarrage d'un live | 20 |
4 fonctionnalités • 90 scénarios
🔍 Recherche
| Fonctionnalité | Scénarios |
|---|---|
| Recherche de contenu | 55 |
1 fonctionnalités • 55 scénarios
🎯 Recommendation
9 fonctionnalités • 180 scénarios
🔒 Rgpd Compliance
8 fonctionnalités • 158 scénarios
Pas de dégradation temporelle des jauges
En tant que système de recommandation Je veux que les jauges n'évoluent que par les actions utilisateur Afin d'avoir un comportement prévisible et fiable
16 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un utilisateur est connecté
1. Aucune dégradation automatique avec le temps
Étant donné que ma jauge "Économie" est à 80% Et que je n'écoute aucun contenu pendant 30 jours
Quand je me reconnecte après 30 jours
Alors ma jauge "Économie" est toujours à 80% Et aucune dégradation temporelle n'a été appliquée
2. Jauges conservées après 6 mois d'inactivité
Étant donné que mes jauges sont:
| catégorie | niveau |
|---|---|
| Automobile | 75% |
| Voyage | 60% |
| Musique | 45% |
Et que je pars en vacances pendant 6 mois sans utiliser l'app
Quand je me reconnecte après 6 mois
Alors mes jauges sont exactement les mêmes:
| catégorie | niveau |
|---|---|
| Automobile | 75% |
| Voyage | 60% |
| Musique | 45% |
3. Évolution naturelle par les actions
Étant donné que j'aimais "Économie" il y a 1 an (jauge 80%) Et que depuis, je skip tous les contenus "Économie" Et que j'ai skippé 50 contenus "Économie" en 1 an
Alors ma jauge "Économie" descend naturellement via les skips Et atteint environ 55% (80% - 50 × 0.5% = 55%) Et la dégradation vient des actions, pas du temps
4. Pas de cron job de dégradation
Étant donné que le système vérifie les jauges quotidiennement
Quand un utilisateur n'a pas d'activité depuis 90 jours
Alors aucun job de dégradation n'est exécuté Et les jauges restent inchangées Et aucune ressource CPU n'est consommée pour la dégradation
5. Comportement prévisible après absence
Étant donné que ma jauge "Sport" était à 70% Et que je n'utilise pas l'app pendant 1 an
Quand je reviens et demande des recommandations
Alors mes recommandations reflètent toujours mes goûts d'avant Et je reçois du contenu "Sport" prioritaire Et le comportement est cohérent et prévisible
6. Réinitialiser manuellement mes centres d'intérêt
Étant donné que je veux repartir de zéro
Quand je vais dans les paramètres Et que je clique sur "Réinitialiser mes centres d'intérêt" Et que je confirme l'action
Alors toutes mes jauges reviennent à 50% Et je vois le message "Vos centres d'intérêt ont été réinitialisés"
7. Confirmation avant réinitialisation
Étant donné que je suis dans les paramètres
Quand je clique sur "Réinitialiser mes centres d'intérêt"
Alors je vois un message de confirmation:
| titre | Êtes-vous sûr ? |
|---|---|
| message | Cette action remettra toutes vos jauges à 50% |
| actions | Confirmer / Annuler |
8. Annuler la réinitialisation
Étant donné que j'ai cliqué sur "Réinitialiser mes centres d'intérêt" Et que la confirmation est affichée
Quand je clique sur "Annuler"
Alors mes jauges ne sont pas modifiées Et je reviens aux paramètres
9. Raison de réinitialisation - changement de vie
Étant donné que j'utilisais RoadWave pour mes trajets professionnels Et que mes jauges reflétaient "Économie" (85%) et "Technologie" (75%) Et que je change de vie et deviens musicien
Quand je réinitialise mes centres d'intérêt
Alors je peux repartir avec toutes les jauges à 50% Et découvrir du contenu "Musique" et "Culture" sans biais
10. Pas de suggestion automatique de réinitialisation
Étant donné que je n'ai pas utilisé l'app depuis 1 an
Quand je me reconnecte
Alors aucune suggestion de réinitialisation n'est affichée Et mes jauges sont conservées telles quelles Et je garde le contrôle total
11. Historique conservé après réinitialisation
Étant donné que j'ai écouté 500 contenus
Quand je réinitialise mes centres d'intérêt
Alors mes jauges reviennent à 50% Mais mon historique d'écoute est conservé Et je peux toujours consulter mes anciens contenus écoutés
12. Évolution future basée sur nouvelles actions
Étant donné que j'ai réinitialisé mes jauges à 50%
Quand j'écoute 5 contenus "Voyage" à >80%
Alors ma jauge "Voyage" monte à 60% (50% + 5 × 2%) Et l'algorithme recommence à apprendre mes nouvelles préférences
13. Respect de l'historique utilisateur
Étant donné qu'un utilisateur aime "Cryptomonnaie" depuis 2 ans Et que sa jauge est à 90%
Quand 2 ans s'écoulent sans dégradation temporelle
Alors sa jauge reste à 90% Et le système ne fait pas d'"oubli" artificiel
14. Coût infrastructure zéro
Étant donné qu'aucune dégradation temporelle n'existe
Quand le système calcule les jauges
Alors aucun calcul de date n'est nécessaire Et aucun batch nocturne ne tourne Et aucun bug de fuseau horaire ne peut survenir Et le coût CPU est minimal
15. UX prévisible - jauge = actions
Étant donné qu'un utilisateur consulte sa jauge "Sport" à 65%
Quand il se demande pourquoi elle est à 65%
Alors il peut retracer ses actions:
| action | impact |
|---|---|
| 10 likes automatiques | +10% |
| 3 abonnements Sport | +15% |
| 5 skips de contenu non-Sport | 0% |
Et il comprend que c'est le reflet exact de ses actions Et il n'y a pas de mystère ou automatisme caché
16. Statistiques affichées sans date
Étant donné que je consulte mes centres d'intérêt
Quand je vois mes jauges
Alors je vois:
| information | affiché |
|---|---|
| Niveau actuel | ✅ 75% |
| Évolution depuis début | ✅ +25% |
| Dernière mise à jour | ❌ |
Et aucune date n'est affichée car non pertinente Et seules les actions comptent
Évolution des jauges d'intérêt
En tant que système de recommandation Je veux faire évoluer les jauges d'intérêt selon les actions utilisateur Afin d'affiner les recommandations personnalisées
21 scénarios (20 standards, 1 plan)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un utilisateur est connecté
1. Like automatique renforcé après écoute ≥80%
Étant donné qu'un contenu de 5 minutes est tagué "Automobile" Et que ma jauge "Automobile" est à 45%
Quand j'écoute le contenu pendant 4 minutes 30 secondes (90%)
Alors je reçois un like automatique renforcé Et ma jauge "Automobile" augmente de 2% Et ma jauge "Automobile" est maintenant à 47%
2. Like automatique renforcé exactement à 80%
Étant donné qu'un contenu de 10 minutes est tagué "Voyage" Et que ma jauge "Voyage" est à 60%
Quand j'écoute le contenu pendant exactement 8 minutes (80%)
Alors je reçois un like automatique renforcé Et ma jauge "Voyage" augmente de 2% Et ma jauge "Voyage" est maintenant à 62%
3. Like automatique standard après écoute 30-79%
Étant donné qu'un contenu de 5 minutes est tagué "Automobile" Et que ma jauge "Automobile" est à 45%
Quand j'écoute le contenu pendant 2 minutes 30 secondes (50%)
Alors je reçois un like automatique standard Et ma jauge "Automobile" augmente de 1% Et ma jauge "Automobile" est maintenant à 46%
4. Like automatique standard à 30% exactement
Étant donné qu'un contenu de 10 minutes est tagué "Musique" Et que ma jauge "Musique" est à 40%
Quand j'écoute le contenu pendant exactement 3 minutes (30%)
Alors je reçois un like automatique standard Et ma jauge "Musique" augmente de 1%
5. Like automatique standard à 79%
Étant donné qu'un contenu de 10 minutes est tagué "Sport" Et que ma jauge "Sport" est à 55%
Quand j'écoute le contenu pendant 7 minutes 54 secondes (79%)
Alors je reçois un like automatique standard Et ma jauge "Sport" augmente de 1% Et ma jauge "Sport" est maintenant à 56%
6. Like explicite (manuel) +2%
Étant donné qu'un contenu est tagué "Économie" Et que ma jauge "Économie" est à 70%
Quand j'écoute le contenu partiellement Et que je clique manuellement sur le bouton "Like"
Alors ma jauge "Économie" augmente de 2% Et ma jauge "Économie" est maintenant à 72%
7. Like manuel cumulable avec like automatique
Étant donné qu'un contenu de 5 minutes est tagué "Automobile" Et que ma jauge "Automobile" est à 45%
Quand j'écoute le contenu pendant 2 minutes 30 secondes (50%)
Alors je reçois un like automatique standard (+1%)
Quand je clique ensuite sur le bouton "Like"
Alors ma jauge augmente encore de 2% (like manuel) Et ma jauge "Automobile" a augmenté de 3% au total Et ma jauge "Automobile" est maintenant à 48%
8. Abonnement créateur impacte tous ses tags
Étant donné qu'un créateur publie des contenus tagués "Automobile" et "Technologie" Et que mes jauges sont:
| catégorie | niveau |
|---|---|
| Automobile | 50% |
| Technologie | 45% |
Quand je m'abonne à ce créateur
Alors ma jauge "Automobile" augmente de 5% Et ma jauge "Technologie" augmente de 5% Et mes nouvelles jauges sont:
| catégorie | niveau |
|---|---|
| Automobile | 55% |
| Technologie | 50% |
9. Skip rapide (<10s) diminue la jauge
Étant donné qu'un contenu est tagué "Économie" Et que ma jauge "Économie" est à 45%
Quand je skip le contenu après 5 secondes
Alors ma jauge "Économie" diminue de 0.5% Et ma jauge "Économie" est maintenant à 44.5%
10. Skip à exactement 10s ne diminue pas la jauge
Étant donné qu'un contenu est tagué "Politique" Et que ma jauge "Politique" est à 50%
Quand je skip le contenu après exactement 10 secondes
Alors ma jauge "Politique" ne change pas Et reste à 50%
11. Skip tardif (≥30%) est neutre
Étant donné qu'un contenu de 10 minutes est tagué "Musique" Et que ma jauge "Musique" est à 60%
Quand j'écoute pendant 3 minutes (30%) Et que je skip ensuite
Alors ma jauge "Musique" ne diminue pas (signal neutre) Et ma jauge reste à 60% (plus le +1% de like auto si applicable)
12. Contenu avec plusieurs tags impacte toutes les jauges
Étant donné qu'un contenu est tagué "Automobile" et "Voyage" Et que mes jauges sont:
| catégorie | niveau |
|---|---|
| Automobile | 45% |
| Voyage | 60% |
Quand j'écoute le contenu à 90%
Alors les deux jauges augmentent de 2% Et mes nouvelles jauges sont:
| catégorie | niveau |
|---|---|
| Automobile | 47% |
| Voyage | 62% |
13. Contenu avec 3 tags impacte les 3 jauges
Étant donné qu'un contenu est tagué "Sport", "Santé" et "Technologie" Et que mes jauges sont à 50% pour chaque catégorie
Quand je skip rapidement après 5 secondes
Alors les 3 jauges diminuent de 0.5% Et toutes passent à 49.5%
14. Jauges bornées - ne peut pas dépasser 100%
Étant donné que ma jauge "Cryptomonnaie" est à 99% Et qu'un contenu tagué "Cryptomonnaie" est disponible
Quand j'écoute le contenu à 95% (like auto renforcé +2%)
Alors ma jauge "Cryptomonnaie" passe à 100% (maximum) Et ne dépasse pas 100%
15. Jauges bornées - ne peut pas descendre sous 0%
Étant donné que ma jauge "Politique" est à 0.3% Et qu'un contenu tagué "Politique" est disponible
Quand je skip rapidement après 3 secondes (-0.5%)
Alors ma jauge "Politique" passe à 0% (minimum) Et ne devient pas négative
16. Calcul immédiat à chaque action
Étant donné que ma jauge "Voyage" est à 50%
Quand j'écoute un contenu "Voyage" à 85%
Alors la jauge est mise à jour immédiatement (pas de batch) Et passe à 52%
Quand je demande mes recommandations dans la seconde suivante
Alors l'algorithme utilise déjà la valeur 52%
17. Like manuel après écoute <30% (pas de like auto)
Étant donné qu'un contenu de 10 minutes est tagué "Culture" Et que ma jauge "Culture" est à 60%
Quand j'écoute pendant 2 minutes (20%)
Alors je ne reçois pas de like automatique
Quand je clique sur le bouton "Like"
Alors ma jauge "Culture" augmente de 2% uniquement Et ma jauge "Culture" est maintenant à 62%
18. Unlike retire le like manuel
Étant donné que j'ai liké manuellement un contenu "Sport" Et que ma jauge "Sport" est passée de 55% à 57% (+2%)
Quand je clique sur "Unlike"
Alors ma jauge "Sport" diminue de 2% Et ma jauge "Sport" revient à 55%
19. Unlike ne peut pas retirer un like automatique
Étant donné que j'ai écouté un contenu "Musique" à 90% Et que j'ai reçu un like automatique renforcé (+2%) Et que ma jauge "Musique" est à 52%
Quand j'essaie de faire "Unlike"
Alors l'action n'est pas disponible Et ma jauge reste à 52%
20. Tags définis par créateur à la publication
Étant donné que je suis un créateur
Quand je publie un contenu
Alors je dois sélectionner 1 à 3 tags Et ces tags sont fixés après publication Et impacteront les jauges de tous les auditeurs
21. 📋 Plan: Calculs avec différentes durées d'écoute
Étant donné qu'un contenu de 10 minutes est tagué "Voyage" Et que ma jauge "Voyage" est à 50%
Quand j'écoute pendant ()
Alors ma jauge évolue de Et ma nouvelle jauge est à <nouveau_niveau>
📊 Exemples de données:
| duree | pourcentage | impact | nouveau_niveau |
|---|---|---|---|
| 1 min | 10% | 0% | 50% |
| 3 min | 30% | +1% | 51% |
| 5 min | 50% | +1% | 51% |
| 7.9 min | 79% | +1% | 51% |
| 8 min | 80% | +2% | 52% |
| 9.5 min | 95% | +2% | 52% |
| 5 sec | <1% | -0.5% | 49.5% |
Jauge initiale et cold start
En tant que nouvel utilisateur Je veux que mes jauges d'intérêt démarrent de manière neutre Afin de découvrir du contenu sans biais initial
15 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible
1. Inscription - toutes les jauges à 50%
Quand je m'inscris sur RoadWave
Alors toutes mes jauges d'intérêt sont initialisées à 50% Et je ne dois pas remplir de questionnaire Et l'inscription est ultra-rapide
2. Liste des catégories disponibles
Étant donné que je suis un nouvel utilisateur
Quand je consulte mes centres d'intérêt
Alors je vois les catégories suivantes à 50%:
| catégorie |
|---|
| Automobile |
| Voyage |
| Famille |
| Amour |
| Musique |
| Économie |
| Cryptomonnaie |
| Politique |
| Culture générale |
| Sport |
| Technologie |
| Santé |
3. Cold start - premier contenu écouté
Étant donné que je viens de m'inscrire Et que toutes mes jauges sont à 50%
Quand j'écoute mon premier podcast "Automobile" à 90%
Alors ma jauge "Automobile" monte à 52% (+2%) Et toutes les autres jauges restent à 50%
4. Cold start - premier skip
Étant donné que je viens de m'inscrire Et que toutes mes jauges sont à 50%
Quand je skip rapidement un contenu "Économie"
Alors ma jauge "Économie" descend à 49.5% (-0.5%) Et toutes les autres jauges restent à 50%
5. Après 10 écoutes, profil commence à se dessiner
Étant donné que je suis un nouvel utilisateur Et que j'ai écouté:
| contenu | tags | completion |
|---|---|---|
| Contenu 1 | Automobile | 90% |
| Contenu 2 | Automobile, Sport | 85% |
| Contenu 3 | Voyage | 75% |
| Contenu 4 | Économie | skip 5s |
| Contenu 5 | Automobile | 95% |
| Contenu 6 | Sport | 80% |
| Contenu 7 | Politique | skip 8s |
| Contenu 8 | Voyage | 88% |
| Contenu 9 | Automobile | 92% |
| Contenu 10 | Technologie | 40% |
Alors mes jauges reflètent mes préférences:
| catégorie | tendance |
|---|---|
| Automobile | Forte hausse (>55%) |
| Voyage | Hausse modérée (~53%) |
| Sport | Hausse modérée (~53%) |
| Économie | Baisse légère (~49.5%) |
| Politique | Baisse légère (~49.5%) |
| Technologie | Neutre (~51%) |
6. Pas de questionnaire onboarding par défaut
Quand je termine l'inscription
Alors aucun questionnaire de centres d'intérêt n'est affiché Et je peux commencer à écouter immédiatement Et l'algorithme apprend naturellement
7. Algorithme avec jauges à 50% - chances égales
Étant donné que toutes mes jauges sont à 50%
Quand l'algorithme calcule les recommandations
Alors tous les types de contenus ont une chance égale Et aucun biais initial n'est appliqué Et la géolocalisation prime sur les intérêts
8. Questionnaire optionnel après 3 écoutes (post-MVP)
Étant donné que j'ai écouté 3 contenus
Quand je termine ma 3ème écoute
Alors je vois une notification in-app optionnelle:
| titre | Améliorez vos recommandations |
|---|---|
| message | Sélectionnez vos centres d'intérêt |
| actions | Configurer maintenant / Plus tard |
9. Remplir le questionnaire optionnel (post-MVP)
Étant donné que le questionnaire optionnel est affiché
Quand je sélectionne les centres d'intérêt suivants:
| catégorie |
|---|
| Automobile |
| Voyage |
| Sport |
Alors les jauges sélectionnées passent à 70% Et les jauges non sélectionnées passent à 30% Et je vois le message "Vos préférences ont été enregistrées"
10. Skipper le questionnaire optionnel (post-MVP)
Étant donné que le questionnaire optionnel est affiché
Quand je clique sur "Plus tard"
Alors toutes mes jauges conservent 50% Et l'algorithme continue d'apprendre naturellement Et je ne suis plus sollicité
11. Comportement déterministe et testable
Étant donné deux nouveaux utilisateurs A et B
Quand les deux s'inscrivent au même moment
Alors leurs jauges sont identiques (toutes à 50%) Et leurs recommandations initiales sont identiques (basées sur géo uniquement)
12. Équité entre créateurs au cold start
Étant donné qu'un nouvel utilisateur s'inscrit Et qu'il existe 1000 contenus de catégories variées dans sa zone
Quand l'algorithme génère les premières recommandations
Alors tous les contenus ont une pondération intérêts identique (50%) Et seuls la géolocalisation et l'engagement différencient les contenus Et aucun créateur n'a d'avantage initial
13. Catégories extensibles
Étant donné que RoadWave ajoute une nouvelle catégorie "Gastronomie"
Quand je consulte mes centres d'intérêt
Alors je vois la nouvelle catégorie "Gastronomie" à 50% Et je peux commencer à l'explorer normalement
14. Voir l'évolution de mes jauges
Étant donné que je suis un utilisateur avec historique
Quand je consulte mes centres d'intérêt dans les paramètres
Alors je vois mes jauges actuelles:
| catégorie | niveau | evolution |
|---|---|---|
| Automobile | 67% | +17% |
| Voyage | 82% | +32% |
| Économie | 34% | -16% |
| Sport | 50% | 0% |
Et je comprends mes préférences actuelles
15. Friction zéro à l'inscription
Étant donné que je veux m'inscrire rapidement
Quand je remplis les 4 champs obligatoires Et que je clique sur "S'inscrire"
Alors mon compte est créé immédiatement Et je peux commencer à écouter dans les 30 secondes Et aucune configuration supplémentaire n'est requise
Synchronisation actions offline
En tant qu'utilisateur Je veux que mes actions offline soient synchronisées quand je me reconnecte Afin de ne perdre aucune interaction même sans connexion
45 scénarios
Contexte commun à tous les scénarios
Étant donné que j'utilise l'application RoadWave
1. Like d'un contenu en mode offline
Étant donné que je n'ai aucune connexion Internet
Quand je like un contenu téléchargé
Alors l'action est enregistrée localement dans SQLite: Et l'UI affiche immédiatement le like (optimistic update)
2. Unlike d'un contenu en mode offline
Étant donné que je n'ai aucune connexion Internet Et que j'avais liké un contenu
Quand je retire mon like
Alors l'action est enregistrée localement: Et l'UI retire immédiatement le like
3. Abonnement à un créateur en mode offline
Étant donné que je n'ai aucune connexion Internet
Quand je m'abonne à un créateur
Alors l'action est enregistrée localement: Et l'UI affiche immédiatement "Abonné ✓"
4. Désabonnement d'un créateur en mode offline
Étant donné que je n'ai aucune connexion Internet Et que j'étais abonné à un créateur
Quand je me désabonne
Alors l'action est enregistrée localement: Et l'UI affiche "S'abonner"
5. Signalement d'un contenu en mode offline
Étant donné que je n'ai aucune connexion Internet
Quand je signale un contenu pour "Contenu inapproprié"
Alors l'action est enregistrée localement: Et je vois "Signalement enregistré. Sera envoyé à la reconnexion."
6. Progression audio-guide en mode offline
Étant donné que je n'ai aucune connexion Internet Et que j'écoute un audio-guide multi-séquences
Quand je termine la séquence 3/10
Alors la progression est enregistrée localement: Et ma progression est sauvegardée
7. Multiple actions offline stockées en queue
Étant donné que je n'ai aucune connexion Internet pendant 2 jours
Quand j'effectue plusieurs actions:
| action | cible |
|---|---|
| like | contenu A |
| like | contenu B |
| subscribe | créateur X |
| unlike | contenu C |
| report | contenu D |
Alors les 5 actions sont stockées dans pending_actions Et elles seront synchronisées dans l'ordre à la reconnexion
8. Détection reconnexion Internet
Étant donné que j'étais en mode offline
Quand l'app détecte une reconnexion Internet
Alors le processus de synchronisation démarre automatiquement Et je vois une notification "Synchronisation en cours..."
9. Récupération queue locale pendant sync
Étant donné que la synchronisation démarre
Quand l'app récupère les actions en attente
Alors une requête SQL est exécutée: Et toutes les actions sont récupérées dans l'ordre chronologique
10. Envoi batch API des actions
Étant donné que 15 actions sont en attente
Quand le batch est envoyé au backend
Alors une requête POST /sync/actions est faite: Et toutes les actions sont groupées en une seule requête
11. Backend traite chaque action
Étant donné que le backend reçoit le batch d'actions
Quand il traite chaque action
Alors pour chaque action:
| étape | détail |
|---|---|
| Validation | Vérifier user_id, content_id valides |
| Vérification existence | Contenu/créateur existe toujours ? |
| Application action | INSERT/UPDATE/DELETE en base |
| Mise à jour compteurs | Likes, abonnés, etc. |
| Impact sur algorithme | Mise à jour jauges si nécessaire |
12. Confirmation réception et suppression queue locale
Étant donné que le backend a traité toutes les actions avec succès
Quand la confirmation est reçue par l'app
Alors les actions sont supprimées de la queue locale: Et la table pending_actions est vidée
13. Toast confirmation synchronisation
Étant donné que 15 actions ont été synchronisées
Quand la synchronisation se termine
Alors je vois un toast:
14. Synchronisation silencieuse si peu d'actions
Étant donné que j'ai seulement 2 actions en attente
Quand la synchronisation se termine
Alors aucun toast n'est affiché (sync silencieuse) Et l'expérience reste fluide Mais je peux voir le détail dans l'historique des syncs
15. Échec synchronisation - Retry automatique
Étant donné que la synchronisation échoue (erreur réseau)
Quand l'échec est détecté
Alors un retry automatique est programmé dans 30 secondes Et les actions restent dans pending_actions
16. 3 tentatives échouées - Notification utilisateur
Étant donné que 3 tentatives de synchronisation ont échoué
Quand la 3ème tentative échoue
Alors je reçois une notification:
17. Actions conservées jusqu'à sync réussie
Étant donné que la synchronisation échoue plusieurs fois
Quand les tentatives continuent d'échouer
Alors les actions restent dans pending_actions Et aucune action n'est perdue Et elles seront envoyées dès que la connexion sera stable
18. Rétention max 7 jours - Purge automatique
Étant donné qu'une action est en attente depuis 7 jours
Quand le système détecte cette ancienneté
Alors l'action est automatiquement supprimée de la queue Et je vois "1 action trop ancienne supprimée (>7 jours)" Et cela évite une queue infinie
19. Justification rétention 7 jours
Étant donné qu'un utilisateur ne se connecte jamais pendant 2 semaines
Quand ses actions ont >7 jours
Alors elles sont purgées automatiquement Et évite une queue qui grandit indéfiniment
20. Retry manuel après échec
Étant donné que la synchronisation a échoué
Quand je clique sur "Réessayer maintenant"
Alors une nouvelle tentative de synchronisation est lancée immédiatement Et si elle réussit, les actions sont synchronisées
21. Backend retourne contenus supprimés
Étant donné que j'ai liké un contenu offline Mais que le contenu a été supprimé entre temps
Quand le backend traite la synchronisation
Alors il retourne:
22. App supprime fichiers locaux contenus supprimés
Étant donné que le backend retourne deleted_content_ids: [123, 456]
Quand l'app traite la réponse
Alors elle supprime les fichiers locaux des contenus 123 et 456 Et libère l'espace disque Et les actions associées sont retirées de la queue
23. Contenu supprimé en cours d'écoute
Étant donné que j'écoute le contenu 123 en offline Et que la sync détecte que le contenu a été supprimé
Quand la lecture actuelle se termine
Alors l'app attend 2 secondes Et passe automatiquement au contenu suivant Et le fichier du contenu 123 est supprimé en arrière-plan
24. Toast notification contenu retiré
Étant donné que 2 contenus téléchargés ont été supprimés
Quand la synchronisation se termine
Alors je vois un toast:
25. Contenu modéré après téléchargement
Étant donné que j'ai téléchargé un contenu qui est ensuite modéré
Quand la synchronisation détecte la modération
Alors le contenu est immédiatement supprimé du device Et je ne peux plus l'écouter Et cela garantit la conformité même offline
26. Justification pas de conflit possible
Étant donné que les actions offline sont unilatérales (likes, abonnements)
Quand elles sont synchronisées
Alors il n'y a pas de conflit de version possible Et pas de merge complexe nécessaire
27. Justification UX fluide offline
Étant donné que toutes les actions fonctionnent offline
Quand l'utilisateur interagit sans connexion
Alors l'expérience est identique au mode online Et l'utilisateur n'est pas bloqué Et peut utiliser l'app normalement
28. Justification batch = Économie requêtes
Étant donné que 15 actions sont en attente
Quand elles sont synchronisées en batch
Alors 1 seule requête HTTP est envoyée (vs 15 si individuelles) Et cela économise la bande passante et la batterie Et réduit la charge serveur
29. Justification conformité modération offline
Étant donné qu'un contenu illégal est modéré pendant qu'un user est offline
Quand le user se reconnecte
Alors le contenu est immédiatement supprimé de son device Et cela garantit que les contenus illégaux disparaissent même offline
30. Historique synchronisations
Étant donné que j'accède à "Paramètres > Synchronisation"
Quand je consulte l'historique
Alors je vois:
| date | actions sync | statut |
|---|---|---|
| 15/06/2025 14:30:00 | 15 | Réussi ✅ |
| 14/06/2025 09:15:00 | 7 | Réussi ✅ |
| 13/06/2025 18:45:00 | 3 | Échec ❌ |
31. Détail d'une synchronisation
Étant donné que je clique sur une ligne de l'historique
Quand le détail s'affiche
Alors je vois:
32. Compteur actions en attente visible
Étant donné que j'ai 12 actions en attente de synchronisation
Quand j'accède à l'onglet Profil
Alors je vois un badge "12" sur l'icône de synchronisation Et je sais qu'il y a des actions en attente
33. Synchronisation manuelle forcée
Étant donné que je veux forcer une synchronisation immédiate
Quand je vais dans "Paramètres > Synchronisation" Et que je clique sur "Synchroniser maintenant"
Alors la synchronisation démarre immédiatement Et toutes les actions en attente sont envoyées
34. Statistiques utilisateur - Syncs effectuées
Étant donné que j'accède à mes statistiques
Quand je consulte la section Synchronisation
Alors je vois:
| métrique | valeur |
|---|---|
| Synchronisations depuis début | 87 |
| Actions synchronisées total | 1,234 |
| Taux de succès | 94% |
| Dernière sync | Il y a 2h |
35. Statistiques admin - Volume synchronisations
Étant donné qu'un admin consulte les métriques de synchronisation
Quand il accède au dashboard
Alors il voit:
| métrique | valeur |
|---|---|
| Synchronisations/jour | 45,678 |
| Actions synchronisées/jour | 234,567 |
| Taux succès sync | 96.5% |
| Temps moyen traitement batch | 0.8s |
| Actions en attente (global) | 12,345 |
36. Alerte admin si taux échec sync >10%
Étant donné que le taux d'échec sync dépasse 10%
Quand le système détecte cette anomalie
Alors une alerte est envoyée:
37. Synchronisation rapide <2s
Étant donné que j'ai 20 actions en attente
Quand la synchronisation démarre
Alors le traitement prend <2 secondes Et je ne remarque aucun ralentissement de l'app
38. Synchronisation de gros batch (100 actions)
Étant donné que je n'ai pas synchronisé pendant 1 semaine Et que j'ai 100 actions en attente
Quand la synchronisation démarre
Alors le batch de 100 actions est traité en <5 secondes Et toutes les actions sont synchronisées avec succès
39. Gestion charge serveur - 10 000 syncs simultanées
Étant donné que 10 000 utilisateurs se reconnectent simultanément
Quand chacun envoie un batch de 20 actions
Alors le serveur traite 200 000 actions Et grâce au traitement asynchrone (queue Redis), le temps de réponse reste <3s Et aucun timeout n'est constaté
40. Stockage SQLite optimisé
Étant donné que la table pending_actions stocke des centaines d'actions
Quand des requêtes sont exécutées
Alors la table est indexée sur created_at Et les requêtes SELECT et DELETE sont instantanées (<10ms) Et l'expérience utilisateur reste fluide
41. Nettoyage automatique table pending_actions
Étant donné que la table pending_actions grossit avec le temps
Quand les actions sont synchronisées et supprimées
Alors la table est automatiquement optimisée (VACUUM sur SQLite) Et l'espace disque est libéré Et les performances restent optimales
42. Action dupliquée - Idempotence
Étant donné que j'ai liké un contenu offline Et que la sync échoue et retry
Quand le backend reçoit 2 fois le même like
Alors il applique l'idempotence (1 seul like enregistré) Et le compteur de likes n'est pas faussé
43. Séquence like/unlike offline
Étant donné que j'ai liké puis unliké un contenu offline
Quand les 2 actions sont synchronisées
Alors le backend applique les 2 actions dans l'ordre Et le résultat final est "pas de like" (état correct)
44. Abonnement puis désabonnement offline
Étant donné que je me suis abonné puis désabonné d'un créateur offline
Quand les 2 actions sont synchronisées
Alors le backend applique les 2 actions dans l'ordre Et le résultat final est "pas abonné" Et les jauges évoluent correctement (+5% puis -5% = 0% net)
45. Créateur supprimé pendant offline
Étant donné que je me suis abonné à un créateur offline Mais que le créateur a supprimé son compte entre temps
Quand la sync traite l'abonnement
Alors le backend retourne "creator_deleted" Et l'action est ignorée silencieusement Et aucune erreur n'est affichée à l'utilisateur
Téléchargement de contenus offline
En tant qu'utilisateur Je veux télécharger des contenus pour les écouter sans connexion Afin de profiter de RoadWave même dans les zones sans réseau
49 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis connecté à l'application RoadWave
1. Option "Autour de moi" - Rayon 50 km
Étant donné que je suis à Paris (position GPS détectée)
Quand je sélectionne "Télécharger > Autour de moi"
Alors l'app recherche tous les contenus géolocalisés dans un rayon de 50 km Et je vois une liste de contenus de Paris et banlieue proche Et l'estimation affiche "~150 contenus disponibles"
2. Option "Ma ville" - Limite administrative détectée
Étant donné que je suis à Lyon (position GPS détectée)
Quand je sélectionne "Télécharger > Ma ville"
Alors l'app détecte automatiquement "Lyon" comme ville Et recherche tous les contenus géolocalisés "Lyon" Et je vois uniquement les contenus de la ville de Lyon (pas banlieue)
3. Option "Mon département" - Sélection dans liste
Étant donné que je veux télécharger des contenus pour un département
Quand je sélectionne "Télécharger > Mon département"
Alors je vois une liste de tous les départements français:
| département |
|---|
| 01 - Ain |
| 02 - Aisne |
| 75 - Paris |
| 69 - Rhône |
| ... |
Et je peux choisir un département
4. Sélection département et téléchargement contenus
Étant donné que je sélectionne "75 - Paris" dans la liste des départements
Quand la sélection est confirmée
Alors l'app recherche tous les contenus géolocalisés "Paris" Et je vois "~234 contenus disponibles pour Paris"
5. Option "Ma région" - Sélection dans liste
Étant donné que je veux télécharger des contenus pour une région
Quand je sélectionne "Télécharger > Ma région"
Alors je vois une liste de toutes les régions françaises:
| région |
|---|
| Auvergne-Rhône-Alpes |
| Bretagne |
| Île-de-France |
| Nouvelle-Aquitaine |
| Occitanie |
| ... |
Et je peux choisir une région
6. Sélection région et téléchargement contenus
Étant donné que je sélectionne "Bretagne" dans la liste des régions
Quand la sélection est confirmée
Alors l'app recherche tous les contenus géolocalisés des départements bretons:
| département |
|---|
| Côtes-d'Armor (22) |
| Finistère (29) |
| Ille-et-Vilaine (35) |
| Morbihan (56) |
Et je vois "~487 contenus disponibles pour Bretagne"
7. Recherche manuelle ville
Étant donné que je veux télécharger des contenus pour une ville spécifique
Quand je tape "Marseille" dans la barre de recherche
Alors l'app propose des suggestions:
| suggestion |
|---|
| Marseille (13) |
| Marseille-en-Beauvaisis |
Et je peux sélectionner "Marseille (13)"
8. Recherche manuelle avec autocomplétion
Étant donné que je tape "Ly" dans la barre de recherche
Quand l'autocomplétion s'active
Alors je vois des suggestions:
| suggestion |
|---|
| Lyon (69) |
| Lys-lez-Lannoy |
Et je peux affiner ma recherche
9. Utilisateur gratuit - Limite 50 contenus max
Étant donné que je suis un utilisateur gratuit Et que j'ai déjà téléchargé 45 contenus
Quand j'accède à la page Téléchargements
Alors je vois "45 / 50 contenus téléchargés" Et je peux télécharger 5 contenus supplémentaires maximum
10. Utilisateur gratuit - Tentative dépasser limite 50
Étant donné que je suis gratuit et j'ai déjà 50 contenus téléchargés
Quand j'essaie de télécharger un 51ème contenu
Alors le téléchargement est refusé Et je vois le message:
11. Utilisateur Premium - Téléchargements illimités
Étant donné que je suis un utilisateur Premium Et que j'ai déjà téléchargé 245 contenus
Quand j'accède à la page Téléchargements
Alors je vois "245 contenus (3.2 GB)" Et aucune limite n'est affichée Et je peux télécharger autant de contenus que je veux
12. Limite Premium = Espace disque disponible
Étant donné que je suis Premium Et que mon device a 500 MB d'espace disque disponible
Quand j'essaie de télécharger 100 contenus (2 GB)
Alors le téléchargement échoue après ~50 contenus (500 MB) Et je vois "Espace disque insuffisant. Libérez de l'espace pour continuer."
13. Calcul temps écoute disponible gratuit
Étant donné que je suis gratuit avec 50 contenus téléchargés Et que la durée moyenne d'un contenu est 5 minutes
Quand je calcule le temps d'écoute disponible
Alors 50 contenus × 5 min = 250 minutes = 4h10 d'écoute Et cela suffit pour un trajet quotidien ou road trip court
14. Calcul temps écoute disponible Premium illimité
Étant donné que je suis Premium avec 300 contenus téléchargés Et que la durée moyenne est 5 minutes
Quand je calcule le temps d'écoute disponible
Alors 300 contenus × 5 min = 1500 minutes = 25h d'écoute Et cela suffit pour un road trip de plusieurs jours
15. Téléchargement par défaut en WiFi uniquement
Étant donné que je suis connecté en WiFi
Quand je clique sur "Télécharger 20 contenus"
Alors le téléchargement démarre immédiatement Et aucune popup de confirmation n'apparaît
16. Tentative téléchargement en données mobiles - Popup confirmation
Étant donné que je suis connecté en 4G (pas de WiFi)
Quand je clique sur "Télécharger 20 contenus"
Alors une popup apparaît:
17. Calcul estimation consommation data mobile
Étant donné que je veux télécharger 20 contenus Et que la durée moyenne est 5 minutes Et que la qualité Standard est 48 kbps Opus
Quand l'estimation est calculée
Alors consommation = 20 contenus × 5 min × 48 kbps / 8 = 72 MB Et ce montant est affiché dans la popup
18. Confirmation téléchargement en données mobiles
Étant donné que je vois la popup de confirmation données mobiles
Quand je clique sur "Continuer quand même"
Alors le téléchargement démarre immédiatement via 4G Et la consommation data est comptabilisée sur mon forfait mobile
19. Refus téléchargement données mobiles - Attendre WiFi
Étant donné que je vois la popup de confirmation données mobiles
Quand je clique sur "Attendre WiFi"
Alors les téléchargements sont mis en file d'attente Et ils démarreront automatiquement quand le WiFi sera détecté
20. Détection automatique WiFi et reprise téléchargements
Étant donné que j'ai mis 20 contenus en file d'attente (attente WiFi)
Quand l'app détecte une connexion WiFi
Alors les téléchargements démarrent automatiquement Et je reçois une notification "Téléchargements en cours via WiFi"
21. Qualité Standard (48 kbps) par défaut
Étant donné que je configure mes téléchargements
Quand j'accède aux paramètres de qualité
Alors la qualité "Standard (48 kbps - ~20 MB/h)" est sélectionnée par défaut Et elle est disponible pour tous (gratuit + Premium)
22. Qualité Basse (24 kbps) disponible pour tous
Étant donné que j'ai peu d'espace disque disponible
Quand je sélectionne qualité "Basse (24 kbps - ~10 MB/h)"
Alors mes prochains téléchargements seront en 24 kbps Et l'espace utilisé sera divisé par 2 par rapport à Standard Et cette option est disponible pour gratuit + Premium
23. Qualité Haute (64 kbps) réservée Premium
Étant donné que je suis un utilisateur gratuit
Quand je consulte les options de qualité
Alors l'option "Haute (64 kbps - ~30 MB/h)" est grisée Et je vois "👑 Premium uniquement" Et je ne peux pas la sélectionner
24. Utilisateur Premium peut choisir qualité Haute
Étant donné que je suis un utilisateur Premium
Quand je consulte les options de qualité
Alors l'option "Haute (64 kbps - ~30 MB/h)" est disponible Et je peux la sélectionner pour mes téléchargements Et la qualité audio sera excellente (meilleure restitution voix et ambiances)
25. Comparaison taille fichiers selon qualité
Étant donné que je veux télécharger 50 contenus de 5 min chacun
Quand je compare les qualités
Alors les tailles totales sont:
| qualité | bitrate | taille totale |
|---|---|---|
| Basse | 24 kbps | ~250 MB |
| Standard | 48 kbps | ~500 MB |
| Haute | 64 kbps | ~650 MB |
26. Justification Standard = Bon compromis
Étant donné que le contenu RoadWave est principalement de la voix
Quand la qualité Standard (48 kbps Opus) est utilisée
Alors la qualité est très correcte pour la voix Et équivalente à la radio FM Et le compromis qualité/taille est optimal
27. Justification Haute réservée Premium = Incitation upgrade
Étant donné qu'un utilisateur gratuit veut la meilleure qualité
Quand il voit que Haute est réservée Premium
Alors cela l'incite à passer Premium pour 4.99€/mois Et c'est un avantage tangible supplémentaire de Premium
28. Changement qualité après téléchargements existants
Étant donné que j'ai déjà téléchargé 30 contenus en qualité Standard
Quand je change la qualité vers Haute (si Premium)
Alors les 30 contenus existants restent en Standard Et seuls les nouveaux téléchargements seront en Haute Et je peux manuellement re-télécharger les 30 contenus pour les avoir en Haute
29. Téléchargement individuel d'un contenu
Étant donné que je consulte la page d'un contenu
Quand je clique sur l'icône de téléchargement 📥
Alors le téléchargement démarre Et une barre de progression apparaît Et l'icône devient ✅ quand terminé
30. Téléchargement batch de contenus sélectionnés
Étant donné que je consulte une liste de contenus pour "Paris"
Quand je sélectionne 15 contenus manuellement Et que je clique sur "Télécharger la sélection"
Alors les 15 contenus sont téléchargés en parallèle (max 3 simultanés) Et une notification affiche "15 contenus téléchargés"
31. Téléchargement automatique recommandations zone
Étant donné que je sélectionne "Autour de moi" (Paris)
Quand je clique sur "Télécharger les 50 meilleurs contenus"
Alors l'algorithme sélectionne automatiquement les 50 contenus les mieux notés/récents Et les télécharge tous Et je n'ai pas besoin de choisir manuellement
32. Barre de progression téléchargement global
Étant donné que je télécharge 20 contenus
Quand les téléchargements sont en cours
Alors je vois une barre de progression globale:
33. Téléchargements en tâche de fond
Étant donné que je lance le téléchargement de 30 contenus
Quand je ferme l'app ou passe à une autre activité
Alors les téléchargements continuent en arrière-plan Et je reçois une notification quand tous sont terminés
34. Pause et reprise téléchargements
Étant donné que je télécharge 20 contenus
Quand je clique sur "Pause"
Alors les téléchargements en cours se terminent Et les téléchargements en attente sont mis en pause Et je peux cliquer sur "Reprendre" plus tard
35. Annulation téléchargements
Étant donné que je télécharge 20 contenus
Quand je clique sur "Annuler"
Alors tous les téléchargements sont arrêtés Et les fichiers partiels sont supprimés Et l'espace disque est libéré
36. Gestion erreurs téléchargement
Étant donné que je télécharge un contenu Mais que la connexion Internet coupe au milieu
Quand la connexion revient
Alors le téléchargement reprend automatiquement où il s'était arrêté Et aucune perte de progression n'a lieu
37. Retry automatique après échec
Étant donné qu'un téléchargement échoue 3 fois consécutives
Quand l'échec est détecté
Alors le contenu est marqué "Échec" Et je vois une notification "3 contenus n'ont pas pu être téléchargés" Et je peux retry manuellement en cliquant sur "Réessayer"
38. Liste contenus téléchargés
Étant donné que j'ai téléchargé 45 contenus
Quand j'accède à "Téléchargements"
Alors je vois la liste complète de mes 45 contenus Et pour chaque contenu: titre, créateur, durée, taille, date téléchargement
39. Tri contenus téléchargés
Étant donné que je consulte ma liste de téléchargements
Quand je clique sur "Trier par"
Alors je peux trier par:
| critère | ordre |
|---|---|
| Date téléchargement | Plus récent / Plus ancien |
| Titre | A-Z / Z-A |
| Créateur | A-Z / Z-A |
| Durée | Plus long / Plus court |
| Taille | Plus gros / Plus petit |
40. Recherche dans contenus téléchargés
Étant donné que j'ai 200 contenus téléchargés
Quand je tape "Tesla" dans la barre de recherche
Alors seuls les contenus contenant "Tesla" s'affichent Et je peux rapidement trouver un contenu spécifique
41. Suppression individuelle contenu téléchargé
Étant donné que je veux supprimer un contenu téléchargé
Quand je swipe left (iOS) ou long press (Android) sur le contenu Et que je clique sur "Supprimer"
Alors le fichier est supprimé du device Et l'espace disque est libéré Et le compteur est décrémenté (ex: 45/50 → 44/50)
42. Suppression batch contenus téléchargés
Étant donné que je veux supprimer plusieurs contenus
Quand je sélectionne 10 contenus Et que je clique sur "Supprimer la sélection"
Alors les 10 fichiers sont supprimés Et ~100 MB d'espace disque sont libérés Et une notification confirme "10 contenus supprimés"
43. Suppression tous les contenus téléchargés
Étant donné que j'ai 45 contenus téléchargés
Quand je clique sur "Supprimer tout" Et que je confirme l'action
Alors tous les 45 contenus sont supprimés Et l'espace disque total est libéré (~450 MB) Et le compteur repasse à 0/50
44. Espace disque utilisé visible
Étant donné que j'ai téléchargé 45 contenus
Quand j'accède à la page Téléchargements
Alors je vois l'espace disque utilisé:
45. Statistiques téléchargements
Étant donné que j'accède à mes statistiques
Quand je consulte la section Téléchargements
Alors je vois:
| métrique | valeur |
|---|---|
| Contenus actuellement téléchargés | 45 |
| Espace disque utilisé | 478 MB |
| Contenus téléchargés depuis début | 287 |
| Total data téléchargée | 3.2 GB |
| Téléchargements via WiFi | 92% |
| Téléchargements via mobile | 8% |
46. Lecture contenu téléchargé sans connexion
Étant donné que je n'ai aucune connexion Internet (mode avion) Et que j'ai des contenus téléchargés
Quand je lance un contenu téléchargé
Alors la lecture démarre normalement depuis le fichier local Et aucune erreur de connexion n'apparaît
47. Badge "Téléchargé" sur contenus offline
Étant donné que j'ai téléchargé certains contenus
Quand je consulte une liste de contenus
Alors les contenus téléchargés ont un badge ✅ "Offline" Et je sais immédiatement lesquels sont disponibles sans connexion
48. Filtre "Téléchargés uniquement"
Étant donné que je veux voir uniquement mes contenus offline
Quand j'active le filtre "Téléchargés uniquement"
Alors seuls les contenus téléchargés s'affichent Et je peux facilement naviguer dans mon catalogue offline
49. Playlist offline automatique
Étant donné que j'ai téléchargé 45 contenus
Quand j'accède à "Téléchargements"
Alors je peux lancer une playlist aléatoire de mes 45 contenus Et profiter d'une écoute continue offline
Validité et renouvellement contenus offline
En tant qu'utilisateur Je veux que mes contenus téléchargés restent valides un certain temps Afin de garantir la légalité et la fraîcheur du contenu
38 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis connecté à l'application RoadWave Et que j'ai des contenus téléchargés
1. Validité de 30 jours après téléchargement
Étant donné que je télécharge un contenu le 1er juin 2025
Quand le téléchargement est terminé
Alors le contenu est valide jusqu'au 1er juillet 2025 (30 jours) Et la date d'expiration est stockée en local
2. Affichage date expiration sur contenu téléchargé
Étant donné que j'ai téléchargé un contenu il y a 20 jours
Quand je consulte les détails du contenu
Alors je vois "Expire dans 10 jours" Et je sais combien de temps il reste avant expiration
3. Standard industrie aligné (Spotify, YouTube, Deezer)
Étant donné que Spotify, YouTube Music et Deezer utilisent 30 jours
Quand RoadWave fixe également 30 jours
Alors c'est le standard accepté par les utilisateurs Et il n'y a pas de confusion avec les autres plateformes
4. Justification 30 jours - Force reconnexion régulière
Étant donné qu'un utilisateur ne se connecte jamais
Quand ses contenus expirent après 30 jours
Alors il est obligé de se reconnecter pour les renouveler Et le système peut vérifier:
| vérification |
|---|
| Abonnement Premium toujours actif |
| Contenus non modérés/supprimés |
| Métadonnées à jour |
5. Justification 30 jours - Évite stockage obsolète
Étant donné qu'un contenu a été modéré après téléchargement
Quand le contenu expire après 30 jours maximum
Alors le contenu illégal est automatiquement supprimé Et ne reste pas indéfiniment sur le device
6. Détection WiFi et contenus >25 jours
Étant donné que j'ai des contenus téléchargés il y a 26 jours
Quand l'app détecte une connexion WiFi
Alors une requête GET /offline/contents/refresh est envoyée Et le backend vérifie chaque contenu
7. Vérification abonnement Premium toujours actif
Étant donné qu'un contenu téléchargé en Premium est à renouveler
Quand le backend vérifie le statut Et que l'abonnement Premium est toujours actif
Alors la validité est renouvelée à 30 jours supplémentaires
8. Abonnement Premium expiré - Contenu non renouvelé
Étant donné qu'un contenu Premium téléchargé est à renouveler
Quand le backend vérifie le statut Et que l'abonnement Premium a expiré
Alors le contenu n'est pas renouvelé Et il sera supprimé à l'expiration (J-0) Et l'utilisateur voit "Contenu Premium expiré (abonnement inactif)"
9. Vérification contenu pas modéré/supprimé
Étant donné qu'un contenu téléchargé est à renouveler
Quand le backend vérifie le statut Et que le contenu a été modéré ou supprimé entre temps
Alors le contenu n'est pas renouvelé Et sera supprimé immédiatement du device Et l'utilisateur voit "1 contenu retiré (violation règles)"
10. Mise à jour métadonnées lors du renouvellement
Étant donné qu'un contenu téléchargé est renouvelé
Quand le backend traite le renouvellement
Alors les métadonnées sont mises à jour:
| métadonnée | mise à jour si changée |
|---|---|
| Titre | ✅ |
| Nom créateur | ✅ |
| Description | ✅ |
| Tags | ✅ |
| Statut Premium | ✅ |
Et l'utilisateur voit les infos à jour
11. Pas de re-téléchargement audio si fichier OK
Étant donné qu'un contenu est renouvelé
Quand le fichier audio local est intact
Alors seules les métadonnées sont mises à jour Et le fichier audio n'est pas re-téléchargé Et cela économise la bande passante
12. Re-téléchargement audio si fichier corrompu
Étant donné qu'un contenu est renouvelé
Quand le fichier audio local est corrompu (checksum invalide)
Alors le fichier audio est re-téléchargé entièrement Et le nouveau fichier remplace le corrompu
13. Renouvellement silencieux si WiFi régulier
Étant donné que je me connecte en WiFi tous les jours
Quand mes contenus atteignent 25-30 jours
Alors ils sont automatiquement renouvelés en arrière-plan Et je ne vois aucune notification (processus transparent) Et mes contenus restent valides indéfiniment
14. Renouvellement batch de plusieurs contenus
Étant donné que j'ai 30 contenus à renouveler
Quand le renouvellement automatique se déclenche
Alors une requête batch est envoyée: Et le backend traite les 30 contenus en une seule requête Et cela économise les requêtes HTTP
15. Temps de traitement renouvellement
Étant donné que 30 contenus sont à renouveler
Quand la requête batch est traitée
Alors le backend répond en <2 secondes Et les métadonnées sont mises à jour localement Et l'utilisateur ne remarque aucun ralentissement
16. Notification J-3 avant expiration
Étant donné que j'ai 15 contenus qui expirent dans 3 jours
Quand le système vérifie les expirations
Alors je reçois une notification: Et je peux agir avant l'expiration
17. Pas de notification si connexion WiFi régulière
Étant donné que je me connecte en WiFi tous les jours Et que mes contenus sont automatiquement renouvelés
Quand le système vérifie les expirations
Alors aucune notification J-3 n'est envoyée
18. Notification uniquement si contenus non renouvelés
Étant donné que j'ai 20 contenus dont 15 renouvelés et 5 non renouvelés
Quand le J-3 arrive pour les 5 non renouvelés
Alors je reçois "5 contenus expirent dans 3 jours" Et seuls les contenus à risque sont mentionnés
19. Action utilisateur après notification J-3
Étant donné que je reçois la notification J-3
Quand je clique sur la notification
Alors l'app s'ouvre sur la page Téléchargements Et je vois les contenus qui vont expirer en rouge Et je peux me connecter en WiFi pour les renouveler
20. Suppression automatique J-0 (expiration)
Étant donné qu'un contenu n'a pas été renouvelé
Quand le jour d'expiration arrive (J-0)
Alors le fichier est automatiquement supprimé du device Et l'espace disque est libéré Et le compteur est décrémenté (ex: 45/50 → 44/50)
21. Toast après suppression automatique J-0
Étant donné que 15 contenus viennent d'expirer
Quand l'utilisateur ouvre l'app
Alors il voit un toast:
22. Liste contenus supprimés après expiration
Étant donné que 15 contenus ont expiré
Quand je consulte l'historique des suppressions
Alors je vois la liste des 15 contenus supprimés:
| titre | créateur | date expiration |
|---|---|---|
| Mon épisode préféré | JeanDupont | 15 juin 2025 |
| Road trip Bretagne | MarieLambert | 15 juin 2025 |
| ... | ... | ... |
Et je peux les re-télécharger si je veux
23. Re-téléchargement après expiration
Étant donné qu'un contenu a expiré et été supprimé
Quand je retrouve ce contenu dans l'app
Alors le badge ✅ "Offline" n'est plus affiché Et je peux le re-télécharger normalement Et la validité repart à 30 jours
24. Utilisateur ne se connecte jamais pendant 30 jours
Étant donné que je télécharge 50 contenus le 1er juin Mais que je ne me connecte jamais en WiFi pendant 30 jours
Quand le 1er juillet arrive
Alors tous les 50 contenus expirent Et sont automatiquement supprimés Et je n'ai plus aucun contenu offline
25. Utilisateur en zone blanche 30+ jours
Étant donné que je télécharge 50 contenus avant de partir en zone sans réseau Et que je reste 45 jours sans connexion
Quand les contenus expirent après 30 jours
Alors ils sont supprimés même si je ne peux pas me connecter Et je perds l'accès à mes contenus offline
26. Recommandation téléchargement avant zone blanche longue
Étant donné que je prépare un road trip de 60 jours
Quand je consulte la FAQ
Alors je vois la recommandation:
27. Changement statut Premium en gratuit pendant validité
Étant donné que je suis Premium et j'ai téléchargé 200 contenus
Quand mon abonnement Premium expire Et que je repasse en gratuit
Alors au prochain renouvellement, seulement 50 contenus sont conservés Et les 150 autres sont supprimés (limite gratuit) Et je vois "Limite gratuit (50 contenus) appliquée. 150 contenus supprimés."
28. Sélection automatique 50 meilleurs contenus si passage gratuit
Étant donné que je repasse en gratuit avec 200 contenus téléchargés
Quand le système applique la limite de 50
Alors les 50 contenus les plus récemment écoutés sont conservés Et les 150 autres sont supprimés Et cela maximise les chances de garder les contenus que j'aime
29. Contenus Premium exclusifs supprimés si abonnement expire
Étant donné que j'ai téléchargé 20 contenus Premium exclusifs
Quand mon abonnement Premium expire
Alors les 20 contenus Premium sont immédiatement supprimés Et je vois "20 contenus Premium supprimés (abonnement expiré)"
30. Affichage temps restant avant expiration
Étant donné que j'ai 45 contenus téléchargés
Quand je consulte la page Téléchargements
Alors je vois pour chaque contenu:
| contenu | temps restant |
|---|---|
| Mon épisode (récent) | Expire dans 28 jours |
| Road trip (ancien) | Expire dans 3 jours |
Et je sais lesquels sont prioritaires pour renouvellement
31. Tri par date expiration
Étant donné que j'ai 45 contenus avec différentes dates d'expiration
Quand je trie par "Expiration"
Alors les contenus qui expirent le plus tôt apparaissent en premier Et je peux voir rapidement lesquels nécessitent une reconnexion urgente
32. Badge rouge si expiration <3 jours
Étant donné qu'un contenu expire dans 2 jours
Quand je consulte la liste des téléchargements
Alors le contenu a un badge rouge "⚠️ Expire bientôt" Et il est visuellement mis en avant
33. Statistiques utilisateur - Taux de renouvellement
Étant donné que j'accède à mes statistiques
Quand je consulte la section Téléchargements
Alors je vois:
| métrique | valeur |
|---|---|
| Contenus actuels | 45 |
| Contenus expirés depuis début | 87 |
| Contenus renouvelés (auto) | 234 |
| Taux renouvellement automatique | 73% |
34. Statistiques admin - Taux expiration global
Étant donné qu'un admin consulte les métriques offline
Quand il accède au dashboard
Alors il voit:
| métrique | valeur |
|---|---|
| Contenus téléchargés actifs | 1,234,567 |
| Expirations ce mois | 45,678 |
| Taux expiration | 3.7% |
| Renouvellements automatiques/mois | 234,567 |
35. Alerte admin si taux expiration >10%
Étant donné que le taux d'expiration mensuel dépasse 10%
Quand le système détecte cette anomalie
Alors une alerte est envoyée:
36. Email rappel si pas de connexion WiFi depuis 20 jours
Étant donné que je n'ai pas connecté l'app en WiFi depuis 20 jours Et que j'ai 45 contenus téléchargés
Quand le système détecte cette inactivité WiFi
Alors je reçois un email:
37. Performance renouvellement avec 10 000 utilisateurs simultanés
Étant donné que 10 000 utilisateurs se connectent en WiFi simultanément
Quand chacun demande le renouvellement de 50 contenus
Alors le serveur traite 500 000 vérifications Et grâce au cache Redis et index PostgreSQL, le temps de réponse reste <3s Et les serveurs gèrent la charge sans problème
38. Logs audit renouvellements
Étant donné qu'un contenu est renouvelé
Quand l'opération se termine
Alors un log est enregistré:
| timestamp | user_id | content_id | action | résultat |
|---|---|---|---|---|
| 2025-06-15 14:30:00 | abc123 | xyz789 | renew | success (+30d) |
| 2025-06-15 14:30:01 | abc123 | def456 | renew | failed (deleted) |
Et ces logs aident à débugger les problèmes
Modération préventive
22 scénarios
Contexte commun à tous les scénarios
Étant donné que le système de modération préventive est actif
1. Créateur nouvellement inscrit
Étant donné que je viens de créer un compte créateur Et que je n'ai jamais publié de contenu
Quand j'examine mon statut de créateur
Alors mon compte est marqué comme "Nouveau créateur" Et mes 3 premiers contenus devront être validés manuellement Et je suis informé de ce processus lors de l'onboarding
2. Publication du premier contenu par un nouveau créateur
Étant donné que je suis un nouveau créateur Et que je n'ai publié aucun contenu auparavant
Quand je publie mon premier contenu
Alors le contenu entre en file d'attente de validation manuelle Et le statut du contenu est "En attente de validation" Et le contenu n'est pas diffusé sur la plateforme Et je reçois une notification:
3. Validation manuelle par un modérateur
Étant donné que j'ai publié mon premier contenu Et que le contenu est en attente de validation
Quand un modérateur examine mon contenu
Alors le modérateur utilise la transcription automatique Whisper Et le modérateur vérifie:
| critère | conforme |
|---|---|
| Respect des règles communauté | oui |
| Pas de contenu inapproprié | oui |
| Qualité audio acceptable | oui |
| Métadonnées cohérentes | oui |
| Tags appropriés | oui |
Et si tout est conforme, le contenu est validé
4. Délai de validation de 24-48h jours ouvrés
Étant donné que j'ai publié mon premier contenu lundi à 10:00
Quand le contenu entre en file de validation
Alors le contenu est validé avant mercredi 10:00 (48h jours ouvrés) Et dans la plupart des cas, la validation est effectuée sous 24h Et je reçois une notification dès que le contenu est validé
5. Notification de validation réussie
Étant donné que mon premier contenu a été validé par un modérateur
Quand la validation est approuvée
Alors je reçois une notification: Et le statut du contenu passe à "Publié" Et le contenu devient visible pour tous les utilisateurs Et il entre dans l'algorithme de recommandation
6. Refus de validation si contenu non conforme
Étant donné que mon premier contenu viole les règles de la communauté
Quand le modérateur examine le contenu
Alors le contenu est refusé Et je reçois une notification détaillée: Et le contenu reste en statut "Refusé" Et je peux modifier et republier
7. Les 3 premiers contenus sont validés manuellement
Étant donné que je suis un nouveau créateur
Quand je publie mes contenus
Alors les contenus suivants nécessitent une validation manuelle:
| contenu | validation manuelle |
|---|---|
| 1er | oui |
| 2ème | oui |
| 3ème | oui |
| 4ème | non (auto) |
Et après 3 contenus validés, mes futurs contenus sont publiés automatiquement
8. Passage en mode automatique après 3 validations
Étant donné que mes 3 premiers contenus ont été validés avec succès
Quand je publie mon 4ème contenu
Alors le contenu est publié automatiquement Et aucune validation manuelle n'est requise Et le statut passe directement à "Publié" Et je reçois une notification:
9. Évolution du score de confiance
Étant donné que je suis un créateur établi
Quand le système évalue mon historique
Alors un score de confiance est calculé basé sur:
| critère | poids |
|---|---|
| Nombre de contenus publiés | 20% |
| Strikes reçus | 40% |
| Signalements infondés | 20% |
| Ancienneté du compte | 10% |
| Taux d'engagement positif | 10% |
Et le score évolue dynamiquement
10. Créateur fiable - Publication automatique
Étant donné que je suis un créateur Et que j'ai 0 strike depuis 6 mois Et que tous mes contenus précédents ont été conformes
Quand mon score de confiance est calculé
Alors je suis classé comme "Créateur fiable" Et tous mes nouveaux contenus sont publiés automatiquement Et aucune validation manuelle n'est nécessaire Et je bénéficie d'une publication instantanée
11. Créateur suspect - Validation manuelle systématique
Étant donné que je suis un créateur Et que j'ai reçu 2 strikes récents (< 3 mois)
Quand mon score de confiance est recalculé
Alors je suis classé comme "Créateur suspect" Et tous mes nouveaux contenus nécessitent une validation manuelle Et chaque contenu est examiné avant publication Et je suis notifié de ce changement de statut:
12. Réhabilitation après période sans incident
Étant donné que j'étais un "Créateur suspect" Et que je publie 10 contenus conformes sur 6 mois Et que je ne reçois aucun nouveau strike
Quand le système réévalue mon score de confiance
Alors je passe en "Créateur fiable" Et la publication automatique est rétablie Et je reçois une notification de réhabilitation:
13. Toute publicité nécessite validation manuelle
Étant donné qu'un annonceur soumet une publicité audio
Quand la publicité est créée
Alors elle entre automatiquement en file de validation manuelle Et aucune publicité n'est diffusée sans validation préalable Et cela est obligatoire pour des raisons de responsabilité juridique
14. Validation d'une publicité - Processus complet
Étant donné qu'une publicité est en attente de validation
Quand un modérateur senior examine la publicité
Alors le modérateur vérifie:
| critère | conforme |
|---|---|
| Transcription automatique Whisper | effectuée |
| Contenu conforme aux règles | oui |
| Pas de fausse publicité / arnaque | oui |
| Respect du ciblage géographique | oui |
| Durée conforme (10-60s) | oui |
| Volume audio acceptable (pas trop fort) | oui |
| Métadonnées correctes | oui |
Et si tout est conforme, la publicité est validée
15. Délai de validation d'une publicité - 24-48h
Étant donné qu'un annonceur soumet une publicité lundi à 10:00
Quand la publicité entre en file de validation
Alors la publicité est validée avant mercredi 10:00 (48h jours ouvrés) Et l'annonceur est notifié dès la validation Et la campagne publicitaire peut alors démarrer
16. Refus de validation d'une publicité
Étant donné qu'une publicité contient des éléments non conformes
Quand le modérateur examine la publicité
Alors la publicité est refusée Et l'annonceur reçoit une notification détaillée: Et l'annonceur peut modifier et resoumettre la publicité Et aucun remboursement n'est effectué pour une publicité refusée
17. Économie de modération grâce à la prévention
Étant donné que la modération préventive est active
Quand on analyse l'efficacité du système
Alors 80% des contenus inappropriés sont détectés avant publication Et cela réduit le nombre de signalements de 70% Et les ressources de modération sont optimisées Et la qualité de la plateforme est préservée dès le début
18. Qualité de la plateforme maintenue
Étant donné que tous les nouveaux créateurs sont vérifiés
Quand on analyse la qualité globale des contenus
Alors le taux de contenus inappropriés est <1% Et les utilisateurs font confiance à la plateforme Et la réputation de RoadWave est préservée Et l'expérience utilisateur est optimale
19. Information claire sur le processus de validation
Étant donné que je suis un nouveau créateur
Quand je consulte la page d'aide "Validation des contenus"
Alors j'apprends que: Et le processus est clair et transparent
20. Badge "Créateur vérifié" après validation
Étant donné que mes 3 premiers contenus ont été validés avec succès
Quand je consulte mon profil créateur
Alors un badge discret "✓ Créateur vérifié" s'affiche Et ce badge rassure les auditeurs sur la qualité de mes contenus Et il améliore ma crédibilité sur la plateforme
21. Justification de la modération préventive
Étant donné que la modération préventive est en place
Quand on évalue les bénéfices
Alors les avantages suivants sont constatés:
| bénéfice |
|---|
| Prévention meilleure que réaction |
| Économie de ressources de modération (×3-5) |
| Qualité de la plateforme préservée dès le début |
| Confiance des utilisateurs renforcée |
| Moins de contenus inappropriés signalés |
| Réputation de la plateforme protégée |
Et l'investissement dans la prévention est rentable
22. Coût de la modération préventive
Étant donné que 100 nouveaux créateurs publient 3 contenus chacun Et que 50 publicités sont soumises par mois
Quand on calcule le coût de modération préventive
Alors le coût en temps modérateur est:
| type | nombre | temps/contenu | total |
|---|---|---|---|
| Nouveaux créateurs | 300 | 5 min | 25h |
| Publicités | 50 | 10 min | 8.3h |
Et le coût total est d'environ 33h de modération/mois Et c'est largement compensé par la réduction des signalements réactifs
Sanctions et notifications de modération
27 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis un créateur de contenu Et que j'ai publié un contenu
1. Notification multi-canal après sanction
Étant donné que mon contenu a été modéré
Quand la sanction est appliquée
Alors je reçois une notification sur 3 canaux:
| canal | timing | contenu |
|---|---|---|
| Push | Immédiat | "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 d'appel |
Et chaque canal contient un lien vers les détails complets
2. Notification push immédiate
Étant donné que mon contenu vient d'être modéré
Quand la sanction est appliquée
Alors je reçois une notification push immédiate Et le message est court: "⚠️ Votre contenu a été modéré" Et je peux cliquer pour voir les détails Et la notification utilise Firebase Cloud Messaging (Android) ou APNs (iOS) Et le coût est de 0€
3. Popup in-app au prochain lancement
Étant donné que mon contenu a été modéré
Quand j'ouvre l'application
Alors une popup détaillée s'affiche automatiquement Et la popup contient:
| élément | description |
|---|---|
| Titre du contenu | "Mon podcast #42" |
| Icône d'avertissement | ⚠️ |
| Catégorie violée | 🚫 Haine & violence |
| Sanction | Strike 2/4 - Suspension 7 jours |
| Bouton "Voir détails" | Redirige vers page détaillée |
| Bouton "Compris" | Ferme la popup |
Et je ne peux pas fermer la popup sans l'avoir vue
4. Email de notification complet dans l'heure
Étant donné que mon contenu a été modéré à 14:00
Quand la sanction est appliquée
Alors je reçois un email avant 15:00 (dans l'heure) Et l'objet de l'email est "Modération de votre contenu "[Titre du contenu]"" Et l'email contient toutes les informations détaillées Et le coût est d'environ 0.001€ par email (Brevo, Resend)
5. Email de notification complet et structuré
Étant donné que mon contenu "Mon podcast #42" a été modéré
Quand je reçois l'email de notification
Alors l'email contient la structure suivante:
6. Page détaillée de la sanction in-app
Étant donné que je clique sur "Voir détails" dans la notification
Quand la page détaillée s'affiche
Alors je vois les 6 éléments obligatoires:
| élément | contenu |
|---|---|
| 1. Catégorie violée | 🚫 Haine & violence (Article 3.2 CGU) |
| 2. Raison détaillée | Explication claire et non juridique |
| 3. Extrait audio | Timestamp exact: 3:42-4:15 |
| 4. Transcription | Texte problématique surligné en rouge |
| 5. Gravité | Strike actuel + conséquences (Strike 2/4, 7j susp) |
| 6. Recours | Lien formulaire d'appel + délai 7j |
7. Affichage du passage problématique avec timestamp
Étant donné que la page détaillée de la sanction est affichée
Quand je consulte l'extrait audio concerné
Alors le timestamp exact est affiché: "3:42-4:15" Et je peux écouter uniquement cette portion de l'audio Et un player audio intégré permet l'écoute du passage Et la transcription correspondante est affichée en dessous Et les mots/phrases problématiques sont surlignés en rouge
8. Référence précise aux CGU
Étant donné que la sanction fait référence à l'Article 3.2 des CGU
Quand je clique sur "Article 3.2"
Alors je suis redirigé vers la section correspondante des CGU Et la section "Haine & violence" est mise en évidence Et je peux lire exactement ce qui est interdit Et cela m'aide à comprendre mon erreur
9. Gravité de la sanction avec système de strikes
Étant donné que c'est mon 2ème strike
Quand je consulte les détails de la sanction
Alors je vois clairement "Strike 2/4" Et les conséquences sont explicitées: Et je comprends l'escalade des sanctions
10. Accès au formulaire d'appel depuis la notification
Étant donné que j'ai reçu une notification de modération
Quand je clique sur "Contester cette décision"
Alors je suis redirigé vers le formulaire d'appel Et le formulaire est pré-rempli avec les informations de la sanction Et je peux commencer à rédiger mon appel
11. Accès au formulaire d'appel depuis "Mes sanctions"
Étant donné que j'ai reçu une sanction il y a 2 jours
Quand j'ouvre "Profil créateur > Mes sanctions"
Alors je vois la liste de mes sanctions Et chaque sanction a un bouton "Faire appel" (si délai <7j) Et je peux accéder au formulaire d'appel
12. Structure du formulaire d'appel
Étant donné que j'ouvre le formulaire d'appel
Quand le formulaire s'affiche
Alors je vois les champs suivants:
| champ | type | obligatoire | description |
|---|---|---|---|
| Sanction contestée | Pré-rempli (readonly) | oui | "Strike 2 - Podcast #42" |
| Raison de l'appel | Texte (50-1000 car) | oui | Explication courte de la contestation |
| Arguments détaillés | Zone texte enrichie | oui | Arguments complets |
| Preuves | Upload fichiers | non | Max 5 fichiers, 10 MB total |
Et tous les champs obligatoires sont marqués d'un astérisque
13. Validation du formulaire d'appel
Étant donné que je remplis le formulaire d'appel
Quand je clique sur "Soumettre l'appel"
Alors le système valide les champs obligatoires Et si un champ obligatoire est vide, une erreur s'affiche Et si la raison fait moins de 50 caractères, une erreur s'affiche Et si tout est valide, l'appel est soumis
14. Confirmation après soumission de l'appel
Étant donné que j'ai soumis un appel valide
Quand l'appel est enregistré
Alors un numéro de ticket unique est généré: "#MOD-2026-00142" Et un email de confirmation est envoyé: Et le statut de l'appel est "En cours d'examen" Et je peux suivre le statut dans "Mes sanctions"
15. Délai de soumission de 7 jours maximum
Étant donné que j'ai reçu une sanction le 2026-01-15
Quand j'essaie de faire appel le 2026-01-25 (10 jours plus tard)
Alors le formulaire d'appel est désactivé Et un message s'affiche: Et je ne peux plus contester la sanction
16. Bouton "Faire appel" visible si délai respecté
Étant donné que j'ai reçu une sanction il y a 3 jours
Quand je consulte "Mes sanctions"
Alors le bouton "Faire appel" est actif Et un compteur indique "4 jours restants pour faire appel" Et je peux cliquer pour soumettre un appel
17. SLA de 72h garanti pour appel standard
Étant donné que j'ai soumis un appel standard le lundi à 10:00
Quand l'appel est en cours de traitement
Alors un modérateur senior est assigné Et l'appel doit être traité avant jeudi 10:00 (72h - 3 jours ouvrés) Et je reçois une réponse dans ce délai
18. Appel complexe avec notification intermédiaire
Étant donné que j'ai soumis un appel complexe Et que le traitement nécessite plus de 72h
Quand 3 jours se sont écoulés
Alors je reçois un email de notification intermédiaire: Et l'appel est traité sous 5 jours ouvrés au total Et un modérateur senior + admin modération examinent le cas
19. Appel CRITIQUE traité en 24h
Étant donné que j'ai reçu une suspension longue ou un ban Et que je soumets un appel
Quand l'appel est classé en priorité CRITIQUE
Alors l'admin modération traite l'appel sous 24h Et je reçois une réponse rapide Et le cas est examiné en priorité absolue
20. Réponse finale détaillée - Appel accepté
Étant donné que mon appel est accepté
Quand je reçois la réponse finale
Alors l'email contient:
| élément | contenu |
|---|---|
| Décision | Annulation de la sanction |
| Justification | Explication de pourquoi l'appel est accepté |
| Actions | Strike retiré, suspension annulée, contenu rétabli |
| Définitif | "Cette décision est définitive" |
Et le strike est retiré de mon compte Et le contenu est rétabli sur la plateforme Et je peux continuer normalement
21. Réponse finale détaillée - Appel rejeté
Étant donné que mon appel est rejeté
Quand je reçois la réponse finale
Alors l'email contient:
| élément | contenu |
|---|---|
| Décision | Maintien de la sanction |
| Justification | Explication de pourquoi l'appel est rejeté |
| Actions | Sanction maintenue, strike conservé |
| Définitif | "Cette décision est définitive" |
Et la sanction reste active Et je ne peux pas faire de second appel Et je dois respecter la suspension
22. Réponse finale - Réduction de sanction
Étant donné que mon appel est partiellement accepté
Quand je reçois la réponse finale
Alors la décision est "Réduction de sanction" Et l'email explique: Et le strike est réduit Et la suspension est raccourcie Et je suis notifié de la nouvelle date de fin
23. Suivi du statut de l'appel in-app
Étant donné que j'ai soumis un appel
Quand je consulte "Mes sanctions"
Alors je vois le statut actuel de l'appel:
| statut | badge | couleur |
|---|---|---|
| En cours d'examen | En cours 🔍 | orange |
| Appel accepté | Accepté ✓ | vert |
| Appel rejeté | Rejeté ✗ | rouge |
| Sanction réduite | Partiellement accepté | bleu |
Et une notification badge m'alerte quand le statut change
24. Historique complet des sanctions visible
Étant donné que je suis un créateur
Quand j'ouvre "Profil créateur > Mes sanctions"
Alors je vois la liste complète de mes sanctions passées:
| colonne | description |
|---|---|
| Date | 15/01/2026 |
| Contenu | "Mon podcast #42" |
| Catégorie | 🚫 Haine & violence |
| Sanction | Strike 2 - Suspension 7j |
| Statut | Active / Terminée / Annulée |
| Appel | Aucun / Accepté / Rejeté |
Et les sanctions sont triées par date décroissante
25. Conformité DSA - Transparence obligatoire
Étant donné que le système de sanction est en place
Quand un audit DSA est effectué
Alors chaque sanction contient:
| élément DSA | présent |
|---|---|
| Référence précise à la règle violée | oui |
| Explication claire et compréhensible | oui |
| Preuve (extrait + transcription) | oui |
| Possibilité de recours (appel) | oui |
| Délai de recours clairement indiqué | oui |
| Réponse motivée au recours | oui |
Et le système est conforme au Digital Services Act
26. Décision définitive après premier appel
Étant donné que mon premier appel a été rejeté
Quand j'essaie de faire un second appel
Alors le bouton "Faire appel" est désactivé Et un message s'affiche: "Cette décision est définitive. Aucun second appel n'est possible." Et je ne peux plus contester la sanction Et je dois respecter la décision finale
27. Coût des notifications multi-canal
Étant donné que 100 sanctions sont appliquées en un mois
Quand on calcule le coût des notifications
Alors le coût total est d'environ 0.10€:
| canal | coût unitaire | coût pour 100 |
|---|---|---|
| Email | 0.001€ | 0.10€ |
| Push | 0€ | 0€ |
| In-app | 0€ | 0€ |
Et le coût est négligeable même à grande échelle
Signalement de contenu inapproprié
23 scénarios (22 standards, 1 plan)
Contexte commun à tous les scénarios
Étant donné que je suis un utilisateur connecté Et que je suis en train d'écouter un contenu
1. Affichage du formulaire de signalement
Étant donné que j'écoute un contenu inapproprié
Quand j'ouvre le menu du contenu Et que je clique sur "Signaler"
Alors un formulaire de signalement s'affiche Et le formulaire contient une liste déroulante "Catégorie du problème" Et le formulaire contient un champ texte "Commentaire (optionnel)" Et le formulaire contient un bouton "Envoyer le signalement"
2. Liste des 7 catégories prédéfinies
Étant donné que le formulaire de signalement est affiché
Quand je clique sur la liste déroulante "Catégorie du problème"
Alors je vois les 7 catégories suivantes:
| icône | 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é |
| 📧 | 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é |
Et chaque catégorie a une description claire
3. Sélection de la catégorie "Haine & violence"
Étant donné que le formulaire de signalement est affiché
Quand je sélectionne la catégorie "🚫 Haine & violence"
Alors la catégorie est sélectionnée Et la description "Incitation à la haine, discrimination, menaces" s'affiche Et je peux passer au champ commentaire
4. Catégorie "Autre" nécessite un commentaire obligatoire
Étant donné que le formulaire de signalement est affiché
Quand je sélectionne la catégorie "🔧 Autre"
Alors le champ "Commentaire" devient obligatoire Et un message s'affiche: "Veuillez décrire le problème (obligatoire)" Et le placeholder change en "Décrivez le problème rencontré" Et je ne peux pas envoyer le signalement sans commentaire
5. Champ commentaire optionnel avec incitation
Étant donné que le formulaire de signalement est affiché Et que j'ai sélectionné une catégorie autre que "Autre"
Quand je consulte le champ "Commentaire"
Alors le champ est optionnel (pas d'astérisque rouge) Et le placeholder indique "Décrivez le problème (optionnel mais recommandé)" Et la limite de caractères est de 500 Et un compteur affiche "0/500"
6. Envoi de signalement sans commentaire
Étant donné que j'ai sélectionné la catégorie "📧 Spam" Et que je n'ai pas rempli le champ commentaire
Quand je clique sur "Envoyer le signalement"
Alors le signalement est envoyé avec succès Et aucune erreur de validation ne s'affiche Et le commentaire est enregistré comme vide
7. Envoi de signalement avec commentaire
Étant donné que j'ai sélectionné la catégorie "🚫 Haine & violence" Et que j'ai saisi le commentaire "Le créateur tient des propos discriminatoires à 2:30"
Quand je clique sur "Envoyer le signalement"
Alors le signalement est envoyé avec succès Et le commentaire est enregistré avec le signalement Et il sera visible par les modérateurs
8. Limite de 500 caractères pour le commentaire
Étant donné que le formulaire de signalement est affiché
Quand je saisis un commentaire de 501 caractères
Alors le champ limite automatiquement à 500 caractères Et le compteur affiche "500/500" Et les caractères supplémentaires ne sont pas acceptés
9. Toast de confirmation après signalement
Étant donné que j'ai envoyé un signalement
Quand le signalement est enregistré
Alors un toast notification s'affiche Et le toast contient le message "✓ Signalement envoyé. Nous l'examinerons sous 24-48h." Et le toast s'affiche pendant 5 secondes Et le toast contient un bouton "Voir mes signalements" Et je peux fermer le toast manuellement avec un bouton X
10. Accès à l'historique des signalements via le toast
Étant donné que le toast de confirmation est affiché
Quand je clique sur "Voir mes signalements"
Alors je suis redirigé vers la page "Mes signalements" Et je vois la liste de tous mes signalements Et le signalement que je viens d'envoyer apparaît en premier
11. Historique personnel des signalements
Étant donné que j'ai envoyé 3 signalements précédemment
Quand j'ouvre "Profil > Mes signalements"
Alors je vois la liste de mes 3 signalements Et chaque signalement affiche:
| information | description |
|---|---|
| Titre du contenu | "Podcast #42" |
| Créateur | @pseudo_createur |
| Catégorie | 🚫 Haine & violence |
| Date | 15/01/2026 |
| Statut | En cours / Traité / Rejeté |
| Mon commentaire | Texte que j'ai saisi |
Et les signalements sont triés par date décroissante
12. 📋 Plan: Statuts possibles d'un signalement
Étant donné que j'ai envoyé un signalement
Quand le statut du signalement est ""
Alors le badge affiché est "" Et la couleur du badge est ""
📊 Exemples de données:
| statut | badge | couleur |
|---|---|---|
| En cours | En cours | orange |
| Traité | Traité ✓ | vert |
| Rejeté | Rejeté ✗ | rouge |
13. Notification in-app si action prise
Étant donné que j'ai signalé un contenu il y a 24h
Quand le modérateur traite mon signalement Et que le contenu est effectivement retiré
Alors je reçois une notification in-app Et la notification indique "Votre signalement a été traité. Le contenu a été retiré." Et le statut de mon signalement passe à "Traité ✓" Et je peux voir les détails de l'action prise
14. Notification si signalement rejeté
Étant donné que j'ai signalé un contenu
Quand le modérateur rejette mon signalement
Alors je reçois une notification in-app Et la notification indique "Votre signalement a été examiné. Le contenu ne viole pas les règles de la communauté." Et le statut de mon signalement passe à "Rejeté ✗" Et je peux voir la raison du rejet
15. Un contenu peut être signalé plusieurs fois
Étant donné qu'un contenu a déjà été signalé par 5 autres utilisateurs
Quand je signale le même contenu
Alors mon signalement est enregistré indépendamment Et le compteur de signalements du contenu passe à 6 Et mon signalement rejoint la file d'attente de modération Et les signalements cumulés augmentent la priorité de traitement
16. Limite de signalements par utilisateur
Étant donné que j'ai déjà signalé le même contenu il y a 2 jours
Quand j'essaie de signaler à nouveau le même contenu
Alors un message m'informe "Vous avez déjà signalé ce contenu" Et le formulaire de signalement n'est pas affiché Et je peux consulter le statut de mon signalement précédent
17. Détection de signalements abusifs répétés
Étant donné que j'ai envoyé 10 signalements ce mois-ci Et que 8 d'entre eux ont été rejetés comme infondés
Quand j'essaie d'envoyer un nouveau signalement
Alors mon compte est marqué comme "signaleur suspect" Et un avertissement s'affiche: Et je peux toujours envoyer le signalement Mais mes futurs signalements auront une priorité réduite
18. Sanction pour signalements abusifs graves
Étant donné que j'ai envoyé 20 signalements abusifs en 1 mois Et que tous ont été rejetés comme volontairement faux
Quand le modérateur détecte le pattern abusif
Alors mon compte reçoit un avertissement formel Et je perds la possibilité de signaler pendant 30 jours Et je reçois un email m'expliquant la sanction
19. Signalement depuis le player audio
Étant donné que j'écoute un contenu
Quand j'ouvre le menu "⋮" du player
Alors je vois l'option "Signaler" Et je peux ouvrir le formulaire de signalement
20. Signalement depuis la page de détails du contenu
Étant donné que je consulte la page de détails d'un contenu
Quand je clique sur le bouton "⋮" en haut à droite
Alors je vois l'option "Signaler" Et je peux ouvrir le formulaire de signalement
21. Signalement depuis l'historique d'écoute
Étant donné que je consulte mon historique d'écoute
Quand je clique sur "⋮" à côté d'un contenu passé
Alors je vois l'option "Signaler" Et je peux signaler ce contenu même si je ne l'écoute plus actuellement
22. Identité du signaleur anonyme pour le créateur
Étant donné que j'ai signalé un contenu
Quand le créateur est notifié de la modération
Alors mon identité reste anonyme Et le créateur ne peut pas savoir qui a signalé Et seuls les modérateurs ont accès à l'identité du signaleur
23. Coût du système de signalement
Étant donné que le système de signalement est en place
Quand on calcule le coût
Alors le coût est de 0€ Et le formulaire est développé en interne Et aucun service tiers n'est utilisé Et les notifications in-app sont gratuites
Traitement des signalements par l'IA et les modérateurs
25 scénarios (21 standards, 4 plans)
Contexte commun à tous les scénarios
Étant donné que le système de modération est actif
1. Signalement ajouté à la file d'attente asynchrone
Étant donné qu'un utilisateur envoie un signalement pour un contenu audio
Quand le signalement est reçu
Alors le signalement est ajouté à la file d'attente asynchrone Et un worker de traitement est déclenché Et le traitement se fait en arrière-plan sans bloquer l'utilisateur
2. Transcription automatique avec Whisper large-v3
Étant donné qu'un contenu audio signalé dure 5 minutes
Quand le worker de traitement démarre
Alors le système utilise Whisper large-v3 pour transcrire l'audio Et la transcription est en self-hosted (pas de service cloud) Et le texte transcrit est enregistré en base de données Et le délai de transcription est de 1-3 minutes
3. 📋 Plan: Délai de transcription selon durée audio
Étant donné qu'un contenu audio signalé dure minutes
Quand le système transcrit l'audio
Alors la transcription prend environ
📊 Exemples de données:
| duree | delai |
|---|---|
| 2 | 1-3 minutes |
| 10 | 3-10 minutes |
| 45 | 10-20 minutes |
4. Analyse automatique du contenu transcrit
Étant donné que la transcription audio est terminée
Quand le système analyse le texte transcrit
Alors les analyses suivantes sont effectuées:
| analyse | technologie |
|---|---|
| Analyse de sentiment | distilbert-base-uncased |
| Détection de haine | facebook/roberta-hate-speech |
| Mots-clés interdits | Liste noire FR/EN + regex |
Et chaque analyse génère un score de confiance (0-100%)
5. Génération du score de confiance IA
Étant donné que toutes les analyses sont terminées
Quand le système calcule le score final
Alors un score de confiance IA entre 0-100% est généré Et le score indique la probabilité que le contenu viole les règles Et la catégorie la plus probable est identifiée Et les timestamps des passages problématiques sont extraits
6. Détection automatique de contenu clairement inapproprié
Étant donné qu'un contenu contient des insultes graves et répétées
Quand l'IA analyse la transcription
Alors le score de confiance IA est >95% Et la catégorie détectée est "Haine & violence" Et les passages problématiques sont identifiés avec timestamps:
| timestamp | texte problématique |
|---|---|
| 02:15 | [insulte discriminatoire] |
| 03:42 | [propos haineux] |
Et le signalement est classé en priorité CRITIQUE
7. 📋 Plan: SLA selon priorité du signalement
Étant donné qu'un signalement a une priorité ""
Quand le signalement entre en file d'attente
Alors le délai de traitement cible est "" Et le responsable du traitement est ""
📊 Exemples de données:
| priorite | delai | responsable |
|---|---|---|
| CRITIQUE | <2h (24/7) | Modérateur senior (astreinte) |
| HAUTE | <24h (jours ouvrés) | Modérateur junior/senior |
| MOYENNE | <24h (jours ouvrés) | Modérateur junior |
| BASSE | <72h (jours ouvrés) | Modérateur junior |
8. Traitement automatique pour score IA >95%
Étant donné qu'un signalement a un score IA de 97% Et que la catégorie détectée est "Spam" (évidente)
Quand le système évalue le signalement
Alors une action automatique immédiate est déclenchée Et le contenu est retiré automatiquement Et le créateur est notifié de la modération Et le créateur peut faire appel de la décision Et un modérateur senior vérifie l'action a posteriori
9. Signalement CRITIQUE traité en moins de 2h
Étant donné qu'un signalement de priorité CRITIQUE est reçu à 14:00 Et que le contenu concerne une menace de violence
Quand le signalement est assigné à un modérateur senior d'astreinte
Alors le modérateur est alerté immédiatement (push + SMS) Et le signalement est traité avant 16:00 (2h) Et une décision est prise et appliquée Et les autorités peuvent être contactées si nécessaire
10. Astreinte modérateur 24/7 pour signalements CRITIQUES
Étant donné qu'un signalement CRITIQUE est reçu un dimanche à 03:00
Quand le signalement est classé en priorité CRITIQUE
Alors le modérateur senior d'astreinte est alerté Et le signalement est traité dans les 2h (avant 05:00) Et le service d'astreinte garantit une disponibilité 24/7
11. Signalement HAUTE priorité traité en moins de 24h
Étant donné qu'un signalement de priorité HAUTE est reçu lundi à 10:00 Et que le contenu concerne du harcèlement
Quand le signalement entre en file d'attente
Alors le signalement est assigné à un modérateur (junior ou senior) Et le signalement est traité avant mardi 10:00 (24h jours ouvrés) Et une décision est prise et appliquée
12. Signalement BASSE priorité traité en moins de 72h
Étant donné qu'un signalement de priorité BASSE est reçu lundi à 10:00 Et que le contenu concerne des tags incorrects
Quand le signalement entre en file d'attente
Alors le signalement est traité avant jeudi 10:00 (72h jours ouvrés) Et un modérateur junior peut traiter ce type de signalement
13. Calcul du score de priorité
Étant donné qu'un signalement a les caractéristiques suivantes:
| caractéristique | valeur |
|---|---|
| Score IA | 85% |
| Signalements cumulés | 3 |
| Fiabilité du signaleur | 75% |
Quand le système calcule la priorité
Alors la formule appliquée est: Et le score de priorité est: (85 × 0.7) + (3 × 0.2) + (75 × 0.1) = 67.5 Et le signalement est classé en priorité MOYENNE
14. 📋 Plan: Classification selon score de priorité
Étant donné qu'un signalement a un score de priorité de
Quand le système classe le signalement
Alors la priorité assignée est "" Et le signalement entre dans la file ""
📊 Exemples de données:
| score | priorite | file |
|---|---|---|
| 95 | CRITIQUE | Immédiate |
| 82 | HAUTE | Prioritaire |
| 55 | MOYENNE | Normale |
| 25 | BASSE | Différée |
15. Boost de priorité avec signalements cumulés
Étant donné qu'un contenu a été signalé par 1 utilisateur avec un score IA de 60% Et que le signalement est classé en priorité MOYENNE (score 42)
Quand 5 autres utilisateurs signalent le même contenu
Alors le nombre de signalements cumulés passe à 6 Et le score de priorité augmente significativement Et le signalement peut passer en priorité HAUTE Et le traitement est accéléré
16. Impact de la fiabilité du signaleur
Étant donné qu'un utilisateur de confiance (90% fiabilité) envoie un signalement Et qu'un utilisateur suspect (20% fiabilité) envoie un signalement similaire
Quand le système calcule les priorités
Alors le signalement de l'utilisateur de confiance a un score plus élevé Et son signalement est traité en priorité Et le signalement de l'utilisateur suspect est traité plus tard
17. Évolution du score de fiabilité du signaleur
Étant donné qu'un utilisateur a envoyé 10 signalements Et que 8 d'entre eux ont été acceptés par les modérateurs
Quand le système calcule son score de fiabilité
Alors le score est de 80% (8 acceptés / 10 total) Et ses futurs signalements auront plus de poids Et il peut devenir "utilisateur de confiance"
18. Files d'attente séparées par priorité
Étant donné que 50 signalements sont en attente
Quand le système organise la file d'attente
Alors les signalements sont répartis dans les files suivantes:
| file | nombre | priorité |
|---|---|---|
| Immédiate (24/7) | 5 | CRITIQUE |
| Prioritaire | 15 | HAUTE |
| Normale | 20 | MOYENNE |
| Différée | 10 | BASSE |
Et les modérateurs traitent en priorité la file Immédiate
19. Modérateurs assignés selon compétences
Étant donné qu'un signalement complexe de harcèlement est reçu
Quand le système assigne un modérateur
Alors un modérateur senior est prioritairement assigné Et les modérateurs juniors peuvent traiter les cas simples (spam, tags) Et les modérateurs seniors traitent les cas complexes (haine, violence, appels)
20. Stack technique 100% opensource
Étant donné que le système de modération IA est déployé
Quand on analyse les technologies utilisées
Alors toutes les technologies sont opensource:
| composant | technologie | hébergement |
|---|---|---|
| Transcription | Whisper large-v3 | Self-hosted |
| Analyse sentiment | distilbert-base-uncased | Self-hosted |
| Détection haine | facebook/roberta-hate-speech | Self-hosted |
| Mots-clés interdits | Liste noire FR/EN + regex | PostgreSQL |
Et aucune dépendance à Google, AWS, Azure
21. 📋 Plan: Coût selon phase du projet
Étant donné que RoadWave est en phase ""
Quand on calcule le coût de l'infrastructure IA
Alors le coût mensuel est ""
📊 Exemples de données:
| phase | cout |
|---|---|
| MVP | 0-50€ (CPU) |
| Scale | 50-200€ (GPU VPS) |
22. Processing asynchrone en MVP avec CPU
Étant donné que RoadWave est en phase MVP Et que le volume est <1000 signalements/mois
Quand le système traite les signalements
Alors un serveur CPU standard est suffisant Et le coût est de 0€ (serveur existant) Et le processing asynchrone absorbe les pics de charge Et les délais restent acceptables (1-20 minutes)
23. Scaling avec GPU pour gros volumes
Étant donné que RoadWave reçoit >1000 signalements/jour
Quand le système nécessite un scaling
Alors un VPS avec GPU est requis Et le coût passe à 50-200€/mois Et les délais de transcription sont divisés par 5-10 Et le système peut gérer 10 000+ signalements/mois
24. Logs d'audit pour chaque traitement
Étant donné qu'un signalement est traité
Quand une action est prise (rejet, acceptation, sanction)
Alors un log d'audit complet est créé:
| champ | description |
|---|---|
| signalement_id | ID unique du signalement |
| content_id | ID du contenu signalé |
| ia_score | Score de confiance IA |
| ia_category | Catégorie détectée par IA |
| priority | CRITIQUE / HAUTE / MOYENNE / BASSE |
| moderator_id | ID du modérateur assigné |
| action_taken | Retiré / Rejeté / Strike |
| processing_time | Durée du traitement |
| timestamp | Date et heure de la décision |
Et le log est conservé pour conformité DSA Et les logs sont anonymisés après 3 ans (RGPD)
25. Traçabilité complète pour conformité DSA
Étant donné que le système de modération est actif
Quand un audit DSA est effectué
Alors toutes les actions de modération sont tracées Et les délais de traitement sont mesurés et respectés Et les décisions sont justifiées et documentées Et la transparence vis-à-vis des utilisateurs est garantie Et le système est conforme au Digital Services Act
Conditions d'activation de la monétisation
En tant que créateur Je veux pouvoir activer la monétisation quand je remplis les critères Afin de générer des revenus avec mes contenus
28 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis connecté en tant que créateur
1. Critère 1 - Ancienneté de 3 mois validée
Étant donné que mon compte a été créé il y a 91 jours
Quand je consulte les critères de monétisation
Alors le critère "Ancienneté ≥ 3 mois" est validé ✅
2. Critère 1 - Ancienneté insuffisante
Étant donné que mon compte a été créé il y a 60 jours
Quand je consulte les critères de monétisation
Alors le critère "Ancienneté ≥ 3 mois" n'est pas validé ❌ Et je vois "Encore 30 jours avant d'être éligible"
3. Critère 2 - 500 abonnés atteints
Étant donné que j'ai exactement 500 abonnés
Quand je consulte les critères de monétisation
Alors le critère "≥ 500 abonnés" est validé ✅
4. Critère 2 - Pas assez d'abonnés
Étant donné que j'ai 347 abonnés
Quand je consulte les critères de monétisation
Alors le critère "≥ 500 abonnés" n'est pas validé ❌ Et je vois "Encore 153 abonnés nécessaires"
5. Critère 3 - 10 000 écoutes complètes atteintes
Étant donné que mes contenus ont cumulé 10 487 écoutes complètes
Quand je consulte les critères de monétisation
Alors le critère "≥ 10 000 écoutes complètes" est validé ✅
6. Critère 3 - Écoutes incomplètes non comptabilisées
Étant donné que mes contenus ont:
| type écoute | nombre |
|---|---|
| Écoutes complètes | 8 500 |
| Écoutes <80% | 3 000 |
Quand je consulte les critères de monétisation
Alors seules les 8 500 écoutes complètes comptent Et je vois "Encore 1 500 écoutes complètes nécessaires"
7. Critère 4 - Aucun strike actif
Étant donné que je n'ai aucun strike actif Et que je n'ai eu aucun contenu modéré dans les 6 derniers mois
Quand je consulte les critères de monétisation
Alors le critère "Fiabilité" est validé ✅
8. Critère 4 - Strike actif bloque l'éligibilité
Étant donné que j'ai 1 strike actif pour contenu inapproprié
Quand je consulte les critères de monétisation
Alors le critère "Fiabilité" n'est pas validé ❌ Et je vois "Vous devez résoudre votre strike avant d'être éligible"
9. Critère 4 - Contenu modéré dans les 6 derniers mois
Étant donné que je n'ai pas de strike actif Mais qu'un de mes contenus a été modéré il y a 4 mois
Quand je consulte les critères de monétisation
Alors le critère "Fiabilité" n'est pas validé ❌ Et je vois "Attendre 2 mois après le dernier contenu modéré"
10. Critère 5 - 5 contenus publiés dans les 90 derniers jours
Étant donné que j'ai publié:
| date de publication | titre |
|---|---|
| Il y a 15 jours | Contenu 1 |
| Il y a 30 jours | Contenu 2 |
| Il y a 45 jours | Contenu 3 |
| Il y a 60 jours | Contenu 4 |
| Il y a 75 jours | Contenu 5 |
Quand je consulte les critères de monétisation
Alors le critère "≥ 5 contenus publiés dans les 90 derniers jours" est validé ✅
11. Critère 5 - Contenus trop anciens ne comptent pas
Étant donné que j'ai publié:
| date de publication | titre |
|---|---|
| Il y a 15 jours | Contenu 1 |
| Il y a 30 jours | Contenu 2 |
| Il y a 95 jours | Contenu 3 |
| Il y a 120 jours | Contenu 4 |
Quand je consulte les critères de monétisation
Alors seuls 2 contenus comptent (dans les 90 jours) Et je vois "Encore 3 contenus à publier dans les 90 prochains jours"
12. Tous les critères validés - Bouton disponible
Étant donné que tous mes critères sont validés:
| critère | statut |
|---|---|
| Ancienneté ≥ 3 mois | ✅ |
| ≥ 500 abonnés | ✅ |
| ≥ 10 000 écoutes | ✅ |
| Fiabilité | ✅ |
| Régularité (5 contenus) | ✅ |
Quand j'accède à mon profil créateur
Alors le bouton "Demander la monétisation" est actif Et je peux cliquer pour démarrer le KYC
13. Critères incomplets - Bouton grisé avec progression
Étant donné que mes critères sont:
| critère | statut | progression |
|---|---|---|
| Ancienneté ≥ 3 mois | ✅ | 100% |
| ≥ 500 abonnés | ❌ | 347/500 (69%) |
| ≥ 10 000 écoutes | ❌ | 8500/10000 (85%) |
| Fiabilité | ✅ | 100% |
| Régularité (5 contenus) | ✅ | 100% |
Quand j'accède à mon profil créateur
Alors le bouton "Demander la monétisation" est grisé Et je vois la progression détaillée de chaque critère
14. Vérification automatique SQL lors de la demande
Étant donné que je clique sur "Demander la monétisation"
Quand le système vérifie mes critères
Alors une requête SQL est exécutée: Et si tous les critères sont TRUE, je suis redirigé vers le KYC
15. Notification par email quand critères atteints
Étant donné que je viens d'atteindre 500 abonnés Et que c'était mon dernier critère manquant
Quand le système détecte l'éligibilité
Alors je reçois un email:
16. Badge "Éligible monétisation" dans profil
Étant donné que je remplis tous les critères Mais que je n'ai pas encore activé la monétisation
Quand un utilisateur consulte mon profil
Alors il voit un badge "Éligible monétisation 💰" Et cela renforce ma crédibilité de créateur
17. Justification anti-fraude - Délai 3 mois
Étant donné qu'un compte suspect crée du contenu frauduleux
Quand le compte est détecté dans les 2 premiers mois
Alors le compte est banni avant d'atteindre les 3 mois Et le créateur n'a jamais été éligible à la monétisation Et aucun paiement n'a été effectué
18. Justification qualité - 10 000 écoutes
Étant donné qu'un créateur produit du contenu de mauvaise qualité
Quand ses contenus ne génèrent que 2 000 écoutes complètes
Alors il ne peut pas activer la monétisation Et seuls les créateurs avec contenu apprécié sont monétisés
19. Réduction coût administratif plateforme
Étant donné que RoadWave a 10 000 créateurs inscrits Et que seuls 500 remplissent tous les critères
Quand le système calcule le coût administratif
Alors seulement 500 KYC sont à gérer (vs 10 000) Et seulement 500 virements mensuels (vs 10 000) Et la charge comptable est réduite de 95%
20. Statistiques publiques pour transparence
Quand un utilisateur consulte la page "Devenir créateur"
Alors il voit les statistiques:
| métrique | valeur exemple |
|---|---|
| Nombre créateurs monétisés | 1 247 |
| Revenus moyens par créateur | 127€/mois |
| Top créateur (anonymisé) | 2 450€/mois |
| Critères d'éligibilité à remplir | 5 critères |
Et cela permet de fixer des attentes réalistes
21. Cache Redis pour calcul rapide critères
Étant donné que je consulte mes critères de monétisation
Quand le système charge la page
Alors les compteurs sont récupérés depuis Redis:
| clé Redis | exemple valeur |
|---|---|
| creator:[id]:subscribers_count | 347 |
| creator:[id]:complete_listens_total | 8500 |
| creator:[id]:recent_contents_count | 7 |
Et le temps de réponse est <50ms
22. Mise à jour temps réel des compteurs
Étant donné que je viens de publier un nouveau contenu
Quand un utilisateur écoute ce contenu en entier
Alors le compteur "complete_listens_total" est incrémenté immédiatement Et si je rafraîchis la page critères, je vois la nouvelle valeur Et cela encourage les créateurs à continuer de produire
23. Historique des tentatives d'activation
Étant donné que j'ai tenté d'activer la monétisation il y a 2 mois Mais que les critères n'étaient pas remplis
Quand j'accède à mes logs d'activité
Alors je vois:
| date | action | résultat | raison |
|---|---|---|---|
| 2025-11-15 | Demande monétisation | Refusée | Seulement 300 abonnés |
Et cela m'aide à suivre ma progression
24. Performance avec 100 000 créateurs
Étant donné que RoadWave a 100 000 créateurs Et que chacun consulte ses critères 1 fois par jour
Quand le système traite ces requêtes
Alors la table users est indexée sur created_at Et la table subscriptions est indexée sur creator_id Et la table contents est indexée sur creator_id et published_at Et chaque requête reste <50ms grâce aux index
25. Export des critères pour support client
Étant donné que je contacte le support car je pense être éligible
Quand l'agent support consulte mon compte
Alors il voit un export JSON complet: Et l'agent peut expliquer précisément pourquoi je ne suis pas éligible
26. Notification 30 jours avant éligibilité probable
Étant donné que mes critères sont:
| critère | statut | progression |
|---|---|---|
| Ancienneté ≥ 3 mois | ❌ | 60/90 jours |
| Tous les autres critères | ✅ | 100% |
Quand il reste exactement 30 jours avant les 90 jours
Alors je reçois une notification:
27. Pas de bypass possible pour amis/influenceurs
Étant donné qu'un créateur influent me contacte directement Et qu'il demande un bypass des critères
Quand je consulte la politique RoadWave
Alors la réponse est "Aucune exception possible, critères automatiques uniquement" Et cela garantit l'équité pour tous les créateurs
28. A/B test futur sur seuils (post-MVP)
Étant donné que RoadWave veut tester des seuils différents
Quand un A/B test est lancé en 2027
Alors groupe A voit: 500 abonnés, 10 000 écoutes Et groupe B voit: 300 abonnés, 5 000 écoutes Et les métriques (taux activation, fraude, qualité) sont comparées Et le meilleur seuil est déployé définitivement
Contenus Premium exclusifs
En tant que créateur monétisé Je veux pouvoir rendre certains contenus exclusifs aux abonnés Premium Afin d'inciter les utilisateurs à s'abonner
34 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis un créateur avec la monétisation activée
1. Toggle "Réservé Premium" lors de la création
Étant donné que je crée un nouveau contenu
Quand j'accède aux options de publication
Alors je vois un toggle "Réservé aux abonnés Premium 👑" Et je peux l'activer ou le désactiver
2. Contenu marqué Premium lors de la création
Étant donné que je crée un nouveau contenu
Quand j'active le toggle "Réservé Premium" Et que je publie le contenu
Alors le champ is_premium en base est mis à true
Et le contenu est visible uniquement pour les utilisateurs Premium
3. Contenu gratuit par défaut
Étant donné que je crée un nouveau contenu
Quand je ne touche pas au toggle "Réservé Premium" Et que je publie le contenu
Alors le champ is_premium en base est mis à false (défaut)
Et le contenu est accessible à tous les utilisateurs
4. Modification d'un contenu existant en Premium
Étant donné que j'ai publié un contenu gratuit il y a 2 jours
Quand je modifie le contenu et active le toggle "Réservé Premium" Et que j'enregistre les modifications
Alors le contenu devient immédiatement Premium Et les utilisateurs gratuits ne peuvent plus y accéder
5. Passage d'un contenu Premium en gratuit
Étant donné que j'ai publié un contenu Premium il y a 1 mois
Quand je modifie le contenu et désactive le toggle "Réservé Premium" Et que j'enregistre les modifications
Alors le contenu devient immédiatement gratuit Et tous les utilisateurs peuvent maintenant y accéder
6. Aucune limite sur pourcentage de contenus Premium
Étant donné que je publie 10 nouveaux contenus
Quand je décide de rendre les 10 contenus Premium (100%)
Alors le système accepte sans limitation Et je peux avoir 100% de mon catalogue en Premium
7. Stratégie freemium - Mix gratuit/premium
Étant donné que je publie 10 nouveaux contenus
Quand je décide de rendre 5 contenus Premium et 5 gratuits (50/50)
Alors le système accepte cette stratégie Et je peux tester différents mix pour optimiser mes revenus
8. Stratégie tout gratuit possible
Étant donné que je suis monétisé via publicités
Quand je décide de ne mettre aucun contenu en Premium (0%)
Alors le système accepte cette stratégie Et je génère des revenus uniquement via les publicités
9. Badge 👑 visible sur l'interface utilisateur
Étant donné qu'un utilisateur consulte ma liste de contenus
Quand il voit un contenu Premium
Alors un badge 👑 "Premium" est affiché Et le contenu est clairement identifiable comme réservé
10. Utilisateur gratuit voit les contenus Premium dans la liste
Étant donné que je suis un utilisateur gratuit
Quand je consulte les contenus d'un créateur
Alors je vois aussi les contenus Premium dans la liste Et ils sont affichés avec un badge 👑 Mais je ne peux pas les lire
11. Tentative de lecture Premium par utilisateur gratuit - Overlay bloquant
Étant donné que je suis un utilisateur gratuit
Quand je clique sur un contenu Premium pour le lire
Alors un overlay bloquant apparaît Et je vois le message: Et un bouton "Passer Premium" est affiché
12. CTA "Passer Premium" redirige vers abonnement
Étant donné que je vois l'overlay de contenu Premium bloqué
Quand je clique sur "Passer Premium"
Alors je suis redirigé vers la page d'abonnement Premium Et je peux m'abonner pour 4.99€/mois
13. Utilisateur Premium peut lire tous les contenus Premium
Étant donné que je suis un utilisateur Premium actif
Quand je clique sur un contenu Premium
Alors le contenu se lance immédiatement Et je n'ai aucun overlay bloquant Et je peux profiter pleinement du contenu exclusif
14. Contenus Premium inclus dans les recommandations
Étant donné que l'algorithme génère ma file de 5 contenus
Quand je suis un utilisateur gratuit
Alors les contenus Premium peuvent apparaître dans les recommandations Et cela me fait découvrir qu'il existe du contenu exclusif
15. Contenu Premium skippé automatiquement pour utilisateur gratuit
Étant donné que je suis un utilisateur gratuit Et qu'un contenu Premium apparaît dans ma file de recommandation
Quand j'écoute le contenu précédent jusqu'à la fin
Alors le contenu Premium est automatiquement skippé Et le contenu suivant (gratuit) est lancé Et le slot Premium ne compte pas dans ma file de 5 contenus
16. Contenu Premium diffusé normalement pour utilisateur Premium
Étant donné que je suis un utilisateur Premium Et qu'un contenu Premium apparaît dans ma file de recommandation
Quand j'écoute le contenu précédent jusqu'à la fin
Alors le contenu Premium est lancé normalement Et je profite du contenu exclusif sans interruption
17. Champ is_premium boolean en base PostgreSQL
Étant donné qu'un contenu est créé
Quand il est stocké en base de données
Alors la table contents contient un champ is_premium BOOLEAN DEFAULT FALSE
Et ce champ est indexé pour requêtes rapides
18. Index PostgreSQL sur is_premium
Étant donné que l'algorithme doit filtrer les contenus selon le statut Premium
Quand une requête SQL est exécutée:
Alors l'index sur is_premium accélère la requête
Et le temps de réponse reste <20ms
19. Cache Redis pour statut Premium
Étant donné qu'un contenu Premium est consulté fréquemment
Quand l'API vérifie le statut Premium
Alors la valeur est récupérée depuis Redis: Et le cache a un TTL de 1 heure Et cela évite des requêtes SQL inutiles
20. Invalidation cache lors de modification statut Premium
Étant donné qu'un contenu est passé de gratuit à Premium
Quand le créateur enregistre la modification
Alors le cache Redis content:[id]:premium est invalidé immédiatement
Et la nouvelle valeur est mise à jour
Et les utilisateurs voient le changement en temps réel
21. Justification liberté créateur - Stratégie personnalisée
Étant donné que chaque créateur a une audience différente
Quand un créateur décide de sa stratégie Premium
Alors il peut tester différentes approches:
| stratégie | % Premium | objectif |
|---|---|---|
| Tout gratuit | 0% | Maximiser audience + revenus pub |
| Mix 50/50 | 50% | Équilibrer audience et exclusivité |
| Premium majoritaire | 80% | Cibler abonnés fidèles |
| 100% Premium | 100% | Contenu ultra-exclusif |
22. Justification incitation Premium - Argument fort pour s'abonner
Étant donné qu'un utilisateur gratuit voit beaucoup de contenus Premium
Quand il consulte les profils de ses créateurs préférés
Alors il voit que 60% de leur contenu est réservé Premium Et cela l'incite à s'abonner pour 4.99€/mois Et RoadWave augmente son taux de conversion vers Premium
23. Justification équité - Petit créateur peut tout mettre en Premium
Étant donné que je suis un petit créateur avec 600 abonnés Et que 50 sont abonnés Premium
Quand je mets 100% de mon contenu en Premium
Alors je génère des revenus uniquement via mes 50 abonnés Premium Et cela me permet de vivre de mon contenu malgré une petite audience
24. Justification équité - Gros créateur peut tout offrir gratuitement
Étant donné que je suis un gros créateur avec 50 000 abonnés Et que je génère déjà beaucoup de revenus publicitaires
Quand je laisse 100% de mon contenu gratuit
Alors je maximise mon audience et mes revenus pub Et je n'ai pas besoin de mettre du contenu en Premium
25. Statistiques créateur - Ratio Premium/Gratuit
Étant donné que j'accède à mon tableau de bord créateur
Quand je consulte mes statistiques de contenus
Alors je vois:
| métrique | valeur |
|---|---|
| Contenus totaux | 47 |
| Contenus gratuits | 32 (68%) |
| Contenus Premium | 15 (32%) |
| Écoutes Premium ce mois | 12,345 |
| Écoutes gratuites ce mois | 28,901 |
26. Statistiques créateur - Revenus par type
Étant donné que j'ai des contenus gratuits et Premium
Quand je consulte mes revenus détaillés
Alors je vois:
| source | montant |
|---|---|
| Revenus pub (gratuit) | 86.70€ |
| Revenus Premium (exclusifs) | 34.20€ |
| Revenus Premium (tout contenu) | 78.90€ |
Et je peux comparer l'efficacité de chaque stratégie
27. Notification créateur - Contenu Premium très écouté
Étant donné que j'ai publié un contenu Premium il y a 3 jours Et qu'il a généré 5 000 écoutes Premium (très élevé)
Quand le système détecte cette performance
Alors je reçois une notification:
28. A/B test utilisateur - Impact badge Premium sur conversion
Étant donné que RoadWave veut optimiser le taux de conversion Premium
Quand un A/B test est lancé
Alors groupe A voit le badge 👑 "Premium" Et groupe B voit le badge 💎 "Exclusif" Et les taux de clic et conversion sont mesurés Et le badge le plus performant est déployé définitivement
29. Analytics plateforme - Adoption fonctionnalité Premium
Étant donné que RoadWave suit l'adoption de la fonctionnalité
Quand un admin consulte les métriques
Alors il voit:
| métrique | valeur |
|---|---|
| Créateurs utilisant Premium | 847 (68%) |
| % moyen contenus Premium | 23% |
| Taux conversion vers Premium (users) | 8.5% |
| Revenus Premium/mois | 47,890€ |
30. Impact sur churn - Contenus Premium réduisent le churn Premium
Étant donné qu'un utilisateur Premium envisage de résilier Mais qu'il a accès à 150 contenus Premium de ses créateurs préférés
Quand il voit la valeur exclusive qu'il perdrait
Alors il est moins susceptible de résilier (churn réduit de ~30%) Et les contenus Premium augmentent la rétention
31. Transparence - Créateur voit combien de contenus Premium il a
Étant donné que j'accède à mon profil créateur
Quand je consulte mes contenus
Alors je peux filtrer par statut:
| filtre | résultats |
|---|---|
| Tous | 47 |
| Gratuits | 32 |
| Premium 👑 | 15 |
Et je peux facilement gérer mon catalogue
32. Export liste contenus avec statut Premium (RGPD)
Étant donné que je demande l'export de mes données
Quand l'export est généré
Alors la liste de mes contenus inclut le statut Premium:
33. Suppression compte créateur et contenus Premium
Étant donné que je supprime définitivement mon compte créateur
Quand la suppression est confirmée
Alors tous mes contenus (gratuits et Premium) sont supprimés Et les utilisateurs Premium ne peuvent plus y accéder Et les fichiers audio sont supprimés du CDN sous 7 jours
34. Performance avec 1 million de contenus Premium
Étant donné que RoadWave a 1 million de contenus dont 300 000 Premium
Quand l'algorithme génère une recommandation
Alors la requête SQL filtre efficacement avec l'index is_premium
Et le temps de réponse reste <50ms
Et la scalabilité est garantie
Désactivation et suspension monétisation
En tant que créateur ou plateforme Je veux pouvoir désactiver ou suspendre la monétisation selon certaines conditions Afin de gérer les pauses, problèmes techniques ou violations des règles
35 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis un créateur avec la monétisation activée
1. Désactivation temporaire par le créateur
Étant donné que je veux faire une pause dans ma création de contenu
Quand j'accède à "Paramètres > Monétisation" Et que je clique sur "Désactiver temporairement la monétisation"
Alors ma monétisation est désactivée immédiatement Et je ne génère plus de revenus à partir de maintenant
2. Confirmation avant désactivation
Étant donné que je clique sur "Désactiver temporairement"
Quand une popup de confirmation apparaît
Alors je vois le message: Et je dois confirmer pour continuer
3. Solde conservé pendant désactivation
Étant donné que mon solde actuel est 87.45€
Quand je désactive ma monétisation le 15 du mois
Alors mon solde de 87.45€ est conservé Et il sera reporté au mois suivant Et si le total dépasse 50€, il sera versé normalement le 15 du mois prochain
4. Contenus restent accessibles pendant désactivation
Étant donné que j'ai désactivé ma monétisation
Quand des utilisateurs écoutent mes contenus
Alors mes contenus restent accessibles normalement Mais je ne génère aucun revenu (ni pub ni Premium)
5. Réactivation sans refaire le KYC si <2 ans
Étant donné que j'ai désactivé ma monétisation il y a 8 mois Et que mes documents KYC sont toujours valides
Quand je clique sur "Réactiver la monétisation"
Alors la réactivation est immédiate Et je n'ai pas besoin de refaire le KYC Et je recommence à générer des revenus dès maintenant
6. Nouveau KYC requis si inactivité >2 ans
Étant donné que j'ai désactivé ma monétisation il y a 25 mois
Quand j'essaie de réactiver
Alors le système demande un nouveau KYC Et je vois: Et je dois soumettre à nouveau mes documents
7. Historique des désactivations/réactivations
Étant donné que j'ai désactivé et réactivé ma monétisation plusieurs fois
Quand j'accède à "Paramètres > Monétisation > Historique"
Alors je vois la liste complète:
| date | action | raison |
|---|---|---|
| 15/06/2025 | Réactivation | Reprise création contenu |
| 01/03/2025 | Désactivation | Pause vacances |
| 20/01/2025 | Activation | KYC validé |
8. Suspension si 3+ strikes actifs
Étant donné que je reçois un 3ème strike pour violation des règles
Quand le strike devient actif
Alors ma monétisation est suspendue automatiquement Et je vois:
9. Réactivation après résolution des strikes
Étant donné que ma monétisation est suspendue pour 3 strikes
Quand je résous tous mes strikes (après expiration ou contestation) Et que mon compteur de strikes passe à 0
Alors ma monétisation est réactivée automatiquement Et je reçois un email de confirmation
10. Suspension si RIB invalide après 3 échecs de virement
Étant donné que 3 tentatives de virement ont échoué (15, 18, 22 du mois)
Quand le 3ème échec est confirmé
Alors ma monétisation est suspendue automatiquement Et je vois:
11. Réactivation après mise à jour RIB valide
Étant donné que ma monétisation est suspendue pour RIB invalide
Quand je mets à jour mon RIB avec un compte bancaire valide Et que Mangopay valide le nouveau RIB
Alors ma monétisation est réactivée automatiquement Et un virement est tenté immédiatement pour le solde en attente
12. Suspension si documents KYC expirés
Étant donné que ma carte d'identité expire dans 30 jours
Quand je reçois un email de rappel de mise à jour Mais que je ne mets pas à jour mes documents Et que ma CNI expire
Alors ma monétisation est suspendue automatiquement après 30 jours de grâce
13. Préavis 30 jours avant suspension pour docs expirés
Étant donné que ma CNI expire le 15 juin 2025
Quand le 15 mai 2025 arrive (30 jours avant)
Alors je reçois un email d'alerte:
14. Réactivation après renouvellement documents KYC
Étant donné que ma monétisation est suspendue pour CNI expirée
Quand je soumets une nouvelle CNI valide Et que Mangopay valide le document sous 24-72h
Alors ma monétisation est réactivée automatiquement Et je recommence à générer des revenus
15. Suspension si fraude détectée
Étant donné que le système détecte une activité frauduleuse (bots, écoutes artificielles)
Quand l'équipe modération confirme la fraude
Alors ma monétisation est suspendue immédiatement Et mon compte est mis sous enquête Et je reçois un email m'informant de la suspension
16. Enquête fraude - Vérification manuelle
Étant donné que ma monétisation est suspendue pour suspicion de fraude
Quand l'équipe modération enquête
Alors elle analyse:
| élément à vérifier | outil |
|---|---|
| Patterns d'écoute suspects | Analytics + logs |
| Origine géographique | Logs IP |
| Vitesse de croissance anormale | Graphiques statistiques |
| Plaintes utilisateurs | Système de signalement |
17. Levée suspension si fraude non confirmée
Étant donné que mon compte était suspendu pour suspicion de fraude
Quand l'enquête conclut qu'il n'y a pas eu de fraude
Alors ma monétisation est réactivée Et les revenus suspendus pendant l'enquête sont versés normalement Et je reçois un email d'excuses avec explication
18. Suspension définitive si fraude confirmée
Étant donné que l'enquête confirme une fraude avérée
Quand l'équipe modération prend la décision
Alors ma monétisation est définitivement désactivée Et mon solde en attente est gelé (non versé) Et je peux recevoir un strike 4 (ban définitif du compte)
19. Suppression définitive sur demande créateur
Étant donné que je veux arrêter définitivement la monétisation
Quand j'accède à "Paramètres > Monétisation > Supprimer définitivement"
Alors une confirmation stricte est demandée Et je dois taper "SUPPRIMER" pour confirmer
20. Solde versé sous 30 jours après suppression
Étant donné que je supprime définitivement ma monétisation Et que mon solde en attente est 127.45€
Quand la suppression est confirmée
Alors mon solde sera versé sous 30 jours Et je reçois un dernier virement de clôture Et mon e-wallet Mangopay est clôturé
21. Suppression auto si inactivité 24 mois + solde <50€
Étant donné que je n'ai plus publié de contenu depuis 24 mois Et que mon solde en attente est 12.30€ (<50€)
Quand le processus de purge RGPD s'exécute
Alors ma monétisation est automatiquement supprimée Et mon solde de 12.30€ est perdu (trop faible pour virement) Et mes données KYC sont archivées puis supprimées selon la législation
22. Email de préavis 60 jours avant purge RGPD
Étant donné que je suis inactif depuis 22 mois
Quand le système détecte l'inactivité
Alors je reçois un email:
23. Ban définitif compte - Strike 4
Étant donné que je reçois un 4ème strike (violation grave ou répétée)
Quand l'équipe modération applique le strike 4
Alors mon compte est banni définitivement Et ma monétisation est supprimée définitivement Et mon solde en attente est gelé (non versé) Et je ne peux plus créer de nouveau compte (blacklist email/SIRET)
24. Email pour toute suspension
Étant donné que ma monétisation est suspendue (quelle qu'en soit la raison)
Quand la suspension devient effective
Alors je reçois immédiatement un email:
25. Notification in-app avec raison explicite
Étant donné que ma monétisation est suspendue
Quand je me connecte à l'application
Alors je vois une bannière en haut de mon dashboard:
26. Email de confirmation lors de réactivation
Étant donné que ma monétisation était suspendue
Quand elle est réactivée (automatiquement ou manuellement)
Alors je reçois un email:
27. Dashboard admin - Suspensions actives
Étant donné qu'un admin RoadWave consulte les suspensions
Quand il accède au dashboard admin "Monétisation > Suspensions"
Alors il voit:
| raison suspension | nombre actif | taux |
|---|---|---|
| Strikes (3+) | 23 | 1.8% |
| RIB invalide | 12 | 0.9% |
| Documents KYC expirés | 8 | 0.6% |
| Fraude sous enquête | 3 | 0.2% |
| TOTAL | 46 | 3.7% |
28. Alertes si taux de suspension >5%
Étant donné que le taux de suspension dépasse 5%
Quand le système détecte cette anomalie
Alors une alerte est envoyée à l'équipe:
29. Statistiques personnelles - Temps actif monétisation
Étant donné que j'accède à mon dashboard créateur
Quand je consulte "Statistiques > Monétisation"
Alors je vois:
| métrique | valeur |
|---|---|
| Date activation monétisation | 20 janvier 2025 |
| Temps actif total | 8 mois |
| Périodes de désactivation | 2 (3 mois total) |
| Suspensions subies | 0 |
| Statut actuel | ✅ Actif |
30. Export données suspension (RGPD)
Étant donné que je demande l'export de mes données
Quand l'export est généré
Alors l'historique des suspensions est inclus:
31. Suppression compte et données monétisation
Étant donné que je supprime définitivement mon compte RoadWave
Quand la suppression est confirmée
Alors toutes mes données de monétisation sont supprimées:
| donnée | action |
|---|---|
| Solde en attente | Versé sous 30 jours puis supprimé |
| Historique revenus | Archivé 10 ans (obligation légale) |
| Documents KYC | Archivés 10 ans chez Mangopay puis supprimés |
| E-wallet Mangopay | Clôturé après versement final |
32. Conservation archives 10 ans obligation légale
Étant donné que je supprime mon compte
Quand mes données sont archivées
Alors RoadWave conserve 10 ans:
| donnée archivée | raison |
|---|---|
| Relevés mensuels PDF | Obligation comptable France |
| Déclarations DAS2 | Obligation fiscale France |
| Justificatifs virements | Preuve paiement en cas d'audit |
Et après 10 ans, tout est supprimé définitivement
33. Suspension temporaire pour maintenance technique
Étant donné que Mangopay effectue une maintenance planifiée
Quand la maintenance est programmée
Alors tous les créateurs reçoivent un email préventif 7 jours avant:
34. Réactivation progressive après incident majeur
Étant donné qu'un incident technique majeur suspend toutes les monétisations
Quand l'incident est résolu
Alors les réactivations se font progressivement:
| vague | critère | % créateurs |
|---|---|---|
| 1 | Top 10% créateurs (revenus) | 10% |
| 2 | Créateurs vérifiés | 30% |
| 3 | Tous les autres créateurs | 60% |
Et cela évite une surcharge système lors de la reprise
35. Support prioritaire pour créateurs suspendus injustement
Étant donné que ma monétisation est suspendue Et que je pense que c'est une erreur
Quand je contacte le support avec tag "Suspension monétisation"
Alors mon ticket est traité en priorité (SLA 24h) Et un agent expert examine mon cas Et si suspension injustifiée, je suis réactivé immédiatement avec excuses
KYC et inscription à la monétisation
En tant que créateur éligible Je veux compléter le KYC pour activer la monétisation Afin de recevoir des paiements légalement
37 scénarios
Contexte commun à tous les scénarios
Étant donné que je remplis tous les critères de monétisation Et que j'ai cliqué sur "Demander la monétisation"
1. Redirection vers formulaire KYC Mangopay
Quand je démarre le processus d'activation
Alors je suis redirigé vers un formulaire KYC Et le formulaire est fourni par Mangopay (iframe sécurisée) Et toutes les données sont chiffrées et hébergées en EU
2. Statut auto-entrepreneur accepté
Étant donné que je suis auto-entrepreneur
Quand je renseigne mon statut juridique
Alors l'option "Auto-entrepreneur (micro-BNC)" est disponible Et je peux continuer le processus
3. Statut société SARL/SAS/SASU accepté
Étant donné que j'ai créé une société
Quand je renseigne mon statut juridique
Alors les options suivantes sont disponibles:
| statut juridique |
|---|
| SARL |
| SAS |
| SASU |
Et je peux continuer le processus
4. Statut particulier refusé
Étant donné que je n'ai pas de statut professionnel
Quand j'essaie de m'inscrire en tant que "Particulier"
Alors le formulaire affiche: Et je ne peux pas continuer sans statut professionnel
5. Document SIRET obligatoire et validé
Étant donné que je renseigne mon SIRET
Quand je saisis "12345678901234" (14 chiffres)
Alors le format est validé Et Mangopay vérifie l'existence du SIRET auprès du répertoire SIRENE Et si valide, le document est accepté
6. SIRET invalide ou inexistant
Étant donné que je renseigne un SIRET inexistant
Quand je saisis "99999999999999"
Alors Mangopay rejette le SIRET Et je vois "SIRET non trouvé dans le répertoire SIRENE. Vérifiez le numéro." Et je dois corriger avant de continuer
7. RIB professionnel obligatoire
Étant donné que j'upload mon RIB
Quand le RIB est scanné par Mangopay
Alors le système vérifie que le titulaire correspond à mon SIRET Et que l'IBAN commence par "FR" (compte français) Et si valide, le document est accepté
8. RIB particulier refusé
Étant donné que j'upload un RIB de compte particulier
Quand Mangopay détecte que le compte n'est pas professionnel
Alors le RIB est rejeté Et je vois:
9. Pièce d'identité CNI en cours de validité
Étant donné que j'upload ma carte nationale d'identité
Quand Mangopay analyse le document
Alors la date d'expiration est vérifiée Et si la CNI est valide, le document est accepté Et mon identité est vérifiée par OCR + vérification manuelle
10. Pièce d'identité expirée refusée
Étant donné que j'upload une CNI expirée depuis 2 ans
Quand Mangopay analyse le document
Alors le document est rejeté Et je vois "Pièce d'identité expirée. Veuillez fournir un document en cours de validité."
11. Passeport accepté comme alternative
Étant donné que je n'ai pas de CNI
Quand j'upload mon passeport en cours de validité
Alors Mangopay accepte le passeport Et mon identité est vérifiée de la même manière
12. Numéro TVA intracommunautaire si applicable
Étant donné que mon CA dépasse 37 000€/an Et que je suis sorti de la franchise en base
Quand je renseigne mon numéro TVA intracommunautaire
Alors le format "FR + 11 chiffres" est validé Et Mangopay vérifie l'existence auprès de la Commission Européenne (VIES)
13. TVA non applicable pour micro-BNC sous franchise
Étant donné que je suis auto-entrepreneur sous franchise en base Et que mon CA est <37 000€/an
Quand je remplis le formulaire KYC
Alors le champ "Numéro TVA" est optionnel Et je peux continuer sans TVA
14. Kbis <3 mois pour sociétés
Étant donné que je suis gérant d'une SARL
Quand j'upload mon extrait Kbis
Alors Mangopay vérifie que le Kbis date de moins de 3 mois Et que le SIRET correspond Et si valide, le document est accepté
15. Kbis trop ancien refusé
Étant donné que j'upload un Kbis de 5 mois
Quand Mangopay analyse le document
Alors le Kbis est rejeté Et je vois "Le Kbis doit dater de moins de 3 mois. Téléchargez un extrait récent sur infogreffe.fr"
16. Vérification identité ne correspond pas au compte
Étant donné que mon compte RoadWave est au nom de "Jean Dupont" Mais que ma CNI est au nom de "Pierre Martin"
Quand Mangopay compare les identités
Alors le KYC est rejeté Et je vois:
17. Liste noire anti-blanchiment détectée
Étant donné que mon identité apparaît sur une liste anti-blanchiment
Quand Mangopay effectue la vérification AML (Anti-Money Laundering)
Alors le KYC est automatiquement rejeté Et je vois "Votre demande ne peut être acceptée pour des raisons de conformité légale" Et mon compte créateur peut être suspendu
18. Délai de vérification 24-72h si documents conformes
Étant donné que j'ai soumis tous les documents valides
Quand Mangopay traite ma demande
Alors je reçois un email "KYC en cours de vérification (24-72h)" Et mon statut est "En attente de validation" Et je peux continuer à publier des contenus en attendant
19. Validation KYC réussie
Étant donné que mes documents sont conformes
Quand Mangopay valide mon KYC après 48h
Alors je reçois un email "Monétisation activée !" Et mon statut passe à "Monétisé" Et je commence à générer des revenus dès maintenant
20. Rejet KYC pour documents invalides
Étant donné que j'ai soumis une CNI floue et illisible
Quand Mangopay analyse les documents
Alors le KYC est rejeté après 24h Et je reçois un email détaillant les documents à refournir:
21. E-wallet Mangopay créé automatiquement
Étant donné que mon KYC est validé
Quand Mangopay finalise mon inscription
Alors un e-wallet Mangopay est créé automatiquement à mon nom Et tous mes futurs revenus seront transférés vers ce wallet Et les virements SEPA vers mon RIB seront effectués depuis ce wallet
22. Conformité RGPD - Données hébergées EU
Étant donné que je fournis mes documents KYC
Quand Mangopay stocke mes données
Alors toutes les données sont hébergées en Union Européenne Et Mangopay est régulé par l'ACPR (Autorité de Contrôle Prudentiel) Et mes données sont protégées selon le RGPD
23. KYC gratuit inclus dans Mangopay
Étant donné que je complète le KYC
Quand le processus se termine
Alors aucun frais ne m'est facturé (0€) Et aucun frais n'est facturé à RoadWave (inclus dans l'offre Mangopay)
24. Base légale - Conformité fiscale française
Étant donné que RoadWave est une plateforme française
Quand je génère des revenus >1200€/an
Alors RoadWave doit déclarer ces revenus aux impôts (DAS2) Et le KYC permet de garantir l'identité réelle du bénéficiaire Et cela respecte la réglementation fiscale française
25. Base légale - Directive anti-blanchiment EU 2018/843
Étant donné que RoadWave verse de l'argent aux créateurs
Quand le KYC est effectué
Alors RoadWave respecte la 5ème directive anti-blanchiment EU Et Mangopay effectue les vérifications requises (identité, liste noire, origine fonds)
26. Notification de mise à jour documents expirés
Étant donné que ma CNI va expirer dans 30 jours
Quand le système détecte l'expiration proche
Alors je reçois un email:
27. Suspension monétisation si documents expirés
Étant donné que ma CNI est expirée depuis 10 jours Et que je n'ai pas mis à jour mes documents
Quand le système vérifie mon statut KYC
Alors ma monétisation est suspendue automatiquement Et je ne génère plus de revenus jusqu'à mise à jour
28. Réactivation sans nouveau KYC si données à jour
Étant donné que j'ai désactivé temporairement ma monétisation il y a 6 mois Et que mes documents KYC sont toujours valides
Quand je réactive la monétisation
Alors je n'ai pas besoin de refaire le KYC Et la réactivation est immédiate
29. Nouveau KYC requis après 2 ans d'inactivité
Étant donné que j'ai désactivé ma monétisation il y a 25 mois
Quand j'essaie de réactiver
Alors le système demande un nouveau KYC Et je dois soumettre des documents à jour (CNI peut avoir changé)
30. Support créateur pour problèmes KYC
Étant donné que mon KYC est rejeté et je ne comprends pas pourquoi
Quand je contacte le support RoadWave
Alors un agent peut consulter les raisons du rejet Mangopay Et m'aider à fournir les bons documents
31. Export données KYC pour RGPD
Étant donné que je demande l'export de mes données personnelles
Quand l'export est généré
Alors les informations KYC sont incluses: Et les documents scannés (CNI, RIB) sont exclus pour sécurité
32. Suppression compte et données KYC
Étant donné que je supprime définitivement mon compte RoadWave
Quand la suppression est confirmée
Alors mes données KYC chez Mangopay sont archivées 10 ans (obligation légale) Mais supprimées de la base RoadWave immédiatement Et mon e-wallet est clôturé après versement du solde final
33. Statistiques KYC pour monitoring plateforme
Étant donné que RoadWave suit la qualité du processus KYC
Quand un admin consulte les métriques
Alors il voit:
| métrique | valeur exemple |
|---|---|
| Demandes KYC ce mois | 247 |
| Taux de validation | 87% |
| Délai moyen validation | 36h |
| Taux de rejet (documents invalides) | 13% |
Et cela permet d'optimiser le processus
34. Vérification SIRET via API INSEE
Étant donné que je saisis mon SIRET
Quand le système le valide
Alors une requête est faite à l'API SIRENE de l'INSEE Et le système vérifie que le SIRET existe et est actif Et récupère le nom de l'entreprise pour pré-remplir le formulaire
35. Détection fraude - Même SIRET utilisé par plusieurs comptes
Étant donné qu'un SIRET "12345678901234" est déjà utilisé par un autre créateur
Quand j'essaie d'utiliser le même SIRET
Alors le système détecte la duplication Et affiche "Ce SIRET est déjà utilisé par un autre compte RoadWave" Et je dois contacter le support si c'est une erreur
36. Protection données sensibles - Logs chiffrés
Étant donné que des données KYC sensibles transitent dans le système
Quand les logs sont enregistrés
Alors les numéros SIRET, IBAN et données CNI sont masqués: Et seule l'équipe sécurité peut accéder aux données complètes
37. Backup Mangopay des documents KYC
Étant donné que mes documents KYC sont stockés chez Mangopay
Quand un audit est demandé par les autorités
Alors Mangopay peut fournir les documents originaux Et RoadWave n'a pas besoin de stocker ces documents (réduction risque RGPD)
Obligations fiscales
En tant que créateur monétisé Je veux que RoadWave génère automatiquement les documents fiscaux requis Afin de faciliter ma comptabilité et respecter la loi
30 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis un créateur avec la monétisation activée Et que je génère des revenus sur RoadWave
1. Génération automatique relevé mensuel PDF
Étant donné que le mois de janvier se termine
Quand le système calcule mes revenus du mois
Alors un relevé mensuel PDF est généré automatiquement Et le PDF est disponible dans mon tableau de bord
2. Contenu du relevé mensuel PDF
Étant donné que mon relevé de janvier est généré
Quand je télécharge le PDF
Alors le document contient:
3. Téléchargement relevé depuis tableau de bord
Étant donné que je suis sur mon tableau de bord créateur
Quand j'accède à l'onglet "Revenus > Historique"
Alors je vois la liste de mes relevés mensuels:
| mois | montant | actions |
|---|---|---|
| Janvier 2025 | 150.00€ | 📄 Télécharger PDF |
| Décembre 2024 | 123.50€ | 📄 Télécharger PDF |
| Novembre 2024 | 98.75€ | 📄 Télécharger PDF |
4. Conservation relevés accessibles 10 ans
Étant donné que j'ai commencé la monétisation en janvier 2025
Quand je consulte mes relevés en janvier 2035 (10 ans plus tard)
Alors tous les relevés depuis 2025 sont toujours accessibles Et je peux télécharger n'importe quel relevé historique Et cela respecte l'obligation de conservation comptable de 10 ans
5. Export CSV à la demande
Étant donné que je clique sur "Exporter pour comptable"
Quand je choisis la période "Année 2025"
Alors un fichier CSV est généré et téléchargé
6. Contenu export CSV détaillé
Étant donné que j'exporte mes données comptables 2025
Quand je télécharge le fichier CSV
Alors le fichier contient:
7. Transmission à l'expert-comptable
Étant donné que j'ai téléchargé mon export CSV 2025
Quand je l'envoie à mon expert-comptable
Alors il peut importer le fichier dans son logiciel comptable Et il saisit rapidement mes revenus RoadWave Et cela facilite ma déclaration fiscale annuelle
8. DAS2 généré automatiquement si revenus >1200€/an
Étant donné que mes revenus 2025 totalisent 2,450€
Quand l'année 2025 se termine
Alors RoadWave génère automatiquement une DAS2 pour les impôts Et la DAS2 est transmise à la DGFIP en janvier 2026
9. Contenu de la DAS2
Étant donné que RoadWave génère ma DAS2 pour 2025
Quand la DGFIP reçoit la déclaration
Alors le document contient:
10. Créateur reçoit une copie de la DAS2
Étant donné que RoadWave transmet ma DAS2 aux impôts
Quand la transmission est confirmée
Alors je reçois un email avec une copie de la DAS2 en pièce jointe Et je peux consulter le document dans mon tableau de bord
11. Pas de DAS2 si revenus <1200€/an
Étant donné que mes revenus 2025 totalisent seulement 890€
Quand l'année 2025 se termine
Alors aucune DAS2 n'est générée car le seuil de 1200€ n'est pas atteint Mais je dois quand même déclarer mes revenus dans ma déclaration personnelle
12. Base légale DAS2 - Obligation France
Étant donné que RoadWave verse des honoraires à des prestataires
Quand les revenus dépassent 1200€/an
Alors la déclaration DAS2 est obligatoire selon l'article 87 du Code Général des Impôts Et le non-respect entraîne une amende de 15€ par bénéficiaire non déclaré
13. Transmission DAS2 via EDI-TDFC
Étant donné que RoadWave génère 1,247 DAS2 pour l'année 2025
Quand la transmission aux impôts est effectuée
Alors la transmission se fait via le portail EDI-TDFC de la DGFIP Et la transmission est automatisée (pas de saisie manuelle) Et un accusé de réception est reçu sous 48h
14. Créateur responsable de déclarer aux impôts
Étant donné que j'ai reçu 2,450€ de revenus RoadWave en 2025
Quand je fais ma déclaration fiscale en mai 2026
Alors je dois déclarer ces 2,450€ dans ma déclaration annuelle Et si je suis auto-entrepreneur, je déclare en BNC (Bénéfices Non Commerciaux)
15. Créateur responsable des cotisations URSSAF
Étant donné que je suis auto-entrepreneur Et que j'ai reçu 2,450€ de revenus RoadWave en 2025
Quand je fais ma déclaration URSSAF trimestrielle
Alors je dois déclarer ces revenus à l'URSSAF Et je paie ~22% de cotisations sociales (soit ~539€)
16. TVA non applicable en franchise en base
Étant donné que je suis auto-entrepreneur en micro-BNC Et que mon chiffre d'affaires est <37,800€/an
Quand je génère des revenus sur RoadWave
Alors je bénéficie de la franchise en base de TVA Et je ne facture pas de TVA à RoadWave Et je ne récupère pas la TVA sur mes achats
17. TVA applicable si CA >37,800€/an
Étant donné que mon chiffre d'affaires total 2025 est 45,000€
Quand je dépasse le seuil de franchise en base (37,800€)
Alors je dois facturer de la TVA (20%) à RoadWave Et je dois obtenir un numéro TVA intracommunautaire Et je dois déclarer ma TVA mensuellement ou trimestriellement
18. Conservation justificatifs 10 ans - Obligation légale
Étant donné que je génère des revenus sur RoadWave
Quand je télécharge mes relevés mensuels et exports CSV
Alors je dois les conserver 10 ans (obligation comptable France) Et en cas de contrôle fiscal, je dois pouvoir les fournir
19. Mangopay transmet automatiquement via DAC7
Étant donné que je suis créateur monétisé sur RoadWave
Quand l'année se termine
Alors Mangopay transmet automatiquement mes revenus aux autorités fiscales EU Et cela respecte la directive DAC7 (2021/514) sur la transparence fiscale des plateformes
20. Directive DAC7 - Obligations plateforme
Étant donné que RoadWave est une plateforme facilitant des transactions
Quand Mangopay gère les paiements
Alors Mangopay transmet automatiquement:
| information | destinataire |
|---|---|
| Identité créateur (SIRET) | Autorités fiscales pays EU |
| Revenus annuels | Autorités fiscales pays EU |
| Nombre transactions | Autorités fiscales pays EU |
Et RoadWave n'a pas besoin de faire cette transmission manuellement
21. Justificatif virement = Preuve bancaire comptable
Étant donné que je reçois un virement de 150.00€ de Mangopay
Quand je consulte mon relevé bancaire
Alors je vois le virement avec la référence MANGOPAY-ABC123 Et ce relevé bancaire sert de justificatif comptable Et je peux le fournir à mon expert-comptable ou aux impôts
22. Notification annuelle rappel déclaration fiscale
Étant donné que je suis créateur monétisé
Quand le mois d'avril 2026 arrive (période déclaration impôts France)
Alors je reçois un email de rappel:
23. Page ressources fiscales pour créateurs
Étant donné que je suis créateur monétisé
Quand j'accède à "Aide > Fiscalité"
Alors je vois une page avec:
| ressource | description |
|---|---|
| Guide auto-entrepreneur RoadWave | PDF expliquant démarches et déclarations |
| FAQ fiscalité | Questions fréquentes sur TVA, cotisations, etc. |
| Liens URSSAF et impots.gouv.fr | Portails officiels |
| Contact expert-comptable partenaire | Recommandations d'experts connaissant RoadWave |
24. Dashboard créateur - Récapitulatif annuel
Étant donné que je consulte mon dashboard en décembre 2025
Quand j'accède à "Revenus > Récapitulatif annuel"
Alors je vois:
25. Génération automatique minimise erreurs
Étant donné que tous les documents fiscaux sont générés automatiquement
Quand un créateur télécharge ses documents
Alors les montants sont garantis corrects (issus de la base de données) Et il n'y a pas d'erreur de saisie manuelle Et cela réduit les risques de contrôle fiscal
26. Conformité RGPD - Données fiscales chiffrées
Étant donné que les documents fiscaux contiennent des données sensibles (SIRET, revenus)
Quand les documents sont stockés
Alors ils sont chiffrés au repos (encryption AES-256) Et seul le créateur et les admins autorisés peuvent y accéder Et les logs d'accès sont conservés pour audit
27. Backup documents fiscaux 10 ans
Étant donné qu'un document fiscal est généré
Quand il est stocké dans la base de données
Alors une copie est sauvegardée sur S3 (stockage durable) Et les backups sont répliqués sur 3 zones de disponibilité Et la conservation est garantie 10 ans minimum
28. Audit trail génération DAS2
Étant donné que 1,247 DAS2 sont générées en janvier 2026
Quand un audit est demandé
Alors tous les événements sont loggés:
| événement | timestamp | détails |
|---|---|---|
| Calcul revenus annuels | 2025-12-31 23:59:00 | 1,247 créateurs éligibles |
| Génération fichier EDI | 2026-01-10 08:00:00 | Format EDI-TDFC |
| Transmission DGFIP | 2026-01-10 10:30:00 | Via portail EDI-TDFC |
| Accusé réception DGFIP | 2026-01-11 14:20:00 | Transmission confirmée |
| Email créateurs | 2026-01-11 16:00:00 | 1,247 emails envoyés |
29. Statistiques admin - Conformité fiscale
Étant donné qu'un admin RoadWave consulte les métriques fiscales
Quand il accède au dashboard admin
Alors il voit:
| métrique | valeur 2025 |
|---|---|
| Créateurs monétisés | 1,247 |
| Créateurs éligibles DAS2 (>1200€) | 847 (68%) |
| Revenus totaux versés | 1,890,345€ |
| DAS2 transmises à la DGFIP | 847 |
| Taux conformité | 100% |
30. Support créateur pour questions fiscales
Étant donné que j'ai une question sur ma déclaration fiscale
Quand je contacte le support RoadWave
Alors l'agent peut consulter mes documents fiscaux Et m'aider à comprendre ce que je dois déclarer Mais il ne peut pas me conseiller fiscalement (pas expert-comptable) Et il me recommande de consulter un expert-comptable si nécessaire
Paiement des créateurs
En tant que créateur monétisé Je veux recevoir mes paiements mensuels de manière fiable Afin d'être rémunéré pour mon travail
35 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis un créateur avec la monétisation activée Et que mon KYC est validé
1. Seuil minimum de 50€ atteint - Paiement effectué
Étant donné que mes revenus du mois sont 73.45€
Quand le dernier jour du mois arrive
Alors mon solde de 73.45€ est transféré vers "en attente de paiement" Et le paiement sera effectué le 15 du mois prochain
2. Seuil minimum de 50€ non atteint - Report mois suivant
Étant donné que mes revenus du mois sont 32.17€
Quand le dernier jour du mois arrive
Alors mon solde de 32.17€ est reporté au mois suivant Et je vois "Solde insuffisant pour paiement (<50€). Report mois prochain."
3. Cumul sur plusieurs mois jusqu'à atteindre 50€
Étant donné que mes revenus sont:
| mois | revenus | solde cumulé |
|---|---|---|
| Janvier | 18.50€ | 18.50€ |
| Février | 22.30€ | 40.80€ |
| Mars | 15.70€ | 56.50€ |
Quand la fin du mois de mars arrive
Alors le solde cumulé de 56.50€ dépasse les 50€ Et un paiement de 56.50€ est effectué le 15 avril
4. Calcul des revenus le dernier jour du mois
Étant donné que nous sommes le 31 janvier à 23h59
Quand le système calcule les revenus du mois
Alors une requête SQL agrège tous les revenus pub et premium Et le solde final du mois est figé dans monthly_revenues Et le compteur du mois en cours repart à 0€ le 1er février
5. Période de traitement contestations 1-14 du mois
Étant donné que mes revenus de janvier sont calculés à 150.00€
Quand la période du 1-14 février arrive
Alors RoadWave analyse les éventuelles fraudes ou contestations Et si une fraude est détectée, les revenus concernés sont retirés du solde Et le solde final est validé le 14 février
6. Virement SEPA le 15 du mois suivant
Étant donné que mes revenus de janvier validés sont 150.00€
Quand le 15 février arrive
Alors Mangopay initie un virement SEPA depuis mon e-wallet vers mon RIB Et le statut du paiement passe à "En cours"
7. Réception virement 16-18 du mois (1-3 jours SEPA)
Étant donné qu'un virement SEPA a été initié le 15 février
Quand 1-3 jours ouvrés s'écoulent
Alors je reçois le virement sur mon compte bancaire entre le 16 et 18 février Et je peux consulter l'historique des paiements dans mon dashboard
8. Virement SEPA gratuit pour comptes EU
Étant donné que mon RIB est français (IBAN FR)
Quand Mangopay effectue le virement
Alors aucun frais n'est prélevé (virement SEPA gratuit) Et je reçois 100% du montant annoncé
9. Virement international hors EU avec frais variables
Étant donné que je suis créateur expatrié avec RIB hors Union Européenne
Quand Mangopay effectue le virement international
Alors des frais variables s'appliquent selon le pays Et les frais sont déduits du montant final Et je vois le détail des frais dans mon historique
10. E-wallet Mangopay automatique
Étant donné que mon KYC est validé
Quand mes revenus sont calculés
Alors les revenus sont automatiquement transférés vers mon e-wallet Mangopay Et l'e-wallet est débité lors du virement SEPA vers mon RIB Et je n'ai aucune action manuelle à faire
11. Tableau de bord - Revenus pub temps réel
Étant donné que j'accède à mon tableau de bord créateur
Quand je consulte l'onglet "Revenus"
Alors je vois:
| métrique | valeur exemple |
|---|---|
| Revenus pub ce mois | 123.45€ |
| Revenus premium ce mois | 67.89€ |
| Solde disponible ce mois | 191.34€ |
| Prochain paiement | 15 mars 2025 |
Et ces valeurs sont mises à jour en temps réel (cache Redis, refresh 10 min)
12. Tableau de bord - Solde en attente de paiement
Étant donné que mes revenus de janvier sont calculés et validés Et que nous sommes le 10 février
Quand je consulte mon tableau de bord
Alors je vois:
| métrique | valeur exemple |
|---|---|
| Solde en attente | 150.00€ |
| Date de paiement | 15 février 2025 |
| Statut | En attente |
13. Historique des virements permanents
Étant donné que je suis monétisé depuis 6 mois
Quand je consulte l'historique des paiements
Alors je vois la liste complète:
| date paiement | montant | statut | référence virement |
|---|---|---|---|
| 15/02/2025 | 150.00€ | Payé | MANGOPAY-ABC123 |
| 15/01/2025 | 123.50€ | Payé | MANGOPAY-XYZ789 |
| 15/12/2024 | 98.75€ | Payé | MANGOPAY-DEF456 |
| ... | ... | ... | ... |
14. Export comptable CSV téléchargeable
Étant donné que je clique sur "Télécharger export comptable"
Quand le fichier CSV est généré
Alors je télécharge un fichier contenant: Et je peux transmettre ce fichier à mon expert-comptable
15. Échec virement - Tentative 1 échouée
Étant donné qu'un virement est initié le 15 février Mais que mon RIB est invalide ou le compte est fermé
Quand Mangopay détecte l'échec
Alors le statut passe à "Échec - Retry programmé le 18 février" Et je reçois un email m'alertant du problème
16. Échec virement - Retry automatique J+3
Étant donné que le virement du 15 février a échoué
Quand le 18 février arrive (J+3)
Alors Mangopay tente automatiquement un nouveau virement Et si le RIB est toujours invalide, le virement échoue à nouveau
17. Échec virement - Retry automatique J+7
Étant donné que les 2 premières tentatives ont échoué
Quand le 22 février arrive (J+7)
Alors Mangopay tente une 3ème et dernière fois Et si le virement échoue encore, la monétisation est suspendue
18. Échec virement - Suspension monétisation après 3 échecs
Étant donné que les 3 tentatives de virement ont échoué
Quand le système détecte le 3ème échec
Alors ma monétisation est suspendue automatiquement Et je reçois un email:
19. Mise à jour RIB et réactivation paiement
Étant donné que ma monétisation est suspendue pour RIB invalide Et que mon solde en attente est 150.00€
Quand je mets à jour mon RIB avec un compte valide
Alors Mangopay tente immédiatement un nouveau virement Et si le virement réussit, ma monétisation est réactivée automatiquement
20. Notification email lors de chaque paiement
Étant donné qu'un virement de 150.00€ est effectué le 15 février
Quand le virement est confirmé par Mangopay
Alors je reçois un email:
21. Justification seuil 50€ - Éviter frais bancaires micro-sommes
Étant donné que Mangopay facture des frais fixes par virement Et que les banques peuvent facturer des frais de réception
Quand un créateur génère seulement 5€/mois
Alors un virement mensuel coûterait proportionnellement trop cher Et le seuil de 50€ garantit des frais proportionnels raisonnables
22. Comparaison avec YouTube (seuil 100$)
Étant donné que YouTube fixe le seuil à 100$ (~90€)
Quand RoadWave fixe le seuil à 50€
Alors RoadWave est plus accessible pour petits créateurs Et les paiements arrivent plus rapidement
23. Comparaison avec Twitch (seuil 50$)
Étant donné que Twitch fixe le seuil à 50$ (~45€)
Quand RoadWave fixe le seuil à 50€
Alors le seuil est aligné sur Twitch Et les créateurs comprennent facilement le système
24. Comparaison avec Spotify (seuil 10€ mais délais longs)
Étant donné que Spotify a un seuil bas de 10€ mais verse tous les 3 mois
Quand RoadWave a un seuil de 50€ mais verse chaque mois
Alors les créateurs reçoivent leurs paiements plus régulièrement Et la trésorerie est plus prévisible
25. Relevé mensuel PDF automatique
Étant donné que mes revenus de janvier sont calculés
Quand le 1er février arrive
Alors un relevé mensuel PDF est généré automatiquement: Et le PDF est téléchargeable depuis mon tableau de bord
26. Conservation relevés 10 ans (obligation comptable)
Étant donné que je génère des revenus sur RoadWave
Quand je télécharge mes relevés mensuels
Alors je dois les conserver 10 ans (obligation légale France) Et RoadWave conserve également une copie pendant 10 ans pour audit
27. Dashboard admin - Monitoring paiements
Étant donné qu'un admin RoadWave consulte les paiements du mois
Quand il accède au dashboard admin
Alors il voit:
| métrique | valeur exemple |
|---|---|
| Créateurs payés ce mois | 1,247 |
| Montant total versé | 127,345€ |
| Paiements en attente | 34 |
| Échecs virements | 3 |
| Délai moyen réception (jours) | 1.8 |
28. Alerte admin si taux échec >5%
Étant donné que 8% des virements du mois ont échoué
Quand le système détecte le taux d'échec élevé
Alors une alerte est envoyée à l'équipe technique:
29. Statistiques personnelles - Moyenne revenus sur 6 mois
Étant donné que je suis monétisé depuis 6 mois
Quand je consulte mes statistiques
Alors je vois:
| métrique | valeur |
|---|---|
| Revenus moyens/mois | 134.50€ |
| Meilleur mois | 189.00€ |
| Mois le plus bas | 87.30€ |
| Tendance | +12% ↗ |
Et cela m'aide à suivre ma progression
30. Projection revenus annuels
Étant donné que mes revenus moyens sont 134.50€/mois
Quand je consulte les projections
Alors le système estime mes revenus annuels à ~1,614€ Et je peux anticiper mes déclarations fiscales
31. Notification seuil symbolique 1000€ cumulés
Étant donné que mes revenus cumulés depuis inscription atteignent 1000€
Quand le paiement qui franchit ce seuil est effectué
Alors je reçois une notification:
32. Performance calcul avec 100 000 créateurs monétisés
Étant donné que RoadWave a 100 000 créateurs monétisés
Quand le calcul des paiements du 15 du mois est lancé
Alors un job asynchrone traite les paiements par batch de 1000 Et tous les virements sont initiés en 2-4 heures Et les serveurs Mangopay gèrent la charge sans problème
33. Backup des données de paiement
Étant donné que les paiements sont critiques pour les créateurs
Quand un paiement est effectué
Alors les données sont sauvegardées dans PostgreSQL (principal) Et répliquées vers une base de backup (replica) Et une copie d'archive est stockée sur S3 (conservation 10 ans)
34. Audit trail complet des paiements
Étant donné qu'un paiement est initié, traité et complété
Quand un audit est demandé
Alors tous les événements sont loggés:
| événement | timestamp | détails |
|---|---|---|
| Calcul revenus mois | 2025-01-31 23:59:00 | Montant: 150.00€ |
| Validation période fraude | 2025-02-14 23:59:00 | Aucune fraude détectée |
| Initiation virement | 2025-02-15 09:00:00 | Mangopay ref: ABC123 |
| Confirmation virement | 2025-02-16 14:30:00 | Reçu par banque créateur |
Et ces logs sont conservés 10 ans pour conformité
35. Protection fraude - Détection pattern suspect
Étant donné qu'un créateur génère subitement 10 000€ de revenus en 1 mois
Alors que sa moyenne est de 50€/mois
Quand le système détecte cette anomalie
Alors le paiement est mis en attente pour vérification manuelle Et l'équipe modération analyse le compte avant validation
Sources de revenus créateurs
En tant que créateur monétisé Je veux générer des revenus via publicités et abonnés Premium Afin d'être rémunéré pour mon travail
34 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis un créateur avec la monétisation activée Et que mon KYC est validé
1. CPM créateur de 3€ / 1000 écoutes complètes
Étant donné que mes contenus ont généré 1000 écoutes complètes par des utilisateurs gratuits
Quand le calcul des revenus du mois est effectué
Alors je touche 3.00€ pour ces 1000 écoutes Et ce montant est ajouté à mon solde disponible
2. 10 000 écoutes gratuits → 30€ de revenus pub
Étant donné que mes contenus ont généré 10 000 écoutes complètes (utilisateurs gratuits)
Quand le mois se termine
Alors je touche 30.00€ de revenus publicitaires Et ces revenus sont visibles en temps réel dans mon tableau de bord
3. 50 000 écoutes gratuits → 150€ de revenus pub
Étant donné que mes contenus ont généré 50 000 écoutes complètes (utilisateurs gratuits)
Quand le mois se termine
Alors je touche 150.00€ de revenus publicitaires
4. 100 000 écoutes gratuits → 300€ de revenus pub
Étant donné que mes contenus ont généré 100 000 écoutes complètes (utilisateurs gratuits)
Quand le mois se termine
Alors je touche 300.00€ de revenus publicitaires
5. Répartition économique - Plateforme garde 94%
Étant donné qu'une publicité facturée 0.05€/écoute génère 50€ CPM
Quand la plateforme calcule la répartition
Alors le créateur touche 3€ (6% du CA pub) Et la plateforme garde 47€ (94%) pour:
| poste budgétaire | coût estimé |
|---|---|
| CDN + infrastructure | 10-15€ |
| Modération + support | 5-10€ |
| Développement + R&D | 10-15€ |
| Marge opérationnelle | 10-15€ |
6. Écoute complète = ≥80% du contenu écouté
Étant donné qu'un utilisateur gratuit écoute mon contenu de 10 minutes
Quand il écoute 8 minutes (80%)
Alors l'écoute compte comme "complète" Et je génère 0.003€ de revenus pub (3€/1000)
7. Écoute incomplète <80% ne compte pas
Étant donné qu'un utilisateur gratuit écoute mon contenu de 10 minutes Mais il skip après 5 minutes (50%)
Quand le calcul des revenus est effectué
Alors cette écoute ne compte pas comme "complète" Et je ne génère aucun revenu publicitaire pour cette écoute
8. Écoutes Premium ne comptent pas pour les revenus pub
Étant donné qu'un utilisateur Premium écoute 100% de mon contenu
Quand le calcul des revenus publicitaires est effectué
Alors cette écoute ne compte pas dans les revenus pub Mais elle compte dans les revenus Premium (système séparé)
9. Détection bots - Écoutes exclues
Étant donné qu'un bot génère 10 000 écoutes artificielles sur mes contenus
Quand le système détecte le pattern suspect (rate limiting, IP unique, etc.)
Alors ces écoutes sont marquées comme frauduleuses Et elles sont exclues du calcul des revenus publicitaires
10. Comparaison avec YouTube (3-5€/1000 vues)
Étant donné que YouTube paie 3-5€/1000 vues
Quand RoadWave fixe le CPM créateur à 3€/1000 écoutes
Alors le tarif est aligné sur le bas de la fourchette YouTube Et cela est compétitif pour un MVP sans marché publicitaire mature
11. Comparaison avec Spotify (3-4€/1000 écoutes)
Étant donné que Spotify paie ~3-4€/1000 écoutes
Quand RoadWave fixe le CPM créateur à 3€/1000 écoutes
Alors le tarif est aligné sur l'industrie musicale Et les créateurs audio peuvent anticiper des revenus similaires
12. Tableau de bord - Revenus pub temps réel
Étant donné que j'accède à mon tableau de bord créateur
Quand je consulte mes revenus publicitaires
Alors je vois:
| métrique | valeur exemple |
|---|---|
| Écoutes complètes ce mois (gratuit) | 23 456 |
| Revenus pub ce mois | 70.37€ |
| CPM effectif | 3.00€ |
Et ces valeurs sont mises à jour toutes les 10 minutes
13. Répartition 70/30 - Créateur touche 70%
Étant donné qu'un utilisateur Premium paie 4.99€/mois
Quand la répartition est calculée
Alors 3.49€ sont reversés aux créateurs écoutés (70%) Et 1.50€ sont gardés par la plateforme (30%)
14. Utilisateur écoute 3 créateurs - Répartition proportionnelle
Étant donné qu'un utilisateur Premium paie 4.99€/mois Et qu'il écoute 3 créateurs ce mois:
| créateur | temps écoute | ratio |
|---|---|---|
| Créateur A | 10h | 50% |
| Créateur B | 6h | 30% |
| Créateur C | 4h | 20% |
Quand le calcul des revenus Premium est effectué
Alors la répartition est:
| créateur | revenus |
|---|---|
| Créateur A | 1.75€ |
| Créateur B | 1.05€ |
| Créateur C | 0.70€ |
Et la somme totale versée aux créateurs est 3.50€ (70% de 4.99€)
15. Calcul SQL proportionnel au temps d'écoute
Étant donné qu'un utilisateur Premium a écouté plusieurs créateurs
Quand le système calcule les revenus du mois
Alors la requête SQL suivante est exécutée:
16. Utilisateur écoute un seul créateur - 100% à ce créateur
Étant donné qu'un utilisateur Premium paie 4.99€/mois Et qu'il n'écoute qu'un seul créateur (moi)
Quand le mois se termine
Alors je touche 3.49€ (70% de 4.99€) Et je reçois 100% de la part créateurs
17. Utilisateur Premium inactif - Aucun revenu généré
Étant donné qu'un utilisateur Premium paie 4.99€/mois Mais qu'il n'écoute aucun contenu ce mois
Quand le calcul des revenus Premium est effectué
Alors aucun créateur ne reçoit de revenus de cet utilisateur Et les 3.49€ de la part créateurs restent à la plateforme Et cela couvre les coûts d'infrastructure
18. Comparaison avec YouTube Premium (70/30)
Étant donné que YouTube Premium reverse 70% aux créateurs
Quand RoadWave fixe également 70/30
Alors le modèle est aligné sur le standard industrie Et les créateurs ont confiance dans l'équité du système
19. Comparaison avec Spotify (70/30)
Étant donné que Spotify reverse 70% aux artistes
Quand RoadWave fixe également 70/30
Alors le modèle est identique à Spotify Et les créateurs audio comprennent facilement le système
20. Apple Music moins avantageux (52/48)
Étant donné qu'Apple Music ne reverse que 52% aux artistes
Quand RoadWave offre 70% aux créateurs
Alors RoadWave est plus avantageux de 18 points Et cela devient un argument marketing fort
21. Justification équité - Créateurs les plus écoutés gagnent plus
Étant donné que 2 créateurs ont le même nombre d'abonnés Premium Mais que le Créateur A est écouté 20h/mois et le Créateur B seulement 2h/mois
Quand les revenus Premium sont calculés
Alors le Créateur A gagne 10× plus que le Créateur B Et cela récompense la qualité et l'engagement (pas juste l'abonnement)
22. Pas de "winner takes all" - Équité totale
Étant donné qu'un utilisateur Premium écoute 10 créateurs différents
Quand les revenus sont calculés
Alors chacun des 10 créateurs reçoit sa part proportionnelle Et il n'y a pas de système où un seul créateur prend tout
23. Marge plateforme 30% couvre absence revenus pub Premium
Étant donné qu'un utilisateur Premium ne voit aucune publicité
Quand la plateforme calcule ses revenus
Alors elle ne touche que les 30% de l'abonnement Premium (1.50€) Et cette marge compense la perte des revenus publicitaires (qui auraient été ~47€/1000 écoutes)
24. Tableau de bord - Revenus Premium temps réel
Étant donné que j'accède à mon tableau de bord créateur
Quand je consulte mes revenus Premium
Alors je vois:
| métrique | valeur exemple |
|---|---|
| Abonnés Premium actifs ayant écouté | 47 |
| Heures d'écoute Premium ce mois | 234h |
| Revenus Premium ce mois | 89.23€ |
Et ces valeurs sont mises à jour toutes les 10 minutes
25. Revenus cumulés pub + premium
Étant donné que j'ai généré ce mois:
| source | montant |
|---|---|
| Revenus pub | 150.00€ |
| Revenus Premium | 89.23€ |
Quand je consulte mon solde disponible
Alors le total est 239.23€ Et ce solde sera versé le 15 du mois prochain (si ≥50€)
26. Dashboard créateur - Vue d'ensemble
Étant donné que j'accède à mon tableau de bord créateur
Quand je consulte la page revenus
Alors je vois:
27. Export comptable CSV pour expert-comptable
Étant donné que je clique sur "Exporter pour comptable"
Quand l'export est généré
Alors je télécharge un fichier CSV: Et je peux transmettre ce fichier à mon expert-comptable
28. Notification hebdomadaire progression revenus
Étant donné que je suis créateur monétisé
Quand chaque lundi matin arrive
Alors je reçois un email récapitulatif:
29. Graphique évolution revenus sur 12 mois
Étant donné que je suis monétisé depuis 12 mois
Quand j'accède à mes statistiques
Alors je vois un graphique en courbes montrant:
| mois | revenus pub | revenus premium | total |
|---|---|---|---|
| Jan 25 | 150€ | 89€ | 239€ |
| Déc 24 | 123€ | 55€ | 178€ |
| Nov 24 | 100€ | 56€ | 156€ |
| ... | ... | ... | ... |
Et cela m'aide à suivre ma progression
30. Top 3 contenus les plus rentables du mois
Étant donné que j'ai publié 20 contenus ce mois
Quand je consulte mes statistiques détaillées
Alors je vois mon top 3 contenus:
| titre | écoutes | revenus pub | revenus premium | total |
|---|---|---|---|---|
| Mon meilleur épisode | 12,345 | 37.04€ | 23.45€ | 60.49€ |
| Discussion tech | 8,901 | 26.70€ | 15.67€ | 42.37€ |
| Road trip Bretagne | 7,234 | 21.70€ | 12.34€ | 34.04€ |
Et cela m'aide à comprendre quel type de contenu plaît le plus
31. Alertes seuils de revenus
Étant donné que j'ai activé les notifications de seuils
Quand mes revenus du mois dépassent 100€ pour la première fois
Alors je reçois une notification:
32. Performance calcul avec 100 000 créateurs
Étant donné que RoadWave a 100 000 créateurs monétisés
Quand le calcul des revenus mensuels est lancé le dernier jour du mois
Alors un job asynchrone traite tous les créateurs Et le calcul prend environ 2-4 heures pour tous les créateurs Et les résultats sont stockés dans la table monthly_revenues
33. Cache Redis pour métriques temps réel
Étant donné que je consulte mon dashboard plusieurs fois par jour
Quand la page se charge
Alors les compteurs sont récupérés depuis Redis:
| clé Redis | valeur exemple |
|---|---|
| creator:[id]:complete_listens:202501 | 50234 |
| creator:[id]:premium_hours:202501 | 234 |
| creator:[id]:revenue_ads:202501 | 150.70 |
| creator:[id]:revenue_premium:202501 | 89.23 |
Et le temps de réponse est <30ms
34. Prévision revenus fin de mois
Étant donné que nous sommes le 20 du mois Et que mes revenus actuels sont 160€
Quand le système calcule la projection
Alors il estime les revenus fin de mois à ~240€ (extrapolation linéaire) Et affiche "Projection fin de mois: ~240€" Et cela m'aide à anticiper mes revenus
Actions complémentaires à l'arrêt
En tant qu'auditeur avec véhicule arrêté Je veux accéder à des actions avancées depuis l'application mobile Afin de liker explicitement, m'abonner ou signaler du contenu
23 scénarios (21 standards, 2 plans)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un utilisateur est connecté Et que le véhicule est à l'arrêt (vitesse GPS = 0 km/h)
1. Like explicite avec bouton cœur
Étant donné que j'écoute un contenu tagué "Automobile" Et que ma jauge "Automobile" est à 60%
Quand je clique sur le bouton cœur "Like"
Alors ma jauge "Automobile" augmente de 2% Et une animation de cœur rouge s'affiche Et une vibration courte est déclenchée Et ma jauge "Automobile" est maintenant à 62%
2. Like explicite cumulable avec like automatique
Étant donné que j'ai écouté un contenu "Voyage" à 85% Et que j'ai reçu un like automatique renforcé (+2%) Et que ma jauge "Voyage" est à 52%
Quand je clique sur le bouton cœur "Like"
Alors ma jauge "Voyage" augmente encore de 2% Et ma jauge "Voyage" passe à 54% Et les deux likes sont cumulés
3. Unlike retire le like manuel uniquement
Étant donné que j'ai liké manuellement un contenu "Sport" Et que ma jauge "Sport" est à 57%
Quand je clique à nouveau sur le bouton cœur (toggle)
Alors le cœur redevient vide (unlike) Et ma jauge "Sport" diminue de 2% Et ma jauge "Sport" revient à 55%
4. Unlike ne retire pas le like automatique
Étant donné que j'ai écouté un contenu "Musique" à 90% Et que j'ai reçu un like automatique renforcé (+2%) Et que ma jauge "Musique" est à 52% Et que je n'ai PAS liké manuellement
Quand je consulte l'interface
Alors le bouton "Unlike" n'est pas disponible Et le cœur reste grisé (aucun like manuel) Et ma jauge reste à 52%
5. Abonnement à un créateur
Étant donné qu'un créateur publie des contenus tagués "Automobile" et "Technologie" Et que mes jauges sont:
| catégorie | niveau |
|---|---|
| Automobile | 50% |
| Technologie | 45% |
Quand je clique sur "S'abonner" sur le profil du créateur
Alors ma jauge "Automobile" augmente de 5% Et ma jauge "Technologie" augmente de 5% Et une animation d'étoile dorée s'affiche Et un badge "Abonné ✓" apparaît sur le profil Et mes nouvelles jauges sont:
| catégorie | niveau |
|---|---|
| Automobile | 55% |
| Technologie | 50% |
6. Désabonnement d'un créateur
Étant donné que je suis abonné à un créateur Et que mes jauges "Automobile" et "Technologie" sont à 55% et 50%
Quand je clique sur "Se désabonner"
Alors ma jauge "Automobile" diminue de 5% Et ma jauge "Technologie" diminue de 5% Et le badge "Abonné ✓" disparaît Et mes nouvelles jauges sont:
| catégorie | niveau |
|---|---|
| Automobile | 50% |
| Technologie | 45% |
7. Signalement d'un contenu inapproprié
Étant donné que j'écoute un contenu
Quand je clique sur le menu contextuel "⋮" Et que je sélectionne "Signaler"
Alors un formulaire de signalement s'ouvre Et je dois sélectionner une catégorie:
| Catégorie |
|---|
| Haine et violence |
| Contenu sexuel |
| Illégalité |
| Droits d'auteur |
| Spam |
| Désinformation (fake news) |
| Autre |
Et je peux ajouter un commentaire optionnel Et le signalement est envoyé au flux de modération
8. Feedback visuel pour like explicite
Étant donné que je clique sur le bouton cœur
Quand le like est enregistré
Alors une animation de cœur rouge se lance (0.5s) Et le cœur reste rouge plein Et une vibration haptique courte est déclenchée (iOS: .light, Android: 50ms) Et un badge "♥ Ajouté à vos favoris" s'affiche 2 secondes
9. Feedback visuel pour abonnement
Étant donné que je clique sur "S'abonner"
Quand l'abonnement est enregistré
Alors une animation d'étoile dorée se lance (0.8s) Et le bouton devient "Abonné ✓" avec badge doré Et une notification "Abonné à [Créateur]" s'affiche Et les contenus du créateur seront boostés +30% dans l'algo
10. Bouton like désactivé si vitesse >10 km/h
Étant donné que je conduis à 50 km/h
Quand j'essaie d'accéder au bouton cœur dans l'app mobile
Alors le bouton est grisé et non cliquable Et un message "Arrêtez-vous pour liker" s'affiche si clic tenté Et seules les commandes au volant physiques fonctionnent
11. Bouton abonnement désactivé en conduite
Étant donné que je conduis à 40 km/h
Quand j'essaie d'accéder au profil créateur dans l'app
Alors le bouton "S'abonner" est désactivé Et un message "Arrêtez-vous pour vous abonner" s'affiche Et la navigation dans l'app est limitée aux fonctions lecture
12. Signalement possible en conduite via vocal
Étant donné que je conduis à 60 km/h Et que j'utilise CarPlay avec Siri
Quand je dis "Hey Siri, signale ce contenu"
Alors Siri demande "Quelle catégorie ?" Et je peux répondre vocalement "Spam" ou autre catégorie Et le signalement est enregistré sans toucher l'écran
13. Actions vocales disponibles avec CarPlay/Android Auto
Étant donné que je conduis avec CarPlay activé
Quand je dis "Hey Siri, like ce podcast"
Alors un like explicite (+2%) est enregistré Et Siri confirme "J'ai ajouté ce contenu à vos favoris"
Quand je dis "OK Google, abonne-moi à ce créateur"
Alors l'abonnement est enregistré (+5% toutes jauges) Et Google Assistant confirme "Vous êtes maintenant abonné"
14. Menu contextuel accessible à l'arrêt uniquement
Étant donné que le véhicule est à l'arrêt
Quand je clique sur le menu "⋮" (3 points verticaux)
Alors les options disponibles sont:
| Option |
|---|
| Like (cœur) |
| S'abonner au créateur |
| Signaler |
| Partager |
| Voir le profil du créateur |
| Télécharger (mode offline) |
Et toutes les options sont cliquables
15. Menu contextuel limité en conduite
Étant donné que je conduis à 30 km/h
Quand j'essaie d'ouvrir le menu "⋮"
Alors seules 2 options sont disponibles:
| Option |
|---|
| Signaler (vocal possible) |
| Suivant |
Et les actions complexes sont désactivées
16. Persistance des likes manuels en base de données
Étant donné que je like manuellement 5 contenus
Quand je ferme l'application Et que je me reconnecte plus tard
Alors tous mes likes manuels sont toujours présents Et les cœurs rouges sont affichés sur les contenus likés Et mes jauges reflètent toujours l'impact (+2% × 5 likes)
17. Liste "Mes contenus likés" accessible dans profil
Étant donné que j'ai liké manuellement 10 contenus
Quand j'accède à mon profil utilisateur
Alors je vois une section "❤️ Mes favoris" Et la liste affiche les 10 contenus likés Et je peux cliquer pour réécouter Et je peux retirer un like (unlike) depuis cette liste
18. Liste "Mes abonnements" accessible dans profil
Étant donné que je suis abonné à 5 créateurs
Quand j'accède à mon profil utilisateur
Alors je vois une section "⭐ Mes abonnements" Et la liste affiche les 5 créateurs avec leurs avatars Et je peux accéder au profil de chaque créateur Et je peux me désabonner depuis cette liste
19. Impact abonnement sur tous les tags du créateur
Étant donné qu'un créateur a publié des contenus avec ces tags:
| Contenu | Tags |
|---|---|
| C1 | Automobile, Voyage |
| C2 | Automobile, Technologie |
| C3 | Voyage, Famille |
Et que mes jauges sont toutes à 50%
Quand je m'abonne à ce créateur
Alors les jauges impactées sont:
| Tag | Impact |
|---|---|
| Automobile | +5% |
| Voyage | +5% |
| Technologie | +5% |
| Famille | +5% |
Et toutes les autres jauges restent à 50%
20. Limite d'abonnements (200 maximum)
Étant donné que je suis abonné à 200 créateurs
Quand j'essaie de m'abonner à un 201ème créateur
Alors un message "Limite de 200 abonnements atteinte" s'affiche Et je dois me désabonner d'un créateur existant pour en ajouter un nouveau
21. Confirmation avant désabonnement
Étant donné que je suis abonné à un créateur
Quand je clique sur "Se désabonner"
Alors une popup de confirmation s'affiche: Et je dois confirmer pour valider Et je peux annuler pour conserver l'abonnement
22. 📋 Plan: Cumul like automatique + like manuel
Étant donné qu'un contenu est tagué "Sport" Et que ma jauge "Sport" est à 50%
Quand j'écoute à % (like auto ) Et que je like manuellement (+2%)
Alors l'impact total est Et ma nouvelle jauge est <nouveau_niveau>
📊 Exemples de données:
| pourcentage | auto | total | nouveau_niveau |
|---|---|---|---|
| 10 | 0 | +2% | 52% |
| 30 | +1% | +3% | 53% |
| 50 | +1% | +3% | 53% |
| 80 | +2% | +4% | 54% |
| 95 | +2% | +4% | 54% |
23. 📋 Plan: Actions disponibles selon vitesse GPS
Étant donné que je roule à km/h
Quand j'essaie d'accéder à
Alors l'action est
📊 Exemples de données:
| vitesse | action | disponibilite |
|---|---|---|
| 0 | Like manuel | disponible |
| 0 | Abonnement | disponible |
| 0 | Signalement | disponible |
| 5 | Like manuel | disponible |
| 5 | Abonnement | disponible |
| 10 | Like manuel | désactivée |
| 10 | Abonnement | désactivée |
| 50 | Like manuel | désactivée |
| 50 | Abonnement | désactivée |
| 50 | Signalement vocal | disponible |
Commande "Précédent"
En tant qu'auditeur Je veux que le bouton "Précédent" ait un comportement intelligent Afin de rejouer le contenu actuel ou revenir au précédent selon la progression
19 scénarios (17 standards, 2 plans)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un utilisateur est connecté
1. Précédent après <10s revient au contenu précédent
Étant donné que j'ai écouté le contenu "A" pendant 2 minutes Et que j'écoute maintenant le contenu "B" depuis 5 secondes
Quand j'appuie sur "Précédent"
Alors la lecture revient au contenu "A" Et la position de lecture est à 2 minutes (position exacte sauvegardée) Et le contenu "B" reste en historique
2. Précédent après ≥10s rejoue le contenu actuel
Étant donné que j'écoute le contenu "C" depuis 15 secondes
Quand j'appuie sur "Précédent"
Alors le contenu "C" rejoue depuis le début (position 0:00) Et la lecture ne revient pas au contenu précédent Et la progress bar revient à 0%
3. Précédent exactement à 10s rejoue le contenu actuel
Étant donné que j'écoute le contenu "D" depuis exactement 10 secondes
Quand j'appuie sur "Précédent"
Alors le contenu "D" rejoue depuis le début Et la lecture ne revient pas au contenu précédent
4. Précédent sur le premier contenu de session
Étant donné que je viens de démarrer l'application Et que j'écoute le contenu "Premier" depuis 3 secondes
Quand j'appuie sur "Précédent"
Alors le contenu "Premier" rejoue depuis le début Et aucun contenu précédent n'existe
5. Historique de navigation limité à 10 contenus
Étant donné que j'ai écouté 10 contenus [C1, C2, ..., C10] Et que l'historique Redis contient 10 entrées
Quand je passe au contenu C11
Alors le contenu C1 est supprimé de l'historique (FIFO) Et l'historique contient [C2, C3, ..., C10, C11] Et la taille reste à 10 contenus maximum
6. Position exacte sauvegardée dans l'historique
Étant donné que j'écoute le contenu "A" (durée 5 minutes)
Quand j'atteins 2 minutes 30 secondes Et que j'appuie sur "Suivant"
Alors l'historique enregistre:
| content_id | position_seconds | listened_at |
|---|---|---|
| A | 150 | 2026-01-21T10:30:00 |
Quand je reviens au contenu "A" via "Précédent"
Alors la lecture reprend exactement à 2 minutes 30 secondes
7. Navigation arrière sur plusieurs contenus
Étant donné que j'ai écouté dans l'ordre: A (2min), B (30s), C (3min) Et que j'écoute maintenant D depuis 1 seconde
Quand j'appuie sur "Précédent" (1ère fois)
Alors je reviens au contenu C à la position 3 minutes
Quand j'appuie sur "Précédent" (<10s sur C)
Alors je reviens au contenu B à la position 30 secondes
Quand j'appuie sur "Précédent" (<10s sur B)
Alors je reviens au contenu A à la position 2 minutes
8. Précédent après milieu du contenu rejoue depuis début
Étant donné que j'écoute un contenu de 5 minutes
Quand j'atteins 2 minutes 30 secondes (milieu) Et que j'appuie sur "Précédent"
Alors le contenu actuel rejoue depuis 0:00 Et je ne reviens pas au contenu précédent
9. Enchaînement Suivant puis Précédent rapide
Étant donné que j'écoute le contenu "A" depuis 1 minute
Quand j'appuie sur "Suivant"
Alors le contenu "B" démarre
Quand j'appuie immédiatement sur "Précédent" (2s après)
Alors je reviens au contenu "A" à la position 1 minute Et le contenu "B" reste dans l'historique
10. Transition fluide avec animation 0.3s
Étant donné que j'appuie sur "Précédent"
Quand le changement de contenu se produit
Alors la transition audio utilise un fade out/in de 0.3 secondes Et la progress bar revient avec une animation fluide Et l'interface ne montre aucun message de confirmation
11. Historique survit au changement de réseau
Étant donné que j'ai un historique de 5 contenus en cache Redis
Quand je perds la connexion réseau temporairement Et que je reviens en ligne
Alors l'historique de navigation est toujours disponible Et je peux toujours utiliser "Précédent"
12. Historique stocké en Redis avec structure complète
Étant donné que j'ai écouté 3 contenus
Quand je consulte le cache Redis
Alors la structure est: Et l'ordre est du plus récent au plus ancien
13. Précédent sur contenu en cours au début (<10s) du premier
Étant donné que je démarre une session avec le contenu "Initial" Et que j'écoute depuis 3 secondes
Quand j'appuie sur "Précédent"
Alors le contenu "Initial" rejoue depuis le début Et aucune erreur n'est générée Et l'historique reste vide
14. Compteur de temps respecte les seuils exacts
Étant donné que j'écoute un contenu
Quand le temps écoulé est de 9.9 secondes Et que j'appuie sur "Précédent"
Alors je reviens au contenu précédent
Quand le temps écoulé est de 10.0 secondes Et que j'appuie sur "Précédent"
Alors le contenu actuel rejoue depuis le début
15. Progress bar visuelle reflète le retour exact
Étant donné que j'ai écouté le contenu "A" jusqu'à 75% (3min45 sur 5min) Et que je suis passé au contenu "B"
Quand je reviens au contenu "A" via "Précédent"
Alors la progress bar affiche 75% Et l'indicateur de temps affiche "3:45 / 5:00" Et la lecture reprend exactement à cet endroit
16. Métadonnées d'historique incluent timestamp précis
Étant donné que j'écoute un contenu "X" pendant 45 secondes à 10:30:15
Quand je passe au contenu suivant
Alors l'historique enregistre:
| content_id | position_seconds | listened_at |
|---|---|---|
| X | 45 | 2026-01-21T10:30:15Z |
Et le timestamp précis permet l'analyse d'usage
17. Suppression FIFO respecte l'ordre chronologique
Étant donné un historique de [C1@10:00, C2@10:02, ..., C10@10:20]
Quand j'ajoute C11 à 10:22
Alors C1 (le plus ancien) est supprimé Et l'historique contient [C2@10:02, ..., C11@10:22] Et la taille reste exactement 10 entrées
18. 📋 Plan: Comportement selon temps écouté
Étant donné que j'écoute un contenu depuis secondes
Quand j'appuie sur "Précédent"
Alors l'action est
📊 Exemples de données:
| temps | comportement |
|---|---|
| 1 | revenir au contenu précédent |
| 5 | revenir au contenu précédent |
| 9 | revenir au contenu précédent |
| 10 | rejouer le contenu actuel depuis 0:00 |
| 11 | rejouer le contenu actuel depuis 0:00 |
| 30 | rejouer le contenu actuel depuis 0:00 |
| 180 | rejouer le contenu actuel depuis 0:00 |
19. 📋 Plan: Positions de reprise exactes
Étant donné que j'écoute un contenu de 10 minutes
Quand j'atteins et passe au suivant Et que je reviens via "Précédent"
Alors la lecture reprend exactement à
📊 Exemples de données:
| position |
|---|
| 0:15 |
| 1:30 |
| 3:45 |
| 5:00 |
| 7:23 |
| 9:50 |
Commandes vocales CarPlay et Android Auto
En tant que conducteur avec CarPlay ou Android Auto Je veux utiliser des commandes vocales pour interagir avec l'application Afin de garder les mains sur le volant et les yeux sur la route
25 scénarios (23 standards, 2 plans)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un utilisateur est connecté Et que CarPlay ou Android Auto est activé
1. Disponibilité des commandes vocales uniquement avec CarPlay/Android Auto
Étant donné que je conduis avec CarPlay activé
Quand je dis "Hey Siri"
Alors Siri est disponible pour les commandes RoadWave
Étant donné que je conduis avec Android Auto activé
Quand je dis "OK Google"
Alors Google Assistant est disponible pour les commandes RoadWave
2. Parc automobile compatible avec vocal (30-40% en 2026)
Étant donné que nous sommes en 2026
Quand je consulte les statistiques du parc automobile EU
Alors environ 30-40% des véhicules ont CarPlay ou Android Auto Et ces utilisateurs peuvent utiliser les commandes vocales Et les 60-70% restants utilisent les commandes au volant uniquement
3. Commande vocale "Like ce podcast" avec Siri
Étant donné que j'écoute un contenu tagué "Automobile" Et que ma jauge "Automobile" est à 60%
Quand je dis "Hey Siri, like ce podcast"
Alors un like explicite (+2%) est enregistré Et ma jauge "Automobile" passe à 62% Et Siri confirme vocalement "J'ai ajouté ce contenu à vos favoris" Et aucune interaction écran n'est requise
4. Commande vocale "Like ce contenu" avec Google Assistant
Étant donné que j'écoute un contenu tagué "Voyage"
Quand je dis "OK Google, like ce contenu"
Alors un like explicite est enregistré (+2%) Et Google Assistant confirme "J'ai liké ce contenu pour vous" Et la commande fonctionne sans toucher l'écran
5. Commande vocale "Abonne-moi à ce créateur"
Étant donné que j'écoute un contenu d'un créateur tagué "Automobile" et "Technologie" Et que mes jauges sont à 50% et 45%
Quand je dis "Hey Siri, abonne-moi à ce créateur"
Alors l'abonnement est enregistré Et mes jauges augmentent de 5% chacune (55% et 50%) Et Siri confirme "Vous êtes maintenant abonné à [Nom du créateur]"
6. Commande vocale "Passe au contenu suivant"
Étant donné que j'écoute un contenu "A"
Quand je dis "Hey Siri, passe au contenu suivant"
Alors le contenu "B" démarre immédiatement Et la commande a le même effet que le bouton physique "Suivant"
7. Commande vocale "Signale ce contenu"
Étant donné que j'écoute un contenu inapproprié
Quand je dis "OK Google, signale ce contenu"
Alors Google Assistant demande "Quelle catégorie ?" Et je réponds vocalement "Spam" Alors le signalement est enregistré avec la catégorie "Spam" Et Google Assistant confirme "J'ai signalé ce contenu"
8. Commande vocale avec catégorie de signalement
Étant donné que j'écoute un contenu
Quand je dis "Hey Siri, signale ce contenu pour haine"
Alors le signalement est enregistré avec la catégorie "Haine et violence" Et Siri confirme "J'ai signalé ce contenu pour haine et violence" Et le flux de modération reçoit le signalement
9. Liste des catégories de signalement vocales supportées
Étant donné que je dis "signale ce contenu pour [catégorie]"
Quand la catégorie est:
| Mot-clé vocal | Catégorie mappée |
|---|---|
| "haine" | Haine et violence |
| "sexuel" | Contenu sexuel |
| "illégalité" | Illégalité |
| "droits d'auteur" | Droits d'auteur |
| "spam" | Spam |
| "fake news" | Désinformation |
| "autre" | Autre |
Alors le signalement est enregistré avec la bonne catégorie
10. Commande vocale non reconnue - fallback
Étant donné que je dis "Hey Siri, super ce podcast"
Quand Siri ne reconnaît pas l'intent RoadWave
Alors Siri répond "Je ne comprends pas cette commande RoadWave" Et elle suggère "Dites 'like ce podcast' ou 'passe au suivant'"
11. Commandes vocales disponibles en conduite uniquement
Étant donné que je roule à 50 km/h
Quand j'utilise les commandes vocales
Alors toutes les commandes sont disponibles:
| Commande | Action |
|---|---|
| "Like ce podcast" | Like explicite +2% |
| "Abonne-moi à ce créateur" | Abonnement +5% |
| "Passe au suivant" | Contenu suivant |
| "Reviens au précédent" | Contenu précédent (règle 10s) |
| "Pause" | Pause lecture |
| "Reprends la lecture" | Play |
| "Signale ce contenu" | Signalement |
12. Intent iOS personnalisé pour RoadWave
Étant donné que l'app iOS implémente les Intents
Quand je configure les Shortcuts iOS
Alors les intents suivants sont disponibles:
| Intent Name | Action |
|---|---|
| LikeCurrentContentIntent | Like explicite |
| SubscribeToCreatorIntent | Abonnement |
| ReportContentIntent | Signalement |
| SkipToNextContentIntent | Suivant |
Et Siri les reconnaît automatiquement
13. Intent Android personnalisé pour RoadWave
Étant donné que l'app Android implémente les Voice Actions
Quand je configure les actions Google Assistant
Alors les actions suivantes sont disponibles:
| Action Name | Action |
|---|---|
| com.roadwave.LIKE_CONTENT | Like explicite |
| com.roadwave.SUBSCRIBE_CREATOR | Abonnement |
| com.roadwave.REPORT_CONTENT | Signalement |
| com.roadwave.SKIP_NEXT | Suivant |
Et Google Assistant les reconnaît
14. Confirmation vocale après action réussie
Étant donné que je dis "Hey Siri, like ce podcast"
Quand l'action est enregistrée avec succès
Alors Siri répond immédiatement avec confirmation: Et la réponse est naturelle et concise Et elle ne distrait pas de la conduite
15. Gestion d'erreur vocale si action échoue
Étant donné que je dis "Hey Siri, abonne-moi à ce créateur" Et que j'ai atteint la limite de 200 abonnements
Quand Siri essaie d'enregistrer l'abonnement
Alors l'action échoue Et Siri répond "Impossible de s'abonner, limite de 200 abonnements atteinte" Et elle suggère "Désabonnez-vous d'un créateur pour continuer"
16. Commandes vocales multilingues (français)
Étant donné que mon Siri est configuré en français
Quand je dis "Hey Siri, j'aime ce podcast"
Alors la commande est reconnue (variante de "like ce podcast")
Quand je dis "Hey Siri, mets une étoile"
Alors la commande est reconnue (variante de "like")
17. Implémentation post-MVP (Sprint 5)
Étant donné que les commandes vocales sont une feature Sprint 5
Quand le MVP est lancé
Alors seules les commandes au volant physiques sont disponibles
Quand le Sprint 5 est déployé
Alors les intents iOS/Android sont activés Et les commandes vocales deviennent disponibles
18. Priorisation commandes vocales vs boutons physiques
Étant donné que je conduis avec CarPlay Et que j'ai accès aux boutons physiques ET aux commandes vocales
Quand je veux liker un contenu
Alors je peux soit: Et les 3 méthodes sont valides
19. Statistiques d'usage des commandes vocales
Étant donné que 100 utilisateurs avec CarPlay utilisent RoadWave
Quand je consulte les analytics
Alors je peux voir:
| Métrique | Exemple valeur |
|---|---|
| Taux d'utilisation commandes vocal | 15% |
| Commande la plus utilisée | "Like" |
| Taux de reconnaissance réussie | 92% |
| Taux d'échec / incompréhension | 8% |
20. Feedback haptique désactivé pour commandes vocales
Étant donné que je like un contenu via commande vocale
Quand l'action est enregistrée
Alors aucune vibration haptique n'est déclenchée Et seule la confirmation vocale est donnée
21. Badge visuel mis à jour après commande vocale
Étant donné que je dis "Hey Siri, like ce podcast"
Quand l'action est enregistrée
Alors le badge "♥ Ajouté à vos favoris" s'affiche sur l'écran CarPlay Et le cœur devient rouge plein dans l'interface Et la mise à jour est visible même sans toucher l'écran
22. Commandes vocales avec contenu sans créateur
Étant donné que j'écoute un contenu anonyme (créateur supprimé)
Quand je dis "Hey Siri, abonne-moi à ce créateur"
Alors Siri répond "Ce créateur n'est plus disponible" Et aucun abonnement n'est enregistré
23. Limitation temporelle des commandes vocales
Étant donné que je dis "Hey Siri, like ce podcast" Et que le contenu change 1 seconde après
Quand Siri traite la commande 2 secondes plus tard
Alors la commande s'applique au contenu qui était en lecture au moment de la commande Et non au contenu actuel (système de timestamp)
24. 📋 Plan: Commandes vocales avec différents assistants
Étant donné que j'utilise
Quand je dis
Alors l'action est exécutée Et la confirmation est
📊 Exemples de données:
| assistant | commande | action | confirmation |
|---|---|---|---|
| Siri | "Like ce podcast" | Like +2% | "Ajouté à vos favoris" |
| Google Assistant | "Like ce contenu" | Like +2% | "J'ai liké ce contenu" |
| Siri | "Abonne-moi à ce créateur" | Abonnement +5% | "Vous êtes abonné" |
| Google Assistant | "Abonne-moi à ce créateur" | Abonnement +5% | "Abonnement enregistré" |
| Siri | "Signale ce contenu" | Signalement | "J'ai signalé ce contenu" |
| Google Assistant | "Signale ce contenu" | Signalement | "Contenu signalé" |
25. 📋 Plan: Mapping catégories signalement vocal
Étant donné que je dis "signale ce contenu pour <mot_cle>"
Quand <mot_cle> est reconnu
Alors la catégorie mappée est
📊 Exemples de données:
| mot_cle | categorie |
|---|---|
| haine | Haine et violence |
| violence | Haine et violence |
| sexuel | Contenu sexuel |
| porno | Contenu sexuel |
| illégal | Illégalité |
| terrorisme | Illégalité |
| copyright | Droits d'auteur |
| droits auteur | Droits d'auteur |
| spam | Spam |
| fake news | Désinformation |
| fausse info | Désinformation |
Commandes au volant et interactions simplifiées
En tant que conducteur en sécurité Je veux utiliser uniquement les commandes simplifiées au volant Afin de naviguer sans distraction et en toute sécurité
21 scénarios (19 standards, 2 plans)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un utilisateur est connecté Et que l'application est connectée via CarPlay ou Android Auto
1. Trois commandes disponibles au volant uniquement
Étant donné que je conduis à 50 km/h
Quand je consulte les commandes physiques disponibles
Alors seules 3 actions sont disponibles:
| Commande | Action |
|---|---|
| Suivant | Passer au contenu suivant |
| Précédent | Revenir au précédent (règle 10s) |
| Play/Pause | Pause/reprise avec fade 0.3s |
Et aucune commande complexe n'est proposée
2. Commande "Suivant" au volant
Étant donné que j'écoute un contenu "A"
Quand j'appuie sur le bouton physique "Suivant" au volant
Alors le contenu "B" démarre immédiatement Et aucune action supplémentaire n'est requise Et l'interface ne demande aucune confirmation
3. Commande "Précédent" au volant respecte règle 10s
Étant donné que j'écoute un contenu depuis 5 secondes
Quand j'appuie sur "Précédent" au volant
Alors je reviens au contenu précédent (règle <10s)
Étant donné que j'écoute un contenu depuis 15 secondes
Quand j'appuie sur "Précédent" au volant
Alors le contenu actuel rejoue depuis le début (règle ≥10s)
4. Commande "Play/Pause" avec fade audio
Étant donné qu'un contenu est en lecture
Quand j'appuie sur "Pause" au volant
Alors la lecture se met en pause avec un fade out de 0.3 secondes Et la position de lecture est sauvegardée
Quand j'appuie sur "Play" au volant
Alors la lecture reprend avec un fade in de 0.3 secondes Et la reprise se fait à la position exacte
5. Aucune commande complexe supportée
Étant donné que je conduis
Quand j'essaie un appui long sur "Suivant"
Alors l'action n'est pas détectée (non supporté iOS/Android)
Quand j'essaie un double-appui sur "Pause"
Alors l'action n'est pas détectée Et seules les actions simples (clic simple) fonctionnent
6. Compatibilité 100% tous véhicules
Étant donné que je conduis une voiture avec commandes basiques Et que mon véhicule a seulement Suivant/Précédent/Pause
Quand j'utilise RoadWave
Alors toutes les fonctions essentielles sont accessibles Et je n'ai pas besoin de boutons supplémentaires
7. Feedback visuel discret après action
Étant donné que j'appuie sur "Suivant"
Quand le contenu change
Alors l'interface CarPlay/Android Auto affiche le nouveau titre Et aucune popup ne bloque la vue Et le changement est fluide et immédiat
8. Like automatique renforcé après écoute ≥80%
Étant donné que j'écoute un contenu de 5 minutes tagué "Automobile"
Quand j'écoute pendant 4 minutes 30 secondes (90%)
Alors un like automatique renforcé (+2 points) est enregistré Et un badge discret "♥ Ajouté à vos favoris" s'affiche 2 secondes Et aucune action manuelle n'est requise
9. Like automatique standard après écoute 30-79%
Étant donné que j'écoute un contenu de 5 minutes tagué "Voyage"
Quand j'écoute pendant 2 minutes (40%) Et que j'appuie sur "Suivant"
Alors un like automatique standard (+1 point) est enregistré Et un badge discret s'affiche brièvement Et je peux continuer à conduire sans interruption
10. Signal négatif après skip rapide <10s
Étant donné que j'écoute un contenu tagué "Politique"
Quand j'appuie sur "Suivant" après seulement 5 secondes
Alors un signal négatif (-0.5 point) est enregistré Et la jauge "Politique" diminue légèrement Et aucun message n'est affiché (transparence)
11. Pas de like si écoute <30%
Étant donné que j'écoute un contenu de 10 minutes
Quand j'écoute pendant 2 minutes (20%) Et que j'appuie sur "Suivant"
Alors aucun like n'est enregistré Et les jauges ne changent pas Et le système considère l'écoute comme neutre
12. Badge de feedback visuel disparaît après 2 secondes
Étant donné que je reçois un like automatique
Quand le badge "♥ Ajouté à vos favoris" apparaît
Alors il reste visible 2 secondes en bas de l'écran Et il disparaît automatiquement sans action Et il ne bloque pas la vue de la route
13. Tracking du temps d'écoute précis côté client
Étant donné que je démarre la lecture d'un contenu
Quand le player audio iOS/Android enregistre le temps
Alors le startTime est enregistré à la milliseconde
Quand j'arrête la lecture (Suivant, Pause, ou fin)
Alors la durée exacte écoutée est calculée Et le pourcentage (durée / durée_totale * 100) est envoyé à l'API
14. API reçoit les événements d'écoute pour calcul
Étant donné que j'écoute un contenu de 5 minutes à 80%
Quand l'événement est envoyé à l'API
Alors le backend reçoit: Et le backend calcule le like automatique (+2 points) Et les jauges sont mises à jour immédiatement (Redis + PostgreSQL)
15. Actions différentes selon arrêt du contenu
Étant donné que j'écoute un contenu
Quand j'appuie sur "Suivant"
Alors l'action envoyée est "skipped"
Quand le contenu se termine naturellement
Alors l'action envoyée est "completed"
Quand j'appuie sur "Pause"
Alors l'action envoyée est "paused" Et le backend traite chaque action différemment
16. Calcul immédiat côté backend sans délai
Étant donné que l'API reçoit un événement d'écoute
Quand le backend traite l'événement
Alors les jauges sont mises à jour immédiatement (< 100ms) Et les nouvelles recommandations utilisent les valeurs actualisées Et il n'y a aucun batch différé
17. Compatibilité iOS avec AVPlayer
Étant donné que l'app iOS utilise AVPlayer
Quand les commandes physiques sont interceptées
Alors les événements MPRemoteCommandCenter sont capturés:
| Commande | Événement iOS |
|---|---|
| Suivant | nextTrackCommand |
| Précédent | previousTrackCommand |
| Play/Pause | playCommand / pauseCommand |
Et le tracking du temps utilise CMTime
18. Compatibilité Android avec MediaSession
Étant donné que l'app Android utilise MediaPlayer
Quand les commandes physiques sont interceptées
Alors les événements MediaSession sont capturés:
| Commande | Action Android |
|---|---|
| Suivant | ACTION_SKIP_TO_NEXT |
| Précédent | ACTION_SKIP_TO_PREVIOUS |
| Play/Pause | ACTION_PLAY / ACTION_PAUSE |
Et le tracking du temps utilise SystemClock.elapsedRealtime()
19. Sécurité maximale - pas de distraction
Étant donné que je conduis à 80 km/h
Quand j'utilise RoadWave avec les commandes au volant
Alors je n'ai jamais besoin de regarder mon téléphone Et je n'ai jamais besoin de toucher l'écran CarPlay/Android Auto Et toutes les actions sont accessibles via boutons physiques Et les likes sont enregistrés automatiquement
20. 📋 Plan: Calcul du like automatique selon pourcentage
Étant donné que j'écoute un contenu tagué "Sport"
Quand j'écoute pendant %
Alors le like automatique est Et l'impact sur la jauge est
📊 Exemples de données:
| pourcentage | type | points |
|---|---|---|
| 10 | aucun | 0 |
| 25 | aucun | 0 |
| 29 | aucun | 0 |
| 30 | standard | +1 |
| 50 | standard | +1 |
| 79 | standard | +1 |
| 80 | renforcé | +2 |
| 90 | renforcé | +2 |
| 100 | renforcé | +2 |
21. 📋 Plan: Signal négatif uniquement si skip très rapide
Étant donné que j'écoute un contenu
Quand je skip après secondes
Alors le signal est Et l'impact est
📊 Exemples de données:
| secondes | type | points |
|---|---|---|
| 3 | négatif | -0.5 |
| 5 | négatif | -0.5 |
| 9 | négatif | -0.5 |
| 10 | neutre | 0 |
| 15 | neutre | 0 |
| 30 | neutre | 0 |
File d'attente et commande "Suivant"
En tant qu'auditeur en déplacement Je veux que l'application pré-calcule intelligemment les prochains contenus Afin d'avoir une navigation fluide sans latence
20 scénarios (19 standards, 1 plan)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un utilisateur est connecté Et que la géolocalisation est activée
1. Pré-calcul initial de 5 contenus en cache
Étant donné que je viens de démarrer l'application Et que je suis situé à Paris (48.8566, 2.3522) Et que je suis en mode voiture (vitesse ≥ 5 km/h)
Quand l'application initialise la lecture
Alors une file d'attente de 5 contenus est pré-calculée Et la file est stockée en cache Redis avec la clé "user:{user_id}:queue" Et les métadonnées incluent ma position, le timestamp de calcul et le mode Et le cache a un TTL de 15 minutes
2. Commande "Suivant" sans latence
Étant donné qu'une file d'attente de 5 contenus est en cache Et que j'écoute actuellement le contenu "A"
Quand j'appuie sur le bouton "Suivant"
Alors le contenu suivant démarre immédiatement (< 100ms) Et le contenu est retiré de la file d'attente Et il reste 4 contenus dans la file
3. Recalcul automatique après déplacement >10km
Étant donné que la file a été calculée à Paris (48.8566, 2.3522) Et que j'ai 5 contenus en cache
Quand je me déplace à Versailles (48.8049, 2.1204) soit 12km
Alors la file d'attente est invalidée automatiquement Et une nouvelle file de 5 contenus est recalculée Et elle est basée sur ma nouvelle position
4. Recalcul automatique toutes les 10 minutes
Étant donné qu'une file a été calculée il y a 10 minutes Et que ma position n'a pas changé
Quand le timer de rafraîchissement expire
Alors une nouvelle file de 5 contenus est recalculée Et les anciens contenus non écoutés sont remplacés Et les nouveaux contenus publiés depuis sont inclus
5. Recalcul quand il reste moins de 3 contenus
Étant donné qu'il reste 3 contenus dans ma file d'attente
Quand j'appuie sur "Suivant"
Alors il reste 2 contenus Et un recalcul asynchrone est déclenché en arrière-plan Et 3 nouveaux contenus sont ajoutés à la file Et la file contient maintenant 5 contenus
6. Insertion prioritaire d'un contenu géolocalisé en mode voiture
Étant donné que j'ai une file de 5 contenus pré-calculée Et que je suis en mode voiture Et que je me déplace à 50 km/h vers un point avec contenu géolocalisé
Quand je suis à 98m du point (ETA = 7 secondes)
Alors une notification est envoyée (icône + compteur 7→1 + son) Et je dois appuyer sur "Suivant" dans les 7 secondes pour valider
Quand j'appuie sur "Suivant"
Alors un décompte de 5 secondes démarre Et après 5 secondes, le contenu géolocalisé s'insère et démarre Et il remplace le contenu actuel dans la lecture
7. Contenu géolocalisé ignoré est perdu (cooldown activé)
Étant donné qu'une notification géolocalisée est affichée (compteur 7→1)
Quand je ne clique pas sur "Suivant" pendant les 7 secondes
Alors la notification disparaît Et le contenu géolocalisé est perdu (pas d'insertion dans la file) Et un cooldown de 10 minutes est activé Et aucune nouvelle notification géolocalisée ne sera envoyée pendant 10 minutes
8. Validation d'une notification géolocalisée
Étant donné qu'une notification géolocalisée est affichée (compteur à 5) Et que j'écoute un podcast
Quand j'appuie sur "Suivant"
Alors le compteur bascule à "5" (décompte final) Et le podcast actuel continue de jouer Et après 5 secondes, le contenu géolocalisé démarre Et le podcast est mis en pause et sauvegardé dans l'historique
9. Invalidation immédiate après modification des préférences
Étant donné que j'ai une file de 5 contenus en cache Et que ma vitesse GPS est de 5 km/h (piéton)
Quand je modifie mes curseurs de préférences (géo/découverte/politique)
Alors la file d'attente est invalidée immédiatement Et une nouvelle file est recalculée avec les nouvelles préférences Et les anciens contenus en cache sont supprimés
10. Blocage modification préférences en conduite (>10 km/h)
Étant donné que ma vitesse GPS est de 50 km/h (en voiture)
Quand j'essaie d'accéder aux réglages de préférences
Alors l'interface affiche "Paramètres verrouillés en conduite" Et je ne peux pas modifier les curseurs géo/découverte/politique Et un message "Arrêtez-vous pour modifier vos préférences" s'affiche
11. Invalidation lors du démarrage d'un live suivi
Étant donné que je suis abonné au créateur "RadioVoyage" Et que j'ai une file de 5 contenus en cache Et que je suis dans la zone géographique du créateur
Quand le créateur "RadioVoyage" démarre une radio live
Alors je reçois une notification push Et le contenu live s'insère en tête de la file d'attente Et la file d'attente est recalculée
12. Métadonnées de cache Redis
Étant donné qu'une file d'attente est calculée
Quand elle est stockée dans Redis
Alors la clé est "user:{user_id}:queue" Et les métadonnées incluent:
| champ | valeur |
|---|---|
| last_lat | 48.8566 |
| last_lon | 2.3522 |
| computed_at | 2026-01-21T10:30:00Z |
| mode | voiture |
Et le TTL est de 15 minutes (900 secondes)
13. Contenu géolocalisé remplace le contenu actuel (pas d'insertion en file)
Étant donné que j'écoute le contenu C2 de ma file [C1, C2, C3, C4, C5] Et qu'une notification géolocalisée "Tour Eiffel" est déclenchée
Quand je valide la notification Et que le décompte de 5s se termine
Alors le contenu "Tour Eiffel" remplace C2 et démarre Et C2 est sauvegardé dans l'historique de navigation Et la file reste [C3, C4, C5] (pas de contenu retiré) Et quand "Tour Eiffel" se termine, C3 démarre
14. Invalidation après déplacement exactement 10km
Étant donné que la file a été calculée à une position donnée
Quand je me déplace d'exactement 10.0 km
Alors la file d'attente n'est PAS invalidée (seuil strict >10km) Et les contenus en cache restent valides
Quand je me déplace de 10.1 km supplémentaires (total 10.1km)
Alors la file d'attente est invalidée Et une nouvelle file est calculée
15. Rafraîchissement exactement après 10 minutes
Étant donné qu'une file a été calculée à 10:00:00
Quand l'heure actuelle est 10:10:00
Alors le timer de rafraîchissement expire Et une nouvelle file de 5 contenus est recalculée Et le timestamp "computed_at" est mis à jour
16. Recalcul asynchrone non-bloquant
Étant donné qu'il reste 2 contenus dans la file Et que j'appuie sur "Suivant"
Quand le recalcul asynchrone démarre
Alors la lecture du contenu actuel n'est pas interrompue Et le recalcul se fait en arrière-plan Et les nouveaux contenus sont ajoutés dès disponibles (< 500ms) Et l'utilisateur ne perçoit aucune latence
17. Notification basée sur ETA (pas distance fixe)
Étant donné qu'un contenu géolocalisé existe à un point GPS Et que je roule à 130 km/h
Quand je suis à 252m du point (ETA = 7 secondes)
Alors une notification est envoyée
Quand je suis à 300m du point (ETA = 8 secondes)
Alors aucune notification n'est envoyée (ETA >7s)
18. 📋 Plan: Différentes distances de déplacement et invalidation
Étant donné qu'une file a été calculée à une position donnée
Quand je me déplace de km
Alors la file est
📊 Exemples de données:
| distance | action |
|---|---|
| 5 | conservée |
| 9.9 | conservée |
| 10.0 | conservée |
| 10.1 | invalidée et recalculée |
| 15 | invalidée et recalculée |
| 50 | invalidée et recalculée |
19. Quota de 6 contenus géolocalisés par heure
Étant donné que j'ai validé 6 notifications géolocalisées dans la dernière heure
Quand un 7ème contenu géolocalisé est détecté (ETA 7s)
Alors aucune notification n'est envoyée Et le quota horaire est respecté
20. Mode piéton - pas de notification avec compteur 7s
Étant donné que je suis en mode piéton (vitesse <5 km/h) Et qu'un audio-guide géolocalisé existe à 150m
Quand je passe dans le rayon de 200m
Alors une notification push système est envoyée Et aucun compteur 7s n'est affiché Et je peux ouvrir l'app en tapant sur la notification
Lecture en boucle et enchaînement automatique
En tant qu'auditeur Je veux que les contenus s'enchaînent automatiquement avec un délai paramétrable Afin d'avoir une expérience fluide sans interruption
27 scénarios (24 standards, 3 plans)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un utilisateur est connecté
1. Passage automatique après 2 secondes (mode standard)
Étant donné que j'écoute un contenu "A" en mode standard
Quand la lecture se termine naturellement
Alors un timer de 2 secondes démarre Et un overlay s'affiche: "Contenu suivant dans 2s..." Et une barre de décompte visuelle s'affiche
Quand le timer atteint 0
Alors le contenu "B" démarre automatiquement Et l'overlay disparaît
2. Passage automatique après 1 seconde (mode Kids)
Étant donné que je suis en mode Kids Et que j'écoute un contenu pour enfants
Quand la lecture se termine
Alors un timer de 1 seconde démarre Et le message "Contenu suivant dans 1s..." s'affiche
Quand le timer expire
Alors le contenu suivant démarre automatiquement
3. Passage immédiat après une radio live (0 seconde)
Étant donné que j'écoute une radio live
Quand le créateur arrête la diffusion
Alors le passage au contenu suivant est immédiat (0s de délai) Et aucun overlay de décompte n'est affiché Et la transition est fluide
4. Annulation du passage automatique
Étant donné qu'un contenu se termine Et que le timer de 2 secondes démarre
Quand je clique sur "Rester sur ce contenu" pendant le décompte
Alors le timer est annulé Et le contenu actuel reste en pause à la fin Et le contenu suivant n'est pas lancé
5. Insertion de publicité pendant le délai de transition
Étant donné que j'ai écouté 4 contenus sans publicité Et que le 5ème contenu se termine
Quand le délai de 2 secondes démarre
Alors une publicité s'insère dans la file d'attente Et le message devient "Publicité (15s)" Et la publicité démarre après les 2 secondes Et elle ne coupe jamais un contenu en cours
6. Fréquence de publicité paramétrable admin
Étant donné que la fréquence pub est configurée à "1/5 contenus"
Quand j'écoute 10 contenus
Alors 2 publicités sont insérées (après les contenus 5 et 10)
Étant donné que l'admin change la fréquence à "1/3 contenus"
Quand j'écoute 9 contenus
Alors 3 publicités sont insérées (après les contenus 3, 6 et 9)
7. Publicité skippable après 5 secondes par défaut
Étant donné qu'une publicité de 30 secondes démarre Et que le délai minimal de visionnage est configuré à 5 secondes
Quand j'écoute pendant 3 secondes
Alors le bouton "Passer" n'est pas encore visible
Quand j'atteins 5 secondes d'écoute
Alors le bouton "Passer" apparaît Et je peux cliquer pour passer au contenu suivant
8. Délai minimal de publicité paramétrable admin
Étant donné qu'une publicité démarre Et que l'admin a configuré le délai à 10 secondes
Quand j'écoute pendant 9 secondes
Alors le bouton "Passer" n'est pas visible
Quand j'atteins 10 secondes
Alors le bouton "Passer" apparaît Et je peux skipper la publicité
9. Like et abonnement autorisés sur une publicité
Étant donné qu'une publicité est en lecture
Quand je clique sur le bouton cœur (véhicule arrêté)
Alors la publicité reçoit un like (+2% jauges tags pub)
Quand je clique sur "S'abonner" au créateur de la pub
Alors je suis abonné (+5% jauges tags créateur) Et le créateur de pub bénéficie de l'engagement
10. Métriques d'engagement publicité trackées
Étant donné qu'une publicité de 30s est diffusée à 100 auditeurs
Quand 40 auditeurs écoutent entièrement (30s) Et que 50 auditeurs skippent après 10s Et que 10 auditeurs skippent avant 5s
Alors les métriques sont:
| Métrique | Valeur |
|---|---|
| Taux d'écoute complète | 40% |
| Taux de skip après seuil | 50% |
| Taux de skip immédiat | 10% |
| Durée moyenne d'écoute | 18s |
11. Message "Aucun contenu disponible" si file vide
Étant donné que la file d'attente est vide Et qu'aucun contenu n'est disponible dans ma zone
Quand le contenu actuel se termine
Alors un message s'affiche: "Aucun contenu disponible dans cette zone" Et une proposition apparaît: "Élargir la zone de recherche ?" Et un bouton "Élargir" est disponible Et la lecture se met en pause automatiquement
12. Élargissement automatique de la zone de recherche
Étant donné que le message "Aucun contenu disponible" s'affiche
Quand je clique sur "Élargir la zone"
Alors l'algorithme relance une recherche avec rayon +50km Et une notification "Recherche élargie à 50km" s'affiche Et la file d'attente est recalculée Et la lecture reprend automatiquement
13. Refus d'élargissement laisse en pause
Étant donné que le message "Aucun contenu disponible" s'affiche
Quand je clique sur "Annuler"
Alors la lecture reste en pause Et l'interface affiche "En attente de contenu" Et je peux manuellement naviguer ou chercher du contenu
14. Retry avec backoff exponentiel en cas d'échec réseau
Étant donné que le contenu suivant échoue au chargement
Quand la première tentative échoue
Alors le système retente après 1 seconde (backoff 1s)
Quand la 2ème tentative échoue
Alors le système retente après 2 secondes (backoff 2s)
Quand la 3ème tentative échoue
Alors le système retente après 4 secondes (backoff 4s) Et après 3 échecs totaux, le système bascule en mode offline
15. Basculement mode offline après 3 échecs réseau
Étant donné que j'ai eu 3 échecs de chargement consécutifs
Quand le 3ème échec se produit
Alors un message "Connexion instable, basculement mode offline" s'affiche Et la lecture continue avec les contenus téléchargés uniquement Et les contenus en ligne sont temporairement désactivés
Quand la connexion revient
Alors le mode en ligne est automatiquement rétabli
16. Overlay de décompte avec barre visuelle
Étant donné qu'un contenu se termine
Quand le timer de 2 secondes démarre
Alors un overlay semi-transparent s'affiche en bas de l'écran Et le texte "Contenu suivant dans 2s..." est visible Et une barre de progression décroît de 100% à 0% en 2 secondes Et la couleur de la barre passe de vert à orange Et l'overlay disparaît automatiquement après le décompte
17. Bouton "Rester sur ce contenu" pendant décompte
Étant donné que le décompte de 2 secondes est actif
Quand l'overlay s'affiche
Alors un bouton "Rester sur ce contenu" est visible Et il est cliquable pendant les 2 secondes
Quand je clique dessus
Alors le timer est annulé immédiatement Et l'overlay disparaît Et le contenu actuel reste affiché en pause
18. Pas d'interruption d'un contenu en cours
Étant donné que j'écoute un contenu de 10 minutes Et que je suis à 5 minutes de lecture
Quand une publicité devrait s'insérer (fréquence 1/5)
Alors la publicité n'interrompt jamais le contenu en cours Et elle attend la fin du contenu actuel Et elle s'insère pendant le délai de transition (2s)
19. Publicités uniquement pour utilisateurs gratuits
Étant donné que je suis un utilisateur gratuit
Quand j'écoute 5 contenus
Alors une publicité est insérée après le 5ème contenu
Étant donné que je passe en compte Premium
Quand j'écoute 100 contenus
Alors aucune publicité n'est insérée Et l'enchaînement est direct (2s de transition seulement)
20. Message clair pour l'utilisateur lors de la publicité
Étant donné qu'une publicité va démarrer
Quand le délai de transition démarre
Alors le message affiché est: "Publicité (15s)" Et la durée totale de la pub est indiquée Et l'utilisateur sait qu'il s'agit d'une pub Et la transparence est maximale
21. Transition fluide entre contenus sans coupure
Étant donné qu'un contenu se termine Et que le suivant est pré-chargé en cache
Quand le timer de 2s expire
Alors la transition audio utilise un crossfade de 0.3s Et il n'y a aucun blanc ou coupure Et l'expérience est fluide
22. Gestion des erreurs de chargement avec retry
Étant donné que le contenu suivant échoue au chargement
Quand la 1ère tentative échoue
Alors une notification "Chargement..." s'affiche Et le système retente automatiquement
Quand la 2ème tentative réussit
Alors la lecture démarre normalement Et aucune action utilisateur n'est requise
23. Mode offline après échecs multiples
Étant donné que j'ai 50 contenus téléchargés en mode offline Et que j'ai eu 3 échecs réseau consécutifs
Quand le mode offline s'active
Alors seuls les contenus téléchargés sont disponibles Et un badge "Mode offline" s'affiche en haut de l'écran Et la lecture continue sans interruption
24. Compteur de contenus avant prochaine publicité
Étant donné que la fréquence pub est 1/5 contenus Et que j'ai écouté 3 contenus depuis la dernière pub
Quand je consulte l'interface
Alors un indicateur discret affiche "2 contenus avant pub" Et l'utilisateur sait quand attendre la prochaine publicité
25. 📋 Plan: Délai de transition selon mode
Étant donné que je suis en mode
Quand un contenu se termine
Alors le délai de transition est secondes Et le message affiché est
📊 Exemples de données:
| mode | delai | message |
|---|---|---|
| Standard | 2 | "Contenu suivant dans 2s..." |
| Kids | 1 | "Contenu suivant dans 1s..." |
| Live | 0 | (aucun message) |
26. 📋 Plan: Fréquence d'insertion des publicités
Étant donné que la fréquence pub est configurée à
Quand j'écoute contenus
Alors publicités sont insérées
📊 Exemples de données:
| frequence | contenus | pubs |
|---|---|---|
| 1/3 | 6 | 2 |
| 1/3 | 9 | 3 |
| 1/5 | 10 | 2 |
| 1/5 | 15 | 3 |
| 1/7 | 14 | 2 |
| 1/7 | 21 | 3 |
27. 📋 Plan: Backoff exponentiel retry
Étant donné que le chargement échoue
Quand je suis à la tentative
Alors le délai de retry est secondes
📊 Exemples de données:
| tentative | delai |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 3 | 4 |
Partage de contenu
En tant qu'utilisateur de RoadWave Je veux pouvoir partager du contenu audio Afin de faire découvrir l'application à d'autres personnes
22 scénarios (20 standards, 2 plans)
Contexte commun à tous les scénarios
Étant donné que l'application RoadWave est démarrée Et que l'utilisateur "jean@example.com" est connecté
1. Bouton partager disponible dans le player en lecture
Étant donné que le contenu "Balade à Paris" est en cours de lecture
Quand l'utilisateur consulte les contrôles du player
Alors le bouton "Partager" ⬆️ est visible
2. Bouton partager disponible sur la page profil créateur
Étant donné que l'utilisateur consulte le profil de "@paris_stories"
Quand l'utilisateur consulte un contenu dans la liste
Alors le bouton "Partager" est disponible pour chaque contenu
3. Bouton partager dans la liste de recherche
Étant donné que l'utilisateur effectue une recherche "voyage paris"
Quand l'utilisateur ouvre le menu contextuel d'un résultat
Alors l'option "Partager" est disponible
4. Bouton partager dans l'historique personnel
Étant donné que l'utilisateur consulte son historique d'écoute
Quand l'utilisateur sélectionne un contenu de l'historique
Alors le bouton "Partager" est accessible
5. 📋 Plan: Menu de partage avec options multiples
Étant donné que le contenu "" est disponible
Quand l'utilisateur clique sur le bouton "Partager"
Alors le menu natif OS s'ouvre Et les options suivantes sont disponibles:
| option |
|---|
| Copier le lien |
| WhatsApp |
| Email |
| SMS |
| Plus... |
📊 Exemples de données:
| contenu |
|---|
| Balade à Paris |
| Secrets de Montmartre |
6. Génération du lien de partage
Étant donné un contenu avec l'ID "content_12345"
Quand l'utilisateur copie le lien de partage
Alors le lien généré est "https://roadwave.fr/share/c/content_12345"
7. Ouverture du lien partagé avec l'application installée (Deep link)
Étant donné que l'application RoadWave est installée sur l'appareil Et qu'un lien "https://roadwave.fr/share/c/content_12345" est partagé
Quand l'utilisateur clique sur le lien
Alors l'application RoadWave s'ouvre automatiquement Et le contenu "content_12345" commence à jouer
8. Ouverture du lien partagé sans l'application installée (Web player)
Étant donné que l'application RoadWave n'est pas installée Et qu'un lien "https://roadwave.fr/share/c/content_12345" est partagé
Quand l'utilisateur clique sur le lien
Alors une page web responsive s'affiche Et le web player HTML5 est visible Et les boutons de téléchargement App Store et Google Play sont affichés
9. Contenu de la page web de partage
Étant donné un contenu public avec les métadonnées suivantes:
| champ | valeur |
|---|---|
| titre | Balade à Paris |
| créateur | @paris_stories |
| durée | 12 min |
| écoutes | 2300 |
| localisation | Paris 5e |
| type_geo | Ancré |
| tags | Voyage, Histoire |
Quand la page de partage est affichée
Alors la page contient:
| élément |
|---|
| Cover image 16:9 |
| Titre "Balade à Paris" |
| "@paris_stories" |
| "12 min · 🎧 2.3K" |
| "📍 Paris 5e · Ancré" |
| "🏷️ #Voyage #Histoire" |
| Description |
| Player HTML5 |
| Bouton App Store |
| Bouton Google Play |
10. Métadonnées Open Graph pour partage social
Étant donné un contenu "Balade à Paris" par "@paris_stories"
Quand la page de partage est générée
Alors les métadonnées Open Graph incluent:
| propriété | valeur |
|---|---|
| og:title | Balade à Paris - RoadWave |
| og:description | Écoutez ce contenu par @paris_stories |
| og:type | music.song |
| og:site_name | RoadWave |
| twitter:card | player |
Et l'aperçu s'affiche correctement sur WhatsApp Et l'aperçu s'affiche correctement sur Facebook Et l'aperçu s'affiche correctement sur Twitter
11. 📋 Plan: Deep linking par plateforme
Étant donné que l'application RoadWave est installée sur Et qu'un lien de partage est ouvert
Quand le système détecte l'application
Alors l'application s'ouvre via <mécanisme>
📊 Exemples de données:
| plateforme | mécanisme |
|---|---|
| iOS | Universal Links |
| Android | App Links |
12. Fallback URL scheme pour deep linking
Étant donné que les App Links ne fonctionnent pas
Quand le système tente d'ouvrir le contenu
Alors l'URL scheme "roadwave://content/content_12345" est utilisé
13. Badge Premium visible sur le lien partagé
Étant donné un contenu Premium "Visite VIP Louvre"
Quand l'utilisateur non-premium clique sur le lien partagé
Alors la page web affiche le badge "👑 Contenu Premium"
14. Preview 30 secondes d'un contenu Premium partagé
Étant donné un contenu Premium "Visite VIP Louvre" de 15 minutes Et qu'un utilisateur non-premium ouvre le lien partagé
Quand le player démarre automatiquement
Alors l'audio joue pendant 30 secondes exactement Et un fade out de 2 secondes est appliqué Et un overlay "Contenu réservé Premium" s'affiche après 32 secondes
15. Contenu de l'overlay paywall Premium
Étant donné qu'un contenu Premium a atteint la limite de 30 secondes
Quand l'overlay paywall s'affiche
Alors le texte suivant est visible:
16. Actions disponibles sur l'overlay Premium
Étant donné que l'overlay paywall Premium est affiché
Quand l'utilisateur consulte les options
Alors les actions suivantes sont disponibles:
| action | comportement |
|---|---|
| Passer Premium | Redirection vers paiement Mangopay web |
| Télécharger l'app | Redirection vers App Store/Google Play |
| Rejouer les 30 premières sec | Relecture illimitée du preview |
17. Relecture illimitée du preview Premium
Étant donné un contenu Premium partagé Et que l'utilisateur a écouté les 30 premières secondes
Quand l'utilisateur clique sur "Rejouer"
Alors les 30 premières secondes sont rejouées Et cette action est possible de manière illimitée
18. Tracking des partages Premium
Étant donné un créateur "@guide_louvre" avec un contenu Premium
Quand son contenu est partagé
Alors les métriques suivantes sont enregistrées:
| métrique | valeur |
|---|---|
| Partages Premium | +1 |
| Ouvertures lien | compteur |
| Conversions Premium | si souscription |
19. Rémunération créateur sur conversion Premium via partage
Étant donné un contenu Premium partagé par "@guide_louvre"
Quand un utilisateur s'abonne via le lien partagé
Alors le créateur reçoit 70% des revenus de cet abonnement Et la conversion est trackée dans son dashboard
20. Partage d'un contenu supprimé
Étant donné qu'un lien de partage "https://roadwave.fr/share/c/deleted_content" est ouvert Et que le contenu n'existe plus
Quand la page web se charge
Alors un message "Ce contenu n'est plus disponible" s'affiche Et les boutons de téléchargement de l'app sont affichés
21. Partage d'un contenu en attente de modération
Étant donné un contenu en cours de validation modération
Quand un lien de partage est ouvert
Alors le message "Ce contenu est en cours de validation" s'affiche
22. Génération du lien hors connexion
Étant donné que l'utilisateur n'a pas de connexion réseau
Quand l'utilisateur tente de partager un contenu
Alors le lien est copié dans le presse-papiers Et un message "Lien copié (nécessite connexion pour ouvrir)" s'affiche
Avantages Premium
En tant qu'abonné Premium Je veux bénéficier d'avantages exclusifs Afin de profiter d'une expérience audio améliorée sans publicité
37 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis connecté à l'application RoadWave
1. Utilisateur gratuit voit 1 publicité tous les 5 contenus
Étant donné que je suis un utilisateur gratuit
Quand j'écoute ma file de contenus
Alors je vois une publicité tous les 5 contenus Et la publicité dure 30 secondes en moyenne Et je ne peux pas la skip
2. Utilisateur Premium ne voit aucune publicité
Étant donné que je suis un utilisateur Premium
Quand j'écoute mes contenus
Alors aucune publicité n'est diffusée Et je passe directement d'un contenu à l'autre Et l'expérience d'écoute est fluide et ininterrompue
3. Badge "0 publicité" sur page Premium
Étant donné que je consulte la page des avantages Premium
Quand je lis la liste des avantages
Alors je vois en premier: Et c'est l'argument principal mis en avant
4. Utilisateur gratuit voit contenus Premium bloqués
Étant donné que je suis un utilisateur gratuit
Quand je consulte les contenus d'un créateur
Alors je vois les contenus marqués Premium avec badge 👑 Mais je ne peux pas les lire (overlay bloquant)
5. Utilisateur Premium accède à tous les contenus exclusifs
Étant donné que je suis un utilisateur Premium
Quand je consulte les contenus d'un créateur
Alors tous les contenus Premium sont accessibles Et je peux les lire sans restriction Et j'ai accès à 100% du catalogue (gratuit + Premium)
6. Nombre de contenus Premium disponibles
Étant donné que je suis Premium
Quand je consulte les statistiques
Alors je vois combien de contenus Premium sont disponibles sur la plateforme Et par exemple: "8,547 contenus Premium exclusifs disponibles" Et cela justifie la valeur de l'abonnement
7. Utilisateur gratuit écoute en 48 kbps Opus
Étant donné que je suis un utilisateur gratuit
Quand je lance un contenu
Alors l'audio est streamé en 48 kbps Opus Et cela consomme environ 20 MB/heure Et la qualité est très correcte pour de la voix
8. Utilisateur Premium écoute en 64 kbps Opus
Étant donné que je suis un utilisateur Premium
Quand je lance un contenu
Alors l'audio est streamé en 64 kbps Opus Et cela consomme environ 30 MB/heure Et la qualité est excellente (détails audio supérieurs)
9. Comparaison qualité 48 kbps vs 64 kbps
Étant donné que je consulte la page Premium
Quand je lis la section qualité audio
Alors je vois l'explication:
10. Justification 48 kbps suffisant pour gratuit
Étant donné que le contenu RoadWave est principalement de la voix
Quand la qualité est fixée à 48 kbps pour gratuit
Alors c'est largement suffisant pour comprendre clairement Et équivalent à la qualité radio FM Et les utilisateurs gratuits ne sont pas frustrés
11. Justification 64 kbps avantage tangible Premium
Étant donné que les audiophiles et créateurs audio sont exigeants
Quand la qualité Premium est à 64 kbps
Alors la différence est perceptible à l'oreille Et les ambiances, musiques de fond, nuances de voix sont mieux rendues Et cela justifie l'abonnement Premium
12. Switch automatique qualité selon abonnement
Étant donné que je suis gratuit et j'écoute en 48 kbps
Quand je souscris à Premium
Alors dès le contenu suivant, je passe automatiquement en 64 kbps Et je peux entendre la différence de qualité immédiatement
13. Consommation data Premium vs Gratuit
Étant donné que je roule 1 heure par jour
Quand je calcule la consommation mensuelle
Alors en gratuit: 20 MB/h × 1h × 22 jours = 440 MB/mois Et en Premium: 30 MB/h × 1h × 22 jours = 660 MB/mois Et la différence est de 220 MB/mois (acceptable pour 4G/5G illimitée)
14. Utilisateur gratuit limité à 50 contenus téléchargés
Étant donné que je suis un utilisateur gratuit
Quand j'accède au mode offline
Alors je peux télécharger jusqu'à 50 contenus maximum Et si j'essaie de télécharger un 51ème, je vois:
15. Utilisateur Premium téléchargements illimités
Étant donné que je suis un utilisateur Premium
Quand j'accède au mode offline
Alors je peux télécharger autant de contenus que je veux Et la seule limite est l'espace de stockage de mon device Et par exemple 500 contenus × 10 MB = 5 GB
16. Justification limite 50 contenus gratuit
Étant donné que 50 contenus de 10 minutes = ~8 heures d'écoute
Quand un utilisateur gratuit prépare un road trip
Alors 8 heures couvrent largement une journée de trajet Et cela permet un usage offline raisonnable sans abuser
17. Justification illimité Premium pour longs road trips
Étant donné qu'un road trip de plusieurs jours nécessite 20-50h de contenu
Quand un utilisateur Premium télécharge 200 contenus
Alors il peut partir serein sans connexion internet pendant 1 semaine Et cela justifie pleinement l'abonnement Premium
18. Affichage compteur téléchargements gratuit
Étant donné que je suis gratuit et j'ai téléchargé 37 contenus
Quand j'accède à la page Téléchargements
Alors je vois:
19. Pas de compteur pour Premium
Étant donné que je suis Premium et j'ai téléchargé 187 contenus
Quand j'accède à la page Téléchargements
Alors je vois simplement: Et aucune limite n'est affichée
20. Utilisateur gratuit historique limité à 100 derniers
Étant donné que je suis un utilisateur gratuit
Quand j'accède à mon historique d'écoute
Alors je vois les 100 derniers contenus écoutés Et les contenus plus anciens ne sont pas affichés Et je vois un message "Historique limité à 100 contenus. Passez Premium pour un historique illimité."
21. Utilisateur Premium historique illimité
Étant donné que je suis un utilisateur Premium
Quand j'accède à mon historique d'écoute
Alors je vois tous les contenus que j'ai écoutés depuis mon inscription Et je peux scroller jusqu'au premier contenu jamais écouté Et l'historique est complet et permanent
22. Recherche dans historique Premium
Étant donné que je suis Premium et j'ai 2 000 contenus dans mon historique
Quand je recherche "Tesla" dans mon historique
Alors tous les contenus écoutés contenant "Tesla" sont affichés Et je peux retrouver facilement un contenu écouté il y a 6 mois
23. Justification limite 100 gratuit suffisante
Étant donné que 100 contenus de 10 min = ~16 heures d'écoute
Quand un utilisateur gratuit écoute 1h/jour
Alors l'historique couvre les 16 derniers jours Et cela suffit pour retrouver un contenu récent
24. Justification illimité Premium pour power users
Étant donné qu'un power user écoute 3h/jour depuis 2 ans
Quand il veut retrouver un contenu spécifique écouté il y a 1 an
Alors l'historique illimité Premium lui permet de retrouver ce contenu Et cela apporte une vraie valeur ajoutée
25. Export historique complet (Premium uniquement)
Étant donné que je suis Premium
Quand je demande l'export de mes données
Alors l'historique complet est inclus dans l'export:
26. Affichage tableau comparatif Gratuit vs Premium
Étant donné que je consulte la page Premium
Quand je vois le tableau comparatif
Alors il affiche:
27. Justification 0 pub = argument principal
Étant donné qu'une publicité de 30s tous les 5 contenus = 6 min/h de pub
Quand un utilisateur écoute 1h/jour
Alors il subit 180 min de pub/mois (3 heures !) Et payer 4.99€ pour éviter 3h de pub/mois est très rentable Et c'est l'argument de conversion n°1
28. Justification qualité audio avantage tangible
Étant donné que la différence 48 kbps → 64 kbps est audible
Quand un audiophile compare les deux
Alors il entend clairement la différence sur un bon système audio voiture Et cela justifie l'abonnement pour les exigeants
29. Justification offline illimité pour road trips
Étant donné qu'un road trip de 2 semaines nécessite 50-100h de contenu
Quand un utilisateur Premium télécharge 300 contenus avant de partir
Alors il peut partir en zone sans réseau sereinement Et cela apporte une vraie valeur pratique
30. Justification pas d'over-engineering
Étant donné que RoadWave se concentre sur l'essentiel
Quand les avantages Premium sont définis
Alors il n'y a pas de:
| fonctionnalité superflue | raison exclusion |
|---|---|
| Badges cosmétiques | Pas de valeur réelle |
| Avatar Premium exclusif | Inutile pour audio |
| Fonctionnalités sociales avancées | Pas prioritaire MVP |
| Early access nouveaux contenus | Complexité > bénéfice |
Et cela réduit la complexité et le coût de développement
31. CTA Premium après 5ème publicité
Étant donné que je suis gratuit et je viens d'entendre ma 5ème pub
Quand la publicité se termine
Alors je vois un message:
32. CTA Premium quand limite 50 téléchargements atteinte
Étant donné que je suis gratuit et j'ai atteint 50 téléchargements
Quand j'essaie de télécharger un 51ème contenu
Alors je vois une popup:
33. CTA Premium quand contenu exclusif bloqué
Étant donné que je suis gratuit et je clique sur un contenu Premium
Quand l'overlay bloquant apparaît
Alors je vois:
34. Statistiques conversion - Quel avantage convertit le mieux ?
Étant donné qu'un admin consulte les statistiques de conversion
Quand il analyse les sources de conversion
Alors il voit:
| source de conversion | % conversions |
|---|---|
| CTA après 5ème pub | 42% |
| CTA contenu Premium bloqué | 28% |
| CTA limite 50 téléchargements | 18% |
| Page Premium directe | 12% |
Et cela aide à optimiser le placement des CTA
35. A/B test message CTA
Étant donné que RoadWave veut optimiser les conversions
Quand un A/B test est lancé sur le CTA après pub
Alors groupe A voit "Marre des pubs ?" (focus négatif) Et groupe B voit "Profitez de 0 publicité" (focus positif) Et le taux de conversion est mesuré Et le message le plus performant est déployé
36. Notification Premium après 30 jours d'utilisation gratuite
Étant donné que je suis utilisateur gratuit depuis 30 jours Et que j'écoute régulièrement (15h cumulées)
Quand le 30ème jour arrive
Alors je reçois une notification:
37. Trial gratuit refusé mais onboarding amélioré
Étant donné qu'il n'y a pas de trial gratuit
Quand un nouvel utilisateur s'inscrit
Alors un onboarding explique clairement les avantages Premium Et il peut comparer gratuit vs Premium dès le premier lancement Et cela l'aide à décider rapidement s'il veut payer
Gestion abonnement Premium
En tant qu'utilisateur Je veux gérer facilement mon abonnement Premium Afin de souscrire, renouveler ou annuler en toute transparence
41 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis connecté à l'application RoadWave
1. Souscription via Web (desktop/mobile) avec Mangopay
Étant donné que je consulte la page Premium sur le site web
Quand je clique sur "S'abonner - Mensuel 4.99€"
Alors je suis redirigé vers le formulaire de paiement Mangopay Et je saisis mes informations de carte bancaire Et le paiement de 4.99€ est prélevé immédiatement Et la commission Mangopay est de 1.8% + 0.18€ = 0.27€ Et RoadWave reçoit 4.72€ net
2. Calcul commission Mangopay
Étant donné qu'un utilisateur paie 4.99€ via Mangopay
Quand la commission est calculée
Alors la commission est : 4.99€ × 1.8% + 0.18€ = 0.09€ + 0.18€ = 0.27€ Et RoadWave reçoit : 4.99€ - 0.27€ = 4.72€ Et la commission représente 5.4% du prix
3. Souscription via iOS App avec Apple IAP
Étant donné que j'utilise l'app iOS
Quand je clique sur "S'abonner - Mensuel 5.99€"
Alors je suis redirigé vers l'interface Apple In-App Purchase Et le prix affiché est 5.99€ (majoré de 20%) Et le paiement est effectué via mon compte Apple Et Apple prend 30% de commission = 1.80€ Et RoadWave reçoit 4.19€ net
4. Souscription via Android App avec Google Play Billing
Étant donné que j'utilise l'app Android
Quand je clique sur "S'abonner - Mensuel 5.99€"
Alors je suis redirigé vers l'interface Google Play Billing Et le prix affiché est 5.99€ (majoré de 20%) Et le paiement est effectué via mon compte Google Et Google prend 30% de commission = 1.80€ Et RoadWave reçoit 4.19€ net
5. Majoration 20% sur mobile pour compenser commission 30%
Étant donné que Apple/Google prennent 30% de commission
Quand RoadWave fixe le prix mobile
Alors le prix web est 4.99€ (commission Mangopay 5.4%) Et le prix mobile est 5.99€ (commission Apple/Google 30%) Et la majoration est de 1€ (+20%) Et cela compense partiellement la commission excessive
6. Email incitation souscription web moins chère
Étant donné que je consulte Premium depuis l'app mobile
Quand je vois le prix 5.99€
Alors je vois aussi un message: Et un lien vers le site web est fourni
7. Calcul économie souscription web vs mobile
Étant donné que le prix web est 4.99€/mois Et que le prix mobile est 5.99€/mois
Quand je calcule l'économie annuelle
Alors web : 4.99€ × 12 = 59.88€/an Et mobile : 5.99€ × 12 = 71.88€/an Et économie : 12€/an (soit 20% d'économie)
8. Activation immédiate après paiement réussi
Étant donné que je viens de payer mon abonnement Premium
Quand le paiement est confirmé
Alors mon statut passe immédiatement à "Premium" Et je peux accéder aux avantages Premium dès maintenant Et je reçois un email de confirmation
9. Email confirmation souscription
Étant donné que j'ai souscrit à Premium
Quand la souscription est confirmée
Alors je reçois un email:
10. Email rappel 7 jours avant renouvellement
Étant donné que mon abonnement mensuel se renouvelle le 15 juillet
Quand le 8 juillet arrive (7 jours avant)
Alors je reçois un email de rappel:
11. Renouvellement automatique réussi
Étant donné que mon abonnement mensuel arrive à échéance le 15 juillet
Quand le 15 juillet arrive
Alors Mangopay/Apple/Google prélève automatiquement 4.99€ (ou 5.99€) Et mon abonnement est renouvelé pour 1 mois supplémentaire Et je reçois un email de confirmation
12. Email confirmation renouvellement
Étant donné que mon abonnement vient d'être renouvelé
Quand le paiement est confirmé
Alors je reçois un email:
13. Échec paiement renouvellement - Tentative 1
Étant donné que mon abonnement doit se renouveler le 15 juillet Mais que ma carte bancaire est expirée ou sans fonds
Quand le prélèvement échoue
Alors je reçois un email:
14. Retry automatique paiement après 3 jours
Étant donné que le paiement a échoué le 15 juillet
Quand le 18 juillet arrive (J+3)
Alors Mangopay/Apple/Google tente automatiquement un nouveau prélèvement Et si le paiement réussit, l'abonnement est renouvelé normalement Et si le paiement échoue encore, un 2ème retry est programmé
15. Retry automatique paiement après 7 jours
Étant donné que 2 tentatives ont échoué (15 juillet et 18 juillet)
Quand le 22 juillet arrive (J+7)
Alors une 3ème et dernière tentative est effectuée Et si le paiement réussit, l'abonnement est sauvé Et si le paiement échoue, l'abonnement est annulé automatiquement
16. Annulation automatique après 3 échecs paiement
Étant donné que les 3 tentatives de renouvellement ont échoué (J+0, J+3, J+7)
Quand la 3ème tentative échoue
Alors mon abonnement Premium est annulé automatiquement Et mon statut repasse à "Gratuit" Et je perds accès aux avantages Premium Et je reçois un email d'annulation
17. Email annulation automatique pour impayé
Étant donné que mon abonnement a été annulé pour échec paiement
Quand l'annulation devient effective
Alors je reçois un email:
18. Annulation self-service dans Settings
Étant donné que je veux annuler mon abonnement
Quand j'accède à "Paramètres > Abonnement"
Alors je vois un bouton "Annuler l'abonnement" Et je peux annuler en 2 clics sans contacter le support
19. Confirmation avant annulation
Étant donné que je clique sur "Annuler l'abonnement"
Quand une popup de confirmation apparaît
Alors je vois:
20. Accès Premium maintenu jusqu'à fin période payée
Étant donné que j'ai annulé mon abonnement le 1er juillet Et que mon abonnement mensuel était valable jusqu'au 15 juillet
Quand l'annulation est confirmée
Alors je garde l'accès Premium jusqu'au 15 juillet Et à partir du 16 juillet, je repasse en gratuit Et je ne suis pas remboursé pour les 14 jours restants
21. Justification pas de remboursement prorata
Étant donné que l'industrie (Spotify, Netflix, YouTube) ne rembourse pas prorata
Quand RoadWave applique la même règle
Alors c'est le standard accepté par les utilisateurs Et cela simplifie la gestion comptable Et évite les abus (souscription puis annulation immédiate pour remboursement)
22. Email confirmation annulation
Étant donné que j'ai annulé mon abonnement
Quand l'annulation est enregistrée
Alors je reçois un email:
23. Pas de renouvellement après annulation
Étant donné que j'ai annulé mon abonnement le 1er juillet
Quand le 15 juillet arrive (date de renouvellement prévue)
Alors aucun prélèvement n'est effectué Et mon statut passe automatiquement à "Gratuit" Et je ne reçois pas d'email de renouvellement
24. Réabonnement possible immédiatement
Étant donné que j'ai annulé mon abonnement il y a 5 jours
Quand j'accède à la page Premium
Alors je peux me réabonner immédiatement Et le processus de paiement est le même que la première fois
25. Pas de nouvelle période d'essai au réabonnement
Étant donné que j'ai annulé mon abonnement il y a 3 mois
Quand je me réabonne
Alors je paie immédiatement 4.99€ (pas d'essai gratuit)
26. Offre win-back pour utilisateurs ayant annulé
Étant donné que j'ai annulé mon abonnement il y a 1 mois
Quand je reçois un email de win-back
Alors je vois une offre spéciale:
27. Table subscriptions en base PostgreSQL
Étant donné qu'un utilisateur souscrit à Premium
Quand les données sont enregistrées
Alors la table subscriptions contient:
28. Statuts possibles dans subscription.status
Étant donné qu'un abonnement peut avoir différents statuts
Quand le statut est stocké en base
Alors les valeurs possibles sont:
| statut | description |
|---|---|
| active | Abonnement actif et payé |
| cancelled | Annulé par utilisateur (accès jusqu'à fin période) |
| expired | Période terminée, pas renouvelé |
| past_due | Échec paiement, en retry automatique |
29. Cache Redis pour vérification Premium temps réel
Étant donné qu'un utilisateur lance un contenu
Quand l'app vérifie s'il est Premium
Alors une clé Redis est consultée: Et si la clé n'existe pas, elle est recalculée depuis PostgreSQL Et cela garantit des performances <10ms
30. Refresh cache Redis via webhooks
Étant donné qu'un paiement est confirmé par Mangopay/Apple/Google
Quand un webhook est reçu par RoadWave
Alors le cache Redis premium:{user_id} est mis à jour immédiatement Et l'utilisateur voit son statut Premium activé sans délai
31. Webhooks Mangopay - PAYIN_NORMAL_SUCCEEDED
Étant donné qu'un paiement Mangopay réussit
Quand Mangopay envoie le webhook PAYIN_NORMAL_SUCCEEDED
Alors RoadWave met à jour subscriptions.status = 'active' Et met à jour current_period_end = NOW() + 1 mois Et refresh le cache Redis premium:{user_id} = true
32. Webhooks Mangopay - PAYIN_NORMAL_FAILED
Étant donné qu'un paiement Mangopay échoue
Quand Mangopay envoie le webhook PAYIN_NORMAL_FAILED
Alors RoadWave met à jour subscriptions.status = 'past_due' Et programme un retry automatique dans 3 jours Et envoie un email à l'utilisateur
33. Webhooks Apple - App Store Server Notifications
Étant donné qu'un paiement Apple IAP change de statut
Quand Apple envoie une notification serveur
Alors RoadWave parse la notification (JSON) Et met à jour la subscription en conséquence Et refresh le cache Redis
34. Webhooks Google - Real-time Developer Notifications
Étant donné qu'un paiement Google Play change de statut
Quand Google envoie une notification temps réel
Alors RoadWave parse la notification (JSON) Et met à jour la subscription en conséquence Et refresh le cache Redis
35. Dashboard admin - Métriques abonnements
Étant donné qu'un admin consulte les métriques Premium
Quand il accède au dashboard
Alors il voit:
| métrique | valeur |
|---|---|
| Abonnés actifs | 12,547 |
| Nouveaux abonnements ce mois | 1,234 |
| Annulations ce mois | 287 (2.3%) |
| Churn rate mensuel | 2.3% |
| MRR (Revenus mensuels récurrents) | 58,890€ |
| Taux conversion gratuit → Premium | 8.5% |
36. Calcul churn rate mensuel
Étant donné que 287 utilisateurs ont annulé ce mois Et qu'il y avait 12,547 abonnés au début du mois
Quand le churn rate est calculé
Alors churn = 287 / 12,547 = 2.3% Et un churn <5% est considéré comme excellent Et RoadWave surveille cette métrique de près
37. Alerte si churn rate >5%
Étant donné que le churn rate mensuel dépasse 5%
Quand le système détecte cette anomalie
Alors une alerte est envoyée à l'équipe:
38. Enquête satisfaction à l'annulation
Étant donné que je viens d'annuler mon abonnement
Quand l'annulation est confirmée
Alors je vois un questionnaire rapide: Et les réponses aident à améliorer l'offre Premium
39. Répartition canaux souscription
Étant donné qu'un admin analyse les canaux de souscription
Quand il consulte les statistiques
Alors il voit:
| canal | abonnés | % total | revenus/mois |
|---|---|---|---|
| Web (Mangopay) | 8,234 | 65.6% | 41,088€ |
| iOS (Apple) | 2,845 | 22.7% | 17,042€ |
| Android (Google) | 1,468 | 11.7% | 8,793€ |
Et cela aide à orienter les efforts marketing (inciter web = moins de commission)
40. Performance vérification Premium <10ms
Étant donné que 100 000 utilisateurs consultent des contenus simultanément
Quand chaque requête vérifie le statut Premium via Redis
Alors le temps de réponse moyen est <10ms Et Redis gère facilement 100 000 requêtes/seconde Et l'expérience utilisateur est fluide
41. Backup données abonnements
Étant donné que les données d'abonnements sont critiques
Quand un backup est effectué
Alors PostgreSQL est répliqué en temps réel sur un replica Et un snapshot quotidien est stocké sur S3 Et en cas de crash, les données peuvent être restaurées <5 minutes
Multi-devices et détection simultanée
En tant qu'abonné Premium Je veux utiliser mon compte sur plusieurs appareils Mais limité à 1 seul stream actif à la fois pour éviter le partage abusif
30 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis un utilisateur Premium actif Et que mon compte est valide
1. 1 seul stream actif autorisé par compte
Étant donné que je n'écoute rien actuellement
Quand je lance un contenu sur mon iPhone
Alors le stream démarre normalement Et Redis enregistre: active_streams:{user_id} = {device_id: "iPhone", started_at: timestamp}
2. Détection connexion simultanée - Arrêt premier device
Étant donné que j'écoute un contenu sur mon iPhone
Quand je lance un contenu sur mon iPad
Alors le système détecte une session active sur iPhone Et la lecture sur iPhone est arrêtée immédiatement (WebSocket close) Et je vois sur iPhone: "Lecture interrompue : votre compte est utilisé sur un autre appareil" Et la lecture démarre sur iPad normalement
3. Message explicite sur device interrompu
Étant donné que ma lecture sur iPhone vient d'être interrompue
Quand je regarde l'écran de mon iPhone
Alors je vois une overlay avec le message: Et un bouton "Reprendre ici" est disponible
4. Reprendre lecture sur device interrompu
Étant donné que ma lecture sur iPhone a été interrompue Et que je veux reprendre sur iPhone
Quand je clique sur "Reprendre ici"
Alors la lecture démarre sur iPhone Et l'iPad est à son tour interrompu avec le même message Et le "ping-pong" entre devices est possible (mais pénible)
5. Enregistrement session active dans Redis
Étant donné que je lance un contenu sur mon iPhone
Quand la lecture démarre
Alors une entrée Redis est créée:
6. Heartbeat toutes les 30 secondes pour maintenir session
Étant donné que j'écoute un contenu sur mon iPhone
Quand 30 secondes s'écoulent
Alors l'app envoie un heartbeat au serveur Et le serveur refresh le TTL Redis à 300 secondes Et la session reste active
7. Session considérée morte après 5 minutes sans heartbeat
Étant donné que j'écoute un contenu sur mon iPhone Mais que l'app crash ou que le réseau coupe
Quand 5 minutes s'écoulent sans heartbeat
Alors l'entrée Redis expire automatiquement (TTL atteint) Et je peux relancer sur n'importe quel device sans conflit
8. Vérification session avant démarrage lecture
Étant donné que je veux lancer un contenu sur mon iPad
Quand j'appuie sur Play
Alors le serveur vérifie Redis: active_streams:{user_id} Et si une session existe sur un autre device, elle est tuée Et la nouvelle session iPad est enregistrée dans Redis
9. Gestion multi-utilisateurs simultanés
Étant donné que 100 000 utilisateurs Premium écoutent simultanément
Quand Redis stocke 100 000 entrées active_streams
Alors chaque entrée a un TTL de 5 minutes Et Redis gère facilement cette charge (~10 MB de RAM) Et les vérifications sont quasi-instantanées (O(1))
10. Contenus téléchargés (offline) ne comptent pas comme stream
Étant donné que j'ai téléchargé 20 contenus en mode offline
Quand j'écoute un contenu téléchargé sur mon iPhone sans réseau
Alors aucune session active n'est enregistrée dans Redis Et je peux écouter offline pendant qu'un autre device stream online
11. Transition rapide device <10s tolérée
Étant donné que j'écoute dans ma voiture sur mon iPhone Et que j'arrive chez moi
Quand je lance la lecture sur mon iPad dans les 10 secondes
Alors la transition est considérée comme un changement de device légitime Et aucun message d'erreur n'est affiché sur iPhone Et la lecture reprend exactement où j'étais sur iPad
12. Détection transition rapide via timestamps
Étant donné que la session iPhone a started_at = 14:30:00
Quand je lance sur iPad à 14:30:05 (5 secondes après)
Alors le serveur détecte: diff = 5s < 10s Et applique une "graceful transition" (pas de message d'erreur iPhone) Et Redis met à jour: active_streams:{user_id} = {device_id: "iPad", ...}
13. Plusieurs devices disponibles mais 1 seul actif
Étant donné que je possède:
| device | status |
|---|---|
| iPhone | Installé |
| iPad | Installé |
| MacBook (web) | Connecté |
| Android (conjoint) | Installé |
Quand je lance un stream sur n'importe quel device
Alors seulement 1 peut être actif à la fois Et les autres devices sont en "standby"
14. Justification anti-partage compte
Étant donné qu'un utilisateur Premium partage son compte avec un ami
Quand les 2 personnes essaient d'écouter simultanément
Alors la lecture est constamment interrompue sur l'un ou l'autre Et l'expérience devient inutilisable Et cela décourage fortement le partage de compte
15. Justification protection revenus créateurs
Étant donné que 1 abonnement Premium = 4.99€/mois
Quand 70% sont reversés aux créateurs (3.49€)
Alors les créateurs sont rémunérés pour 1 personne Et si 2 personnes utilisent le même compte simultanément, c'est injuste Et la limite 1 stream protège l'équité du système
16. Justification UX claire
Étant donné qu'un stream est interrompu sur un device
Quand l'utilisateur voit le message explicite
Alors il comprend immédiatement pourquoi (autre device actif) Et il peut choisir de reprendre sur le device actuel ou l'autre Et il n'y a pas de confusion ou frustration
17. Comparaison avec Spotify (limite 1 stream)
Étant donné que Spotify Premium limite aussi à 1 stream actif
Quand RoadWave applique la même règle
Alors les utilisateurs connaissent déjà ce comportement Et cela paraît normal et accepté par l'industrie
18. Comparaison avec Netflix (plusieurs streams selon formule)
Étant donné que Netflix permet 1-4 streams selon la formule
Quand RoadWave limite à 1 stream pour tous
Alors c'est plus strict que Netflix Mais Netflix cible le foyer familial (TV partagée) Alors que RoadWave cible l'individu conducteur (usage personnel)
19. Détection pattern suspect - Changements devices fréquents
Étant donné qu'un utilisateur change de device 50 fois en 1 heure
Quand le système détecte ce pattern anormal
Alors une alerte est générée pour l'équipe modération Et le compte peut être marqué pour surveillance Et si abus confirmé, suspension possible
20. Logs des changements de device
Étant donné que je change de device plusieurs fois par jour
Quand les changements sont loggés
Alors chaque événement est enregistré:
| timestamp | from_device | to_device | content_id |
|---|---|---|---|
| 2025-06-15 08:30:00 | null | iPhone | abc123 |
| 2025-06-15 09:15:00 | iPhone | iPad | def456 |
| 2025-06-15 18:30:00 | iPad | iPhone | ghi789 |
Et ces logs aident à détecter les partages de compte
21. Métriques admin - Changements devices par utilisateur
Étant donné qu'un admin consulte les métriques de streaming
Quand il accède au dashboard
Alors il voit:
| métrique | valeur |
|---|---|
| Utilisateurs Premium actifs | 12,547 |
| Changements de device/jour (médiane) | 2 |
| Utilisateurs >10 changements/jour | 47 (0.4%) |
| Comptes suspects (>20 changements/j) | 3 |
22. Email d'avertissement si changements excessifs
Étant donné que je change de device 30 fois par jour pendant 3 jours
Quand le système détecte ce pattern
Alors je reçois un email d'avertissement:
23. Suspension compte après avertissement ignoré
Étant donné que j'ai reçu un email d'avertissement il y a 7 jours Mais que je continue à changer de device 30 fois par jour
Quand l'équipe modération examine le compte
Alors mon compte Premium peut être suspendu pour partage abusif Et je reçois un email de suspension avec justification
24. FAQ - Pourquoi ma lecture s'arrête quand j'utilise un autre device ?
Étant donné que je consulte la FAQ Premium
Quand je cherche "lecture interrompue"
Alors je trouve la réponse:
25. Support - Utilisateur pense être piraté
Étant donné qu'un utilisateur voit constamment "Lecture interrompue" Et qu'il pense que son compte est piraté
Quand il contacte le support
Alors le support vérifie les logs de changements de device Et peut identifier les devices (iPhone, iPad perso vs iPhone inconnu) Et conseille de changer le mot de passe si device inconnu détecté
26. Changement mot de passe déconnecte tous les devices
Étant donné que je pense que mon compte est compromis
Quand je change mon mot de passe
Alors tous mes devices sont déconnectés immédiatement Et les sessions actives dans Redis sont supprimées Et je dois me reconnecter sur chaque device Et cela sécurise mon compte
27. Test charge - 100 000 vérifications/seconde
Étant donné que 100 000 utilisateurs Premium lancent des contenus
Quand chaque lancement vérifie Redis (GET active_streams:{user_id})
Alors Redis peut gérer facilement 100 000 requêtes/seconde Et le temps de réponse moyen est <1ms Et aucun ralentissement n'est constaté
28. Test failover Redis
Étant donné que le serveur Redis principal tombe en panne
Quand le failover automatique vers le replica Redis s'active
Alors les sessions actives peuvent être perdues temporairement (max 5 min) Mais les utilisateurs peuvent relancer immédiatement Et l'impact est minimal (pas de perte de données critiques)
29. Test concurrence - Lancement simultané 2 devices
Étant donné que je lance exactement au même instant sur iPhone et iPad
Quand les 2 requêtes arrivent en parallèle au serveur
Alors Redis utilise un lock (SETNX) pour atomicité Et 1 seul device gagne (par exemple iPhone) Et l'autre device (iPad) reçoit immédiatement une erreur Et l'utilisateur peut retry sur iPad si souhaité
30. Nettoyage automatique sessions expirées
Étant donné que 1000 sessions Redis ont expiré (TTL atteint)
Quand Redis supprime automatiquement ces entrées
Alors la mémoire est libérée Et les nouveaux streams peuvent démarrer sans conflit Et aucune intervention manuelle n'est nécessaire
Offre et tarification Premium
En tant qu'utilisateur Je veux pouvoir souscrire à un abonnement Premium Afin de profiter d'une expérience sans publicité avec des avantages exclusifs
31 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis connecté en tant qu'utilisateur
1. Formule mensuelle à 4.99€/mois
Étant donné que je consulte les offres Premium
Quand je vois la formule mensuelle
Alors le prix affiché est 4.99€/mois Et il n'y a aucune réduction Et le prix effectif par mois est 4.99€
2. Formule annuelle à 49.99€/an (2 mois offerts)
Étant donné que je consulte les offres Premium
Quand je vois la formule annuelle
Alors le prix affiché est 49.99€/an Et l'économie affichée est "2 mois offerts" Et le prix effectif par mois est 4.16€ Et je vois le badge "Meilleure offre"
3. Calcul économie formule annuelle
Étant donné que la formule mensuelle coûte 4.99€/mois
Quand je calcule le coût annuel en mensuel
Alors 12 mois × 4.99€ = 59.88€/an Et la formule annuelle coûte 49.99€ Et l'économie est de 9.89€ (≈ 2 mois gratuits) Et la réduction est de 16.5%
4. Pas d'essai gratuit disponible
Étant donné que je consulte les offres Premium
Quand je recherche une option "Essai gratuit"
Alors aucune option d'essai gratuit n'est proposée Et je dois payer dès le premier jour pour accéder au Premium
5. Justification absence essai gratuit - Anti-abus vacances
Étant donné que RoadWave ne propose pas d'essai gratuit
Quand un utilisateur envisage un road trip de 14 jours
Alors il ne peut pas s'abonner pour l'essai gratuit puis annuler Et cela évite les inscriptions opportunistes Et protège les revenus des créateurs
6. Justification absence essai gratuit - Protection revenus créateurs
Étant donné qu'un utilisateur Premium écoute des contenus
Quand il génère des écoutes dès le jour 1
Alors les créateurs sont rémunérés immédiatement (70% de 4.99€) Et il n'y a pas de "période gratuite" sans rémunération créateurs
7. Justification absence essai gratuit - Simplicité
Étant donné que RoadWave gère les abonnements
Quand il n'y a pas d'essai gratuit
Alors pas de gestion complexe de période trial Et pas de workflow de conversion trial → payant Et cela réduit la complexité technique
8. Justification absence essai gratuit - Engagement
Étant donné qu'un utilisateur paie dès le début
Quand il souscrit à Premium
Alors il est plus engagé qu'un utilisateur en essai gratuit Et le taux de churn est généralement plus faible Et la lifetime value (LTV) est plus élevée
9. Pas de partage familial au MVP
Étant donné que je consulte les offres Premium
Quand je recherche une option "Famille" ou "Partage"
Alors aucune option de partage familial n'est disponible Et seuls les abonnements individuels sont proposés
10. Justification absence partage familial - Complexité technique
Étant donné que le partage familial nécessite:
| fonctionnalité | complexité |
|---|---|
| Gestion invitations | Moyenne |
| Validation liens famille | Moyenne |
| Limite devices par membre | Élevée |
| Dashboard admin famille | Élevée |
Quand RoadWave évalue le ROI
Alors le coût dev/support est trop élevé pour le MVP Et la fonctionnalité est reportée post-MVP
11. Justification absence partage familial - Risque abus
Étant donné qu'une offre famille permet 5-6 membres
Quand il n'y a pas de vérification stricte de lien familial
Alors des "familles" de 6 inconnus pourraient se former Et cela réduirait fortement les revenus (6 personnes pour 1 abonnement)
12. Justification absence partage familial - Cible individuelle
Étant donné que RoadWave cible principalement les conducteurs
Quand chaque conducteur utilise l'app individuellement en voiture
Alors le besoin de partage familial est limité Et la plupart des utilisateurs sont des individus (pas des familles)
13. Post-MVP - Offre Famille à 9.99€/mois pour 5 comptes
Étant donné que RoadWave envisage une offre Famille post-MVP
Quand la fonctionnalité est spécifiée
Alors le prix serait 9.99€/mois pour 5 comptes Et cela représente 2€/mois/personne Mais cette offre n'est pas disponible au MVP
14. Comparaison tarif - Spotify à 10.99€/mois
Étant donné que Spotify Premium coûte 10.99€/mois
Quand RoadWave fixe son prix à 4.99€/mois
Alors RoadWave est 54.5% moins cher que Spotify Et cela positionne RoadWave comme très accessible
15. Comparaison tarif - YouTube Premium à 11.99€/mois
Étant donné que YouTube Premium coûte 11.99€/mois
Quand RoadWave fixe son prix à 4.99€/mois
Alors RoadWave est 58.4% moins cher que YouTube Premium Et cela est un argument commercial fort
16. Comparaison tarif - Apple Music à 10.99€/mois
Étant donné qu'Apple Music coûte 10.99€/mois
Quand RoadWave fixe son prix à 4.99€/mois
Alors RoadWave est 54.5% moins cher qu'Apple Music Et cela attire les utilisateurs sensibles au prix
17. Justification tarif bas - Cible conducteurs quotidiens
Étant donné que RoadWave cible les trajets quotidiens domicile-travail
Quand le prix est fixé à 4.99€/mois
Alors c'est un budget raisonnable pour un conducteur Et équivalent à ~1-2 cafés/mois Et psychologiquement acceptable pour un usage quotidien
18. Justification formule annuelle - Engagement long terme
Étant donné que la formule annuelle offre 2 mois gratuits
Quand un utilisateur souscrit pour 1 an
Alors il s'engage sur le long terme Et RoadWave sécurise 49.99€ de revenus immédiatement Et le cash flow est amélioré
19. Justification formule annuelle - Réduction churn
Étant donné qu'un utilisateur paie 49.99€ pour l'année
Quand il envisage d'arrêter après 3 mois
Alors il a déjà payé pour 12 mois Et il continuera probablement à utiliser l'app Et le taux de churn est réduit significativement
20. Affichage comparatif des deux formules
Étant donné que je consulte la page Premium
Quand je vois les deux formules côte à côte
Alors je vois:
21. Mise en avant formule annuelle
Étant donné que je consulte la page Premium
Quand je vois les deux formules
Alors la formule annuelle a un badge "Meilleure offre" ⭐ Et elle est visuellement mise en avant (bordure colorée, taille plus grande) Et l'économie de 2 mois est affichée en gros Et cela incite à choisir la formule annuelle
22. Lien "Pourquoi pas d'essai gratuit ?" en FAQ
Étant donné que je consulte la page Premium
Quand je clique sur "FAQ"
Alors je vois une question "Pourquoi pas d'essai gratuit ?" Et la réponse explique:
23. A/B test formule annuelle (post-MVP)
Étant donné que RoadWave veut optimiser la conversion annuelle
Quand un A/B test est lancé
Alors groupe A voit "2 mois offerts" (économie en durée) Et groupe B voit "Économisez 9.89€" (économie en argent) Et les taux de souscription sont mesurés Et le message le plus performant est déployé
24. Promo temporaire exceptionnelle (Black Friday, etc.)
Étant donné que c'est le Black Friday
Quand une promo temporaire est activée
Alors la formule annuelle peut passer à 39.99€/an (au lieu de 49.99€) Et l'économie affichée est "4 mois offerts !" Et la promo dure 3 jours uniquement Et cela génère un pic de souscriptions
25. Code promo partenariat influenceur
Étant donné qu'un influenceur promeut RoadWave
Quand il partage un code promo "INFLUENCEUR20"
Alors les utilisateurs obtiennent -20% sur le premier mois (3.99€ au lieu de 4.99€) Et le code est valable 1 mois Et les conversions sont trackées par code promo
26. Statistiques admin - Répartition formules
Étant donné qu'un admin consulte les métriques d'abonnements
Quand il accède au dashboard
Alors il voit:
| métrique | valeur |
|---|---|
| Abonnés Premium total | 12,547 |
| Abonnés mensuels | 7,234 (58%) |
| Abonnés annuels | 5,313 (42%) |
| Revenus mensuels récurrents | 58,890€ |
Et ces données aident à piloter la stratégie tarifaire
27. Calcul revenus mensuels récurrents (MRR)
Étant donné que RoadWave a:
| formule | nombre abonnés | prix |
|---|---|---|
| Mensuel | 7,234 | 4.99€/mois |
| Annuel | 5,313 | 49.99€/an |
Quand le MRR est calculé
Alors MRR mensuel = 7,234 × 4.99€ = 36,098€ Et MRR annuel ramené au mois = 5,313 × 49.99€ / 12 = 22,139€ Et MRR total = 58,237€/mois
28. Projection revenus annuels (ARR)
Étant donné que le MRR est de 58,237€
Quand l'ARR est calculé
Alors ARR = 58,237€ × 12 = 698,844€/an Et cela aide à évaluer la valorisation de l'entreprise
29. Affichage prix TTC (TVA incluse)
Étant donné que RoadWave est une plateforme française
Quand les prix sont affichés
Alors tous les prix sont TTC (TVA 20% incluse) Et le prix 4.99€ inclut déjà la TVA Et cela respecte la réglementation française
30. Performance page Premium avec cache
Étant donné que la page Premium est consultée fréquemment
Quand un utilisateur charge la page
Alors les prix et avantages sont servis depuis un cache CDN Et le temps de chargement est <200ms Et cela garantit une expérience fluide
31. Localisation prix selon pays (post-MVP)
Étant donné que RoadWave se lance à l'international post-MVP
Quand un utilisateur se connecte depuis l'Allemagne
Alors les prix peuvent être ajustés (ex: 4.99€ en France, 4.49€ en Pologne) Et cela respecte le pouvoir d'achat local Mais cette fonctionnalité n'est pas au MVP (France uniquement)
Profil créateur
En tant qu'utilisateur de RoadWave Je veux consulter les profils des créateurs Afin de découvrir leur contenu et décider de m'abonner
31 scénarios (28 standards, 3 plans)
Contexte commun à tous les scénarios
Étant donné que l'application RoadWave est démarrée
1. URL du profil créateur
Étant donné un créateur avec le pseudo "paris_stories"
Quand l'utilisateur accède au profil
Alors l'URL est "https://roadwave.fr/@paris_stories"
2. Informations principales du profil
Étant donné un créateur "@paris_stories" avec les informations suivantes:
| champ | valeur |
|---|---|
| photo | avatar_120x120.jpg |
| pseudo | paris_stories |
| badge_vérifié | true |
| bio | Histoires et anecdotes de Paris |
| abonnés | 1200 |
| contenus | 42 |
| durée_totale | 18h |
| écoutes_totales | 54000 |
Quand le profil est affiché
Alors les éléments suivants sont visibles:
| élément | valeur affichée |
|---|---|
| Photo profil | 120×120 px |
| @pseudo | @paris_stories |
| Badge vérifié | ✓ |
| Bio | Histoires et... |
| Nombre abonnés | 1.2K abonnés |
| Nombre contenus | 42 contenus |
| Durée totale | 18h de contenu créé |
| Écoutes totales | 54K écoutes totales |
3. 📋 Plan: Arrondi des statistiques publiques
Étant donné un créateur avec <valeur_exacte> <métrique>
Quand le profil est affiché
Alors la valeur affichée est "<valeur_affichée>"
📊 Exemples de données:
| métrique | valeur_exacte | valeur_affichée |
|---|---|---|
| abonnés | 342 | 342 |
| abonnés | 1200 | 1.2K |
| abonnés | 54000 | 54K |
| abonnés | 1200000 | 1.2M |
| écoutes | 842 | 842 |
| écoutes | 5400 | 5.4K |
| écoutes | 142000 | 142K |
| écoutes | 2100000 | 2.1M |
| durée (heures) | 18 | 18h |
| durée (heures) | 142 | 142h |
4. Bio avec markdown basique
Étant donné un créateur avec la bio suivante en markdown:
Quand le profil est affiché
Alors le texte en gras "Histoires de Paris" est formaté Et le texte en italique "Nouveau contenu chaque semaine" est formaté Et le lien "https://paris-stories.fr" est cliquable
5. Limitation de la bio à 300 caractères
Étant donné un créateur qui entre une bio de 350 caractères
Quand la bio est sauvegardée
Alors seuls les 300 premiers caractères sont conservés Et un message "Maximum 300 caractères" s'affiche
6. Boutons d'action principaux
Étant donné que l'utilisateur consulte un profil créateur
Quand la page est chargée
Alors les boutons suivants sont visibles:
| bouton | action |
|---|---|
| S'abonner | Abonnement au créateur |
| Partager profil | Menu de partage |
| ••• | Menu contextuel |
7. Menu contextuel du profil [•••]
Étant donné que l'utilisateur clique sur le bouton [•••]
Quand le menu s'ouvre
Alors les options suivantes sont disponibles:
| option | description |
|---|---|
| Partager profil | Partager le lien du profil |
| Signaler profil | Signaler spam ou usurpation d'identité |
| Bloquer créateur | Masquer tous les contenus du créateur |
8. Liste des contenus du créateur
Étant donné un créateur avec 3 contenus publiés
Quand le profil est affiché
Alors chaque contenu affiche:
| élément | exemple |
|---|---|
| Cover image | Image 16:9 |
| Titre | Balade à Paris |
| Durée et écoutes | 12 min · 🎧 2.3K |
| Localisation | 📍 Paris |
| Bouton lecture | ▶️ |
9. 📋 Plan: Options de tri des contenus
Étant donné un créateur avec 10 contenus publiés
Quand l'utilisateur sélectionne le tri "<option_tri>"
Alors les contenus sont triés par <critère>
📊 Exemples de données:
| option_tri | critère |
|---|---|
| Plus récents | Date publication DESC (défaut) |
| Plus populaires | Écoutes × facteur temporel (90 jours) |
| Plus anciens | Date publication ASC |
10. Filtrage des contenus par tag
Étant donné un créateur avec des contenus taggés "Voyage", "Histoire", "Gastronomie"
Quand l'utilisateur filtre par tags "Voyage, Histoire"
Alors seuls les contenus avec ces tags sont affichés Et le nombre de résultats est indiqué "12 contenus"
11. Recherche locale dans le profil
Étant donné que l'utilisateur consulte le profil de "@paris_stories" Et que le créateur a publié 50 contenus
Quand l'utilisateur entre "Montmartre" dans la barre de recherche
Alors la recherche s'effectue sur les titres et descriptions Et seuls les contenus correspondants sont affichés Et le placeholder indique "Rechercher dans les contenus de @paris_stories"
12. Chargement paginé des contenus
Étant donné un créateur avec 100 contenus publiés
Quand le profil est affiché
Alors 20 contenus sont chargés initialement Et un bouton "Charger plus" est visible en bas de page
Quand l'utilisateur clique sur "Charger plus"
Alors 20 contenus supplémentaires sont chargés
13. Informations publiques visibles par tous
Étant donné que l'utilisateur consulte un profil créateur
Alors les informations suivantes sont publiques:
| information | visible |
|---|---|
| Photo et pseudo | ✅ |
| Badge vérifié | ✅ |
| Bio | ✅ |
| Nombre abonnés | ✅ |
| Nombre contenus | ✅ |
| Durée totale créée | ✅ |
| Écoutes totales | ✅ |
14. Informations privées non visibles
Étant donné que l'utilisateur consulte un profil créateur
Alors les informations suivantes sont privées:
| information | visible |
|---|---|
| Liste des abonnés | ❌ |
| Revenus | ❌ |
| Localisation précise | ❌ |
| Email | ❌ |
15. Dashboard créateur avec métriques privées
Étant donné que le créateur "@paris_stories" consulte son propre dashboard
Quand la page statistiques est affichée
Alors les métriques suivantes sont accessibles:
| métrique | type |
|---|---|
| Taux complétion moyen | 78% |
| Évolution abonnés | Graphique |
| Écoutes par contenu | Tableau |
| Revenus | Dashboard |
| Taux conversion Premium | Pourcentage |
| Démographie (âge/zone) | Agrégée |
16. Graphique d'évolution des abonnés
Étant donné que le créateur consulte son dashboard
Quand il sélectionne la période "30 jours"
Alors un graphique d'évolution des abonnés est affiché Et les périodes disponibles sont:
| période |
|---|
| 30j |
| 90j |
| 1 an |
17. Tableau détaillé des écoutes par contenu
Étant donné un créateur avec 10 contenus publiés
Quand il consulte le tableau des performances
Alors chaque contenu affiche:
| métrique | exemple |
|---|---|
| Titre | Balade |
| Écoutes totales | 2300 |
| Écoutes complètes >80% | 1840 |
| Taux complétion | 80% |
| Likes | 420 |
| Partages | 56 |
18. Affichage du badge vérifié
Étant donné un créateur vérifié "@paris_stories"
Quand son profil est affiché
Alors le badge bleu "✓" est accolé au pseudo Et un tooltip "Compte vérifié" s'affiche au survol
19. Badge vérifié visible partout
Étant donné un créateur vérifié "@paris_stories"
Alors le badge "✓" est affiché dans:
| emplacement |
|---|
| Page profil |
| Player en lecture |
| Résultats de recherche |
| Notifications |
20. 📋 Plan: Attribution automatique du badge selon critères
Étant donné un créateur avec <critère>
Quand les conditions sont validées
Alors le badge vérifié est attribué
📊 Exemples de données:
| critère | automatique |
|---|---|
| KYC Mangopay validé | Oui |
| ≥10K abonnés + compte >6 mois | Oui |
| Célébrité / Média officiel | Manuel |
21. Attribution automatique via KYC
Étant donné un créateur qui complète son KYC Mangopay
Quand les documents sont validés
Alors le badge vérifié est attribué automatiquement Et une notification "Votre compte est maintenant vérifié ✓" est envoyée
22. Attribution automatique à 10K abonnés
Étant donné un créateur avec 9999 abonnés et un compte de 7 mois
Quand il atteint 10000 abonnés
Alors le badge vérifié est attribué automatiquement Et une notification de félicitations est envoyée
23. Demande manuelle de vérification (célébrité)
Étant donné un créateur reconnu publiquement
Quand il soumet le formulaire de demande de vérification
Alors une requête est créée pour l'équipe RoadWave Et l'équipe vérifie l'identité sous 48-72h Et le badge est attribué si validation réussie
24. Retrait du badge en cas de suspension
Étant donné un créateur vérifié avec le badge "✓"
Quand sa monétisation est suspendue
Alors le badge vérifié est retiré temporairement Et le badge est restauré après levée de la suspension
25. Retrait définitif du badge pour strikes multiples
Étant donné un créateur vérifié avec 3 strikes actifs
Quand un 4ème strike est appliqué (ban)
Alors le badge vérifié est retiré définitivement Et le compte est banni
26. Retrait du badge pour usurpation d'identité
Étant donné un créateur vérifié qui usurpe l'identité d'une célébrité
Quand la fraude est détectée
Alors le badge est retiré immédiatement Et le compte est banni Et une enquête est ouverte
27. Profil créateur supprimé
Étant donné qu'un utilisateur tente d'accéder à "@deleted_user"
Quand la page est chargée
Alors un message "Ce profil n'existe pas ou a été supprimé" s'affiche
28. Blocage d'un créateur
Étant donné que l'utilisateur bloque le créateur "@spam_account"
Quand l'utilisateur consulte son flux de recommandations
Alors aucun contenu de "@spam_account" n'est affiché Et le créateur n'apparaît plus dans les recherches
29. Déblocage d'un créateur
Étant donné que l'utilisateur a bloqué "@paris_stories"
Quand il accède à ses paramètres "Comptes bloqués" Et qu'il débloque "@paris_stories"
Alors les contenus du créateur réapparaissent dans les recommandations
30. Signalement d'un profil pour spam
Étant donné que l'utilisateur signale le profil "@spam_account"
Quand il sélectionne la raison "Spam"
Alors le signalement est envoyé à la modération Et un message de confirmation s'affiche Et le profil reste visible jusqu'à décision de modération
31. Signalement pour usurpation d'identité
Étant donné que l'utilisateur signale le profil "@fake_celebrity"
Quand il sélectionne "Usurpation d'identité" Et qu'il fournit une preuve
Alors le signalement est priorisé (priorité HAUTE) Et l'équipe modération traite sous 24h
Création de campagnes publicitaires
En tant que publicitaire Je veux créer des campagnes avec ciblage précis et maîtrise du budget Afin d'optimiser mes investissements publicitaires
30 scénarios (27 standards, 3 plans)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un compte publicitaire est créé et vérifié
1. Création d'une campagne publicitaire complète
Étant donné que je suis connecté en tant que publicitaire
Quand je crée une nouvelle campagne avec les paramètres:
| Paramètre | Valeur |
|---|---|
| Budget total | 300€ |
| Date début | 2026-02-01 |
| Date fin | 2026-02-14 |
| Zone géographique | Département du Var |
| Plages horaires | 7h-9h, 17h-19h |
| Tags ciblés | Automobile, Voyage |
| Tranche d'âge | 18+ |
Alors la campagne est créée avec succès Et le budget quotidien calculé est de 21.43€/jour Et les diffusions estimées sont de ~430 écoutes complètes Et un statut "En attente de validation" est assigné
2. Budget minimum 50€ requis
Étant donné que je crée une nouvelle campagne
Quand je définis un budget de 40€
Alors une erreur s'affiche: "Budget minimum requis: 50€" Et la campagne n'est pas créée
3. Budget de 50€ exactement accepté
Étant donné que je crée une nouvelle campagne
Quand je définis un budget de 50€
Alors la campagne est créée avec succès Et aucune erreur n'est affichée
4. Calcul automatique du budget quotidien
Étant donné une campagne avec:
| Budget total | 300€ |
|---|---|
| Durée | 14 j |
Quand le système calcule le budget quotidien
Alors le budget/jour est de 21.43€ Et le nombre estimé de diffusions/jour est de 430 (à 0.05€/écoute)
5. Ciblage géographique point GPS précis
Étant donné que je crée une campagne
Quand je sélectionne "Point GPS" avec coordonnées (43.1234, 5.9234) Et que je définis un rayon de 5km
Alors la campagne cible uniquement les utilisateurs dans ce rayon Et la zone est représentée par un cercle sur la carte
6. Ciblage géographique ville
Étant donné que je crée une campagne
Quand je sélectionne "Ville" et choisis "Marseille"
Alors la campagne cible tous les utilisateurs dans la commune de Marseille Et les limites administratives sont affichées sur la carte
7. Ciblage géographique département
Étant donné que je crée une campagne
Quand je sélectionne "Département" et choisis "Var (83)"
Alors la campagne cible tout le département du Var Et une estimation de population cible est affichée
8. Ciblage géographique région
Étant donné que je crée une campagne
Quand je sélectionne "Région" et choisis "Provence-Alpes-Côte d'Azur"
Alors la campagne cible toute la région PACA Et l'estimation de population cible est mise à jour
9. Ciblage géographique national
Étant donné que je crée une campagne
Quand je sélectionne "National"
Alors la campagne cible tous les utilisateurs en France Et aucune limite géographique n'est appliquée
10. Ciblage horaire plages multiples
Étant donné que je crée une campagne
Quand je définis les plages horaires:
| Plage |
|---|
| 7h-9h |
| 12h-14h |
| 17h-19h |
Alors la publicité est diffusée uniquement pendant ces plages Et elle n'est jamais diffusée en dehors (ex: 10h, 15h, 20h)
11. Ciblage horaire toute la journée
Étant donné que je crée une campagne
Quand je ne définis aucune plage horaire spécifique
Alors la publicité est diffusée 24h/24 Et aucune restriction horaire n'est appliquée
12. Ciblage par centres d'intérêt
Étant donné que je crée une campagne pour un garage automobile
Quand je sélectionne les tags:
| Tag |
|---|
| Automobile |
| Mécanique |
| Sport |
Alors la publicité est prioritaire pour les utilisateurs avec jauges élevées sur ces tags Et elle peut quand même être diffusée à d'autres utilisateurs (ciblage non exclusif)
13. Classification d'âge obligatoire
Étant donné que je crée une campagne
Quand j'essaie de valider sans sélectionner une tranche d'âge
Alors une erreur s'affiche: "Classification d'âge obligatoire" Et les options proposées sont:
| Option |
|---|
| Tout public |
| 13+ |
| 16+ |
| 18+ |
14. Upload audio publicitaire formats acceptés
Étant donné que je crée une campagne
Quand j'upload un fichier audio format MP3
Alors le fichier est accepté
Quand j'upload un fichier audio format AAC (.aac ou .m4a)
Alors le fichier est accepté
Quand j'upload un fichier audio format WAV
Alors une erreur s'affiche: "Format non supporté. Utilisez MP3 ou AAC"
15. Durée audio publicitaire validée
Étant donné que je crée une campagne
Quand j'upload un audio de 8 secondes
Alors une erreur s'affiche: "Durée minimale: 10 secondes"
Quand j'upload un audio de 65 secondes
Alors une erreur s'affiche: "Durée maximale: 60 secondes"
Quand j'upload un audio de 30 secondes
Alors le fichier est accepté
16. Prépaiement obligatoire via Mangopay
Étant donné que j'ai configuré une campagne à 300€
Quand j'arrive à l'étape de paiement
Alors je dois payer les 300€ avant validation Et le paiement est traité via Mangopay Et seule la carte bancaire est acceptée
17. Recharge automatique optionnelle
Étant donné que j'ai une campagne active
Quand je configure la recharge automatique à 10% du budget
Alors si le budget restant passe sous 30€ (10% de 300€) Et que la campagne recharge automatiquement 100€ Et ma carte bancaire est débitée de 100€ Et le budget total passe à 130€
18. Désactivation recharge automatique
Étant donné que j'ai activé la recharge automatique
Quand je désactive cette option
Alors aucune recharge ne se produit automatiquement Et la campagne s'arrête quand le budget atteint 0€
19. Étalement budget sur période longue
Étant donné une campagne avec:
| Budget total | 1000€ |
|---|---|
| Durée | 30 j |
Quand le système calcule l'étalement
Alors le budget/jour est de 33.33€ Et si le budget se consomme plus vite (ex: 50€/jour) Alors une alerte "Budget épuisé dans 10 jours" est envoyée
20. Estimation population cible selon zone
Étant donné que je sélectionne la zone "Marseille"
Quand le système calcule la population cible
Alors l'estimation affichée est "~15 000 utilisateurs potentiels" Et un message "Estimation basée sur utilisateurs actifs dans la zone" s'affiche
21. Campagne avec date de début différée
Étant donné que je crée une campagne
Quand je définis la date de début au 2026-03-01 (dans 1 mois)
Alors la campagne a le statut "Programmée" Et elle démarre automatiquement le 2026-03-01 à 00h00 Et le budget n'est pas consommé avant cette date
22. Interface self-service accessible
Étant donné que je suis un publicitaire
Quand j'accède à l'interface publicitaire
Alors je peux créer une campagne sans contact commercial RoadWave Et toutes les options sont configurables en autonomie Et un tutoriel guidé est disponible (première utilisation)
23. Aperçu zone ciblée sur carte interactive
Étant donné que je configure une zone géographique
Quand je sélectionne "Département du Var"
Alors une carte Leaflet affiche les limites du département en surbrillance Et un compteur "~50 000 utilisateurs actifs" est affiché Et je peux zoomer/dézoomer pour visualiser la zone
24. Tags multiples pour ciblage affiné
Étant donné que je crée une campagne pour un restaurant
Quand je sélectionne les tags:
| Tag |
|---|
| Gastronomie |
| Tourisme |
| Famille |
Alors la publicité est prioritaire pour utilisateurs intéressés par ces 3 thèmes Et le score de ciblage combine les 3 jauges d'intérêt
25. Validation des dates de campagne
Étant donné que je crée une campagne
Quand je définis une date de début postérieure à la date de fin
Alors une erreur s'affiche: "Date de fin doit être après date de début" Et la campagne n'est pas créée
26. Durée minimale de campagne
Étant donné que je crée une campagne
Quand je définis une durée de moins de 24 heures
Alors une erreur s'affiche: "Durée minimale: 1 jour" Et je dois ajuster les dates
27. Durée maximale de campagne
Étant donné que je crée une campagne
Quand je définis une durée de plus de 90 jours
Alors une erreur s'affiche: "Durée maximale: 90 jours" Et je dois ajuster les dates ou créer plusieurs campagnes
28. 📋 Plan: Calcul budget quotidien selon durée
Étant donné une campagne avec un budget de €
Quand la durée est de jours
Alors le budget quotidien est de <budget_jour>€/jour
📊 Exemples de données:
| budget | duree | budget_jour |
|---|---|---|
| 100 | 10 | 10.00 |
| 300 | 14 | 21.43 |
| 500 | 30 | 16.67 |
| 1000 | 60 | 16.67 |
29. 📋 Plan: Estimation diffusions selon budget
Étant donné un budget quotidien de <budget_jour>€
Quand le coût par écoute complète est 0.05€
Alors le nombre estimé de diffusions/jour est
📊 Exemples de données:
| budget_jour | diffusions |
|---|---|
| 10.00 | 200 |
| 21.43 | 429 |
| 50.00 | 1000 |
| 100.00 | 2000 |
30. 📋 Plan: Formats audio acceptés/rejetés
Étant donné que j'upload un fichier
Quand le format est
Alors le résultat est
📊 Exemples de données:
| fichier | format | resultat |
|---|---|---|
| pub.mp3 | MP3 | accepté |
| pub.aac | AAC | accepté |
| pub.m4a | AAC | accepté |
| pub.wav | WAV | rejeté |
| pub.ogg | OGG | rejeté |
| pub.flac | FLAC | rejeté |
Caractéristiques et facturation des publicités
En tant que système RoadWave Je veux appliquer des règles précises de durée, skippabilité et facturation Afin d'équilibrer expérience utilisateur et rentabilité publicitaire
32 scénarios (29 standards, 3 plans)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un utilisateur gratuit écoute du contenu
1. Durée minimale 10 secondes
Étant donné qu'un publicitaire uploade une publicité de 8 secondes
Quand le système valide la durée
Alors une erreur s'affiche: "Durée minimale: 10 secondes" Et l'upload est rejeté
2. Durée maximale 60 secondes
Étant donné qu'un publicitaire uploade une publicité de 65 secondes
Quand le système valide la durée
Alors une erreur s'affiche: "Durée maximale: 60 secondes" Et l'upload est rejeté
3. Durée recommandée 15-30 secondes
Étant donné qu'un publicitaire crée une campagne
Quand il voit les recommandations
Alors un message s'affiche:
4. Publicité de 10 secondes acceptée
Étant donné qu'un publicitaire uploade une publicité de 10 secondes
Quand le système valide la durée
Alors le fichier est accepté Et aucune erreur n'est affichée
5. Publicité de 60 secondes acceptée
Étant donné qu'un publicitaire uploade une publicité de 60 secondes
Quand le système valide la durée
Alors le fichier est accepté Et un avertissement s'affiche: "⚠️ Durée longue: taux de skip potentiellement élevé"
6. Délai minimum skippable 5 secondes par défaut
Étant donné qu'une publicité de 30 secondes démarre Et que le délai minimal est configuré à 5 secondes
Quand j'écoute pendant 3 secondes
Alors le bouton "Passer" n'est pas visible Et je dois attendre 2 secondes supplémentaires
Quand j'atteins 5 secondes d'écoute
Alors le bouton "Passer" apparaît Et je peux cliquer pour passer au contenu suivant
7. Délai minimum paramétrable admin (3 secondes)
Étant donné que l'admin configure le délai à 3 secondes Et qu'une publicité démarre
Quand j'écoute pendant 3 secondes
Alors le bouton "Passer" apparaît immédiatement Et je peux skipper
8. Délai minimum paramétrable admin (10 secondes)
Étant donné que l'admin configure le délai à 10 secondes Et qu'une publicité démarre
Quand j'écoute pendant 9 secondes
Alors le bouton "Passer" n'est toujours pas visible
Quand j'atteins 10 secondes
Alors le bouton "Passer" apparaît
9. Facturation écoute complète (>80%) - 0.05€
Étant donné qu'une publicité de 30 secondes est diffusée
Quand j'écoute pendant 25 secondes (83%)
Alors l'écoute est considérée comme "complète" Et le publicitaire est facturé 0.05€ Et le compteur "écoutes complètes" s'incrémente
10. Facturation écoute complète exactement 80%
Étant donné qu'une publicité de 30 secondes est diffusée
Quand j'écoute pendant exactement 24 secondes (80%)
Alors l'écoute est considérée comme "complète" Et le publicitaire est facturé 0.05€
11. Facturation skip après délai minimal - 0.02€
Étant donné qu'une publicité de 30 secondes est diffusée Et que le délai minimal est 5 secondes
Quand j'écoute pendant 10 secondes (33%) Et que je clique sur "Passer"
Alors l'écoute est considérée comme "partielle" Et le publicitaire est facturé 0.02€
12. Facturation skip immédiat (<5s) - 0€
Étant donné qu'une publicité de 30 secondes est diffusée Et que le délai minimal est 5 secondes
Quand j'écoute pendant 3 secondes Et que je clique sur "Suivant" (pas de bouton skip encore)
Alors l'écoute est considérée comme "non engagée" Et le publicitaire n'est PAS facturé (0€)
13. Comptabilisation écoute complète à 79%
Étant donné qu'une publicité de 30 secondes est diffusée
Quand j'écoute pendant 23 secondes (77%)
Alors l'écoute est considérée comme "partielle" (pas complète) Et le publicitaire est facturé 0.02€
14. Comptabilisation écoute complète à 100%
Étant donné qu'une publicité de 30 secondes est diffusée
Quand j'écoute les 30 secondes complètes (100%)
Alors l'écoute est considérée comme "complète" Et le publicitaire est facturé 0.05€
15. Budget consommé selon mix écoutes
Étant donné qu'une campagne à 300€ a généré:
| Type écoute | Nombre | Coût unitaire | Total |
|---|---|---|---|
| Complète (>80%) | 4000 | 0.05€ | 200€ |
| Partielle (5-80%) | 2000 | 0.02€ | 40€ |
| Skip immédiat | 1000 | 0€ | 0€ |
Quand je calcule le budget consommé
Alors le total est 240€ Et il reste 60€ de budget disponible
16. Affichage compteur secondes restantes
Étant donné qu'une publicité de 30s démarre Et que le délai minimal est 5s
Quand j'écoute pendant 2 secondes
Alors un compteur s'affiche: "Passer dans 3s..."
Quand j'atteins 5 secondes
Alors le compteur disparaît Et le bouton "Passer la publicité" s'affiche
17. Progress bar publicité visible
Étant donné qu'une publicité de 30s est en lecture
Quand 10 secondes se sont écoulées
Alors la progress bar affiche 33% (10/30) Et l'indicateur temporel affiche "0:10 / 0:30" Et l'utilisateur visualise la progression
18. Message "Publicité" clairement affiché
Étant donné qu'une publicité démarre
Quand l'audio commence
Alors un badge "Publicité" est affiché en haut de l'écran Et la durée totale est indiquée: "Publicité (30s)" Et la transparence est maximale (utilisateur sait que c'est une pub)
19. Transition fluide après publicité
Étant donné qu'une publicité de 30s se termine
Quand la lecture atteint 30 secondes
Alors le délai de transition de 2s démarre Et le contenu normal suivant est annoncé Et l'enchaînement est naturel (même UX que entre contenus)
20. Like autorisé sur publicité
Étant donné qu'une publicité est en lecture Et que le véhicule est à l'arrêt
Quand je clique sur le bouton cœur
Alors un like explicite (+2%) est enregistré Et mes jauges d'intérêt sont mises à jour selon les tags de la pub Et le publicitaire voit un compteur "Likes" incrémenté
21. Abonnement autorisé sur publicité
Étant donné qu'une publicité est diffusée par un créateur Et que le véhicule est à l'arrêt
Quand je clique sur "S'abonner"
Alors l'abonnement est enregistré (+5% jauges) Et le publicitaire bénéficie de l'engagement fort Et cela compte comme une conversion majeure
22. Bouton skip visible et accessible
Étant donné qu'une publicité a dépassé le délai minimal
Quand le bouton "Passer" s'affiche
Alors il est positionné en bas à droite de l'écran Et il a une taille de clic confortable (44×44px minimum iOS) Et il est clairement visible (contraste élevé)
23. Analytics tracking précis par type
Étant donné qu'une publicité est diffusée
Quand un événement se produit
Alors il est tracké en temps réel:
| Événement | Données enregistrées |
|---|---|
| Impression | timestamp, user_id, pub_id, zone_geo |
| Écoute complète | durée_ecoutee, pourcentage, coût (0.05€) |
| Skip après délai | durée_ecoutee, pourcentage, coût (0.02€) |
| Skip immédiat | durée_ecoutee, pourcentage, coût (0€) |
| Like | timestamp, tags impactés |
| Abonnement | timestamp, creator_id |
24. Recommandation sweet spot 15-30s
Étant donné les statistiques RoadWave globales:
| Durée pub | Taux complétion moyen |
|---|---|
| 10s | 65% |
| 15s | 55% |
| 30s | 45% |
| 45s | 30% |
| 60s | 20% |
Quand un publicitaire consulte les recommandations
Alors le sweet spot affiché est "15-30 secondes" Et l'explication est "Meilleur compromis engagement/message"
25. Optimisation durée selon taux de skip campagne
Étant donné qu'une campagne de 60s a un taux de skip de 85%
Quand le publicitaire consulte les recommandations
Alors le système suggère:
26. Coût effectif moyen (CEM) calculé
Étant donné une campagne avec:
| Type écoute | Nombre | Coût unitaire | Total |
|---|---|---|---|
| Complète | 2000 | 0.05€ | 100€ |
| Partielle | 3000 | 0.02€ | 60€ |
| Skip immédiat | 1000 | 0€ | 0€ |
Quand je calcule le coût effectif moyen
Alors CEM = 160€ / 6000 impressions = 0.027€/impression Et cette métrique aide à comparer avec CPM industrie
27. Publicité non skippable interdite
Étant donné qu'un publicitaire demande "Publicité non skippable"
Quand il configure sa campagne
Alors cette option n'existe pas Et toutes les publicités sont obligatoirement skippables après 5s minimum
28. Délai minimal jamais <3 secondes
Étant donné qu'un admin essaie de configurer le délai à 2 secondes
Quand il valide le paramètre
Alors une erreur s'affiche: "Délai minimal: 3 secondes minimum"
29. Délai minimal jamais >10 secondes
Étant donné qu'un admin essaie de configurer le délai à 15 secondes
Quand il valide le paramètre
Alors une erreur s'affiche: "Délai maximal: 10 secondes maximum"
30. 📋 Plan: Facturation selon durée écoutée
Étant donné qu'une publicité de 30s est diffusée
Quand j'écoute pendant s (%)
Alors le type d'écoute est Et le coût facturé est €
📊 Exemples de données:
| duree | pourcentage | type | cout |
|---|---|---|---|
| 3 | 10 | skip immédiat | 0 |
| 5 | 17 | partielle | 0.02 |
| 10 | 33 | partielle | 0.02 |
| 20 | 67 | partielle | 0.02 |
| 24 | 80 | complète | 0.05 |
| 27 | 90 | complète | 0.05 |
| 30 | 100 | complète | 0.05 |
31. 📋 Plan: Budget consommé selon distribution écoutes
Étant donné écoutes complètes à 0.05€ Et écoutes partielles à 0.02€ Et skips immédiats à 0€
Quand je calcule le budget total consommé
Alors le résultat est <budget_total>€
📊 Exemples de données:
| completes | partielles | skips | budget_total |
|---|---|---|---|
| 1000 | 500 | 100 | 60 |
| 2000 | 1000 | 500 | 120 |
| 5000 | 2000 | 1000 | 290 |
| 0 | 1000 | 0 | 20 |
| 1000 | 0 | 0 | 50 |
32. 📋 Plan: Apparition bouton skip selon délai configuré
Étant donné que le délai minimal est configuré à s
Quand j'écoute pendant <temps_ecoute>s
Alors le bouton "Passer" est
📊 Exemples de données:
| delai | temps_ecoute | visible |
|---|---|---|
| 5 | 3 | non visible |
| 5 | 5 | visible |
| 5 | 10 | visible |
| 10 | 8 | non visible |
| 10 | 10 | visible |
| 3 | 2 | non visible |
| 3 | 3 | visible |
Gestion du budget et alertes publicitaires
En tant que publicitaire Je veux suivre en temps réel mon budget et recevoir des alertes Afin de maîtriser mes dépenses et optimiser mes campagnes
30 scénarios (27 standards, 3 plans)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un compte publicitaire est connecté Et qu'une campagne active est en cours
1. Dashboard budget temps réel
Étant donné que ma campagne a un budget de 300€ Et que j'ai consommé 220€
Quand je consulte le dashboard budget
Alors je vois:
| Métrique | Valeur |
|---|---|
| Budget total | 300€ |
| Budget consommé | 220€ |
| Budget restant | 80€ |
| Pourcentage | 73% consommé |
2. Jauge visuelle budget consommé
Étant donné que j'ai consommé 220€ sur 300€
Quand je consulte le dashboard
Alors une jauge de progression affiche 73% Et la couleur est orange (seuil 50-80%) Et un indicateur "80€ restants" est affiché clairement
3. Couleur jauge selon seuil
Étant donné un budget de 300€
Quand j'ai consommé 150€ (50%)
Alors la jauge est verte
Quand j'ai consommé 240€ (80%)
Alors la jauge est orange
Quand j'ai consommé 285€ (95%)
Alors la jauge est rouge Et un message "Budget presque épuisé" s'affiche
4. Projection épuisement budget
Étant donné que j'ai consommé 220€ en 10 jours Et qu'il reste 4 jours de campagne
Quand le système calcule la projection
Alors la consommation quotidienne moyenne est 22€/jour Et la projection affiche "Budget épuisé dans 3.6 jours" Et un avertissement "Campagne s'arrêtera avant la fin prévue" s'affiche
5. Projection avec budget suffisant
Étant donné que j'ai consommé 100€ en 10 jours Et qu'il reste 4 jours de campagne Et que le budget total est 300€
Quand le système calcule la projection
Alors la consommation quotidienne moyenne est 10€/jour Et la projection affiche "Budget suffisant pour toute la campagne" Et le budget restant estimé à la fin est 160€
6. Alerte 80% budget consommé
Étant donné que mon budget est de 300€
Quand je consomme 240€ (80%)
Alors je reçois immédiatement un email: Et une notification push est envoyée Et une notification in-app s'affiche
7. Alerte 90% budget consommé
Étant donné que mon budget est de 300€
Quand je consomme 270€ (90%)
Alors je reçois immédiatement un email:
8. Alerte budget épuisé (100%)
Étant donné que mon budget est de 300€
Quand je consomme les 300€ (100%)
Alors je reçois immédiatement un email: Et la campagne est automatiquement mise en pause Et plus aucune diffusion ne se produit
9. Pause manuelle de campagne
Étant donné que ma campagne est active Et qu'il reste 150€ de budget
Quand je clique sur "Mettre en pause"
Alors le statut passe à "En pause" Et les diffusions s'arrêtent immédiatement Et le budget de 150€ est conservé Et je peux réactiver la campagne plus tard
10. Reprise campagne pausée
Étant donné que ma campagne est en pause Et qu'il reste 150€ de budget
Quand je clique sur "Reprendre la campagne"
Alors le statut passe à "Active" Et les diffusions reprennent immédiatement Et le budget restant de 150€ continue de se consommer
11. Prolongation campagne avec recharge
Étant donné que ma campagne se termine dans 2 jours Et qu'il reste 20€ de budget
Quand je clique sur "Prolonger la campagne" Et que j'ajoute 200€ supplémentaires
Alors le budget total passe à 220€ Et la date de fin peut être prolongée de 10 jours Et un nouveau paiement Mangopay de 200€ est traité
12. Recharge automatique activée
Étant donné que j'ai configuré la recharge automatique Et que le seuil est fixé à 10% (30€ sur budget 300€) Et que le montant de recharge est 100€
Quand le budget restant passe sous 30€
Alors une recharge automatique de 100€ est déclenchée Et ma carte bancaire est débitée via Mangopay Et le budget total passe à budget_restant + 100€ Et je reçois un email de confirmation
13. Échec recharge automatique (carte expirée)
Étant donné que la recharge automatique est activée Et que ma carte bancaire a expiré
Quand le budget passe sous le seuil de 10%
Alors la recharge automatique échoue Et je reçois un email urgent: Et la campagne continue jusqu'à épuisement du budget restant
14. Modification ciblage si budget <50% consommé
Étant donné que j'ai consommé 120€ sur 300€ (40%)
Quand j'essaie de modifier le ciblage géographique
Alors la modification est autorisée Et le ciblage est mis à jour immédiatement Et les nouvelles diffusions utilisent le nouveau ciblage
15. Blocage modification ciblage si budget >50% consommé
Étant donné que j'ai consommé 180€ sur 300€ (60%)
Quand j'essaie de modifier le ciblage géographique
Alors une erreur s'affiche:
16. Modification audio nécessite nouvelle validation
Étant donné que ma campagne est active
Quand je veux modifier le fichier audio
Alors un message s'affiche:
17. Modification plages horaires autorisée
Étant donné que ma campagne cible 7h-9h et 17h-19h
Quand je modifie pour cibler 12h-14h aussi
Alors la modification est appliquée immédiatement Et les diffusions suivantes incluent la nouvelle plage Et aucune re-validation n'est nécessaire
18. Historique consommation budget jour par jour
Étant donné que ma campagne a duré 10 jours
Quand je consulte l'historique
Alors je vois un graphique avec:
| Jour | Consommation | Cumulé |
|---|---|---|
| 1 | 22€ | 22€ |
| 2 | 25€ | 47€ |
| 3 | 20€ | 67€ |
| ... | ... | ... |
| 10 | 18€ | 220€ |
Et je peux identifier les pics de consommation
19. Notification fin de campagne programmée
Étant donné que ma campagne se termine le 14/02
Quand la date de fin est atteinte
Alors je reçois un email:
20. Remboursement budget non utilisé
Étant donné que ma campagne avait 300€ de budget Et qu'elle s'est terminée avec 280€ consommés
Quand la campagne se termine (date ou épuisement)
Alors un remboursement de 20€ est initié via Mangopay Et le délai est de 5-7 jours ouvrés Et je reçois une notification de confirmation
21. Aucun remboursement si budget entièrement consommé
Étant donné que ma campagne avait 300€ de budget Et qu'elle s'est terminée avec 300€ consommés
Quand la campagne se termine
Alors aucun remboursement n'est initié Et le message final indique "Budget entièrement utilisé"
22. Statistiques comparatives budget vs objectif
Étant donné que j'avais défini un objectif de 5000 impressions Et que mon budget était 300€
Quand je consulte les statistiques finales
Alors je vois:
| Métrique | Objectif | Réalisé | Écart |
|---|---|---|---|
| Impressions | 5000 | 6000 | +20% |
| Budget | 300€ | 280€ | -7% |
| Coût/impression | 0.06€ | 0.047€ | -22% |
Et une analyse "✅ Objectifs dépassés avec budget optimisé"
23. Export rapport financier détaillé
Étant donné que je veux analyser mes dépenses
Quand je clique sur "Exporter rapport financier"
Alors je télécharge un CSV avec:
| Colonne |
|---|
| Date/Heure |
| Type écoute |
| Coût unitaire |
| Zone géographique |
| Utilisateur (anonyme) |
| Durée écoutée |
Et je peux l'importer dans Excel pour analyses
24. Tableau de bord multi-campagnes
Étant donné que j'ai 3 campagnes actives
Quand je consulte la vue d'ensemble
Alors je vois un tableau récapitulatif:
| Campagne | Budget | Consommé | % | Jours restants | Projection |
|---|---|---|---|---|---|
| A | 300€ | 220€ | 73 | 4j | Suffisant |
| B | 500€ | 480€ | 96 | 10j | Épuisé 2j |
| C | 200€ | 50€ | 25 | 20j | Suffisant |
Et un badge alerte rouge sur la campagne B
25. Alerte consolidée multi-campagnes
Étant donné que j'ai 5 campagnes actives Et que 2 campagnes ont >80% budget consommé
Quand je reçois les notifications
Alors un email consolidé unique est envoyé: Et je ne reçois pas 2 emails séparés (évite spam)
26. Configuration seuils alertes personnalisés
Étant donné que je configure mes préférences d'alerte
Quand je définis les seuils:
| Seuil | Valeur |
|---|---|
| Alerte 1 | 70% |
| Alerte 2 | 85% |
| Alerte 3 | 95% |
Alors je reçois des alertes à 70%, 85% et 95% Et non aux seuils par défaut 80%, 90%, 100%
27. Désactivation alertes email
Étant donné que je préfère uniquement les notifications in-app
Quand je désactive les alertes email dans mes préférences
Alors je ne reçois plus d'emails d'alerte budget Mais les notifications in-app continuent Et les alertes critiques (échec paiement) sont toujours envoyées par email
28. 📋 Plan: Couleur jauge selon pourcentage consommé
Étant donné un budget de 300€
Quand j'ai consommé € (%)
Alors la couleur de la jauge est
📊 Exemples de données:
| montant | pourcentage | couleur |
|---|---|---|
| 100 | 33 | verte |
| 150 | 50 | verte |
| 180 | 60 | orange |
| 240 | 80 | orange |
| 270 | 90 | rouge |
| 285 | 95 | rouge |
| 300 | 100 | rouge |
29. 📋 Plan: Projection épuisement selon consommation
Étant donné un budget de 300€ Et une consommation actuelle de € Et une durée écoulée de <jours_ecoules> jours
Quand je calcule la consommation quotidienne moyenne
Alors elle est de <conso_jour>€/jour Et le budget sera épuisé dans <jours_restants> jours
📊 Exemples de données:
| consomme | jours_ecoules | conso_jour | jours_restants |
|---|---|---|---|
| 100 | 5 | 20 | 10 |
| 200 | 10 | 20 | 5 |
| 150 | 10 | 15 | 10 |
| 270 | 12 | 22.5 | 1.3 |
30. 📋 Plan: Alertes envoyées selon seuils
Étant donné un budget de 500€
Quand je consomme € (%)
Alors je reçois une alerte
📊 Exemples de données:
| montant | pourcentage | niveau |
|---|---|---|
| 350 | 70 | aucune |
| 400 | 80 | alerte 80% |
| 450 | 90 | alerte 90% |
| 500 | 100 | budget épuisé |
Insertion et fréquence des publicités
En tant que système RoadWave Je veux insérer les publicités de manière équilibrée et non intrusive Afin de préserver l'expérience utilisateur tout en monétisant
31 scénarios (28 standards, 3 plans)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un utilisateur gratuit est connecté
1. Fréquence par défaut 1 pub / 5 contenus
Étant donné que la fréquence par défaut est configurée à 1/5 Et que je suis un utilisateur gratuit
Quand j'écoute 5 contenus
Alors 1 publicité est insérée après le 5ème contenu
Quand j'écoute 10 contenus
Alors 2 publicités sont insérées (après les contenus 5 et 10)
2. Aucune publicité pour utilisateurs Premium
Étant donné que je suis un utilisateur Premium
Quand j'écoute 100 contenus
Alors aucune publicité n'est insérée Et je bénéficie d'une expérience sans interruption publicitaire
3. Fréquence paramétrable par admin (1/3)
Étant donné que l'admin configure la fréquence à 1/3 Et que je suis un utilisateur gratuit
Quand j'écoute 6 contenus
Alors 2 publicités sont insérées (après contenus 3 et 6)
4. Fréquence paramétrable par admin (1/10)
Étant donné que l'admin configure la fréquence à 1/10 Et que je suis un utilisateur gratuit
Quand j'écoute 20 contenus
Alors 2 publicités sont insérées (après contenus 10 et 20)
5. Jamais d'interruption d'un contenu en cours
Étant donné que j'écoute un contenu de 10 minutes Et que je suis à 5 minutes de lecture Et qu'une publicité devrait être insérée selon la fréquence
Quand le système vérifie l'insertion
Alors la publicité attend la fin du contenu actuel Et elle s'insère pendant le délai de transition (2s) Et le contenu n'est jamais interrompu
6. Insertion entre deux contenus uniquement
Étant donné que le contenu "A" se termine Et que le délai de transition de 2s démarre
Quand le système détecte qu'une publicité doit être insérée
Alors le message "Publicité (30s)" s'affiche Et la publicité démarre après les 2 secondes Et l'enchaînement est naturel et fluide
7. Rotation limite 3 fois/jour par utilisateur
Étant donné qu'un utilisateur a entendu la publicité "A" 3 fois aujourd'hui
Quand le système sélectionne une nouvelle publicité à diffuser
Alors la publicité "A" n'est plus éligible pour cet utilisateur aujourd'hui Et une autre publicité "B" est sélectionnée Et cela évite la saturation publicitaire
8. Compteur de diffusions par pub et par utilisateur
Étant donné qu'un utilisateur écoute la pub "RestaurantX"
Quand la diffusion se termine
Alors un compteur Redis "pub:RestaurantX:user:123:count" s'incrémente Et le TTL est de 24h (reset à minuit)
Quand le compteur atteint 3
Alors la pub "RestaurantX" est exclue des prochaines sélections aujourd'hui
9. Limite max 6 pubs/heure par utilisateur
Étant donné qu'un utilisateur a entendu 6 publicités dans la dernière heure
Quand le système devrait insérer une 7ème pub
Alors l'insertion est reportée à l'heure suivante Et un compteur horaire Redis "pub:user:123:hourly" est vérifié Et cela évite le spam publicitaire
10. Ciblage géographique prioritaire - Point GPS
Étant donné qu'une publicité cible un point GPS à 2km de ma position Et qu'une autre publicité cible ma ville entière
Quand le système sélectionne une publicité
Alors la publicité point GPS est priorisée (score géo plus élevé) Et le ciblage précis est favorisé
11. Ciblage géographique prioritaire - Hiérarchie
Étant donné que 4 publicités sont éligibles:
| Publicité | Zone | Distance |
|---|---|---|
| A | Point GPS | 1km |
| B | Ville | 0km |
| C | Département | 0km |
| D | National | N/A |
Quand le système sélectionne selon priorité géographique
Alors l'ordre de priorité est: A > B > C > D Et la publicité A (Point GPS, la plus précise) est diffusée
12. Ciblage centres d'intérêt secondaire
Étant donné que 2 publicités ciblent ma zone géographique:
| Publicité | Tags | Mes jauges |
|---|---|---|
| A | Automobile | 80% |
| B | Voyage | 40% |
Quand le système applique le score centres d'intérêt
Alors la publicité A est favorisée (meilleur match jauges) Et le ciblage thématique affine la sélection
13. Ciblage horaire strict
Étant donné qu'une campagne cible uniquement 7h-9h Et qu'il est 10h30
Quand le système sélectionne une publicité
Alors cette campagne n'est PAS éligible Et seules les campagnes "toute la journée" ou avec plage horaire actuelle sont considérées
14. Ciblage horaire pendant plage active
Étant donné qu'une campagne cible 7h-9h et 17h-19h Et qu'il est 8h15
Quand le système sélectionne une publicité
Alors cette campagne est éligible Et elle peut être diffusée
15. Normalisation volume audio -14 LUFS
Étant donné qu'une publicité est uploadée avec volume trop élevé (-6 LUFS)
Quand le système encode l'audio via FFmpeg
Alors le volume est normalisé automatiquement à -14 LUFS Et le publicitaire reçoit une notification "Volume audio ajusté pour conformité" Et cela évite l'effet "pub trop forte" frustrant
16. Validation volume audio lors encodage
Étant donné qu'une publicité est soumise
Quand FFmpeg encode le fichier
Alors une commande loudnorm est appliquée: Et le fichier final respecte le standard broadcast -14 LUFS
17. Sélection aléatoire si critères équivalents
Étant donné que 3 publicités ont le même score géo Et qu'elles ont toutes des jauges centres d'intérêt équivalentes Et qu'aucune n'a été diffusée 3 fois aujourd'hui
Quand le système sélectionne une publicité
Alors une sélection aléatoire équitable est faite Et chaque campagne a 33% de chances d'être diffusée
18. Exclusion publicités avec budget épuisé
Étant donné qu'une campagne "A" a épuisé son budget Et qu'une campagne "B" a encore du budget disponible
Quand le système sélectionne une publicité
Alors seule la campagne "B" est éligible Et la campagne "A" est automatiquement exclue
19. Exclusion publicités hors dates de campagne
Étant donné qu'une campagne "A" est programmée du 01/02 au 14/02 Et que nous sommes le 20/01
Quand le système sélectionne une publicité
Alors la campagne "A" n'est pas éligible Et seules les campagnes actives aujourd'hui sont considérées
20. Publicité visible uniquement dans zone géographique
Étant donné qu'une publicité cible "Marseille uniquement" Et que je suis à Lyon
Quand le système sélectionne une publicité
Alors cette publicité n'est jamais éligible pour moi Et je ne la verrai jamais tant que je reste à Lyon
21. Tracking compteur horaire avec TTL
Étant donné qu'un utilisateur entend une pub à 10h05
Quand le compteur horaire est incrémenté
Alors la clé Redis "pub:user:123:hourly:2026012110" est créée Et le TTL est de 1 heure (expire à 11h05) Et le système compte les pubs dans la fenêtre glissante d'1h
22. Reset compteur quotidien à minuit
Étant donné qu'un utilisateur a entendu la pub "A" 3 fois le 20/01
Quand minuit passe et on est le 21/01
Alors le compteur "pub:A:user:123:count" est expiré (TTL 24h) Et l'utilisateur peut à nouveau entendre la pub "A" jusqu'à 3 fois
23. Aucune pub si aucune campagne éligible
Étant donné qu'aucune campagne n'a de budget disponible
Quand le système devrait insérer une publicité
Alors aucune pub n'est insérée Et l'enchaînement de contenus continue normalement Et le prochain contenu démarre directement
24. Priorisation campagnes avec budget important restant
Étant donné que 2 campagnes sont éligibles:
| Campagne | Budget restant | Jours restants |
|---|---|---|
| A | 500€ | 2j |
| B | 50€ | 10j |
Quand le système applique la priorisation budgétaire
Alors la campagne A est légèrement favorisée (urgence dépense) Et cela aide à épuiser les budgets avant fin de campagne
25. Log des sélections pour analytics
Étant donné qu'une publicité "RestaurantX" est sélectionnée
Quand elle est diffusée à l'utilisateur "123"
Alors un événement est loggé en base:
| Champ | Valeur |
|---|---|
| pub_id | RestaurantX |
| user_id | 123 |
| timestamp | 2026-01-21 10:30 |
| zone_geo | Marseille |
| score_geo | 0.85 |
| score_interet | 0.70 |
Et cela permet l'analytics publicitaire
26. Détection changement statut utilisateur (gratuit → premium)
Étant donné que je suis un utilisateur gratuit Et que j'entends des publicités
Quand je souscris à Premium
Alors le système détecte le changement de statut immédiatement Et plus aucune publicité n'est insérée dès le prochain contenu Et mon expérience devient sans pub instantanément
27. Interface admin pour ajuster fréquence globale
Étant donné que je suis admin RoadWave
Quand j'accède aux paramètres publicitaires
Alors je peux ajuster le curseur de fréquence:
| Option | Fréquence |
|---|---|
| 1/3 | Haute (agressif) |
| 1/5 | Standard (défaut) |
| 1/7 | Modérée |
| 1/10 | Faible |
Et le changement s'applique en temps réel à tous les utilisateurs
28. A/B testing fréquence sur cohortes utilisateurs
Étant donné que l'admin active un test A/B
Quand 50% des utilisateurs ont fréquence 1/5 Et 50% des utilisateurs ont fréquence 1/7
Alors les métriques sont trackées séparément:
| Cohorte | Fréquence | Taux désabonnement | Revenus/user |
|---|---|---|---|
| A | 1/5 | 2.5% | 0.50€ |
| B | 1/7 | 1.8% | 0.40€ |
Et l'admin peut identifier la fréquence optimale
29. 📋 Plan: Insertion publicité selon fréquence
Étant donné que la fréquence est
Quand j'écoute contenus
Alors publicités sont insérées
📊 Exemples de données:
| frequence | contenus | pubs |
|---|---|---|
| 1/3 | 9 | 3 |
| 1/5 | 10 | 2 |
| 1/5 | 25 | 5 |
| 1/7 | 14 | 2 |
| 1/10 | 30 | 3 |
30. 📋 Plan: Priorité géographique selon type zone
Étant donné qu'une publicité cible <type_zone>
Quand le système calcule le score géographique
Alors la priorité est
📊 Exemples de données:
| type_zone | score |
|---|---|
| Point GPS | 1.0 |
| Ville | 0.8 |
| Département | 0.6 |
| Région | 0.4 |
| National | 0.2 |
31. 📋 Plan: Exclusion publicité selon compteur quotidien
Étant donné qu'une publicité a été entendue fois aujourd'hui
Quand le système vérifie l'éligibilité
Alors la publicité est
📊 Exemples de données:
| fois | eligible |
|---|---|
| 0 | éligible |
| 1 | éligible |
| 2 | éligible |
| 3 | non éligible |
| 4 | non éligible |
Métriques d'engagement et dashboard publicitaire
En tant que publicitaire Je veux consulter des métriques détaillées en temps réel Afin d'optimiser mes campagnes et mesurer leur ROI
27 scénarios (24 standards, 3 plans)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un compte publicitaire est connecté Et qu'une campagne active est en cours
1. Dashboard temps réel avec métriques essentielles
Étant donné que ma campagne a généré 1000 diffusions
Quand je consulte le dashboard
Alors je vois les métriques suivantes mises à jour en temps réel:
| Métrique | Valeur |
|---|---|
| Impressions | 1000 |
| Écoutes complètes (>80%) | 400 |
| Taux d'écoute complète | 40% |
| Taux de skip | 60% |
| Durée moyenne d'écoute | 18s |
| Likes | 25 |
| Abonnements | 5 |
| Coût par écoute | 0.05€ |
2. Calcul impressions totales
Étant donné que ma publicité a été diffusée 2500 fois
Quand je consulte le dashboard
Alors le compteur "Impressions" affiche 2500 Et il s'incrémente en temps réel à chaque nouvelle diffusion
3. Calcul écoutes complètes (>80%)
Étant donné que ma publicité de 30s a été:
| Durée écoutée | Nombre |
|---|---|
| 25s (83%) | 300 |
| 20s (67%) | 200 |
| 10s (33%) | 150 |
| 5s (17%) | 50 |
Quand je consulte les écoutes complètes
Alors le compteur affiche 300 (uniquement ≥80%) Et le taux d'écoute complète est de 43% (300/700)
4. Calcul taux de skip
Étant donné 1000 diffusions totales Et 400 écoutes complètes
Quand je consulte le taux de skip
Alors il affiche 60% ((1000-400)/1000) Et il est calculé comme (total - complètes) / total
5. Durée moyenne d'écoute calculée
Étant donné que ma publicité de 30s a été écoutée:
| Durée | Nombre d'utilisateurs |
|---|---|
| 30s | 400 |
| 20s | 300 |
| 10s | 200 |
| 5s | 100 |
Quand je consulte la durée moyenne
Alors le calcul est: (30×400 + 20×300 + 10×200 + 5×100) / 1000 Et le résultat affiché est 21s
6. Métriques de likes sur publicité
Étant donné que 50 utilisateurs ont liké ma publicité
Quand je consulte le dashboard
Alors le compteur "Likes" affiche 50 Et un taux de like de 5% est calculé (50/1000 impressions) Et cela indique une forte appréciation du contenu
7. Métriques d'abonnements générés
Étant donné que 10 utilisateurs se sont abonnés après avoir entendu ma pub
Quand je consulte le dashboard
Alors le compteur "Abonnements" affiche 10 Et un taux de conversion de 1% est calculé (10/1000) Et cela représente un engagement très fort
8. Calcul coût par écoute (CPE)
Étant donné que j'ai dépensé 200€ Et obtenu 4000 écoutes complètes
Quand je consulte le coût par écoute
Alors le CPE affiché est 0.05€ (200/4000) Et il correspond au tarif standard RoadWave
9. Répartition géographique avec heatmap
Étant donné que ma campagne cible le département du Var Et que j'ai 1000 diffusions réparties:
| Zone | Diffusions | Pourcentage |
|---|---|---|
| Toulon | 400 | 40% |
| Hyères | 250 | 25% |
| Fréjus | 200 | 20% |
| Autres | 150 | 15% |
Quand je consulte la heatmap géographique
Alors une carte Leaflet affiche les zones avec intensité proportionnelle Et Toulon apparaît en rouge foncé (forte concentration) Et les autres villes en dégradé orange/jaune
10. Répartition horaire avec graphique
Étant donné que ma campagne cible les plages 7h-9h et 17h-19h Et que j'ai 1000 diffusions:
| Plage horaire | Diffusions |
|---|---|
| 7h-8h | 300 |
| 8h-9h | 250 |
| 17h-18h | 280 |
| 18h-19h | 170 |
Quand je consulte le graphique horaire
Alors un histogramme Chart.js affiche les 4 barres Et je peux identifier que 7h-8h est le pic d'écoute Et optimiser mes futures campagnes sur cette plage
11. Taux de complétion par tranche d'âge
Étant donné que ma campagne est Tout Public Et que j'ai des écoutes sur différentes tranches:
| Tranche d'âge | Écoutes complètes | Total diffusions | Taux |
|---|---|---|---|
| 18-24 ans | 120 | 400 | 30% |
| 25-34 ans | 200 | 400 | 50% |
| 35-44 ans | 80 | 200 | 40% |
Quand je consulte l'analyse par âge
Alors je vois que les 25-34 ans ont le meilleur taux (50%) Et je peux cibler cette tranche pour mes prochaines campagnes
12. Comparatif de campagnes A/B testing
Étant donné que j'ai 2 campagnes actives:
| Campagne | Budget | Écoutes complètes | Taux | CPE |
|---|---|---|---|---|
| A | 300€ | 4000 | 40% | 0.075€ |
| B | 300€ | 6000 | 60% | 0.05€ |
Quand je consulte le comparatif
Alors je vois que la campagne B performe mieux Et le tableau recommande "Campagne B: +50% écoutes, -33% CPE" Et je peux allouer plus de budget à la campagne B
13. Export données CSV pour analyse externe
Étant donné que je veux analyser mes données dans Excel
Quand je clique sur "Exporter CSV"
Alors je télécharge un fichier avec les colonnes:
| Colonne |
|---|
| Date |
| Heure |
| Zone géographique |
| Tranche d'âge |
| Durée écoute |
| Skip (Oui/Non) |
| Like (Oui/Non) |
| Abonnement (Oui/Non) |
Et je peux faire des analyses personnalisées
14. Export graphiques interactifs
Étant donné que je consulte le dashboard
Quand je clique sur un graphique Chart.js
Alors je peux zoomer/filtrer interactivement Et je peux exporter le graphique en PNG Et l'image est en haute résolution pour présentations
15. Rapport PDF automatique fin de campagne
Étant donné que ma campagne de 14 jours se termine
Quand la date de fin est atteinte
Alors un rapport PDF est généré automatiquement Et il contient:
| Section |
|---|
| Résumé exécutif |
| Métriques clés |
| Graphiques de performance |
| Heatmap géographique |
| Répartition horaire |
| Analyse tranches d'âge |
| Recommandations optimisation |
Et je reçois un email avec le PDF en pièce jointe
16. Métriques temps réel rafraîchies automatiquement
Étant donné que je consulte le dashboard à 10h00
Quand une nouvelle diffusion se produit à 10h01
Alors les métriques sont rafraîchies automatiquement (polling 30s) Et je vois les nouveaux chiffres sans recharger la page Et un badge "Mis à jour il y a 15s" s'affiche
17. Alertes performance personnalisées
Étant donné que je configure une alerte "Taux de skip >70%" Et que ma campagne atteint 72% de skip
Quand le seuil est dépassé
Alors je reçois un email d'alerte:
18. Benchmark vs moyennes RoadWave
Étant donné que ma campagne a 45% d'écoutes complètes
Quand je consulte le benchmark
Alors je vois "Votre taux: 45% | Moyenne RoadWave: 40%" Et un badge "📊 Performance: +12% vs moyenne" s'affiche Et je sais que ma campagne performe au-dessus de la moyenne
19. Coût total consommé vs budget
Étant donné que j'ai un budget de 300€ Et que j'ai consommé 220€
Quand je consulte le dashboard
Alors je vois une jauge "Budget consommé: 73%" (220/300) Et le montant restant "80€ restants" Et une projection "Épuisé dans 3 jours à ce rythme"
20. Répartition coûts par type d'écoute
Étant donné que j'ai dépensé 200€ avec:
| Type d'écoute | Nombre | Coût unitaire | Total |
|---|---|---|---|
| Écoute complète | 3000 | 0.05€ | 150€ |
| Skip après 5s | 2000 | 0.02€ | 40€ |
| Skip immédiat | 500 | 0€ | 0€ |
Quand je consulte la répartition
Alors un graphique camembert affiche:
| Segment | Pourcentage |
|---|---|
| Écoutes complètes | 75% (150€) |
| Skips partiels | 20% (40€) |
| Skips immédiats | 5% (0€) |
21. Évolution performance dans le temps
Étant donné une campagne de 30 jours
Quand je consulte le graphique d'évolution
Alors je vois une courbe Chart.js avec:
| Axe | Donnée |
|---|---|
| X | Jours (1-30) |
| Y | Taux d'écoute complète (%) |
Et je peux identifier les tendances (amélioration/dégradation) Et les jours avec pics d'engagement
22. Métriques avancées - Taux de réécoute
Étant donné qu'un utilisateur a entendu ma pub 3 fois Et qu'il l'a écoutée complètement les 3 fois
Quand je consulte les métriques avancées
Alors le "Taux de réécoute" affiche 100% Et cela indique que le contenu n'est pas perçu comme spam Et les utilisateurs tolèrent bien la répétition
23. Recommandations automatiques d'optimisation
Étant donné que ma campagne a un taux de skip de 75% Et que la durée moyenne d'écoute est de 8s sur 30s
Quand je consulte les recommandations
Alors le système suggère:
24. Suivi multi-campagnes avec vue consolidée
Étant donné que j'ai 3 campagnes actives simultanément
Quand je consulte la vue consolidée
Alors je vois un tableau récapitulatif:
| Campagne | Budget | Dépensé | Diffusions | Taux complète | CPE |
|---|---|---|---|---|---|
| A | 300€ | 220€ | 4000 | 40% | 0.05€ |
| B | 500€ | 150€ | 3000 | 60% | 0.05€ |
| C | 200€ | 180€ | 3600 | 35% | 0.05€ |
Et je peux comparer les performances d'un coup d'œil
25. 📋 Plan: Calcul taux d'écoute complète
Étant donné diffusions totales Et écoutes complètes (≥80%)
Quand je calcule le taux
Alors le résultat est %
📊 Exemples de données:
| total | completes | taux |
|---|---|---|
| 1000 | 400 | 40 |
| 2000 | 1200 | 60 |
| 500 | 100 | 20 |
| 1000 | 850 | 85 |
26. 📋 Plan: Calcul coût par écoute (CPE)
Étant donné un budget dépensé de € Et écoutes complètes
Quand je calcule le CPE
Alors le résultat est €
📊 Exemples de données:
| depense | ecoutes | cpe |
|---|---|---|
| 100 | 2000 | 0.05 |
| 300 | 6000 | 0.05 |
| 50 | 1000 | 0.05 |
| 500 | 10000 | 0.05 |
27. 📋 Plan: Classification performance vs benchmark
Étant donné un taux d'écoute complète de % Et une moyenne RoadWave de 40%
Quand je compare à la moyenne
Alors la performance est
📊 Exemples de données:
| taux | classification |
|---|---|
| 60 | Excellente (+50%) |
| 50 | Bonne (+25%) |
| 40 | Moyenne |
| 30 | Faible (-25%) |
| 20 | Très faible (-50%) |
Validation et modération des publicités
En tant que modérateur RoadWave Je veux valider manuellement toutes les publicités avant diffusion Afin de garantir la qualité et la légalité des contenus publicitaires
29 scénarios (27 standards, 2 plans)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et qu'un modérateur RoadWave est connecté
1. Validation manuelle obligatoire avant diffusion
Étant donné qu'un publicitaire a créé une campagne Et que le paiement de 300€ a été effectué
Quand la campagne est soumise
Alors elle passe en statut "En attente de validation" Et elle est ajoutée à la file d'attente des modérateurs Et la diffusion ne démarre PAS avant validation manuelle Et le publicitaire reçoit un email "Votre campagne est en cours de validation (24-48h)"
2. Délai de validation 24-48h ouvrées
Étant donné qu'une campagne est soumise le lundi 10h
Quand le modérateur la valide le mardi 15h
Alors le délai est de 29h (dans les 48h ouvrées) Et le publicitaire reçoit une notification "Votre campagne est approuvée"
3. Validation dépassant 48h avec notification
Étant donné qu'une campagne est soumise le lundi 10h
Quand 48h ouvrées se sont écoulées Et que la campagne n'est toujours pas validée
Alors le publicitaire reçoit un email automatique: Et un modérateur senior est assigné automatiquement
4. Acceptation de campagne publicitaire
Étant donné qu'une campagne est en attente de validation Et que l'audio respecte toutes les règles
Quand le modérateur clique sur "Approuver"
Alors le statut passe à "Approuvée" Et la campagne démarre à la date programmée Et le publicitaire reçoit un email de confirmation Et le budget commence à être consommé dès le début
5. Refus de campagne avec motif détaillé
Étant donné qu'une campagne contient du contenu alcool
Quand le modérateur clique sur "Refuser" Et qu'il sélectionne le motif "Contenu interdit: Alcool" Et qu'il ajoute le commentaire "La publicité pour l'alcool est interdite en France"
Alors le statut passe à "Refusée" Et le publicitaire reçoit un email détaillé avec:
| Champ | Valeur |
|---|---|
| Motif | Contenu interdit: Alcool |
| Commentaire | La publicité pour l'alcool est interdite en France |
| Action requise | Modifier votre contenu et soumettre à nouveau |
Et un remboursement automatique de 300€ est déclenché
6. Remboursement automatique après refus
Étant donné qu'une campagne à 500€ est refusée
Quand le statut passe à "Refusée"
Alors un remboursement Mangopay de 500€ est initié automatiquement Et le délai de remboursement est de 5-7 jours ouvrés Et le publicitaire reçoit un email "Remboursement en cours"
7. Contenus interdits - Alcool
Étant donné qu'une publicité mentionne "Whisky premium 40°"
Quand le modérateur écoute l'audio
Alors il doit refuser la campagne Et sélectionner le motif "Contenu interdit: Alcool"
8. Contenus interdits - Tabac
Étant donné qu'une publicité mentionne "Cigarettes électroniques"
Quand le modérateur écoute l'audio
Alors il doit refuser la campagne Et sélectionner le motif "Contenu interdit: Tabac/Vape"
9. Contenus interdits - Jeux d'argent
Étant donné qu'une publicité mentionne "Gagnez 10 000€ - Paris sportifs"
Quand le modérateur écoute l'audio
Alors il doit refuser la campagne Et sélectionner le motif "Contenu interdit: Jeux d'argent"
10. Contenus interdits - Politique pendant campagne électorale
Étant donné qu'une publicité politique est soumise Et que nous sommes en période de campagne électorale officielle
Quand le modérateur écoute l'audio
Alors il doit refuser la campagne Et sélectionner le motif "Contenu interdit: Publicité politique (période électorale)"
11. Contenus interdits - Contenu sexuel
Étant donné qu'une publicité contient des propos sexuellement explicites
Quand le modérateur écoute l'audio
Alors il doit refuser la campagne Et sélectionner le motif "Contenu interdit: Contenu sexuel"
12. Contenus interdits - Violence
Étant donné qu'une publicité contient des descriptions violentes
Quand le modérateur écoute l'audio
Alors il doit refuser la campagne Et sélectionner le motif "Contenu interdit: Violence"
13. Contenu légal autorisé - Commerce local
Étant donné qu'une publicité pour un restaurant local dit "Découvrez notre menu du jour"
Quand le modérateur écoute l'audio
Alors il doit approuver la campagne
14. Contenu légal autorisé - Service professionnel
Étant donné qu'une publicité pour un garage dit "Révision complète à partir de 99€"
Quand le modérateur écoute l'audio
Alors il doit approuver la campagne
15. Critères de validation - Qualité audio
Étant donné qu'une publicité a une qualité audio très basse (bruits, saturation)
Quand le modérateur écoute l'audio
Alors il peut refuser avec le motif "Qualité audio insuffisante" Et recommander "Veuillez soumettre un fichier audio de meilleure qualité"
16. Critères de validation - Classification d'âge correcte
Étant donné qu'une publicité contient du langage familier Et qu'elle est classée "Tout public"
Quand le modérateur écoute l'audio
Alors il peut refuser avec le motif "Classification d'âge incorrecte" Et recommander "Reclasser en 13+ minimum"
17. Critères de validation - Respect réglementation française
Étant donné qu'une publicité fait des promesses mensongères "Perdez 10kg en 1 semaine"
Quand le modérateur écoute l'audio
Alors il doit refuser avec le motif "Non-conformité réglementaire: Publicité mensongère"
18. File d'attente modération priorisée
Étant donné que 10 campagnes sont en attente de validation Et que la campagne A a été soumise il y a 40h Et que la campagne B a été soumise il y a 2h
Quand le modérateur consulte sa file
Alors la campagne A apparaît en premier (priorité temporelle) Et un badge "Urgente - >40h" est affiché
19. Dashboard modération - Vue d'ensemble
Étant donné que je suis modérateur
Quand j'accède au dashboard modération publicités
Alors je vois:
| Métrique | Exemple valeur |
|---|---|
| Campagnes en attente | 5 |
| Délai moyen de validation | 28h |
| Campagnes validées aujourd'hui | 12 |
| Campagnes refusées aujourd'hui | 3 |
| Taux d'acceptation | 80% |
20. Transcription automatique pour aide modération
Étant donné qu'une publicité audio est soumise
Quand le système traite l'audio
Alors une transcription automatique est générée via Whisper Et elle est affichée au modérateur pour faciliter la revue Et elle permet une recherche par mots-clés (alcool, tabac, etc.)
21. Détection automatique mots-clés interdits
Étant donné qu'une publicité audio est soumise
Quand la transcription contient "whisky" ou "vodka"
Alors un flag automatique "⚠️ Alcool détecté" est ajouté Et la campagne est priorisée pour validation manuelle rapide Et le modérateur est alerté du contenu potentiellement interdit
22. Historique modération publicitaire
Étant donné qu'un publicitaire a eu 2 campagnes refusées
Quand il soumet une 3ème campagne
Alors le modérateur voit l'historique:
| Date | Statut | Motif |
|---|---|---|
| 2026-01-15 | Refusée | Contenu interdit: Alcool |
| 2026-01-20 | Refusée | Qualité audio faible |
Et il peut en tenir compte dans sa décision
23. Appel possible après refus
Étant donné que ma campagne a été refusée pour "Classification incorrecte"
Quand je conteste la décision via le formulaire d'appel
Alors un modérateur senior revoit la campagne Et il peut approuver si la classification est en fait correcte Et le délai de réponse est de 48-72h
24. Notification temps réel pour modérateurs
Étant donné que je suis modérateur connecté
Quand une nouvelle campagne est soumise
Alors je reçois une notification in-app Et le compteur "Campagnes en attente" s'incrémente en temps réel Et je peux cliquer pour consulter immédiatement
25. Statistiques conformité par catégorie
Étant donné que je suis admin modération
Quand je consulte les statistiques mensuelles
Alors je vois les motifs de refus:
| Motif | Nombre | Pourcentage |
|---|---|---|
| Alcool | 15 | 30% |
| Qualité audio | 12 | 24% |
| Classification erronée | 10 | 20% |
| Publicité mensongère | 8 | 16% |
| Autres | 5 | 10% |
26. Export rapport modération
Étant donné que je suis modérateur senior
Quand j'exporte le rapport mensuel
Alors je reçois un fichier CSV avec:
| Colonne |
|---|
| Campagne ID |
| Publicitaire |
| Date soumission |
| Date décision |
| Statut |
| Motif (si refus) |
| Modérateur |
Et je peux l'analyser dans Excel
27. Validation partielle avec demande modification
Étant donné qu'une campagne a un contenu acceptable Mais que la classification d'âge est incorrecte
Quand le modérateur clique sur "Demander modification"
Alors le publicitaire reçoit un email: Et le statut devient "Modification requise" Et le publicitaire peut modifier sans repayer
28. 📋 Plan: Contenus interdits automatiquement détectés
Étant donné qu'une publicité contient le mot <mot_cle>
Quand la transcription automatique est analysée
Alors un flag est ajouté Et le motif de refus suggéré est
📊 Exemples de données:
| mot_cle | flag | motif |
|---|---|---|
| whisky | ⚠️ Alcool | Contenu interdit: Alcool |
| vodka | ⚠️ Alcool | Contenu interdit: Alcool |
| cigarette | ⚠️ Tabac | Contenu interdit: Tabac |
| casino | ⚠️ Jeux argent | Contenu interdit: Jeux |
| paris sportifs | ⚠️ Jeux argent | Contenu interdit: Jeux |
29. 📋 Plan: Délais de validation selon soumission
Étant donné qu'une campagne est soumise à
Quand elle est validée heures plus tard
Alors le statut est
📊 Exemples de données:
| jour | heure | delai | conformite |
|---|---|---|---|
| Lundi | 10h | 24 | Dans les délais (24h) |
| Lundi | 10h | 48 | Dans les délais (48h) |
| Lundi | 10h | 50 | Hors délais (>48h) |
| Vendredi | 16h | 72 | Dans les délais (we) |
Architecture technique radio live
En tant que système Je veux gérer efficacement les flux audio en temps réel Afin d'assurer une diffusion stable et scalable des lives
24 scénarios
Contexte commun à tous les scénarios
Étant donné que l'infrastructure RoadWave est opérationnelle Et que les serveurs Go avec Pion WebRTC sont actifs
1. Ingestion WebRTC du flux créateur
Étant donné qu'un créateur démarre un live depuis son application mobile
Quand le flux audio WebRTC (Opus 48 kbps) arrive sur le serveur
Alors le serveur Go avec Pion WebRTC accepte la connexion Et le flux est traité en temps réel
2. Conversion temps réel Opus vers segments HLS
Étant donné qu'un flux WebRTC Opus est reçu par le serveur
Quand le serveur traite le flux
Alors FFmpeg convertit en segments HLS (.ts) Et un fichier manifest .m3u8 est généré et mis à jour régulièrement Et les segments ont une durée de 2 secondes chacun
3. Distribution via Bunny CDN
Étant donné que les segments HLS sont générés
Quand un auditeur demande à rejoindre le live
Alors le manifest .m3u8 est servi via Bunny CDN Et les segments .ts sont cachés sur le CDN Et la distribution est globale avec latence minimale
4. Lecture HLS native sur mobile iOS
Étant donné qu'un auditeur iOS rejoint un live
Quand l'application charge le flux HLS
Alors le player natif AVPlayer gère la lecture Et le buffer de 15 secondes est appliqué automatiquement Et la qualité s'adapte selon la connexion
5. Lecture HLS native sur mobile Android
Étant donné qu'un auditeur Android rejoint un live
Quand l'application charge le flux HLS
Alors le player natif ExoPlayer gère la lecture Et le buffer de 15 secondes est configuré Et la qualité s'adapte selon la connexion
6. Enregistrement parallèle du flux pour replay
Étant donné qu'un live est en cours
Alors un processus parallèle enregistre le flux Opus raw Et l'enregistrement est stocké temporairement sur le serveur Et l'enregistrement est indépendant de la diffusion HLS
7. Traitement post-live asynchrone
Étant donné qu'un live vient de se terminer
Quand le processus post-live démarre
Alors un job asynchrone est créé dans la queue Redis Et un worker Go récupère le job Et le worker exécute FFmpeg pour les conversions
8. Conversion Opus raw vers MP3 256 kbps
Étant donné qu'un worker traite un job post-live
Quand la conversion démarre
Alors FFmpeg convertit Opus raw en MP3 256 kbps Et la normalisation audio à -14 LUFS est appliquée Et les silences prolongés (>3 secondes) sont détectés et nettoyés
9. Génération segments HLS pour le replay
Étant donné que le MP3 256 kbps est généré
Quand le worker crée les segments HLS
Alors des segments .ts de 10 secondes sont créés Et un manifest .m3u8 est généré Et les segments sont uploadés vers le stockage Bunny
10. Publication automatique du replay
Étant donné que tous les segments HLS sont uploadés
Quand le worker finalise le job
Alors une entrée de contenu "replay" est créée en base PostgreSQL Et le titre est "[REPLAY] [Titre live original]" Et le type géographique est "Géo-neutre" Et le replay est immédiatement disponible pour les auditeurs
11. Suppression automatique fichier Opus raw après 7 jours
Étant donné qu'un replay est publié depuis 7 jours
Quand le job de nettoyage quotidien s'exécute
Alors le fichier Opus raw est supprimé du stockage Et seul le MP3 256 kbps et les segments HLS sont conservés Et l'espace de stockage est libéré
12. Scalabilité horizontale des workers de conversion
Étant donné que 50 lives se terminent simultanément
Quand les jobs post-live sont créés
Alors les workers Go disponibles traitent les jobs en parallèle Et si tous les workers sont occupés, les jobs attendent en queue Redis Et de nouveaux workers peuvent être lancés automatiquement (Kubernetes)
13. Limitation du nombre de lives simultanés (MVP)
Étant donné que l'infrastructure MVP est configurée pour 100 lives simultanés Et que 100 lives sont actuellement en cours
Quand un nouveau créateur essaie de démarrer un live
Alors la demande est refusée avec le code erreur 503 Et le message "Capacité maximale atteinte. Veuillez réessayer dans quelques minutes" est retourné Et la demande peut être mise en queue prioritaire si créateur Premium
14. Monitoring des ressources serveur en temps réel
Étant donné que plusieurs lives sont en cours
Alors le système monitore en temps réel:
| métrique | seuil alerte |
|---|---|
| CPU utilisation | >80% |
| Mémoire utilisation | >85% |
| Bande passante upload | >80% capacité |
| Nombre connexions WebRTC | >90 |
| Latence moyenne CDN | >200ms |
Et si un seuil est dépassé, une alerte est envoyée à l'équipe technique
15. Calcul du coût de bande passante CDN
Étant donné qu'un live a 100 auditeurs simultanés Et que la qualité est 48 kbps Opus
Quand le live dure 1 heure
Alors la bande passante totale est d'environ 2.16 GB Et le coût Bunny CDN est d'environ 0.02€ (tarif ~0.01€/GB) Et ces métriques sont enregistrées pour facturation créateur si nécessaire
16. Cache CDN des segments HLS
Étant donné qu'un live est diffusé via Bunny CDN
Quand un segment .ts est généré
Alors le segment est uploadé vers Bunny origin Et Bunny CDN cache le segment sur ses edge servers Et les auditeurs suivants récupèrent le segment depuis le cache Et la charge sur le serveur origin est réduite de ~90%
17. Gestion de la latence WebRTC créateur
Étant donné qu'un créateur diffuse avec une connexion 4G
Quand la latence réseau augmente ponctuellement
Alors le buffer côté serveur absorbe les fluctuations Et la qualité peut être réduite temporairement (48 kbps → 32 kbps) Et un warning est affiché au créateur si la connexion est trop instable
18. Détection automatique de la musique protégée (post-MVP)
Étant donné qu'un live contient de la musique en arrière-plan
Quand le système d'audio fingerprint analyse le flux
Alors une empreinte audio est calculée toutes les 30 secondes Et l'empreinte est comparée à une base de données de contenus protégés Et si une correspondance est trouvée, un warning est envoyé au créateur Et si le créateur ne corrige pas sous 30 secondes, le live peut être arrêté
19. Stockage des métadonnées de live en PostgreSQL
Étant donné qu'un créateur démarre un live
Alors les métadonnées suivantes sont enregistrées:
| champ | exemple valeur |
|---|---|
| live_id | uuid v4 |
| creator_id | uuid créateur |
| title | "Mon super live" |
| started_at | timestamp UTC |
| zone_geo | "Île-de-France" |
| tags | ["Actualité", "Tech"] |
| classification_age | "Tout public" |
Et ces données sont indexées pour recherche et analytics
20. Cache Redis pour compteurs temps réel
Étant donné qu'un live est en cours
Alors Redis stocke les compteurs temps réel:
| clé Redis | valeur exemple |
|---|---|
| live:[live_id]:listeners | 247 |
| live:[live_id]:likes | 89 |
| live:[live_id]:reports | 0 |
Et ces compteurs sont mis à jour toutes les 2 secondes Et les compteurs sont persistés en PostgreSQL toutes les 60 secondes
21. Heartbeat auditeurs pour compteur précis
Étant donné qu'un auditeur écoute un live
Alors l'application envoie un heartbeat toutes les 10 secondes Et le heartbeat met à jour le timestamp dans Redis Et si aucun heartbeat n'est reçu pendant 30 secondes, l'auditeur est retiré du compteur
22. Gestion des pannes serveur pendant un live
Étant donné qu'un live est en cours sur serveur A
Quand le serveur A tombe en panne
Alors Kubernetes redémarre automatiquement un pod Mais le live en cours est perdu (pas de failover temps réel en MVP) Et le créateur voit le message "Connexion perdue. Veuillez redémarrer le live" Et les auditeurs voient "Le live est terminé suite à un problème technique"
23. Backup automatique des enregistrements live
Étant donné qu'un live est enregistré en Opus raw
Quand l'enregistrement dépasse 10 minutes
Alors un backup incrémental est créé toutes les 10 minutes Et le backup est stocké sur un stockage secondaire (S3-compatible) Et en cas de crash serveur, le live peut être récupéré jusqu'au dernier backup
24. Logs et audit trail des lives
Étant donné qu'un live démarre, se déroule et se termine
Alors tous les événements sont loggés:
| événement | détails enregistrés |
|---|---|
| Démarrage live | timestamp, creator_id, zone_geo |
| Auditeur rejoint | timestamp, user_id, position GPS |
| Auditeur quitte | timestamp, user_id, durée écoute |
| Signalement | timestamp, user_id, catégorie |
| Fin live | timestamp, durée totale, stats finales |
Et ces logs sont conservés 90 jours pour analytics et conformité RGPD
Arrêt du live
En tant que créateur Je veux arrêter ma diffusion en direct de manière contrôlée Afin de terminer proprement mon live et générer un replay automatiquement
19 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis connecté en tant que créateur Et que je diffuse actuellement un live
1. Arrêt manuel avec compte à rebours 5 secondes
Quand j'appuie sur le bouton "Arrêter live"
Alors un compte à rebours de 5 secondes démarre Et je vois le message "Ce live se termine dans 5... 4... 3... 2... 1" Et un bouton "Annuler" est affiché pendant le décompte Et l'audio du compte à rebours est diffusé aux auditeurs
2. Annulation du compte à rebours
Étant donné que j'ai appuyé sur "Arrêter live" Et que le compte à rebours affiche "3 secondes"
Quand j'appuie sur "Annuler"
Alors le compte à rebours s'arrête Et le live continue normalement Et aucune notification n'est envoyée aux auditeurs
3. Arrêt effectif après compte à rebours
Étant donné que le compte à rebours est à 0
Alors le live s'arrête Et la diffusion aux auditeurs se termine Et le message "Live terminé" s'affiche Et le processus de traitement post-live démarre automatiquement
4. Déconnexion créateur courte (moins de 60 secondes)
Étant donné que je diffuse un live
Quand ma connexion est perdue pendant 30 secondes
Alors les auditeurs voient le message "Connexion créateur perdue, reconnexion en cours..." Et le live continue de bufferer Et quand ma connexion revient, le live reprend normalement
5. Déconnexion créateur longue (60 secondes ou plus)
Étant donné que je diffuse un live
Quand ma connexion est perdue pendant 60 secondes
Alors le live s'arrête automatiquement Et les auditeurs voient le message "Le live est terminé suite à une coupure de connexion" Et le processus de traitement post-live démarre
6. Enregistrement automatique pendant le live
Étant donné que je diffuse un live
Alors mon flux audio est enregistré en continu Et le format d'enregistrement est Opus raw Et l'enregistrement est stocké temporairement sur le serveur
7. Génération automatique du replay après arrêt
Étant donné que mon live vient de se terminer Et que l'option "Publier replay automatiquement" est activée (par défaut)
Quand le traitement post-live démarre
Alors un job asynchrone est créé Et le job effectue les opérations suivantes:
| opération | détail |
|---|---|
| Conversion format | Opus raw → MP3 256 kbps |
| Génération segments HLS | Segments .ts pour streaming |
| Normalisation volume | -14 LUFS |
| Détection silences prolongés | Nettoyage automatique |
8. Publication du replay
Étant donné que le traitement post-live est terminé
Alors le replay est publié automatiquement sous 5 à 10 minutes Et le titre est "[REPLAY] [Titre live original]" Et la zone de diffusion est la même que le live Et les tags sont identiques au live Et la classification d'âge est identique Et le type géographique est "Géo-neutre" (contenu pérenne)
9. Notification de disponibilité du replay aux auditeurs
Étant donné que le replay de mon live est publié
Quand un auditeur qui a écouté le live se reconnecte
Alors il voit une notification in-app "Le replay de [Titre] est disponible"
10. Option désactivation publication automatique replay
Étant donné que je configure un nouveau live
Quand je désactive l'option "Publier replay automatiquement" Et que je démarre puis arrête le live
Alors le live est enregistré Mais le replay n'est pas publié automatiquement Et je peux décider manuellement de le publier plus tard
11. Suppression manuelle du replay après publication
Étant donné que mon live a généré un replay publié
Quand j'accède à mes contenus
Alors je vois le replay dans ma liste Et je peux le supprimer comme n'importe quel contenu
Quand je supprime le replay
Alors le fichier source Opus raw est supprimé immédiatement
12. Conservation fichier source Opus raw
Étant donné que mon live est terminé Et que le replay est publié
Alors le fichier Opus raw est conservé pendant 7 jours Et après 7 jours, le fichier raw est supprimé automatiquement Et seul le MP3 256 kbps est conservé
13. Modification du replay interdite
Étant donné que mon live a généré un replay publié
Quand j'essaie de modifier l'audio du replay
Alors l'action est refusée Et je vois le message "Les replays ne peuvent pas être modifiés pour garantir l'intégrité de l'enregistrement" Et je peux uniquement modifier les métadonnées (titre, description)
14. Statistiques du live disponibles après arrêt
Étant donné que mon live est terminé
Quand j'accède aux statistiques
Alors je vois:
| métrique | exemple valeur |
|---|---|
| Durée totale | 1h 23min |
| Nombre d'auditeurs max | 247 |
| Nombre d'auditeurs moyen | 183 |
| Nombre de likes | 89 |
| Nombre d'abonnements | 12 |
| Signalements reçus | 0 |
15. Live terminé avec signalements en cours
Étant donné que mon live a reçu 3 signalements pendant la diffusion
Quand le live se termine
Alors le replay n'est pas publié automatiquement Et le contenu est en attente de modération Et je vois le message "Votre replay sera publié après vérification suite aux signalements reçus" Et un modérateur doit valider ou refuser le replay sous 24h
16. Arrêt forcé par un modérateur
Étant donné que je diffuse un live Et qu'un modérateur détecte du contenu interdit
Quand le modérateur clique sur "Arrêter le live immédiatement"
Alors le live s'arrête sans compte à rebours Et je vois le message "Votre live a été interrompu par la modération" Et je reçois une notification détaillant la raison Et le replay n'est pas publié Et le fichier source est conservé 30 jours pour appel
17. Métriques de bande passante pendant le live
Étant donné que je diffuse un live Et que 100 auditeurs écoutent simultanément
Alors la bande passante consommée est d'environ 4.8 Mbps via CDN Et le coût estimé Bunny CDN est d'environ 0.02€ par heure de diffusion Et je peux voir ces métriques en temps réel dans l'interface créateur
18. Live sans auditeurs pendant 5 minutes
Étant donné que je diffuse un live Et qu'aucun auditeur n'écoute depuis 5 minutes
Alors je vois un message d'information "Aucun auditeur actuellement connecté" Mais le live continue normalement Et je peux choisir de continuer ou d'arrêter
19. Qualité audio du replay supérieure au live
Étant donné que mon live était diffusé en Opus 48 kbps
Quand le replay est généré
Alors le replay est encodé en MP3 256 kbps Et la qualité audio du replay est supérieure au live Et la taille du fichier est optimisée pour le stockage long terme
Comportement auditeur pendant un live
En tant qu'auditeur Je veux écouter des lives de manière stable Afin de profiter du contenu en temps réel sans coupures
27 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis connecté en tant qu'auditeur Et qu'un créateur diffuse actuellement un live
1. Rejoindre un live avec buffer de synchronisation 15 secondes
Quand je clique sur "Rejoindre le live"
Alors la connexion au flux HLS s'établit Et je commence à écouter avec un décalage de 15 secondes par rapport au créateur Et le buffer de 15 secondes garantit une lecture stable
2. Justification du buffer 15 secondes
Étant donné les alternatives de buffer possibles:
| buffer | stabilité 3G | stabilité 4G | décalage perceptible | décision |
|---|---|---|---|---|
| 5s | Faible | Moyenne | Non | ❌ |
| 10s | Moyenne | Bonne | Non | ❌ |
| 15s | Bonne | Excellente | Léger acceptable | ✅ |
| 20s+ | Excellente | Excellente | Oui | ❌ |
Alors le buffer optimal est 15 secondes
3. Lecture stable sur réseau 3G
Étant donné que je suis sur réseau 3G Et que j'écoute un live
Quand des micro-coupures réseau surviennent
Alors le buffer de 15 secondes absorbe les coupures Et la lecture continue sans interruption perceptible
4. Lecture stable sur réseau 4G
Étant donné que je suis sur réseau 4G Et que j'écoute un live
Alors la lecture est fluide Et le buffer de 15 secondes prévient les coupures lors de changement de cellule
5. Continuation du live en sortant de la zone géographique
Étant donné que j'écoute un live régional "Île-de-France" Et que je suis situé en Île-de-France
Quand je me déplace et sors du département
Alors le live continue de jouer normalement Et je peux écouter jusqu'à la fin naturelle du live Et après la fin du live, l'algorithme propose du contenu correspondant à ma nouvelle position
6. Abonné dans la zone reçoit notification push
Étant donné que je suis abonné au créateur "JeanDupont" Et que je suis situé en Île-de-France
Quand "JeanDupont" démarre un live en Île-de-France
Alors je reçois une notification push "🔴 JeanDupont est en direct : [Titre du live]" Et quand je tape sur la notification, l'app s'ouvre et le live démarre immédiatement
7. Abonné hors zone ne reçoit pas de notification
Étant donné que je suis abonné au créateur "JeanDupont" Et que je suis situé à Lyon
Quand "JeanDupont" démarre un live en Île-de-France
Alors je ne reçois pas de notification push Et cela évite la frustration de ne pas pouvoir écouter un live hors zone
8. Découverte d'un live via l'algorithme de recommandation
Étant donné que je suis dans la zone géographique du live Et que je navigue dans l'app avec "Suivant"
Quand l'algorithme propose un live en cours
Alors je vois l'indicateur "🔴 EN DIRECT" Et je peux choisir de le rejoindre ou de passer au suivant
9. Reconnexion rapide après coupure réseau (moins de 90 secondes)
Étant donné que j'écoute un live
Quand je perds ma connexion réseau pendant 45 secondes Et que je retrouve ma connexion
Alors je reprends le live au moment actuel (pas au buffer ancien) Et le saut temporel est transparent (pas de message d'erreur) Et je ne rate que quelques secondes de contenu
10. Reconnexion longue après coupure réseau (90 secondes ou plus)
Étant donné que j'écoute un live
Quand je perds ma connexion réseau pendant 90 secondes Et que je retrouve ma connexion
Alors je vois le message "Live en cours perdu, passage au contenu suivant" Et l'algorithme propose automatiquement le contenu suivant Et je peux manuellement revenir au live s'il est toujours en cours
11. Interactions disponibles pendant le live - Like
Étant donné que j'écoute un live Et que mon véhicule est à l'arrêt
Quand je clique sur le bouton "❤️ Like"
Alors le like est enregistré immédiatement Et le compteur de likes visible par le créateur s'incrémente Et ma jauge d'intérêt pour les tags du live augmente de +2%
12. Interactions disponibles pendant le live - Abonnement
Étant donné que j'écoute un live Et que je ne suis pas encore abonné au créateur
Quand je clique sur le bouton "S'abonner"
Alors je m'abonne au créateur Et ma jauge d'intérêt pour tous les tags du créateur augmente de +5% Et je recevrai des notifications pour ses prochains lives
13. Interactions disponibles pendant le live - Skip
Étant donné que j'écoute un live
Quand j'appuie sur "Suivant" (ou commande au volant)
Alors je quitte le live immédiatement Et l'algorithme propose le contenu suivant Et si j'ai écouté moins de 10 secondes, ma jauge d'intérêt diminue de -0.5%
14. Commande Précédent désactivée pendant un live
Étant donné que j'écoute un live
Quand j'appuie sur "Précédent" (ou commande au volant)
Alors rien ne se passe Et un message d'information s'affiche brièvement "Précédent non disponible sur les lives"
15. Chat en direct désactivé (décision définitive)
Étant donné que j'écoute un live
Alors aucune interface de chat n'est disponible Et je ne peux pas envoyer de messages au créateur Et je ne peux pas voir de messages d'autres auditeurs Et cette fonctionnalité ne sera jamais implémentée
16. Réactions emoji désactivées (décision définitive)
Étant donné que j'écoute un live
Alors aucune réaction emoji n'est disponible Et je ne peux pas envoyer d'emoji en temps réel Et cette fonctionnalité ne sera jamais implémentée
17. Message d'information sur l'absence de chat
Étant donné que j'écoute mon premier live
Quand j'accède à l'interface du live
Alors je vois un bandeau informatif "💬 Les discussions ne sont pas disponibles sur RoadWave pour garantir votre sécurité en voiture et éviter le harcèlement." Et ce bandeau n'apparaît qu'une seule fois (première expérience)
18. Signalement d'un live en cours
Étant donné que j'écoute un live Et que le contenu me semble inapproprié
Quand je clique sur le bouton "Signaler"
Alors je vois les catégories de signalement:
| catégorie |
|---|
| Haine et violence |
| Contenu sexuel |
| Illégalité |
| Droits d'auteur |
| Désinformation dangereuse |
| Harcèlement |
| Autre |
Et quand je sélectionne une catégorie Alors le signalement est envoyé en priorité selon la catégorie Et un modérateur peut écouter le live en temps réel si besoin
19. Statistiques visibles par les auditeurs pendant le live
Étant donné que j'écoute un live
Quand je consulte les informations du live
Alors je vois:
| information | exemple valeur |
|---|---|
| Nombre d'auditeurs | 247 personnes |
| Durée du live | 1h 23min |
| Nom du créateur | @JeanDupont |
| Zone de diffusion | Île-de-France |
| Tags | Actualité, Société |
Mais je ne vois pas les likes ou autres métriques détaillées
20. Compteur d'auditeurs arrondi pour préserver la vie privée
Étant donné que j'écoute un live avec exactement 247 auditeurs
Quand je consulte le nombre d'auditeurs
Alors je vois "~250 auditeurs" (arrondi à la dizaine supérieure)
21. Qualité audio adaptative pendant le live
Étant donné que j'écoute un live
Quand ma connexion passe de 4G à 3G
Alors la qualité audio s'adapte automatiquement Et je passe de 48 kbps à 24 kbps Opus Et la transition est transparente sans coupure
22. Consommation de données pendant un live
Étant donné que j'écoute un live en qualité standard 48 kbps Et que j'écoute pendant 1 heure
Alors j'ai consommé environ 21.6 MB de données mobiles Et cette consommation est affichée dans les paramètres de l'app
23. Lecture du replay après la fin du live
Étant donné que j'écoute un live depuis 30 minutes
Quand le créateur arrête le live
Alors je vois le message "Le live est terminé. Le replay sera disponible dans quelques minutes" Et le contenu suivant est automatiquement proposé après 2 secondes
24. Notification de disponibilité du replay
Étant donné que j'ai écouté un live jusqu'à la fin Et que le replay est publié 8 minutes plus tard
Quand je rouvre l'application
Alors je vois une notification in-app "Le replay de [Titre] est maintenant disponible" Et je peux cliquer pour l'écouter immédiatement
25. Aucune publicité pendant un live pour utilisateurs gratuits
Étant donné que je suis un utilisateur gratuit Et que j'écoute un live
Alors aucune publicité n'est insérée pendant le live Et la publicité apparaît seulement entre le live et le contenu suivant
26. Détection de contexte voiture pendant un live
Étant donné que j'écoute un live Et que ma vitesse est supérieure à 10 km/h
Alors l'interface tactile est désactivée pour la sécurité Et seules les commandes au volant sont actives (Play/Pause/Suivant)
27. Détection de contexte piéton pendant un live
Étant donné que j'écoute un live Et que ma vitesse est inférieure à 5 km/h
Alors l'interface tactile complète est disponible Et je peux liker, m'abonner, signaler via l'écran tactile
Démarrage d'un live
En tant que créateur Je veux démarrer une diffusion en direct Afin de partager du contenu audio en temps réel avec mes auditeurs
20 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis connecté en tant que créateur vérifié Et que j'ai les permissions de diffusion live
1. Vérifications pré-live réussies
Étant donné que ma connexion upload est supérieure à 1 Mbps Et que j'ai autorisé l'accès au microphone Et que j'ai défini une zone de diffusion "Île-de-France"
Quand je lance les vérifications pré-live
Alors toutes les vérifications sont validées Et je peux démarrer le live
2. Échec pré-live avec connexion insuffisante
Étant donné que ma connexion upload est de 0.5 Mbps
Quand je lance les vérifications pré-live
Alors je vois un warning "Connexion insuffisante pour garantir une diffusion stable (minimum 1 Mbps)" Et je peux choisir de continuer quand même ou d'annuler
3. Échec pré-live sans autorisation microphone
Étant donné que je n'ai pas autorisé l'accès au microphone
Quand j'essaie de démarrer un live
Alors je vois le message "Accès au microphone requis pour démarrer un live" Et je suis redirigé vers les paramètres système
4. Échec pré-live sans zone de diffusion définie
Étant donné que je n'ai pas défini de zone de diffusion
Quand j'essaie de démarrer un live
Alors je vois le message "Veuillez définir une zone de diffusion avant de démarrer" Et je suis redirigé vers le formulaire de configuration du live
5. Démarrage live avec buffer 15 secondes
Étant donné que toutes les vérifications pré-live sont validées
Quand j'appuie sur "Démarrer live"
Alors je vois le message "Live démarre dans 15s... Testez votre micro" Et un compte à rebours de 15 secondes s'affiche Et mon flux audio est enregistré pendant ces 15 secondes Et le live n'est pas encore visible publiquement
6. Live devient public après buffer initial
Étant donné que j'ai démarré un live Et que le buffer de 15 secondes s'est écoulé
Alors le live devient public Et les auditeurs peuvent le rejoindre Et les abonnés dans la zone reçoivent une notification push
7. Notification push aux abonnés dans la zone géographique
Étant donné que j'ai 1000 abonnés au total Et que 300 abonnés sont situés en Île-de-France Et que 700 abonnés sont situés hors Île-de-France
Quand mon live en Île-de-France devient public
Alors 300 abonnés reçoivent une notification push "🔴 [Mon pseudo] est en direct : [Titre live]" Et 700 abonnés ne reçoivent pas de notification
8. Configuration métadonnées obligatoires pour un live
Quand je configure un nouveau live
Alors je dois renseigner:
| champ | format | validation |
|---|---|---|
| Titre | 5-100 caractères | Obligatoire |
| Tags | 1-3 centres 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 |
9. Validation échouée avec titre trop court
Quand j'essaie de créer un live avec le titre "Live"
Alors la validation échoue Et je vois le message "Le titre doit contenir entre 5 et 100 caractères"
10. Validation échouée sans tags
Étant donné que j'ai rempli tous les champs sauf les tags
Quand j'essaie de démarrer le live
Alors la validation échoue Et je vois le message "Veuillez sélectionner entre 1 et 3 centres d'intérêt"
11. Limite de durée 8 heures
Étant donné que mon live dure depuis 7 heures et 30 minutes
Alors je vois un warning "Votre live se terminera dans 30 min" Et le message est affiché de manière non intrusive
12. Arrêt automatique à 8 heures
Étant donné que mon live dure depuis 8 heures
Alors le live s'arrête automatiquement Et je vois le message "Durée maximale atteinte (8 heures). Vous pouvez redémarrer un nouveau live si nécessaire" Et le processus de traitement post-live démarre
13. Diffusion contenu interdit - Concert en direct
Étant donné que je diffuse un concert en direct depuis une salle Et qu'un auditeur signale le contenu pour "Violation droits d'auteur"
Quand un modérateur écoute le live Et qu'il confirme la violation
Alors le live est arrêté immédiatement Et je reçois un Strike 2 (suspension 7 jours) Et je vois le message "Votre live a été interrompu pour violation des droits d'auteur" Et le replay n'est pas publié
14. Diffusion contenu interdit - Événement sportif payant
Étant donné que je diffuse un match de football avec droits TV Et que le contenu est détecté par l'IA audio fingerprint
Quand la détection est confirmée
Alors le live est arrêté immédiatement Et je reçois un Strike 2 (suspension 7 jours)
15. Diffusion contenu violent
Étant donné que je diffuse du contenu violent (agression physique) Et que 5 auditeurs signalent le contenu
Quand un modérateur vérifie en temps réel Et confirme la violence
Alors le live est coupé immédiatement Et mon compte est banni définitivement Et les autorités sont notifiées
16. Détection musique protégée en arrière-plan
Étant donné que mon live contient de la musique protégée en fond
Quand l'IA audio fingerprint détecte la violation après 2 minutes
Alors je reçois un avertissement en direct "Musique protégée détectée. Veuillez couper le son ou risquez un arrêt du live" Et j'ai 30 secondes pour corriger Et si je ne corrige pas, le live est arrêté avec Strike 1
17. Signalement pendant un live
Étant donné que je diffuse un live Et qu'un auditeur clique sur "Signaler"
Quand l'auditeur sélectionne la catégorie "Harcèlement"
Alors le signalement est envoyé en priorité HAUTE Et un modérateur peut écouter le live en temps réel Et le live continue pendant l'écoute de vérification
18. Dépassement nombre de lives simultanés autorisés (limite plateforme)
Étant donné que la plateforme héberge actuellement 2000 lives simultanés Et que c'est la limite de l'infrastructure actuelle
Quand j'essaie de démarrer un nouveau live
Alors je vois le message "Capacité maximale atteinte. Veuillez réessayer dans quelques minutes" Et ma demande est mise en file d'attente prioritaire si je suis créateur Premium
19. Premier live d'un nouveau créateur
Étant donné que je n'ai jamais diffusé de live auparavant Et que j'ai moins de 3 contenus validés
Quand j'essaie de démarrer mon premier live
Alors je vois le message "Les lives sont disponibles après validation de vos 3 premiers contenus" Et le bouton "Démarrer live" est désactivé
20. Créateur avec score de confiance faible
Étant donné que j'ai 2 strikes actifs
Quand j'essaie de démarrer un live
Alors je vois le message "Fonctionnalité live temporairement indisponible suite à vos sanctions" Et je dois attendre la fin de ma suspension
Recherche de contenu
En tant qu'utilisateur de RoadWave Je veux rechercher des contenus audio par mots-clés, localisation et filtres Afin de trouver facilement le contenu qui m'intéresse
55 scénarios (49 standards, 6 plans)
Contexte commun à tous les scénarios
Étant donné que l'application RoadWave est démarrée Et que l'utilisateur "jean@example.com" est connecté
1. Recherche full-text basique
Étant donné que la base contient les contenus suivants:
| titre | description | créateur |
|---|---|---|
| Balade à Paris | Visite du quartier Latin | @paris_stories |
| Secrets de Montmartre | Histoire de la butte | @explore_paris |
| Voyage en Normandie | Découverte des plages | @voyages_fr |
Quand l'utilisateur recherche "paris"
Alors 2 résultats sont retournés Et les résultats incluent "Balade à Paris" Et les résultats incluent "Secrets de Montmartre"
2. Recherche avec stemming français
Étant donné un contenu avec le titre "Voyage en Bretagne"
Quand l'utilisateur recherche "voyages"
Alors le contenu "Voyage en Bretagne" est trouvé Et le stemming a transformé "voyages" en racine "voyag"
3. 📋 Plan: Stemming français sur différentes formes
Étant donné un contenu avec le mot "<mot_original>"
Quand l'utilisateur recherche ""
Alors le contenu est trouvé grâce au stemming français
📊 Exemples de données:
| mot_original | recherche |
|---|---|
| voyage | voyages |
| voyager | voyage |
| balades | balade |
| historique | histoire |
4. Recherche avec accents ignorés
Étant donné un contenu avec le titre "Découverte de l'Élysée"
Quand l'utilisateur recherche "decouverte elysee"
Alors le contenu est trouvé Et les accents sont normalisés automatiquement
5. Champs indexés avec pondération
Étant donné les contenus suivants:
| titre | description | créateur | tags |
|---|---|---|---|
| Voyage Paris | Balade sympa | @user1 | Tourisme |
| Balade Lyon | Voyage en ville | @paris_guide | Voyage |
Quand l'utilisateur recherche "paris"
Alors "Voyage Paris" est en première position Et "@paris_guide" apparaît en second
6. Ranking par pertinence et popularité
Étant donné les contenus suivants:
| titre | écoutes | rang_texte |
|---|---|---|
| Balade Paris | 50000 | 0.8 |
| Paris la nuit | 1000 | 0.9 |
Quand l'utilisateur recherche "paris"
Alors le score final combine rang_texte × (1 + log(écoutes + 1)) Et "Balade Paris" est mieux classé grâce à sa popularité
7. Autocomplete pendant la frappe
Étant donné que l'utilisateur commence à taper "par"
Quand 3 caractères sont saisis
Alors des suggestions apparaissent:
| suggestion |
|---|
| paris |
| parc naturel |
| parvis notre-dame |
Et le top 5 des suggestions est affiché
8. Historique des 10 dernières recherches
Étant donné que l'utilisateur a effectué les recherches suivantes:
| recherche | date |
|---|---|
| voyage paris | 2026-01-20 |
| audio-guide louvre | 2026-01-19 |
| podcast automobile | 2026-01-18 |
Quand l'utilisateur ouvre la barre de recherche
Alors les 10 dernières recherches sont affichées Et elles sont triées par date décroissante
9. Correction automatique si aucun résultat
Étant donné que l'utilisateur recherche "ballade paris" (faute d'orthographe) Et qu'aucun résultat n'est trouvé
Quand la page de résultats s'affiche
Alors une suggestion "Essayez plutôt : balade paris" est affichée
10. Recherches populaires suggérées
Étant donné qu'aucun résultat n'est trouvé pour une recherche
Quand la page s'affiche
Alors des suggestions populaires sont affichées:
| suggestion |
|---|
| balade paris |
| audio-guide louvre |
| visite montmartre |
11. Saisie d'un lieu avec autocomplete
Étant donné que l'utilisateur ouvre le filtre "Lieu"
Quand il tape "Louv"
Alors Nominatim retourne des suggestions:
| suggestion | type |
|---|---|
| Musée du Louvre, Paris | monument |
| Louvres, Val-d'Oise | commune |
12. Sélection d'un lieu et définition du rayon
Étant donné que l'utilisateur sélectionne "Paris, France" Et que les coordonnées sont (48.8566, 2.3522)
Quand il définit un rayon de 50 km
Alors la recherche PostGIS utilise ST_DWithin avec 50000 mètres
13. 📋 Plan: Recherche géographique avec différents rayons
Étant donné un contenu à 30 km de Paris
Quand l'utilisateur recherche autour de Paris avec un rayon de
Alors le contenu est <résultat>
📊 Exemples de données:
| rayon | résultat |
|---|---|
| 20 km | non trouvé |
| 50 km | trouvé |
| 100 km | trouvé |
14. Utilisation de "Autour de moi" (GPS actuel)
Étant donné que l'utilisateur active le GPS Et que sa position est (48.8566, 2.3522)
Quand il sélectionne "Autour de moi"
Alors la recherche utilise ses coordonnées GPS actuelles Et un rayon par défaut de 10 km est appliqué
15. Curseur de rayon avec limites
Étant donné que l'utilisateur ouvre le curseur de rayon
Quand il ajuste le curseur
Alors les valeurs disponibles vont de 5 km à 500 km Et la valeur s'affiche en temps réel "50 km"
16. Affichage de la distance dans les résultats
Étant donné une recherche géographique autour de Paris Et un contenu à 2.3 km de distance
Quand les résultats sont affichés
Alors la distance "À 2.3 km" est indiquée pour chaque résultat
17. 📋 Plan: Tri par proximité géographique
Étant donné des contenus à différentes distances de Paris:
| contenu | distance |
|---|---|
| Louvre Guide | 0.5 km |
| Tour Eiffel | 2.0 km |
| Versailles | 20 km |
Quand l'utilisateur trie par "Proximité"
Alors les résultats sont affichés dans l'ordre:
| position | contenu |
|---|---|
| 1 | Louvre Guide |
| 2 | Tour Eiffel |
| 3 | Versailles |
18. Géocodage avec Nominatim (MVP)
Étant donné que l'application est en phase MVP
Quand une requête de géocodage est effectuée
Alors l'API publique Nominatim est utilisée Et le rate limit de 1 req/s est respecté
19. Géocodage avec fallback Mapbox
Étant donné que Nominatim ne retourne aucun résultat
Quand l'application tente un fallback
Alors l'API Mapbox Geocoding est utilisée Et le coût de 0.50€ / 1000 requêtes est appliqué
20. Ouverture du panneau de filtres
Étant donné que l'utilisateur est sur la page de recherche
Quand il clique sur "Filtres"
Alors un panneau latéral s'ouvre Et 7 catégories de filtres sont affichées:
| catégorie |
|---|
| Type de contenu |
| Durée |
| Classification âge |
| Géo-pertinence |
| Tags |
| Date de publication |
| Abonnement |
21. Filtre par type de contenu (multi-sélection)
Étant donné que l'utilisateur ouvre les filtres
Quand il sélectionne:
| type |
|---|
| Contenu court |
| Audio-guide |
Alors seuls ces types de contenus sont recherchés Et les podcasts et radios live sont exclus
22. 📋 Plan: Filtre par durée
Étant donné un contenu de <durée> minutes
Quand l'utilisateur filtre par ""
Alors le contenu est <résultat>
📊 Exemples de données:
| durée | tranche | résultat |
|---|---|---|
| 3 | <5 min | trouvé |
| 3 | 5-15 min | non trouvé |
| 10 | 5-15 min | trouvé |
| 20 | 15-30 min | trouvé |
| 45 | >30 min | trouvé |
23. Filtre par classification âge
Étant donné des contenus avec différentes classifications:
| contenu | classification |
|---|---|
| Conte enfants | Tout public |
| Podcast news | 13+ |
| Débat politique | 16+ |
Quand l'utilisateur filtre "Tout public"
Alors seul "Conte enfants" est affiché
24. Filtre par géo-pertinence
Étant donné des contenus avec différents types géo:
| contenu | type_geo |
|---|---|
| Guide Louvre | Ancré |
| Podcast Paris | Contextuel |
| News nationales | Neutre |
Quand l'utilisateur filtre "Ancré, Contextuel"
Alors "Guide Louvre" et "Podcast Paris" sont affichés Et "News nationales" est exclu
25. Filtre par tags (multi-sélection)
Étant donné des contenus taggés:
| contenu | tags |
|---|---|
| Voyage en Italie | Voyage, Gastronomie |
| Histoire de Rome | Voyage, Histoire |
| Économie italienne | Économie |
Quand l'utilisateur sélectionne les tags "Voyage, Histoire"
Alors "Histoire de Rome" est en priorité (2 tags correspondants) Et "Voyage en Italie" est affiché (1 tag correspondant) Et "Économie italienne" est exclu
26. 📋 Plan: Filtre par date de publication
Étant donné un contenu publié il y a <délai>
Quand l'utilisateur filtre par "<période>"
Alors le contenu est <résultat>
📊 Exemples de données:
| délai | période | résultat |
|---|---|---|
| 12 heures | Dernières 24h | trouvé |
| 3 jours | Cette semaine | trouvé |
| 15 jours | Ce mois | trouvé |
| 8 mois | Cette année | trouvé |
| 2 ans | Toutes dates | trouvé |
| 2 ans | Cette année | non trouvé |
27. Filtre par type d'abonnement
Étant donné des contenus gratuits et Premium:
| contenu | type |
|---|---|
| Balade Paris | Gratuit |
| Visite VIP Louvre | Premium |
Quand l'utilisateur filtre "Premium uniquement 👑"
Alors seul "Visite VIP Louvre" est affiché
28. Combinaison de filtres multiples (AND logic)
Étant donné que l'utilisateur applique les filtres:
| filtre | valeur |
|---|---|
| Type | Audio-guide |
| Durée | 5-15 min |
| Tags | Voyage |
| Classification | Tout public |
Quand la recherche est lancée
Alors seuls les contenus respectant TOUS les critères sont affichés
29. Réinitialisation des filtres
Étant donné que l'utilisateur a appliqué 5 filtres différents
Quand il clique sur "Réinitialiser"
Alors tous les filtres sont désactivés Et la recherche affiche tous les résultats
30. Sauvegarde d'une recherche
Étant donné que l'utilisateur a appliqué plusieurs filtres
Quand il clique sur "💾 Sauvegarder cette recherche" Et qu'il entre le nom "Podcasts voyage Paris"
Alors la recherche est sauvegardée Et elle apparaît dans l'onglet "Recherches sauvegardées"
31. Limite de 5 recherches sauvegardées
Étant donné que l'utilisateur a déjà 5 recherches sauvegardées
Quand il tente de sauvegarder une 6ème recherche
Alors un message d'erreur s'affiche Et il doit supprimer une recherche existante avant d'en ajouter une nouvelle
32. Notifications pour recherches sauvegardées
Étant donné une recherche sauvegardée "Podcasts voyage Paris" Et que l'utilisateur a activé les notifications
Quand 3 nouveaux contenus correspondants sont publiés
Alors une notification "3 nouveaux contenus dans 'Podcasts voyage Paris'" est envoyée
33. 📋 Plan: Options de tri des résultats
Étant donné une recherche avec plusieurs résultats
Quand l'utilisateur sélectionne le tri ""
Alors les résultats sont triés selon
📊 Exemples de données:
| option | algorithme |
|---|---|
| Pertinence | Score recherche × (1 + log(écoutes + 1)) |
| Popularité | Écoutes complètes derniers 30j DESC |
| Récent | Date publication DESC |
| Proximité | Distance GPS ASC (si recherche géo) |
| Durée | Durée audio ASC ou DESC |
34. Structure d'un résultat de recherche
Étant donné un résultat de recherche
Quand la page est affichée
Alors chaque résultat contient:
| élément | exemple |
|---|---|
| Cover image | 120×68 px (16:9) |
| Titre | Balade à Paris (2 lignes max) |
| Créateur | @paris_stories ✓ |
| Durée | 12 min |
| Écoutes | 🎧 2.3K |
| Localisation | 📍 Paris 5e · Ancré |
| Tags | 🏷️ #Voyage #Histoire |
| Badge Premium | 👑 (si applicable) |
| Distance | À 2.3 km (si recherche géo) |
| Bouton lecture | ▶️ Écouter |
| Menu contextuel | ⋮ |
35. Lazy loading des images
Étant donné une page avec 20 résultats de recherche
Quand la page se charge
Alors seules les 5 premières images sont chargées Et les images suivantes se chargent au scroll
36. Troncature du titre sur 2 lignes maximum
Étant donné un contenu avec un titre de 120 caractères
Quand le résultat est affiché
Alors le titre est tronqué après 2 lignes Et "..." est ajouté à la fin
37. Lien cliquable vers le profil créateur
Étant donné un résultat de recherche pour "@paris_stories"
Quand l'utilisateur clique sur "@paris_stories"
Alors il est redirigé vers "https://roadwave.fr/@paris_stories"
38. Menu contextuel d'un résultat [⋮]
Étant donné que l'utilisateur clique sur [⋮] pour un résultat
Quand le menu s'ouvre
Alors les actions suivantes sont disponibles:
| action |
|---|
| Partager |
| Ajouter à une playlist |
| Télécharger (offline) |
| Signaler |
39. Pagination avec 20 résultats par page
Étant donné une recherche retournant 100 résultats
Quand la page est affichée
Alors 20 résultats sont chargés initialement Et un indicateur "1-20 sur 100 résultats" est visible
40. Infinite scroll automatique
Étant donné que l'utilisateur scroll dans les résultats
Quand il atteint 80% de la page
Alors les 20 résultats suivants sont chargés automatiquement Et un loader est affiché pendant le chargement
41. Bouton fallback "Charger 20 suivants"
Étant donné que l'infinite scroll est désactivé (paramètres)
Quand l'utilisateur atteint la fin de la page
Alors un bouton "Charger 20 suivants" est affiché Et les résultats se chargent au clic
42. Basculement entre vue liste et vue carte
Étant donné que l'utilisateur est sur la page de résultats
Quand il clique sur le toggle "Liste / Carte"
Alors la vue carte Leaflet s'affiche Et les résultats sont affichés comme markers sur la carte
43. Affichage de la carte Leaflet
Étant donné que la vue carte est activée
Quand la carte se charge
Alors la carte utilise les tuiles OpenStreetMap Et le centre est la position de recherche (ou GPS utilisateur) Et le zoom initial montre tous les résultats
44. Markers cliquables sur la carte
Étant donné que 10 résultats sont affichés sur la carte
Quand l'utilisateur clique sur un marker
Alors une popup s'affiche avec:
| élément |
|---|
| Titre |
| Créateur |
| Durée |
| Distance |
| Bouton ▶️ Écouter |
45. Clustering des markers proches
Étant donné que 50 résultats sont très proches géographiquement
Quand la carte est affichée
Alors les markers proches sont groupés en clusters Et le nombre de contenus est affiché sur le cluster Et le cluster se décompose au zoom
46. Synchronisation liste / carte
Étant donné que l'utilisateur est en vue carte
Quand il clique sur un marker et écoute le contenu Et qu'il rebascule en vue liste
Alors le contenu écouté est marqué dans la liste Et la position de scroll est maintenue
47. Index PostgreSQL full-text pour performances
Étant donné que la base contient 100K contenus
Quand une recherche full-text est effectuée
Alors l'index GIN sur to_tsvector est utilisé Et la requête retourne en moins de 100ms
48. Index PostGIS GIST pour recherche géo
Étant donné une recherche géographique avec rayon 50 km
Quand la requête PostGIS ST_DWithin est exécutée
Alors l'index GIST sur la colonne location est utilisé Et la requête retourne en moins de 50ms
49. Index composites pour filtres
Étant donné une recherche avec filtres multiples
Quand les filtres type, durée, âge, géo, date sont appliqués
Alors l'index composite idx_content_filters est utilisé Et les performances restent optimales
50. Index GIN pour recherche par tags
Étant donné une recherche filtrée par tags "Voyage, Histoire"
Quand la requête est exécutée
Alors l'index GIN sur la colonne tags est utilisé Et la recherche est performante même avec 500K contenus
51. Aucun résultat trouvé
Étant donné que l'utilisateur recherche "xyzabc123"
Quand aucun résultat n'est trouvé
Alors un message "Aucun résultat pour 'xyzabc123'" s'affiche Et des suggestions de recherches populaires sont proposées
52. Recherche vide
Étant donné que l'utilisateur clique sur "Rechercher" sans saisir de texte
Quand la recherche est lancée
Alors un message "Veuillez entrer au moins 2 caractères" s'affiche
53. Erreur de géocodage Nominatim
Étant donné que l'API Nominatim est indisponible
Quand l'utilisateur tente une recherche géographique
Alors un message "Service de localisation temporairement indisponible" s'affiche Et la recherche continue sans filtre géographique
54. GPS désactivé pour "Autour de moi"
Étant donné que l'utilisateur a désactivé le GPS
Quand il sélectionne "Autour de moi"
Alors un message "Veuillez activer la localisation" s'affiche Et un bouton "Activer" ouvre les paramètres système
55. Timeout de recherche après 10 secondes
Étant donné qu'une recherche complexe est lancée
Quand la requête dépasse 10 secondes
Alors la recherche est annulée Et un message "La recherche a pris trop de temps, veuillez réessayer" s'affiche
Classification de géo-pertinence des contenus
En tant que plateforme de contenu géolocalisé Je veux classifier les contenus selon leur pertinence géographique Afin d'adapter l'algorithme de recommandation
10 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible
1. Créateur choisit le type géo-ancré pour un audio-guide
Étant donné que je suis un créateur connecté
Quand je publie un audio-guide de la Tour Eiffel Et que je choisis la classification "Géo-ancré"
Alors le contenu est enregistré avec:
| champ | valeur |
|---|---|
| type_geo | geo_ancre |
| ponderation_geo | 0.7 |
| ponderation_interets | 0.1 |
2. Créateur choisit le type géo-contextuel pour actualité régionale
Étant donné que je suis un créateur connecté
Quand je publie une actualité régionale en Bretagne Et que je choisis la classification "Géo-contextuel"
Alors le contenu est enregistré avec:
| champ | valeur |
|---|---|
| type_geo | geo_contextuel |
| ponderation_geo | 0.5 |
| ponderation_interets | 0.3 |
3. Créateur choisit le type géo-neutre pour un podcast philosophie
Étant donné que je suis un créateur connecté
Quand je publie un podcast de philosophie Et que je choisis la classification "Géo-neutre"
Alors le contenu est enregistré avec:
| champ | valeur |
|---|---|
| type_geo | geo_neutre |
| ponderation_geo | 0.2 |
| ponderation_interets | 0.6 |
4. Publication impossible sans classification géographique
Étant donné que je crée un contenu audio
Quand j'essaie de publier sans sélectionner de type géographique
Alors la publication échoue Et je vois le message "Vous devez sélectionner un type de géo-pertinence"
5. Modérateur reclassifie un contenu mal catégorisé
Étant donné qu'un contenu podcast générique est classifié "Géo-ancré" Et que le modérateur examine le contenu
Quand le modérateur le reclassifie en "Géo-neutre"
Alors la nouvelle classification est appliquée immédiatement Et l'algorithme utilise la pondération géo = 0.2 Et le créateur reçoit une notification de reclassification
6. Créateur modifie la classification après publication
Étant donné que j'ai publié un contenu classifié "Géo-contextuel" Et que je réalise qu'il devrait être "Géo-neutre"
Quand je modifie la classification en "Géo-neutre"
Alors la modification est enregistrée Et l'algorithme utilise la nouvelle pondération Et je vois le message "Classification modifiée avec succès"
7. Statistiques de classification dans le profil créateur
Étant donné que je suis un créateur Et que j'ai publié 30 contenus:
| type | nombre |
|---|---|
| Géo-ancré | 10 |
| Géo-contextuel | 15 |
| Géo-neutre | 5 |
Quand je consulte mes statistiques
Alors je vois la répartition de mes classifications Et des suggestions pour optimiser la portée
8. Contenu géo-ancré fortement pondéré par la proximité
Étant donné qu'un audio-guide "Géo-ancré" existe à la Tour Eiffel Et qu'un utilisateur est à 100m de la Tour Eiffel
Quand l'algorithme calcule le score
Alors la pondération géo est de 0.7 Et le score géo est proche de 1 (très proche) Et le contenu a un score final élevé
9. Contenu géo-neutre moins sensible à la distance
Étant donné qu'un podcast philosophie "Géo-neutre" existe à Paris Et qu'un utilisateur est à Marseille (750 km)
Quand l'algorithme calcule le score
Alors la pondération géo est de 0.2 Et le score géo est bas (distance élevée) Mais le score intérêts (0.6) peut compenser Et le contenu peut quand même être recommandé si intérêts match
10. Comparaison scores entre types géo pour même distance
Étant donné 3 contenus au même endroit (Paris):
| type | ponderation_geo |
|---|---|
| Géo-ancré | 0.7 |
| Géo-contextuel | 0.5 |
| Géo-neutre | 0.2 |
Et qu'un utilisateur est à 50 km de Paris
Quand l'algorithme calcule les scores
Alors le contenu "Géo-ancré" a le score géo le plus élevé Et le contenu "Géo-neutre" a le score géo le plus faible Mais peut avoir un score final plus élevé si forte correspondance intérêts
Gestion du contenu politique (MVP simplifié)
En tant qu'utilisateur Je veux pouvoir filtrer le contenu politique Afin de contrôler mon exposition à ce type de contenu
13 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible
1. Créateur tagge son contenu comme "Politique"
Étant donné que je suis un créateur connecté
Quand je publie un contenu sur un débat politique Et que je sélectionne le tag "Politique"
Alors le contenu est enregistré avec le tag "Politique" Et aucune classification gauche/droite n'est demandée (MVP)
2. Tag "Politique" au même niveau que les autres tags
Étant donné que je crée un contenu
Quand je consulte la liste des tags disponibles
Alors je vois les tags suivants au même niveau:
| tag |
|---|
| Économie |
| Sport |
| Culture |
| Politique |
| Automobile |
| Voyage |
| Musique |
3. Par défaut, tous les contenus politiques sont visibles
Étant donné que je suis un nouvel utilisateur Et que je n'ai pas modifié les paramètres de contenu politique
Quand je demande des recommandations
Alors les contenus tagués "Politique" sont inclus normalement Et aucun filtrage n'est appliqué
4. Activer le filtrage "Masquer contenu politique"
Étant donné que je suis connecté
Quand j'active l'option "Masquer contenu politique" dans les paramètres
Alors tous les contenus tagués "Politique" sont exclus de mes recommandations Et je vois le message "Contenu politique masqué"
5. Filtrage politique actif - aucun contenu politique recommandé
Étant donné que j'ai activé "Masquer contenu politique" Et qu'il existe 100 contenus dont 20 tagués "Politique"
Quand je demande 50 recommandations
Alors je reçois 50 contenus parmi les 80 non-politiques Et 0% de contenus politiques sont proposés
6. Désactiver le filtrage "Masquer contenu politique"
Étant donné que j'ai activé "Masquer contenu politique"
Quand je désactive cette option dans les paramètres
Alors les contenus politiques sont à nouveau inclus dans mes recommandations Et le filtrage est levé immédiatement
7. Mode Kids filtre automatiquement le contenu politique
Étant donné que je suis un utilisateur de 14 ans Et que le mode Kids est activé
Quand je demande des recommandations
Alors tous les contenus tagués "Politique" sont automatiquement exclus Et ce indépendamment du paramètre "Masquer contenu politique"
8. Statistiques créateur sur contenu politique
Étant donné que je suis un créateur Et que j'ai publié 20 contenus dont 5 tagués "Politique"
Quand je consulte mes statistiques
Alors je vois le nombre d'utilisateurs ayant masqué le contenu politique Et le taux d'engagement comparé aux autres tags
9. Recherche avec tag "Politique"
Étant donné que je recherche du contenu
Quand je filtre par tag "Politique"
Alors seuls les contenus tagués "Politique" sont affichés Et ce même si j'ai activé "Masquer contenu politique" (recherche explicite)
10. Partage de contenu politique avec filtre actif
Étant donné que j'ai activé "Masquer contenu politique" Et qu'un ami me partage un lien vers un contenu tagué "Politique"
Quand j'ouvre le lien
Alors je peux accéder au contenu (partage explicite) Et je vois un avertissement "Ce contenu est tagué Politique"
11. Pas de classification gauche/droite en MVP
Étant donné que je suis un créateur
Quand je publie un contenu tagué "Politique"
Alors aucune option de classification idéologique n'est proposée Et je ne peux pas indiquer "Gauche", "Droite", "Centre", etc.
12. Pas d'équilibrage imposé en MVP
Étant donné qu'un utilisateur écoute majoritairement du contenu politique de gauche
Quand l'algorithme génère des recommandations
Alors aucun équilibrage droite/gauche n'est appliqué Et les recommandations suivent l'algorithme standard (intérêts, géo, engagement)
13. Notification post-MVP pour classification avancée
Étant donné que RoadWave passe en phase post-MVP Et que la classification politique avancée est activée
Quand je me connecte
Alors je reçois une notification m'informant des nouvelles options Et je peux configurer mes préférences d'équilibrage politique
Contenus géolocalisés en mode voiture
En tant qu'utilisateur en voiture Je veux recevoir des notifications de contenus géolocalisés au bon moment Afin de découvrir du contenu contextuel sans distraction au volant
36 scénarios (32 standards, 4 plans)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que l'application est ouverte (premier plan) Et que le GPS est activé Et que l'utilisateur est en mode voiture (vitesse ≥ 5 km/h)
1. Calcul ETA et notification 7 secondes avant le point GPS
Étant donné qu'un contenu géolocalisé existe à la Tour Eiffel (48.8584, 2.2945) Et que je me déplace à 50 km/h vers ce point Et que je suis à 98 mètres du point (ETA = 7 secondes)
Quand le système calcule l'ETA
Alors une notification est déclenchée immédiatement Et le compteur "7" s'affiche avec l'icône 🏛️ Et une notification sonore (bip court) est jouée
2. 📋 Plan: Calcul ETA à différentes vitesses
Étant donné qu'un contenu géolocalisé existe à un point GPS Et que je me déplace à km/h
Quand je suis à mètres du point
Alors l'ETA calculé est secondes Et la notification est déclenchée :
📊 Exemples de données:
| vitesse | distance | eta | notification |
|---|---|---|---|
| 10 | 19 | 7 | Oui |
| 50 | 98 | 7 | Oui |
| 130 | 252 | 7 | Oui |
| 50 | 200 | 14 | Non |
| 10 | 50 | 18 | Non |
3. Notification immédiate si vitesse <5 km/h ET distance <50m
Étant donné qu'un contenu géolocalisé existe à 30m de ma position Et que ma vitesse est 3 km/h (arrêté à un feu rouge)
Quand le système détecte cette situation
Alors une notification est déclenchée immédiatement Et je n'ai pas besoin d'attendre le calcul ETA
4. Notification minimaliste sans texte (sécurité routière)
Étant donné qu'une notification géolocalisée est déclenchée
Quand la notification s'affiche
Alors les éléments suivants sont visibles:
| élément | présent |
|---|---|
| Icône du tag | ✅ |
| Compteur 7→1 | ✅ |
| Son bref (bip) | ✅ |
| Titre texte | ❌ |
| Description | ❌ |
| Cover image | ❌ |
| Bouton Annuler | ❌ |
5. 📋 Plan: Icônes selon le tag du contenu
Étant donné qu'un contenu géolocalisé avec le tag est disponible
Quand la notification s'affiche
Alors l'icône est affichée
📊 Exemples de données:
| tag | icone |
|---|---|
| Culture générale | 🏛️ |
| Histoire | 📜 |
| Voyage | ✈️ |
| Famille | 👨👩👧 |
| Musique | 🎵 |
| Sport | ⚽ |
| Technologie | 💻 |
| Automobile | 🚗 |
6. Compteur décrémentant de 7 à 1
Étant donné qu'une notification géolocalisée s'affiche
Quand le compteur démarre
Alors le compteur affiche "7" Et après 1 seconde, il affiche "6" Et après 2 secondes, il affiche "5" Et après 3 secondes, il affiche "4" Et après 4 secondes, il affiche "3" Et après 5 secondes, il affiche "2" Et après 6 secondes, il affiche "1" Et après 7 secondes, la notification disparaît
7. Notification sonore uniquement en mode CarPlay
Étant donné que l'application est connectée à CarPlay Et qu'un contenu géolocalisé est détecté (ETA 7s)
Quand la notification est déclenchée
Alors seule la notification sonore (bip) est jouée Et aucun overlay visuel n'est affiché (icône, compteur) Et l'utilisateur peut valider via le bouton "Suivant" au volant
8. Notification sonore uniquement en mode Android Auto
Étant donné que l'application est connectée à Android Auto Et qu'un contenu géolocalisé est détecté (ETA 7s)
Quand la notification est déclenchée
Alors seule la notification sonore (bip) est jouée Et aucun overlay visuel n'est affiché Et l'utilisateur peut valider via le bouton "Suivant" au volant
9. Notification complète (sonore + visuelle) en mode normal
Étant donné que l'application n'est PAS connectée à CarPlay/Android Auto Et qu'un contenu géolocalisé est détecté
Quand la notification est déclenchée
Alors la notification sonore (bip) est jouée Et l'overlay visuel s'affiche (icône + compteur 7→1)
10. Validation via bouton "Suivant" et décompte 5 secondes
Étant donné qu'une notification géolocalisée est affichée (compteur à 5) Et que j'écoute un podcast
Quand j'appuie sur le bouton "Suivant"
Alors le compteur bascule à "5" (décompte final) Et le contenu actuel continue de jouer normalement Et le compteur décrémente: 5→4→3→2→1 Et après 5 secondes, le contenu géolocalisé démarre (fade in 0.3s)
11. Transition fluide avec fade out/in
Étant donné que le décompte atteint "0"
Quand le contenu géolocalisé doit démarrer
Alors le contenu actuel fait un fade out de 0.3s Et le contenu géolocalisé fait un fade in de 0.3s Et il n'y a pas de silence entre les deux
12. Contenu actuel se termine pendant le décompte
Étant donné que j'ai validé la notification (décompte 5s démarre) Et que mon contenu actuel se termine après 2 secondes
Quand le contenu actuel se termine
Alors le contenu suivant du buffer démarre immédiatement Et le décompte continue (3→2→1) Et à la fin du décompte, le contenu géolocalisé remplace le buffer
13. Ignorance de la notification (pas de clic pendant 7s)
Étant donné qu'une notification géolocalisée s'affiche (compteur 7)
Quand 7 secondes s'écoulent sans que j'appuie sur "Suivant"
Alors la notification disparaît automatiquement Et le contenu géolocalisé est perdu (pas d'insertion dans la file) Et un cooldown de 10 minutes est activé
14. Quota de 6 contenus géolocalisés par heure
Étant donné que j'ai validé 6 notifications géolocalisées dans la dernière heure
Quand un 7ème contenu géolocalisé est détecté
Alors aucune notification n'est envoyée Et le contenu n'est pas inséré dans la file
15. Fenêtre glissante de 60 minutes
Étant donné que j'ai validé 6 contenus géolocalisés Et que le premier contenu a été validé il y a 61 minutes
Quand un nouveau contenu géolocalisé est détecté
Alors la notification est envoyée (quota libéré : 5/6) Et le compteur horaire est mis à jour
16. 📋 Plan: Gestion du quota horaire
Étant donné que <nb_valides> notifications ont été validées dans la dernière heure
Quand un nouveau contenu géolocalisé est détecté
Alors la notification est
📊 Exemples de données:
| nb_valides | action |
|---|---|
| 0 | envoyée |
| 3 | envoyée |
| 5 | envoyée |
| 6 | non envoyée |
| 7 | non envoyée |
17. Exception audio-guides multi-séquences (comptent comme 1)
Étant donné que j'ai démarré un audio-guide avec 8 séquences Et que cet audio-guide compte comme 1 contenu dans le quota
Quand toutes les séquences de l'audio-guide sont lues
Alors mon quota reste à 1/6 Et je peux encore valider 5 contenus géolocalisés simples
18. Cooldown de 10 minutes après notification ignorée
Étant donné qu'une notification géolocalisée a été ignorée (pas de clic) Et qu'un cooldown de 10 minutes est activé
Quand 5 minutes s'écoulent Et qu'un nouveau contenu géolocalisé est détecté
Alors aucune notification n'est envoyée (cooldown actif)
19. Cooldown expire après 10 minutes
Étant donné qu'un cooldown a été activé il y a 10 minutes
Quand un nouveau contenu géolocalisé est détecté
Alors la notification est envoyée (cooldown expiré)
20. Pas de cooldown si notification validée
Étant donné qu'une notification géolocalisée est affichée
Quand j'appuie sur "Suivant" dans les 7 secondes
Alors aucun cooldown n'est activé Et la prochaine notification pourra être envoyée normalement
21. Contenu géolocalisé dans l'historique de navigation
Étant donné que j'écoute un contenu du buffer Et que j'ai validé un contenu géolocalisé "Tour Eiffel" Et que j'ai écouté 42 secondes du contenu géolocalisé
Quand j'appuie sur "Suivant" (skip) Et que j'appuie ensuite sur "Précédent"
Alors le contenu géolocalisé reprend à 42 secondes
22. Contenu ignoré n'entre pas dans l'historique
Étant donné qu'une notification géolocalisée a été ignorée
Quand j'appuie sur "Précédent"
Alors le contenu géolocalisé ignoré n'apparaît PAS dans l'historique Et je reviens au contenu d'avant
23. Skip pendant le décompte annule l'insertion
Étant donné que j'ai validé une notification (décompte 5s en cours) Et que le compteur affiche "3"
Quand j'appuie à nouveau sur "Suivant"
Alors le décompte est annulé Et le contenu suivant du buffer démarre Et le contenu géolocalisé n'entre PAS dans l'historique
24. Détection mode piéton (vitesse <5 km/h stable 10s)
Étant donné que je suis en mode voiture Et que ma vitesse passe à 3 km/h
Quand cette vitesse reste stable pendant 10 secondes
Alors le mode piéton est activé automatiquement Et les notifications passent en mode push arrière-plan (si permission accordée)
25. Détection mode voiture (vitesse ≥5 km/h stable 10s)
Étant donné que je suis en mode piéton Et que ma vitesse passe à 15 km/h
Quand cette vitesse reste stable pendant 10 secondes
Alors le mode voiture est activé automatiquement Et les notifications passent en mode sonore + icône (app premier plan requise)
26. Hysteresis pour éviter basculements intempestifs
Étant donné que ma vitesse passe de 20 km/h à 3 km/h (arrêt feu rouge) Et que ma vitesse remonte à 20 km/h après 8 secondes
Quand le système vérifie le mode
Alors aucun basculement n'a lieu (hysteresis de 10s non atteinte) Et je reste en mode voiture
27. 📋 Plan: Effets du basculement voiture → piéton
Étant donné que je bascule de voiture à piéton
Quand le basculement est effectué
Alors les paramètres suivants changent:
| paramètre | voiture | piéton |
|---|---|---|
| App requise | Premier plan | Arrière-plan OK |
| Notification | Sonore + icône + compteur | Push système |
| Rayon détection | ETA 7s (variable) | 200m fixes |
| Type contenu | Tous géolocalisés | Audio-guides uniquement |
28. Haute vitesse (130 km/h sur autoroute)
Étant donné que je roule à 130 km/h (36.1 m/s) Et qu'un contenu géolocalisé est à 252 mètres
Quand l'ETA de 7s est atteint Et que je valide la notification
Alors le décompte 5s démarre Et le contenu géolocalisé démarre encore avant le point GPS (72m avant)
29. Multiples points géolocalisés proches (route touristique)
Étant donné que 3 châteaux sont espacés de 800m chacun Et que je valide la notification du Château A
Quand j'arrive près du Château B (57s plus tard à 50 km/h)
Alors la notification du Château B est envoyée (quota 2/6, pas de cooldown)
30. Mode stationnement (vitesse <1 km/h pendant 2 min)
Étant donné que je me gare à 30m d'un château Et que ma vitesse est <1 km/h pendant 2 minutes
Quand le mode stationnement est détecté
Alors aucune notification de contenu géolocalisé n'est envoyée Et le système bascule automatiquement en mode piéton
31. Reprise conduite après stationnement
Étant donné que je suis en mode stationnement Et que ma vitesse passe à 20 km/h pendant 10 secondes
Quand le système détecte la reprise de conduite
Alors le mode voiture est réactivé Et les notifications géolocalisées reprennent (si quota non atteint)
32. Contenu géolocalisé simple (1 séquence unique)
Étant donné qu'un contenu géolocalisé simple existe à un point GPS
Quand la notification est déclenchée (ETA 7s) Et que je valide
Alors le contenu démarre après décompte 5s Et à la fin du contenu, le buffer normal reprend Et ce contenu compte 1/6 dans le quota
33. Audio-guide multi-séquences (2+ séquences enchaînées)
Étant donné qu'un audio-guide avec 8 séquences existe
Quand je démarre l'audio-guide Et que les séquences s'enchaînent automatiquement (GPS ou manuel)
Alors l'audio-guide entier compte 1/6 dans le quota Et les séquences ne déclenchent PAS de notification avec compteur 7s Et elles se déclenchent au point GPS exact (rayon 30m)
34. GPS désactivé en mode voiture
Étant donné que je suis en mode voiture
Quand le GPS est désactivé
Alors aucune notification géolocalisée ne peut être envoyée Et un message d'erreur s'affiche: "GPS requis pour les contenus géolocalisés"
35. App en arrière-plan en mode voiture
Étant donné que je suis en mode voiture Et que l'app passe en arrière-plan
Quand un contenu géolocalisé est détecté
Alors aucune notification n'est envoyée (app premier plan requise) Et le contenu n'est pas perdu (sera proposé si app rouverte dans le rayon)
36. Permission "Always Location" refusée (mode piéton indisponible)
Étant donné que je refuse la permission "Always Location"
Quand ma vitesse passe <5 km/h
Alors le mode piéton n'est PAS activé Et le mode voiture reste actif (avec permission "When In Use") Et aucune notification arrière-plan n'est envoyée
Gestion de l'historique et reproposition
En tant que système de recommandation Je veux gérer l'historique d'écoute intelligemment Afin d'éviter les répétitions et offrir une découverte maximale
19 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible
1. Contenu écouté complètement (>80%) - jamais reproposé
Étant donné qu'un utilisateur a écouté un contenu à 85%
Quand l'algorithme génère les recommandations
Alors ce contenu n'est jamais reproposé Et il est marqué comme "écouté" dans l'historique
2. Contenu écouté à 80% exactement - jamais reproposé
Étant donné qu'un utilisateur a écouté un contenu exactement à 80%
Quand l'algorithme génère les recommandations
Alors ce contenu n'est pas reproposé (seuil >= 80%)
3. Contenu skippé rapidement (<10s) - ne pas reproposer
Étant donné qu'un utilisateur a skippé un contenu après 8 secondes
Quand l'algorithme génère les recommandations
Alors ce contenu n'est pas reproposé (signal négatif fort) Et la jauge d'intérêt correspondante est réduite de 0.5%
4. Contenu skippé exactement à 10s - ne pas reproposer
Étant donné qu'un utilisateur a skippé un contenu après exactement 10 secondes
Quand l'algorithme génère les recommandations
Alors ce contenu n'est pas reproposé (seuil < 10s strict)
5. Contenu partiellement écouté (10-80%) - reproposer avec reprise
Étant donné qu'un utilisateur a écouté un contenu à 45% Et qu'il est arrivé à la position 2:30 (150 secondes)
Quand l'algorithme propose à nouveau ce contenu
Alors le contenu peut être reproposé Et la position de reprise est 150 secondes Et l'utilisateur voit "Reprendre à 2:30"
6. Contenu écouté à 11% - reproposition possible
Étant donné qu'un utilisateur a écouté un contenu à 11%
Quand l'algorithme génère les recommandations
Alors ce contenu peut être reproposé (>10%) Et la position de reprise est sauvegardée
7. Contenu écouté à 79% - reproposition possible
Étant donné qu'un utilisateur a écouté un contenu à 79%
Quand l'algorithme génère les recommandations
Alors ce contenu peut être reproposé (<80%) Et l'utilisateur peut terminer l'écoute
8. Audio-guide avec flag replayable=true
Étant donné qu'un audio-guide a le flag "replayable = true" Et qu'un utilisateur l'a écouté à 95%
Quand l'algorithme génère les recommandations
Alors l'audio-guide peut être reproposé Et il est marqué comme "Écouté - Rejouable"
9. Podcast standard sans flag replayable
Étant donné qu'un podcast n'a pas de flag replayable Et qu'un utilisateur l'a écouté à 90%
Quand l'algorithme génère les recommandations
Alors le podcast n'est jamais reproposé
10. Stockage dans user_content_history
Étant donné qu'un utilisateur écoute un contenu
Quand l'écoute se termine ou est skippée
Alors les données suivantes sont enregistrées:
| champ | exemple |
|---|---|
| user_id | user-123 |
| content_id | content-456 |
| completion_rate | 0.45 (45%) |
| last_position | 150 (secondes) |
| listened_at | 2026-01-21 14:30:00 |
11. Historique illimité stocké
Étant donné qu'un utilisateur a écouté 5000 contenus
Quand il consulte son historique
Alors tous les 5000 contenus sont disponibles Et aucun contenu n'est supprimé automatiquement
12. Algorithme considère les 100 derniers pour performance
Étant donné qu'un utilisateur a écouté 500 contenus
Quand l'algorithme génère les recommandations
Alors il vérifie uniquement les 100 derniers contenus pour exclusion Et cette limite est une optimisation de requête SQL
13. Export historique complet (RGPD)
Étant donné qu'un utilisateur demande l'export RGPD
Quand l'export est généré
Alors l'historique complet est inclus avec:
| information | inclus |
|---|---|
| Tous les contenus | ✅ |
| Dates d'écoute | ✅ |
| Taux complétion | ✅ |
| Positions reprise | ✅ |
14. Reprise automatique d'un contenu partiellement écouté
Étant donné que j'ai écouté un podcast à 60% (position 10:00)
Quand ce podcast est reproposé par l'algorithme Et que je lance la lecture
Alors l'écoute reprend automatiquement à 10:00 Et je vois une notification "Reprise à 10:00"
15. Option "Reprendre du début" pour contenu partiellement écouté
Étant donné que j'ai écouté un podcast à 60%
Quand ce podcast est reproposé
Alors je vois deux options:
| option | action |
|---|---|
| Reprendre à 10:00 | Lecture à partir de 10:00 |
| Depuis le début | Lecture à partir de 0:00 |
16. Contenu écouté il y a 6 mois - toujours en historique
Étant donné qu'un utilisateur a écouté un contenu il y a 6 mois à 90%
Quand l'algorithme génère les recommandations
Alors ce contenu n'est toujours pas reproposé Et l'historique n'a pas de limite temporelle
17. Nouveau contenu du même créateur après écoute complète
Étant donné qu'un utilisateur a écouté un contenu de "Créateur A" à 90% Et que "Créateur A" publie un nouveau contenu
Quand l'algorithme génère les recommandations
Alors le nouveau contenu peut être recommandé Et seul l'ancien contenu est exclu (pas tout le créateur)
18. Statistiques personnelles d'historique
Étant donné que je consulte mon profil
Quand j'accède à la section "Historique"
Alors je vois:
| métrique | exemple |
|---|---|
| Nombre total d'écoutes | 1,234 |
| Heures écoutées | 456h |
| Taux complétion moyen | 72% |
| Top 5 catégories | Voyage, Sport |
19. Filtrer l'historique par date
Étant donné que je consulte mon historique
Quand je filtre par "Dernière semaine"
Alors seuls les contenus écoutés dans les 7 derniers jours sont affichés Et je peux exporter cette sélection
Médias traditionnels sur RoadWave
En tant que média établi Je veux publier du contenu géolocalisé sur RoadWave Afin d'atteindre une audience locale et mobile
21 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible
1. Création d'un compte média vérifié
Étant donné que je représente Le Monde
Quand je crée un compte média Et que je fournis les justificatifs (SIRET, documents officiels)
Alors mon compte est créé en attente de vérification Et l'équipe RoadWave examine ma demande sous 48-72h
2. Validation compte média par l'équipe RoadWave
Étant donné qu'un compte média "Le Parisien" est en attente
Quand l'équipe RoadWave valide le compte
Alors le compte reçoit le badge vérifié ✓ Et le média peut publier sans validation des 3 premiers contenus Et je vois le message "Compte média vérifié avec succès"
3. Badge vérifié visible sur profil média
Étant donné que "France Inter" a un compte vérifié
Quand un utilisateur consulte le profil
Alors il voit le badge ✓ à côté du nom Et une mention "Média vérifié"
4. Pas de validation des 3 premiers contenus pour médias
Étant donné que je suis un média vérifié
Quand je publie mon premier contenu
Alors le contenu est publié immédiatement sans validation Et il est visible pour tous les utilisateurs Et je ne passe pas par la modération initiale
5. Modération a posteriori uniquement
Étant donné que "Libération" publie un contenu
Quand le contenu est publié
Alors il est immédiatement disponible Mais peut être signalé et modéré a posteriori Et suit les mêmes règles de modération que les créateurs
6. Publication flash info géolocalisé
Étant donné que je suis "Ouest-France" (média régional)
Quand je publie un flash info sur un événement à Rennes Et que je le géolocalise en Bretagne (géo-contextuel)
Alors le contenu est publié immédiatement Et il est recommandé aux utilisateurs en Bretagne
7. Publication chronique thématique
Étant donné que je suis "France Culture"
Quand je publie une chronique philosophie (géo-neutre)
Alors le contenu est disponible partout en France Et suit l'algorithme de recommandation standard
8. Publication édito politique
Étant donné que je suis "Le Figaro"
Quand je publie un édito politique Et que je le tague "Politique"
Alors le contenu est publié immédiatement Et la classification politique MVP s'applique (pas gauche/droite) Et les utilisateurs ayant activé "Masquer politique" ne le voient pas
9. Formats de contenu autorisés pour médias
Étant donné que je suis un média vérifié
Quand je publie du contenu
Alors je peux publier:
| format | exemple |
|---|---|
| Flash info géolocalisé | Actualité régionale 2-5 min |
| Chronique thématique | Culture, économie, sport 5-15min |
| Édito et débats | Opinion 10-30 min |
| Reportage | Investigation 15-45 min |
10. Médias suivent les règles standard de classification âge
Étant donné que je suis "RTL"
Quand je publie un contenu sensible
Alors je dois obligatoirement classifier par âge:
| classification | type contenu |
|---|---|
| Tout public | Info générale |
| 13+ | Actualité avec sujets sensibles |
| 16+ | Débats avec violence verbale |
| 18+ | Sujets adultes |
11. Monétisation médias - partage revenus pub standard
Étant donné que je suis un média vérifié Et que mes contenus génèrent des écoutes
Quand le mois se termine
Alors je reçois 3€ / 1000 écoutes complètes (même taux que créateurs) Et le paiement suit les mêmes règles (seuil 50€, mensuel)
12. Sponsoring direct non géré par plateforme
Étant donné que je suis "Europe 1" Et que je veux intégrer un sponsor dans mon contenu
Quand je mentionne le sponsor dans l'audio
Alors c'est autorisé (sponsoring éditorial) Mais RoadWave ne gère pas la transaction Et je gère la relation sponsor directement
13. Médias peuvent avoir plusieurs comptes créateurs
Étant donné que je suis "Le Monde"
Quand je veux créer des sous-comptes par rubrique
Alors je peux créer:
| compte | description |
|---|---|
| @lemonde_politique | Actualité politique |
| @lemonde_economie | Économie et entreprises |
| @lemonde_culture | Culture et spectacles |
Et tous sont liés au compte média principal
14. Médias régionaux privilégiés localement
Étant donné que "Sud-Ouest" publie du contenu géo-contextuel en Nouvelle-Aquitaine Et qu'un utilisateur est à Bordeaux
Quand l'algorithme calcule les recommandations
Alors le contenu de "Sud-Ouest" a un score géo élevé Et il est privilégié pour l'audience locale
15. Médias nationaux accessibles partout
Étant donné que "France Inter" publie un podcast géo-neutre
Quand des utilisateurs à Paris, Lyon, Marseille demandent des recommandations
Alors le podcast est accessible partout sans distinction géographique Et suit l'algorithme de recommandation standard
16. Statistiques détaillées pour médias
Étant donné que je suis un média vérifié
Quand je consulte mes statistiques
Alors je vois:
| métrique | exemple |
|---|---|
| Écoutes par région | Île-de-France: 45% |
| Taux complétion | 72% |
| Démographie auditeurs | 25-34 ans: 35% |
| Top contenus | Flash info Paris |
| Revenus générés | 1,234€ |
17. Médias peuvent exporter analytics
Étant donné que je suis "Libération"
Quand je clique sur "Exporter analytics"
Alors je reçois un CSV avec données détaillées Et je peux analyser les données avec mes outils internes
18. Contact prioritaire équipe RoadWave
Étant donné que je suis un média vérifié
Quand j'ai un problème technique ou question
Alors je peux contacter le support média prioritaire Et j'obtiens une réponse sous 24h (vs 48-72h standard)
19. Médias peuvent programmer la publication
Étant donné que je suis "France Culture"
Quand je prépare un contenu à l'avance
Alors je peux programmer la publication pour une date/heure future Et le contenu sera publié automatiquement au moment choisi
20. API dédiée pour médias (post-MVP)
Étant donné que je suis un grand média avec beaucoup de contenus
Quand RoadWave développe l'API médias
Alors je peux automatiser la publication via API Et intégrer RoadWave dans mon workflow de production
21. Signalement d'un contenu média traité en priorité
Étant donné qu'un contenu de "Le Monde" est signalé
Quand le signalement arrive en modération
Alors il est traité avec la même priorité qu'un créateur standard Et le badge vérifié ne donne pas d'immunité modération
Mode Kids pour utilisateurs 13-15 ans
En tant que parent ou adolescent Je veux activer un mode Kids avec filtrage de contenu Afin de protéger les mineurs des contenus inappropriés
15 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible
1. Activation manuelle du mode Kids
Étant donné que je suis un utilisateur de 14 ans Et que le mode Kids n'est pas activé par défaut
Quand j'active le mode Kids dans les paramètres
Alors le mode Kids est activé sur mon compte Et je vois le message "Mode Kids activé - Contenus filtrés pour 13-15 ans"
2. Parent active le mode Kids pour son enfant
Étant donné que je suis le parent d'un utilisateur de 13 ans Et que j'ai accès au compte de mon enfant
Quand j'active le mode Kids
Alors le mode Kids est activé sur le compte enfant Et seuls les contenus "Tous publics" sont accessibles
3. Filtrage contenu - uniquement "Tous publics"
Étant donné que le mode Kids est activé sur mon compte Et qu'il existe des contenus avec les classifications:
| classification | nombre |
|---|---|
| Tous publics | 100 |
| 13+ | 50 |
| 16+ | 30 |
| 18+ | 20 |
Quand je demande des recommandations
Alors seuls les 100 contenus "Tous publics" sont proposés Et les contenus 13+, 16+, 18+ sont exclus
4. Exclusion automatique du contenu politique
Étant donné que le mode Kids est activé Et qu'il existe 20 contenus "Tous publics" dont 5 tagués "Politique"
Quand je demande des recommandations
Alors seuls les 15 contenus non-politiques sont proposés Et les 5 contenus politiques sont automatiquement exclus
5. Pas de publicité en mode Kids
Étant donné que le mode Kids est activé Et que je suis un utilisateur gratuit
Quand j'écoute du contenu
Alors aucune publicité n'est diffusée Et je n'ai pas d'insertion publicitaire (règle 1/5 désactivée)
6. Publicité validée manuellement en mode Kids (post-MVP)
Étant donné que le mode Kids est activé Et qu'une publicité a été validée manuellement pour le mode Kids
Quand j'écoute du contenu
Alors cette publicité peut être diffusée Mais la fréquence reste inférieure au mode standard
7. Interface standard même en mode Kids
Étant donné que le mode Kids est activé
Quand j'ouvre l'application
Alors l'interface est identique au mode normal Et seul le filtrage de contenu est actif (pas d'UI enfant)
8. Désactivation du mode Kids
Étant donné que le mode Kids est activé
Quand je désactive le mode Kids dans les paramètres
Alors tous les contenus sont à nouveau accessibles selon mon âge Et je vois le message "Mode Kids désactivé"
9. Utilisateur 16 ans ne peut pas activer le mode Kids 13-15 ans
Étant donné que je suis un utilisateur de 16 ans
Quand j'essaie d'activer le mode Kids
Alors l'activation réussit Et le mode Kids filtre les contenus 16+ et 18+ (pas seulement 13+) Et je vois uniquement les contenus "Tous publics"
10. Tentative d'accès direct à contenu 16+ en mode Kids
Étant donné que le mode Kids est activé Et qu'un ami me partage un contenu 16+
Quand j'essaie d'accéder au contenu via le lien
Alors l'accès est refusé Et je vois le message "Ce contenu n'est pas accessible en mode Kids"
11. Recherche en mode Kids filtre automatiquement
Étant donné que le mode Kids est activé
Quand je recherche "débat"
Alors seuls les contenus "Tous publics" apparaissent dans les résultats Et les contenus 13+, 16+, 18+ sont exclus de la recherche
12. Audio-guide en mode Kids
Étant donné que le mode Kids est activé Et qu'un audio-guide "Tous publics" existe au musée du Louvre
Quand je suis à proximité du Louvre
Alors l'audio-guide est proposé normalement Et toutes les séquences sont accessibles
13. Statistiques créateur - audience mode Kids
Étant donné que je suis un créateur Et que mes contenus "Tous publics" sont écoutés par des utilisateurs mode Kids
Quand je consulte mes statistiques
Alors je vois le pourcentage d'écoutes en mode Kids Et je peux adapter mes contenus en conséquence
14. Notification lors de l'activation du mode Kids
Quand j'active le mode Kids
Alors je reçois une notification explicative:
| information | description |
|---|---|
| Contenu | Seuls les contenus "Tous publics" accessibles |
| Politique | Contenus politiques automatiquement masqués |
| Publicité | Aucune publicité affichée |
15. Badge mode Kids visible dans le profil
Étant donné que le mode Kids est activé
Quand je consulte mon profil
Alors je vois un badge "Mode Kids actif 🛡️" Et je peux le désactiver en un clic
Paramétrabilité admin et A/B testing
En tant qu'administrateur RoadWave Je veux configurer les paramètres de l'algorithme à chaud Afin d'optimiser l'engagement sans redéploiement
20 scénarios (19 standards, 1 plan)
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis connecté en tant qu'admin
1. Accès au dashboard admin
Quand j'accède au dashboard admin
Alors je vois tous les paramètres configurables de l'algorithme Et je vois les valeurs actuelles et par défaut
2. Modifier le poids géo pour contenu ancré
Étant donné que le poids_geo_ancre est à 0.7 (défaut)
Quand je modifie le poids_geo_ancre à 0.8 Et que je sauvegarde
Alors la nouvelle valeur est appliquée immédiatement Et tous les nouveaux calculs utilisent 0.8 Et je vois le message "Paramètre mis à jour avec succès"
3. Validation des plages de valeurs
Quand j'essaie de configurer poids_geo_ancre à 1.5 (hors plage 0.5-1.0)
Alors la modification échoue Et je vois le message "Valeur hors plage autorisée (0.5 - 1.0)"
4. 📋 Plan: Modification de tous les paramètres configurables
Quand je modifie "" à "<nouvelle_valeur>"
Alors la modification est appliquée immédiatement Et la nouvelle valeur respecte la plage ""
📊 Exemples de données:
| parametre | nouvelle_valeur | plage |
|---|---|---|
| poids_geo_ancre | 0.8 | 0.5 - 1.0 |
| poids_geo_contextuel | 0.6 | 0.3 - 0.7 |
| poids_geo_neutre | 0.3 | 0.0 - 0.4 |
| poids_engagement | 0.3 | 0.0 - 0.5 |
| part_aleatoire_global | 0.15 | 0.0 - 0.3 |
| distance_max_km | 150 | 50 - 500 |
| rayon_gps_point_m | 1000 | 100 - 2000 |
| seuil_min_ecoutes_engagement | 100 | 10 - 200 |
5. Aucun recalcul batch après modification
Étant donné que le poids_geo_ancre est modifié de 0.7 à 0.8
Quand la modification est appliquée
Alors aucun recalcul batch n'est lancé (économie CPU) Et seuls les nouveaux calculs utilisent la valeur 0.8
6. Versioning des configurations
Étant donné que je modifie plusieurs paramètres
Quand je sauvegarde la configuration
Alors une nouvelle version est créée (ex: v1.2.3) Et je peux voir l'historique des versions Et je peux comparer deux versions
7. Rollback en 1 clic
Étant donné que la configuration actuelle est v1.2.3 Et que la version précédente était v1.2.2
Quand je clique sur "Restaurer v1.2.2"
Alors tous les paramètres de v1.2.2 sont réappliqués Et je vois le message "Configuration restaurée à v1.2.2"
8. Créer une variante A/B testing
Quand je crée une nouvelle variante "Test engagement élevé" Et que je configure:
| parametre | valeur |
|---|---|
| poids_engagement | 0.4 |
| poids_geo_ancre | 0.6 |
Et que je lance le test A/B
Alors 50% des utilisateurs reçoivent la Config A (défaut) Et 50% des utilisateurs reçoivent la Config B (test)
9. Split utilisateurs aléatoire pour A/B test
Étant donné qu'un test A/B est actif
Quand 1000 nouveaux utilisateurs se connectent
Alors environ 500 sont assignés à la Config A Et environ 500 sont assignés à la Config B Et l'assignation est aléatoire et équilibrée
10. Utilisateur reste dans la même variante
Étant donné qu'un utilisateur est assigné à la Config B
Quand il se reconnecte plusieurs fois
Alors il reste toujours dans la Config B Et il ne change pas de variante pendant le test
11. Métriques comparatives A/B testing
Étant donné qu'un test A/B est actif depuis 7 jours
Quand je consulte le dashboard A/B testing
Alors je vois les métriques suivantes pour chaque config:
| metrique | Config A | Config B |
|---|---|---|
| Taux complétion moyen | 68% | 72% |
| Engagement (likes) | 15% | 18% |
| Durée session moyenne | 23 min | 27 min |
| Taux skip rapide (<10s) | 12% | 9% |
12. Dashboard graphique temps réel
Étant donné qu'un test A/B est actif
Quand je consulte le dashboard
Alors je vois des graphiques temps réel:
| graphique | type |
|---|---|
| Évolution engagement | Ligne |
| Répartition utilisateurs | Camembert |
| Taux complétion | Barres |
| Durée session | Ligne |
13. Terminer un test A/B et appliquer la meilleure config
Étant donné qu'un test A/B montre que Config B est meilleure
Quand je clique sur "Appliquer Config B pour tous"
Alors la Config B devient la configuration par défaut Et tous les utilisateurs utilisent maintenant Config B Et l'ancien test est archivé
14. Audit engagement global
Quand je consulte la section "Audit engagement"
Alors je vois:
| metrique | valeur |
|---|---|
| Temps écoute moyen/session | 25 min |
| Temps écoute médian/session | 18 min |
| Taux complétion moyen | 70% |
| % sessions avec ≥1 like | 35% |
15. Graphiques évolution engagement selon config
Étant donné que plusieurs modifications de config ont été faites
Quand je consulte les graphiques d'évolution
Alors je vois l'impact de chaque changement de config Et je peux corréler changements config avec métriques
16. Export CSV pour analyse externe
Quand je clique sur "Exporter données"
Alors je peux télécharger un CSV avec:
| colonne | exemple |
|---|---|
| date | 2026-01-21 |
| version_config | v1.2.3 |
| taux_completion | 0.72 |
| engagement_moyen | 0.45 |
| duree_session_min | 27 |
17. Alerte automatique si métrique critique baisse
Étant donné que le taux de complétion moyen est à 70%
Quand une nouvelle config fait baisser le taux à 55%
Alors je reçois une alerte email "Baisse critique du taux de complétion" Et je peux rollback rapidement
18. Prévisualisation impact avant application
Étant donné que je modifie poids_geo_ancre de 0.7 à 0.9
Quand je clique sur "Prévisualiser impact"
Alors je vois une simulation sur échantillon de 1000 utilisateurs Et je vois l'estimation d'impact sur les métriques clés
19. Notes et commentaires sur modifications config
Quand je modifie une configuration
Alors je peux ajouter une note "Test pour améliorer contenu local" Et cette note est visible dans l'historique des versions Et l'équipe peut comprendre le contexte des changements
20. Permissions admin pour modification config
Étant donné que je suis un admin junior
Quand j'essaie de modifier un paramètre critique
Alors l'accès est refusé Et je vois "Permission admin senior requise" Et seuls les admins seniors peuvent modifier les paramètres
Paramétrabilité utilisateur et profils
En tant qu'utilisateur Je veux personnaliser mon expérience de recommandation Afin d'adapter l'application à mes différents contextes d'usage
25 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible Et que je suis connecté
1. Accès aux paramètres de personnalisation
Quand j'ouvre les paramètres de personnalisation
Alors je vois trois curseurs disponibles:
| curseur | description |
|---|---|
| Géolocalisation | Local ← slider → National |
| Découverte | 0% ← slider → 50% |
| Politique | Masquer / Équilibré / Mes préférences |
2. Modifier le curseur Géolocalisation vers Local
Étant donné que le curseur Géolocalisation est au centre (défaut)
Quand je déplace le curseur vers "Local" (gauche)
Alors l'algorithme privilégie fortement les contenus proches Et la pondération géographique augmente Et je vois le message "Recommandations locales privilégiées"
3. Modifier le curseur Géolocalisation vers National
Étant donné que le curseur Géolocalisation est au centre
Quand je déplace le curseur vers "National" (droite)
Alors l'algorithme privilégie la découverte nationale Et la pondération géographique diminue Et je reçois des contenus de toute la France
4. Curseur Découverte à 0% - aucun aléatoire
Quand je règle le curseur Découverte à 0%
Alors 0% de contenus aléatoires dans mes recommandations Et 100% de contenus calculés selon score combiné Et je vois le message "Personnalisation maximale"
5. Curseur Découverte à 10% - défaut équilibré
Quand je règle le curseur Découverte à 10%
Alors 10% de contenus aléatoires Et 90% de contenus calculés Et je vois le message "Équilibre découverte/personnalisation"
6. Curseur Découverte à 30% - découverte élevée
Quand je règle le curseur Découverte à 30%
Alors 30% de contenus aléatoires Et 70% de contenus calculés Et je vois le message "Découverte élevée activée"
7. Curseur Découverte à 50% - découverte maximale
Quand je règle le curseur Découverte à 50%
Alors 50% de contenus aléatoires Et 50% de contenus calculés Et je vois le message "Découverte maximale (équivaut à national)"
8. Créer un profil personnalisé "Trajet quotidien"
Quand je crée un nouveau profil nommé "🚗 Trajet quotidien" Et que je configure:
| parametre | valeur |
|---|---|
| Géolocalisation | Local |
| Découverte | 5% |
| Politique | Masquer |
Et que je sauvegarde
Alors le profil "🚗 Trajet quotidien" est créé Et je peux l'activer en un clic
9. Créer un profil "Road trip"
Quand je crée un profil "🛣️ Road trip" Et que je configure:
| parametre | valeur |
|---|---|
| Géolocalisation | Régional |
| Découverte | 30% |
| Politique | Équilibré |
Alors le profil est sauvegardé Et je peux switcher entre profils facilement
10. Créer un profil "Enfants"
Quand je crée un profil "👶 Enfants" Et que j'active le Mode Kids
Alors tous les paramètres sont adaptés pour enfants:
| parametre | valeur |
|---|---|
| Mode Kids | Activé |
| Politique | Masquer (forcé) |
| Publicité | Aucune |
11. Activer un profil existant
Étant donné que j'ai créé un profil "🚗 Trajet quotidien"
Quand je clique sur "Activer" pour ce profil
Alors tous les paramètres du profil sont appliqués Et je vois le message "Profil 'Trajet quotidien' activé" Et l'algorithme utilise ces paramètres immédiatement
12. Synchronisation profils entre devices
Étant donné que j'ai créé 3 profils sur mon iPhone
Quand je me connecte sur mon iPad
Alors mes 3 profils sont automatiquement synchronisés Et je peux les utiliser sur l'iPad
13. Modification d'un profil synchronisée
Étant donné que j'ai un profil "Road trip" sur iPhone
Quand je modifie ce profil sur iPhone
Alors la modification est synchronisée sur tous mes devices Et le profil est mis à jour partout en temps réel
14. Pas de partage de profils entre utilisateurs
Étant donné que j'ai créé des profils personnalisés Et que ma conjointe a un compte RoadWave
Quand elle se connecte sur son compte
Alors elle ne voit pas mes profils Et chaque utilisateur a ses propres profils
15. Auto-switch selon contexte (détection trajet récurrent)
Étant donné que j'utilise toujours le profil "Trajet quotidien" Et que je pars de chez moi vers mon travail tous les matins à 8h
Quand le système détecte ce trajet récurrent
Alors le profil "Trajet quotidien" est activé automatiquement Et je reçois une notification "Profil 'Trajet quotidien' activé"
16. Désactiver l'auto-switch
Étant donné que l'auto-switch de profil est actif
Quand je désactive cette option dans les paramètres
Alors les profils ne changent plus automatiquement Et je dois les activer manuellement
17. Blocage modification si vitesse GPS >10 km/h
Étant donné que je conduis à 50 km/h
Quand j'essaie de modifier un curseur
Alors la modification est bloquée Et je vois le message "Modification impossible pendant la conduite" Et je dois m'arrêter ou être passager pour modifier
18. Modification possible si vitesse <10 km/h
Étant donné que je suis arrêté à un feu rouge (5 km/h)
Quand j'essaie de modifier un curseur
Alors la modification est autorisée Et je peux ajuster les paramètres
19. Warning au lancement app
Quand je lance l'application pour la première fois
Alors je vois un warning "Configurez vos préférences avant de prendre la route" Et un bouton "Configurer maintenant" Et je peux accéder rapidement aux paramètres
20. Modification uniquement app arrêtée ou mode passager
Étant donné que je suis passager dans une voiture Et que le mode passager est activé
Quand j'essaie de modifier les paramètres
Alors la modification est autorisée Et le blocage vitesse GPS ne s'applique pas
21. Statistiques d'utilisation des profils
Étant donné que j'utilise plusieurs profils
Quand je consulte mes statistiques
Alors je vois:
| metrique | exemple |
|---|---|
| Profil le plus utilisé | Trajet quotidien |
| Heures par profil | 25h / 10h / 5h |
| Dernier profil actif | Road trip |
22. Supprimer un profil
Étant donné que j'ai créé un profil "Test"
Quand je supprime ce profil
Alors le profil est définitivement supprimé Et je vois le message "Profil 'Test' supprimé" Et il disparaît de tous mes devices
23. Limite de profils par utilisateur
Étant donné que j'ai créé 10 profils
Quand j'essaie de créer un 11ème profil
Alors la création échoue Et je vois le message "Maximum 10 profils par utilisateur"
24. Dupliquer un profil existant
Étant donné que j'ai un profil "Trajet quotidien"
Quand je clique sur "Dupliquer"
Alors un nouveau profil "Trajet quotidien (copie)" est créé Et il a les mêmes paramètres que l'original Et je peux le modifier indépendamment
25. Réinitialiser un profil aux valeurs par défaut
Étant donné que j'ai modifié un profil
Quand je clique sur "Réinitialiser"
Alors tous les paramètres reviennent aux valeurs par défaut:
| parametre | valeur défaut |
|---|---|
| Géolocalisation | Équilibré |
| Découverte | 10% |
| Politique | Équilibré |
Formule de scoring et recommandation
En tant que système de recommandation Je veux calculer un score combiné pour chaque contenu Afin de proposer les contenus les plus pertinents à l'utilisateur
21 scénarios
Contexte commun à tous les scénarios
Étant donné que l'API RoadWave est disponible
1. Calcul du score géographique linéaire
Étant donné qu'un contenu existe à Paris Et que la distance_max_km est configurée à 200 km
Quand un utilisateur est à 50 km du contenu
Alors le score_geo = 1 - (50 / 200) = 0.75
2. Score géo à distance nulle (sur place)
Étant donné qu'un contenu existe à un point GPS précis
Quand un utilisateur est exactement au même point (0 km)
Alors le score_geo = 1.0 (maximum)
3. Score géo à distance_max (200 km)
Étant donné qu'un contenu existe à Paris
Quand un utilisateur est à 200 km du contenu
Alors le score_geo = 1 - (200 / 200) = 0.0
4. Score géo au-delà de distance_max
Étant donné qu'un contenu existe à Paris
Quand un utilisateur est à 250 km du contenu (au-delà de 200 km max)
Alors le score_geo = 0.0 (minimum) Et le contenu a peu de chances d'être recommandé sauf engagement très élevé
5. Calcul du score d'intérêts avec jauges utilisateur
Étant donné qu'un utilisateur a les jauges suivantes:
| categorie | niveau |
|---|---|
| Automobile | 80% |
| Voyage | 60% |
| Musique | 40% |
Et qu'un contenu est tagué "Automobile" et "Voyage"
Quand l'algorithme calcule le score_interets
Alors score_interets = (0.8 + 0.6) / 2 = 0.7
6. Score d'intérêts avec un seul tag
Étant donné qu'un utilisateur a la jauge "Économie" à 90% Et qu'un contenu est tagué uniquement "Économie"
Quand l'algorithme calcule le score_interets
Alors score_interets = 0.9
7. Score d'intérêts avec tags non matchés
Étant donné qu'un utilisateur a des jauges "Sport" et "Politique" élevées Et qu'un contenu est tagué "Musique" et "Philosophie" Et que l'utilisateur n'a pas ces catégories
Quand l'algorithme calcule le score_interets
Alors score_interets = 0.5 (neutre par défaut pour catégories inconnues)
8. Calcul du score d'engagement avec métriques
Étant donné qu'un contenu a:
| metrique | valeur |
|---|---|
| ecoutes | 1000 |
| ecoutes_completes | 700 |
| likes | 300 |
| abonnements_apres | 50 |
Quand l'algorithme calcule le score_engagement
Alors taux_completion = 700 / 1000 = 0.7 Et ratio_likes = 300 / 1000 = 0.3 Et ratio_abonnements = 50 / 1000 = 0.05 Et score_engagement = (0.7 × 0.5) + (0.3 × 0.3) + (0.05 × 0.2) = 0.35 + 0.09 + 0.01 = 0.45
9. Contenu avec moins de 50 écoutes - score neutre
Étant donné qu'un contenu a seulement 30 écoutes
Quand l'algorithme calcule le score_engagement
Alors score_engagement = 0.5 (neutre par défaut) Et le contenu n'est pas pénalisé pour manque de données
10. Contenu avec exactement 50 écoutes - calcul réel
Étant donné qu'un contenu a exactement 50 écoutes Et des métriques d'engagement complètes
Quand l'algorithme calcule le score_engagement
Alors le score est calculé normalement (pas de seuil neutre)
11. Bonus aléatoire - 10% des recommandations
Étant donné qu'un utilisateur demande 10 recommandations Et que la part_aleatoire_global est à 10%
Quand l'algorithme génère les recommandations
Alors 1 contenu sur 10 est tiré aléatoirement Et 9 contenus sont calculés avec le score combiné Et le contenu aléatoire n'est pas dans l'historique déjà écouté
12. Curseur utilisateur découverte à 0% - aucun aléatoire
Étant donné qu'un utilisateur configure le curseur découverte à 0%
Quand l'utilisateur demande 20 recommandations
Alors les 20 contenus sont calculés avec le score combiné Et aucun contenu aléatoire n'est proposé
13. Curseur utilisateur découverte à 50% - découverte max
Étant donné qu'un utilisateur configure le curseur découverte à 50%
Quand l'utilisateur demande 20 recommandations
Alors 10 contenus sont tirés aléatoirement Et 10 contenus sont calculés avec le score combiné
14. Score final combiné pour contenu géo-ancré
Étant donné qu'un contenu "Géo-ancré" a:
| parametre | valeur |
|---|---|
| score_geo | 0.9 |
| score_interets | 0.6 |
| score_engagement | 0.45 |
| poids_geo | 0.7 |
| poids_interets | 0.1 |
| poids_engagement | 0.2 |
Quand l'algorithme calcule le score_final
Alors score_final = (0.9 × 0.7) + (0.6 × 0.1) + (0.45 × 0.2) Et score_final = 0.63 + 0.06 + 0.09 = 0.78
15. Score final combiné pour contenu géo-neutre
Étant donné qu'un contenu "Géo-neutre" a:
| parametre | valeur |
|---|---|
| score_geo | 0.3 |
| score_interets | 0.9 |
| score_engagement | 0.6 |
| poids_geo | 0.2 |
| poids_interets | 0.6 |
| poids_engagement | 0.2 |
Quand l'algorithme calcule le score_final
Alors score_final = (0.3 × 0.2) + (0.9 × 0.6) + (0.6 × 0.2) Et score_final = 0.06 + 0.54 + 0.12 = 0.72 Et le contenu peut être recommandé malgré la distance
16. Contenu viral lointain peut être recommandé
Étant donné qu'un contenu viral existe à Paris Et qu'il a un score_engagement très élevé de 0.95 Et qu'un utilisateur est à Marseille (score_geo = 0.1)
Quand l'algorithme calcule le score_final
Alors le score_engagement élevé compense le score_geo faible Et le contenu peut apparaître dans les recommandations
17. Ordre de recommandation par score décroissant
Étant donné 5 contenus avec les scores suivants:
| contenu | score_final |
|---|---|
| Contenu A | 0.85 |
| Contenu B | 0.72 |
| Contenu C | 0.90 |
| Contenu D | 0.65 |
| Contenu E | 0.78 |
Quand l'utilisateur demande des recommandations
Alors l'ordre de proposition est:
| position | contenu |
|---|---|
| 1 | Contenu C |
| 2 | Contenu A |
| 3 | Contenu E |
| 4 | Contenu B |
| 5 | Contenu D |
18. Exclusion de l'historique déjà écouté >80%
Étant donné qu'un utilisateur a écouté les contenus suivants:
| contenu | completion |
|---|---|
| Contenu A | 85% |
| Contenu B | 95% |
| Contenu C | 30% |
Quand l'algorithme génère les recommandations
Alors "Contenu A" et "Contenu B" ne sont jamais proposés Mais "Contenu C" peut être reproposé
19. Pré-calcul de 5 contenus suivants
Étant donné qu'un utilisateur écoute un contenu
Quand l'algorithme prépare les contenus suivants
Alors 5 contenus sont pré-calculés selon le score Et ces contenus sont mis en cache pour performance
20. Recalcul si déplacement >10 km
Étant donné que 5 contenus suivants sont pré-calculés Et que l'utilisateur se déplace de 12 km
Quand l'utilisateur demande le contenu suivant
Alors l'algorithme recalcule les scores avec la nouvelle position Et propose de nouveaux contenus plus pertinents géographiquement
21. Recalcul après 10 minutes d'inactivité
Étant donné que 5 contenus suivants sont pré-calculés Et que 11 minutes se sont écoulées sans action
Quand l'utilisateur demande le contenu suivant
Alors l'algorithme recalcule les scores Et prend en compte les nouveaux contenus publiés
Anonymisation des données GPS après 24h
18 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis un utilisateur avec le GPS activé Et que j'utilise l'application depuis plusieurs jours
1. Conservation des données GPS précises pendant 24h
Étant donné que j'écoute un contenu à la position GPS 48.8566, 2.3522 (Paris, Tour Eiffel) Et qu'il est 10:00 le 2025-01-20
Quand l'événement d'écoute est enregistré en base de données
Alors les coordonnées précises 48.8566, 2.3522 sont stockées
Et le champ anonymized est à false
Et le champ created_at contient "2025-01-20 10:00:00"
Et ces données précises servent à la recommandation personnalisée
2. Conversion en geohash après 24h
Étant donné que j'ai écouté un contenu le 2025-01-20 à 10:00 à la position 48.8566, 2.3522
Quand le job quotidien d'anonymisation s'exécute le 2025-01-21 à 02:00
Alors les coordonnées précises sont converties en geohash précision 5
Et le geohash correspond à une zone d'environ 5km²
Et les coordonnées originales 48.8566, 2.3522 sont supprimées définitivement
Et le champ anonymized passe à true
Et il est impossible de retrouver la position précise d'origine
3. Requête SQL d'anonymisation (PostGIS)
Étant donné que le job quotidien d'anonymisation s'exécute
Quand la requête SQL suivante est exécutée:
Alors toutes les positions vieilles de plus de 24h sont anonymisées Et le processus est automatique et irréversible Et les données sont conformes RGPD
4. Précision du geohash niveau 5
Étant donné qu'une position GPS est convertie en geohash précision 5
Quand on analyse la zone couverte
Alors la zone fait environ 5km² (4.9km × 4.9km) Et cette précision est suffisante pour des analytics agrégées Et cette précision ne permet pas d'identifier un individu (conformité CNIL)
5. Exemple de conversion Paris
Étant donné que ma position précise est 48.8566, 2.3522 (Tour Eiffel)
Quand la conversion en geohash précision 5 est appliquée
Alors le geohash généré est "u09wh" Et ce geohash couvre une zone de ~5km² autour de la Tour Eiffel Et toutes les positions dans cette zone partagent le même geohash Et il est impossible de distinguer deux utilisateurs dans cette zone
6. Conservation de l'historique personnel utilisateur
Étant donné que j'ai écouté des contenus aux positions suivantes:
| date | heure | latitude | longitude | lieu |
|---|---|---|---|---|
| 2025-01-15 | 08:30 | 48.8566 | 2.3522 | Paris |
| 2025-01-16 | 14:00 | 43.6047 | 1.4442 | Toulouse |
| 2025-01-17 | 19:00 | 45.7640 | 4.8357 | Lyon |
Quand j'ouvre mon historique personnel dans "Profil > Mes trajets"
Alors je vois mes trajets avec les positions précises intégrales Et ces données ne sont pas anonymisées tant que mon compte est actif Et seul moi peut accéder à ces données Et elles ne sont pas utilisées pour des analytics globales
7. Anonymisation pour analytics globales uniquement
Étant donné que RoadWave génère des analytics agrégées
Quand l'équipe analyse les zones géographiques populaires
Alors seules les données anonymisées (geohash) sont utilisées Et les positions précises de l'historique personnel ne sont jamais agrégées Et les heatmaps de trafic utilisent uniquement les geohash ~5km²
8. Planification du job d'anonymisation
Étant donné que le système est en production
Quand on consulte les jobs planifiés (cron)
Alors un job "anonymize_gps_data" est configuré Et le job s'exécute tous les jours à 02:00 (heure creuse) Et le job traite toutes les positions vieilles de plus de 24h Et un log est généré pour traçabilité
9. Exécution du job avec métriques
Étant donné que le job d'anonymisation s'exécute le 2025-01-21 à 02:00
Quand le job se termine
Alors un rapport est généré avec:
| métrique | valeur |
|---|---|
| Nombre de positions traitées | 15420 |
| Nombre de positions anonymisées | 15420 |
| Durée d'exécution | 3.5s |
| Erreurs | 0 |
Et le rapport est loggé dans Sentry/Grafana Et une alerte est envoyée si le job échoue
10. Performances du job d'anonymisation
Étant donné que 100 000 positions doivent être anonymisées
Quand le job s'exécute
Alors le traitement se fait en moins de 30 secondes Et la requête PostGIS est optimisée avec index Et aucun impact sur les performances de l'application en production
11. Impossibilité de réidentification
Étant donné qu'une position a été anonymisée en geohash "u09wh"
Quand un attaquant tente de retrouver la position précise d'origine
Alors il est impossible de déterminer la position exacte Et des milliers de positions précises correspondent au même geohash Et il n'y a aucune traçabilité vers la position originale Et cette anonymisation est irréversible
12. Conformité CNIL - données véritablement anonymisées
Étant donné que les positions sont converties en geohash précision 5
Quand un auditeur CNIL vérifie la conformité
Alors les données sont considérées comme véritablement anonymisées Et elles ne sont plus considérées comme des données personnelles Et aucun consentement n'est requis pour leur traitement analytique Et elles peuvent être conservées indéfiniment
13. Heatmap de trafic avec données anonymisées
Étant donné que RoadWave génère une heatmap des zones populaires
Quand on analyse les données utilisées
Alors seules les positions anonymisées (geohash) sont agrégées Et la heatmap montre des zones de ~5km² Et aucune position précise n'est révélée Et cette analyse ne nécessite pas de consentement utilisateur (données anonymes)
14. Statistiques géographiques par département
Étant donné que RoadWave analyse l'utilisation par département
Quand les statistiques sont générées
Alors les données anonymisées sont agrégées par département Et les résultats montrent: "Paris (75): 12 500 écoutes, Lyon (69): 8 300 écoutes" Et aucune donnée personnelle n'est révélée Et les statistiques sont RGPD-compliant
15. Coût de la solution d'anonymisation
Étant donné que PostGIS est utilisé pour l'anonymisation GPS
Quand on calcule le coût de la solution
Alors le coût est de 0€ (PostGIS inclus dans PostgreSQL) Et aucune librairie tierce n'est nécessaire Et la solution est entièrement maîtrisée (self-hosted)
16. Anonymisation respecte les positions en cours de session
Étant donné que je suis en train d'écouter du contenu actuellement Et que certaines de mes positions ont plus de 24h
Quand le job d'anonymisation s'exécute
Alors mes positions de plus de 24h sont anonymisées Mais ma position actuelle (session en cours) reste précise Et la recommandation continue de fonctionner normalement
17. Suppression de compte et anonymisation GPS
Étant donné que je demande la suppression de mon compte
Quand le compte est supprimé (après grace period de 30j)
Alors toutes mes positions GPS (précises et anonymisées) sont supprimées Et mon historique personnel de trajets est supprimé Et aucune donnée GPS ne subsiste, même anonymisée
18. Export de données avant anonymisation
Étant donné que je demande un export de mes données Et que certaines de mes positions ont été anonymisées
Quand l'export est généré
Alors les positions précises de mon historique personnel sont incluses Mais les positions déjà anonymisées (>24h, analytics) apparaissent en geohash Et l'export précise quelles données ont été anonymisées et pourquoi
Conformité administrative RGPD (Registre, Breach, DPO)
22 scénarios (21 standards, 1 plan)
1. Registre des traitements en Markdown versionné Git
Étant donné que RoadWave doit tenir un registre des traitements
Quand on consulte la documentation
Alors un fichier docs/rgpd/registre-traitements.md existe
Et le fichier est versionné dans Git
Et l'historique des modifications est traçable via Git
Et chaque traitement est documenté dans une section dédiée
2. Contenu obligatoire pour chaque traitement
Étant donné que le registre des traitements contient le traitement "Géolocalisation utilisateurs"
Quand on lit la section correspondante
Alors les informations suivantes sont présentes:
| information obligatoire | exemple |
|---|---|
| Nom du traitement | Géolocalisation utilisateurs |
| Finalité | Recommandation de contenu géolocalisé |
| Catégories de données | Coordonnées GPS, historique de position |
| Base légale | Consentement (Article 6.1.a RGPD) |
| Durée de conservation | 24h (précis), puis geohash anonymisé |
| Destinataires | Aucun tiers |
| Transferts hors UE | Aucun |
| Mesures de sécurité | TLS 1.3, anonymisation après 24h |
3. 📋 Plan: Traitements documentés dans le registre
Étant donné que le registre des traitements est complet
Quand on liste tous les traitements
Alors le traitement "" est documenté avec la base légale "<base_legale>"
📊 Exemples de données:
| traitement | base_legale |
|---|---|
| Géolocalisation utilisateurs | Consentement |
| Historique d'écoute | Intérêt légitime |
| Création de contenu | Exécution du contrat |
| Analytics (Matomo) | Consentement |
| Paiements (Mangopay) | Exécution du contrat |
| Modération contenus | Intérêt légitime |
| Notifications push | Consentement |
4. Review trimestrielle du registre
Étant donné que le registre des traitements existe
Quand on consulte l'historique Git
Alors une mise à jour est effectuée au moins tous les 3 mois Et chaque mise à jour a un commit avec message explicite Et un tag Git marque chaque review trimestrielle Et les modifications sont traçables (auteur, date, changements)
5. Mise à jour immédiate si nouveau traitement
Étant donné qu'une nouvelle fonctionnalité nécessite un traitement de données
Quand la fonctionnalité est développée
Alors le registre est mis à jour AVANT le déploiement en production Et le nouveau traitement est documenté complètement Et un commit Git enregistre l'ajout Et le DPO valide la conformité RGPD du nouveau traitement
6. Migration future vers interface admin PostgreSQL
Étant donné que RoadWave dépasse 100 000 utilisateurs
Quand la complexité du registre augmente
Alors une interface admin PostgreSQL est développée Et le registre Markdown est migré vers la base de données Et l'historique Git est conservé pour audit Et l'interface permet une gestion plus efficace des traitements
7. Détection automatique d'événements critiques
Étant donné que le système de monitoring est actif
Quand un événement critique se produit
Alors une alerte est envoyée selon le type d'événement:
| événement | outil | alerte |
|---|---|---|
| Erreur backend critique | Sentry | Discord/Slack immédiat |
| Pic requêtes anormal | Grafana | Email équipe |
| Accès non autorisé DB | PostgreSQL logs | SMS fondateur |
| Authentification suspecte | Zitadel alerts | Email équipe |
Et les alertes permettent une réaction rapide
8. Runbook de procédure breach disponible
Étant donné qu'une violation de données potentielle est détectée
Quand l'équipe consulte la documentation
Alors un runbook docs/rgpd/procedure-breach.md existe
Et le runbook contient une checklist 72h CNIL
Et chaque étape est clairement documentée
Et les contacts d'urgence sont listés
9. Checklist 72h en cas de breach
Étant donné qu'une violation de données est confirmée
Quand l'équipe suit la procédure breach
Alors les étapes suivantes sont exécutées dans les délais:
| délai | étape |
|---|---|
| H+0 | Détection et confinement immédiat |
| H+24 | Évaluation gravité (données concernées, users impactés) |
| H+48 | Notification CNIL si risque pour utilisateurs |
| H+72 | Notification utilisateurs si risque élevé |
Et chaque étape est documentée pour audit
10. Évaluation de la gravité du breach
Étant donné qu'une violation de données est détectée
Quand l'équipe évalue la gravité
Alors les critères suivants sont analysés:
| critère | exemple |
|---|---|
| Type de données concernées | Emails, mots de passe, GPS, etc. |
| Nombre d'utilisateurs impactés | 10, 100, 10000, etc. |
| Mesures de sécurité existantes | Chiffrement, hachage, anonymisation |
| Risque pour les droits et libertés | Faible, modéré, élevé |
Et si le risque est élevé, la CNIL est notifiée sous 72h
11. Notification CNIL dans les 72h
Étant donné qu'un breach avec risque élevé est confirmé à 10:00 le 2025-01-20
Quand la gravité est évaluée comme nécessitant une notification
Alors la CNIL est notifiée avant 10:00 le 2025-01-23 (72h) Et la notification contient:
| information |
|---|
| Nature de la violation |
| Données concernées |
| Nombre d'utilisateurs impactés |
| Conséquences probables |
| Mesures prises |
| Mesures de remédiation |
Et un email pré-rédigé (template) est utilisé pour gagner du temps
12. Notification des utilisateurs si risque élevé
Étant donné qu'un breach impacte 5000 utilisateurs Et que le risque est élevé (mots de passe non chiffrés exposés)
Quand la CNIL est notifiée
Alors les utilisateurs impactés sont notifiés dans les 72h Et l'email contient: Et un lien de réinitialisation de mot de passe est inclus
13. Aucune notification si risque faible
Étant donné qu'un breach mineur est détecté (logs techniques exposés, aucune donnée personnelle)
Quand l'équipe évalue la gravité
Alors le risque est jugé faible Et aucune notification CNIL n'est requise (Article 33.1 RGPD) Et aucune notification utilisateur n'est envoyée Et un log interne est créé pour traçabilité
14. Monitoring proactif pour éviter découverte tardive
Étant donné que Sentry et Grafana sont configurés
Quand un comportement anormal est détecté
Alors une alerte est envoyée en temps réel Et l'équipe peut réagir avant qu'un breach majeur ne se produise Et les logs sont analysés quotidiennement pour détecter des anomalies Et cette approche proactive limite les risques de découverte tardive
15. Fondateur = DPO temporaire (MVP)
Étant donné que RoadWave est en phase MVP Et que l'entreprise a moins de 250 employés
Quand on vérifie l'obligation légale d'avoir un DPO
Alors le DPO n'est pas obligatoire selon le RGPD Article 37 Et le fondateur assume temporairement le rôle de DPO Et le fondateur suit la formation CNIL gratuite (4h)
16. Formation CNIL du DPO temporaire
Étant donné que le fondateur est DPO temporaire
Quand on vérifie sa formation
Alors le fondateur a suivi la formation CNIL en ligne (4h) Et le fondateur a obtenu la certification "Atelier RGPD" (gratuit) Et le certificat est conservé pour audit Et la formation couvre:
| sujet |
|---|
| Principes fondamentaux du RGPD |
| Droits des personnes |
| Sécurité des données |
| Violations de données (breach) |
| Registre des traitements |
17. Contact DPO publié et accessible
Étant donné que je consulte les mentions légales de RoadWave
Quand je cherche le contact du DPO
Alors l'email "dpo@roadwave.fr" est clairement affiché Et cet email est également dans les CGU Et le délai de réponse garanti est de 1 mois maximum (RGPD Article 12.3) Et une adresse postale est également fournie
18. Demande d'exercice de droits RGPD au DPO
Étant donné que je veux exercer mon droit d'accès à mes données
Quand j'envoie un email à dpo@roadwave.fr
Alors je reçois un accusé de réception dans les 48h Et ma demande est traitée dans un délai maximum de 1 mois Et si le délai dépasse 1 mois, je suis informé de la prolongation (max 2 mois supplémentaires) Et la réponse est complète et conforme au RGPD
19. Types de demandes gérées par le DPO
Étant donné que je contacte le DPO
Quand j'envoie une demande
Alors le DPO peut traiter les demandes suivantes:
| type de demande |
|---|
| Droit d'accès (Article 15) |
| Droit de rectification (Article 16) |
| Droit à l'effacement (Article 17) |
| Droit à la portabilité (Article 20) |
| Droit d'opposition (Article 21) |
| Plainte RGPD |
| Question sur le traitement des données |
Et chaque demande reçoit une réponse personnalisée
20. Migration vers DPO externe si croissance
Étant donné que RoadWave dépasse 100 000 utilisateurs
Quand la charge de travail DPO augmente
Alors un DPO externe mutualisé est engagé Et le coût est d'environ 200€/mois Et le DPO externe a les certifications CNIL requises Et un contrat de sous-traitance RGPD est signé
21. Recrutement DPO interne si >10 employés
Étant donné que RoadWave a plus de 10 employés
Quand l'entreprise se structure
Alors un DPO interne peut être recruté Et le DPO interne a une certification CNIL (AFCDP ou équivalent) Et le DPO est indépendant et ne peut être licencié pour ses fonctions Et le DPO a un accès direct à la direction
22. Récapitulatif des coûts RGPD
Étant donné que toutes les mesures RGPD sont en place
Quand on calcule le coût total mensuel
Alors le récapitulatif est le suivant:
| mesure | implémentation | coût |
|---|---|---|
| Consentement | Tarteaucitron.js + PostgreSQL | 0€ |
| Anonymisation GPS | Geohash PostGIS (24h) | 0€ |
| Export données | JSON+HTML+ZIP asynchrone | 0€ |
| Suppression compte | Grace period 30j + anonymisation | 0€ |
| Mode dégradé | GeoIP 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€ (< 5K events) |
| DPO | Fondateur formé CNIL | 0€ |
Et le coût total est d'environ 5€/mois Et cette conformité est 100% opensource et maîtrisée
Gestion du consentement RGPD
16 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis un nouvel utilisateur Et que j'accède à l'application pour la première fois
1. Affichage du banner de consentement au premier lancement web
Étant donné que j'accède à l'application web pour la première fois
Quand la page se charge
Alors un banner RGPD Tarteaucitron.js s'affiche Et le banner est en français Et le banner propose les options suivantes:
| option | description |
|---|---|
| Tout accepter | Active tous les consentements |
| Tout refuser | Refuse tous les consentements optionnels |
| Personnaliser | Ouvre le panneau de personnalisation |
Et le banner est customisé aux couleurs de RoadWave
2. Granularité des consentements
Étant donné que le banner RGPD est affiché
Quand je clique sur "Personnaliser"
Alors je vois les catégories de consentements suivantes:
| catégorie | type | requis |
|---|---|---|
| Fonctionnel | Nécessaire | oui |
| Analytique | Optionnel | non |
| Marketing | Optionnel | non |
Et chaque catégorie a une description claire de son usage Et je peux accepter ou refuser chaque catégorie individuellement
3. Consentement géolocalisation précise - obligatoire
Étant donné que je suis sur l'application mobile Et que l'onboarding est terminé
Quand l'application a besoin d'accéder à ma position précise
Alors un écran de demande de consentement s'affiche Et le message explique clairement l'usage: Et je peux accepter ou refuser Et si je refuse, l'application bascule en mode dégradé (GeoIP uniquement)
4. Double consentement GPS - banner app + permission OS
Étant donné que je veux activer la géolocalisation précise
Quand j'accepte le consentement dans l'application
Alors l'application demande également la permission au système d'exploitation Et sur iOS, la popup système s'affiche: "Autoriser RoadWave à accéder à votre position ?" Et sur Android, la popup système s'affiche avec les options "Toujours autoriser / Autoriser seulement pendant l'utilisation / Refuser" Et les deux consentements (app + OS) doivent être acceptés pour activer le GPS précis
5. Enregistrement du consentement en base de données
Étant donné que j'ai accepté les consentements suivants:
| type | accepté |
|---|---|
| Fonctionnel | oui |
| Analytique | oui |
| Marketing | non |
| GPS précis | oui |
Quand je valide mes choix
Alors un enregistrement est créé dans la table user_consents
Et l'enregistrement contient les champs suivants:
| champ | valeur |
|---|---|
| user_id | [mon ID utilisateur] |
| consent_type | fonctionnel / analytique / gps |
| version | 1 |
| accepted | true / false |
| timestamp | [date et heure exacte] |
Et chaque type de consentement a un enregistrement séparé
6. Versioning des consentements
Étant donné que j'ai accepté le consentement "Analytique" version 1 le 2025-01-01 Et que les CGU sont mises à jour le 2025-06-01
Quand je me connecte après la mise à jour
Alors un nouveau consentement version 2 m'est demandé Et mon ancien consentement version 1 reste dans l'historique Et je dois accepter la nouvelle version pour continuer à utiliser les analytics
7. Historique complet conservé pour preuve légale
Étant donné que j'ai modifié mes consentements plusieurs fois:
| date | consent_type | accepted | version |
|---|---|---|---|
| 2025-01-01 | Analytique | oui | 1 |
| 2025-03-15 | Analytique | non | 1 |
| 2025-06-01 | Analytique | oui | 2 |
Quand un auditeur CNIL consulte mon historique de consentements
Alors tous les enregistrements sont conservés Et l'historique prouve que chaque consentement a été donné librement Et les timestamps permettent de prouver la conformité à tout moment
8. Consentement analytique - optionnel
Étant donné que je refuse le consentement "Analytique"
Quand j'utilise l'application
Alors aucun cookie Matomo _pk_id n'est déposé
Et aucune donnée d'usage n'est envoyée à Matomo
Et l'application fonctionne normalement sans analytics
9. Consentement notifications push - optionnel
Étant donné que je refuse le consentement "Notifications push"
Quand un créateur que je suis publie un nouveau contenu
Alors je ne reçois pas de notification push Mais je peux voir le nouveau contenu dans l'application Et l'application fonctionne normalement
10. Consentement GPS précis - requis pour fonctionnalités géo
Étant donné que je refuse le consentement "GPS précis"
Quand j'utilise l'application
Alors je peux accéder aux contenus nationaux Mais les contenus géolocalisés précis (Ancré, Contextuel) ne sont pas disponibles Et les audio-guides nécessitent l'activation du GPS Et un banner permanent me rappelle que l'activation du GPS améliore l'expérience
11. Révocation d'un consentement depuis les paramètres
Étant donné que j'ai accepté le consentement "Analytique" Et que j'utilise l'application depuis 3 mois
Quand j'ouvre "Paramètres > Confidentialité > Gérer mes consentements"
Alors je vois la liste de tous mes consentements actuels Et je peux révoquer le consentement "Analytique"
Quand je révoque le consentement
Alors un nouvel enregistrement est créé avec accepted = false
Et le cookie Matomo est supprimé immédiatement
Et les analytics sont désactivées à partir de ce moment
12. Acceptation d'un consentement précédemment refusé
Étant donné que j'avais refusé le consentement "GPS précis"
Quand j'ouvre "Paramètres > Confidentialité > Gérer mes consentements" Et que je clique sur "Activer la géolocalisation précise"
Alors un nouvel enregistrement est créé avec accepted = true
Et la permission OS est demandée si ce n'est pas déjà fait
Et l'application bascule en mode géolocalisation précise
Et les contenus géolocalisés deviennent disponibles immédiatement
13. Export de l'historique des consentements pour audit
Étant donné qu'un contrôle CNIL est en cours
Quand l'équipe RoadWave exporte l'historique des consentements
Alors l'export contient pour chaque utilisateur:
| champ | description |
|---|---|
| user_id | ID anonymisé |
| consent_type | Type de consentement |
| version | Version des CGU/consentement |
| accepted | Accepté ou refusé |
| timestamp | Date et heure exacte |
| ip_address | IP (anonymisée) au moment du consentement |
| user_agent | Navigateur/app utilisé |
Et l'export est au format CSV pour analyse Et les données prouvent la conformité RGPD
14. Conformité recommandations CNIL
Étant donné que le système de consentement est implémenté
Quand un auditeur CNIL vérifie la conformité
Alors le système respecte les critères suivants:
| critère CNIL | respecté |
|---|---|
| Consentement libre | oui |
| Consentement spécifique (granulaire) | oui |
| Consentement éclairé (information claire) | oui |
| Consentement univoque (action positive) | oui |
| Révocable à tout moment | oui |
| Preuve du consentement conservée | oui |
15. Tarteaucitron.js self-hosted
Étant donné que l'application web utilise Tarteaucitron.js
Quand je consulte les sources JavaScript chargées
Alors le script Tarteaucitron.js est hébergé sur les serveurs RoadWave Et aucun script tiers (CDN externe) n'est chargé Et le code source de Tarteaucitron.js est vérifiable Et aucune donnée n'est envoyée à un tiers lors de l'affichage du banner
16. Coût de la solution - 0€
Étant donné que Tarteaucitron.js est opensource Et que PostgreSQL est utilisé pour le backend
Quand on calcule le coût de la solution de consentement
Alors le coût est de 0€ Et la solution est entièrement maîtrisée (self-hosted) Et aucune dépendance à un service SaaS tiers
Durée de conservation des données et purge automatique
19 scénarios
Contexte commun à tous les scénarios
Étant donné que le système de purge automatique est actif
1. Auditeur inactif depuis 5 ans - suppression automatique
Étant donné que je suis un auditeur (sans contenu créé) Et que je ne me suis pas connecté depuis le 2020-01-01 Et que la date actuelle est 2025-01-02 (>5 ans)
Quand le job de purge automatique s'exécute
Alors mon compte est automatiquement supprimé Et toutes mes données personnelles sont effacées Et aucune trace ne subsiste dans la base de données
2. Créateur avec contenus actifs - conservation indéfinie
Étant donné que je suis un créateur Et que j'ai créé 10 contenus qui reçoivent encore des écoutes Et que je ne me suis pas connecté depuis 6 ans
Quand le job de purge automatique s'exécute
Alors mon compte n'est pas supprimé Et mes données personnelles sont conservées tant que mes contenus sont écoutés Et mes contenus continuent d'être diffusés normalement
3. Créateur inactif sans écoutes - suppression automatique
Étant donné que je suis un créateur Et que j'ai créé 5 contenus Et que je ne me suis pas connecté depuis 5 ans (depuis 2020-01-01) Et que mes contenus n'ont reçu aucune écoute depuis 2 ans (depuis 2023-01-01) Et que la date actuelle est 2025-01-02
Quand le job de purge automatique s'exécute
Alors mon compte est automatiquement supprimé Et mes contenus sont anonymisés (créateur = "Utilisateur supprimé") Et les fichiers audio restent disponibles mais anonymisés
4. Notifications par email avant purge
Étant donné que je suis inactif depuis 4 ans et 9 mois
Quand le système détecte que je suis éligible à la purge dans 90 jours
Alors je reçois un email avec le sujet "Votre compte RoadWave sera supprimé dans 90 jours" Et l'email contient: Et un lien de connexion est inclus dans l'email
5. Rappels à 90j, 30j et 7j avant suppression
Étant donné que je suis éligible à la purge automatique
Quand les délais s'écoulent
Alors je reçois les emails suivants:
| délai | sujet email |
|---|---|
| 90 jours | Votre compte sera supprimé dans 90 jours |
| 30 jours | Rappel: Votre compte sera supprimé dans 30 jours |
| 7 jours | Dernière alerte: suppression dans 7 jours |
Et chaque email contient un lien de connexion pour réactiver le compte Et les notifications push sont également envoyées si activées
6. Connexion annule la suppression programmée
Étant donné que je suis éligible à la purge dans 15 jours Et que j'ai reçu plusieurs emails d'avertissement
Quand je me connecte à mon compte
Alors la suppression programmée est annulée immédiatement Et le compteur d'inactivité est remis à zéro Et je reçois un email de confirmation: "Votre compte a été réactivé" Et je peux continuer à utiliser l'application normalement
7. Exécution quotidienne du job de purge
Étant donné que le système est en production
Quand on consulte les jobs planifiés
Alors un job "purge_inactive_accounts" est configuré Et le job s'exécute tous les jours à 03:00 (heure creuse) Et le job identifie les comptes éligibles à la purge Et le job traite les suppressions automatiques
8. Critères d'éligibilité à la purge
Étant donné que le job de purge s'exécute
Quand le système identifie les comptes éligibles
Alors les critères suivants sont appliqués:
| type_compte | critères |
|---|---|
| Auditeur uniquement | 5 ans sans connexion |
| Créateur avec contenus actifs | Jamais (tant qu'écoutes) |
| Créateur inactif | 5 ans sans connexion + 2 ans sans écoute |
Et seuls les comptes remplissant tous les critères sont supprimés
9. Métriques du job de purge
Étant donné que le job de purge s'exécute le 2025-01-15
Quand le job se termine
Alors un rapport est généré avec:
| métrique | exemple |
|---|---|
| Comptes analysés | 150 000 |
| Comptes éligibles à la purge | 350 |
| Auditeurs supprimés | 300 |
| Créateurs inactifs supprimés | 50 |
| Créateurs conservés (actifs) | 0 |
| Erreurs | 0 |
| Durée d'exécution | 45s |
Et le rapport est loggé pour audit
10. Contenus de comptes purgés conservés anonymement
Étant donné que mon compte créateur est purgé automatiquement
Quand la suppression est effective
Alors mes contenus créés sont conservés indéfiniment Et les contenus sont anonymisés (créateur = "Utilisateur supprimé") Et les fichiers audio restent sur le CDN Et les statistiques d'écoute sont préservées Et les utilisateurs peuvent toujours écouter mes contenus
11. Créateur inactif mais contenus populaires - pas de purge
Étant donné que je suis un créateur inactif depuis 6 ans Mais que mes contenus reçoivent 500+ écoutes par mois
Quand le job de purge s'exécute
Alors mon compte n'est pas supprimé Et je continue de recevoir les emails d'avertissement tous les 6 mois Et mes contenus continuent d'être diffusés Et je peux me reconnecter à tout moment
12. Qu'est-ce qu'une "écoute" pour le calcul d'inactivité
Étant donné que je suis un créateur
Quand le système calcule si mes contenus sont "actifs"
Alors une "écoute" est comptabilisée si:
| condition | comptabilisée |
|---|---|
| Écoute complète (>80%) | oui |
| Écoute partielle (>30%) | oui |
| Skip rapide (<30%) | non |
| Écoute par un bot (détecté) | non |
Et au moins 1 écoute valide dans les 2 dernières années maintient le compte actif
13. Conformité principe de minimisation
Étant donné que le système de purge automatique est en place
Quand un auditeur RGPD vérifie la conformité
Alors le système respecte le principe de minimisation:
| principe | respecté |
|---|---|
| Conservation limitée dans le temps | oui |
| Suppression automatique après inactivité | oui |
| Délai raisonnable (5 ans) | oui |
| Notifications préalables | oui |
| Exception justifiée (contenus actifs) | oui |
Et le délai de 5 ans est conforme aux standards de l'industrie
14. Actions qui réinitialisent le compteur d'inactivité
Étant donné que je suis inactif depuis 4 ans
Quand j'effectue l'une des actions suivantes:
| action |
|---|
| Connexion à l'application |
| Publication d'un nouveau contenu |
| Like d'un contenu |
| Abonnement à un créateur |
| Modification de mon profil |
Alors le compteur d'inactivité est remis à zéro Et la suppression programmée est annulée Et je ne suis plus éligible à la purge pour 5 ans
15. Traçabilité des suppressions automatiques
Étant donné qu'un compte est supprimé automatiquement
Quand la suppression est effective
Alors un log d'audit est créé avec:
| champ | valeur |
|---|---|
| user_id | [ID anonymisé] |
| account_type | auditeur / créateur |
| last_login | 2020-01-15T10:00:00Z |
| last_content_listen | 2023-06-01T14:30:00Z |
| purge_date | 2025-01-15T03:00:00Z |
| notifications_sent | 3 (90j, 30j, 7j) |
| reason | 5_years_inactivity |
Et le log est conservé 5 ans pour audit RGPD Et l'user_id est pseudonymisé pour anonymat
16. Compte Premium inactif - pas de privilège spécial
Étant donné que je suis un utilisateur Premium Et que je suis inactif depuis 5 ans
Quand le job de purge s'exécute
Alors mon compte est supprimé comme un compte gratuit Et l'abonnement Premium ne prolonge pas la durée de conservation Et aucun remboursement n'est effectué (compte inactif depuis 5 ans)
17. Compte avec signalements de modération - purge différée
Étant donné que je suis éligible à la purge Mais que j'ai des signalements de modération en cours
Quand le job de purge s'exécute
Alors ma purge est différée de 90 jours Et les signalements sont traités en priorité Et si les signalements aboutissent à un ban, le compte est supprimé immédiatement Et si les signalements sont infondés, la purge automatique reprend son cours
18. Pourquoi 5 ans d'inactivité
Étant donné que le délai de purge est fixé à 5 ans
Quand on justifie ce choix
Alors les raisons suivantes sont avancées:
| justification |
|---|
| Standard de l'industrie (Google, Facebook: 2-3 ans) |
| Équilibre raisonnable entre minimisation et utilité |
| Conforme aux recommandations CNIL |
| Laisse une marge de réactivation pour utilisateurs |
| Exception pour créateurs = intérêt légitime communauté |
19. Politique de conservation visible dans les CGU
Étant donné que je consulte les CGU de RoadWave
Quand je lis la section "Conservation des données"
Alors la politique de purge automatique est clairement expliquée: Et les utilisateurs sont informés dès l'inscription
Cookies et analytics avec Matomo self-hosted
20 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis un utilisateur de l'application web RoadWave
1. Cookies strictement nécessaires - pas de consentement requis
Étant donné que j'accède à l'application web
Quand je me connecte
Alors les cookies techniques suivants sont déposés:
| cookie | type | durée | finalité | consentement |
|---|---|---|---|---|
| session | Technique | 30j | Authentification | Non requis |
| refresh_token | Technique | 30j | Session persistante | Non requis |
Et ces cookies sont essentiels au fonctionnement de l'application Et ils sont exemptés de consentement selon l'article 82 de la loi Informatique et Libertés
2. Cookie analytique Matomo - consentement requis
Étant donné que j'ai accepté le consentement "Analytique"
Quand je navigue sur l'application web
Alors le cookie _pk_id est déposé
Et la durée de conservation est de 13 mois
Et ce cookie sert à Matomo pour analytics
Et mon IP est automatiquement anonymisée (2 derniers octets)
3. Refus du consentement analytique - pas de cookie Matomo
Étant donné que j'ai refusé le consentement "Analytique"
Quand je navigue sur l'application web
Alors aucun cookie _pk_id n'est déposé
Et aucune donnée d'usage n'est collectée
Et l'application fonctionne normalement sans analytics
4. Matomo hébergé sur les serveurs RoadWave
Étant donné que RoadWave utilise Matomo pour les analytics
Quand on analyse l'infrastructure
Alors Matomo est installé sur les serveurs RoadWave (Docker) Et aucune donnée n'est envoyée à un service tiers Et toutes les données restent dans l'UE Et l'accès à Matomo est restreint à l'équipe RoadWave
5. IP anonymisées automatiquement
Étant donné que Matomo collecte des données d'usage
Quand une requête est enregistrée
Alors l'adresse IP est automatiquement anonymisée Et les 2 derniers octets sont remplacés par des zéros Et une IP 192.168.1.100 devient 192.168.0.0 Et cette anonymisation est irréversible Et elle est conforme aux recommandations CNIL
6. Configuration Matomo conforme RGPD
Étant donné que Matomo est configuré pour RoadWave
Quand on vérifie les paramètres
Alors les configurations suivantes sont activées:
| paramètre | valeur |
|---|---|
| Anonymisation IP (2 octets) | activé |
| Respect Do Not Track | activé |
| Suppression auto anciens logs (25 mois) | activé |
| Géolocalisation IP désactivée | activé |
| User ID anonymisé | activé |
Et la configuration est RGPD-compliant
7. Aucun tracker tiers utilisé
Étant donné que j'accède à l'application web
Quand j'inspecte les requêtes réseau avec les DevTools
Alors aucune requête n'est envoyée vers les domaines suivants:
| domaine tiers interdit |
|---|
| google-analytics.com |
| facebook.com (Pixel) |
| hotjar.com |
| mixpanel.com |
| segment.io |
| amplitude.com |
Et toutes les requêtes analytics vont uniquement vers matomo.roadwave.fr
8. Conformité zéro cookie tiers
Étant donné que j'analyse les cookies déposés sur roadwave.fr
Quand je consulte la liste des cookies
Alors tous les cookies sont first-party (domaine roadwave.fr) Et aucun cookie tiers (third-party) n'est présent Et cette politique respecte les recommandations CNIL 2020
9. Alternative Plausible SaaS (EU-hosted)
Étant donné que RoadWave pourrait utiliser Plausible au lieu de Matomo
Quand on compare les deux solutions
Alors Plausible a les caractéristiques suivantes:
| caractéristique | valeur |
|---|---|
| Hébergement | UE (Allemagne) |
| Conformité RGPD | Natif (pas de cookie) |
| Coût | 9€/mois (50K pageviews) |
| IP anonymisées | Automatique |
| Consentement requis | Non (selon CNIL 2020) |
Mais Matomo self-hosted reste le choix prioritaire (0€, contrôle total)
10. Aucun transfert de données hors UE
Étant donné que Matomo est self-hosted
Quand on analyse les flux de données
Alors aucune donnée d'analytics n'est transférée hors de l'UE Et les serveurs sont localisés en France Et aucun transfert vers les US (pas de Privacy Shield / DPF requis) Et la souveraineté des données est garantie
11. Matomo self-hosted - coût estimé
Étant donné que Matomo est hébergé sur l'infrastructure RoadWave
Quand on calcule le coût mensuel
Alors le coût est d'environ 5€/mois:
| composant | coût |
|---|---|
| Serveur supplémentaire | 0€ (mutualisé) |
| Base de données MySQL | 0€ (mutualisé) |
| Stockage logs (25 mois) | ~5€/mois |
| License Matomo | 0€ (opensource) |
Et ce coût est marginal comparé à un SaaS tiers (9-50€/mois)
12. Respect du signal Do Not Track (DNT)
Étant donné que mon navigateur envoie le header "DNT: 1"
Quand j'accède à l'application web
Alors Matomo détecte le signal DNT
Et aucune donnée d'usage n'est collectée
Et aucun cookie _pk_id n'est déposé
Et l'application fonctionne normalement
Et un message discret s'affiche: "Vos préférences de confidentialité sont respectées (DNT activé)"
13. Logs Matomo supprimés après 25 mois
Étant donné que Matomo collecte des données d'usage
Quand les logs atteignent 25 mois d'ancienneté
Alors un job automatique supprime les anciens logs Et seules les données agrégées (rapports) sont conservées Et les données brutes (logs) sont supprimées définitivement Et cette politique respecte le principe de minimisation RGPD
14. Données collectées par Matomo
Étant donné que j'ai accepté le consentement "Analytique"
Quand je navigue sur l'application web
Alors Matomo collecte les données suivantes:
| donnée collectée | anonymisée |
|---|---|
| Pages visitées | non |
| Durée de visite | non |
| Navigateur / OS | non |
| Résolution écran | non |
| Provenance (referrer) | non |
| IP (2 derniers octets) | oui |
| User ID (hashé) | oui |
Et aucune donnée personnelle identifiable n'est collectée
15. User ID hashé pour analytics
Étant donné que je suis connecté à l'application Et que j'ai accepté le consentement "Analytique"
Quand Matomo enregistre mes actions
Alors mon user_id est hashé (SHA-256) Et le hash est 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 Et il est impossible de retrouver mon user_id original depuis ce hash Et ce processus garantit l'anonymat
16. Conformité recommandations CNIL sur les cookies
Étant donné que RoadWave utilise Matomo self-hosted
Quand un auditeur CNIL vérifie la conformité
Alors le système respecte les recommandations CNIL 2020:
| recommandation CNIL | respecté |
|---|---|
| Consentement requis pour cookies analytics | oui |
| IP anonymisées | oui |
| Pas de transfert hors UE | oui |
| Durée conservation limitée (25 mois) | oui |
| Respect Do Not Track | oui |
| Transparence (liste cookies dans CGU) | oui |
17. Intégration Tarteaucitron.js pour gérer Matomo
Étant donné que Tarteaucitron.js gère les consentements
Quand je personnalise mes consentements
Alors je vois l'option "Analytique (Matomo)"
Et une description est affichée:
Et je peux activer ou désactiver Matomo indépendamment
Et si je désactive, le cookie _pk_id est supprimé immédiatement
18. Analytics sur application mobile
Étant donné que j'utilise l'application mobile
Quand j'accepte le consentement "Analytique"
Alors l'app utilise le SDK Matomo Mobile Et les données sont envoyées à la même instance Matomo self-hosted Et les mêmes règles d'anonymisation s'appliquent Et aucun SDK tiers (Google Analytics, Firebase) n'est utilisé
19. Refus analytics sur mobile
Étant donné que j'ai refusé le consentement "Analytique" sur mobile
Quand j'utilise l'application
Alors aucune donnée d'usage n'est collectée Et le SDK Matomo est désactivé Et l'application fonctionne normalement sans différence d'UX
20. Matomo opensource et auditable
Étant donné que Matomo est opensource
Quand on consulte le code source
Alors le code est disponible publiquement sur GitHub Et le code peut être audité par des experts indépendants Et aucune backdoor ou collecte cachée n'est possible Et cette transparence renforce la confiance utilisateur
Mode dégradé avec GeoIP (sans GPS précis)
20 scénarios (19 standards, 1 plan)
Contexte commun à tous les scénarios
Étant donné que je suis un nouvel utilisateur Et que je lance l'application pour la première fois
1. 📋 Plan: Trois niveaux de géolocalisation disponibles
Étant donné que j'utilise le niveau de géolocalisation ""
Quand le système détermine ma position
Alors la technologie utilisée est "" Et les contenus accessibles sont "" Et le consentement RGPD est ""
📊 Exemples de données:
| niveau | technologie | contenus | 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 |
2. GeoIP activé par défaut au premier lancement
Étant donné que je lance l'application pour la première fois Et que je n'ai pas encore accepté le GPS précis
Quand l'application démarre
Alors le système utilise automatiquement GeoIP basé sur mon adresse IP Et ma position est détectée au niveau ville: "Paris, France" Et aucun consentement n'est requis (GeoIP ne collecte pas de données personnelles) Et je peux accéder aux contenus régionaux et de ville
3. Détection de ville avec MaxMind GeoLite2
Étant donné que mon adresse IP est 93.184.216.34
Quand le système utilise GeoIP MaxMind GeoLite2
Alors ma ville est détectée: "Paris" Et ma région est détectée: "Île-de-France" Et mon pays est détecté: "France" Et la précision est d'environ 80% au niveau ville Et aucune coordonnée GPS précise n'est révélée
4. Banner d'invitation à activer le GPS
Étant donné que j'utilise l'application en mode GeoIP
Quand je suis sur l'écran principal
Alors un banner discret s'affiche en haut: Et le banner n'est pas intrusif (pas de popup modale) Et je peux le fermer temporairement avec un bouton X Et le banner réapparaît tous les 7 jours si je ne l'active pas
5. Upgrade volontaire vers GPS depuis le banner
Étant donné que le banner d'invitation au GPS est affiché
Quand je clique sur "Activer"
Alors un écran de consentement GPS s'affiche Et l'écran explique les avantages: Et je peux accepter ou refuser Et si j'accepte, la permission OS est demandée
6. Contenus disponibles en mode Pays (aucune géoloc)
Étant donné que je n'autorise aucune géolocalisation
Quand le système recherche du contenu à me proposer
Alors seuls les contenus "National" sont disponibles Et les contenus géolocalisés (Ancré, Contextuel) ne sont pas proposés Et je vois un message: "Activez la géolocalisation pour plus de contenu local"
7. Contenus disponibles en mode Ville (GeoIP)
Étant donné que j'utilise le mode GeoIP et que je suis détecté à Paris
Quand le système recherche du contenu à me proposer
Alors les contenus suivants sont disponibles:
| type_contenu | disponible |
|---|---|
| National | oui |
| Région Île-de-France | oui |
| Ville Paris | oui |
| Hyperlocal (GPS) | non |
| Audio-guides | non |
Et je reçois des recommandations pertinentes pour Paris
8. Tous contenus disponibles en mode Précis (GPS)
Étant donné que j'ai activé la géolocalisation précise
Quand le système recherche du contenu à me proposer
Alors tous les types de contenus sont disponibles:
| type_contenu | disponible |
|---|---|
| National | oui |
| Régional | oui |
| Ville | oui |
| Hyperlocal (Ancré) | oui |
| Contextuel | oui |
| Audio-guides | oui |
9. GeoIP ne nécessite pas de consentement RGPD
Étant donné que j'utilise le mode GeoIP
Quand un auditeur CNIL vérifie la conformité
Alors GeoIP n'est pas considéré comme une donnée personnelle Et l'adresse IP n'est pas conservée après détection de la ville Et seule la ville est stockée (non identifiant) Et aucun consentement n'est requis conformément au RGPD
10. Base de données MaxMind self-hosted
Étant donné que RoadWave utilise MaxMind GeoLite2
Quand on analyse l'infrastructure
Alors la base de données GeoLite2 est hébergée sur les serveurs RoadWave Et aucune requête n'est envoyée à un service tiers Et la base de données est mise à jour automatiquement chaque mois Et le coût est de 0€ (GeoLite2 est gratuit)
11. Mise à jour mensuelle de la base GeoIP
Étant donné que MaxMind publie des mises à jour mensuelles
Quand le 1er du mois arrive
Alors un job automatique télécharge la nouvelle base GeoLite2 Et la base est mise à jour sans interruption de service Et un log est créé pour traçabilité Et si la mise à jour échoue, une alerte est envoyée
12. UX acceptable en mode GeoIP
Étant donné que j'utilise le mode GeoIP à Paris
Quand je parcours l'application
Alors je peux écouter du contenu pertinent pour Paris et l'Île-de-France Et l'expérience est satisfaisante même sans GPS précis Et je ne suis pas bloqué dans l'utilisation de l'application Et je peux choisir d'activer le GPS quand je le souhaite
13. Incitation progressive à activer le GPS
Étant donné que j'utilise le mode GeoIP depuis 2 semaines Et que je n'ai pas activé le GPS
Quand je consulte un audio-guide dans les résultats de recherche
Alors un message s'affiche: Et si je clique "Plus tard", je peux continuer à utiliser l'app normalement Et l'incitation reste douce et non intrusive
14. Upgrade GeoIP vers GPS
Étant donné que j'utilise le mode GeoIP
Quand j'active la géolocalisation précise
Alors le système bascule immédiatement en mode GPS Et les contenus hyperlocaux deviennent disponibles Et mon feed se rafraîchit avec du contenu plus précis Et un toast de confirmation s'affiche: "Géolocalisation activée"
15. Downgrade GPS vers GeoIP
Étant donné que j'utilise le mode GPS précis
Quand je désactive la géolocalisation dans les paramètres OS
Alors le système bascule automatiquement en mode GeoIP Et les contenus hyperlocaux ne sont plus proposés Et un banner s'affiche: "Géolocalisation désactivée. Seul le contenu régional est disponible." Et l'application continue de fonctionner normalement
16. Détection automatique au démarrage de l'app
Étant donné que j'ouvre l'application
Quand l'app vérifie les permissions de géolocalisation
Alors le système détecte automatiquement le mode disponible:
| permission GPS | consentement app | mode activé |
|---|---|---|
| Refusée | Non demandé | Pays |
| Refusée | Accepté | GeoIP |
| Accordée | Accepté | GPS précis |
Et le mode est appliqué sans interaction utilisateur
17. Précision acceptable pour la plupart des cas
Étant donné que j'habite à Lyon Et que mon IP est une IP résidentielle standard
Quand le système utilise GeoIP pour me localiser
Alors la ville détectée est "Lyon" (correct à 80%) Et dans 20% des cas, la ville peut être légèrement erronée (banlieue proche) Et cette précision est suffisante pour proposer du contenu régional pertinent
18. GeoIP avec VPN ou proxy
Étant donné que j'utilise un VPN avec une IP sortante à Paris Mais que je suis physiquement à Lyon
Quand le système utilise GeoIP
Alors la ville détectée est "Paris" (IP du VPN) Et les contenus proposés sont pour Paris Et je peux activer le GPS précis pour corriger la localisation
19. Pas de donnée personnelle collectée avec GeoIP
Étant donné que j'utilise le mode GeoIP
Quand le système détermine ma ville via mon IP
Alors l'adresse IP n'est pas conservée après détection Et seule la ville "Paris" est stockée en base de données Et la ville seule n'est pas une donnée personnelle (RGPD) Et aucun consentement n'est donc requis
20. Solution GeoIP gratuite et self-hosted
Étant donné que RoadWave utilise MaxMind GeoLite2
Quand on calcule le coût de la solution
Alors le coût est de 0€ Et la solution est opensource Et la base de données est hébergée sur les serveurs RoadWave Et aucun coût SaaS tiers
Portabilité des données (Article 20 RGPD)
22 scénarios (21 standards, 1 plan)
Contexte commun à tous les scénarios
Étant donné que je suis un utilisateur connecté Et que j'ai utilisé l'application depuis 6 mois
1. Demande d'export depuis les paramètres
Étant donné que je suis dans "Paramètres > Confidentialité"
Quand je clique sur "Exporter mes données"
Alors une page d'information s'affiche expliquant: Et un bouton "Confirmer l'export" est disponible
2. Confirmation et démarrage de l'export
Étant donné que je clique sur "Confirmer l'export"
Quand la demande est validée
Alors un message de confirmation s'affiche: Et un worker background démarre la génération de l'export Et le statut de l'export est "En cours de génération" Et je peux voir le statut dans "Paramètres > Confidentialité > Mes exports"
3. Contenu de l'archive ZIP
Étant donné que mon export est généré
Quand je télécharge et ouvre l'archive
Alors l'archive a la structure suivante: Et tous les fichiers sont inclus
4. Contenu du fichier export.json
Étant donné que j'ouvre le fichier export.json
Quand j'analyse le contenu
Alors le JSON contient les sections suivantes:
| section | description |
|---|---|
| profile | Email, pseudo, date inscription, bio |
| listening_history | Historique complet d'écoute |
| created_contents | Métadonnées des contenus créés |
| subscriptions | Liste des créateurs suivis |
| likes | Liste des contenus likés |
| interest_gauges | Valeurs des jauges d'intérêt |
| consent_history | Historique des consentements |
| premium_subscription | Informations abonnement Premium |
Et le JSON est formaté de manière lisible (indentation) Et toutes les dates sont au format ISO 8601
5. Contenu du fichier index.html
Étant donné que j'ouvre le fichier index.html dans un navigateur
Quand la page se charge
Alors je vois un site web stylé avec navigation Et les sections suivantes sont affichées:
| section | contenu |
|---|---|
| Mon profil | Email, pseudo, date inscription, statistiques |
| Historique d'écoute | Liste paginée avec dates, titres, durées |
| Mes contenus | Liste avec lectures audio intégrées |
| Mes abonnements | Grille des créateurs suivis |
| Mes likes | Liste des contenus likés avec liens |
| Centres d'intérêt | Graphiques des jauges |
| Consentements | Historique des acceptations/refus |
Et la navigation est intuitive (menu latéral) Et le design est responsive (mobile/desktop)
6. Fichiers audio inclus dans l'export
Étant donné que j'ai créé 5 contenus audio
Quand mon export est généré
Alors le dossier audio/ contient mes 5 fichiers
Et les fichiers sont au format Opus original
Et chaque fichier est nommé: content-[id].opus
Et les fichiers audio correspondent aux métadonnées dans export.json
7. Fichier README.txt explicatif
Étant donné que j'ouvre le fichier README.txt
Quand je lis le contenu
Alors le fichier explique:
8. 📋 Plan: Données de profil exportées
Étant donné que mon export est généré
Quand j'ouvre export.json et lis la section "profile"
Alors je trouve les données suivantes:
| champ | exemple |
|---|---|
| email | user@example.com |
| pseudo | @roadwave_user |
| date_inscription | 2025-01-15T10:30:00Z |
| bio | Passionné d'automobile... |
| avatar_url | https://cdn.roadwave.fr/... |
| compte_verifie | false |
| premium | true |
9. Historique d'écoute exporté
Étant donné que j'ai écouté 150 contenus depuis 6 mois
Quand mon export est généré
Alors la section "listening_history" contient 150 entrées Et chaque entrée contient:
| champ | exemple |
|---|---|
| content_id | C123 |
| content_title | Histoire de la Tour Eiffel |
| creator_name | @historien_paris |
| listened_at | 2025-01-20T15:30:00Z |
| duration_listened | 180 (secondes) |
| completion_rate | 0.85 (85%) |
| location | [geohash ou coords précises] |
Et les contenus sont triés par date décroissante
10. Centres d'intérêt exportés
Étant donné que mes jauges d'intérêt sont:
| catégorie | valeur |
|---|---|
| Automobile | 78% |
| Voyage | 65% |
| Musique | 52% |
| Politique | 30% |
Quand mon export est généré
Alors la section "interest_gauges" contient ces valeurs Et chaque jauge indique la date de dernière modification
11. Historique des consentements exporté
Étant donné que j'ai modifié mes consentements plusieurs fois
Quand mon export est généré
Alors la section "consent_history" contient:
| date | consent_type | accepted | version |
|---|---|---|---|
| 2025-01-15T10:00 | Fonctionnel | oui | 1 |
| 2025-01-15T10:00 | Analytique | oui | 1 |
| 2025-01-15T10:00 | Marketing | non | 1 |
| 2025-03-20T14:30 | Analytique | non | 1 |
Et l'historique complet est visible
12. Génération asynchrone pour éviter timeout
Étant donné que j'ai beaucoup de données (500 contenus créés, 10 000 écoutes)
Quand je demande un export
Alors la génération se fait en arrière-plan via un worker Et la page web ne timeout pas Et je peux continuer à utiliser l'application pendant la génération Et je reçois un email quand l'export est prêt
13. Délai de génération conforme RGPD
Étant donné que je demande un export le 2025-01-20 à 10:00
Quand le worker génère l'export
Alors l'export est disponible maximum 48h plus tard (avant le 2025-01-22 à 10:00) Et la plupart des exports sont prêts en moins de 6h Et le délai respecte l'article 20 du RGPD
14. Email de notification avec lien de téléchargement
Étant donné que mon export est terminé
Quand le worker finalise la génération
Alors je reçois un email avec le sujet "Votre export de données RoadWave est prêt" Et l'email contient: Et le lien de téléchargement est sécurisé (token unique)
15. Lien de téléchargement expire après 7 jours
Étant donné que mon export a été généré le 2025-01-20 Et que je reçois le lien de téléchargement
Quand j'essaie d'accéder au lien le 2025-01-28 (8 jours plus tard)
Alors le lien est expiré Et je reçois un message "Ce lien a expiré. Veuillez demander un nouvel export." Et je peux demander un nouvel export si nécessaire
16. Limite de 1 export par mois
Étant donné que j'ai demandé un export le 2025-01-15
Quand j'essaie de demander un nouvel export le 2025-01-20
Alors je reçois un message d'erreur: Et le bouton "Confirmer l'export" est désactivé Et la date du prochain export possible est affichée
17. Nouvel export possible après 1 mois
Étant donné que j'ai demandé un export le 2025-01-15
Quand la date atteint le 2025-02-15
Alors je peux demander un nouvel export Et le bouton "Confirmer l'export" est actif Et aucune limite ne s'applique
18. Lien de téléchargement sécurisé avec token unique
Étant donné que mon export est prêt
Quand je reçois le lien de téléchargement
Alors le lien contient un token unique et non devinable
Et le format du lien est: https://roadwave.fr/exports/download/[token_unique]
Et le token est valide uniquement pour mon compte
Et le token expire après 7 jours ou après 3 téléchargements
19. Vérification de l'authentification avant téléchargement
Étant donné que je reçois le lien d'export
Quand je clique sur le lien
Alors le système vérifie que je suis connecté Et si je ne suis pas connecté, je suis redirigé vers la page de connexion Et après connexion, le téléchargement démarre automatiquement Et seul le propriétaire du compte peut télécharger l'export
20. Conformité portabilité des données
Étant donné que mon export est généré
Quand un auditeur RGPD vérifie la conformité
Alors l'export respecte les exigences de l'article 20:
| exigence RGPD | respecté |
|---|---|
| Format structuré (JSON) | oui |
| Format couramment utilisé | oui |
| Format lisible par machine | oui |
| Format interopérable | oui |
| Délai raisonnable (48h max) | oui |
| Exhaustivité des données | oui |
| Gratuité pour l'utilisateur | oui |
21. Gratuité de l'export
Étant donné que je demande un export de mes données
Quand l'export est généré et téléchargé
Alors aucun coût n'est facturé Et l'export est entièrement gratuit Et aucune inscription Premium n'est requise Et le droit à la portabilité est accessible à tous les utilisateurs
22. Suivi du statut de génération
Étant donné que j'ai demandé un export
Quand j'ouvre "Paramètres > Confidentialité > Mes exports"
Alors je vois le statut actuel:
| statut | description |
|---|---|
| En cours de génération | Worker en train de générer l'archive |
| Prêt au téléchargement | Lien de téléchargement disponible |
| Expiré | Lien expiré (>7j), nouvel export requis |
Et la date de demande est affichée Et la taille estimée de l'archive est visible
Suppression du compte utilisateur (Article 17 RGPD - Droit à l'effacement)
21 scénarios
Contexte commun à tous les scénarios
Étant donné que je suis un utilisateur connecté Et que j'ai utilisé l'application depuis plusieurs mois
1. Demande de suppression depuis les paramètres
Étant donné que je suis dans "Paramètres > Compte"
Quand je clique sur "Supprimer mon compte"
Alors une page d'avertissement s'affiche avec le message: Et deux boutons sont disponibles: "Annuler" et "Confirmer la suppression"
2. Confirmation de suppression avec mot de passe
Étant donné que je clique sur "Confirmer la suppression"
Quand un formulaire de confirmation s'affiche
Alors je dois entrer mon mot de passe pour confirmer Et je dois cocher "Je comprends que cette action est définitive" Et un captcha peut être requis pour éviter les suppressions automatisées
Quand je valide le formulaire
Alors la suppression est initiée
3. Compte désactivé immédiatement après confirmation
Étant donné que j'ai confirmé la suppression de mon compte
Quand la demande est traitée
Alors mon compte est désactivé immédiatement Et je suis déconnecté de toutes mes sessions Et je ne peux plus me reconnecter Et si j'essaie de me connecter, je reçois le message:
4. Contenus cachés pendant le grace period
Étant donné que mon compte est en cours de suppression
Quand un autre utilisateur recherche mes contenus
Alors mes contenus ne sont plus diffusés dans l'application Et mes contenus n'apparaissent plus dans les recherches Et mes contenus ne sont plus recommandés Mais mes contenus ne sont pas encore supprimés définitivement
5. Email de confirmation envoyé immédiatement
Étant donné que j'ai confirmé la suppression de mon compte
Quand la demande est traitée
Alors je reçois un email avec le sujet "Confirmation de suppression de votre compte RoadWave" Et l'email contient: Et le lien d'annulation est valide 30 jours
6. Annulation de la suppression dans les 30 jours
Étant donné que j'ai demandé la suppression de mon compte le 2025-01-20 Et que je reçois l'email de confirmation
Quand je clique sur le lien "Annuler la suppression" le 2025-02-05 (16 jours plus tard)
Alors mon compte est réactivé immédiatement Et je peux me reconnecter normalement Et mes contenus redeviennent visibles dans l'application Et toutes mes données sont restaurées Et je reçois un email de confirmation: "Votre compte a été réactivé"
7. Lien d'annulation expire après 30 jours
Étant donné que j'ai demandé la suppression de mon compte le 2025-01-20
Quand j'essaie de cliquer sur le lien d'annulation le 2025-02-25 (36 jours plus tard)
Alors le lien est expiré Et je reçois un message "Ce lien a expiré. Votre compte a été définitivement supprimé." Et la suppression effective a déjà eu lieu
8. Suppression effective sans annulation
Étant donné que j'ai demandé la suppression de mon compte le 2025-01-20 Et que je n'ai pas cliqué sur le lien d'annulation
Quand la date atteint le 2025-02-19 (30 jours plus tard)
Alors un job automatique exécute la suppression définitive Et toutes mes données personnelles sont supprimées
9. Liste des données supprimées définitivement
Étant donné que la suppression effective est exécutée
Quand le job de suppression se termine
Alors les données suivantes sont supprimées:
| données | supprimé |
|---|---|
| Compte utilisateur (email, mdp) | oui |
| Profil (pseudo, bio, avatar) | oui |
| Historique d'écoute | oui |
| Historique GPS | oui |
| Centres d'intérêt (jauges) | oui |
| Sessions et tokens | oui |
| Likes et abonnements | oui |
| Notifications non lues | oui |
| Historique consentements | oui |
| Données de paiement | oui |
Et ces suppressions sont irréversibles
10. Anonymisation des contenus créés
Étant donné que j'ai créé 10 contenus audio
Quand la suppression effective est exécutée
Alors mes contenus audio restent disponibles dans l'application Et le nom du créateur devient "Utilisateur supprimé" Et mon pseudo n'est plus visible Et les métadonnées (titre, description, tags, géolocalisation) sont conservées Et les fichiers audio restent sur le CDN Et les statistiques d'écoute sont conservées
11. Justification de l'anonymisation (intérêt légitime)
Étant donné que mes contenus sont conservés anonymement
Quand un auditeur RGPD vérifie la conformité
Alors la conservation est justifiée par l'intérêt légitime de la communauté Et les contenus ne contiennent plus de données personnelles identifiables Et la suppression complète nuirait à l'expérience des autres utilisateurs Et cette pratique est conforme au RGPD si anonymisation réelle
12. Contenu anonymisé visible pour les autres utilisateurs
Étant donné que mon compte a été supprimé Et que mes contenus ont été anonymisés
Quand un utilisateur consulte un de mes anciens contenus
Alors le créateur affiché est "Utilisateur supprimé" Et le profil du créateur n'est plus accessible Et le contenu reste écoutable normalement Et les likes et statistiques sont conservés
13. Suppression de mes likes avec conservation des compteurs
Étant donné que j'avais liké 50 contenus
Quand la suppression effective est exécutée
Alors mes likes sont supprimés de la base de données Mais les compteurs de likes sur les contenus sont préservés Et les créateurs ne perdent pas leurs statistiques Et seule la relation "user X a liké content Y" est supprimée
14. Suppression de mes abonnements
Étant donné que je suivais 20 créateurs
Quand la suppression effective est exécutée
Alors mes abonnements sont supprimés Et les compteurs d'abonnés des créateurs sont décrémentés de 1 Et les créateurs ne reçoivent pas de notification de désabonnement
15. Révocation de tous les tokens immédiatement
Étant donné que je suis connecté sur 3 appareils (mobile, tablette, web)
Quand je demande la suppression de mon compte
Alors tous mes tokens d'authentification sont révoqués immédiatement Et je suis déconnecté de tous mes appareils Et toute tentative de reconnexion échoue
16. Rappels par email pendant le grace period
Étant donné que j'ai demandé la suppression de mon compte le 2025-01-20
Quand le grace period s'écoule
Alors je reçois des emails de rappel:
| date | jours restants | sujet email |
|---|---|---|
| 2025-02-04 | 15 jours | Plus que 15 jours pour annuler la suppression |
| 2025-02-12 | 7 jours | Dernière semaine pour annuler la suppression |
| 2025-02-17 | 2 jours | Attention: suppression définitive dans 2 jours |
Et chaque email contient le lien d'annulation
17. Conformité droit à l'effacement
Étant donné que la suppression de mon compte est complète
Quand un auditeur RGPD vérifie la conformité
Alors le processus respecte l'article 17 du RGPD:
| exigence RGPD | respecté |
|---|---|
| Suppression de toutes les données personnelles | oui |
| Délai raisonnable (30j grace period acceptable) | oui |
| Possibilité d'annulation (bonne pratique) | oui |
| Anonymisation des contenus (intérêt légitime) | oui |
| Révocation des tokens et sessions | oui |
| Suppression irréversible | oui |
18. Suppression d'un compte Premium
Étant donné que j'ai un abonnement Premium actif
Quand je demande la suppression de mon compte
Alors mon abonnement est annulé immédiatement Et aucun remboursement n'est effectué (conformément aux CGV) Et je reçois un email de confirmation d'annulation de l'abonnement Et le reste du processus de suppression se déroule normalement
19. Suppression d'un compte créateur avec revenus en attente
Étant donné que je suis un créateur avec 75€ de revenus en attente de paiement
Quand je demande la suppression de mon compte
Alors un message m'informe: Et je peux choisir "Recevoir le paiement et attendre" ou "Renoncer au paiement" Et si je choisis "Recevoir le paiement", la suppression est repoussée de 7 jours
20. Suppression avec signalements de modération en cours
Étant donné que j'ai 2 signalements en cours de traitement
Quand je demande la suppression de mon compte
Alors les signalements sont automatiquement clôturés Et les contenus signalés sont masqués immédiatement Et aucune sanction n'est appliquée (compte déjà en suppression)
21. Log de la suppression pour traçabilité
Étant donné que la suppression effective est exécutée
Quand le job de suppression se termine
Alors un log est créé avec:
| champ | valeur |
|---|---|
| user_id | [ID anonymisé] |
| deletion_requested_at | 2025-01-20T10:00:00Z |
| deletion_executed_at | 2025-02-19T02:00:00Z |
| deletion_cancelled | false |
| data_deleted | [liste des tables] |
| contents_anonymized | 10 |
Et ce log est conservé 5 ans pour audit RGPD Et l'user_id est pseudonymisé pour anonymat