Résolution des incohérences #10, #11, et #12 de l'analyse d'architecture. ## Phase 1 : Réorganisation Features BDD (Point #10 - RÉSOLU) - Créer structure features/{api,ui,e2e} - Déplacer 83 features en 3 catégories via git mv (historique préservé) - features/api/ : 53 features (tests API backend) - features/ui/ : 22 features (tests UI mobile) - features/e2e/ : 8 features (tests end-to-end) Domaines déplacés : - API : authentication, recommendation, rgpd-compliance, content-creation, moderation, monetisation, premium, radio-live, publicites - UI : audio-guides, navigation, interest-gauges, mode-offline, partage, profil, recherche - E2E : abonnements, error-handling ## Phase 2 : Mise à jour Documentation ### ADR-007 - Tests BDD - Ajouter section "Convention de Catégorisation des Features" - Documenter règles api/ui/e2e avec exemples concrets - Spécifier step definitions (backend Go, mobile Dart) ### ADR-024 - Stratégie CI/CD Monorepo (NOUVEAU) - Créer ADR dédié pour stratégie CI/CD avec path filters - Architecture workflows séparés (backend.yml, mobile.yml, shared.yml) - Configuration path filters détaillée avec exemples YAML - Matrice de déclenchement et optimisations (~70% gain temps CI) - Plan d'implémentation (~2h, reporté jusqu'au développement) ### ADR-016 - Organisation Monorepo - Simplifier en retirant section CI/CD détaillée - Ajouter référence vers ADR-024 pour stratégie CI/CD ### INCONSISTENCIES-ANALYSIS.md - Point #10 (Tests BDD synchronisés) : ✅ RÉSOLU - Catégorisation features implémentée - ADR-007 mis à jour avec convention complète - Point #11 (70/30 Split paiements) : ✅ ANNULÉ (faux problème) - ADR-009 et Règle 18 parfaitement cohérents - Documentation exhaustive existante (formule, SQL, comparaisons) - Point #12 (Monorepo path filters) : ⏸️ DOCUMENTÉ - Architecture CI/CD complète dans ADR-024 - Implémentation reportée (projet en phase documentation) - Métriques mises à jour : - MODERATE : 6/9 traités (4 résolus + 1 annulé + 1 documenté) - ADR à jour : 100% (19/19 avec ADR-024) ## Phase 3 : Validation - Structure features validée (api/ui/e2e, aucun répertoire restant) - Historique Git préservé (git mv, renommages détectés) - 83 features total (API: 53, UI: 22, E2E: 8) Closes: Point #10 (résolu), Point #11 (annulé), Point #12 (documenté) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
280 lines
12 KiB
Gherkin
280 lines
12 KiB
Gherkin
# language: fr
|
||
Fonctionnalité: 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
|
||
|
||
Contexte:
|
||
Étant donné que je suis un utilisateur Premium actif
|
||
Et que mon compte est valide
|
||
|
||
# ===== LIMITE 1 STREAM ACTIF =====
|
||
|
||
Scénario: 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}
|
||
|
||
Scénario: 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
|
||
|
||
Scénario: 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:
|
||
"""
|
||
🔴 Lecture interrompue
|
||
|
||
Votre compte Premium est utilisé sur un autre appareil.
|
||
|
||
Un seul stream actif est autorisé à la fois pour protéger
|
||
les revenus des créateurs et éviter le partage de compte.
|
||
"""
|
||
Et un bouton "Reprendre ici" est disponible
|
||
|
||
Scénario: 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)
|
||
|
||
# ===== IMPLÉMENTATION TECHNIQUE REDIS =====
|
||
|
||
Scénario: 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:
|
||
```
|
||
Key: active_streams:{user_id}
|
||
Value: {
|
||
"device_id": "iPhone-ABC123",
|
||
"started_at": "2025-06-15T14:30:00Z",
|
||
"content_id": "xyz789"
|
||
}
|
||
TTL: 300 secondes (5 minutes)
|
||
```
|
||
|
||
Scénario: 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
|
||
|
||
Scénario: 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
|
||
|
||
Scénario: 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
|
||
|
||
Scénario: 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))
|
||
|
||
# ===== EXCEPTIONS ET CAS PARTICULIERS =====
|
||
|
||
Scénario: 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
|
||
Car le contenu offline ne consomme pas de bande passante serveur
|
||
|
||
Scénario: 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
|
||
|
||
Scénario: 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", ...}
|
||
|
||
Scénario: 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"
|
||
|
||
# ===== JUSTIFICATIONS =====
|
||
|
||
Scénario: 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
|
||
|
||
Scénario: 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
|
||
|
||
Scénario: 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
|
||
|
||
Scénario: 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
|
||
|
||
Scénario: 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)
|
||
|
||
# ===== MONITORING ET DÉTECTION ABUS =====
|
||
|
||
Scénario: 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
|
||
|
||
Scénario: 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
|
||
|
||
Scénario: 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 |
|
||
|
||
Scénario: 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:
|
||
"""
|
||
⚠️ Activité inhabituelle détectée sur votre compte
|
||
|
||
Nous avons détecté un nombre anormalement élevé de changements de device (30/jour).
|
||
|
||
Rappel: Le partage de compte Premium est interdit selon nos CGU.
|
||
Un seul stream actif est autorisé à la fois.
|
||
|
||
Si cette activité continue, votre compte pourra être suspendu.
|
||
"""
|
||
|
||
Scénario: 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
|
||
|
||
# ===== SUPPORT UTILISATEUR =====
|
||
|
||
Scénario: 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:
|
||
"""
|
||
Q: Pourquoi ma lecture s'arrête quand j'utilise un autre appareil ?
|
||
|
||
R: Votre abonnement Premium autorise 1 seul stream actif à la fois.
|
||
Si vous lancez la lecture sur un autre appareil, le premier est automatiquement arrêté.
|
||
|
||
Pourquoi cette limite ?
|
||
- Protéger les revenus des créateurs (1 abonnement = 1 personne)
|
||
- Éviter le partage de compte abusif
|
||
|
||
Vous pouvez utiliser autant d'appareils que vous voulez, mais un seul peut lire à la fois.
|
||
"""
|
||
|
||
Scénario: 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é
|
||
|
||
Scénario: 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
|
||
|
||
# ===== TESTS TECHNIQUES =====
|
||
|
||
Scénario: 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é
|
||
|
||
Scénario: 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)
|
||
|
||
Scénario: 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é
|
||
|
||
Scénario: 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
|