refactor(docs): réorganiser la documentation selon principes DDD

Réorganise la documentation du projet selon les principes du Domain-Driven Design (DDD) pour améliorer la cohésion, la maintenabilité et l'alignement avec l'architecture modulaire du backend.

**Structure cible:**
```
docs/domains/
├── README.md (Context Map)
├── _shared/ (Core Domain)
├── recommendation/ (Supporting Subdomain)
├── content/ (Supporting Subdomain)
├── moderation/ (Supporting Subdomain)
├── advertising/ (Generic Subdomain)
├── premium/ (Generic Subdomain)
└── monetization/ (Generic Subdomain)
```

**Changements effectués:**

Phase 1: Création de l'arborescence des 7 bounded contexts
Phase 2: Déplacement des règles métier (01-19) vers domains/*/rules/
Phase 3: Déplacement des diagrammes d'entités vers domains/*/entities/
Phase 4: Déplacement des diagrammes flux/états/séquences vers domains/*/
Phase 5: Création des README.md pour chaque domaine
Phase 6: Déplacement des features Gherkin vers domains/*/features/
Phase 7: Création du Context Map (domains/README.md)
Phase 8: Mise à jour de mkdocs.yml pour la nouvelle navigation
Phase 9: Correction automatique des liens internes (script fix-markdown-links.sh)
Phase 10: Nettoyage de l'ancienne structure (regles-metier/, diagrammes/, features/)

**Configuration des tests:**
- Makefile: godog run docs/domains/*/features/
- scripts/generate-bdd-docs.py: features_dir → docs/domains

**Avantages:**
 Cohésion forte: toute la doc d'un domaine au même endroit
 Couplage faible: domaines indépendants, dépendances explicites
 Navigabilité améliorée: README par domaine = entrée claire
 Alignement code/docs: miroir de backend/internal/
 Onboarding facilité: exploration domaine par domaine
 Tests BDD intégrés: features au plus près des règles métier

Voir docs/REFACTOR-DDD.md pour le plan complet.
This commit is contained in:
jpgiannetti
2026-02-07 17:15:02 +01:00
parent 78422bb2c0
commit 5e5fcf4714
227 changed files with 1413 additions and 1967 deletions

View File

@@ -0,0 +1,195 @@
# language: fr
Fonctionnalité: Actions complémentaires - Mode piéton
En tant qu'auditeur en mode piéton
Je veux accéder à des actions avancées depuis l'application mobile
Afin de liker explicitement, m'abonner ou signaler du contenu
Contexte:
Étant donné que l'API RoadWave est disponible
Et qu'un utilisateur est connecté
Et qu'il est en mode piéton (vitesse < 5 km/h)
Scénario: 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%
Scénario: 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
Scénario: 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%
Scénario: 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%
Scénario: 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% |
Scénario: 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% |
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: Menu contextuel avec toutes les options
Étant donné que j'utilise l'app en mode piéton
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
Scénario: 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)
Scénario: 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
Scénario: 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
Scénario: 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%
Scénario: 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
Scénario: 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:
"""
Se désabonner de @CreateurNom ?
Vous ne recevrez plus de notifications pour ses contenus.
Vos jauges diminueront de 5%.
"""
Et je dois confirmer pour valider
Et je peux annuler pour conserver l'abonnement
Plan du Scénario: Cumul like automatique + like manuel
Étant donné qu'un contenu est tagué "Sport"
Et que ma jauge "Sport" est à 50%
Quand j'écoute à <pourcentage>% (like auto <auto>)
Et que je like manuellement (+2%)
Alors l'impact total est <total>
Et ma nouvelle jauge est <nouveau_niveau>
Exemples:
| 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% |

View File

@@ -0,0 +1,266 @@
# language: fr
Fonctionnalité: 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
Contexte:
Étant donné que l'API RoadWave est disponible
Et qu'un utilisateur est connecté
Scénario: 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
Scénario: 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%
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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"
Scénario: 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:
"""
user:{user_id}:history = [
{content_id: "C3", position_seconds: 45, listened_at: "2026-01-21T10:33:00Z"},
{content_id: "C2", position_seconds: 120, listened_at: "2026-01-21T10:30:00Z"},
{content_id: "C1", position_seconds: 180, listened_at: "2026-01-21T10:27:00Z"}
]
"""
Et l'ordre est du plus récent au plus ancien
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Plan du Scénario: Comportement selon temps écouté
Étant donné que j'écoute un contenu depuis <temps> secondes
Quand j'appuie sur "Précédent"
Alors l'action est <comportement>
Exemples:
| 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 |
Plan du Scénario: Positions de reprise exactes
Étant donné que j'écoute un contenu de 10 minutes
Quand j'atteins <position> et passe au suivant
Et que je reviens via "Précédent"
Alors la lecture reprend exactement à <position>
Exemples:
| position |
| 0:15 |
| 1:30 |
| 3:45 |
| 5:00 |
| 7:23 |
| 9:50 |
# Comportement avec contenus géolocalisés
Scénario: Précédent après avoir écouté un contenu géolocalisé ≥10s
Étant donné que j'écoute un contenu buffer "C1"
Et qu'une notification géolocalisée "Tour Eiffel" apparaît
Quand j'accepte la notification (décompte 5s)
Et que le contenu géolocalisé démarre
Et que je l'écoute pendant 42 secondes
Quand j'appuie sur "Suivant" (skip)
Alors le contenu buffer suivant "C2" démarre
Et le contenu géolocalisé entre dans l'historique:
"""json
{
"id": "geo_tour_eiffel",
"position_seconds": 42,
"type": "geo_anchored"
}
"""
Quand j'appuie sur "Précédent"
Alors le contenu géolocalisé reprend à 42 secondes
Car j'ai écouté 10 secondes
Scénario: Précédent après avoir écouté un contenu géolocalisé <10s
Étant donné que j'ai accepté un contenu géolocalisé "Château"
Et que je l'ai écouté pendant 5 secondes uniquement
Quand j'appuie sur "Suivant" (skip)
Alors le contenu buffer suivant démarre
Quand j'appuie sur "Précédent"
Alors je reviens au contenu AVANT le géolocalisé
Et le contenu géolocalisé n'est PAS rejoué
Car j'ai écouté < 10 secondes
Scénario: Notification géolocalisée ignorée n'entre PAS dans historique
Étant donné que j'écoute un contenu "A"
Et qu'une notification géolocalisée apparaît (compteur 71)
Quand je n'appuie PAS sur "Suivant" (notification ignorée)
Alors le contenu "A" continue normalement
Et le contenu géolocalisé n'entre PAS dans l'historique
Quand j'appuie sur "Précédent"
Alors je reviens au contenu précédent "A-1"
Et le contenu géolocalisé ignoré n'apparaît jamais
Scénario: Annulation décompte géolocalisé n'entre PAS dans historique
Étant donné qu'une notification géolocalisée est acceptée
Et que le décompte "5" démarre (543...)
Quand j'appuie sur "Suivant" pendant le décompte (annulation)
Alors le décompte est annulé
Et le contenu buffer suivant démarre
Et le contenu géolocalisé n'entre PAS dans l'historique
Quand j'appuie sur "Précédent"
Alors je reviens au contenu avant le décompte
Et le contenu géolocalisé annulé n'apparaît jamais
Scénario: Historique mixte contenus buffer et géolocalisés
Étant donné que j'ai écouté dans l'ordre:
| contenu | type | position_seconds |
| Buffer 1 | contextuel | 180 |
| Géo Tour Eiffel | geo_anchored | 42 |
| Buffer 2 | neutre | 90 |
| Buffer 3 | contextuel | 30 |
Et que j'écoute maintenant "Buffer 4" depuis 2 secondes
Quand j'appuie sur "Précédent" (1ère fois)
Alors je reviens à "Buffer 3" à 30 secondes
Quand j'appuie sur "Précédent" (2ème fois, <10s)
Alors je reviens à "Buffer 2" à 90 secondes
Quand j'appuie sur "Précédent" (3ème fois, <10s)
Alors je reviens à "Géo Tour Eiffel" à 42 secondes
Quand j'appuie sur "Précédent" (4ème fois, <10s)
Alors je reviens à "Buffer 1" à 180 secondes
Scénario: Contenu géolocalisé dans limite FIFO 10 contenus
Étant donné que j'ai un historique de 10 contenus incluant 3 géolocalisés:
| position | contenu | type |
| 1 | Buffer 1 | contextuel |
| 2 | Géo A | geo_anchored |
| 3 | Buffer 2 | neutre |
| 4 | Géo B | geo_anchored |
| 5-9 | Buffer 3-7 | contextuel |
| 10 | Géo C | geo_anchored |
Quand j'ajoute un 11ème contenu "Buffer 8"
Alors "Buffer 1" (le plus ancien) est supprimé
Et l'historique contient:
| position | contenu |
| 1 | Géo A |
| 2 | Buffer 2 |
| ... | ... |
| 10 | Buffer 8 |
Et les contenus géolocalisés suivent la même règle FIFO

View File

@@ -0,0 +1,238 @@
# language: fr
Fonctionnalité: 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
Contexte:
Étant donné que l'API RoadWave est disponible
Et qu'un utilisateur est connecté
Et que CarPlay ou Android Auto est activé
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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]"
Scénario: 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"
Scénario: 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"
Scénario: 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
Scénario: 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
Scénario: 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'"
Scénario: 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 |
Scénario: 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
Scénario: 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
Scénario: 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:
"""
J'ai ajouté ce contenu à vos favoris
"""
Et la réponse est naturelle et concise
Et elle ne distrait pas de la conduite
Scénario: 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"
Scénario: 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")
Scénario: 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
Scénario: 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:
- Attendre l'arrêt et cliquer le bouton cœur (recommandé)
- Dire "Hey Siri, like ce podcast" (en conduite)
- Laisser le like automatique se faire (écoute 80%)
Et les 3 méthodes sont valides
Scénario: 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% |
Scénario: 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
Car je n'ai pas le téléphone en main
Scénario: 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
Scénario: 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é
Scénario: 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)
Plan du Scénario: Commandes vocales avec différents assistants
Étant donné que j'utilise <assistant>
Quand je dis <commande>
Alors l'action <action> est exécutée
Et la confirmation est <confirmation>
Exemples:
| 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é" |
Plan du Scénario: Mapping catégories signalement vocal
Étant donné que je dis "signale ce contenu pour <mot_cle>"
Quand <mot_cle> est reconnu
Alors la catégorie mappée est <categorie>
Exemples:
| 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 |

View File

@@ -0,0 +1,205 @@
# language: fr
Fonctionnalité: 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é
Contexte:
É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
Scénario: 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
Scénario: 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
Scénario: 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)
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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)
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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:
"""
{
"content_id": "abc123",
"duration": 240,
"content_total": 300,
"percentage": 80.0,
"action": "completed"
}
"""
Et le backend calcule le like automatique (+2 points)
Et les jauges sont mises à jour immédiatement (Redis + PostgreSQL)
Scénario: 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
Scénario: 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é
Scénario: 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
Scénario: 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()
Scénario: 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
Plan du Scénario: Calcul du like automatique selon pourcentage
Étant donné que j'écoute un contenu tagué "Sport"
Quand j'écoute pendant <pourcentage>%
Alors le like automatique est <type>
Et l'impact sur la jauge est <points>
Exemples:
| 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 |
Plan du Scénario: Signal négatif uniquement si skip très rapide
Étant donné que j'écoute un contenu
Quand je skip après <secondes> secondes
Alors le signal est <type>
Et l'impact est <points>
Exemples:
| 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 |

View File

@@ -0,0 +1,309 @@
# language: fr
Fonctionnalité: UI - Contenus géolocalisés en mode voiture
En tant qu'utilisateur en mode voiture
Je veux recevoir des notifications visuelles minimalistes pour contenus géolocalisés
Afin d'écouter du contenu pertinent sans distraction dangereuse
Contexte:
Étant donné que l'application RoadWave est ouverte (premier plan)
Et que l'utilisateur est connecté
Et qu'il est en mode voiture (vitesse 5 km/h)
# Affichage notification minimaliste
Scénario: Notification visuelle minimaliste 7 secondes avant arrivée
Étant donné que j'écoute un podcast "Voyage en France"
Et qu'un contenu géolocalisé "Tour Eiffel" existe à 98m
Quand l'API déclenche la notification (ETA 7s)
Alors un son bref (bip 0.5s) est joué
Et une icône 🏛 apparaît en bas de l'écran
Et un compteur "7" s'affiche en grand (72pt, bold, blanc)
Et AUCUN texte n'est affiché (pas de titre, pas de description)
Et le podcast actuel continue de jouer normalement
Scénario: Compteur décrémente visuellement pendant 7 secondes
Étant donné qu'une notification est affichée avec compteur "7"
Quand 1 seconde s'écoule
Alors le compteur affiche "6"
Quand 1 seconde s'écoule
Alors le compteur affiche "5"
Et ainsi de suite jusqu'à "1"
Quand le compteur atteint "0"
Alors la notification disparaît automatiquement
Et le contenu géolocalisé est perdu (non accepté)
Scénario: Icône correspond au tag du contenu géolocalisé
Étant donné que des contenus géolocalisés existent avec différents tags
Quand une notification est affichée
Alors l'icône correspond au tag principal:
| Tag | Icône | Couleur |
| Culture générale | 🏛 | Bleu |
| Histoire | 📜 | Marron |
| Voyage | | Vert |
| Famille | 👨👩👧 | Orange |
| Musique | 🎵 | Rose |
| Sport | | Rouge |
| Technologie | 💻 | Gris |
| Automobile | 🚗 | Noir |
| Politique | 🏛 | Bleu foncé |
| Économie | 📈 | Vert foncé |
| Cryptomonnaie | | Or |
| Santé | 🏥 | Rouge clair |
| Amour | | Rose vif |
Scénario: Notification n'affiche AUCUN texte (sécurité routière)
Étant donné qu'une notification géolocalisée apparaît
Quand je consulte l'interface
Alors je ne vois AUCUN texte à lire:
Pas de titre du contenu
Pas de description
Pas de nom du créateur
Pas de durée
Pas de bouton "Annuler" ou "Plus tard"
Et je vois uniquement:
Une icône (emoji selon tag)
Un compteur chiffré (71)
Et c'est tout (minimalisme absolu)
# Validation "Suivant" et décompte
Scénario: User appuie sur "Suivant" pendant notification
Étant donné qu'une notification affiche "5" (5 secondes restantes)
Quand j'appuie sur le bouton "Suivant" (physique ou tactile)
Alors la notification disparaît avec fade out (0.3s)
Et un nouveau compteur "5" apparaît (décompte 5 secondes)
Et le podcast actuel continue de jouer normalement
Et aucune baisse de volume n'est appliquée
Scénario: Décompte 5 secondes avec contenu actuel qui continue
Étant donné que j'ai cliqué "Suivant" pendant la notification
Et que le décompte "5" démarre
Quand les 5 secondes s'écoulent (54321)
Alors le podcast actuel joue pendant tout le décompte
Et le volume reste à 100% (pas de duck)
Quand le compteur atteint "0"
Alors le podcast actuel fait fade out (0.3s)
Et le contenu géolocalisé fait fade in (0.3s)
Et la transition est fluide sans silence
Scénario: Interface pendant décompte affiche texte contextuel
Étant donné que le décompte "3" est affiché
Quand je consulte l'écran
Alors je vois:
- Le compteur "3" en grand (72pt, centré)
- Le texte "Contenu géolocalisé arrive" en petit en dessous
- Le player actuel en haut (titre, barre de progression, contrôles)
Et l'interface est claire et non distrayante
# Contenu actuel se termine pendant décompte
Scénario: Contenu actuel se termine pendant décompte (buffer démarre)
Étant donné que j'écoute un podcast de 10 minutes
Et qu'il reste 2 secondes de lecture
Quand j'accepte un contenu géolocalisé (décompte 5s démarre)
Et que le podcast se termine après 2 secondes
Alors le contenu suivant du buffer démarre immédiatement
Et le décompte continue (321)
Quand le décompte atteint 0
Alors le contenu buffer fait fade out
Et le contenu géolocalisé fait fade in
Et il n'y a jamais de silence
# Annulation décompte
Scénario: User appuie à nouveau sur "Suivant" pendant décompte (annulation)
Étant donné que le décompte "3" est affiché
Quand j'appuie à nouveau sur "Suivant"
Alors le décompte est annulé immédiatement
Et le contenu suivant du buffer démarre
Et le contenu géolocalisé est perdu
Et il n'entre PAS dans l'historique de navigation
# Navigation avec contenus géolocalisés
Scénario: Contenu géolocalisé accepté entre dans l'historique
Étant donné que j'ai accepté un contenu géolocalisé
Et que je l'ai écouté pendant 42 secondes
Quand j'appuie sur "Suivant" (skip)
Alors le contenu buffer suivant démarre
Et le contenu géolocalisé est ajouté à l'historique:
"""json
{
"id": "geo_tour_eiffel",
"position_seconds": 42,
"listened_at": "2026-02-02T10:30:00Z",
"type": "geo_anchored"
}
"""
Scénario: Commande "Précédent" après skip contenu géolocalisé (≥10s écoutés)
Étant donné que j'ai écouté un contenu géolocalisé pendant 42 secondes
Et que j'ai skippé vers le contenu suivant
Quand j'appuie sur "Précédent"
Alors le contenu géolocalisé reprend à 42 secondes
Car j'ai écouté 10 secondes (règle standard)
Et la position exacte est restaurée
Scénario: Commande "Précédent" après skip rapide (<10s écoutés)
Étant donné que j'ai écouté un contenu géolocalisé pendant 5 secondes
Et que j'ai skippé vers le contenu suivant
Quand j'appuie sur "Précédent"
Alors le contenu AVANT le géolocalisé reprend
Car j'ai écouté < 10 secondes (règle standard)
Et le contenu géolocalisé est considéré comme non écouté
Scénario: Notification ignorée n'entre PAS dans l'historique
Étant donné qu'une notification "Tour Eiffel" s'affiche
Et que je n'appuie PAS sur "Suivant" pendant 7 secondes
Quand la notification disparaît
Et que j'appuie sur "Précédent"
Alors je reviens au contenu AVANT la notification
Et le contenu géolocalisé ignoré n'apparaît pas dans l'historique
# Conformité CarPlay / Android Auto
Scénario: Mode CarPlay désactive overlay visuel (sonore uniquement)
Étant donné que l'app est connectée à CarPlay
Et qu'un contenu géolocalisé est détecté (ETA 7s)
Quand la notification est déclenchée
Alors UNIQUEMENT un son bref (bip) est joué
Et AUCUN overlay visuel n'est affiché:
❌ Pas d'icône
❌ Pas de compteur visuel
❌ Pas de texte
Et je peux toujours appuyer sur bouton "Suivant" physique
Et le décompte 5s démarre après validation
Scénario: Mode Android Auto désactive overlay visuel (sonore uniquement)
Étant donné que l'app est connectée à Android Auto
Et qu'un contenu géolocalisé est détecté (ETA 7s)
Quand la notification est déclenchée
Alors UNIQUEMENT une notification sonore système est jouée
Et AUCUN overlay visuel n'est affiché
Et je peux appuyer sur "Suivant" pour valider
Et le comportement est identique à CarPlay
Scénario: Détection automatique CarPlay active mode sonore uniquement
Étant donné que je démarre l'app normalement (mode standard)
Quand je connecte mon téléphone à CarPlay
Alors le mode CarPlay est détecté automatiquement
Et les notifications géolocalisées passent en mode sonore uniquement
Quand je déconnecte CarPlay
Alors le mode standard reprend
Et les notifications affichent à nouveau icône + compteur
# Son de notification
Scénario: Son de notification configurable dans réglages
Étant donné que je vais dans Réglages > Notifications géolocalisées
Quand je consulte les options sonores
Alors je peux choisir:
| Option | Description |
| Bip système | Son système court (0.5s) |
| Son RoadWave personnalisé | "Ding" doux RoadWave |
| Muet | Visuel uniquement (pas de son) |
Et le volume suit le volume système notifications (pas media)
Scénario: Pas de vibration en mode voiture
Étant donné qu'une notification géolocalisée est déclenchée
Quand le son est joué
Alors AUCUNE vibration n'est déclenchée
Car le téléphone est sur support voiture
Et la vibration est inutile
# Feedback visuel
Scénario: Transition fluide après validation notification
Étant donné qu'une notification affiche "7"
Quand j'appuie sur "Suivant"
Alors la transition visuelle est fluide:
1. Fade out icône + compteur "7" (0.3s)
2. Fade in nouveau compteur "5" (0.3s)
3. Décompte 54321
4. Fade out player actuel + fade in géolocalisé (0.3s)
Et aucune transition brusque ou clignotement
Scénario: Compteur visuel grande taille pour lisibilité
Étant donné qu'une notification ou décompte est affiché
Quand je consulte l'interface
Alors le compteur respecte:
- Police: 72pt minimum
- Weight: Bold
- Couleur: Blanc (ou contraste élevé)
- Background: Noir semi-transparent (50% opacity)
- Position: Centré horizontalement, bas de l'écran
Et le chiffre est lisible en vision périphérique sans quitter la route
# Quota et cooldown (side-effects UI)
Scénario: Notification quota atteint n'affiche rien (silencieuse)
Étant donné que j'ai reçu 6 notifications géolocalisées dans l'heure
Et que je passe devant un 7ème contenu géolocalisé
Quand l'API refuse la notification (quota 429)
Alors AUCUNE notification n'est affichée côté UI
Et AUCUN son n'est joué
Et le contenu continue normalement
Et je ne suis pas interrompu
Scénario: Notification cooldown actif n'affiche rien (silencieuse)
Étant donné qu'une notification précédente a été ignorée
Et qu'un cooldown de 10 minutes est actif
Quand je passe devant un contenu géolocalisé
Alors AUCUNE notification n'est affichée
Et le refus est silencieux (pas de message d'erreur)
# Edge cases
Scénario: Haute vitesse (130 km/h) - notification 252m avant
Étant donné que je roule à 130 km/h sur autoroute
Et qu'un contenu géolocalisé existe sur mon trajet
Quand l'API détecte ETA 7s (distance 252m)
Alors la notification s'affiche avec compteur "7"
Quand j'accepte (décompte 5s)
Alors le contenu géolocalisé démarre 72m AVANT le point
Et le timing est correct même à haute vitesse
Scénario: App doit être au premier plan (mode voiture)
Étant donné que je suis en mode voiture
Et que l'app est en arrière-plan (minimisée)
Quand je passe devant un contenu géolocalisé
Alors AUCUNE notification n'est envoyée
Car l'app doit être ouverte pour mode voiture
Et la sécurité routière exige l'app visible
Scénario: Notification disparaît si user change de contexte
Étant donné qu'une notification affiche "4"
Quand je minimise l'application
Alors la notification est annulée immédiatement
Et le contenu géolocalisé est perdu
Car l'app n'est plus au premier plan
Plan du Scénario: Décompte visuel selon temps restant
Étant donné qu'une notification est affichée
Et que <temps> secondes se sont écoulées
Quand je consulte l'écran
Alors le compteur affiche <chiffre>
Exemples:
| temps | chiffre |
| 0 | 7 |
| 1 | 6 |
| 2 | 5 |
| 3 | 4 |
| 4 | 3 |
| 5 | 2 |
| 6 | 1 |
| 7 | (disparu) |
Plan du Scénario: Mode CarPlay/Android Auto selon connexion
Étant donné que l'app est <mode_initial>
Quand je <action>
Alors le mode devient <mode_final>
Et les notifications sont <type_notif>
Exemples:
| mode_initial | action | mode_final | type_notif |
| standard | connecte CarPlay | CarPlay | sonore uniquement |
| standard | connecte Android Auto | Android Auto | sonore uniquement |
| CarPlay | déconnecte CarPlay | standard | sonore + visuel |
| Android Auto | déconnecte Android Auto | standard | sonore + visuel |

View File

@@ -0,0 +1,188 @@
# language: fr
Fonctionnalité: 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
Contexte:
Étant donné que l'API RoadWave est disponible
Et qu'un utilisateur est connecté
Et que la géolocalisation est activée
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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 71 + 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
Scénario: Contenu géolocalisé ignoré est perdu (cooldown activé)
Étant donné qu'une notification géolocalisée est affichée (compteur 71)
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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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)
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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)
Plan du Scénario: 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 <distance> km
Alors la file est <action>
Exemples:
| 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 |
Scénario: 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é
Scénario: 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

View File

@@ -0,0 +1,255 @@
# language: fr
Fonctionnalité: 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
Contexte:
Étant donné que l'API RoadWave est disponible
Et qu'un utilisateur est connecté
Scénario: 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
Scénario: 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
Car l'attention des enfants est plus courte
Scénario: 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
Scénario: 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é
Scénario: 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
Scénario: 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)
Scénario: 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
Scénario: 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é
Scénario: 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
Scénario: 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 |
Scénario: 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
Scénario: É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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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)
Scénario: 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)
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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
Scénario: 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é
Plan du Scénario: Délai de transition selon mode
Étant donné que je suis en mode <mode>
Quand un contenu se termine
Alors le délai de transition est <delai> secondes
Et le message affiché est <message>
Exemples:
| mode | delai | message |
| Standard | 2 | "Contenu suivant dans 2s..." |
| Kids | 1 | "Contenu suivant dans 1s..." |
| Live | 0 | (aucun message) |
Plan du Scénario: Fréquence d'insertion des publicités
Étant donné que la fréquence pub est configurée à <frequence>
Quand j'écoute <contenus> contenus
Alors <pubs> publicités sont insérées
Exemples:
| 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 |
Plan du Scénario: Backoff exponentiel retry
Étant donné que le chargement échoue
Quand je suis à la tentative <tentative>
Alors le délai de retry est <delai> secondes
Exemples:
| tentative | delai |
| 1 | 1 |
| 2 | 2 |
| 3 | 4 |

View File

@@ -0,0 +1,265 @@
# language: fr
Fonctionnalité: Mode piéton - Notifications push et basculement automatique
En tant qu'utilisateur à pied
Je veux recevoir des notifications push pour audio-guides à proximité
Afin d'être alerté même avec l'application en arrière-plan
Contexte:
Étant donné que l'application RoadWave est installée
Et que l'utilisateur est connecté
# Détection automatique mode piéton
Scénario: Basculement automatique vers mode piéton (vitesse < 5 km/h)
Étant donné que je suis en mode voiture (vitesse 50 km/h)
Quand ma vitesse GPS moyenne passe à 3 km/h pendant 10 secondes
Alors l'application bascule automatiquement en mode piéton
Et aucune popup de confirmation n'est affichée
Et les notifications passent de "sonores + icône" à "push arrière-plan"
Et le rayon de détection passe de 7s ETA à 200 mètres
Scénario: Basculement automatique vers mode voiture (vitesse ≥ 5 km/h)
Étant donné que je suis en mode piéton (vitesse 3 km/h)
Quand ma vitesse GPS moyenne passe à 20 km/h pendant 10 secondes
Alors l'application bascule automatiquement en mode voiture
Et aucune popup de confirmation n'est affichée
Et les notifications passent de "push arrière-plan" à "sonores + icône"
Et le rayon de détection passe de 200m à 7s ETA
Scénario: Hysteresis pour éviter basculements intempestifs
Étant donné que je suis en mode piéton (vitesse 3 km/h)
Quand ma vitesse passe brièvement à 6 km/h pendant 2 secondes
Et qu'elle redescend à 3 km/h
Alors le mode piéton est conservé
Et aucun basculement n'a lieu
Car la durée de 10 secondes stables n'a pas été atteinte
Scénario: Vitesse moyenne calculée sur 30 secondes
Étant donné que je suis en mode voiture
Et que mes vitesses sur 30 secondes sont: [50, 48, 52, 3, 2, 4, 3, 2, ...]
Quand la vitesse moyenne sur 30s devient < 5 km/h
Et qu'elle reste stable pendant 10 secondes
Alors le basculement vers mode piéton s'effectue
# Permissions et activation
Scénario: Permission "While Using App" demandée au premier lancement
Étant donné que c'est le premier lancement de l'application
Quand j'arrive sur l'onboarding
Alors une demande de permission "Autoriser la localisation pendant l'utilisation" s'affiche
Et l'explication est: "RoadWave utilise votre position pour proposer des contenus audio géolocalisés adaptés à votre trajet"
Quand j'accepte
Alors le mode voiture est pleinement fonctionnel
Et le mode piéton notifications push n'est PAS encore activé
Scénario: Permission "Always" demandée uniquement si user active mode piéton
Étant donné que j'utilise RoadWave avec permission "While Using App"
Et que je vais dans Réglages > Notifications audio-guides piéton
Quand je clique sur le toggle "Activer notifications piéton"
Alors un écran d'éducation s'affiche:
"""
📍 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]
"""
Quand je clique sur "Continuer"
Alors la demande système "Autoriser toujours" (iOS) ou "Autoriser tout le temps" (Android) s'affiche
Et le mode piéton push est activé si j'accepte
Scénario: Permission arrière-plan refusée désactive mode piéton push
Étant donné que je refuse la permission "Autoriser toujours"
Quand je reviens dans l'application
Alors le toggle "Notifications piéton" est grisé et désactivé
Et un message s'affiche: "Permission refusée. Mode piéton désactivé."
Et le mode voiture reste pleinement fonctionnel
Et je peux toujours utiliser les audio-guides en mode manuel
Scénario: Permission arrière-plan peut être accordée plus tard
Étant donné que j'ai refusé la permission arrière-plan
Quand je vais dans Réglages de l'app
Alors un bouton "Activer notifications piéton" est disponible
Et un lien vers les réglages système iOS/Android est fourni
Quand j'accorde la permission dans les réglages système
Et que je reviens dans l'app
Alors le mode piéton push est automatiquement activé
# Notifications push en arrière-plan
Scénario: Notification push quand app en arrière-plan (mode piéton)
Étant donné que je suis en mode piéton
Et que l'application est en arrière-plan (fermée)
Et que je marche à proximité du Louvre
Quand je passe dans le rayon de 200 mètres d'un audio-guide
Alors une notification push système s'affiche:
"""
Audio-guide à proximité
Musée du Louvre : La Joconde - @paris_museum
"""
Et je reçois la notification même si l'app est fermée
Scénario: Tap sur notification ouvre app sur le contenu
Étant donné qu'une notification push "Audio-guide à proximité" s'affiche
Quand je tape sur la notification
Alors l'application s'ouvre
Et je suis redirigé vers la page du contenu audio-guide
Et je peux démarrer la lecture manuellement
Et je peux voir la description, le créateur, la durée, etc.
Scénario: Geofencing iOS/Android pour économie batterie
Étant donné que le mode piéton est activé
Et que l'application utilise geofencing natif
Quand je me déplace à pied
Alors l'OS iOS/Android gère la détection de proximité
Et l'application n'a pas besoin d'être constamment active
Et la batterie est préservée (< 5% consommation supplémentaire)
Scénario: Rayon de détection 200 mètres en mode piéton
Étant donné que je suis en mode piéton
Et qu'un audio-guide existe à 250 mètres
Quand je me déplace
Alors aucune notification n'est envoyée (hors rayon)
Quand je passe à 180 mètres
Alors une notification push est envoyée
Car je suis dans le rayon de 200m
# Quota anti-spam mode piéton
Scénario: Même quota 6 notifications/heure en mode piéton
Étant donné que je suis en mode piéton
Et que j'ai reçu 6 notifications push dans la dernière heure
Quand je passe près d'un 7ème audio-guide
Alors aucune notification n'est envoyée
Et le quota horaire est respecté
Scénario: Cooldown 10 min si notification ignorée (app pas ouverte)
Étant donné qu'une notification push a été envoyée
Et que je ne l'ai pas ouverte dans les 10 minutes
Quand le système détecte l'ignorance
Alors un cooldown de 10 minutes est activé
Et aucune nouvelle notification n'est envoyée pendant 10 min
# Basculement automatique
Scénario: Basculement transparent sans friction
Étant donné que je marche à 3 km/h (mode piéton)
Et que je monte dans ma voiture
Quand ma vitesse passe à 50 km/h (stable 10s)
Alors le basculement vers mode voiture s'effectue automatiquement
Et je n'ai rien à faire
Et aucune popup ne m'interrompt
Et l'expérience est transparente
Scénario: Notifications adaptées automatiquement
Étant donné que je passe de piéton (3 km/h) à voiture (50 km/h)
Quand le basculement s'effectue
Alors les notifications push arrière-plan sont désactivées
Et les notifications sonores + icône (app ouverte) sont activées
Et le rayon passe de 200m à ETA 7 secondes
Et l'adaptation est immédiate
# Garantie RGPD et fonctionnalité optionnelle
Scénario: Application utilisable sans permission arrière-plan
Étant donné que je refuse la permission "Autoriser toujours"
Quand j'utilise RoadWave
Alors le mode voiture fonctionne à 100%
Et je peux accéder à tous les audio-guides en mode manuel
Et je peux télécharger des contenus offline
Et seules les notifications push piéton sont désactivées
Scénario: Révocation permission arrière-plan désactive mode piéton
Étant donné que le mode piéton push était actif
Quand je révoque la permission dans les réglages iOS/Android
Et que j'ouvre l'application
Alors un message s'affiche: "Permission arrière-plan révoquée. Mode piéton désactivé."
Et le toggle est grisé dans les réglages
Et le mode voiture reste fonctionnel
Scénario: Désactivation mode piéton dans réglages
Étant donné que le mode piéton push est actif
Quand je vais dans Réglages > Notifications audio-guides piéton
Et que je désactive le toggle
Alors les notifications push sont arrêtées
Et le geofencing est désactivé
Et la permission arrière-plan reste accordée (mais non utilisée)
Et je peux réactiver plus tard
# Messages d'information
Scénario: Message clair sur usage permission arrière-plan
Étant donné que je consulte les réglages
Quand j'affiche les informations sur le mode piéton
Alors je vois:
"""
RoadWave utilise votre position en arrière-plan uniquement
pour vous alerter d'audio-guides à proximité quand vous
marchez. Cette fonctionnalité peut être désactivée à tout
moment. Votre position n'est jamais partagée avec des tiers.
"""
# Cas limites
Scénario: Mode indéterminé si vitesse exactement 5 km/h
Étant donné que ma vitesse moyenne est exactement 5.0 km/h
Quand le système vérifie le mode
Alors le mode actuel est conservé (pas de basculement)
Car le seuil est strict (< 5 km/h pour piéton, ≥ 5 km/h pour voiture)
Scénario: Basculement impossible si GPS désactivé
Étant donné que je désactive le GPS
Quand le système tente de détecter la vitesse
Alors aucun basculement automatique ne se produit
Et le mode actuel est conservé par défaut
Et un message "GPS désactivé" s'affiche si je tente de naviguer
Scénario: Notification push ignorée ne consomme pas de quota
Étant donné qu'une notification push est envoyée
Et que je ne l'ouvre pas (ignorée)
Quand je consulte mon quota
Alors cette notification compte quand même dans le quota 6/h
Et le cooldown 10 min est activé
Plan du Scénario: Basculement selon vitesse
Étant donné que ma vitesse moyenne est <vitesse> km/h pendant 10s
Et que je suis en mode <mode_initial>
Quand le système détecte la vitesse stable
Alors le mode devient <mode_final>
Exemples:
| vitesse | mode_initial | mode_final |
| 2 | voiture | piéton |
| 3 | voiture | piéton |
| 4 | voiture | piéton |
| 5 | piéton | voiture |
| 10 | piéton | voiture |
| 50 | piéton | voiture |
| 130 | piéton | voiture |
Plan du Scénario: Rayon de détection selon mode
Étant donné que je suis en mode <mode>
Quand un contenu géolocalisé existe à <distance>
Alors une notification est <decision>
Exemples:
| mode | distance | decision |
| piéton | 150m | envoyée |
| piéton | 199m | envoyée |
| piéton | 201m | non envoyée |
| piéton | 300m | non envoyée |
| voiture | 98m (ETA 7s) | envoyée |
| voiture | 150m (ETA 10s) | non envoyée |