# language: fr
Fonctionnalité: Multi-devices Premium - Dernier device prend priorité (KISS)
  En tant que système Premium
  Je veux appliquer une règle simple: le dernier device à démarrer prend toujours la priorité
  Afin d'éviter la complexité des exceptions temporelles et géographiques

  Contexte:
    Étant donné qu'un utilisateur "UserA" a un abonnement Premium actif
    Et que l'utilisateur possède 2 devices:
      | device     | type    |
      | iPhone_123 | iOS     |
      | iPad_456   | iOS     |

  # Règle KISS : Dernier device = Priorité

  Scénario: Transition normale - Device 2 démarre après Device 1
    Étant donné que "UserA" écoute un contenu sur iPhone_123
    Et que le heartbeat iPhone_123 est actif (toutes les 30s)
    Quand "UserA" démarre la lecture sur iPad_456 (5 secondes après)
    Alors le serveur détecte une session active (iPhone_123)
    Et envoie un WebSocket close à iPhone_123
    Et iPhone_123 affiche le message:
      """
      ⚠️ Lecture interrompue

      Votre compte est utilisé sur un autre appareil.

      Un seul appareil peut écouter à la fois avec votre compte Premium.

      Le partage de compte viole nos CGU et peut entraîner une suspension.

      [Reprendre ici] [Sécuriser mon compte]
      """
    Et Redis met à jour active_streams:UserA = {device_id: "iPad_456", started_at: timestamp}
    Et la lecture démarre sur iPad_456

  # Offline connecté internet

  Scénario: Device 1 offline MAIS connecté WiFi - Device 2 coupe Device 1
    Étant donné que "UserA" écoute un contenu téléchargé en offline sur iPhone_123
    Mais que iPhone_123 est connecté au WiFi
    Et que le heartbeat iPhone_123 est envoyé toutes les 30s
    Quand "UserA" démarre la lecture online sur iPad_456
    Alors le serveur détecte une session active (iPhone_123, mode offline)
    Et envoie un WebSocket close à iPhone_123
    Et iPhone_123 affiche le même message d'interruption
    Et iPad_456 démarre normalement

  # Offline déconnecté internet (exception technique)

  Scénario: Device 1 vraiment offline (mode avion) - Pas de détection possible
    Étant donné que "UserA" écoute un contenu offline sur iPhone_123 en mode avion
    Et qu'aucun heartbeat n'est envoyé (pas de connexion internet)
    Quand "UserA" démarre la lecture online sur iPad_456
    Alors le serveur ne détecte AUCUNE session active
    Car aucun heartbeat depuis iPhone_123
    Et iPad_456 démarre normalement
    Et iPhone_123 continue en offline (pas de coupure possible)
    Et c'est une exception technique acceptable ("Tant pis")

  Scénario: Device 1 offline reconnecte - Heartbeat reprend
    Étant donné que "UserA" écoutait offline sur iPhone_123 en mode avion
    Quand iPhone_123 sort du mode avion et se connecte au WiFi
    Alors le heartbeat reprend immédiatement
    Et Redis crée/met à jour active_streams:UserA = {device_id: "iPhone_123", started_at: timestamp}
    Et si iPad_456 démarre, iPhone_123 sera coupé normalement

  # Heartbeat et TTL Redis

  Scénario: Heartbeat toutes les 30s maintient la session active
    Étant donné que "UserA" écoute sur iPhone_123
    Quand iPhone_123 envoie un heartbeat toutes les 30 secondes
    Alors Redis met à jour active_streams:UserA avec TTL 5 minutes
    Et la session reste active tant que les heartbeats arrivent

  Scénario: Pas de heartbeat pendant 5 min - Session expirée
    Étant donné que "UserA" écoutait sur iPhone_123
    Mais que iPhone_123 a été éteint brutalement (pas de heartbeat final)
    Quand 5 minutes se sont écoulées sans heartbeat
    Alors Redis expire automatiquement l'entrée active_streams:UserA (TTL)
    Et iPad_456 peut démarrer sans détecter de conflit

  # Boutons message coupure

  Scénario: Bouton "Reprendre ici" sur device coupé
    Étant donné que iPhone_123 a été coupé par iPad_456
    Et que le message d'interruption est affiché sur iPhone_123
    Quand "UserA" clique sur [Reprendre ici] sur iPhone_123
    Alors le serveur détecte que iPad_456 est actif
    Et envoie un WebSocket close à iPad_456
    Et iPhone_123 reprend la lecture
    Et iPad_456 affiche le même message d'interruption

  Scénario: Bouton "Sécuriser mon compte" sur device coupé
    Étant donné que iPhone_123 a été coupé par iPad_456
    Et que le message d'interruption est affiché sur iPhone_123
    Quand "UserA" clique sur [Sécuriser mon compte]
    Alors l'utilisateur est redirigé vers:
      - Page changement mot de passe
      - Option "Déconnecter tous les appareils"
    Et un email de sécurité est envoyé
    Et un log de sécurité est créé (suspicion piratage)

  # Limite offline 30 jours

  Scénario: Contenus offline expirés >30j - Force reconnexion
    Étant donné que "UserA" a téléchargé 50 contenus il y a 32 jours
    Et qu'il n'a pas reconnecté son device depuis 32 jours
    Quand "UserA" essaie d'écouter un contenu offline
    Alors un message s'affiche:
      """
      Contenus expirés (>30 jours)

      Reconnectez-vous au WiFi pour renouveler vos contenus.
      """
    Et la lecture est bloquée
    Et cela force la reconnexion (détection multi-devices redevient possible)

  Scénario: Notification J-3 avant expiration contenus offline
    Étant donné que "UserA" a des contenus offline qui expirent dans 3 jours
    Quand le système détecte l'approche de l'expiration
    Alors une notification push est envoyée:
      """
      ⚠️ 10 contenus offline expirent dans 3 jours

      Reconnectez-vous au WiFi pour renouveler automatiquement.
      """

  # Détection abus post-MVP

  Scénario: Monitoring patterns suspects - Flag modération manuelle
    Étant donné que le système monitore les patterns d'utilisation
    Quand "UserA" change de device >10 fois par jour pendant 7 jours
    Alors un flag de suspicion est créé dans le dashboard modération
    Et un email d'investigation est envoyé à "UserA":
      """
      Activité suspecte détectée sur votre compte

      Nous avons détecté des changements fréquents d'appareil.

      Si ce n'est pas vous, sécurisez votre compte immédiatement.

      [Sécuriser mon compte] [Contacter le support]
      """
    Mais aucune action automatique n'est prise (évite faux positifs)

  Scénario: Connexions alternées villes éloignées - Flag modération
    Étant donné que le système monitore les localisations approximatives
    Quand "UserA" se connecte à Paris à 10h puis Marseille à 10h30 (même jour)
    Et que ce pattern se répète 5 fois en 1 semaine
    Alors un flag de suspicion est créé
    Et un modérateur humain enquête manuellement
    Mais aucun blocage automatique (évite faux positifs: TGV légitime)

  Scénario: Partage de compte confirmé - Suspension 7 jours
    Étant donné qu'un modérateur confirme manuellement un partage de compte
    Et que les preuves sont claires (signalements users + patterns suspects)
    Quand le modérateur applique la sanction
    Alors le compte est suspendu 7 jours
    Et un email de warning est envoyé:
      """
      ⚠️ Suspension de compte (7 jours)

      Le partage de compte Premium viole nos CGU.

      Votre compte est suspendu jusqu'au [Date].

      En cas de récidive, le compte sera définitivement fermé.
      """

  Scénario: Récidive partage de compte - Ban définitif
    Étant donné qu'un compte a déjà été suspendu 7 jours pour partage
    Et que le partage continue après la réactivation
    Quand le modérateur confirme la récidive
    Alors le compte est définitivement fermé (ban)
    Et un email de fermeture définitive est envoyé
    Et le remboursement pro-rata de l'abonnement est effectué

  # Cas d'usage réels

  Scénario: User change de pièce (voiture → maison) rapidement
    Étant donné que "UserA" écoute dans sa voiture sur iPhone_123
    Quand il arrive chez lui et passe sur iPad_456 après 30 secondes
    Alors iPhone_123 est coupé immédiatement
    Et iPad_456 prend le relai
    Et l'utilisateur comprend le message (device unique)

  Scénario: User oublie son téléphone en lecture et part
    Étant donné que "UserA" écoute sur iPhone_123
    Et qu'il part en laissant iPhone_123 en lecture
    Quand il démarre la lecture sur iPad_456 au travail
    Alors iPhone_123 est coupé à distance (WebSocket close)
    Et iPad_456 prend la priorité

  Scénario: TGV Paris → Lyon (légitime) - Pas de faux positif
    Étant donné que "UserA" prend le TGV Paris → Lyon
    Et qu'il écoute pendant tout le trajet sur iPhone_123
    Quand le système détecte un changement de localisation (GPS)
    Alors aucun flag de suspicion n'est créé
    Car c'est un déplacement continu légitime
    Et aucune action automatique n'est prise

  # Implémentation technique Redis

  Scénario: Stockage Redis - Structure active_streams
    Étant donné que "UserA" démarre la lecture sur iPhone_123
    Quand le heartbeat est envoyé au serveur
    Alors Redis stocke:
      | clé                  | valeur                                                |
      | active_streams:UserA | {"device_id": "iPhone_123", "started_at": 1707311400} |
    Et un TTL de 5 minutes (300 secondes) est défini
    Et la clé expire automatiquement si pas de heartbeat

  Scénario: Mise à jour Redis à chaque heartbeat
    Étant donné qu'une session active existe sur iPhone_123
    Quand un heartbeat est envoyé toutes les 30 secondes
    Alors Redis met à jour le TTL à 5 minutes
    Et started_at reste inchangé (timestamp initial)
    Et la session reste active indéfiniment tant que les heartbeats arrivent

  # Justification KISS

  Scénario: Comparaison avec règle complexe - Avantages KISS
    Étant donné qu'on compare la règle KISS avec une règle complexe (exceptions temporelles, GPS, etc.)
    Quand on évalue les avantages
    Alors les avantages KISS sont:
      | avantage                         | description                                           |
      | Simplicité technique             | Pas de tracking GPS précis, pas de calcul distances   |
      | Pas de faux positifs             | TGV légitime ne déclenche pas d'alerte automatique    |
      | Assume bonne foi                 | Majorité users honnêtes, gestion réactive suffit      |
      | Message dissuasif clair          | Avertissement CGU dans message, option sécurité       |
      | Protection revenus créateurs     | 1 abonnement = 1 personne = 1 écoute active           |
      | UX claire                        | User comprend immédiatement le comportement           |
