# Documentation RoadWave --- ## Table des matières - [RoadWave](#roadwave) - [RoadWave - Architecture Technique](#roadwave---architecture-technique) - [ADR-001 : Langage Backend](#adr-001--langage-backend) - [ADR-002 : Protocole de Streaming](#adr-002--protocole-de-streaming) - [ADR-003 : Codec Audio](#adr-003--codec-audio) - [ADR-004 : CDN](#adr-004--cdn) - [ADR-005 : Base de Données](#adr-005--base-de-données) - [ADR-006 : Chiffrement](#adr-006--chiffrement) - [ADR-007 : Tests et Spécifications Exécutables](#adr-007--tests-et-spécifications-exécutables) - [ADR-008 : Authentification et Gestion d'Identité](#adr-008--authentification-et-gestion-didentité) - [ADR-009 : Solution de Paiement et Gestion des Abonnements](#adr-009--solution-de-paiement-et-gestion-des-abonnements) - [ADR-010 : Commandes au volant et likes](#adr-010--commandes-au-volant-et-likes) - [ADR-011 : Conformité App Stores et Plateformes Auto](#adr-011--conformité-app-stores-et-plateformes-auto) - [ADR-012 : Architecture Backend](#adr-012--architecture-backend) - [ADR-013 : ORM et Accès Données](#adr-013--orm-et-accès-données) - [ADR-014 : Frontend Mobile](#adr-014--frontend-mobile) - [ADR-015 : Stratégie Tests](#adr-015--stratégie-tests) - [Règles métier RoadWave](#règles-métier-roadwave) - [Annexe : Fonctionnalités reportées Post-MVP](#annexe--fonctionnalités-reportées-post-mvp) - [Audio-guides multi-séquences pour piétons](#audio-guides-multi-séquences-pour-piétons) - [Impact des abonnements sur l'algorithme](#impact-des-abonnements-sur-lalgorithme) - [Limites d'abonnements et désabonnement](#limites-dabonnements-et-désabonnement) - [Notifications contextuelles selon le mode de déplacement](#notifications-contextuelles-selon-le-mode-de-déplacement) - [Création d'audio-guide multi-séquences](#création-daudio-guide-multi-séquences) - [Intégration audio-guides avec autres fonctionnalités](#intégration-audio-guides-avec-autres-fonctionnalités) - [Audio-guide mode piéton (navigation manuelle)](#audio-guide-mode-piéton-navigation-manuelle) - [Audio-guide mode voiture (GPS automatique)](#audio-guide-mode-voiture-gps-automatique) - [Audio-guides modes vélo et transport](#audio-guides-modes-vélo-et-transport) - [Audio-guides Premium et monétisation](#audio-guides-premium-et-monétisation) - [Sauvegarde et reprise de progression audio-guide](#sauvegarde-et-reprise-de-progression-audio-guide) - [Classification des contenus par âge](#classification-des-contenus-par-âge) - [Connexion utilisateur](#connexion-utilisateur) - [Inscription utilisateur](#inscription-utilisateur) - [Récupération de compte](#récupération-de-compte) - [Gestion des sessions et tokens](#gestion-des-sessions-et-tokens) - [Authentification à deux facteurs (2FA)](#authentification-à-deux-facteurs-2fa) - [Vérification d'email](#vérification-demail) - [Métadonnées et publication de contenu](#métadonnées-et-publication-de-contenu) - [Modification et suppression de contenu](#modification-et-suppression-de-contenu) - [Upload et encodage de contenu audio](#upload-et-encodage-de-contenu-audio) - [Validation des 3 premiers contenus](#validation-des-3-premiers-contenus) - [Élargissement automatique de zone quand aucun contenu n'est disponible](#élargissement-automatique-de-zone-quand-aucun-contenu-nest-disponible) - [Gestion d'un contenu supprimé pendant l'écoute](#gestion-dun-contenu-supprimé-pendant-lécoute) - [Mode dégradé sans géolocalisation](#mode-dégradé-sans-géolocalisation) - [Gestion de la perte de réseau et buffering adaptatif](#gestion-de-la-perte-de-réseau-et-buffering-adaptatif) - [Tests BDD - Documentation des fonctionnalités](#tests-bdd---documentation-des-fonctionnalités) - [Pas de dégradation temporelle des jauges](#pas-de-dégradation-temporelle-des-jauges) - [Évolution des jauges d'intérêt](#évolution-des-jauges-dintérêt) - [Jauge initiale et cold start](#jauge-initiale-et-cold-start) - [Synchronisation actions offline](#synchronisation-actions-offline) - [Téléchargement de contenus offline](#téléchargement-de-contenus-offline) - [Validité et renouvellement contenus offline](#validité-et-renouvellement-contenus-offline) - [Modération préventive](#modération-préventive) - [Sanctions et notifications de modération](#sanctions-et-notifications-de-modération) - [Signalement de contenu inapproprié](#signalement-de-contenu-inapproprié) - [Traitement des signalements par l'IA et les modérateurs](#traitement-des-signalements-par-lia-et-les-modérateurs) - [Conditions d'activation de la monétisation](#conditions-dactivation-de-la-monétisation) - [Contenus Premium exclusifs](#contenus-premium-exclusifs) - [Désactivation et suspension monétisation](#désactivation-et-suspension-monétisation) - [KYC et inscription à la monétisation](#kyc-et-inscription-à-la-monétisation) - [Obligations fiscales](#obligations-fiscales) - [Paiement des créateurs](#paiement-des-créateurs) - [Sources de revenus créateurs](#sources-de-revenus-créateurs) - [Actions complémentaires à l'arrêt](#actions-complémentaires-à-larrêt) - [Commande "Précédent"](#commande-précédent) - [Commandes vocales CarPlay et Android Auto](#commandes-vocales-carplay-et-android-auto) - [Commandes au volant et interactions simplifiées](#commandes-au-volant-et-interactions-simplifiées) - [File d'attente et commande "Suivant"](#file-dattente-et-commande-suivant) - [Lecture en boucle et enchaînement automatique](#lecture-en-boucle-et-enchaînement-automatique) - [Partage de contenu](#partage-de-contenu) - [Avantages Premium](#avantages-premium) - [Gestion abonnement Premium](#gestion-abonnement-premium) - [Multi-devices et détection simultanée](#multi-devices-et-détection-simultanée) - [Offre et tarification Premium](#offre-et-tarification-premium) - [Profil créateur](#profil-créateur) - [Création de campagnes publicitaires](#création-de-campagnes-publicitaires) - [Caractéristiques et facturation des publicités](#caractéristiques-et-facturation-des-publicités) - [Gestion du budget et alertes publicitaires](#gestion-du-budget-et-alertes-publicitaires) - [Insertion et fréquence des publicités](#insertion-et-fréquence-des-publicités) - [Métriques d'engagement et dashboard publicitaire](#métriques-dengagement-et-dashboard-publicitaire) - [Validation et modération des publicités](#validation-et-modération-des-publicités) - [Architecture technique radio live](#architecture-technique-radio-live) - [Arrêt du live](#arrêt-du-live) - [Comportement auditeur pendant un live](#comportement-auditeur-pendant-un-live) - [Démarrage d'un live](#démarrage-dun-live) - [Recherche de contenu](#recherche-de-contenu) - [Classification de géo-pertinence des contenus](#classification-de-géo-pertinence-des-contenus) - [Gestion du contenu politique (MVP simplifié)](#gestion-du-contenu-politique-mvp-simplifié) - [Contenus géolocalisés en mode voiture](#contenus-géolocalisés-en-mode-voiture) - [Gestion de l'historique et reproposition](#gestion-de-lhistorique-et-reproposition) - [Médias traditionnels sur RoadWave](#médias-traditionnels-sur-roadwave) - [Mode Kids pour utilisateurs 13-15 ans](#mode-kids-pour-utilisateurs-13-15-ans) - [Paramétrabilité admin et A/B testing](#paramétrabilité-admin-et-ab-testing) - [Paramétrabilité utilisateur et profils](#paramétrabilité-utilisateur-et-profils) - [Formule de scoring et recommandation](#formule-de-scoring-et-recommandation) - [Anonymisation des données GPS après 24h](#anonymisation-des-données-gps-après-24h) - [Conformité administrative RGPD (Registre, Breach, DPO)](#conformité-administrative-rgpd-registre-breach-dpo) - [Gestion du consentement RGPD](#gestion-du-consentement-rgpd) - [Durée de conservation des données et purge automatique](#durée-de-conservation-des-données-et-purge-automatique) - [Cookies et analytics avec Matomo self-hosted](#cookies-et-analytics-avec-matomo-self-hosted) - [Mode dégradé avec GeoIP (sans GPS précis)](#mode-dégradé-avec-geoip-sans-gps-précis) - [Portabilité des données (Article 20 RGPD)](#portabilité-des-données-article-20-rgpd) - [Suppression du compte utilisateur (Article 17 RGPD - Droit à l'effacement)](#suppression-du-compte-utilisateur-article-17-rgpd---droit-à-leffacement) ---
# 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](#docs/adr/010-commandes-volant) 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/](#docs/adr/) ## Stack Technologique | Composant | Technologie | ADR | |-----------|-------------|-----| | **Backend** | Go + Fiber | [ADR-001](#docs/adr/001-langage-backend) | | **Architecture Backend** | Monolithe Modulaire | [ADR-012](#docs/adr/012-architecture-backend) | | **Authentification** | Zitadel | [ADR-008](#docs/adr/008-authentification) | | **Streaming** | HLS | [ADR-002](#docs/adr/002-protocole-streaming) | | **Codec** | Opus | [ADR-003](#docs/adr/003-codec-audio) | | **CDN** | Bunny CDN | [ADR-004](#docs/adr/004-cdn) | | **Base de données** | PostgreSQL + PostGIS | [ADR-005](#docs/adr/005-base-de-donnees) | | **ORM/Accès données** | sqlc | [ADR-013](#docs/adr/013-orm-acces-donnees) | | **Cache** | Redis Cluster | [ADR-005](#docs/adr/005-base-de-donnees) | | **Chiffrement** | TLS 1.3 | [ADR-006](#docs/adr/006-chiffrement) | | **Live** | WebRTC | [ADR-002](#docs/adr/002-protocole-streaming) | | **Frontend Mobile** | Flutter | [ADR-014](#docs/adr/014-frontend-mobile) | | **Tests** | Testify + Godog (Gherkin) | [ADR-015](#docs/adr/015-strategie-tests), [ADR-007](#docs/adr/007-tests-bdd) | | **Paiements** | Mangopay | [ADR-009](#docs/adr/009-solution-paiement) | | **Commandes volant** | Like automatique | [ADR-010](#docs/adr/010-commandes-volant) | | **Conformité stores** | CarPlay, Android Auto, App/Play Store | [ADR-011](#docs/adr/011-conformite-stores-carplay-android-auto) | --- ## 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 ```sql -- 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 1. **Buffering mobile** : Pré-chargement agressif avant tunnels (détection GPS) 2. **Handoff réseau** : Buffer suffisant pour survivre aux changements de cellule 3. **Mode offline** : Téléchargement complet sur WiFi 4. **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 1. **Phase 1** (0-1M users) : Bunny CDN seul 2. **Phase 2** (1-5M users) : Ajout Nginx origin shield si nécessaire 3. **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 ```sql 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 `.feature` servent 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 ```gherkin 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 run` avant 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 ```go 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 ```go // 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 voiture - `NSLocationAlwaysAndWhenInUseUsageDescription` : explication mode piéton (optionnel) - In-app disclosure obligatoire avant demande "Always" - Flux two-step : When In Use → Always (si user active mode piéton) - Si refusée : app fonctionne en mode voiture uniquement - **Action** : Voir strings détaillés dans [05-interactions-navigation.md](#../regles-metier/05-interactions-navigation.md#512-mode-piéton-audio-guides) ### 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](https://developer.android.com/training/cars/media) - [CarPlay Developer Guide](https://developer.apple.com/carplay) - [Google Play UGC Policy](https://support.google.com/googleplay/android-developer/answer/9876937) - [App Store Guidelines](https://developer.apple.com/app-store/review/guidelines/) - [Apple DMA Update EU](https://www.revenuecat.com/blog/growth/apple-eu-dma-update-june-2025/) - [Google Background Location 2026](https://support.google.com/googleplay/android-developer/answer/9799150)
# 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 ```sql -- 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; ``` ```bash sqlc generate ``` ```go // 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 generate` pour 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_audio` mature avec support HLS, buffering adaptatif - **CarPlay/Android Auto** : Support via packages communautaires (`flutter_carplay`, `android_auto_flutter`) - **Géolocalisation** : `geolocator` robuste avec gestion permissions - **Écosystème** : Widgets riches (Material/Cupertino), state management mature (Bloc, Riverpod) ## Packages clés ```yaml 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_test` pour widgets, `integration_test` pour 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) ```go // 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](#007-tests-bdd) pour contexte complet. ```gherkin # 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](#../../README) traduits en `.feature`. ## Tests intégration (Testcontainers) ```go // 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) ```dart // 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) ```javascript // 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 ```yaml # .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/testify` - `github.com/cucumber/godog` - `github.com/testcontainers/testcontainers-go` - `grafana/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](#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](#02-algorithme-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](#03-centres-interet-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](#04-creation-publication-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](#05-interactions-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](#06-publicites) **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](#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](#08-abonnements-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](#09-monetisation-createurs) **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](#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](#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](#12-gestion-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](#13-conformite-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](#14-moderation-flows) **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](#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](#16-audio-guides-multi-sequences) **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 : 1. **Décisions** : choix validés avec justifications 2. **Comportements détaillés** : flux utilisateur, cas limites 3. **Paramètres** : valeurs exactes, seuils, durées 4. **Points d'attention Gherkin** : éléments à tester --- ## 🚀 Utilisation Ces documents servent de **référence unique** pour : - ✅ Développement backend/frontend - ✅ Écriture des tests Gherkin (BDD) - ✅ Validation QA - ✅ Documentation produit **Prochaine étape** : Création des fichiers `.feature` Gherkin dans `features/` basés sur ces règles. --- ## 📊 Statistiques - **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** : 1. Utilisateur clique "Mot de passe oublié" 2. Email avec lien de reset envoyé 3. Lien expire après **1 heure** 4. Page de reset : nouveau mot de passe (validation règles) 5. Confirmation + déconnexion tous devices (sauf celui en cours) **Notifications** : - Email immédiat si changement mot de passe - Push si changement depuis appareil non reconnu **Limite** : - Maximum **3 demandes/heure** (anti-spam) **Justification** : - Standard sécurité - Pas de coût SMS - Protection contre attaque sociale --- ## Récapitulatif Section 1
## 2. Algorithme de recommandation ### 2.1 Classification de géo-pertinence **Décision** : 3 types de contenus selon leur pertinence géographique | Type | Description | Exemple | Pondération géo | |------|-------------|---------|-----------------| | **Géo-ancré** | Contenu lié à un lieu précis | Audio-guide monument, pub restaurant local | 70% | | **Géo-contextuel** | Pertinent dans une zone | Actualité régionale, événement local | 50% | | **Géo-neutre** | Universel, pas de lien géo | Podcast philosophie, musique | 20% | **Qui décide** : - ✅ Créateur choisit le type à la publication - ✅ Modération peut reclassifier après validation - ✅ Modification possible après publication (tout le monde a le droit de se tromper) **Justification** : - Différencie audio-guide (hyper-local) des podcasts génériques - Algorithme adapte automatiquement la pondération - Coût : champ supplémentaire en DB + règle algo --- ### 2.2 Formule de scoring **Décision** : Score combiné dynamique selon type de contenu ``` score_final = (score_geo * poids_geo_type) + (score_interets * poids_interets_type) + (score_engagement * 0.2) + (bonus_aleatoire) où : - score_geo = 1 - (distance_km / distance_max_km) - score_interets = moyenne des jauges utilisateur pour les tags du contenu - score_engagement = (taux_completion * 0.5) + (ratio_likes * 0.3) + (ratio_abonnements * 0.2) - bonus_aleatoire = 10% des recommandations tirées aléatoirement ``` **Pondérations par type** : | Type | Poids géo | Poids intérêts | |------|-----------|----------------| | Géo-ancré | 0.7 | 0.1 | | Géo-contextuel | 0.5 | 0.3 | | Géo-neutre | 0.2 | 0.6 | **Paramètres** : - Distance max recommandée : **200 km** - Dégradation : **linéaire** (1 - distance/200km) - Rayon point GPS : **500m** (adapté au volume de contenu local) **Tous ces paramètres sont configurables à chaud via interface admin.** **Justification** : - Flexibilité totale selon type de contenu - Linéaire = rattrapage naturel du contenu viral ancien - Auditable via métriques engagement (moyenne/médiane) --- ### 2.3 Score d'engagement et popularité **Décision** : Intégration popularité avec poids 0.2 **Métriques** : - **Taux de complétion** : écoutes >80% / total écoutes (poids 0.5) - **Ratio likes** : likes / écoutes (poids 0.3) - **Ratio abonnements** : nouveaux abonnés après écoute / écoutes (poids 0.2) **Seuil minimum** : - Minimum **50 écoutes** avant de considérer l'engagement - Contenu <50 écoutes : score engagement = 0.5 (neutre) **Contenu viral** : - Un contenu viral à Paris **peut** être proposé à Marseille - Score géo faible compensé par score engagement élevé - Paramétrable admin **Dépréciation temporelle** : - Pas de dépréciation automatique - Ratio linéaire = contenu ancien mais toujours apprécié reste pertinent **Justification** : - Équilibre découverte / qualité - Pas de pénalisation arbitraire des contenus anciens - Coût : calculs sur métriques existantes --- ### 2.4 Part d'aléatoire (exploration) **Décision** : 10% par défaut, paramétrable utilisateur **Fonctionnement** : - 1 contenu sur 10 = tirage aléatoire (hors historique déjà écouté) - Utilisateur peut ajuster : curseur 0% (aucun aléatoire) à 50% (exploration max) **Curseur utilisateur** : - 🎯 **0%** : Personnalisé max (recommandations strictes) - ⚖️ **10%** : Équilibré (défaut) - 🎲 **30%** : Découverte élevée - 🌍 **50%** : Découverte max (équivaut à national = découverte) **Justification** : - Évite la bulle de filtre - Laisse l'utilisateur maître de son expérience - Coût : variable aléatoire en algo --- ### 2.5 Contenu politique (version MVP simplifiée) > ⚠️ **Note** : La classification politique avancée (échelle gauche/droite, équilibrage imposé) a été reportée post-MVP. Voir [ANNEXE-POST-MVP.md](#ANNEXE-POST-MVP) pour la version complète. **Décision MVP** : Tag simple "Politique" sans classification idéologique **Tagging** : - Créateur peut taguer son contenu comme "Politique" (optionnel) - Tag "Politique" au même niveau que "Économie", "Sport", "Culture", etc. - **Pas de classification gauche/droite** - **Pas d'équilibrage imposé** **Filtrage utilisateur** : - Option paramètres : **"Masquer contenu politique"** - Si activé → 0% de contenus tagués "Politique" dans le feed - Par défaut : désactivé (tous contenus visibles) **Justification MVP** : - **Simplicité** : Pas de modération politique coûteuse (~2000€/mois économisés) - **Neutralité technique** : Aucun jugement éditorial sur orientation - **Risque minimal** : Évite controverses et contentieux DSA au lancement - **Fonctionnel** : Utilisateurs peuvent filtrer si souhaité **Post-MVP** : - Classification avancée possible si forte demande utilisateurs - Nécessite ressources modération dédiées et audit DSA --- ### 2.6 Mode Kids (13-15 ans) **Décision** : Mode optionnel pour adolescents 13-15 ans uniquement > ⚠️ **Note** : Âge minimum d'inscription = **13 ans** (obligation légale EU). Pas d'utilisateurs <13 ans sur la plateforme. **Tranche concernée** : | Tranche | Description | Contenus autorisés | Restrictions | |---------|-------------|-------------------|--------------| | **13-15 ans** | Collège | Contenus "Tous publics" uniquement | Filtrage 16+ et 18+ | **Activation** : - ❌ **Pas d'activation automatique** (tous les utilisateurs ont ≥13 ans) - ✅ **Activation manuelle** via toggle paramètres - ✅ Parents peuvent activer pour leurs enfants 13-15 ans - ✅ Utilisateur peut désactiver à tout moment **Filtrage quand Mode Kids activé** : - ✅ Contenus "Tous publics" uniquement - ❌ Exclusion contenus 16+ et 18+ - ❌ Pas de contenu politique (automatiquement filtré) - ❌ Pas de publicité (ou uniquement pub validée manuellement) **Interface** : - Interface standard (pas d'interface dédiée enfants pour MVP) - Filtrage algorithmique des contenus inappropriés **Justification** : - **Conformité légale** : Âge minimum 13 ans (RGPD, DSA) - **Simplicité MVP** : Un seul mode optionnel vs 4 tranches d'âge - **Protection mineurs** : Filtrage contenus adultes pour 13-15 ans - **Flexibilité** : Parents décident d'activer ou non --- ### 2.7 Déclenchement géographique **Décision** : Notification au passage, pas d'anticipation **Fonctionnement** : 1. Utilisateur passe à <500m d'un point GPS (contenu géo-ancré) 2. **Notification sonore** (bip court) + **visuelle** (logo selon type) 3. Types de logos : 📍 Info, 🏛️ Culturel, 🍴 Commercial, 🎭 Événement 4. Délai réaction utilisateur : **5 secondes** pour accepter (bouton volant ou commande vocale) 5. Si accepté → lecture immédiate 6. Si ignoré → contenu proposé normalement en file d'attente **Publicités** : - ⚠️ **Jamais d'interruption** de contenu en cours - Pub s'intercale **entre deux séquences** uniquement - Notification pub : son différent (facultatif selon paramètres) **Gestion demi-tour** : - Si utilisateur repart du point après notification → pas de nouvelle notification (déjà proposé) - Réinitialisation après 24h **Justification** : - Respect écoute en cours (pas de coupure brutale) - UX fluide (utilisateur garde contrôle) - Simplicité technique (pas de prédiction trajectoire) --- ### 2.8 Historique et repropositon **Décision** : Pas de reproposition sauf contenu partiel **Règles** : | État écoute | Completion | Action | |-------------|------------|--------| | **Écouté complètement** | >80% | ❌ Ne jamais reproposer (sauf flag `replayable = true` pour audio-guides) | | **Skippé rapidement** | <10s | ❌ Ne pas reproposer | | **Partiellement écouté** | 10-80% | ✅ Reproposer avec reprise position (`last_position_seconds`) | **Stockage historique** : - Table `user_content_history` (user_id, content_id, completion_rate, last_position, listened_at) - Historique **illimité** (PostgreSQL) - Algorithme considère les **100 derniers** pour optimisation requêtes - Export complet disponible (RGPD) **Justification** : - Découverte maximale (pas de redites) - Respect erreurs de clic (contenu partiel = 2nde chance) - Coût stockage négligeable (PostgreSQL scalable) --- ### 2.9 Paramétrabilité admin (interface dashboard) **Décision** : Tous paramètres scoring exposés + A/B testing **Paramètres configurables à chaud** : | Paramètre | Plage | Défaut | Unité | |-----------|-------|--------|-------| | `poids_geo_ancre` | 0.5 - 1.0 | 0.7 | % | | `poids_geo_contextuel` | 0.3 - 0.7 | 0.5 | % | | `poids_geo_neutre` | 0.0 - 0.4 | 0.2 | % | | `poids_engagement` | 0.0 - 0.5 | 0.2 | % | | `part_aleatoire_global` | 0.0 - 0.3 | 0.1 | % | | `distance_max_km` | 50 - 500 | 200 | km | | `rayon_gps_point_m` | 100 - 2000 | 500 | m | | `seuil_min_ecoutes_engagement` | 10 - 200 | 50 | nb | **Application changements** : - Immédiat : nouveaux calculs utilisent nouvelle config - Aucun recalcul batch (coût CPU) - Version config trackée (git-like) - Rollback 1 clic **A/B Testing** : - Création variantes (Config A vs Config B) - Split utilisateurs 50/50 aléatoire - Métriques comparatives : taux complétion, engagement, session duration - Dashboard graphique temps réel **Audit engagement** : - Métriques clés : moyenne/médiane temps d'écoute par session - Graphiques : évolution engagement selon config - Export CSV pour analyse externe **Justification** : - Optimisation continue sans redéploiement - Data-driven decisions (métriques objectives) - Coût : dashboard admin à développer (one-time) --- ### 2.10 Paramétrabilité utilisateur **Décision** : Curseurs avancés avec profils sauvegardables **Niveaux de personnalisation** : **Curseurs disponibles** : - 📍 **Géolocalisation** : Local ← slider → National (découverte = national) - 🎲 **Découverte** : 0% ← slider → 50% (part aléatoire) - ⚖️ **Politique** : Masquer / Équilibré / Mes préférences **Profils sauvegardables** : - 🚗 Trajet quotidien (boulot) : géo local, découverte 5%, politique masqué - 🛣️ Road trip : géo régional, découverte 30%, politique équilibré - 👶 Enfants : Mode Kids activé **Synchronisation** : - ✅ Sync profils entre devices (cloud PostgreSQL) - ❌ Pas de partage profils entre utilisateurs (famille) - Auto-switch selon context (détection trajet récurrent via GPS) **Sécurité conduite** : - ⚠️ **Blocage modification si vitesse GPS >10 km/h** - Warning au lancement app : "Configurez avant de prendre la route" - Modifications uniquement app arrêtée/passager **Justification** : - Utilisateur maître de son expérience - Contextes d'usage différents (quotidien vs voyage) - Sécurité routière (pas de distraction) --- ### 2.11 Médias traditionnels **Décision** : Ouverture aux médias établis **Médias autorisés** : - Presse nationale : Le Monde, Le Parisien, Libération, Le Figaro, etc. - Radios : France Inter, RTL, Europe 1, etc. - Médias régionaux : Ouest-France, Sud-Ouest, etc. **Format contenus** : - Flashs info géolocalisés (actualité régionale) - Chroniques thématiques (culture, économie, sport) - Éditos et débats (classification politique appliquée) **Validation** : - Compte média vérifié (badge ✓) - Pas de validation 3 premiers contenus (confiance établie) - Modération a posteriori uniquement **Monétisation** : - Partage revenus pub standard (même conditions créateurs) - Possibilité sponsoring direct (pas via plateforme) **Justification** : - Crédibilité plateforme (contenus professionnels) - Diversité éditoriale - Attractivité grand public (noms reconnus) --- ## Récapitulatif Section 2
## 3. Centres d'intérêt et jauges ### 3.1 Évolution des jauges **Décision** : Système simple avec valeurs fixes | Action | Impact jauge | Justification | |--------|--------------|---------------| | **Like automatique renforcé (≥80% écoute)** | +2% | Signal fort d'intérêt (écoute quasi-complète) | | **Like automatique standard (30-79% écoute)** | +1% | Signal modéré d'intérêt | | **Like explicite (manuel)** | +2% | Signal fort, cumulable avec auto | | **Abonnement créateur** | +5% sur tous ses tags | Signal très fort d'affinité | | **Skip rapide (<10s)** | -0.5% | Désintérêt marqué | | **Skip tardif (≥30%)** | 0% | Neutre (contenu essayé suffisamment) | **Paramètres techniques** : - Les jauges sont bornées strictement entre **0% et 100%** - Calcul immédiat à chaque action (pas de batch différé) - Les tags du contenu sont définis par le créateur à la publication - Si un contenu a plusieurs tags, chaque jauge correspondante est impactée **Exemple de calcul** : ``` Contenu de 5 minutes tagué "Automobile" + "Voyage" Scénario 1 : Écoute 4min30 (90%) → Like automatique renforcé (+2%) → Jauge Automobile : 45% → 47% → Jauge Voyage : 60% → 62% Scénario 2 : Écoute 2min30 (50%) → Like automatique standard (+1%) → Jauge Automobile : 45% → 46% → Jauge Voyage : 60% → 61% Scénario 3 : Écoute 2min30 (50%) + Like manuel → Like auto +1% puis like manuel +2% = +3% total → Jauge Automobile : 45% → 48% → Jauge Voyage : 60% → 63% Scénario 4 : Skip après 5s → Signal négatif (-0.5%) → Jauge Automobile : 45% → 44.5% → Jauge Voyage : 60% → 59.5% ``` **Justification** : - **Like automatique** : Reflète l'engagement réel (voir [ADR-010](#../adr/010-commandes-volant)) - **Sécurité routière** : Pas d'action complexe en conduite - **Prévisibilité** : Règles claires et déterministes - **Coût minimal** : Calculs simples en backend - **Fiabilité** : Pas d'edge cases complexes - **Ajustable** : Valeurs modifiables via dashboard admin si besoin --- ### 3.2 Jauge initiale **Décision** : Démarrage neutre à 50%, pas de questionnaire **À l'inscription** : - Toutes les jauges d'intérêt sont initialisées à **50%** - Pas de questionnaire onboarding (friction zéro) - L'algorithme apprend naturellement via les premières écoutes **Catégories disponibles** : - Automobile - Voyage - Famille - Amour - Musique - Économie - Cryptomonnaie - Politique - Culture générale - Sport - Technologie - Santé - *... (extensible)* **Cold start (premiers jours)** : 1. Nouvel utilisateur s'inscrit → toutes jauges à 50% 2. Écoute premier podcast "Automobile" → jauge Auto monte à 51% 3. Skip un contenu "Économie" → jauge Éco descend à 48% 4. Après 10-15 écoutes, profil commence à se dessiner clairement **Alternative optionnelle (post-MVP)** : - Questionnaire **optionnel** proposé après 3 écoutes (in-app) - Message : "Améliorez vos recommandations en sélectionnant vos centres d'intérêt" - Si rempli : jauges sélectionnées passent à 70%, non sélectionnées à 30% - Si skip : conserve 50% partout **Justification** : - **Inscription ultra-rapide** : pas de questionnaire = moins de churn - **Découverte naturelle** : l'algorithme apprend en quelques écoutes - **Équitable** : pas de biais initial vers certains créateurs - **Comportement déterministe** : facile à tester et débugger - **Cold start acceptable** : à 50%, tous les contenus ont une chance égale initialement --- ### 3.3 Dégradation temporelle **Décision** : Pas de dégradation automatique Les jauges **ne diminuent jamais** avec le temps de manière automatique. **Règle** : - Une jauge ne change **que par les actions utilisateur** (like, écoute, skip) - Pas de cron job de dégradation périodique - Pas de "rafraîchissement" artificiel **Scénario illustratif** : ``` Utilisateur aimait "Économie" (jauge 80%) il y a 1 an → Depuis, skip tous les contenus Éco → Jauge descend naturellement à 40% via les skips → Pas besoin de dégradation temporelle ``` **Si utilisateur inactif longtemps** : - Utilisateur part en vacances 6 mois → jauges conservées - Au retour : ses jauges reflètent toujours ses goûts d'avant - Comportement cohérent et prévisible **Alternative utilisateur (contrôle explicite)** : - Bouton "Réinitialiser mes centres d'intérêt" dans paramètres - Action manuelle : remet toutes les jauges à 50% - Permet nouveau départ si souhaité (changement de vie, etc.) **Justification** : - **Principe KISS** (Keep It Simple, Stupid) - **Coût 0** : pas de batch nocturne, pas de calculs temporels - **Fiabilité maximale** : pas de bugs de fuseaux horaires, dates, etc. - **UX prévisible** : jauge = reflet des actions, pas d'automatisme caché - **Respect historique** : si utilisateur aimait X depuis 2 ans, pourquoi "oublier" ? - **Évolution naturelle** : les actions récentes suffisent à faire évoluer les jauges --- ## Récapitulatif Section 3
## 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** : 1. Créateur upload ses 3 premiers contenus 2. Contenus passent en **file d'attente modération** 3. Modérateur junior RoadWave : - Écoute 30 secondes (ou 15s à 2x) - Vérifie métadonnées - Valide ou rejette avec raison 4. Si accepté : contenu publié + notification créateur 5. Si refusé : notification avec raison détaillée + lien vers règles 6. Après 3 contenus validés : créateur passe en **statut vérifié** **Critères de validation** : | Critère | Détails | |---------|---------| | **Qualité audio** | Compréhensible (pas de grésillement excessif) | | **Respect règles** | Pas de contenu prohibé évident (haine, spam, illégal) | | **Classification âge** | Cohérente avec contenu écouté | | **Tags pertinents** | Correspondance minimale avec contenu | | **Zone diffusion** | Cohérente (pas "Tour Eiffel" avec zone "National") | **Délai de validation** : - Objectif : **24-48h** (jours ouvrés) - Priorité : FIFO (First In First Out) - Weekend : délai peut atteindre 72h - Message au créateur : "Validation en cours, délai estimé 24-48h" **Notification créateur** : **Si accepté** : - Email + push : "✅ Votre contenu '[Titre]' est en ligne !" - Lien direct vers le contenu - Compteur : "2/3 contenus validés pour devenir créateur vérifié" **Si refusé** : - Email + push : "❌ Contenu '[Titre]' refusé" - Raison détaillée : "Qualité audio insuffisante" / "Tags non pertinents" / "Classification incorrecte" / etc. - Lien vers règles de publication - Possibilité de correction + resoumission **Après 3 validations** : Créateur obtient **statut "Vérifié"** : - Badge ✓ visible sur profil - Contenus futurs publiés **immédiatement** (modération a posteriori uniquement) - Modération seulement si signalé par utilisateurs **Outils modérateur** : - Écoute accélérée (1.5x ou 2x) = double productivité - Interface dédiée : queue de contenus à valider - Raccourcis clavier : A (Accepter), R (Rejeter), Espace (Pause) - Historique créateur visible (si déjà 1-2 contenus validés) **Modération communautaire (post-MVP)** : ⚠️ **Non implémenté au MVP** (complexité juridique) Vision future (envisageable) : - Créateurs établis peuvent opt-in "Modérateur communautaire" - Formation obligatoire (30 min) + quiz (80%) - Pré-validation uniquement (validation finale toujours par équipe RoadWave) - Compensation : badges, premium offert - Attribution aléatoire (pas de collusion) **Justification décision MVP** : - **Responsabilité juridique** : plateforme reste responsable (DSA EU) - **Qualité garantie** : modérateurs formés et mandatés - **Anti-spam efficace** : bloque 95% des abus dès le début - **Coût raisonnable** : 30s × 3 contenus = 1.5 min/créateur - **UX acceptable** : délai 24-48h expliqué clairement - **Pas de validation par pairs** au MVP = évite risques juridiques (collusion, compétence, conflits) --- ### 4.4 Modification et suppression **Décision** : Modification métadonnées uniquement, suppression immédiate **Modification autorisée** : | Élément | Modifiable | Justification | |---------|------------|---------------| | **Titre** | ✅ | Correction coquilles | | **Description** | ✅ | Si ajoutée ultérieurement | | **Tags** | ✅ | Ajustement pertinence | | **Image couverture** | ✅ | Personnalisation | | **Audio** | ❌ | Intégrité contenu | | **Zone diffusion** | ❌ | Évite manipulation algo | | **Type géo** | ❌ | Évite manipulation algo | | **Classification âge** | ❌ | Sécurité mineurs | **Raisons restrictions** : **Audio non modifiable** : - Évite fraude : uploader contenu validé → remplacer par spam - Intégrité : auditeurs doivent écouter ce qui a été validé **Zone/Type non modifiables** : - Évite manipulation : créer "Local Paris" → changer en "National" pour boost visibilité - Évite abus : créer "Neutre" (faible pondération géo) → changer en "Ancré" (forte pondération) **Classification non modifiable** : - Évite contournement : uploader "Tout public" → passer en "18+" sans revalidation - Sécurité : garantit que classification a été vérifiée **Si besoin de changer audio/zone/classification** : - Action : **Supprimer contenu + republier** - Si créateur <3 contenus validés : retourne en file validation - Si créateur ≥3 contenus validés : publication immédiate **Suppression de contenu** : | Aspect | Comportement | |--------|--------------| | **Délai** | Immédiat | Suppression BDD + CDN sous 5 min | | **Réversibilité** | Non | Suppression définitive | | **Historique auditeurs** | Marqué "Contenu supprimé par créateur" | Conserve écoute dans historique | | **Analytics plateforme** | Anonymisé et conservé | Métriques globales (RGPD compliant) | | **Fichiers CDN** | Supprimés sous 24h | Purge cache Bunny CDN | **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** : 1. User entend notification sonore + voit icône et compteur 2. User appuie "Suivant" dans les 7 secondes → décompte 5s démarre 3. Pendant décompte : contenu actuel continue, compteur visible (5...4...3...2...1) 4. Si contenu actuel se termine pendant décompte → contenu suivant du buffer démarre 5. À la fin du décompte → contenu géolocalisé démarre (fade out/in 0.3s) **Si user n'appuie pas sur "Suivant"** : - Notification disparaît après 7 secondes - Contenu géolocalisé est perdu (pas d'insertion dans file) - Pas de nouveau contenu géolocalisé pendant **10 minutes** (éviter spam) **Limitation anti-spam** : - Maximum **6 contenus géolocalisés par heure** - Timer reset toutes les heures (rolling window) - Exception : séquences d'un même audio-guide multi-séquences (comptent comme 1) - Si quota atteint : notifications suivantes ignorées jusqu'à libération du quota **Invalidation immédiate** : - Utilisateur change ses préférences (curseurs géo/découverte/politique) - ⚠️ **Modification bloquée si vitesse GPS >10 km/h** (sécurité routière) - Live démarre d'un créateur suivi dans la zone **Implémentation** : ``` Redis cache : - Clé : user:{user_id}:queue - Structure : [content_1, content_2, ..., content_5] - Métadonnées : {last_lat, last_lon, computed_at, mode: "voiture"|"pieton"} - TTL : 15 minutes Tracking GPS temps réel (mobile) : - Vérification toutes les 1 seconde - Calcul ETA vers points géolocalisés proches (rayon 500m) - Si ETA ≤ 7s → trigger notification - Historique GPS : 30 derniers points pour calcul vitesse moyenne Quota anti-spam (Redis) : - Clé : user:{user_id}:geo_quota - Structure : sorted set avec timestamps des 6 derniers contenus - TTL : 1 heure - Vérification avant notification : ZCOUNT pour compter contenus dernière heure Cooldown après ignorance (Redis) : - Clé : user:{user_id}:geo_cooldown - TTL : 10 minutes - Set après notification ignorée ``` **Justification** : - **Expérience fluide** : pas de latence au clic "Suivant" - **Réactivité géo** : contenu local inséré immédiatement - **Coût optimisé** : recalcul uniquement si nécessaire - **Sécurité** : pas de modification en conduite --- ### 5.1.2 Mode piéton (audio-guides) **Décision** : Notifications push en arrière-plan avec rayon large **Contexte** : - Mode piéton détecté automatiquement si vitesse moyenne < 5 km/h - Cas d'usage : visites à pied, musées, monuments, quartiers historiques - User n'a pas besoin d'avoir l'app ouverte - ⚠️ **Fonctionnalité optionnelle** : requiert permission "localisation en arrière-plan" (activée par user) **Détection** : - App peut être en arrière-plan (si permission accordée) - Rayon de détection : **200 mètres** autour du point GPS - Geofencing iOS/Android pour minimiser consommation batterie - Permission demandée uniquement si user active "Notifications audio-guides piéton" dans settings **Notification push système** : Format : ``` Titre : "Audio-guide à proximité" Body : "[Nom du contenu] - [Nom créateur]" Action : Tap → ouvre app sur le contenu ``` Exemple : ``` Audio-guide à proximité Musée du Louvre : La Joconde - @paris_museum ``` **Permissions requises** : ⚠️ **Important** : Permission "Always Location" est **optionnelle** et demandée uniquement si user active le mode piéton dans settings. iOS (`Info.plist`) : ```xml NSLocationWhenInUseUsageDescription RoadWave utilise votre position pour vous proposer des contenus audio géolocalisés adaptés à votre trajet en temps réel. NSLocationAlwaysAndWhenInUseUsageDescription 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. ``` Android (`AndroidManifest.xml`) : ```xml ``` **Disclosure avant demande permission** (Android requis, iOS recommandé) : Écran affiché avant demande permission "Always Location" : ``` ┌────────────────────────────────────────┐ │ 📍 Notifications audio-guides piéton │ ├────────────────────────────────────────┤ │ Pour vous alerter d'audio-guides à │ │ proximité même quand vous marchez avec │ │ l'app fermée, RoadWave a besoin de │ │ votre position en arrière-plan. │ │ │ │ Votre position sera utilisée pour : │ │ ✅ Détecter monuments à 200m │ │ ✅ Vous envoyer une notification │ │ │ │ Votre position ne sera jamais : │ │ ❌ Vendue à des tiers │ │ ❌ Utilisée pour de la publicité │ │ │ │ Cette fonctionnalité est optionnelle. │ │ Vous pouvez utiliser RoadWave sans │ │ cette permission. │ │ │ │ [Continuer] [Non merci] │ │ │ │ Plus d'infos : Politique confidentialité│ └────────────────────────────────────────┘ ``` **Si user refuse** : - Mode piéton désactivé (uniquement mode voiture disponible) - App fonctionne normalement avec permission "When In Use" - Audio-guides accessibles en mode manuel (user ouvre app, sélectionne contenu) **Comportement après tap sur notification** : 1. User tap notification push 2. App s'ouvre sur la page du contenu 3. User peut démarrer la lecture manuellement 4. Navigation libre (voir section 16.2 pour audio-guides piéton) **Basculement automatique voiture ↔ piéton** : Détection par vitesse GPS moyenne sur 30 secondes : - Vitesse < 5 km/h (stable 10s) → mode piéton - Vitesse ≥ 5 km/h (stable 10s) → mode voiture Changements de mode : | Mode actuel | Vitesse détectée | Nouveau mode | Effet | |-------------|------------------|--------------|-------| | Piéton | ≥ 5 km/h | Voiture | Notifications push → sonores + icône (app ouverte requise) | | Voiture | < 5 km/h | Piéton | Notifications sonores → push arrière-plan | **Pas de popup confirmation** : - Basculement transparent et automatique - User n'a rien à faire - Hysteresis (10s) pour éviter basculements intempestifs **Quota anti-spam mode piéton** : - Même limitation que mode voiture : **6 contenus/heure** - Cooldown 10 min si notification ignorée (app pas ouverte après tap) **Justification** : - ✅ Expérience adaptée aux visites à pied (rayon large, pas de timing précis) - ✅ Économie batterie (geofencing natif iOS/Android) - ✅ User peut garder téléphone en poche - ✅ Basculement automatique = pas de friction --- ### 5.2 Commande "Précédent" **Décision** : Comportement smart selon progression écoute **Règles** : | Situation | Temps écouté | Action "Précédent" | |-----------|--------------|-------------------| | **Début de contenu** | <10 secondes | Retour au contenu précédent (position exacte) | | **Milieu/fin** | ≥10 secondes | Replay contenu actuel depuis le début | | **Premier de session** | N/A | Replay depuis début (rien avant) | **Historique de navigation** : - **10 contenus maximum** en mémoire (Redis List) - Structure : `[{content_id, position_seconds, listened_at}, ...]` - FIFO : au-delà de 10, suppression du plus ancien **Exemple scénario** : ``` Utilisateur écoute : 1. Contenu A → écoute 5s → "Suivant" 2. Contenu B → écoute 2min30 → "Suivant" 3. Contenu C → écoute 5s → "Précédent" → Retour Contenu B à 2min30 (car >10s) 4. Sur Contenu B → "Précédent" → Retour Contenu A à 5s (position exacte) ``` **Interface (responsabilité front)** : - ❌ Pas de message UI - ✅ Progress bar revient au début ou à position exacte - ✅ Animation fluide (transition 0.3s) **Justification** : - **UX intuitive** : comportement standard Spotify/YouTube - **Pas de frustration** : si début, vraiment revenir en arrière - **Simplicité** : règle unique (seuil 10s) --- ### 5.3 Interactions au volant : Like automatique et engagement > ⚠️ **Architecture Decision Record** : Voir [ADR-010](#../adr/010-commandes-volant) 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) : ```go type ListenEvent struct { UserID string ContentID string StartedAt time.Time StoppedAt time.Time Duration int // secondes écoutées ContentTotal int // durée totale contenu Percentage float64 // duration / contentTotal * 100 Action string // "completed", "skipped", "paused" } func ProcessListenEvent(event ListenEvent) { percentage := event.Percentage // Signal négatif fort if event.Action == "skipped" && event.Duration < 10 { UpdateJauges(event.UserID, event.ContentID, -0.5) return } // Like automatique if percentage >= 80 { AutoLike(event.UserID, event.ContentID, 2.0) // Renforcé } else if percentage >= 30 { AutoLike(event.UserID, event.ContentID, 1.0) // Standard } // < 30% : pas de like } ``` **Mobile** (iOS/Android) : ```swift // iOS - Tracking écoute class AudioPlayerManager { var startTime: Date? let contentDuration: TimeInterval func onPlay() { startTime = Date() } func onStop(action: String) { // "completed" | "skipped" | "paused" guard let start = startTime else { return } let duration = Date().timeIntervalSince(start) let percentage = (duration / contentDuration) * 100 // API call API.track(ListenEvent( contentId: currentContentId, duration: Int(duration), percentage: percentage, action: action )) } } ``` --- #### Justification **Avantages** : - ✅ **Sécurité routière maximale** : aucune action complexe au volant - ✅ **UX intuitive** : comportement standard industrie (Spotify, YouTube Music, Deezer) - ✅ **Compatibilité 100%** : fonctionne sur tous véhicules, tous OS - ✅ **Engagement amélioré** : tous les contenus écoutés génèrent des signaux - ✅ **Algorithme plus précis** : données granulaires (30%, 50%, 80%, 100%) - ✅ **Simplicité développement** : pas de workarounds complexes iOS/Android **Inconvénients mitigés** : - ⚠️ Pas de like explicite en conduite → **Mitigation** : like automatique + vocal (CarPlay/Android Auto) - ⚠️ Pas d'abonnement en conduite → **Mitigation** : liste "Créateurs à découvrir" dans app - ⚠️ Like automatique peut surprendre → **Mitigation** : onboarding clair + unlike possible --- #### Communication utilisateurs (onboarding) **Écran onboarding 1** : ``` 🚗 Conduite sécurisée RoadWave détecte automatiquement vos goûts selon vos écoutes. Plus vous écoutez longtemps, plus l'algorithme s'améliore ! [Suivant] ``` **Écran onboarding 2** : ``` ❤️ Likes automatiques Pas besoin de liker manuellement : si vous écoutez >50% d'un contenu, on comprend que vous aimez ! [Suivant] ``` **Écran onboarding 3** : ``` ⏸️ Commandes simples Utilisez les boutons au volant : • Suivant → Prochain contenu • Précédent → Contenu d'avant • Pause → Mettre en pause [Commencer] ``` --- ### 5.4 Lecture en boucle et enchaînement **Décision** : Passage automatique après 2s + insertion pub paramétrable **Fin de contenu** : 1. Audio termine → **Timer 2 secondes** démarre 2. UI overlay : "Contenu suivant dans 2s..." + barre décompte 3. Possibilité annuler : bouton "Rester sur ce contenu" (optionnel) 4. Timer atteint 0 → passage automatique au contenu suivant **Délai selon contexte** : | Mode | Délai | Justification | |------|-------|---------------| | **Standard** | 2 secondes | Temps réaction confortable | | **Mode Kids** | 1 seconde | Attention courte enfants | | **Live** | 0 seconde | Enchaînement immédiat | **Insertion publicité** : - Pub s'insère **pendant le délai de 2s** (transition naturelle) - Fréquence : **paramétrable admin** (défaut : 1 pub / 5 contenus) - Message : "Publicité (15s)" puis lecture pub - ⚠️ **Jamais d'interruption** d'un contenu en cours **Publicité skippable** : - Durée minimale visionnage : **paramétrable** (défaut : 5 secondes) - Bouton "Passer" apparaît après délai - Métriques engagement : taux skip, durée écoute moyenne - **Like et abonnement autorisés sur pub** (engagement créateur pub) **Si aucun contenu disponible** : 1. Message : "Aucun contenu disponible dans cette zone" 2. Proposition : "Élargir la zone de recherche ?" (bouton) 3. Si accepté → relance algo avec rayon +50km 4. Sinon → lecture en pause, attente action utilisateur **Gestion erreurs** : - Échec chargement contenu suivant → **retry 3× avec backoff exponentiel** - Si 3 échecs → message "Connexion instable, basculement mode offline" - Mode offline → lecture contenus téléchargés uniquement **Justification** : - **Fluidité** : enchaînement naturel sans action utilisateur - **Contrôle** : possibilité annuler pendant délai - **Paramétrabilité pub** : évite frustration excès publicité - **Engagement pub** : like/abonnement autorisé = monétisation créateurs pub --- ## Récapitulatif Section 5
## 6. Publicités ### 6.1 Système de campagnes publicitaires **Décision** : Interface self-service avec maîtrise budget et métriques détaillées **Fonctionnalités publicitaire** : #### Création de campagne **Paramètres configurables** : | Paramètre | Options | Justification | |-----------|---------|---------------| | **Budget total** | Montant libre (min 50€) | Maîtrise coût total | | **Durée campagne** | Date début/fin + étalement | Ex: 300€ sur 2 semaines | | **Ciblage géographique** | Point GPS / Ville / Département / Région / National | Précision selon besoin | | **Ciblage horaire** | Plages horaires (ex: 7h-9h, 17h-19h) | Optimisation trajet domicile-travail | | **Centres d'intérêt** | Tags (ex: Automobile, Voyage) | Ciblage thématique | | **Tranche d'âge** | Tout public / 13+ / 16+ / 18+ | Respect classifications | **Étalement budget** : ``` Exemple campagne : - Budget : 300€ - Durée : 14 jours - Zone : Département du Var - Horaires : 7h-9h + 17h-19h (rush) Calcul automatique : → Budget/jour = 300€ / 14 = 21.43€/jour → Diffusions/jour estimées : ~430 (0.05€/écoute) → Alerte si budget épuisé avant fin (réajustement possible) ``` **Mode de paiement** : - ✅ Prépaiement obligatoire (évite impayés) - ✅ Carte bancaire uniquement (Mangopay) - ✅ Recharge automatique optionnelle (si budget <10%) #### Validation et modération **Processus** : 1. Publicitaire upload audio pub (formats : MP3, AAC) 2. **Validation manuelle obligatoire** (modérateur RoadWave) - Délai : 24-48h ouvrées - Critères : respect réglementation, qualité audio, classification correcte 3. Si accepté → campagne démarre à la date choisie 4. Si refusé → email avec raison + remboursement automatique **Contenus interdits en pub** : - ❌ Alcool, tabac (réglementation française) - ❌ Jeux d'argent - ❌ Contenu politique (pendant campagnes électorales) - ❌ Contenu sexuel ou violence - ✅ Tous commerces/services légaux #### Dashboard métriques engagement **Indicateurs temps réel** : | Métrique | Description | Utilité | |----------|-------------|---------| | **Impressions** | Nombre de diffusions | Volume exposition | | **Écoutes complètes** | Pub écoutée >80% | Engagement réel | | **Taux de skip** | % skip après délai min | Qualité contenu | | **Durée moyenne écoute** | Secondes écoutées | Rétention attention | | **Likes** | Nombre de likes | Appréciation contenu | | **Abonnements** | Abonnements au créateur pub | Conversion forte | | **Coût par écoute** | Budget / écoutes complètes | ROI campagne | | **Répartition géographique** | Heatmap diffusions | Validation ciblage | | **Répartition horaire** | Graphique par heure | Optimisation horaires | **Métriques engagement avancées** : - **Taux complétion par tranche d'âge** : identifier audience réceptive - **Carte de chaleur GPS** : visualiser zones forte écoute - **Comparatif campagnes** : A/B testing créatifs publicitaires **Export données** : - ✅ CSV/Excel pour analyse externe - ✅ Graphiques interactifs (Chart.js) - ✅ Rapport PDF automatique fin de campagne #### Gestion budget et alertes **Suivi temps réel** : - Dashboard : Budget restant, % consommé, jours restants - Projection : "À ce rythme, budget épuisé dans X jours" - Alerte email/push si : - Budget consommé à 80% - Budget consommé à 90% - Budget épuisé - Campagne terminée (rapport final) **Ajustements en cours** : - ✅ Pause campagne (budget conservé) - ✅ Prolonger campagne (recharge budget) - ✅ Modifier ciblage horaire/géo (si <50% budget consommé) - ❌ Modifier audio (nécessite nouvelle validation) #### Système d'enchères (post-MVP) **Optionnel future** : - Enchère au CPM (coût pour 1000 impressions) - Priorité selon prix : pub prix élevé → diffusion privilégiée - Floor price : 2€ CPM minimum - Évite surcharge pub : max 1 pub / 5 contenus stricte **Justification décision MVP** : - Tarif fixe simple : 0.05€/écoute complète - Pas de complexité enchères immédiatement - Scalable : passage enchères ultérieur si demande forte --- ### 6.2 Insertion et fréquence **Décision** : Paramétrable admin + respect expérience utilisateur **Fréquence d'insertion** : - **Défaut : 1 pub / 5 contenus** (utilisateurs gratuits) - **Paramétrable admin** : curseur 1/3 à 1/10 - **Utilisateurs Premium** : 0 pub (modèle sans publicité) **Règles strictes** : - ⚠️ **Jamais d'interruption** contenu en cours - Pub s'insère uniquement **entre deux contenus** (pendant délai 2s) - Rotation : même pub max **3 fois/jour** par utilisateur (évite saturation) - Limite : max **6 pubs/heure** par utilisateur (évite spam) **Ciblage intelligent** : - Géolocalisation prioritaire (point GPS > ville > département > région > national) - Centres d'intérêt secondaires (tags utilisateur) - Horaire (campagne 7h-9h → diffusion uniquement pendant plage) **Volume audio normalisé** : - Pub normalisée à **-14 LUFS** (standard broadcast) - Évite effet "pub trop forte" (frustration utilisateur) - Validation automatique via FFmpeg lors encodage --- ### 6.3 Caractéristiques publicités **Durée** : - Minimum : **10 secondes** - Maximum : **60 secondes** - Recommandé : **15-30 secondes** (sweet spot engagement) **Skippable** : - Délai minimum obligatoire : **5 secondes** (paramétrable admin : 3-10s) - Bouton "Passer la publicité" apparaît après délai - Durée minimale comptabilisée pour facturation **Facturation** : - **Écoute complète** (>80%) : 0.05€ facturé publicitaire - **Skip après délai min** : 0.02€ (exposition partielle) - **Skip immédiat** (<5s) : 0€ (pas d'engagement) **Justification modèle tarif** : - Incitatif qualité : pub engageante = coût réduit - Équitable : publicitaire paie pour attention réelle - Transparent : dashboard montre écoutes complètes vs skips --- ## Récapitulatif Section 6
## 7. Radio live ### 7.1 Démarrage d'un live **Décision** : Buffer 15s + notification abonnés + limite 8h **Processus de démarrage** : 1. Créateur appuie "Démarrer live" dans l'app 2. **Vérification pré-live** : - Connexion ≥1 Mbps upload (warning si insuffisant) - Micro autorisé - Zone diffusion déjà définie (ville, département, région, national) 3. **Buffer initial 15 secondes** avant diffusion publique - Créateur parle pendant 15s → accumulation buffer serveur - Message créateur : "Live démarre dans 15s... Testez votre micro" - Permet vérifier qualité audio avant diffusion 4. Après 15s → **Live public**, auditeurs peuvent rejoindre **Notification abonnés** : - ✅ **Push notification immédiate** à tous les abonnés dans la zone géographique - Message : "🔴 [Nom créateur] est en direct : [Titre live]" - Tap notification → ouverture app + lecture live immédiate - **Filtrage géographique** : si abonné hors zone, pas de notif (évite frustration) **Limite de durée** : - **Maximum 8 heures** par session live - Warning créateur à 7h30 : "Votre live se terminera dans 30 min" - Si besoin continuer → arrêt + redémarrage nouveau live (évite abus ressources serveur) **Métadonnées obligatoires** : | Champ | Format | Validation | |-------|--------|------------| | **Titre** | 5-100 caractères | Ex: "Discussion politique en direct" | | **Tags** | 1-3 centres d'intérêt | Sélection liste prédéfinie | | **Classification âge** | Enum | Tout public / 13+ / 16+ / 18+ | | **Zone diffusion** | Geo | Ville / Département / Région / National | **Contenus interdits en live** : | Type | Description | Sanction | |------|-------------|----------| | **Concert/spectacle** | Diffusion concert en direct depuis la salle | Strike 2 immédiat + 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** : 1. Créateur appuie "Arrêter live" 2. **Compte à rebours 5 secondes** affiché - Message audio : "Ce live se termine dans 5... 4... 3... 2... 1" - Permet au créateur de faire un outro propre - Annulable pendant décompte (bouton "Annuler") 3. Timer atteint 0 → arrêt diffusion 4. **Traitement post-live automatique** démarre (voir ci-dessous) **Fin automatique si déconnexion** : | Durée coupure | Comportement | |---------------|--------------| | **<60 secondes** | Message auditeurs : "Connexion créateur perdue, reconnexion en cours..." | | **≥60 secondes** | Arrêt automatique live + message : "Le live est terminé suite à une coupure de connexion" | **Enregistrement automatique** : ✅ **Obligatoire et automatique** (valeur ajoutée énorme) **Processus** : 1. Pendant live : enregistrement continu serveur (format Opus raw) 2. Fin live → **job asynchrone** (worker Go + FFmpeg) : - Conversion MP3 256 kbps (qualité optimale) - Génération segments HLS (comme contenu classique) - Normalisation volume -14 LUFS - Détection silences prolongés (nettoyage) 3. **Publication automatique** du replay : - Titre : "[REPLAY] [Titre live original]" - Même zone diffusion, tags, classification - Disponible sous **5-10 minutes** après fin live - Type géo : automatiquement "Géo-neutre" (replay = contenu pérenne) **Options créateur** : | Option | Défaut | Description | |--------|--------|-------------| | **Publier replay automatiquement** | ✅ OUI | Désactivable avant démarrage live | | **Supprimer replay après coup** | ✅ Possible | Suppression standard contenu | | **Modifier replay** | ❌ Non | Intégrité enregistrement | **Conservation fichier source** : - Opus raw conservé **7 jours** après fin live (backup) - Suppression automatique après 7j (économie stockage) - Si replay supprimé par créateur → fichier raw supprimé immédiatement **Justification** : - **Compte à rebours 5s** : outro propre, pas de coupure brutale - **Tolérance 60s** : évite arrêts intempestifs (tunnel, changement cellule) - **Enregistrement auto** : valorisation contenu éphémère, génération contenu pérenne - **MP3 256 kbps** : qualité optimale pour replay (vs 48 kbps live) - **Coût** : stockage minimal (Opus → MP3 1× par live, puis suppression raw après 7j) --- ### 7.3 Comportement auditeur **Décision** : Buffer 15s + continuation hors zone + reconnexion au live actuel + écoute passive uniquement **Buffer de synchronisation** : - **15 secondes** entre créateur et auditeurs - Raisons : - Stabilité réseau mobile (3G/4G fluctuant) - Synchronisation approximative acceptable (pas besoin temps réel strict) - Permet buffering anticiper coupures courtes (tunnels) **Comparaison buffers** : | Buffer | Avantages | Inconvénients | Décision | |--------|-----------|---------------|----------| | 5s | Quasi temps réel | Instable 3G, coupures fréquentes | ❌ | | 10s | Bon compromis | Légèrement juste pour 3G | ❌ | | **15s** | **Stabilité optimale 3G/4G** | Léger décalage acceptable | ✅ | | 20s+ | Très stable | Décalage trop perceptible | ❌ | **Zone géographique pendant live** : - ✅ **Continuation si sortie de zone** - Scénario : auditeur écoute live régional → sort du département → **live continue** - Raisons : - Pas de coupure brutale (mauvaise UX) - Écoute engagée = terminer naturellement - Après fin live → algo normal (pas de contenus hors zone) **Reconnexion après coupure réseau** : | Durée coupure | Comportement | |---------------|--------------| | **<90 secondes** | Reprend au live actuel (pas au buffer ancien) + saut temporel transparent | | **≥90 secondes** | Message : "Live en cours perdu, passage au contenu suivant" + algo propose contenu normal | **Interactions disponibles** : **Décision ferme** : ❌ **Aucun chat en direct, ni maintenant ni dans le futur** **Raisons** : - **Sécurité routière** : pas de distraction en voiture (focus UX) - **Harcèlement** : évite contenu haineux, insultes, trolling - **Modération** : pas de coût modération temps réel (impossible à scale) - **Simplicité** : écoute passive = expérience uniforme **Actions autorisées pendant live** : | Action | Disponible | Effet | |--------|------------|-------| | **Like** | ✅ | Bouton cœur interface mobile (véhicule arrêté) | | **Abonnement créateur** | ✅ | Bouton profil créateur (interface mobile) | | **Skip** | ✅ | Passe au contenu suivant, sort du live | | **Précédent** | ❌ | Pas de sens sur live (flux temps réel) | | **Chat** | ❌ | Jamais implémenté (décision définitive) | | **Réactions emoji** | ❌ | Jamais implémenté (décision définitive) | **Messages utilisateur** : - "💬 Les discussions ne sont pas disponibles sur RoadWave pour garantir votre sécurité en voiture et éviter le harcèlement." **Justification décision définitive** : - **UX cohérente** : RoadWave = écoute en conduisant, pas réseau social interactif - **Bien-être** : évite toxicité, harcèlement, haine (fléau réseaux sociaux) - **Juridique** : pas de risque contentieux modération chat (DSA EU) - **Coût** : 0€ infra chat, 0€ modération temps réel - **Différenciation** : positionnement "audio safe" vs plateformes toxiques --- ### 7.4 Architecture technique **Stack** : ``` Créateur (App mobile) ↓ WebRTC (OPUS 48 kbps) Serveur Ingestion (Go + Pion WebRTC) ↓ Conversion temps réel Serveur HLS (segments .ts) ↓ CDN (Bunny) Auditeurs (App mobile, HLS natif) ``` **Flux détaillé** : 1. **Créateur** → WebRTC OPUS 48 kbps vers serveur Go 2. **Serveur Go** → Conversion temps réel OPUS → segments HLS (.m3u8 + .ts) 3. **Bunny CDN** → Distribution HLS avec cache 4. **Auditeurs** → Lecture HLS native iOS/Android (buffer 15s) 5. **Enregistrement parallèle** → Opus raw stocké temporairement 6. **Post-live** → Job async : Opus → MP3 256 kbps → Publication replay **Dépendances** : - ✅ **Pion WebRTC** (Go library, open source, MIT license) - ✅ **FFmpeg** (conversion audio, LGPL/GPL) - ✅ **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 1. Utilisateur à pied (<5 km/h) passe à <**100m** d'un lieu avec audio-guides 2. **Notification push** : "📍 Audio-guide disponible : [Musée du Louvre]" 3. Tap notification → **Page de sélection** audio-guides #### Page de sélection **Affichage** : ``` 📍 Musée du Louvre Choisissez votre guide : ┌─────────────────────────────────┐ │ 🎨 Visite complète (45 min) │ │ Par [Créateur A] • 12 séquences│ │ ⭐ 4.8 • 1.2K écoutes │ └─────────────────────────────────┘ ┌─────────────────────────────────┐ │ 🏛️ Œuvres majeures (20 min) │ │ Par [Créateur B] • 5 séquences │ │ ⭐ 4.9 • 3.5K écoutes │ └─────────────────────────────────┘ ┌─────────────────────────────────┐ │ 👶 Visite famille (30 min) │ │ Par [Créateur C] • 8 séquences │ │ ⭐ 4.7 • 850 écoutes │ └─────────────────────────────────┘ ``` #### Interface audio-guide **Après sélection** : ``` 🎨 Visite complète • Musée du Louvre Piste actuelle : 2/12 "La Joconde - Histoire et mystères" [████████────────────] 3:24 / 6:50 Liste des séquences : ✅ 1. Introduction et architecture ▶️ 2. La Joconde - Histoire et mystères ⏸️ 3. Vénus de Milo ⏸️ 4. Victoire de Samothrace ⏸️ 5. Peintures Renaissance ... ⏸️ 12. Conclusion et boutique ``` **Navigation** : | Action | Geste | Effet | |--------|-------|-------| | **Séquence suivante** | Tap "Suivant" ou commande vocale "Suivant" | Passe à séquence N+1 | | **Séquence précédente** | Tap "Précédent" ou commande vocale "Précédent" | Revient à séquence N-1 | | **Saut direct** | Tap séquence dans liste | Lecture séquence choisie | | **Pause** | Tap bouton pause | Met en pause, reprise position exacte | | **Quitter** | Tap "×" | Sauvegarde progression, sortie guide | **Guidage vocal automatique** : - Entre 2 séquences : "Vous avez terminé la séquence 2. Dirigez-vous vers la Vénus de Milo pour la séquence 3." - Si utilisateur s'éloigne (>50m de la prochaine pièce) : "Vous vous éloignez de la prochaine étape. Consultez le plan." **Sauvegarde progression** : - Position dans guide sauvegardée automatiquement - Retour ultérieur : "Reprendre à la séquence 5 ?" ou "Recommencer depuis le début" - Historique : guide marqué "Terminé" si toutes séquences écoutées **Création audio-guide multiséquence** : **Processus créateur** : 1. Créateur upload **plusieurs fichiers audio** (1 par séquence) 2. Numérote les séquences : "Séquence 1", "Séquence 2", etc. 3. Titre chaque séquence : "Introduction", "La Joconde", etc. 4. Définit **point GPS unique** pour tout le guide (centre du lieu) 5. Métadonnées : durée totale calculée automatiquement **Format stockage** : ```json { "guide_id": "abc123", "title": "Visite complète Musée du Louvre", "location": {"lat": 48.8606, "lon": 2.3376, "radius": 200}, "sequences": [ { "sequence_number": 1, "title": "Introduction et architecture", "audio_url": "https://cdn.../seq1.mp3", "duration_seconds": 180 }, { "sequence_number": 2, "title": "La Joconde - Histoire et mystères", "audio_url": "https://cdn.../seq2.mp3", "duration_seconds": 410 }, ... ], "total_duration_seconds": 2700, "creator_id": "creator_xyz" } ``` **Justification** : - **UX piéton** : navigation tactile adaptée (pas de commandes volant) - **Autonomie** : utilisateur maître de son rythme (pas d'enchaînement forcé) - **Choix** : plusieurs guides = diversité styles (famille, expert, rapide) - **Engagement** : sauvegarde progression = incitation terminer - **Coût** : réutilise infra contenu standard (juste métadonnées séquences) --- ### 8.4 Limites et désabonnement **Décision** : 200 abonnements max + désabonnement -5% jauges **Nombre maximum d'abonnements** : - **200 créateurs maximum** par utilisateur - Raisons : - **Évite spam** : au-delà de 200, notifications ingérables - **Usage réaliste** : 200 créateurs = déjà énorme (vs 100-150 sur YouTube/Twitter) - **Performance** : requêtes SQL optimisées (index sur 200 max) **Si limite atteinte** : - Message : "Vous suivez déjà 200 créateurs. Désabonnez-vous d'un créateur pour en suivre un nouveau." - Liste triable : par date abonnement, nb contenus écoutés, dernière activité - Suggestion : "Vous n'avez pas écouté [Créateur X] depuis 6 mois, le désabonner ?" **Abonnement initial** : - Impact : **+5% toutes jauges tags du créateur** (défini en [ADR-010](#../adr/010-commandes-volant)) - 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é | PDF | <3 mois | **Vérification** : Via Mangopay (KYC intégré + vérification bancaire) **Délai** : 24-72h si documents conformes **Rejet possible si** : - Documents invalides/illisibles - Identité ne correspond pas au compte RoadWave - Liste noire anti-blanchiment (vérification automatique Mangopay) - RIB non professionnel (particulier) **Base légale** : - **Conformité fiscale** : L'État français impose déclaration revenus >1200€/an (DAS2) - **Anti-blanchiment** : Directive EU 2018/843 (5ème directive LCB-FT) - **RGPD** : Données hébergées EU via Mangopay (conforme) **Justification** : - **Responsabilité légale** : RoadWave doit pouvoir prouver identité réelle créateurs monétisés - **Automatisation** : Mangopay gère tout (KYC, vérifications, conformité, e-wallets) - **KYC gratuit** : inclus dans l'offre Mangopay (vs 1.20€ chez Stripe) - **Souveraineté EU** : Mangopay est européen (France/Luxembourg), régulé ACPR --- ### 9.4 Sources de revenus créateurs #### A) Publicités (utilisateurs gratuits) **Formule** : **3€ / 1000 écoutes complètes** (CPM créateur) **Répartition économique** : ``` Publicité facturée par RoadWave : 0.05€/écoute complète = 50€ CPM ├─ Créateur touche : 3€ (6% du CA pub) └─ Plateforme garde : 47€ (94%) ├─ CDN + infrastructure : ~10-15€ ├─ Modération + support : ~5-10€ ├─ Développement + R&D : ~10-15€ └─ Marge opérationnelle : ~10-15€ ``` **Exemple concret** : - 10 000 écoutes/mois → créateur touche **30€** - 50 000 écoutes/mois → créateur touche **150€** - 100 000 écoutes/mois → créateur touche **300€** **Comparaison industrie** : - YouTube : 3-5€/1000 vues - Spotify : 3-4€/1000 écoutes - RoadWave : 3€/1000 écoutes (aligné) **Règles comptabilisation** : - ✅ Écoute complète = ≥80% du contenu écouté - ✅ Utilisateur gratuit uniquement - ❌ Écoutes Premium ne comptent pas ici (autre système) - ❌ Bots détectés exclus (rate limiting + analyse patterns) --- #### B) Abonnés Premium **Formule** : **70% au créateur, 30% à la plateforme** **Répartition proportionnelle au temps d'écoute effectif** : ``` Utilisateur Premium = 4.99€/mois ├─ 3.49€ reversés aux créateurs (70%) └─ 1.50€ gardés par plateforme (30%) Si l'utilisateur écoute 3 créateurs ce mois : - Créateur A : 10h d'écoute (50%) → 1.75€ - Créateur B : 6h d'écoute (30%) → 1.05€ - Créateur C : 4h d'écoute (20%) → 0.70€ ``` **Calcul technique** : ```sql -- Pour chaque utilisateur Premium SELECT creator_id, SUM(listen_duration_seconds) AS total_seconds, (SUM(listen_duration_seconds) / total_user_seconds) AS ratio, (4.99 * 0.70 * ratio) AS revenue_euros FROM premium_listens WHERE user_id = :user_id AND month = :current_month GROUP BY creator_id; ``` **Comparaison industrie** : - YouTube Premium : 70/30 - Spotify : 70/30 - Apple Music : 52/48 (moins avantageux) - RoadWave : 70/30 (standard) **Justification** : - **Standard industrie** : ratio équitable éprouvé - **Incitation qualité** : créateurs les plus écoutés gagnent plus - **Équité** : pas de "winner takes all", chaque créateur écouté reçoit sa part - **Marge plateforme** : 30% couvre absence revenus pub sur Premium --- ### 9.5 Paiement des créateurs **Seuil minimum** : 50€ - En dessous → solde reporté mois suivant - Évite frais bancaires sur micro-sommes - Standard industrie (YouTube/Twitch/Spotify = 50-100€) **Fréquence** : Mensuelle | Date | Action | |------|--------| | **Dernier jour du mois** (ex: 31 janvier) | Calcul revenus du mois via SQL | | **1-14 du mois suivant** | Traitement contestations/fraudes éventuelles | | **15 du mois suivant** (ex: 15 février) | Virement SEPA via Mangopay (Payout) | | **16-18 du mois suivant** | Réception virement (1-3 jours ouvrés SEPA) | **Virement via Mangopay** : - SEPA pour comptes EU (gratuit, 1-3 jours) - Virement international hors EU (frais variables selon pays, rare en pratique) - **E-wallets automatiques** : chaque créateur possède un wallet Mangopay où ses revenus sont transférés automatiquement **Tableau de bord créateur** (temps réel) : | Métrique | Description | Mise à jour | |----------|-------------|-------------| | **Revenus pub** | Écoutes × CPM | Temps réel | | **Revenus premium** | Abonnés actifs × ratio écoute | Temps réel | | **Solde disponible** | Total revenus mois en cours | Temps réel | | **Solde en attente** | Revenus mois précédent (paiement le 15) | Figé fin de mois | | **Historique virements** | Liste des paiements reçus | Permanent | | **Export comptable CSV** | Données pour expert-comptable | Téléchargement | **Gestion échecs virement** : 1. Tentative 1 (15 du mois) → échec 2. Retry automatique J+3 3. Retry automatique J+7 4. Si 3 échecs → suspension monétisation + email créateur (RIB invalide) --- ### 9.6 Contenus Premium exclusifs **Décision** : Créateur décide individuellement pour chaque contenu **Fonctionnement** : - Toggle "Réservé Premium" lors création/édition contenu - **Aucune limite imposée** : créateur peut mettre 0%, 50% ou 100% en premium - Badge 👑 visible sur interface utilisateur **Comportement utilisateurs gratuits** : - Contenu premium visible dans liste/algo - Tentative lecture → overlay bloquant - Message : "Ce contenu est réservé aux abonnés Premium" - CTA : "Passez Premium pour 4.99€/mois" **Comportement algorithme** : - Contenus premium inclus dans recommandations - Si user gratuit → contenu skippé automatiquement (ne consomme pas de slot) - Si user premium → diffusé normalement **Métadonnées** : - Champ `is_premium` (boolean) en base - Index sur ce champ pour requêtes rapides - Cache Redis : `content:{id}:premium` (TTL 1h) **Justification** : - **Liberté créateur** : chaque créateur choisit sa stratégie (freemium, tout gratuit, tout premium) - **Incitation Premium** : contenu exclusif = argument fort pour s'abonner - **Équité** : un petit créateur peut tout mettre en premium, un gros peut tout offrir gratuitement --- ### 9.7 Obligations fiscales **RoadWave génère automatiquement** : | Document | Fréquence | Destinataire | Base légale | |----------|-----------|--------------|-------------| | **Relevé mensuel PDF** | Chaque mois | Créateur | Transparence | | **Export CSV comptable** | À la demande | Créateur + expert-comptable | Facilitation déclarations | | **DAS2 annuel** | Si >1200€/an | Impôts (DGFIP) | Obligation légale France | **Créateur responsable de** : - Déclarer ses revenus à l'URSSAF (cotisations sociales auto-entrepreneur ou IS/IR) - Déclarer ses revenus aux impôts (IR ou IS selon statut) - Gérer sa TVA si applicable (franchise en base jusqu'à ~37K€/an en micro-BNC) - Conserver justificatifs **10 ans** (obligation légale comptable) **Mangopay transmet automatiquement** : - Données aux autorités fiscales EU via **DAC7** (directive 2021/514) - Justificatif de chaque virement (preuve bancaire pour comptabilité créateur) **Exemple DAS2** : ``` Si créateur a touché 2500€ en 2026 : → RoadWave envoie DAS2 aux impôts en janvier 2027 → Créateur reçoit copie par email → Créateur doit déclarer ces 2500€ dans sa déclaration annuelle ``` **Justification** : - **Conformité légale** : RoadWave doit déclarer revenus versés (DAS2, DAC7) - **Responsabilité fiscale** : Le créateur reste responsable de sa déclaration (impossible de gérer pour lui) - **Automatisation** : Minimise charge administrative côtés créateur et plateforme --- ### 9.8 Désactivation et suspension monétisation **Créateur peut** : - Désactiver temporairement (vacances, pause création) - Réactiver sans refaire KYC si données à jour (<2 ans) - Solde conservé pendant désactivation **Plateforme suspend automatiquement si** : | Motif | Action | Réversible | |-------|--------|------------| | **Strike 3+ actif** | Suspension immédiate | Oui, après résolution strikes | | **Compte bancaire invalide** | Suspension après 3 échecs virement | Oui, après mise à jour RIB | | **Documents KYC expirés** | Suspension avec préavis 30j | Oui, après renouvellement docs | | **Fraude détectée** | Suspension immédiate + enquête | Cas par cas | **Suppression définitive si** : - Demande du créateur (solde versé sous 30 jours) - Inactivité 24 mois + solde <50€ (purge RGPD) - Ban définitif compte (Strike 4) **Notification** : - Email + in-app pour toute suspension - Raison explicite fournie - Procédure de réactivation indiquée **Justification** : - **Flexibilité** : créateur peut faire pause sans perdre statut - **Sécurité** : plateforme doit pouvoir suspendre en cas problème légal/technique - **RGPD** : suppression auto données inactives après délai raisonnable --- ## Récapitulatif Section 9
## 10. Premium ### 10.1 Offre et tarification **Décision** : Deux formules sans essai gratuit | Formule | Prix | Économie | Prix effectif | |---------|------|----------|---------------| | **Mensuel** | 4.99€/mois | - | 4.99€/mois | | **Annuel** | 49.99€/an | 2 mois offerts | 4.16€/mois | **❌ Pas d'essai gratuit** **Raisons** : - **Anti-abus vacances** : évite inscriptions opportunistes (essai 14j avant road trip vacances, puis annulation) - **Protection revenus créateurs** : les écoutes Premium rémunèrent créateurs dès jour 1 - **Simplicité** : pas de gestion période trial + conversion - **Engagement** : utilisateur qui paie dès début = plus engagé **❌ Pas de partage familial (MVP)** **Raisons** : - Complexité technique (gestion invitations, validation liens, limite devices) - Risque abus ("familles" de 6 inconnus) - Coût dev/support élevé pour ROI incertain - La plupart des users RoadWave sont individuels (conducteurs) - **Post-MVP** : Si forte demande, offre "Famille" à 9.99€/mois pour 5 comptes **Justification tarif** : - **Aligné marché bas** : Spotify = 10.99€, YouTube Premium = 11.99€, Apple Music = 10.99€ - **Prix accessible** : cible conducteurs quotidiens (budget raisonnable) - **Incitation annuel** : 2 mois offerts = engagement long terme + réduction churn --- ### 10.2 Multi-devices et détection simultanée **Décision** : 1 seul stream actif par compte à tout moment **Détection connexion simultanée** : ``` User A écoute sur iPhone → User A lance sur iPad → Détection : session active iPhone existe → Action : Arrêt lecture iPhone (WebSocket close) → Message iPhone : "Lecture interrompue : votre compte est utilisé sur un autre appareil" → Lecture démarre iPad ``` **Implémentation technique** : ``` Redis : active_streams:{user_id} → {device_id, started_at} TTL : 5 minutes (refresh à chaque heartbeat) Heartbeat toutes les 30s depuis app : → Si autre device détecté : kill session actuelle → Si pas de heartbeat pendant 5 min : considérer session morte ``` **Exceptions** : - Contenus téléchargés (offline) ne comptent pas comme stream actif - Transition rapide device (<10s) tolérée (changement voiture → maison) **Justification** : - **Anti-partage compte** : empêche 2 personnes d'utiliser même compte Premium - **Protection revenus créateurs** : 1 abonnement = 1 personne = 1 écoute - **UX claire** : message explicite, pas de coupure brutale --- ### 10.3 Contenus exclusifs Premium **Décision** : Créateur décide (déjà couvert section 9.6) **Rappel règles** : - Toggle "Réservé Premium" par contenu - Aucune limite de ratio gratuit/premium - Badge 👑 visible - Users gratuits : lecture bloquée avec CTA "Passez Premium" **Impact algorithme** : - Contenus premium inclus dans recommandations - Si user gratuit → skip automatique (ne consomme pas slot) - Si user premium → diffusé normalement selon score --- ### 10.4 Avantages Premium **Inclus dans l'abonnement** : | Avantage | Gratuit | Premium | |----------|---------|---------| | **Publicités** | 1/5 contenus | 0 (aucune) | | **Contenus exclusifs** | ❌ Bloqués | ✅ Accès complet | | **Qualité audio** | 48 kbps Opus | 64 kbps Opus | | **Mode offline** | 50 contenus max | Illimité | | **Historique écoute** | 100 derniers | Illimité | **Qualité audio** : - Gratuit : 48 kbps Opus (~20 MB/h) = très correct pour voix - Premium : 64 kbps Opus (~30 MB/h) = excellente qualité **Justification différences** : - **0 pub** = argument principal (confort écoute) - **Qualité audio** = avantage tangible audiophiles - **Offline illimité** = use case road trips longs - **Pas d'over-engineering** : pas de badges cosmétiques, fonctionnalités sociales, etc. (focus essentiel) --- ### 10.5 Gestion abonnement **Souscription** : | Canal | Prestataire | Prix | Commission | |-------|-------------|------|------------| | **Web (desktop/mobile)** | Mangopay | 4.99€ | 1.8% + 0.18€ = 0.27€ | | **iOS App** | Apple In-App Purchase | 5.99€ | 30% (Apple) | | **Android App** | Google Play Billing | 5.99€ | 30% (Google) | **Majoration mobile (5.99€)** : - Apple/Google prennent 30% de commission - RoadWave majore prix de 20% pour compenser - **Incitation web** : Email aux users "Abonnez-vous sur roadwave.com pour 4.99€/mois" (38% moins cher en frais !) **Renouvellement automatique** : - Email rappel **7 jours avant** renouvellement - Email confirmation **après** renouvellement réussi - Retry automatique si échec paiement (3 tentatives sur 7 jours) - Annulation automatique après 3 échecs **Annulation** : - Self-service dans Settings app : "Abonnement > Annuler" - Accès Premium maintenu jusqu'à **fin période payée** - Pas de remboursement prorata (standard industrie) - Email confirmation annulation avec date fin d'accès **Réabonnement** : - Possibilité immédiate - ❌ Pas de nouvelle période d'essai (pas d'essai du tout) **Architecture données** : ```sql CREATE TABLE subscriptions ( id UUID PRIMARY KEY, user_id UUID NOT NULL REFERENCES users(id) UNIQUE, mangopay_recurring_payin_id VARCHAR(255), -- Null si IAP mangopay_user_id VARCHAR(255), -- Null si IAP apple_transaction_id VARCHAR(255), -- Null si Mangopay google_purchase_token VARCHAR(255), -- Null si Mangopay status VARCHAR(50) NOT NULL, -- 'active', 'cancelled', 'expired', 'past_due' plan VARCHAR(50) NOT NULL, -- 'monthly', 'yearly' current_period_start TIMESTAMP NOT NULL, current_period_end TIMESTAMP NOT NULL, cancelled_at TIMESTAMP, created_at TIMESTAMP NOT NULL DEFAULT NOW() ); ``` **Vérification Premium en temps réel** : ``` Cache Redis : premium:{user_id} → boolean (TTL 1h) Refresh via webhooks : - Mangopay : PAYIN_NORMAL_SUCCEEDED, PAYIN_NORMAL_FAILED - Apple : App Store Server Notifications - Google : Real-time Developer Notifications ``` --- ## Récapitulatif Section 10
## 11. Mode offline ### 11.1 Téléchargement **Zone géographique** : Choix manuel utilisateur **Options prédéfinies** : - "Autour de moi" (rayon 50 km position actuelle) - "Ma ville" (limite administrative détectée) - "Mon département" (sélection liste) - "Ma région" (sélection liste) - Recherche manuelle : "Paris", "Lyon", "Marseille", etc. **Nombre de contenus téléchargeables** : | Statut | Limite | Affichage | |--------|--------|-----------| | **Gratuit** | 50 contenus max | "12/50 contenus téléchargés" | | **Premium** | Illimité | "245 contenus (3.2 GB)" | **Calcul temps disponible** : - 50 contenus × 5 min moyenne = 250 min = **4h d'écoute** (suffisant pour gratuits) - Premium illimité = limité uniquement par espace disque device **Connexion WiFi/Mobile** : **Par défaut** : WiFi uniquement **Sur données mobiles** : 1. User clique "Télécharger" 2. Détection : pas de WiFi 3. Popup : "Vous n'êtes pas connecté en WiFi. Télécharger via données mobiles consommera environ **X MB**. Continuer ?" 4. Boutons : "Attendre WiFi" / "Continuer" **Calcul estimation** : ``` Nombre contenus × durée moyenne × bitrate qualité Exemple : 20 contenus × 5 min × 48 kbps = ~72 MB ``` **Qualité audio téléchargement** : | Qualité | Bitrate | Taille | Disponibilité | |---------|---------|--------|---------------| | **Basse** | 24 kbps | ~10 MB/h | Gratuit + Premium | | **Standard** | 48 kbps | ~20 MB/h | Gratuit + Premium (défaut) | | **Haute** | 64 kbps | ~30 MB/h | **Premium uniquement** | **Justification** : - Standard = bon compromis qualité/taille (Opus 48 kbps = très correct pour voix) - Haute réservée Premium = incitation upgrade - User peut réduire à "basse" si espace limité --- ### 11.2 Validité et renouvellement **Durée de validité** : 30 jours après téléchargement **Standard industrie** : - Spotify : 30 jours - YouTube Music : 30 jours - Deezer : 30 jours **Renouvellement automatique** : ``` App détecte WiFi + contenus >25 jours → Requête API : GET /offline/contents/refresh → Backend vérifie pour chaque contenu : - Abonnement Premium toujours actif ? - Contenu pas modéré/supprimé ? - Métadonnées à jour ? → Renouvelle validité à 30 jours supplémentaires → Mise à jour métadonnées (titre, créateur, statut) → Pas de re-téléchargement audio (sauf si fichier corrompu) ``` **Notification avant expiration** : - **J-3** : "X contenus expirent dans 3 jours. Connectez-vous en WiFi pour les renouveler" - **J-0** : Suppression automatique - **J+0** : Toast "15 contenus expirés ont été supprimés" **Justification** : - **Force reconnexion** : vérifier abonnement actif, contenus légaux - **Évite stockage obsolète** : contenus supprimés/modérés ne restent pas - **UX transparente** : renouvellement silencieux si WiFi régulier --- ### 11.3 Synchronisation actions offline **Actions stockées localement (SQLite)** : - Likes/unlikes - Abonnements/désabonnements - Signalements - Progression audio-guides **Sync automatique à la reconnexion** : ``` 1. App détecte reconnexion Internet 2. Récupération queue locale : SELECT * FROM pending_actions ORDER BY created_at 3. Envoi batch API : POST /sync/actions 4. Backend traite chaque action 5. Confirmation réception : DELETE FROM pending_actions WHERE id IN (...) 6. Toast : "3 likes et 1 abonnement synchronisés" ``` **Gestion erreurs sync** : - Si échec après 3 tentatives → notification : "Impossible de synchroniser. Réessayez plus tard" - Actions conservées jusqu'à sync réussie (pas de perte) - **Rétention max 7 jours** : après = purge (évite queue infinie) **Conflits contenus supprimés** : ``` Backend retourne : {deleted_content_ids: [123, 456]} → App supprime fichiers locaux → Si contenu 123 en cours d'écoute : - Attendre fin lecture actuelle - Passage auto suivant après 2s → Toast : "1 contenu téléchargé a été retiré (violation règles)" ``` **Justification** : - **Pas de conflit possible** : actions unilatérales user (likes/abonnements) - **UX fluide** : pas de blocage offline - **Batch = économie** : requêtes HTTP groupées - **Conformité modération** : contenu illégal disparaît même offline --- ## Récapitulatif Section 11 | Aspect | Décision | Valeur | |--------|----------|--------| | **Zone téléchargement** | Choix | Manuel (autour/ville/département/région/recherche) | | **Limite gratuit** | Contenus | 50 max | | **Limite Premium** | Contenus | Illimité (espace disque) | | **Connexion** | Par défaut | WiFi (mobile avec confirmation) | | **Qualité Standard** | Bitrate | 48 kbps Opus | | **Qualité Haute** | Bitrate | 64 kbps (Premium uniquement) | | **Validité** | Durée | 30 jours | | **Renouvellement** | Mode | Automatique si WiFi | | **Notification expiration** | Délai | J-3 | | **Sync actions** | Mode | Batch automatique reconnexion | | **Rétention queue** | Durée | 7 jours max | ---
## 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_consents` avec versioning - Champs : user_id, consent_type, version, accepted, timestamp - Historique complet conservé (preuve légale) **Consentements requis** : - **Géolocalisation précise** : obligatoire (banner + permission OS) - **Analytics** : optionnel (Matomo) - **Notifications push** : optionnel (permission OS) **Justification** : - Opensource, 0€, conformité RGPD garantie - Historique backend = preuve légale en cas de contrôle - Granularité conforme recommandations CNIL --- ### 13.2 Anonymisation des données GPS **Décision** : Geohash après 24h **Processus** : 1. Données précises conservées **24h** (recommandation personnalisée) 2. Après 24h : conversion en geohash précision 5 (~5km²) 3. Coordonnées originales supprimées définitivement **Implémentation PostGIS** : ```sql -- Job quotidien UPDATE location_history SET location = ST_SetSRID(ST_GeomFromGeoHash(ST_GeoHash(location::geography, 5)), 4326)::geography, anonymized = true WHERE created_at < NOW() - INTERVAL '24 hours' AND anonymized = false; ``` **Exceptions** : - ✅ Historique personnel visible (liste trajets) : conservation intégrale tant que compte actif - ❌ Analytics globales : uniquement geohash anonyme **Justification** : - Vraie anonymisation RGPD (CNIL compliant) - Permet analytics agrégées (heatmaps trafic) - PostGIS natif, 0€ --- ### 13.3 Export des données (portabilité) **Décision** : JSON + HTML + ZIP, génération asynchrone **Contenu de l'export** : ``` export-roadwave-[user_id]-[date].zip ├── export.json # Machine-readable ├── index.html # Human-readable (stylé) ├── audio/ │ ├── content-123.opus │ ├── content-456.opus │ └── ... └── README.txt # Instructions ``` **Données exportées** : - Profil utilisateur (email, pseudo, date inscription, bio) - Historique d'écoute (titres, dates, durées) - Contenus créés (audio + métadonnées) - Abonnements et likes - Centres d'intérêt (jauges) - Historique consentements **Processus** : 1. Demande via paramètres compte 2. Génération asynchrone (worker background) 3. Email avec lien download (expire **7 jours**) 4. Délai : **48h maximum** (conformité RGPD) **Limite** : - Maximum **1 export/mois** (anti-abus) **Justification** : - Conformité article 20 RGPD (portabilité) - Double format (human + machine) - Worker asynchrone évite timeout --- ### 13.4 Suppression du compte **Décision** : Grace period 30j + anonymisation contenus **Processus** : 1. Utilisateur clique "Supprimer mon compte" 2. Compte désactivé immédiatement (login impossible) 3. Contenus cachés pendant 30 jours (non diffusés) 4. Email confirmation + lien annulation (valide 30j) 5. Après 30j sans annulation : suppression effective **Suppression effective** : - ✅ Compte utilisateur supprimé (données personnelles) - ✅ Historique d'écoute supprimé - ✅ GPS historique supprimé - ✅ Sessions et tokens révoqués - ⚠️ Contenus créés **anonymisés** (créateur = "Utilisateur supprimé") - ⚠️ Likes et abonnements supprimés (mais compteurs préservés) **Contenus conservés anonymement** : - Audio files (CDN) - Métadonnées (titre, description, tags, géolocalisation) - Statistiques d'écoute **Justification** : - Grace period évite suppressions impulsives - Anonymisation contenus = intérêt légitime communauté - Conforme RGPD si créateur = donnée supprimée --- ### 13.5 Mode dégradé (sans GPS précis) **Décision** : GeoIP par défaut, GPS optionnel **Niveaux de précision** : | Niveau | Technologie | Contenus accessibles | Consentement | |--------|-------------|---------------------|--------------| | **Pays** | Aucune géoloc | Contenus nationaux uniquement | ❌ Non requis | | **Ville** | GeoIP (MaxMind) | Contenus régionaux/ville | ❌ Non requis | | **Précis** | GPS | Tous contenus (hyperlocaux inclus) | ✅ Requis | **Implémentation** : - Démarrage app : GeoIP automatique (IP → ville) - Banner in-app : "Activez la géolocalisation pour découvrir du contenu près de chez vous" - Upgrade volontaire vers GPS **API GeoIP** : - MaxMind GeoLite2 (gratuit, self-hosted) - Update DB mensuelle automatique - Précision ~80% au niveau ville **Justification** : - RGPD : pas de consentement requis pour GeoIP (pas de donnée personnelle) - UX dégradée acceptable (contenus disponibles) - Progressive disclosure (upgrade optionnel) --- ### 13.6 Durée de conservation des données **Décision** : 5 ans inactivité → purge automatique **Règles** : | Type de compte | Seuil inactivité | Action | |----------------|------------------|--------| | **Auditeur uniquement** | 5 ans sans connexion | Suppression automatique | | **Créateur avec contenus actifs** | Jamais (tant qu'écoutes) | Conservation indéfinie | | **Créateur inactif** | 5 ans sans connexion + 2 ans sans écoute | Suppression automatique | **Notifications avant suppression** : - Email + push : **90 jours** avant - Email + push : **30 jours** avant - Email + push : **7 jours** avant - Toute connexion = reset compteur inactivité **Contenu conservé** : - Contenus créés par comptes supprimés (anonymisés) : conservation indéfinie **Justification** : - Conformité principe minimisation RGPD - 5 ans = équilibre raisonnable (standard industrie) - Exception créateurs actifs = intérêt légitime plateforme --- ### 13.7 Cookies et trackers web **Décision** : Matomo self-hosted, zéro cookie tiers **Cookies utilisés** : | Cookie | Type | Durée | Finalité | Consentement | |--------|------|-------|----------|--------------| | `session` | Technique | 30j | Authentification | ❌ Non requis | | `refresh_token` | Technique | 30j | Session persistante | ❌ Non requis | | `_pk_id` | Analytique | 13 mois | Matomo (IP anonyme) | ✅ Requis | **Analytics : Matomo self-hosted** : - Hébergé sur nos serveurs (Docker) - IP anonymisées automatiquement (2 derniers octets) - Pas de cookie si consentement refusé - Alternative : Plausible (SaaS EU, 9€/mois) **Trackers interdits** : - ❌ Google Analytics - ❌ Facebook Pixel - ❌ Hotjar, Mixpanel, etc. **Justification** : - Souveraineté données (pas de transfert US) - Conformité RGPD max (CNIL compatible) - Matomo = opensource, 0€ infra --- ### 13.8 Registre des traitements **Décision** : Document Markdown versionné Git (MVP) **Emplacement** : - `docs/rgpd/registre-traitements.md` - Versionné Git (historique modifications) **Contenu obligatoire par traitement** : - Nom et finalité du traitement - Catégories de données collectées - Base légale (consentement / contrat / intérêt légitime) - Durée de conservation - Destinataires (sous-traitants, CDN, etc.) - Transferts hors UE (aucun prévu) **Responsable** : - DPO / Fondateur - Review trimestrielle obligatoire - Update immédiate si nouveau traitement **Migration future** : - Si > 100K utilisateurs : interface admin PostgreSQL **Justification** : - Obligation RGPD Article 30 - Markdown = simple, versionné, auditable - 0€ --- ### 13.9 Notification violations de données (breach) **Décision** : Monitoring + alertes + runbook **Détection automatique** : | Événement | Outil | Alerte | |-----------|-------|--------| | Erreurs backend critiques | Sentry | Discord/Slack immédiat | | Pic requêtes anormal | Grafana | Email équipe | | Accès non autorisé DB | PostgreSQL logs | SMS fondateur | | Authentification suspecte | Zitadel alerts | Email équipe | **Procédure breach** : - Runbook : `docs/rgpd/procedure-breach.md` - Checklist 72h CNIL : 1. H+0 : Détection et confinement 2. H+24 : Évaluation gravité (données concernées, utilisateurs impactés) 3. H+48 : Notification CNIL si risque pour utilisateurs 4. H+72 : Notification utilisateurs si risque élevé **Contact CNIL** : - Email pré-rédigé (template) - Formulaire en ligne (account CNIL créé) **Justification** : - Obligation RGPD Article 33 (notification 72h) - Monitoring proactif évite découverte tardive - Sentry gratuit < 5K events/mois --- ### 13.10 DPO (Délégué à la Protection des Données) **Décision** : Fondateur = DPO temporaire (MVP) **Raison légale** : - Non obligatoire si : - < 250 employés - Pas de traitement à grande échelle de données sensibles - RoadWave : données localisation = sensible MAIS échelle MVP **Formation** : - CNIL : formation gratuite en ligne (4h) - Certification CNIL "Atelier RGPD" (gratuit) **Contact** : - Email : dpo@roadwave.fr - Publié dans CGU et mentions légales - Délai réponse : **1 mois** (RGPD) **Migration future** : - Si > 100K utilisateurs : DPO externe mutualisé (~200€/mois) - Ou recrutement DPO interne si > 10 employés **Justification** : - Conforme RGPD (non obligatoire en phase MVP) - 0€, contrôle total - Bonne pratique : avoir un contact identifié --- ## Récapitulatif Section 13 | Mesure | Implémentation | Coût | |--------|----------------|------| | **Consentement** | Tarteaucitron.js + PostgreSQL | 0€ | | **Anonymisation GPS** | Geohash PostGIS (24h) | 0€ | | **Export données** | JSON+HTML+ZIP asynchrone | 0€ | | **Suppression compte** | Grace period 30j + anonymisation | 0€ | | **Mode dégradé** | GeoIP MaxMind + GPS optionnel | 0€ | | **Conservation** | Purge auto 5 ans inactivité | 0€ | | **Analytics** | Matomo self-hosted | ~5€/mois | | **Registre traitements** | Markdown Git | 0€ | | **Breach detection** | Sentry + Grafana + runbook | 0€ | | **DPO** | Fondateur formé CNIL | 0€ | **Coût total RGPD : ~5€/mois** --- ## Points d'attention pour Gherkin - Tester consentement géolocalisation (accept/refuse → contenus différents) - Tester anonymisation GPS après 24h (job cron) - Tester export données (génération complète + vérification contenu) - Tester grace period suppression (annulation possible) - Tester mode GeoIP (ville détectée correctement) - Tester purge automatique (5 ans inactivité) - Tester notifications avant purge (90j/30j/7j)
## 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** : 1. Signalement reçu → ajout file d'attente asynchrone 2. Transcription audio (1-10 minutes selon durée) 3. Analyse automatique : - Score de confiance : 0-100% - Catégorie détectée - Timestamps des passages problématiques 4. Priorisation automatique selon score **Délais** : - Audio <5 min : 1-3 minutes - Audio 5-30 min : 3-10 minutes - Audio >30 min : 10-20 minutes **Coût** : - **MVP** : 0€ (CPU standard, processing asynchrone) - **Scale** : 50-200€/mois (GPU VPS si >1000 signalements/jour) **Justification** : - 100% open source, pas de dépendance GAFAM - Coût maîtrisé (scaling progressif) - Gain productivité modérateurs ×3-5 --- #### 14.2.2 Délais de traitement (SLA) **Décision** : SLA progressif selon priorité | Priorité | Délai cible | Traitement | |----------|-------------|------------| | **CRITIQUE** | <2h (24/7) | Violence, suicide, mise en danger → Astreinte modérateur senior | | **HAUTE** | <24h (jours ouvrés) | Haine, harcèlement, désinformation → Modérateur junior/senior | | **MOYENNE** | <24h (jours ouvrés) | Spam, contenu inapproprié → Modérateur junior | | **BASSE** | <72h (jours ouvrés) | Qualité audio, tags incorrects → Modérateur junior | **Traitement automatique** : - Score IA >95% + catégorie évidente (ex: spam répété) → Action automatique immédiate - Notification créateur + possibilité d'appel **Justification** : - Réaliste et conforme DSA (Digital Services Act) - Scalable : priorisation automatique - Ressources humaines optimisées --- #### 14.2.3 Priorisation automatique **Décision** : File d'attente intelligente basée sur score IA **Calcul de priorité** : ``` Priorité = (Score_IA × 0.7) + (Signalements_cumulés × 0.2) + (Fiabilité_signaleur × 0.1) ``` **Détails** : - **Score_IA** : 0-100% (confiance analyse automatique) - **Signalements_cumulés** : nombre de signalements du même contenu (boost priorité) - **Fiabilité_signaleur** : score utilisateur (historique signalements pertinents) **Classification résultante** : - Priorité ≥90 → **CRITIQUE** (traitement immédiat) - Priorité 70-89 → **HAUTE** (file prioritaire) - Priorité 40-69 → **MOYENNE** (file normale) - Priorité <40 → **BASSE** (file différée) **Justification** : - Optimise le temps des modérateurs - Traite les cas graves en priorité - Coût : 0€ (algorithme simple) --- ### 14.3 Sanctions #### 14.3.1 Notification au créateur **Décision** : Multi-canal (email + push + in-app) **Canaux utilisés** : | Canal | Timing | Contenu | |-------|--------|---------| | **Push notification** | Immédiat | Alerte courte : "Votre contenu a été modéré" | | **In-app** | Au prochain lancement | Popup détaillée avec bouton "Voir détails" | | **Email** | Dans l'heure | Notification complète avec lien vers formulaire d'appel | **Contenu email** : ``` Objet : Modération de votre contenu "[Titre du contenu]" Bonjour [Pseudo], Votre contenu "[Titre]" publié le [Date] a été modéré. Catégorie violée : [Catégorie] Raison : [Explication détaillée] Sanction : [Strike X / Suspension X jours / Suppression contenu] Extrait audio concerné : [Timestamp] Transcription : "[Passage problématique surligné]" Vous pouvez contester cette décision sous 7 jours : [Lien formulaire d'appel] L'équipe RoadWave ``` **Coût** : - Email : ~0.001€/notification (Brevo, Resend) - Push : 0€ (Firebase Cloud Messaging / APNs) - In-app : 0€ **Justification** : - Conformité DSA (transparence obligatoire) - Multi-canal garantit réception - Coût négligeable --- #### 14.3.2 Détail de la sanction **Décision** : Notification complète avec preuves **Éléments inclus obligatoirement** : 1. **Catégorie violée** : référence précise CGU (ex: "Article 3.2 - Haine & violence") 2. **Raison détaillée** : explication en langage clair (non juridique) 3. **Extrait audio** : timestamp exact du passage problématique (ex: "3:42-4:15") 4. **Transcription** : texte problématique surligné en rouge 5. **Gravité** : Strike actuel + conséquences (ex: "Strike 2/4 - Suspension 7 jours") 6. **Recours** : lien direct vers formulaire d'appel + délai (7 jours) **Exemple visuel in-app** : ``` ┌─────────────────────────────────────┐ │ ⚠️ Contenu modéré │ ├─────────────────────────────────────┤ │ Titre : "Mon podcast #42" │ │ Publié le : 15/01/2026 │ │ │ │ Catégorie violée : │ │ 🚫 Haine & violence (Article 3.2) │ │ │ │ Passage problématique : 3:42-4:15 │ │ "[Transcription surlignée]" │ │ │ │ Sanction : Strike 2/4 │ │ Suspension : 7 jours │ │ │ │ [Contester cette décision] │ └─────────────────────────────────────┘ ``` **Justification** : - Transparence maximale (obligation DSA) - Créateur comprend l'erreur → amélioration future - Réduit les appels non fondés --- #### 14.3.3 Processus d'appel **Décision** : Formulaire in-app structuré **Accès** : - Bouton "Contester cette décision" dans notification - Section "Mes sanctions" dans profil créateur **Formulaire d'appel** : | Champ | Type | Obligatoire | |-------|------|-------------| | **Sanction contestée** | Pré-rempli (non modifiable) | ✅ | | **Raison de l'appel** | Texte libre (50-1000 caractères) | ✅ | | **Arguments** | Zone texte enrichie | ✅ | | **Preuves** | Upload fichiers (max 5, 10 MB total) | ❌ | **Après soumission** : - Génération numéro de ticket unique (ex: `#MOD-2026-00142`) - Email confirmation : "Votre appel sera traité sous 72h" - Statut visible dans l'app : "En cours d'examen" **Délai de soumission** : - Maximum **7 jours** après notification de sanction - Après 7 jours : appel automatiquement refusé **Justification** : - Professionnel et traçable - Intégration complète avec système modération - Coût : 0€ (formulaire custom backend) --- #### 14.3.4 Délai de réponse pour appel **Décision** : SLA 72h garanti **Délais** : | Type d'appel | Délai | Responsable | |--------------|-------|-------------| | **Standard** | 72h max (3 jours ouvrés) | Modérateur senior | | **Complexe** | 5 jours ouvrés + notification intermédiaire J+3 | Modérateur senior + Admin modération | | **Critique** | 24h (cas suspension longue/ban) | Admin modération | **Notification intermédiaire** (si délai >72h) : - Email J+3 : "Votre appel #MOD-XXX est en cours d'examen approfondi. Réponse sous 2 jours." **Réponse finale** : Email détaillé avec : 1. **Décision** : Maintien / Annulation / Réduction de sanction 2. **Justification** : explication de la décision d'appel 3. **Actions** : Strike retiré / Suspension annulée / Contenu rétabli (si applicable) 4. **Définitif** : mention "Cette décision est définitive" (pas de second appel) **Suivi in-app** : - Mise à jour statut : "Appel accepté ✓" ou "Appel rejeté ✗" - Badge notification **Justification** : - Équilibre entre rapidité et qualité de traitement - Conforme pratiques industrie (YouTube, TikTok : 5-7 jours) - Ressources humaines réalistes --- ### 14.4 Outils modérateurs **Stack technique complète** : | Outil | Technologie | Fonction | |-------|-------------|----------| | **Dashboard** | React + TanStack Table | Interface modération | | **File signalements** | PostgreSQL + Redis | Priorisation temps réel | | **Player audio** | Wavesurfer.js | Lecture avec waveform + annotations | | **Transcription** | Whisper large-v3 | Conversion audio → texte | | **Historique créateur** | Vue 360° | Contenus, strikes, appels, métriques | | **Actions rapides** | Shortcuts clavier | Approuver (A), Rejeter (R), Escalade (E) | | **Logs audit** | PostgreSQL + export | Traçabilité complète (DSA) | | **Collaboration** | Système de commentaires | Modérateurs peuvent s'entraider sur cas complexes | **Fonctionnalités clés** : 1. **Lecture accélérée** : 0.75x à 2x (gain productivité) 2. **Marqueurs temporels** : annotation directe sur waveform 3. **Historique créateur** : vue rapide contenus précédents + strikes 4. **Statistiques** : signalements traités/jour, temps moyen, précision 5. **Fil d'activité** : actions récentes équipe (temps réel) **Coût infrastructure** : - MVP : 0-50€/mois (serveur CPU) - Scale : 50-200€/mois (GPU + Redis Cluster) --- ### 14.5 Modération préventive (rappel) **Nouveaux créateurs** : - Validation manuelle des **3 premiers contenus** - Délai : 24-48h (jours ouvrés) - Transcription automatique pour aide modérateur **Score de confiance** : - Évolution dynamique selon historique - Créateur fiable (0 strike depuis 6 mois) → validation automatique - Créateur suspect (strikes récents) → validation manuelle systématique **Publicités** : - Validation manuelle obligatoire 24-48h (responsabilité juridique) - Transcription + analyse métadonnées (ciblage, durée, volume) **Justification** : - Prévention > réaction (économie modération) - Qualité plateforme préservée dès le début --- ## Récapitulatif Section 14 | Point | Décision | Coût | |-------|----------|------| | **Catégories signalement** | 7 catégories prédéfinies + champ libre | 0€ | | **Commentaire signaleur** | Optionnel avec incitation | 0€ | | **Confirmation** | Toast in-app + historique personnel | 0€ | | **IA pré-filtre** | Whisper (CPU MVP, GPU scale) + NLP open source | 0-200€/mois | | **Délais traitement** | SLA progressif : 2h/24h/72h selon priorité | Dépend équipe | | **Priorisation** | File intelligente basée score IA | 0€ | | **Notification sanction** | Email + push + in-app (multi-canal) | ~0.001€/notif | | **Détail sanction** | Complet : raison + extrait + transcription | 0€ | | **Processus appel** | Formulaire in-app structuré | 0€ | | **Délai appel** | 72h garanti (standard) | Dépend équipe | | **Outils modérateurs** | Dashboard React + Whisper + Wavesurfer.js | 0-200€/mois | **Coût total MVP** : **0-200€/mois** (infrastructure IA optionnelle) **Conformité** : - ✅ DSA (Digital Services Act) : transparence, traçabilité, délais - ✅ RGPD : données modération anonymisées après 3 ans - ✅ Logs audit : toutes actions tracées (obligation légale plateforme) **Scalabilité** : - 0-1000 signalements/mois : équipe 1-2 modérateurs junior + 1 senior - 1000-10K signalements/mois : équipe 5-10 modérateurs + IA GPU - 10K+ signalements/mois : équipe dédiée + IA optimisée + modération communautaire --- **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 - WhatsApp - Email - SMS - Plus... (sheet natif OS) **Justification** : - Viralité = croissance organique gratuite - Aucune friction, partage universel --- #### 15.1.2 Comportement du lien partagé **Format URL** : `https://roadwave.fr/share/c/[content_id]` **Comportement multi-plateforme** : ``` User clique lien partagé ↓ Page web responsive ↓ ┌─────────────────────────────────┐ │ Si app installée │ │ → Deep link (ouverture directe) │ └─────────────────────────────────┘ ↓ ┌─────────────────────────────────┐ │ Si app non installée │ │ → Web player + CTA téléchargement│ └─────────────────────────────────┘ ``` **Contenu de la page web** : ```html ┌───────────────────────────────────────┐ │ RoadWave │ ├───────────────────────────────────────┤ │ [Image cover 16:9] │ │ │ │ 📻 Titre du contenu │ │ Par @créateur · 12 min · 🎧 2.3K │ │ │ │ 📍 Paris 5e · Ancré │ │ 🏷️ #Voyage #Histoire │ │ │ │ Description : Lorem ipsum... │ │ │ │ [▶️ Écouter maintenant] │ │ (Player HTML5 si contenu public) │ │ │ │ ────────────────────────────────── │ │ │ │ 📱 Télécharger l'app RoadWave │ │ [App Store] [Google Play] │ │ │ │ [Voir le profil de @créateur] │ └───────────────────────────────────────┘ ``` **Métadonnées Open Graph (SEO)** : ```html ``` **Deep linking** : - iOS : Universal Links (configuration `apple-app-site-association`) - Android : App Links (configuration `assetlinks.json`) - URL scheme : `roadwave://content/[content_id]` **Justification** : - Meilleure viralité (partage social optimisé) - SEO (contenus indexés Google) - UX optimale (web + app) - Coût : 0€ (backend simple + CDN existant) --- #### 15.1.3 Contenus Premium partagés **Décision** : Preview 30 secondes + paywall **Comportement** : 1. User clique lien contenu Premium partagé 2. Page web affiche badge "👑 Contenu Premium" 3. Player démarre automatiquement 4. Après **30 secondes exactement** : - Fade out audio (2 secondes) - Overlay apparaît : ``` ┌─────────────────────────────────┐ │ 👑 Contenu réservé Premium │ │ │ │ Profitez de ce contenu complet │ │ et de milliers d'autres │ │ sans publicité │ │ │ │ [Passer Premium - 4.99€/mois] │ │ [Télécharger l'app] │ └─────────────────────────────────┘ ``` 5. Utilisateur peut : - S'abonner Premium (redirection web Mangopay) - Télécharger l'app (redirection stores) - Rejouer les 30 premières secondes (illimité) **Tracking** : - Métriques créateur : "Partages Premium" + "Conversions Premium" - Créateur touche sa part si conversion (70%) **Justification** : - Équilibre viralité / monétisation - 30s = assez pour donner envie, pas assez pour satisfaire - Protège revenus créateurs --- ### 15.2 Profil créateur **Décision** : Profil public complet et transparent #### 15.2.1 Structure de la page profil **URL** : `https://roadwave.fr/@[pseudo]` **Layout** : ``` ┌────────────────────────────────────────┐ │ [Photo profil 120×120] │ │ @pseudo ✓ │ │ [Badge vérifié si applicable] │ │ │ │ Bio : Lorem ipsum dolor sit amet... │ │ (300 caractères max) │ │ │ │ 🎧 1.2K abonnés │ │ 📻 42 contenus │ │ ⏱️ 18h de contenu créé │ │ 🔊 54K écoutes totales │ │ │ │ [S'abonner] [Partager profil] [•••] │ │ │ │ ──────────────────────────────────── │ │ │ │ Contenus ▼ [Plus récents ▼] │ │ │ │ ┌──────────────────────────────────┐ │ │ │ [Cover] Titre contenu 1 │ │ │ │ 12 min · 🎧 2.3K · 📍 Paris │ │ │ │ [▶️] │ │ │ └──────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────┐ │ │ │ [Cover] Titre contenu 2 │ │ │ │ 8 min · 🎧 5.1K · 📍 Lyon │ │ │ │ [▶️] │ │ │ └──────────────────────────────────┘ │ │ │ │ [Charger plus] │ └────────────────────────────────────────┘ ``` **Informations affichées** : | Élément | Visibilité | Détails | |---------|------------|---------| | **Photo + pseudo** | ✅ Public | Identité visuelle | | **Badge vérifié ✓** | ✅ Public (si applicable) | Compte authentique | | **Bio** | ✅ Public | 0-300 caractères, markdown basique (gras, italique, liens) | | **Nombre abonnés** | ✅ Public | Arrondi si >1000 (ex: 1.2K, 54K) | | **Nombre contenus** | ✅ Public | Exact | | **Durée totale créée** | ✅ Public | Arrondi en heures (ex: 18h, 142h) | | **Écoutes totales** | ✅ Public | Arrondi (ex: 54K, 1.2M) | | **Liste abonnés** | ❌ Privé | Protection vie privée (RGPD) | | **Revenus** | ❌ Privé | Confidentialité financière | | **Localisation précise** | ❌ Privé | Sécurité | | **Email** | ❌ Privé | Anti-spam | **Tri des contenus** : | Option | Comportement | |--------|--------------| | **Plus récents** | Date publication DESC (défaut) | | **Plus populaires** | Écoutes complètes × (1 + (date_publication - now) / 90 jours) | | **Plus anciens** | Date publication ASC | | **Par tag** | Filtre multi-sélection tags | **Recherche locale** : - Barre recherche dans profil : "Rechercher dans les contenus de @pseudo" - Recherche full-text sur titres + descriptions **Actions menu [•••]** : - Partager profil - Signaler profil (spam, usurpation) - Bloquer créateur (masque tous ses contenus) --- #### 15.2.2 Statistiques publiques **Décision** : Stats arrondies et motivantes **Affichage public** : | Métrique | Format affichage | Exemple | |----------|------------------|---------| | **Abonnés** | Exact si <1000, arrondi sinon | 342 / 1.2K / 54K / 1.2M | | **Écoutes totales** | Arrondi dès 1000 | 842 / 5.4K / 142K / 2.1M | | **Contenus publiés** | Exact | 42 contenus | | **Durée totale** | Arrondi en heures | 18h / 142h de contenu | **Métriques PRIVÉES (créateur uniquement)** : | Métrique | Disponible dans dashboard créateur | |----------|-------------------------------------| | **Taux complétion moyen** | 78% (écoutes >80% / écoutes totales) | | **Évolution abonnés** | Graphique 30j / 90j / 1 an | | **Écoutes par contenu** | Tableau détaillé | | **Revenus** | Dashboard monétisation dédié | | **Taux conversion Premium** | Partages → conversions | | **Démographie** | Âge / zone géo (agrégée, anonymisée) | **Justification** : - Arrondi = évite comparaisons anxiogènes - Preuve sociale pour nouveaux auditeurs (trust) - Gamification douce (motivation créateurs) - Privacy by design --- #### 15.2.3 Badge vérifié **Décision** : Badge unique ✓ (vérifié officiel) **Critères d'attribution** (au moins UN des critères) : 1. **KYC monétisation validé** : identité vérifiée via Mangopay KYC 2. **Célébrité / Média officiel** : validation manuelle équipe RoadWave 3. **Communauté significative** : ≥10K abonnés + compte actif >6 mois **Affichage** : - Badge bleu **✓** accolé au pseudo (partout : profil, player, recherche) - Tooltip au survol/appui long : "Compte vérifié" **Processus d'obtention** : | Type | Processus | |------|-----------| | **Automatique (KYC)** | Badge attribué dès validation documents Mangopay | | **Manuel (célébrité)** | Formulaire demande → équipe vérifie identité → validation 48-72h | | **Automatique (10K)** | Badge attribué automatiquement à 10K abonnés si compte >6 mois | **Retrait du badge** : - Suspension monétisation → badge retiré temporairement - Strikes multiples → badge retiré définitivement - Usurpation identité détectée → ban + retrait **Justification** : - Combat usurpations d'identité - Trust auditeurs (surtout pour médias/personnalités) - Simplicité (1 seul badge, pas de gamification excessive) - Coût : 0€ (champ boolean `verified` en DB) --- ### 15.3 Recherche **Décision** : Recherche full-text + géo + filtres avancés #### 15.3.1 Recherche par mot-clé **Implémentation** : PostgreSQL full-text search (français) **Configuration technique** : ```sql -- Index full-text optimisé français CREATE INDEX idx_content_search ON contents USING GIN( to_tsvector('french', coalesce(title, '') || ' ' || coalesce(description, '') || ' ' || coalesce(creator_pseudo, '') ) ); -- Recherche avec ranking SELECT c.*, ts_rank( to_tsvector('french', c.title || ' ' || c.description), plainto_tsquery('french', $search_query) ) AS rank FROM contents c WHERE to_tsvector('french', c.title || ' ' || c.description) @@ plainto_tsquery('french', $search_query) ORDER BY rank DESC, listen_count DESC LIMIT 20; ``` **Champs indexés** : - Titre du contenu (poids × 3) - Description (poids × 1) - Pseudo créateur (poids × 2) - Tags (poids × 1.5) **Fonctionnalités** : | Feature | Description | |---------|-------------| | **Stemming français** | "voyages" trouve "voyage", "voyager", etc. | | **Correction auto** | Suggestion si 0 résultat | | **Recherches populaires** | "Essayez plutôt : balade paris, audio-guide louvre" | | **Historique personnel** | 10 dernières recherches sauvegardées | | **Autocomplete** | Suggestions pendant frappe (top 5) | **Coût** : 0€ (PostgreSQL natif) **Migration future** : - Si >100K contenus : Meilisearch (typo-tolerance avancée, ~20-50€/mois) - Si >1M contenus : Elasticsearch cluster **Justification** : - PostgreSQL full-text = performant jusqu'à 500K contenus - Stemming français natif - 0€, aucune dépendance externe --- #### 15.3.2 Recherche géographique **Décision** : Recherche lieu + rayon paramétrable **Interface utilisateur** : ``` ┌─────────────────────────────────────┐ │ 🔍 Recherche contenu... │ ├─────────────────────────────────────┤ │ �� Lieu │ │ [Paris, France ▼] │ │ · Autour de moi (GPS actuel) │ │ · Entrer une adresse/ville │ │ │ │ 📏 Rayon de recherche │ │ [●─────────────────] 50 km │ │ (curseur 5 km → 500 km) │ │ │ │ 🗺️ [Afficher sur carte] │ └─────────────────────────────────────┘ ``` **Géocodage** : | Service | Usage | Coût | |---------|-------|------| | **Nominatim (OSM)** | MVP (API publique) | 0€ (rate limit 1 req/s) | | **Nominatim self-hosted** | Scale (Docker) | 20-50€/mois VPS | | **Mapbox Geocoding** | Fallback premium | 0.50€ / 1000 requêtes | **Processus de recherche géo** : 1. User tape "Louvre" ou "Paris" 2. Autocomplete via Nominatim → liste suggestions 3. User sélectionne → récupération coordonnées (lat, lon) 4. Requête PostGIS : ```sql SELECT c.*, ST_Distance(c.location::geography, ST_Point($lon, $lat)::geography) AS distance FROM contents c WHERE ST_DWithin( c.location::geography, ST_Point($lon, $lat)::geography, $radius_meters ) ORDER BY distance ASC; ``` **Affichage résultats** : - Tri par défaut : distance croissante - Indication distance : "À 2.3 km" / "À 15 km" / "À 142 km" - Option carte : markers cliquables (clustering si >50 résultats) **Coût** : - MVP : 0€ (Nominatim public) - Scale : 20-50€/mois (Nominatim self-hosted Docker) **Justification** : - Essentiel pour tourisme / planification trajet - OpenStreetMap = pas de dépendance Google - PostGIS = performant (index GIST natif) --- #### 15.3.3 Filtres avancés **Décision** : 7 catégories de filtres combinables **Interface filtres** : ``` ┌─────────────────────────────────────┐ │ Filtres [×] │ ├─────────────────────────────────────┤ │ Type de contenu │ │ ☐ Contenu court (<5 min) │ │ ☐ Podcast (>5 min) │ │ ☐ Radio live │ │ ☐ Audio-guide │ │ │ │ Durée │ │ ○ Toutes durées │ │ ○ <5 min │ │ ○ 5-15 min │ │ ○ 15-30 min │ │ ○ >30 min │ │ │ │ Classification âge │ │ ☐ Tout public │ │ ☐ 13+ │ │ ☐ 16+ │ │ ☐ 18+ │ │ │ │ Géo-pertinence │ │ ☐ Ancré (lieu précis) │ │ ☐ Contextuel (zone large) │ │ ☐ Neutre (national) │ │ │ │ Tags (multi-sélection) │ │ ☐ Automobile ☐ Voyage │ │ ☐ Famille ☐ Histoire │ │ ☐ Économie ☐ Sciences │ │ ... (liste complète tags) │ │ │ │ Date de publication │ │ ○ Toutes dates │ │ ○ Dernières 24h │ │ ○ Cette semaine │ │ ○ Ce mois │ │ ○ Cette année │ │ │ │ Abonnement │ │ ○ Tous les contenus │ │ ○ Gratuits uniquement │ │ ○ Premium uniquement 👑 │ │ │ │ ────────────────────────────── │ │ [Réinitialiser] [Appliquer] │ └─────────────────────────────────────┘ ``` **Options de tri** : | Tri | Algorithme | |-----|-----------| | **Pertinence** | Score recherche × (1 + log(listen_count + 1)) | | **Popularité** | Écoutes complètes derniers 30j DESC | | **Récent** | Date publication DESC | | **Proximité** | Distance GPS ASC (si recherche géo active) | | **Durée** | Durée audio ASC ou DESC | **Sauvegarde de recherches** : - Bouton "💾 Sauvegarder cette recherche" - Nom personnalisable : "Podcasts voyage Paris" - Maximum **5 recherches sauvegardées** - Accès rapide : onglet "Recherches sauvegardées" dans page recherche - Notifications optionnelles : "3 nouveaux contenus dans 'Podcasts voyage Paris'" **Performances** : ```sql -- Index composites pour filtres CREATE INDEX idx_content_filters ON contents ( content_type, duration, age_rating, geo_type, published_at ); -- Index GIN pour tags CREATE INDEX idx_content_tags ON contents USING GIN(tags); ``` **Coût** : 0€ (PostgreSQL + index standards) **Justification** : - Filtres essentiels pour découvrabilité - Combinables = puissance maximale - Sauvegarde = gain temps utilisateurs réguliers --- #### 15.3.4 Page de résultats **Décision** : Liste avec previews enrichies **Layout résultats** : ``` ┌─────────────────────────────────────────┐ │ 🔍 "voyage paris" │ │ 42 résultats · Tri : Pertinence ▼ │ │ [Filtres] [Carte] │ ├─────────────────────────────────────────┤ │ ┌─────────────────────────────────────┐ │ │ │ [Cover ] Balade à Paris │ │ │ │ [16:9 ] @paris_stories ✓ │ │ │ │ [Image ] 12 min · 🎧 2.3K │ │ │ │ 📍 Paris 5e · Ancré │ │ │ │ 🏷️ #Voyage #Histoire │ │ │ │ [▶️ Écouter] [⋮] │ │ │ └─────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────┐ │ │ │ [Cover ] Secrets Montmartre │ │ │ │ [16:9 ] @explore_paris │ │ │ │ [Image ] 8 min · 🎧 5.1K │ │ │ │ 📍 Paris 18e · Guide │ │ │ │ 🏷️ #Voyage #Art │ │ │ │ [▶️ Écouter] [⋮] │ │ │ └─────────────────────────────────────┘ │ │ │ │ [Charger plus] (20 suivants) │ └─────────────────────────────────────────┘ ``` **Informations par résultat** : | Élément | Affichage | |---------|-----------| | **Cover image** | 16:9, 120×68 px, lazy loading | | **Titre** | Tronqué 2 lignes max | | **Créateur** | @pseudo + badge ✓ si vérifié, cliquable → profil | | **Durée** | Format : "3 min" / "12 min" / "1h 24 min" | | **Écoutes** | Arrondi : "2.3K" / "54K" / "1.2M" | | **Localisation** | Ville + type géo (Ancré/Contextuel/Neutre) | | **Tags** | Maximum 3 premiers tags | | **Badge Premium** | 👑 si contenu premium | | **Distance** | Si recherche géo : "À 2.3 km" | **Actions contextuelles [⋮]** : - Partager - Ajouter à une playlist (future feature) - Télécharger (offline) - Signaler **Pagination** : - **20 résultats** par page - Infinite scroll (charger automatiquement si scroll >80%) - Bouton "Charger 20 suivants" en bas (fallback si scroll auto désactivé) **Vue carte (alternative)** : - Bouton toggle "Liste / Carte" - Map Leaflet (OpenStreetMap) - Markers cliquables → popup avec preview - Clustering si >50 résultats proches **Coût** : 0€ (Leaflet open source + OSM tiles gratuit) **Justification** : - Équilibre information / compacité - Lazy loading = performances - Infinite scroll = UX moderne --- ## Récapitulatif Section 15 | Point | Décision | Coût | Complexité | |-------|----------|------|------------| | **15.1.1** Bouton partager | Disponible partout (⬆️), menu natif OS | 0€ | Faible | | **15.1.2** Lien partagé | Web player + deep link + Open Graph SEO | 0€ | Moyenne | | **15.1.3** Premium partagé | Preview 30s + paywall overlay | 0€ | Faible | | **15.2.1** Page profil | Profil public complet (stats + bio + contenus + tri) | 0€ | Faible | | **15.2.2** Stats publiques | Arrondies (abonnés, écoutes, durée totale) | 0€ | Faible | | **15.2.3** Badge vérifié | ✓ si KYC/célébrité/>10K abonnés | 0€ | Faible | | **15.3.1** Recherche texte | PostgreSQL full-text french + stemming | 0€ | Moyenne | | **15.3.2** Recherche géo | Lieu + rayon (Nominatim OSM) | 0-50€/mois | Moyenne | | **15.3.3** Filtres | 7 catégories combinables + sauvegarde recherches | 0€ | Moyenne | | **15.3.4** Page résultats | Liste enrichie + vue carte Leaflet + infinite scroll | 0€ | Moyenne | **Coût total MVP : 0-50€/mois** (Nominatim self-hosted optionnel) --- ## Points d'attention pour Gherkin - Tester partage contenu public vs Premium (preview 30s) - Tester deep linking iOS/Android (ouverture app si installée) - Tester Open Graph (aperçu correct sur WhatsApp, Twitter, Facebook) - Tester profil public (stats arrondies, badge vérifié) - Tester recherche full-text français (stemming, accents) - Tester recherche géo + rayon (PostGIS distance) - Tester combinaison filtres multiples (AND logic) - Tester sauvegarde recherches (max 5) - Tester pagination infinite scroll + fallback bouton - Tester vue carte Leaflet (clustering, markers cliquables)
## 16. Audio-guides multi-séquences ### 16.1 Types d'audio-guides et modes de déplacement **Décision** : 4 modes distincts avec détection automatique #### 16.1.1 Classification par mode | Mode | Vitesse détection | Déclenchement | Use case | |------|-------------------|---------------|----------| | **🚶 Piéton** | <5 km/h | Manuel (bouton "Suivant") | Musées, visites urbaines, monuments | | **🚗 Voiture** | >10 km/h | Auto GPS + Manuel possible | Safari-parc, routes touristiques, circuits auto | | **🚴 Vélo** | 5-25 km/h | Auto GPS + Manuel possible | Pistes cyclables, circuits vélo, parcours nature | | **🚌 Transport** | Variable | Auto GPS + Manuel possible | Bus touristiques, trains panoramiques | **Détection automatique** : - Vitesse moyenne calculée sur 30 secondes - Suggestion mode au démarrage : "Détection : 🚗 Voiture. Est-ce correct ? [Oui] [Changer]" - User peut forcer mode manuellement (settings) **Justification** : - Flexibilité maximale créateurs et utilisateurs - Expériences optimisées par type de déplacement - Gestion cas limites (vélo lent vs piéton rapide) --- #### 16.1.2 Création d'un audio-guide (côté créateur) **Formulaire création** : ``` ┌────────────────────────────────────────┐ │ Nouvel audio-guide multi-séquences │ ├────────────────────────────────────────┤ │ Titre : [Safari du Paugre] │ │ Description : [Découvrez les animaux │ │ du parc en voiture...] │ │ │ │ Mode de déplacement : *obligatoire │ │ ○ 🚶 Piéton (navigation manuelle) │ │ ● 🚗 Voiture (GPS auto + manuel) │ │ ○ 🚴 Vélo (GPS auto + manuel) │ │ ○ 🚌 Transport (GPS auto + manuel) │ │ │ │ Vitesse recommandée : 30-50 km/h │ │ (si voiture/vélo/transport) │ │ │ │ ──────────────────────────────────── │ │ │ │ Séquences (ordre lecture) : │ │ │ │ 1. [📍] Introduction - Point d'accueil │ │ Lat: 43.1234, Lon: 2.5678 │ │ Rayon déclenchement : 30m │ │ Durée : 2:15 │ │ [🎵 Audio uploadé] [✏️] [🗑️] │ │ │ │ 2. [📍] Enclos des lions │ │ Lat: 43.1245, Lon: 2.5690 │ │ Rayon déclenchement : 30m │ │ Durée : 3:42 │ │ [📤 Upload audio] [✏️] [🗑️] │ │ │ │ 3. [📍] Enclos des girafes │ │ [+ Ajouter point GPS] │ │ │ │ [+ Ajouter séquence] │ │ │ │ 📊 Statistiques : │ │ · 2 séquences complètes │ │ · 5:57 durée totale │ │ · 320m distance totale │ │ │ │ [🗺️ Aperçu sur carte] │ │ [✅ Publier audio-guide] │ └────────────────────────────────────────┘ ``` **Métadonnées obligatoires** : | Champ | Requis | Détails | |-------|--------|---------| | **Titre audio-guide** | ✅ | 5-100 caractères | | **Description** | ✅ | 10-500 caractères | | **Mode déplacement** | ✅ | Piéton / Voiture / Vélo / Transport | | **Nombre séquences** | ✅ | Minimum 2, maximum 50 | | **Point GPS par séquence** | ✅ (sauf piéton) | Latitude, longitude (WGS84) | | **Rayon déclenchement** | ✅ (sauf piéton) | 10-100m selon mode | | **Vitesse recommandée** | ❌ | Optionnel, affichée utilisateur | | **Tags** | ✅ | 1-3 parmi liste prédéfinie | | **Classification âge** | ✅ | Tout public / 13+ / 16+ / 18+ | | **Zone diffusion** | ✅ | Polygon géographique | **Wizard de création** : - Étape 1 : Infos générales (titre, description, mode) - Étape 2 : Ajout séquences une par une - Étape 3 : Preview carte (trace + points) - Étape 4 : Validation modération (3 premiers audio-guides) **Justification** : - Contrôle total créateur sur expérience - Carte preview aide visualiser parcours - Wizard guidé = réduction friction création --- ### 16.2 Mode Piéton (manuel) **Décision** : Navigation manuelle avec pub auto-play #### 16.2.1 Passage entre séquences **Séquence normale (sans pub)** : 1. Séquence 1 se termine 2. Player se met en **pause automatique** 3. Message affiché : "Séquence 1 terminée. Appuyez sur Suivant quand vous êtes prêt." 4. User appuie sur [▶|] → Séquence 2 démarre immédiatement **Séquence avec publicité** (1 pub / 5 séquences) : 1. Séquence 2 se termine 2. **Publicité s'enchaîne automatiquement** (pas d'attente bouton) 3. Pub se lit (skippable après 5s) 4. Pub se termine → Player se met en **pause automatique** 5. Message : "Séquence 3 prête. Appuyez sur Suivant." 6. User appuie sur [▶|] → Séquence 3 démarre **Schéma flux** : ``` Séquence 1 [fin] → PAUSE → User clique → Séquence 2 [fin] → PUB AUTO-PLAY → PAUSE → User clique → Séquence 3 ``` **Fréquence pub** : - Gratuits : 1 pub toutes les 5 séquences (paramétrable admin 1/3 à 1/10) - Premium : 0 pub **Justification** : - Pub s'insère naturellement (pas d'attente utilisateur pour déclencher) - User garde contrôle rythme visite (pause après pub) - Monétisation effective créateurs - Premium reste attractif (0 interruption) --- #### 16.2.2 Navigation et contrôles **Décision** : Liberté totale utilisateur **Contrôles disponibles** : | Bouton | Fonction | Comportement | |--------|----------|--------------| | **[▶\|] Suivant** | Passe séquence suivante | Immédiat, même si séquence actuelle pas terminée | | **[\|◀] Précédent** | Retour séquence précédente | Saut direct séquence avant (pas de logique "replay si >10s") | | **[⏸️] Pause** | Pause temporaire | Reprend à position exacte | | **[▶️] Play** | Reprend lecture | Continue position actuelle | | **Liste séquences** | Navigation libre | Tap séquence → saut direct (même séquences non écoutées) | **Interface liste séquences** : ``` ┌────────────────────────────────────────┐ │ 🚶 Audio-guide Piéton │ │ Musée du Louvre │ ├────────────────────────────────────────┤ │ [Cover image] │ │ │ │ ▶️ 0:00 ──●────────── 3:42 │ │ │ │ Séquence 3/12 : La Joconde │ │ │ │ [|◀] [⏸️] [▶|] │ │ │ │ ──────────────────────────────────── │ │ │ │ 📋 Liste des séquences │ │ │ │ ✅ 1. Introduction (2:15) │ │ Écouté le 15/01/2026 │ │ │ │ ✅ 2. Pyramide du Louvre (1:48) │ │ Écouté le 15/01/2026 │ │ │ │ ▶️ 3. La Joconde (3:42) - EN COURS │ │ ──●──────────── 1:22/3:42 │ │ │ │ ⭕ 4. Vénus de Milo (2:58) │ │ │ │ ⭕ 5. Code d'Hammurabi (4:12) │ │ │ │ ⭕ 6. Victoire de Samothrace (3:25) │ │ │ │ ... +6 séquences │ │ │ │ [Tout afficher ▼] │ └────────────────────────────────────────┘ ``` **Navigation libre** : - User peut sauter séquences déjà connues - User peut revenir en arrière à tout moment - User peut aller directement à séquence 8 (même si 4-7 non écoutées) **Sauvegarde progression** : - Checkmarks ✅ sur séquences écoutées >80% - Position exacte sauvegardée dans séquence en cours **Justification** : - Utilisateur contrôle 100% son rythme - Adapté musées : visitor peut voir physiquement une œuvre lointaine et vouloir écouter sa description - Pas de frustration (liberté totale) --- ### 16.3 Mode Voiture (GPS automatique) **Décision** : GPS auto avec navigation manuelle conservée #### 16.3.1 Déclenchement et contrôles **Distinction audio-guides vs contenus géolocalisés simples** : ⚠️ **Important** : Les audio-guides multi-séquences fonctionnent différemment des contenus géolocalisés simples. | Type | Séquences | Déclenchement | Notification | Enchaînement | Comptabilité quota | |------|-----------|---------------|--------------|--------------|-------------------| | **Contenu géolocalisé simple** | 1 séquence unique | Notification 7s avant (temps ETA) | Sonore + icône | Fin → retour buffer normal | 1 contenu = 1 quota | | **Audio-guide multi-séquences** | 2 à 50 séquences | Au point GPS exact (distance 30m) | Ding + toast 2s | Séquences s'enchaînent auto | 1 audio-guide = 1 quota (toutes séquences) | **Fonctionnement GPS automatique** : 1. User démarre audio-guide en voiture (voir section 16.1 pour démarrage) 2. Séquence 1 démarre automatiquement au point GPS défini (rayon 30m) 3. Séquence 1 se termine 4. **Affichage progress bar** : distance temps réel + ETA jusqu'au prochain point 5. User roule vers point GPS suivant 6. Arrivée au point GPS suivant (rayon 30m) → **déclenchement automatique** séquence suivante 7. Notification sonore discrète : "Ding" (0.3s) + toast 2s : "Enclos des girafes" 8. Séquence suivante démarre immédiatement (pas de décompte) **Pas de système "7 secondes avant" pour les audio-guides** : - Contrairement aux contenus géolocalisés simples (voir [05-interactions-navigation.md](#05-interactions-navigation.md#511-file-dattente-et-commande-suivant)) - Les séquences se déclenchent **au point GPS exact** (rayon 30m) - Raison : expérience guidée continue, user sait qu'il suit un parcours **Navigation manuelle CONSERVÉE** : | Bouton | État | Comportement | |--------|------|--------------| | **[▶\|] Suivant** | ✅ Toujours actif | Passe séquence suivante immédiatement (même hors point GPS) | | **[\|◀] Précédent** | ✅ Toujours actif | Retour séquence précédente (même hors point GPS) | | **[⏸️] Pause** | ✅ | Pause temporaire | | **Liste séquences** | ✅ | Saut direct possible | **Use cases navigation manuelle** : | Situation | Solution manuelle | |-----------|-------------------| | Embouteillage (séquence finie, point GPS loin) | User clique Suivant → avance manuellement | | Point GPS inaccessible (route fermée) | User clique Suivant → skip point | | Envie réécouter séquence précédente | User clique Précédent → retour | | Passager manipule l'app | Passager navigue librement | **Avertissement sécurité** : - Si vitesse **>10 km/h** ET user clique bouton (Suivant/Précédent) : - Toast 3 secondes : "⚠️ Manipulation en conduite détectée. Pour votre sécurité, demandez à un passager." - **Action quand même exécutée** (pas de blocage) - Justification : sensibilisation sans bloquer (passager peut légitimement manipuler) **Schéma flux** : ``` Point GPS 1 (30m) → Séquence 1 AUTO → User roule → Distance affichée → Point GPS 2 (30m) → Séquence 2 AUTO ↓ User clique Suivant (manuel) → Séquence 2 immédiate ``` **Justification** : - Flexibilité maximale : GPS optimise expérience MAIS user garde contrôle - Gestion cas limites : routes fermées, détours, embouteillages - Sécurité : warning sensibilise sans bloquer (passager légitime) --- #### 16.3.2 Affichage distance et guidage **Décision** : Distance + direction (PAS de carte miniature) **Interface en conduite** : ``` ┌────────────────────────────────────────┐ │ 🚗 Audio-guide Voiture │ │ Safari du Paugre │ ├────────────────────────────────────────┤ │ │ │ ▶️ 0:00 ──●────────── 2:15 │ │ │ │ Séquence 2/8 : Les lions │ │ │ │ ──────────────────────────────────── │ │ │ │ 📍 Prochain point │ │ │ │ Enclos des girafes │ │ │ │ ┌────────────────────────────────┐ │ │ │ │ │ │ │ ↗️ │ │ │ │ (direction) │ │ │ │ │ │ │ │ 320 mètres │ │ │ │ ≈ 40 secondes │ │ │ │ │ │ │ └────────────────────────────────┘ │ │ │ │ Vitesse actuelle : 28 km/h │ │ Vitesse recommandée : 20-30 km/h │ │ │ │ [|◀] [⏸️] [▶|] [📋 Liste] │ └────────────────────────────────────────┘ ``` **Affichage entre deux séquences** : Quand une séquence se termine et qu'il reste un point GPS suivant, l'interface bascule en mode "attente prochain point" : ``` ┌────────────────────────────────────────┐ │ 🚗 Audio-guide Voiture │ │ Safari du Paugre │ ├────────────────────────────────────────┤ │ │ │ ✅ Séquence 2/8 terminée │ │ Les lions │ │ │ │ ──────────────────────────────────── │ │ │ │ 📍 Prochain point │ │ │ │ Enclos des girafes │ │ │ │ ┌────────────────────────────────┐ │ │ │ [Progress bar] │ │ │ │ ████████░░░░░░░░░ 65% │ │ │ │ │ │ │ │ ↗️ │ │ │ │ (direction) │ │ │ │ │ │ │ │ 320 mètres │ │ │ │ ≈ 40 secondes │ │ │ │ │ │ │ └────────────────────────────────┘ │ │ │ │ Vitesse actuelle : 28 km/h │ │ │ │ [|◀] [▶️ Rejouer séq.] [▶|] │ └────────────────────────────────────────┘ ``` **Progress bar dynamique** : - Se remplit au fur et à mesure qu'on se rapproche du point - Calcul : `progress = 100 - (distance_actuelle / distance_initiale * 100)` - Exemple : distance initiale 500m, distance actuelle 175m → progress = 65% - Couleur : vert (#4CAF50) pour la partie remplie, gris (#E0E0E0) pour le reste **Bouton "Rejouer séq."** : - Permet de réécouter la séquence qui vient de se terminer - User clique → séquence actuelle redémarre depuis 0:00 - Utile si distraction pendant l'écoute --- **Informations affichées** : | Info | Mise à jour | Format | |------|-------------|--------| | **Distance** | Chaque seconde | "320 m" / "1.2 km" | | **ETA** | Chaque seconde | "≈ 40 secondes" / "≈ 2 minutes" | | **Direction** | Chaque 5s | Flèche indique direction (8 directions : ↑ ↗ → ↘ ↓ ↙ ← ↖) | | **Vitesse actuelle** | Chaque seconde | "28 km/h" | | **Vitesse recommandée** | Statique | "20-30 km/h" (définie par créateur) | | **Progress bar** | Chaque seconde | Pourcentage parcouru vers prochain point | **Calcul direction** : ```javascript // Calcul angle entre position actuelle et prochain point const currentGPS = getCurrentLocation(); const nextPoint = audioGuide.sequences[currentIndex + 1].location; const angle = calculateBearing(currentGPS, nextPoint); // 0-360° // Conversion en flèche (8 directions) const arrows = ['↑', '↗', '→', '↘', '↓', '↙', '←', '↖']; const index = Math.round(angle / 45) % 8; const direction = arrows[index]; ``` **Calcul ETA** : ```javascript const distance = calculateDistance(currentGPS, nextPoint); // mètres const currentSpeed = getCurrentSpeed(); // km/h if (currentSpeed > 5) { const eta = (distance / 1000) / currentSpeed * 3600; // secondes return formatETA(eta); // "≈ 40 secondes" ou "≈ 2 minutes" } else { return "En attente de déplacement"; } ``` **Justification** : - Distance + ETA = info essentielle sans surcharge visuelle - Direction (flèche) = aide se repérer sans carte complexe - Simplicité = moins distraction conducteur - Économie batterie (pas de rendu carte) --- #### 16.3.3 Rayon de déclenchement et tolérance **Décision** : Rayon configurable créateur avec défauts intelligents **Rayons par défaut** : | Mode | Rayon déclenchement | Rayon "point manqué" | Justification | |------|---------------------|----------------------|---------------| | **🚗 Voiture** | 30 mètres | 100 mètres | Vitesse élevée = anticipation | | **🚴 Vélo** | 50 mètres | 75 mètres | Vitesse variable, arrêts fréquents | | **🚌 Transport** | 100 mètres | 150 mètres | Arrêts bus/train, moins précis | **Configuration créateur** : - Curseur rayon : **10m → 200m** - Défaut pré-sélectionné selon mode choisi - Preview visuel : cercle sur carte (lors création) - Suggestion auto : "Recommandé : 30m pour voiture à 30 km/h" **Gestion point manqué** : ``` User passe à 110m du point GPS (hors rayon déclenchement 30m MAIS dans rayon tolérance 100m) ↓ Toast : "⚠️ Point manqué : Enclos des girafes" ↓ Popup 5 secondes : ┌────────────────────────────────────┐ │ Point manqué │ │ │ │ "Enclos des girafes" │ │ Vous êtes passé à 110m du point │ │ │ │ [🔊 Écouter quand même] │ │ [⏭️ Passer au suivant] │ │ [🔙 Faire demi-tour] │ └────────────────────────────────────┘ ``` **Actions popup** : | Bouton | Comportement | |--------|--------------| | **Écouter quand même** | Lance séquence immédiatement (même hors zone) | | **Passer au suivant** | Skip séquence, continue vers prochain point | | **Faire demi-tour** | Lance navigation GPS externe (Google Maps / Waze) vers point manqué | **Si user au-delà rayon tolérance (>100m)** : - Aucun popup (point trop loin, probablement hors itinéraire) - User peut naviguer manuellement (bouton Suivant) **Justification** : - Flexibilité créateur (ajuste selon terrain, vitesse prévue) - Gestion intelligente imprévus (détours, routes fermées) - User pas bloqué (toujours moyen avancer) --- ### 16.4 Modes Vélo et Transport **Décision** : Même logique voiture avec tolérances ajustées **Différences par rapport à mode voiture** : | Paramètre | Voiture | Vélo | Transport | |-----------|---------|------|-----------| | **Rayon déclenchement** | 30m | 50m | 100m | | **Rayon tolérance "point manqué"** | 100m | 75m | 150m | | **Vitesse recommandée affichée** | 20-50 km/h | 10-25 km/h | Variable (selon ligne) | | **Warning sécurité** | >10 km/h | >5 km/h | Désactivé | **Mode Vélo spécificités** : - Rayon plus large : vitesse variable, nombreux arrêts (feux, piétons) - Warning sécurité dès 5 km/h (vélo en mouvement) - Tolérance GPS moins stricte (tracé moins prévisible qu'auto) **Mode Transport spécificités** : - Rayon très large : arrêts fréquents (bus, train), ligne fixe - Pas de warning sécurité (user = passager, pas conducteur) - Vitesse recommandée = "Selon ligne" (pas de valeur fixe) - Tolérance horaire : si bus en retard, point peut se déclencher avec 2-3 min de délai **Comportement identique voiture** : - Navigation manuelle conservée (boutons actifs) - Affichage distance + ETA + direction - Gestion point manqué - Pub entre séquences **Justification** : - Vélo : moins de contrôle qu'auto (obstacles, arrêts), nécessite tolérance - Transport : moins de contrôle utilisateur (suit ligne fixe), rayon large compense - Même UX globale = cohérence --- ### 16.5 Publicités dans audio-guides **Décision** : Pub auto-play entre séquences TOUS modes #### 16.5.1 Règles universelles **Insertion publicité** : - Fréquence : **1 pub toutes les 5 séquences** (paramétrable admin 1/3 à 1/10) - Gratuits uniquement, **Premium 0 pub** - Pub s'enchaîne **automatiquement** après séquence - Skippable après **5 secondes** (règle standard RoadWave) - Volume normalisé -14 LUFS (comme pubs normales) **Comportement MODE PIÉTON** : ``` Séquence 2 [fin] → Pub AUTO-PLAY → Pub se termine → PAUSE AUTO → Message "Séquence 3 prête. Appuyez sur Suivant." → User clique [▶|] → Séquence 3 démarre ``` **Comportement MODE VOITURE/VÉLO/TRANSPORT** : ``` Séquence 2 [fin] → Pub AUTO-PLAY → Pub se termine → ATTENTE point GPS suivant OU user clique Suivant → Séquence 3 démarre ``` **Schéma complet** : | Mode | Après séquence normale | Après pub | |------|------------------------|-----------| | **Piéton** | Pause + attente user | Pause + attente user | | **Voiture** | Attente GPS OU user clique Suivant | Attente GPS OU user clique Suivant | | **Vélo** | Attente GPS OU user clique Suivant | Attente GPS OU user clique Suivant | | **Transport** | Attente GPS OU user clique Suivant | Attente GPS OU user clique Suivant | **Justification** : - Monétisation équitable créateurs (tous modes participent) - Pub s'insère naturellement (auto-play, pas d'attente utilisateur) - User garde contrôle : piéton clique Suivant, voiture peut skip manuel - Premium reste attractif (expérience 0 interruption) - Modèle économique viable --- #### 16.5.2 Métriques pub audio-guides **Dashboard créateur** : | Métrique | Affichage | |----------|-----------| | **Impressions pub** | Nombre de pubs insérées dans audio-guides | | **Écoutes complètes pub** | Nombre de pubs écoutées >80% | | **Taux skip pub** | % pubs skippées avant 5s vs après | | **Revenus pub audio-guides** | 3€ / 1000 écoutes complètes (6% CA pub) | **Distinction contenus normaux vs audio-guides** : - Dashboard sépare : "Revenus contenus classiques" / "Revenus audio-guides" - Permet créateur voir performance par type **Justification** : - Transparence créateur (comprend revenus) - Incite création audio-guides (nouvelle source revenus) --- ### 16.6 Reprise et sauvegarde progression **Décision** : Sauvegarde complète automatique avec popup intelligente #### 16.6.1 Sauvegarde automatique **Données sauvegardées** : | Info | Détail | Utilité | |------|--------|---------| | **Audio-guide ID** | Identifiant unique | Retrouver audio-guide | | **Séquence actuelle** | Index (ex: 3/12) | Reprise position | | **Position dans séquence** | Timestamp exact (ex: 1:42/3:20) | Reprise exacte | | **Séquences écoutées** | Liste avec checkmarks ✅ | Historique progression | | **Date dernière écoute** | Timestamp | Proposer reprise si <30j | | **GPS dernière position** | Coordonnées optionnelles | Info contextuelle (non utilisée pour reprise) | **Stockage** : | Environnement | Technologie | Utilité | |---------------|-------------|---------| | **Local** | SQLite mobile | Fonctionnement offline | | **Cloud** | PostgreSQL (sync auto) | Multi-device (reprendre sur autre appareil) | **Synchronisation** : - Sauvegarde locale : chaque fin de séquence + chaque 30s - Sync cloud : à la reconnexion réseau (batch) **Justification** : - Expérience fluide (pas de perte progression) - Multi-device (démarrer sur iPhone, continuer sur iPad) - Offline-first (fonctionne sans réseau) --- #### 16.6.2 Interface de reprise **Conditions popup** : - Dernière écoute **<30 jours** - Progression **>0%** et **<100%** (pas terminé) **Popup reprise** : ``` ┌────────────────────────────────────────┐ │ Reprendre l'audio-guide ? │ ├────────────────────────────────────────┤ │ 🚗 Safari du Paugre │ │ @safari_createur │ │ │ │ Progression : 3/8 séquences écoutées │ │ Dernière écoute : il y a 2 jours │ │ │ │ Vous étiez à : │ │ "Les lions" (1:42/3:20) │ │ │ │ [▶️ Reprendre] [🔄 Recommencer] │ │ [📋 Voir toutes les séquences] │ └────────────────────────────────────────┘ ``` **Actions** : | Bouton | Comportement | |--------|--------------| | **Reprendre** | Continue séquence 3 à position 1:42 exacte | | **Recommencer** | Reset progression, démarre séquence 1 depuis 0:00 | | **Voir séquences** | Affiche liste complète, user choisit séquence départ | **Expiration progression** : - Progression conservée **30 jours** - Après 30j : popup "Audio-guide expiré. Recommencez depuis le début ?" - Suppression données progression (mais historique "écouté" préservé) **Justification** : - Contexte clair : user sait exactement où il en est - Flexibilité : reprendre OU recommencer (choix utilisateur) - 30 jours = raisonnable pour tourisme multi-jours ou retour ultérieur --- #### 16.6.3 Multi-device **Scénario** : 1. User démarre audio-guide sur iPhone (séquences 1-3) 2. Progression sync cloud 3. Lendemain : user ouvre app sur iPad 4. Popup : "Reprendre Safari du Paugre sur cet appareil ?" 5. User clique Reprendre → continue séquence 4 **Conflit de version** : - Si modifications simultanées 2 appareils (rare) : **dernière modification gagne** - Toast : "Progression mise à jour depuis votre autre appareil" **Justification** : - Confort utilisateur (change d'appareil librement) - Use case réel : planning trajet sur tablette, écoute sur smartphone en voiture --- ## Récapitulatif Section 16 | Point | Décision | Coût | Complexité | |-------|----------|------|------------| | **16.1** Types audio-guides | 4 modes (piéton/voiture/vélo/transport) avec détection auto | 0€ | Moyenne | | **16.1.2** Création | Formulaire séquences + GPS + rayon + wizard guidé | 0€ | Moyenne | | **16.2.1** Piéton - Passages | Manuel AVEC pub auto-play entre séquences, pause après | 0€ | Faible | | **16.2.2** Piéton - Navigation | Liberté totale (skip, retour, saut direct liste) | 0€ | Faible | | **16.3.1** Voiture - Déclenchement | GPS auto + boutons manuels actifs (warning sécurité si >10 km/h) | 0€ | Moyenne | | **16.3.2** Voiture - Affichage | Distance + ETA + direction (flèche) + vitesse (PAS de carte) | 0€ | Faible | | **16.3.3** Voiture - Rayon | Configurable créateur (défauts 30m/50m/100m selon mode) | 0€ | Faible | | **16.4** Vélo & Transport | Mêmes règles avec tolérances ajustées + warning adapté | 0€ | Faible | | **16.5** Publicités | 1/5 séquences, auto-play TOUS modes, skippable 5s | 0€ | Faible | | **16.6.1** Sauvegarde | Complète (séquence + position + historique) local + cloud | 0€ | Faible | | **16.6.2** Reprise | Popup intelligente avec choix (reprendre/recommencer), expiration 30j | 0€ | Faible | | **16.6.3** Multi-device | Sync cloud PostgreSQL (reprendre sur autre appareil) | 0€ | Faible | **Coût total MVP : 0€** (GPS natif, calcul distance PostGIS) --- ## Points d'attention pour Gherkin - Tester 4 modes audio-guides (détection vitesse auto) - Tester création séquences avec points GPS + rayon configurable - Tester mode piéton : pause après séquence + pub auto-play + pause après pub + clic Suivant - Tester navigation libre piéton (skip, retour, saut direct liste) - Tester mode voiture : déclenchement GPS auto rayon 30m - Tester navigation manuelle voiture : boutons actifs + warning si vitesse >10 km/h - Tester affichage distance + ETA + direction (flèche 8 directions) - Tester rayon tolérance "point manqué" (popup 3 actions) - Tester mode vélo (rayon 50m) et transport (rayon 100m) - Tester insertion pub 1/5 séquences tous modes avec auto-play - Tester sauvegarde progression locale + sync cloud - Tester popup reprise (3 boutons : reprendre/recommencer/voir liste) - Tester expiration progression 30 jours - Tester multi-device : démarrer iPhone, continuer iPad - Tester gestion conflit progression simultanée 2 appareils
# Annexe : Fonctionnalités reportées Post-MVP **Date** : 2026-01-19 **Statut** : Fonctionnalités validées mais reportées après le MVP --- ## Sommaire 1. [Classification politique et équilibre éditorial](##1-classification-politique-et-équilibre-éditorial) 2. [Système de pourboires créateurs](##2-système-de-pourboires-créateurs) --- ## 1. Classification politique et équilibre éditorial > ⚠️ **Reporté post-MVP** pour raisons de coût, complexité et risques juridiques. ### Contexte du report **Raisons** : - **Coût modération** : Classification manuelle humaine très coûteuse (~2000€/mois pour 1-2 modérateurs senior full-time) - **Risque juridique** : Accusations de biais éditorial, contentieux DSA - **Complexité technique** : Dashboard audit, logs 3 ans, alertes déséquilibre - **Controverse** : Peut créer polémique dès le lancement - **Pas essentiel MVP** : L'application fonctionne sans ce système **Version MVP** (actuelle) : - Tag "Politique" simple (comme "Économie", "Sport") - Pas de classification gauche/droite - Pas d'équilibrage imposé - Option utilisateur "Masquer politique" → 0% contenus politiques --- ### Spécifications complètes (future implémentation) **Échelle de classification** (5 niveaux) : - 🔴 **Extrême gauche** (anticapitalisme radical, révolution) - 🟠 **Gauche** (écologie, social, critique capitalisme modérée) - ⚪ **Centre/Neutre** (pas de positionnement politique clair) - 🔵 **Droite** (sécurité, tradition, économie libérale) - 🟣 **Extrême droite** (nationalisme radical, conservatisme extrême) - 🟢 **Non politique** (enfants, musique, fiction, culture générale) **Qui classifie** : - ❌ Pas de classification automatique IA (outil informatif uniquement, jamais décisionnaire) - ✅ Modérateurs senior après transcription - ✅ Créateur peut contester via processus d'appel **Affichage** : - Badge politique visible : **au choix de l'utilisateur** (paramètre "Afficher orientation politique") - Par défaut : badges masqués (UX neutre) **Règles de diffusion (équilibre imposé)** : | Préférence utilisateur | Répartition | Justification | |------------------------|-------------|---------------| | **Équilibré** (défaut) | 35% gauche / 35% droite / 30% centre-neutre | Neutralité plateforme | | **Plutôt gauche** | 50% gauche / 20% droite / 30% centre-neutre | Préférence respectée avec minimum opposition | | **Plutôt droite** | 50% droite / 20% gauche / 30% centre-neutre | Préférence respectée avec minimum opposition | | **Masquer politique** | 0% gauche / 0% droite / 100% centre-neutre + non politique | Option apolitique | **Audit et conformité DSA** : - Rapport hebdomadaire automatique : % gauche/droite/centre diffusé par utilisateur - Alerte si déséquilibre global plateforme (>55% d'un bord) - Logs conservés **3 ans** (exigence Digital Services Act EU) - Dashboard admin : visualisation répartition temps réel **Sanctions mauvaise classification** : - Classification volontairement incorrecte = Strike 1 - Récidive = Strike 2 (suspension 7j) - Détection via signalements utilisateurs + audit modération **Justification** : - **Conformité juridique DSA** (obligation neutralité plateforme EU) - Protection contre accusations de biais éditorial - Transparence auditable - Coût : temps modération humaine (incompressible) --- ### Conditions de réintégration **Prérequis** : 1. Base utilisateurs stable et revenus suffisants pour financer modération 2. Équipe modération dédiée (2+ modérateurs senior formés) 3. Dashboard admin audit DSA opérationnel 4. Système de logs et archivage 3 ans en place 5. Validation juridique du processus de classification **Chronologie estimée** : - Phase 1 (Post-MVP+3 mois) : Validation demande utilisateurs via sondages - Phase 2 (Post-MVP+6 mois) : Recrutement modérateurs + développement dashboard - Phase 3 (Post-MVP+9 mois) : Tests bêta avec utilisateurs volontaires - Phase 4 (Post-MVP+12 mois) : Déploiement progressif si résultats positifs --- ## 2. Système de pourboires créateurs > ⚠️ **Reporté post-MVP** - Fonctionnalité crypto (Lightning Network) prévue ultérieurement. ### Contexte du report **Raisons** : - **Complexité technique** : Intégration Lightning Network, gestion wallets crypto - **Réglementation** : Incertitude juridique crypto en EU (MiCA 2025) - **Focus MVP** : Priorité sur monétisation via abonnements Premium et publicités - **Adoption utilisateurs** : Nécessite éducation et adoption crypto préalables **Version MVP** (actuelle) : - Monétisation créateurs via : - Partage revenus publicités (3€ CPM) - 70% revenus abonnements Premium --- ### Spécifications complètes (future implémentation) **Système prévu** : Micro-dons via Lightning Network (Bitcoin Layer 2) **Fonctionnement** : 1. Auditeur peut envoyer pourboire pendant ou après écoute 2. Montants suggérés : 0.10€, 0.50€, 1€, 5€ (personnalisable) 3. Transaction instantanée via Lightning Network (frais <0.01€) 4. Créateur reçoit directement dans wallet Lightning 5. Conversion EUR/BTC automatique (optionnelle) **Avantages Lightning Network** : - ✅ Frais quasi-nuls (<1%) vs 1.8% Mangopay - ✅ Transactions instantanées (<1 seconde) - ✅ Micropaiements possibles (dès 0.01€) - ✅ International sans frais supplémentaires - ✅ Pas d'intermédiaire (peer-to-peer) **Contraintes** : - ❌ Adoption crypto limitée (2-5% population EU en 2026) - ❌ Volatilité BTC (nécessite conversion EUR immédiate) - ❌ UX complexe pour utilisateurs non-crypto - ❌ Réglementation MiCA en évolution **Alternatives étudiées** : - Ko-fi / Buy Me a Coffee : simple mais frais 5% - PayPal/Stripe : frais 2.9% + 0.30€ (non viable pour micropaiements) - Mangopay : déjà utilisé, mais frais élevés pour petits montants --- ### Conditions de réintégration **Prérequis** : 1. Réglementation MiCA stabilisée et conforme 2. Adoption crypto suffisante dans la base utilisateurs (>10%) 3. Intégration Lightning Network validée techniquement 4. UX simplifiée pour utilisateurs non-crypto (onboarding dédié) 5. Demande créateurs confirmée via sondages **Chronologie estimée** : - Phase 1 (Post-MVP+6 mois) : Étude de marché et demande utilisateurs - Phase 2 (Post-MVP+12 mois) : Développement intégration Lightning - Phase 3 (Post-MVP+15 mois) : Tests bêta avec créateurs volontaires - Phase 4 (Post-MVP+18 mois) : Déploiement public si résultats positifs --- ## Autres fonctionnalités candidates Post-MVP Liste non exhaustive de fonctionnalités évoquées mais non encore spécifiées : - **Mode offline avancé** : Téléchargement automatique zones fréquentes - **Playlists collaboratives** : Co-création de playlists géolocalisées - **API publique créateurs** : Intégration RSS, podcasts existants - **Gamification** : Badges, défis géolocalisés, leaderboards - **Mode nuit** : Interface sombre automatique - **Statistiques avancées créateurs** : Démographie, retention, heatmaps GPS Ces fonctionnalités seront spécifiées et priorisées selon les retours utilisateurs MVP. --- ## Suivi et validation **Responsable** : Product Owner **Révision** : Trimestrielle **Critères de priorisation** : 1. Demande utilisateurs (votes, sondages) 2. Impact business (revenus, rétention) 3. Faisabilité technique (complexité, ressources) 4. Conformité légale (RGPD, DSA, MiCA) 5. Différenciation concurrentielle
# 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 | | | Déclenchement | | **📊 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 **📊 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** 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 **Alors** une publicité est insérée : **📊 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 **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 tolérance "point manqué" | | | Vitesse recommandée | | | Seuil warning sécurité | | **📊 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 "" **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 "" **📊 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 contenu(s) est/sont trouvé(s) **Quand** le système me propose du contenu **Alors** je reçois le message "" --- ## 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 "" **Quand** le système initialise le buffer audio **Alors** le buffer minimum est de secondes **Et** le buffer cible est de secondes **Et** le buffer maximum est de 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 | Fonctionnalité | Scénarios | |----------------|:---------:| | [Audio-guides multi-séquences pour piétons](#abonnements/audio-guides-pieton) | 29 | | [Impact des abonnements sur l'algorithme](#abonnements/impact-algorithme) | 16 | | [Limites d'abonnements et désabonnement](#abonnements/limites-desabonnement) | 27 | | [Notifications contextuelles selon le mode de déplacement](#abonnements/notifications-contextuelles) | 28 | *4 fonctionnalités • 100 scénarios* ## 🎧 Audio Guides | Fonctionnalité | Scénarios | |----------------|:---------:| | [Audio-guide mode piéton (navigation manuelle)](#audio-guides/mode-pieton) | 29 | | [Audio-guide mode voiture (GPS automatique)](#audio-guides/mode-voiture) | 45 | | [Audio-guides Premium et monétisation](#audio-guides/premium-monetisation) | 31 | | [Audio-guides modes vélo et transport](#audio-guides/modes-velo-transport) | 27 | | [Création d'audio-guide multi-séquences](#audio-guides/creation-audio-guide) | 35 | | [Intégration audio-guides avec autres fonctionnalités](#audio-guides/integration-fonctionnalites) | 39 | | [Sauvegarde et reprise de progression audio-guide](#audio-guides/progression-sauvegarde) | 32 | *7 fonctionnalités • 238 scénarios* ## 🔐 Authentication | Fonctionnalité | Scénarios | |----------------|:---------:| | [Authentification à deux facteurs (2FA)](#authentication/two-factor-authentication) | 16 | | [Classification des contenus par âge](#authentication/classification-age) | 13 | | [Connexion utilisateur](#authentication/connexion) | 11 | | [Gestion des sessions et tokens](#authentication/sessions-tokens) | 13 | | [Inscription utilisateur](#authentication/inscription) | 15 | | [Récupération de compte](#authentication/recuperation-compte) | 14 | | [Vérification d'email](#authentication/verification-email) | 10 | *7 fonctionnalités • 92 scénarios* ## 🎨 Content Creation | Fonctionnalité | Scénarios | |----------------|:---------:| | [Modification et suppression de contenu](#content-creation/modification-suppression) | 30 | | [Métadonnées et publication de contenu](#content-creation/metadonnees-publication) | 34 | | [Upload et encodage de contenu audio](#content-creation/upload-encodage) | 29 | | [Validation des 3 premiers contenus](#content-creation/validation-premiers-contenus) | 30 | *4 fonctionnalités • 123 scénarios* ## ⚠️ Error Handling | Fonctionnalité | Scénarios | |----------------|:---------:| | [Gestion d'un contenu supprimé pendant l'écoute](#error-handling/contenu-supprime-pendant-ecoute) | 11 | | [Gestion de la perte de réseau et buffering adaptatif](#error-handling/perte-reseau) | 17 | | [Mode dégradé sans géolocalisation](#error-handling/geolocalisation-desactivee) | 19 | | [Élargissement automatique de zone quand aucun contenu n'est disponible](#error-handling/aucun-contenu-disponible) | 9 | *4 fonctionnalités • 56 scénarios* ## 📊 Interest Gauges | Fonctionnalité | Scénarios | |----------------|:---------:| | [Jauge initiale et cold start](#interest-gauges/jauge-initiale) | 15 | | [Pas de dégradation temporelle des jauges](#interest-gauges/degradation-temporelle) | 16 | | [Évolution des jauges d'intérêt](#interest-gauges/evolution-jauges) | 21 | *3 fonctionnalités • 52 scénarios* ## 📴 Mode Offline | Fonctionnalité | Scénarios | |----------------|:---------:| | [Synchronisation actions offline](#mode-offline/synchronisation-actions) | 45 | | [Téléchargement de contenus offline](#mode-offline/telechargement) | 49 | | [Validité et renouvellement contenus offline](#mode-offline/validite-renouvellement) | 38 | *3 fonctionnalités • 132 scénarios* ## 🛡️ Moderation | Fonctionnalité | Scénarios | |----------------|:---------:| | [Modération préventive](#moderation/moderation-preventive) | 22 | | [Sanctions et notifications de modération](#moderation/sanctions-notifications) | 27 | | [Signalement de contenu inapproprié](#moderation/signalement) | 23 | | [Traitement des signalements par l'IA et les modérateurs](#moderation/traitement-signalements) | 25 | *4 fonctionnalités • 97 scénarios* ## 💰 Monetisation | Fonctionnalité | Scénarios | |----------------|:---------:| | [Conditions d'activation de la monétisation](#monetisation/conditions-activation) | 28 | | [Contenus Premium exclusifs](#monetisation/contenus-premium-exclusifs) | 34 | | [Désactivation et suspension monétisation](#monetisation/desactivation-suspension) | 35 | | [KYC et inscription à la monétisation](#monetisation/kyc-inscription) | 37 | | [Obligations fiscales](#monetisation/obligations-fiscales) | 30 | | [Paiement des créateurs](#monetisation/paiement-createurs) | 35 | | [Sources de revenus créateurs](#monetisation/sources-revenus) | 34 | *7 fonctionnalités • 233 scénarios* ## 🧭 Navigation | Fonctionnalité | Scénarios | |----------------|:---------:| | [Actions complémentaires à l'arrêt](#navigation/actions-complementaires) | 23 | | [Commande "Précédent"](#navigation/commande-precedent) | 19 | | [Commandes au volant et interactions simplifiées](#navigation/commandes-volant) | 21 | | [Commandes vocales CarPlay et Android Auto](#navigation/commandes-vocales) | 25 | | [File d'attente et commande "Suivant"](#navigation/file-attente-suivant) | 20 | | [Lecture en boucle et enchaînement automatique](#navigation/lecture-enchainement) | 27 | *6 fonctionnalités • 135 scénarios* ## 🔗 Partage | Fonctionnalité | Scénarios | |----------------|:---------:| | [Partage de contenu](#partage/partage-contenu) | 22 | *1 fonctionnalités • 22 scénarios* ## ⭐ Premium | Fonctionnalité | Scénarios | |----------------|:---------:| | [Avantages Premium](#premium/avantages-premium) | 37 | | [Gestion abonnement Premium](#premium/gestion-abonnement) | 41 | | [Multi-devices et détection simultanée](#premium/multi-devices-detection) | 30 | | [Offre et tarification Premium](#premium/offre-tarification) | 31 | *4 fonctionnalités • 139 scénarios* ## 👤 Profil | Fonctionnalité | Scénarios | |----------------|:---------:| | [Profil créateur](#profil/profil-createur) | 31 | *1 fonctionnalités • 31 scénarios* ## 📢 Publicites | Fonctionnalité | Scénarios | |----------------|:---------:| | [Caractéristiques et facturation des publicités](#publicites/caracteristiques-pub) | 32 | | [Création de campagnes publicitaires](#publicites/campagnes-publicitaires) | 30 | | [Gestion du budget et alertes publicitaires](#publicites/gestion-budget-pub) | 30 | | [Insertion et fréquence des publicités](#publicites/insertion-frequence-pub) | 31 | | [Métriques d'engagement et dashboard publicitaire](#publicites/metriques-engagement-pub) | 27 | | [Validation et modération des publicités](#publicites/validation-moderation-pub) | 29 | *6 fonctionnalités • 179 scénarios* ## 📻 Radio Live | Fonctionnalité | Scénarios | |----------------|:---------:| | [Architecture technique radio live](#radio-live/architecture-technique-live) | 24 | | [Arrêt du live](#radio-live/arret-live) | 19 | | [Comportement auditeur pendant un live](#radio-live/comportement-auditeur) | 27 | | [Démarrage d'un live](#radio-live/demarrage-live) | 20 | *4 fonctionnalités • 90 scénarios* ## 🔍 Recherche | Fonctionnalité | Scénarios | |----------------|:---------:| | [Recherche de contenu](#recherche/recherche) | 55 | *1 fonctionnalités • 55 scénarios* ## 🎯 Recommendation | Fonctionnalité | Scénarios | |----------------|:---------:| | [Classification de géo-pertinence des contenus](#recommendation/classification-geo) | 10 | | [Contenus géolocalisés en mode voiture](#recommendation/declenchement-geo) | 36 | | [Formule de scoring et recommandation](#recommendation/scoring-recommandation) | 21 | | [Gestion de l'historique et reproposition](#recommendation/historique-reproposition) | 19 | | [Gestion du contenu politique (MVP simplifié)](#recommendation/contenu-politique) | 13 | | [Mode Kids pour utilisateurs 13-15 ans](#recommendation/mode-kids) | 15 | | [Médias traditionnels sur RoadWave](#recommendation/medias-traditionnels) | 21 | | [Paramétrabilité admin et A/B testing](#recommendation/parametrabilite-admin) | 20 | | [Paramétrabilité utilisateur et profils](#recommendation/parametrabilite-utilisateur) | 25 | *9 fonctionnalités • 180 scénarios* ## 🔒 Rgpd Compliance | Fonctionnalité | Scénarios | |----------------|:---------:| | [Anonymisation des données GPS après 24h](#rgpd-compliance/anonymisation-gps) | 18 | | [Conformité administrative RGPD (Registre, Breach, DPO)](#rgpd-compliance/compliance-administrative) | 22 | | [Cookies et analytics avec Matomo self-hosted](#rgpd-compliance/cookies-analytics) | 20 | | [Durée de conservation des données et purge automatique](#rgpd-compliance/conservation-donnees) | 19 | | [Gestion du consentement RGPD](#rgpd-compliance/consentement) | 16 | | [Mode dégradé avec GeoIP (sans GPS précis)](#rgpd-compliance/mode-degrade-geoip) | 20 | | [Portabilité des données (Article 20 RGPD)](#rgpd-compliance/portabilite-donnees) | 22 | | [Suppression du compte utilisateur (Article 17 RGPD - Droit à l'effacement)](#rgpd-compliance/suppression-compte) | 21 | *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 à **📊 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 **📊 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 " **Quand** 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 **📊 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 **Quand** le profil est affiché **Alors** la valeur affichée est "" **📊 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 "" **Alors** les contenus sont triés par **📊 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 **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 €/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 **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 € **📊 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 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 **Quand** je calcule la consommation quotidienne moyenne **Alors** elle est de €/jour **Et** le budget sera épuisé dans 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 **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 **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 "" **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 **📊 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 minutes **Quand** l'utilisateur filtre par "" **Alors** le contenu est **📊 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 **Quand** l'utilisateur filtre par "" **Alors** le contenu est **📊 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 "