Files
geo/app/docs/QUEUE-APP-API.md

552 lines
21 KiB
Markdown

# 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<String, dynamic>? data; // Body de la requête
@HiveField(4)
final Map<String, dynamic>? 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<String, dynamic>? 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<PendingRequest>(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*