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:
@@ -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é (7→1)
|
||||
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 (5→4→3→2→1)
|
||||
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 (3→2→1)
|
||||
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 5→4→3→2→1
|
||||
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 |
|
||||
Reference in New Issue
Block a user