# language: fr Fonctionnalité: Synchronisation actions offline En tant qu'utilisateur Je veux que mes actions offline soient synchronisées quand je me reconnecte Afin de ne perdre aucune interaction même sans connexion Contexte: Étant donné que j'utilise l'application RoadWave # ===== ACTIONS STOCKÉES LOCALEMENT ===== Scénario: Like d'un contenu en mode offline Étant donné que je n'ai aucune connexion Internet Quand je like un contenu téléchargé Alors l'action est enregistrée localement dans SQLite: ```sql INSERT INTO pending_actions (type, content_id, created_at) VALUES ('like', 'abc123', '2025-06-15 14:30:00'); ``` Et l'UI affiche immédiatement le like (optimistic update) Scénario: Unlike d'un contenu en mode offline Étant donné que je n'ai aucune connexion Internet Et que j'avais liké un contenu Quand je retire mon like Alors l'action est enregistrée localement: ```sql INSERT INTO pending_actions (type, content_id, created_at) VALUES ('unlike', 'abc123', '2025-06-15 14:35:00'); ``` Et l'UI retire immédiatement le like Scénario: Abonnement à un créateur en mode offline Étant donné que je n'ai aucune connexion Internet Quand je m'abonne à un créateur Alors l'action est enregistrée localement: ```sql INSERT INTO pending_actions (type, creator_id, created_at) VALUES ('subscribe', 'creator456', '2025-06-15 14:40:00'); ``` Et l'UI affiche immédiatement "Abonné ✓" Scénario: Désabonnement d'un créateur en mode offline Étant donné que je n'ai aucune connexion Internet Et que j'étais abonné à un créateur Quand je me désabonne Alors l'action est enregistrée localement: ```sql INSERT INTO pending_actions (type, creator_id, created_at) VALUES ('unsubscribe', 'creator456', '2025-06-15 14:45:00'); ``` Et l'UI affiche "S'abonner" Scénario: Signalement d'un contenu en mode offline Étant donné que je n'ai aucune connexion Internet Quand je signale un contenu pour "Contenu inapproprié" Alors l'action est enregistrée localement: ```sql INSERT INTO pending_actions (type, content_id, reason, created_at) VALUES ('report', 'abc123', 'Contenu inapproprié', '2025-06-15 14:50:00'); ``` Et je vois "Signalement enregistré. Sera envoyé à la reconnexion." Scénario: Progression audio-guide en mode offline Étant donné que je n'ai aucune connexion Internet Et que j'écoute un audio-guide multi-séquences Quand je termine la séquence 3/10 Alors la progression est enregistrée localement: ```sql INSERT INTO pending_actions (type, guide_id, sequence_id, created_at) VALUES ('guide_progress', 'guide789', 'seq003', '2025-06-15 15:00:00'); ``` Et ma progression est sauvegardée Scénario: Multiple actions offline stockées en queue Étant donné que je n'ai aucune connexion Internet pendant 2 jours Quand j'effectue plusieurs actions: | action | cible | | like | contenu A | | like | contenu B | | subscribe | créateur X | | unlike | contenu C | | report | contenu D | Alors les 5 actions sont stockées dans pending_actions Et elles seront synchronisées dans l'ordre à la reconnexion # ===== SYNCHRONISATION AUTOMATIQUE ===== Scénario: Détection reconnexion Internet Étant donné que j'étais en mode offline Quand l'app détecte une reconnexion Internet Alors le processus de synchronisation démarre automatiquement Et je vois une notification "Synchronisation en cours..." Scénario: Récupération queue locale pendant sync Étant donné que la synchronisation démarre Quand l'app récupère les actions en attente Alors une requête SQL est exécutée: ```sql SELECT * FROM pending_actions ORDER BY created_at ASC; ``` Et toutes les actions sont récupérées dans l'ordre chronologique Scénario: Envoi batch API des actions Étant donné que 15 actions sont en attente Quand le batch est envoyé au backend Alors une requête POST /sync/actions est faite: ```json { "actions": [ {"type": "like", "content_id": "abc123", "timestamp": "2025-06-15T14:30:00Z"}, {"type": "subscribe", "creator_id": "creator456", "timestamp": "2025-06-15T14:40:00Z"}, {"type": "unlike", "content_id": "def789", "timestamp": "2025-06-15T14:50:00Z"}, ... ] } ``` Et toutes les actions sont groupées en une seule requête Scénario: Backend traite chaque action Étant donné que le backend reçoit le batch d'actions Quand il traite chaque action Alors pour chaque action: | étape | détail | | Validation | Vérifier user_id, content_id valides | | Vérification existence | Contenu/créateur existe toujours ? | | Application action | INSERT/UPDATE/DELETE en base | | Mise à jour compteurs | Likes, abonnés, etc. | | Impact sur algorithme | Mise à jour jauges si nécessaire | Scénario: Confirmation réception et suppression queue locale Étant donné que le backend a traité toutes les actions avec succès Quand la confirmation est reçue par l'app Alors les actions sont supprimées de la queue locale: ```sql DELETE FROM pending_actions WHERE id IN (1, 2, 3, ..., 15); ``` Et la table pending_actions est vidée Scénario: Toast confirmation synchronisation Étant donné que 15 actions ont été synchronisées Quand la synchronisation se termine Alors je vois un toast: """ ✅ Synchronisation réussie 3 likes, 1 abonnement et 1 signalement synchronisés. """ Scénario: Synchronisation silencieuse si peu d'actions Étant donné que j'ai seulement 2 actions en attente Quand la synchronisation se termine Alors aucun toast n'est affiché (sync silencieuse) Et l'expérience reste fluide Mais je peux voir le détail dans l'historique des syncs # ===== GESTION ERREURS SYNC ===== Scénario: Échec synchronisation - Retry automatique Étant donné que la synchronisation échoue (erreur réseau) Quand l'échec est détecté Alors un retry automatique est programmé dans 30 secondes Et les actions restent dans pending_actions Scénario: 3 tentatives échouées - Notification utilisateur Étant donné que 3 tentatives de synchronisation ont échoué Quand la 3ème tentative échoue Alors je reçois une notification: """ ⚠️ Impossible de synchroniser vos actions 15 actions en attente de synchronisation. Vérifiez votre connexion et réessayez. [Réessayer maintenant] [Plus tard] ``` Scénario: Actions conservées jusqu'à sync réussie Étant donné que la synchronisation échoue plusieurs fois Quand les tentatives continuent d'échouer Alors les actions restent dans pending_actions Et aucune action n'est perdue Et elles seront envoyées dès que la connexion sera stable Scénario: Rétention max 7 jours - Purge automatique Étant donné qu'une action est en attente depuis 7 jours Quand le système détecte cette ancienneté Alors l'action est automatiquement supprimée de la queue Et je vois "1 action trop ancienne supprimée (>7 jours)" Et cela évite une queue infinie Scénario: Justification rétention 7 jours Étant donné qu'un utilisateur ne se connecte jamais pendant 2 semaines Quand ses actions ont >7 jours Alors elles sont purgées automatiquement Car après 7 jours, l'action perd sa pertinence Et évite une queue qui grandit indéfiniment Scénario: Retry manuel après échec Étant donné que la synchronisation a échoué Quand je clique sur "Réessayer maintenant" Alors une nouvelle tentative de synchronisation est lancée immédiatement Et si elle réussit, les actions sont synchronisées # ===== CONFLITS CONTENUS SUPPRIMÉS ===== Scénario: Backend retourne contenus supprimés Étant donné que j'ai liké un contenu offline Mais que le contenu a été supprimé entre temps Quand le backend traite la synchronisation Alors il retourne: ```json { "status": "partial_success", "deleted_content_ids": [123, 456], "failed_actions": [ {"type": "like", "content_id": "123", "reason": "content_deleted"} ] } ``` Scénario: App supprime fichiers locaux contenus supprimés Étant donné que le backend retourne deleted_content_ids: [123, 456] Quand l'app traite la réponse Alors elle supprime les fichiers locaux des contenus 123 et 456 Et libère l'espace disque Et les actions associées sont retirées de la queue Scénario: Contenu supprimé en cours d'écoute Étant donné que j'écoute le contenu 123 en offline Et que la sync détecte que le contenu a été supprimé Quand la lecture actuelle se termine Alors l'app attend 2 secondes Et passe automatiquement au contenu suivant Et le fichier du contenu 123 est supprimé en arrière-plan Scénario: Toast notification contenu retiré Étant donné que 2 contenus téléchargés ont été supprimés Quand la synchronisation se termine Alors je vois un toast: """ 🗑️ 2 contenus téléchargés ont été retirés Raison: Violation des règles de la plateforme """ Scénario: Contenu modéré après téléchargement Étant donné que j'ai téléchargé un contenu qui est ensuite modéré Quand la synchronisation détecte la modération Alors le contenu est immédiatement supprimé du device Et je ne peux plus l'écouter Et cela garantit la conformité même offline # ===== JUSTIFICATIONS ===== Scénario: Justification pas de conflit possible Étant donné que les actions offline sont unilatérales (likes, abonnements) Quand elles sont synchronisées Alors il n'y a pas de conflit de version possible Car l'utilisateur ajoute/retire simplement des préférences Et pas de merge complexe nécessaire Scénario: Justification UX fluide offline Étant donné que toutes les actions fonctionnent offline Quand l'utilisateur interagit sans connexion Alors l'expérience est identique au mode online Et l'utilisateur n'est pas bloqué Et peut utiliser l'app normalement Scénario: Justification batch = Économie requêtes Étant donné que 15 actions sont en attente Quand elles sont synchronisées en batch Alors 1 seule requête HTTP est envoyée (vs 15 si individuelles) Et cela économise la bande passante et la batterie Et réduit la charge serveur Scénario: Justification conformité modération offline Étant donné qu'un contenu illégal est modéré pendant qu'un user est offline Quand le user se reconnecte Alors le contenu est immédiatement supprimé de son device Et cela garantit que les contenus illégaux disparaissent même offline # ===== STATISTIQUES ET MONITORING ===== Scénario: Historique synchronisations Étant donné que j'accède à "Paramètres > Synchronisation" Quand je consulte l'historique Alors je vois: | date | actions sync | statut | | 15/06/2025 14:30:00 | 15 | Réussi ✅ | | 14/06/2025 09:15:00 | 7 | Réussi ✅ | | 13/06/2025 18:45:00 | 3 | Échec ❌ | Scénario: Détail d'une synchronisation Étant donné que je clique sur une ligne de l'historique Quand le détail s'affiche Alors je vois: ``` Synchronisation du 15/06/2025 14:30:00 Actions synchronisées: • 3 likes • 1 abonnement • 1 signalement • 10 progressions audio-guides Durée: 1.2s Statut: Réussi ✅ ``` Scénario: Compteur actions en attente visible Étant donné que j'ai 12 actions en attente de synchronisation Quand j'accède à l'onglet Profil Alors je vois un badge "12" sur l'icône de synchronisation Et je sais qu'il y a des actions en attente Scénario: Synchronisation manuelle forcée Étant donné que je veux forcer une synchronisation immédiate Quand je vais dans "Paramètres > Synchronisation" Et que je clique sur "Synchroniser maintenant" Alors la synchronisation démarre immédiatement Et toutes les actions en attente sont envoyées Scénario: Statistiques utilisateur - Syncs effectuées Étant donné que j'accède à mes statistiques Quand je consulte la section Synchronisation Alors je vois: | métrique | valeur | | Synchronisations depuis début | 87 | | Actions synchronisées total | 1,234 | | Taux de succès | 94% | | Dernière sync | Il y a 2h| Scénario: Statistiques admin - Volume synchronisations Étant donné qu'un admin consulte les métriques de synchronisation Quand il accède au dashboard Alors il voit: | métrique | valeur | | Synchronisations/jour | 45,678 | | Actions synchronisées/jour | 234,567 | | Taux succès sync | 96.5% | | Temps moyen traitement batch | 0.8s | | Actions en attente (global) | 12,345 | Scénario: Alerte admin si taux échec sync >10% Étant donné que le taux d'échec sync dépasse 10% Quand le système détecte cette anomalie Alors une alerte est envoyée: """ ⚠️ Taux échec synchronisation anormal: 12.3% Échecs aujourd'hui: 5,621 / 45,678 syncs Causes principales: - Timeout serveur: 3,245 - Erreur réseau client: 1,876 - Données invalides: 500 Action recommandée: Vérifier charge serveur + logs erreurs """ # ===== TESTS PERFORMANCE ===== Scénario: Synchronisation rapide <2s Étant donné que j'ai 20 actions en attente Quand la synchronisation démarre Alors le traitement prend <2 secondes Et je ne remarque aucun ralentissement de l'app Scénario: Synchronisation de gros batch (100 actions) Étant donné que je n'ai pas synchronisé pendant 1 semaine Et que j'ai 100 actions en attente Quand la synchronisation démarre Alors le batch de 100 actions est traité en <5 secondes Et toutes les actions sont synchronisées avec succès Scénario: Gestion charge serveur - 10 000 syncs simultanées Étant donné que 10 000 utilisateurs se reconnectent simultanément Quand chacun envoie un batch de 20 actions Alors le serveur traite 200 000 actions Et grâce au traitement asynchrone (queue Redis), le temps de réponse reste <3s Et aucun timeout n'est constaté Scénario: Stockage SQLite optimisé Étant donné que la table pending_actions stocke des centaines d'actions Quand des requêtes sont exécutées Alors la table est indexée sur created_at Et les requêtes SELECT et DELETE sont instantanées (<10ms) Et l'expérience utilisateur reste fluide Scénario: Nettoyage automatique table pending_actions Étant donné que la table pending_actions grossit avec le temps Quand les actions sont synchronisées et supprimées Alors la table est automatiquement optimisée (VACUUM sur SQLite) Et l'espace disque est libéré Et les performances restent optimales # ===== EDGE CASES ===== Scénario: Action dupliquée - Idempotence Étant donné que j'ai liké un contenu offline Et que la sync échoue et retry Quand le backend reçoit 2 fois le même like Alors il applique l'idempotence (1 seul like enregistré) Et le compteur de likes n'est pas faussé Scénario: Séquence like/unlike offline Étant donné que j'ai liké puis unliké un contenu offline Quand les 2 actions sont synchronisées Alors le backend applique les 2 actions dans l'ordre Et le résultat final est "pas de like" (état correct) Scénario: Abonnement puis désabonnement offline Étant donné que je me suis abonné puis désabonné d'un créateur offline Quand les 2 actions sont synchronisées Alors le backend applique les 2 actions dans l'ordre Et le résultat final est "pas abonné" Et les jauges évoluent correctement (+5% puis -5% = 0% net) Scénario: Créateur supprimé pendant offline Étant donné que je me suis abonné à un créateur offline Mais que le créateur a supprimé son compte entre temps Quand la sync traite l'abonnement Alors le backend retourne "creator_deleted" Et l'action est ignorée silencieusement Et aucune erreur n'est affichée à l'utilisateur