# QUEUE-APP-API.md # Système de File d'Attente pour les Requêtes API Hors Ligne ## 🚀 État actuel de l'implémentation (29/08/2025) ### ✅ Phases complétées - **Phase 1** : Infrastructure de base - COMPLÉTÉ - **Phase 2** : Modification ApiService - COMPLÉTÉ - **Phase 3** : Intégration ConnectivityService - COMPLÉTÉ - **Phase 5** : Alertes utilisateur - COMPLÉTÉ - **Phase 6** : Adaptation des Repositories CRUD - COMPLÉTÉ (tous les 8 repositories) ### ⚠️ Décisions d'architecture importantes 1. **Pas d'IDs temporaires** : La base de données MariaDB utilise des `int unsigned`, donc pas de valeurs négatives possibles 2. **Stratégie sans stockage local pour CREATE** : - CREATE offline → Requête en queue, pas de stockage Hive, message "Création en attente" - UPDATE offline → Modification locale avec `isSynced: false` + requête en queue - DELETE offline → Suppression locale immédiate + requête en queue 3. **Pas d'expiration automatique** : Les requêtes persistent indéfiniment jusqu'à leur envoi 4. **Ordre FIFO strict** : Basé sur `createdAt` pour garantir la cohérence ### 📦 Repositories adaptés (8/8) | Repository | CREATE offline | UPDATE offline | DELETE offline | Notes | |------------|---------------|----------------|----------------|--------| | **PassageRepository** | ✅ Queue + Dialog + Pas de stockage | ✅ Stockage local + Flag | ✅ Suppression immédiate | Priorité haute terrain | | **ClientRepository** | ✅ Queue + Dialog + Pas de stockage | ✅ Stockage local | ✅ Suppression immédiate | Adhérents terrain | | **MembreRepository** | ✅ Queue + Dialog + Retourne null | ✅ Stockage local | ✅ Suppression immédiate | Gestion équipe | | **SectorRepository** | ✅ Queue + Dialog + Status "queued" | ✅ Stockage local | ✅ Suppression + passages | Gère aussi les passages | | **UserRepository** | N/A | ✅ Stockage avec isSynced=false | N/A | Profil utilisateur connecté uniquement | | **AmicaleRepository** | ✅ Queue + Dialog + Pas de stockage | ✅ Stockage local | ✅ Suppression immédiate | Organisation | | **OperationRepository** | ✅ Queue + Dialog + Pas de stockage | ✅ Stockage avec isSynced=false | ✅ Suppression + données liées | Campagnes | ### 📊 Réponses API en mode offline Toutes les requêtes stockées en pending retournent : ```json { "queued": true } ``` ### 🔄 Prochain travail - Implémenter la gestion des conflits de synchronisation - Ajouter la limite de queue (1000 requêtes max) - Créer le système d'export des données en attente - Ajouter un dialog de confirmation lors de la déconnexion avec données en attente - Tester le système complet en mode avion --- ## 📋 Vue d'ensemble ### Objectif Créer un système robuste de gestion des requêtes API en mode hors ligne pour permettre à l'application de fonctionner sans connexion Internet et de synchroniser automatiquement les données dès que la connexion est rétablie. ### Problématique actuelle - Les requêtes API échouent immédiatement sans connexion - Aucun mécanisme de file d'attente pour les requêtes en attente - Les messages du chat sont perdus si envoyés hors ligne - Les modifications CRUD ne sont pas persistées localement pour envoi ultérieur ### Solution proposée Modifier `ApiService` pour qu'il gère automatiquement la file d'attente : stockage dans Hive si hors ligne, envoi direct si en ligne, et traitement automatique de la queue au retour de connexion. ## 🏗️ Architecture ### Flux de données ``` Application (UI/Repository) ↓ ApiService (modifié) ↓ [Si en ligne] → Envoi direct → API ↓ [Si hors ligne] → Stockage → Hive Box "pending_requests" ConnectivityService (écoute en permanence) ↓ [Connexion rétablie] → Notifie ApiService ↓ ApiService.processPendingRequests() → API ``` ### Services impliqués 1. **ApiService** (à modifier) - Vérifie la connectivité avant chaque requête - Si online : envoi direct à l'API - Si offline : stockage dans Hive Box - Méthode `processPendingRequests()` pour vider la queue - Retourne une réponse "pending" avec tempId si offline 2. **ConnectivityService** (à enrichir) - Détecte les changements de connexion - Appelle `ApiService.processPendingRequests()` au retour - Vérifie périodiquement s'il y a des requêtes en attente 3. **Hive Boxes** (nouvelles) - `pending_requests` : File d'attente des requêtes (JAMAIS supprimée si non vide) - `temp_entities` : Entités temporaires (messages temp_, etc.) ## 📊 Analyse des requêtes actuelles ### 1. Chat Service - **POST** `/chat/rooms` - Créer une conversation - **POST** `/chat/rooms/{roomId}/messages` - Envoyer un message - **GET** `/chat/rooms` - Obtenir les conversations - **GET** `/chat/rooms/{roomId}/messages` - Obtenir les messages - **DELETE** `/chat/rooms/{roomId}` - Supprimer une conversation ### 2. User Repository - **GET** `/users` - Liste des utilisateurs - **GET** `/users/{id}` - Détail utilisateur - **POST** `/users` - Créer utilisateur - **PUT** `/users/{id}` - Modifier utilisateur - **DELETE** `/users/{id}` - Supprimer utilisateur ### 3. Amicale Repository - **GET** `/entites` - Liste des amicales - **PUT** `/entites/{id}` - Modifier amicale - **POST** `/entites/{id}/logo` - Upload logo ### 4. Operations/Passages - **GET** `/operations` - Liste des opérations - **POST** `/passages` - Créer un passage - **PUT** `/passages/{id}` - Modifier un passage - **GET** `/operations/{id}/export/excel` - Export Excel ### 5. Authentification - **POST** `/login` - Connexion - **POST** `/logout` - Déconnexion ## 💾 Modèle de données pour la file d'attente ### PendingRequest Model ```dart @HiveType(typeId: 100) class PendingRequest extends HiveObject { @HiveField(0) final String id; // UUID unique @HiveField(1) final String method; // POST, GET, PUT, DELETE @HiveField(2) final String path; // /chat/rooms/xxx/messages @HiveField(3) final Map? data; // Body de la requête @HiveField(4) final Map? queryParams; // Query parameters @HiveField(5) final DateTime createdAt; // Timestamp de création (ORDRE DE TRAITEMENT) @HiveField(6) final String? tempId; // ID temporaire associé (ex: temp_xxx) @HiveField(7) final String context; // chat, user, operation, etc. @HiveField(8) final int retryCount; // Nombre de tentatives @HiveField(9) final String? errorMessage; // Dernière erreur @HiveField(10) final Map? metadata; // Infos additionnelles } ``` **⚠️ IMPORTANT : Les requêtes DOIVENT être traitées dans l'ordre chronologique strict (FIFO - First In First Out) basé sur `createdAt` pour garantir la cohérence des données.** ## 🎯 Cas d'usage spécifiques ### 1. Chat - Envoi de message hors ligne **Workflow actuel:** 1. Utilisateur tape un message 2. Tentative d'envoi direct à l'API 3. Si pas de connexion → Erreur **Nouveau workflow:** 1. Utilisateur tape un message 2. Création d'un message temporaire avec ID `temp_xxx` 3. Sauvegarde immédiate dans Hive (affichage instantané) 4. Si en ligne → Envoi API → Remplacement par message réel 5. Si hors ligne → Ajout à la queue → Message affiché en italique/grisé 6. Quand connexion revenue → Traitement de la queue → Mise à jour avec ID réel **Indicateurs visuels:** - Message en attente : Texte italique + icône horloge - Message en cours d'envoi : Spinner - Message envoyé : Texte normal - Message en erreur : Texte rouge + icône erreur + option retry ### 2. CRUD Utilisateurs/Amicales **Création hors ligne:** - Génération d'un ID temporaire `temp_user_xxx` - Sauvegarde locale dans Hive - Affichage avec badge "En attente de synchronisation" - Synchronisation automatique au retour de connexion **Modification hors ligne:** - Sauvegarde des modifications locales - Marquage de l'entité comme "modified_offline" - Affichage d'un indicateur de synchronisation en attente - Gestion des conflits si modifié par ailleurs **Suppression hors ligne:** - Marquage local comme "deleted" - Masquage de l'UI - Envoi de la suppression au retour de connexion ### 3. Passages terrain **Enregistrement de passage hors ligne:** - Sauvegarde locale complète (coordonnées GPS, timestamp, etc.) - Queue avec priorité HAUTE - Synchronisation prioritaire au retour de connexion - Conservation des données même après envoi (backup) ## 🔄 Gestion de la synchronisation ### Ordre de traitement **FIFO strict (First In First Out)** : Les requêtes sont TOUJOURS traitées dans l'ordre chronologique de leur création (`createdAt`), sans exception. Ceci garantit : - Les messages de chat arrivent dans le bon ordre - Une création précède toujours sa modification - Une modification précède toujours sa suppression - La cohérence des données est maintenue ### Stratégie de retry - 1ère tentative : Immédiate - 2ème tentative : Après 30 secondes - 3ème tentative : Après 2 minutes - 4ème+ tentative : Toutes les 5 minutes - ~~Abandon après 24h~~ **MODIFIÉ**: Pas d'expiration automatique - requêtes persistent indéfiniment ### Gestion des conflits - Messages chat : Pas de conflit (append-only) - CRUD : Dernière modification gagne + log des conflits - Passages : Pas de conflit (chaque passage est unique) ## 🛠️ Plan d'implémentation ### Phase 1 : Infrastructure (Jour 1) ✅ COMPLÉTÉ - [x] Créer le modèle `PendingRequest` - [x] Créer la Hive Box `pending_requests` avec protection - [x] Enrichir `ConnectivityService` avec gestion de queue - [x] Ajouter les indicateurs UI d'alerte ### Phase 2 : Modification ApiService (Jour 1-2) ✅ COMPLÉTÉ - [x] Ajouter vérification connectivité dans chaque méthode - [x] Implémenter le stockage dans Hive si offline - [x] Créer méthode `processPendingRequests()` - [x] Gérer les réponses "pending" avec tempId ### Phase 3 : Traitement de la queue (Jour 2) ✅ COMPLÉTÉ - [x] Implémenter le processeur de queue FIFO - [x] Garantir l'ordre chronologique strict - [x] Implémenter les retry avec backoff - [x] Gérer les erreurs et abandons ### Phase 4 : Chat (Jour 3) - [ ] Adapter `ChatService` pour messages temporaires - [ ] Implémenter l'UI pour messages en attente - [ ] Gérer le remplacement temp_ → ID réel - [ ] Tester envoi/réception hors ligne ### Phase 5 : CRUD (Jour 4) ✅ COMPLÉTÉ - [x] Adapter PassageRepository (COMPLÉTÉ) - [x] Adapter les autres repositories (Client, Membre, Sector, User, Amicale, Operation) - TOUS COMPLÉTÉS - [x] ~~Gérer les IDs temporaires~~ **MODIFIÉ**: Pas d'IDs temporaires (contrainte DB unsigned int) - [x] Implémenter les indicateurs UI - [ ] Gérer les conflits de synchronisation ### Phase 6 : Tests et optimisation (Jour 5) - [ ] Tests unitaires du QueueService - [ ] Tests d'intégration - [ ] Tests de scénarios hors ligne/en ligne - [ ] Optimisation des performances ## 🎨 UI/UX Guidelines ### ⚠️ ALERTES UTILISATEUR OBLIGATOIRES #### Mode hors ligne détecté - **Banner permanent en haut** : Fond orange avec texte "⚠️ Mode hors ligne - X modifications en attente" - **Badge rouge sur l'app bar** : Nombre de requêtes non synchronisées - **Vibration/Son** : Alerte immédiate lors de la perte de connexion #### Tentative de déconnexion avec données en attente - **Dialog bloquant** : ``` ⚠️ ATTENTION Vous avez X modifications non synchronisées. Si vous vous déconnectez maintenant, ces données seront PERDUES : - X messages non envoyés - X modifications d'utilisateurs - X passages terrain [Annuler] [Se reconnecter d'abord] [Forcer déconnexion*] * Les données non synchronisées seront perdues ``` #### Fermeture de l'app avec données en attente - **Notification système** : "GeoSector a des données non synchronisées" - **Dialog de confirmation** si tentative de fermeture ### Indicateurs visuels globaux - **Badge sur l'app bar** : Nombre de requêtes en attente (rouge pulsant) - **Snackbar** : Notification quand connexion perdue/retrouvée - **Pull to refresh** : Force la synchronisation manuelle - **Bouton "Synchroniser"** : Visible uniquement si données en attente ### États des éléments - **En attente** : Opacity 0.7 + icône horloge + texte italique - **En cours de sync** : Shimmer effect ou spinner - **Erreur de sync** : Bordure rouge + icône erreur - **Synchronisé** : État normal ### Messages utilisateur - "⚠️ Pas de connexion - X actions en attente de synchronisation" - "⚠️ Reconnectez-vous pour envoyer vos modifications" - "✅ Connexion rétablie - Synchronisation en cours..." - "✅ Toutes les modifications ont été synchronisées" - "❌ Erreur de synchronisation - Toucher pour réessayer" ## 🔐 Considérations de sécurité ### ⚠️ PROTECTION CRITIQUE DE LA HIVE BOX **SPLASH PAGE - ATTENTION** : - La `splash_page.dart` qui réinitialise les boxes au démarrage DOIT : 1. Vérifier si `pending_requests` box existe et n'est pas vide 2. Si elle contient des données → NE PAS LA SUPPRIMER 3. Afficher un avertissement à l'utilisateur 4. Déclencher immédiatement le traitement de la queue si connexion disponible ```dart // Dans splash_page.dart if (await Hive.boxExists(AppKeys.pendingRequestsBoxName)) { final box = await Hive.openBox(AppKeys.pendingRequestsBoxName); if (box.isNotEmpty) { print('⚠️ ${box.length} requêtes en attente trouvées'); // NE PAS SUPPRIMER LA BOX // Notifier l'utilisateur // Déclencher le traitement si online } } ``` **Dans app_keys.dart** : ```dart static const String pendingRequestsBoxName = 'pending_requests'; static const String tempEntitiesBoxName = 'temp_entities'; ``` ### Autres considérations 1. **Persistance sécurisée** : Chiffrer les données sensibles dans Hive 2. **Expiration des tokens** : Gérer le renouvellement des sessions 3. **Limite de queue** : Maximum 1000 requêtes en attente 4. **Nettoyage** : Purger les requêtes expirées (>24h) SEULEMENT si confirmé par l'utilisateur 5. **Validation** : Revalider les données avant envoi 6. **Sauvegarde** : Export possible des requêtes en attente avant déconnexion forcée ## 📈 Monitoring et debugging ### Logs à implémenter ```dart // Format des logs [ApiService] No connection - Request queued: POST /chat/rooms/xxx/messages [ApiService] Queue size: 5 pending requests [ConnectivityService] Connection restored - Processing queue... [ApiService] Processing pending request 1/5: POST /chat/rooms/xxx/messages [ApiService] Success: temp_xxx → real_id_xxx [ApiService] Retry 2/5 for request xxx [ApiService] WARNING: Request xxx pending for >12h [ApiService] ALERT: User attempting logout with 5 pending requests ``` ### Métriques à suivre - Taille de la queue - Temps moyen de traitement - Taux de succès/échec - Nombre de retry par requête - Durée moyenne hors ligne ## 🚀 Bénéfices attendus 1. **Expérience utilisateur** : Application utilisable sans connexion 2. **Fiabilité** : Aucune perte de données 3. **Performance** : Réponse immédiate (optimistic UI) 4. **Productivité** : Travail continu même en zone blanche 5. **Résilience** : Gestion automatique des problèmes réseau ## ⚠️ Points d'attention 1. **Taille de la queue** : Limiter pour éviter saturation mémoire 2. **Ordre des requêtes** : Respecter les dépendances 3. **Idempotence** : S'assurer que rejouer une requête est safe 4. **Conflits** : Stratégie claire de résolution 5. **Battery** : Optimiser pour ne pas drainer la batterie ## 📝 Planning détaillé d'implémentation ### **Phase 1 : Infrastructure de base** (Jour 1) ✅ COMPLÉTÉ - [x] Créer les constantes dans `app_keys.dart` (pendingRequestsBoxName, tempEntitiesBoxName) - [x] Créer le modèle `PendingRequest` avec annotations Hive - [x] Enregistrer l'adapter PendingRequest dans `HiveAdapters` - [x] Protéger la box `pending_requests` dans `HiveService` - [x] Ajouter `pending_requests` dans `HiveService._boxConfigs` ### **Phase 2 : Modification ApiService** (Jour 1-2) ✅ COMPLÉTÉ - [x] Créer QueueManager dans ApiService pour gérer la file - [x] Modifier les méthodes ApiService (get, post, put, delete) pour vérifier connectivité - [x] Implémenter `processPendingRequests()` dans ApiService - [x] Créer le système de retry avec backoff exponentiel ### **Phase 3 : Intégration ConnectivityService** (Jour 2) ✅ COMPLÉTÉ - [x] Enrichir ApiService avec listener de connectivité pour déclencher la synchronisation au retour de connexion ### **Phase 4 : Chat (Proof of Concept)** (Jour 3) - [ ] Adapter ChatService pour messages temporaires (temp_xxx) - [ ] Créer UI pour messages en attente (italique, icône horloge) - [ ] Implémenter le remplacement temp_id vers real_id ### **Phase 5 : Alertes utilisateur** (Jour 3) ✅ COMPLÉTÉ - [x] Badge de connexion avec indicateur et animation clignotante - [x] Dialog d'information pour création en attente (PassageRepository) - [x] Intégration du compteur de requêtes pendantes dans ConnectivityIndicator - [x] Widget PendingRequestsCounter pour affichage détaillé ### **Phase 6 : Adaptation des Repositories CRUD** (Jour 4-5) ✅ COMPLÉTÉ #### **Priorité HAUTE** (critique terrain) ✅ - [x] Adapter **PassageRepository** pour CRUD hors ligne avec priorité haute - [x] Adapter **ClientRepository** pour création d'adhérents sur le terrain #### **Priorité MOYENNE** ✅ - [x] Adapter **UserRepository** pour CRUD hors ligne (profil utilisateur connecté uniquement) - [x] Adapter **MembreRepository** pour gestion de l'équipe - [x] Adapter **SectorRepository** pour assignation de secteurs #### **Priorité BASSE** ✅ - [x] Adapter **AmicaleRepository** pour modifications moins fréquentes - [x] Adapter **OperationRepository** pour gestion des campagnes ### **Phase 7 : Gestion avancée** (Jour 5) ✅ - [x] Créer système de gestion des conflits - Détection automatique des erreurs 409 (Conflict) - Marquage des requêtes en conflit avec `hasConflict: true` - Méthodes de résolution : `resolveConflictByDeletion()` et `resolveConflictByRetry()` - Gestion des erreurs permanentes (4xx sauf 409) avec suppression automatique - Limite de 5 tentatives pour les erreurs temporaires - [x] Implémenter limite de queue (max 1000 requêtes) - Vérification avant ajout avec exception si limite atteinte - Message d'erreur clair pour l'utilisateur - [x] Créer système d'export des données en attente - Export JSON complet avec `exportPendingRequestsToJson()` - Import avec fusion et détection de doublons `importPendingRequestsFromJson()` - Statistiques détaillées avec `getPendingRequestsStats()` ### **Phase 8 : Monitoring et debug** (Jour 6) - [ ] Ajouter logs détaillés pour monitoring - [ ] Implémenter métriques de performance ### **Phase 9 : Tests** (Jour 6-7) - [ ] Créer tests unitaires pour QueueService - [ ] Créer tests d'intégration mode offline/online - [ ] Tester scénarios réels (mode avion, perte connexion) ### **Phase 10 : Documentation** (Jour 7) - [ ] Documenter l'utilisation pour les développeurs - [ ] Créer guide utilisateur pour le mode hors ligne ## 📊 Estimation et priorités ### **Durée totale estimée** : 5-7 jours ### **MVP minimal (3 jours)** - Phases 1-3 : Infrastructure + ApiService + ConnectivityService - Phase 4 : Chat comme proof of concept - Phase 5 : Alertes utilisateur de base ### **Version complète (7 jours)** - Toutes les phases incluant tous les repositories - Tests complets - Documentation ### **Ordre de priorité des repositories** 1. **🔴 Critique** : PassageRepository, ClientRepository 2. **🟠 Important** : UserRepository, MembreRepository, SectorRepository 3. **🟡 Normal** : AmicaleRepository, OperationRepository ## 🔧 Utilisation des fonctionnalités avancées ### **Gestion des conflits** ```dart // Récupérer les requêtes en conflit final conflicts = ApiService.instance.getConflictedRequests(); final conflictCount = ApiService.instance.getConflictedRequestsCount(); // Résoudre un conflit await ApiService.instance.resolveConflictByDeletion(requestId); // Supprimer await ApiService.instance.resolveConflictByRetry(requestId); // Réessayer ``` ### **Export/Import des données** ```dart // Exporter les requêtes en attente final jsonData = ApiService.instance.exportPendingRequestsToJson(); // Sauvegarder dans un fichier ou partager... // Importer des requêtes final imported = await ApiService.instance.importPendingRequestsFromJson(jsonString); print('$imported requêtes importées'); // Obtenir des statistiques final stats = ApiService.instance.getPendingRequestsStats(); print('Total: ${stats['total']}, Conflits: ${stats['conflicted']}'); ``` ### **Limite de queue** La limite de 1000 requêtes est automatiquement vérifiée. Si atteinte : - Une `ApiException` est levée avec un message explicite - L'utilisateur doit attendre la synchronisation avant de nouvelles opérations ### **Guide de test en mode avion** 1. **Activer le mode avion** sur l'appareil 2. **Effectuer des opérations** (créations, modifications, suppressions) 3. **Vérifier le compteur** de requêtes en attente dans l'interface 4. **Désactiver le mode avion** 5. **Observer la synchronisation** automatique (badge devient vert) 6. **Vérifier les données** synchronisées sur le serveur --- *Document créé le 25/08/2025 - Dernière mise à jour : 29/08/2025 - Système complet avec gestion des conflits et export*