## 11. Mode offline ### 11.1 Téléchargement **Zone géographique** : Choix manuel utilisateur **Options prédéfinies** : - "Autour de moi" (rayon 50 km position actuelle) - "Ma ville" (limite administrative détectée) - "Mon département" (sélection liste) - "Ma région" (sélection liste) - Recherche manuelle : "Paris", "Lyon", "Marseille", etc. **Nombre de contenus téléchargeables** : | Statut | Limite | Affichage | |--------|--------|-----------| | **Gratuit** | 50 contenus max | "12/50 contenus téléchargés" | | **Premium** | Illimité | "245 contenus (3.2 GB)" | **Calcul temps disponible** : - 50 contenus × 5 min moyenne = 250 min = **4h d'écoute** (suffisant pour gratuits) - Premium illimité = limité uniquement par espace disque device **Connexion WiFi/Mobile** : **Par défaut** : WiFi uniquement **Sur données mobiles** : 1. User clique "Télécharger" 2. Détection : pas de WiFi 3. Popup : "Vous n'êtes pas connecté en WiFi. Télécharger via données mobiles consommera environ **X MB**. Continuer ?" 4. Boutons : "Attendre WiFi" / "Continuer" **Calcul estimation** : ``` Nombre contenus × durée moyenne × bitrate qualité Exemple : 20 contenus × 5 min × 48 kbps = ~72 MB ``` **Qualité audio téléchargement** : | Qualité | Bitrate | Taille | Disponibilité | |---------|---------|--------|---------------| | **Basse** | 24 kbps | ~10 MB/h | Gratuit + Premium | | **Standard** | 48 kbps | ~20 MB/h | Gratuit + Premium (défaut) | | **Haute** | 64 kbps | ~30 MB/h | **Premium uniquement** | **Justification** : - Standard = bon compromis qualité/taille (Opus 48 kbps = très correct pour voix) - Haute réservée Premium = incitation upgrade - User peut réduire à "basse" si espace limité --- ### 11.2 Validité et renouvellement **Durée de validité** : 30 jours après téléchargement **Standard industrie** : - Spotify : 30 jours - YouTube Music : 30 jours - Deezer : 30 jours **Renouvellement automatique** : ``` App détecte WiFi + contenus >25 jours → Requête API : GET /offline/contents/refresh → Backend vérifie pour chaque contenu : - Abonnement Premium toujours actif ? - Contenu pas modéré/supprimé ? - Métadonnées à jour ? → Renouvelle validité à 30 jours supplémentaires → Mise à jour métadonnées (titre, créateur, statut) → Pas de re-téléchargement audio (sauf si fichier corrompu) ``` **Notification avant expiration** : - **J-3** : "X contenus expirent dans 3 jours. Connectez-vous en WiFi pour les renouveler" - **J-0** : Suppression automatique - **J+0** : Toast "15 contenus expirés ont été supprimés" **Justification** : - **Force reconnexion** : vérifier abonnement actif, contenus légaux - **Évite stockage obsolète** : contenus supprimés/modérés ne restent pas - **UX transparente** : renouvellement silencieux si WiFi régulier --- ### 11.3 Synchronisation actions offline **Actions stockées localement (SQLite)** : - Likes/unlikes - Abonnements/désabonnements - Signalements - Progression audio-guides **Sync automatique à la reconnexion** : ``` 1. App détecte reconnexion Internet 2. Récupération queue locale : SELECT * FROM pending_actions ORDER BY created_at 3. Envoi batch API : POST /sync/actions 4. Backend traite chaque action 5. Confirmation réception : DELETE FROM pending_actions WHERE id IN (...) 6. Toast : "3 likes et 1 abonnement synchronisés" ``` **Gestion erreurs sync** : - Si échec après 3 tentatives → notification : "Impossible de synchroniser. Réessayez plus tard" - Actions conservées jusqu'à sync réussie (pas de perte) - **Rétention max 7 jours** : après = purge (évite queue infinie) **Justification** : - **Pas de conflit possible** : actions unilatérales user (likes/abonnements) - **UX fluide** : pas de blocage offline - **Batch = économie** : requêtes HTTP groupées --- ### 11.4 Contenus supprimés pendant offline **Problème** : Que se passe-t-il si un utilisateur télécharge des contenus, part offline plusieurs jours, et pendant ce temps certains contenus sont supprimés par les créateurs ou la modération ? **Décision** : Suppression immédiate à la reconnexion (Option A - KISS) #### Processus de synchronisation ``` User se reconnecte (WiFi détecté) ↓ 1. API sync : GET /offline/validate Backend retourne : { "valid_ids": [id1, id2, id3, ...], "deleted_ids": [id10, id12, id15], "metadata_updates": [{id: id5, new_title: "..."}] } 2. App mobile compare avec contenus locaux : - valid_ids : renouvelle validité 30j - deleted_ids : suppression immédiate fichiers locaux - metadata_updates : mise à jour titre/créateur/tags 3. Notification user : Toast : "3 contenus supprimés ont été retirés" ``` #### Gestion contenu en cours d'écoute **Si contenu supprimé en cours de lecture** : ``` ┌────────────────────────────────────────┐ │ Contenu supprimé │ ├────────────────────────────────────────┤ │ Ce contenu n'est plus disponible │ │ et a été retiré par le créateur. │ │ │ │ Passage au contenu suivant... │ │ │ │ [OK] │ └────────────────────────────────────────┘ → Lecture s'arrête → Fichier supprimé localement → Passage automatique au contenu suivant (après 2s) ``` #### Message récapitulatif **Si plusieurs contenus supprimés** : ``` ┌────────────────────────────────────────┐ │ Contenus supprimés │ ├────────────────────────────────────────┤ │ 3 contenus téléchargés ne sont plus │ │ disponibles et ont été retirés. │ │ │ │ Les créateurs peuvent supprimer ou │ │ modifier leurs contenus à tout moment. │ │ │ │ [Voir la liste] [OK] │ └────────────────────────────────────────┘ ``` **Bouton "Voir la liste"** : - Affiche titres + créateurs des contenus supprimés - Permet comprendre ce qui a disparu - Historique conservé 7 jours (puis purge) **Justification KISS** : - ✅ **Simplicité technique** : pas de grace period complexe, pas de gestion d'états intermédiaires - ✅ **Respect créateur** : si créateur supprime = volonté claire immédiate, pas de diffusion prolongée - ✅ **Conformité légale** : contenu modéré (illégal, violation CGU) retiré immédiatement, pas de risque juridique - ✅ **Cas rare** : peu de créateurs suppriment contenus après publication, impact user limité **Post-MVP** : Si feedback négatifs users ("J'étais en train d'écouter et ça s'est coupé brutalement !"), ajouter grace period UNIQUEMENT pour suppression créateur volontaire : - Motif suppression = "modération RoadWave" → Suppression immédiate (sécurité/légalité) - Motif suppression = "créateur volontaire" → Grace period 7 jours + badge "Bientôt retiré" - Motif suppression = "passage Premium" → Si user Premium : conserve accès, si gratuit : grace period 7j **Mais attendre feedback réel avant d'ajouter cette complexité.** --- ## Récapitulatif Section 11 | Aspect | Décision | Valeur | |--------|----------|--------| | **Zone téléchargement** | Choix | Manuel (autour/ville/département/région/recherche) | | **Limite gratuit** | Contenus | 50 max | | **Limite Premium** | Contenus | Illimité (espace disque) | | **Connexion** | Par défaut | WiFi (mobile avec confirmation) | | **Qualité Standard** | Bitrate | 48 kbps Opus | | **Qualité Haute** | Bitrate | 64 kbps (Premium uniquement) | | **Validité** | Durée | 30 jours | | **Renouvellement** | Mode | Automatique si WiFi | | **Notification expiration** | Délai | J-3 | | **Sync actions** | Mode | Batch automatique reconnexion | | **Rétention queue** | Durée | 7 jours max | ---