# GEOSECTOR v2.0 🚒 **Application de gestion des distributions de calendriers par secteurs gĂ©ographiques pour les amicales de pompiers** --- ## 🎯 Vue d'ensemble GEOSECTOR est une solution complĂšte dĂ©veloppĂ©e en Flutter qui rĂ©volutionne la gestion des campagnes de distribution de calendriers pour les amicales de pompiers. L'application combine gĂ©olocalisation, gestion multi-rĂŽles et synchronisation en temps rĂ©el pour optimiser les tournĂ©es et maximiser l'efficacitĂ© des Ă©quipes. ### 🏆 Points forts de la v2.0 - **Architecture moderne** sans Provider, basĂ©e sur l'injection de dĂ©pendances - **RĂ©activitĂ© native** avec ValueListenableBuilder et Hive - **Interface adaptative** selon les rĂŽles utilisateur - **Performance optimisĂ©e** avec un ApiService singleton - **Gestion avancĂ©e des permissions** multi-niveaux - **Gestion d'erreurs centralisĂ©e** avec ApiException - **Interface utilisateur unifiĂ©e** avec UserFormDialog rĂ©utilisable --- ## 📋 Table des matiĂšres 1. [FonctionnalitĂ©s](#-fonctionnalitĂ©s) 2. [Architecture technique](#-architecture-technique) 3. [Installation](#-installation-et-configuration) 4. [ModĂšles de donnĂ©es](#-modĂšles-de-donnĂ©es) 5. [Architecture des composants](#-architecture-des-composants) 6. [Gestion des rĂŽles](#-gestion-des-rĂŽles) 7. [Interface utilisateur](#-interface-utilisateur) 8. [API et synchronisation](#-api-et-synchronisation) 9. [Gestion des erreurs](#-gestion-des-erreurs) 10. [Cartes et gĂ©olocalisation](#-cartes-et-gĂ©olocalisation) --- ## 🚀 FonctionnalitĂ©s ### 🎯 FonctionnalitĂ©s mĂ©tier #### Pour les **Membres** (RĂŽle 1) - ✅ Visualisation des secteurs assignĂ©s sur carte interactive - ✅ Suivi GPS en temps rĂ©el des tournĂ©es - ✅ Enregistrement des passages avec gĂ©olocalisation - ✅ Gestion des stocks de calendriers - ✅ Historique des distributions - ✅ Chat intĂ©grĂ© avec l'Ă©quipe #### Pour les **Admins Amicale** (RĂŽle 2) - ✅ Gestion de leur amicale (informations, coordonnĂ©es) - ✅ Gestion des membres de l'amicale (crĂ©ation, modification, suppression) - ✅ Attribution des rĂŽles aux membres (Membre/Administrateur) - ✅ Gestion du statut actif des comptes membres - ✅ Consultation des statistiques de l'amicale - ✅ Attribution des secteurs aux membres - ✅ Suivi des performances Ă©quipe #### Pour les **Super Admins** (RĂŽle 3+) - ✅ Gestion globale multi-amicales - ✅ Administration des utilisateurs et permissions - ✅ Configuration des paramĂštres systĂšme - ✅ Analytics avancĂ©es et reporting - ✅ Gestion des secteurs gĂ©ographiques ### 🔧 FonctionnalitĂ©s techniques - **đŸ—ș Cartographie avancĂ©e** : Flutter Map avec tuiles Mapbox - **📍 GĂ©olocalisation prĂ©cise** : Suivi GPS des Ă©quipes - **đŸ’Ÿ Stockage hybride** : Cache local Hive + synchronisation cloud avec optimisation des performances - **💬 Communication** : Chat MQTT en temps rĂ©el - **🔐 SĂ©curitĂ©** : Authentification JWT + gestion fine des permissions - **đŸ“± Multi-plateforme** : iOS, Android, Web - **🌐 Mode hors-ligne** : Fonctionnement dĂ©gradĂ© sans connexion - **⚡ Gestion d'erreurs robuste** : Extraction automatique des messages API - **🎹 Interface responsive** : Adaptation automatique selon la taille d'Ă©cran --- ## đŸ—ïž Architecture technique ### Stack technologique | Composant | Technologie | Version | Usage | | ------------------- | ---------------------- | ------- | ------------------------------ | | **Framework** | Flutter | 3.32+ | Interface multi-plateforme | | **Langage** | Dart | 3.0+ | Logique applicative | | **Navigation** | GoRouter | 12.1.3 | Routing dĂ©claratif | | **Stockage local** | Hive | 2.2.3 | Base de donnĂ©es NoSQL locale | | **RĂ©activitĂ©** | ValueListenableBuilder | Native | Écoute des changements Hive | | **HTTP** | Dio | 5.4.0 | Client HTTP avec intercepteurs | | **Cartes** | Flutter Map | 6.1.0 | Rendu cartographique | | **GĂ©olocalisation** | Geolocator | 10.1.0 | Services de localisation | | **Chat** | MQTT5 Client | 4.2.0 | Messagerie temps rĂ©el | | **UI** | Material Design 3 | Native | Composants d'interface | | **Logging** | LoggerService | Custom | Logs conditionnels par env | ### đŸ›ïž Architecture en couches ```mermaid graph TD A[UI Layer - Widgets] --> B[Repository Layer - Business Logic] B --> C[Data Layer - Hive + API] A1[ValueListenableBuilder] --> A A2[Custom Widgets] --> A A3[UserFormDialog] --> A B1[UserRepository] --> B B2[AmicaleRepository] --> B B3[MembreRepository] --> B C1[Hive Boxes] --> C C2[API Service Singleton] --> C C3[ApiException Handler] --> C ``` ### 📁 Structure du projet ``` app/ ├── lib/ │ ├── core/ # Couche centrale │ │ ├── constants/ # Constantes globales │ │ │ ├── app_keys.dart # ClĂ©s des Box Hive │ │ │ └── api_endpoints.dart # Endpoints API │ │ ├── data/ │ │ │ └── models/ # ModĂšles Hive │ │ │ ├── user_model.dart # @HiveType(typeId: 3) │ │ │ ├── amicale_model.dart # @HiveType(typeId: 4) │ │ │ └── membre_model.dart # @HiveType(typeId: 5) │ │ ├── repositories/ # Logique mĂ©tier │ │ │ ├── user_repository.dart │ │ │ ├── amicale_repository.dart │ │ │ └── membre_repository.dart │ │ ├── services/ # Services externes │ │ │ ├── api_service.dart # HTTP Singleton │ │ │ ├── chat_service.dart # MQTT │ │ │ └── location_service.dart # GPS │ │ └── utils/ # Utilitaires │ │ ├── validators.dart │ │ └── formatters.dart │ ├── presentation/ # Interface utilisateur │ │ ├── admin/ # Pages administrateur │ │ │ ├── admin_dashboard_page.dart │ │ │ ├── admin_amicale_page.dart │ │ │ └── admin_statistics_page.dart │ │ ├── user/ # Pages utilisateur │ │ │ ├── user_dashboard_page.dart │ │ │ ├── map_page.dart │ │ │ └── distribution_page.dart │ │ ├── widgets/ # Composants rĂ©utilisables │ │ │ ├── tables/ │ │ │ │ ├── amicale_table_widget.dart │ │ │ │ ├── amicale_row_widget.dart │ │ │ │ ├── membre_table_widget.dart │ │ │ │ └── membre_row_widget.dart │ │ │ ├── forms/ │ │ │ │ ├── amicale_form.dart │ │ │ │ └── custom_text_field.dart │ │ │ └── common/ │ │ │ ├── dashboard_layout.dart │ │ │ └── loading_widget.dart │ │ └── theme/ │ │ └── app_theme.dart │ ├── app.dart # Configuration app │ └── main.dart # Point d'entrĂ©e ├── assets/ # Ressources statiques │ ├── images/ │ ├── icons/ │ └── fonts/ ├── test/ # Tests unitaires ├── integration_test/ # Tests d'intĂ©gration └── docs/ # Documentation ``` --- --- ## 🚀 Installation et configuration ### PrĂ©requis systĂšme - **Flutter SDK** : 3.32 ou supĂ©rieur - **Dart SDK** : 3.0 ou supĂ©rieur - **IDE** : Android Studio, VS Code, ou IntelliJ - **Environnement** : - Android : SDK 21+ (Android 5.0+) - iOS : iOS 12.0+ - Web : Navigateurs modernes ## 🔐 Configuration des clĂ©s API ### Mapbox (Cartographie) 1. CrĂ©er un compte sur [Mapbox](https://www.mapbox.com/) 2. GĂ©nĂ©rer un token d'accĂšs 3. Ajouter le token dans `.env` ### Configuration MQTT (Chat) 1. Configurer votre broker MQTT 2. CrĂ©er les credentials 3. Tester la connexion --- ## đŸ—„ïž ModĂšles de donnĂ©es ### Registres Hive des adaptateurs ```dart // ModĂšles principaux UserModelAdapter() // typeId: 0 OperationModelAdapter() // typeId: 1 SectorModelAdapter() // typeId: 3 PassageModelAdapter() // typeId: 4 MembreModelAdapter() // typeId: 5 UserSectorModelAdapter() // typeId: 6 RegionModelAdapter() // typeId: 7 ClientModelAdapter() // typeId: 10 AmicaleModelAdapter() // typeId: 11 // ModĂšles de chat ConversationModelAdapter() // typeId: 20 MessageModelAdapter() // typeId: 21 ParticipantModelAdapter() // typeId: 22 AnonymousUserModelAdapter() // typeId: 23 AudienceTargetModelAdapter() // typeId: 24 NotificationSettingsAdapter() // typeId: 25 ``` ### Clarification importante : UserModel vs MembreModel vs UserSectorModel ⚠ **ATTENTION** : Il existe une distinction cruciale entre ces trois modĂšles : #### **UserModel** (Box: `users`) - ReprĂ©sente **uniquement l'utilisateur courant connectĂ©** (current user) - StockĂ© dans la box Hive `users` qui ne contient qu'un seul enregistrement - UtilisĂ© pour l'authentification et la session de l'utilisateur actuel - **Ne pas confondre avec les membres de l'amicale** #### **MembreModel** (Box: `membres`) - ReprĂ©sente **tous les membres d'une amicale** - StockĂ© dans la box Hive `membres` qui contient plusieurs enregistrements - UtilisĂ© pour la gestion des Ă©quipes et l'attribution aux secteurs - Chaque membre a son propre ID unique #### **UserSectorModel** (Box: `user_sector`) - ReprĂ©sente **l'association entre un membre et un secteur** - ⚠ **IMPORTANT** : Le champ `id` dans `UserSectorModel` correspond Ă  l'ID du **membre** (MembreModel.id), **PAS** Ă  l'ID de l'utilisateur (UserModel.id) - Permet de savoir quels membres sont affectĂ©s Ă  quels secteurs - Nom trompeur : devrait s'appeler "MemberSectorModel" pour Ă©viter la confusion ### CompatibilitĂ© entre modĂšles - **UserModel ↔ MembreModel** : Conversion bidirectionnelle via `toUserModel()` et `fromUserModel()` - **Synchronisation** : Maintien de la cohĂ©rence entre les deux reprĂ©sentations - **Champs spĂ©cialisĂ©s** : PrĂ©servation des donnĂ©es spĂ©cifiques Ă  chaque modĂšle 🎹 Interface utilisateur Architecture des composants UserFormDialog - Modale unifiĂ©e RĂ©utilisabilitĂ© : MĂȘme widget pour "Mon Compte" et "Gestion des Membres" Personnalisation contextuelle : SĂ©lecteur de rĂŽle (Membre/Administrateur) Checkbox statut actif/inactif Édition du nom d'utilisateur selon le contexte Gestion du nom de tournĂ©e (sectName) Interface responsive : Adaptation automatique selon la largeur d'Ă©cran UserForm - Formulaire intelligent Layout adaptatif : > 900px : Champs groupĂ©s en lignes (username+email, prĂ©nom+nom, tĂ©lĂ©phones, dates) > ≀ 900px : Champs empilĂ©s verticalement > Validation conditionnelle : Au moins nom OU nom de tournĂ©e requis > Champs dynamiques : Affichage selon les permissions et le contexte > Indicateurs visuels : Points rouges sur les champs obligatoires > Tableaux interactifs > AmicaleTableWidget : Gestion des amicales avec Ă©dition inline > MembreTableWidget : Gestion des membres avec actions contextuelles > Alternance de couleurs : AmĂ©lioration de la lisibilitĂ© > Clic sur ligne : Ouverture directe du formulaire d'Ă©dition ## 🔗 API et synchronisation Principe "API First" ### Flow de mise Ă  jour Validation API : Tentative de mise Ă  jour sur le serveur SuccĂšs → Sauvegarde locale avec isSynced: true Erreur → Aucune modification locale + affichage de l'erreur ### Avantages CohĂ©rence des donnĂ©es : Local toujours synchronisĂ© avec le serveur Gestion d'erreurs propre : Pas de conflits entre donnĂ©es locales et distantes UX claire : Feedback immĂ©diat sur les erreurs de validation ### ApiService Singleton - Thread-safe : Initialisation sĂ©curisĂ©e avec verrous - Auto-configuration : DĂ©tection automatique de l'environnement (DEV/REC/PROD) - Gestion de session : Headers d'authentification automatiques - Retry logic : Nouvelles tentatives pour les erreurs rĂ©seau ## ⚠ Gestion des erreurs ### 🎯 SystĂšme ApiException intelligent GEOSECTOR v2.0 utilise un **systĂšme centralisĂ© de gestion des messages** qui s'adapte automatiquement au contexte d'affichage pour garantir une visibilitĂ© optimale des notifications utilisateur. #### **🧠 DĂ©tection automatique de contexte** L'`ApiException` dĂ©tecte intelligemment si elle est appelĂ©e depuis une Dialog et adapte l'affichage : - **đŸ“± Contexte normal** : SnackBar standard en bas d'Ă©cran - **💬 Contexte Dialog** : Overlay SnackBar positionnĂ© au-dessus de la Dialog estompĂ©e - **🌐 Mobile/Web** : Adaptation automatique selon la plateforme - **🎹 CohĂ©rence visuelle** : Couleurs, icĂŽnes et comportements unifiĂ©s ```dart // MĂȘme API partout - dĂ©tection intelligente du contexte void _handleValidation() { if (formInvalid) { // Dans une Dialog : overlay au-dessus, Dialog reste ouverte ApiException.showError(context, Exception("Champs requis manquants")); return; } // SuccĂšs : fermer Dialog puis afficher confirmation Navigator.pop(context); ApiException.showSuccess(context, "DonnĂ©es sauvegardĂ©es"); } ``` #### **✹ Avantages de l'approche unifiĂ©e** | Aspect | Avant | Avec ApiException | |--------|-------|-------------------| | **VisibilitĂ©** | SnackBar masquĂ© par Dialog | Overlay visible au-dessus | | **Consistance** | Messages dispersĂ©s | API unifiĂ©e dans toute l'app | | **Maintenance** | Code rĂ©pĂ©titif | SystĂšme centralisĂ© | | **UX** | Frustrant (messages cachĂ©s) | Fluide et prĂ©visible | ### Architecture centralisĂ©e ```mermaid sequenceDiagram participant UI as dashboard_app_bar.dart participant UR as user_repository.dart participant AS as api_service.dart participant API as API Server participant AE as ApiException participant EU as ErrorUtils Note over UI: Utilisateur clique "Enregistrer" UI->>UR: updateUser(updatedUser) Note over UR: Tente la mise Ă  jour UR->>AS: updateUser(user) Note over AS: Appel HTTP PUT AS->>API: PUT /users/123 {email: "test@test.com"} alt SuccĂšs API API-->>AS: 200 OK {user data} AS-->>UR: UserModel (mis Ă  jour) UR-->>UI: UserModel (succĂšs) UI->>EU: showSuccessSnackBar() Note over UI: ✅ "Profil mis Ă  jour" else Erreur API (ex: email dĂ©jĂ  utilisĂ©) API-->>AS: 409 Conflict {"message": "Cet email est dĂ©jĂ  utilisĂ©"} Note over AS: Conversion en ApiException AS->>AE: ApiException.fromDioException(dioError) AE-->>AS: ApiException("Cet email est dĂ©jĂ  utilisĂ©") AS-->>UR: throw ApiException UR-->>UI: throw ApiException Note over UI: Gestion de l'erreur UI->>EU: showErrorSnackBar(context, exception) EU->>AE: extractErrorMessage(exception) AE-->>EU: "Cet email est dĂ©jĂ  utilisĂ©" Note over UI: ❌ "Erreur: Cet email est dĂ©jĂ  utilisĂ©" Note over UI: Dialog reste ouvert else Erreur rĂ©seau API-->>AS: Network Error / Timeout AS->>AE: ApiException.fromDioException(networkError) AE-->>AS: ApiException("ProblĂšme de connexion rĂ©seau") AS-->>UR: throw ApiException UR-->>UI: throw ApiException UI->>EU: showErrorSnackBar(context, exception) Note over UI: ❌ "ProblĂšme de connexion rĂ©seau" end ``` ## Composants de gestion d'erreurs ### ApiException Extraction intelligente : Messages spĂ©cifiques depuis la rĂ©ponse API Codes HTTP standardisĂ©s : Mapping automatique des erreurs communes Types d'erreurs : Classification (validation, authentification, rĂ©seau, conflit) MĂ©thodes d'affichage : showError() et showSuccess() intĂ©grĂ©es ### ResponsabilitĂ©s par couche ApiService : Conversion des erreurs Dio en ApiException Repository : Propagation transparente des erreurs Interface : Affichage utilisateur via ApiException.showError() ### Messages d'erreurs contextuels 409 Conflict : "Cet email est dĂ©jĂ  utilisĂ© par un autre utilisateur" 400 Bad Request : "DonnĂ©es invalides" 401 Unauthorized : "Non autorisĂ© : veuillez vous reconnecter" 500 Server Error : "Erreur serveur interne" Network Errors : "ProblĂšme de connexion rĂ©seau" Timeout : "DĂ©lai d'attente dĂ©passĂ©" ## 🔧 Pattern de gestion des erreurs API dans les Repositories ### 🎯 ProblĂšme Ă  rĂ©soudre Les messages d'erreur spĂ©cifiques de l'API (comme "Cet email est dĂ©jĂ  utilisĂ©") n'Ă©taient pas affichĂ©s Ă  l'utilisateur. À la place, un message gĂ©nĂ©rique "Erreur inattendue" apparaissait. ### 📝 Modifications requises #### **1. ApiService - Conversion automatique des DioException** Toutes les mĂ©thodes HTTP gĂ©nĂ©riques doivent convertir les `DioException` en `ApiException` : ```dart // ✅ CORRECT - ApiService avec conversion automatique Future put(String path, {dynamic data}) async { try { return await _dio.put(path, data: data); } on DioException catch (e) { throw ApiException.fromDioException(e); // ← Extraction automatique du message } catch (e) { if (e is ApiException) rethrow; throw ApiException('Erreur inattendue lors de la requĂȘte PUT', originalError: e); } } ``` Appliquer le mĂȘme pattern pour `post()`, `get()`, `delete()`. #### **2. Repository - Simplification de la gestion des erreurs** ```dart // ❌ INCORRECT - Code inutile qui ne sera jamais exĂ©cutĂ© Future updateMembre(MembreModel membre) async { try { final response = await ApiService.instance.put('/users/${membre.id}', data: data); if (response.statusCode == 200) { await saveMembreBox(membre); return true; } // ⚠ CE CODE NE SERA JAMAIS ATTEINT car Dio lance une exception pour les codes d'erreur if (response.data != null && response.data is Map) { final responseData = response.data as Map; if (responseData['status'] == 'error') { throw Exception(responseData['message']); } } return false; } catch (e) { rethrow; } } ``` ```dart // ✅ CORRECT - Code simplifiĂ© et fonctionnel Future updateMembre(MembreModel membre) async { try { final response = await ApiService.instance.put('/users/${membre.id}', data: data); // Si on arrive ici, c'est que la requĂȘte a rĂ©ussi (200) await saveMembreBox(membre); return true; } catch (e) { // L'ApiException contient dĂ©jĂ  le message extrait de l'API rethrow; // Propager l'exception pour affichage } } ``` #### **3. AmĂ©lioration des logs (avec LoggerService)** ```dart // ✅ CORRECT - Logs propres sans dĂ©tails techniques catch (e) { // Ne pas logger les dĂ©tails techniques de DioException if (e is ApiException) { LoggerService.error('Erreur lors de la mise Ă  jour: ${e.message}'); } else { LoggerService.error('Erreur lors de la mise Ă  jour'); } rethrow; } ``` N'oubliez pas d'importer `ApiException` : ```dart import 'package:geosector_app/core/utils/api_exception.dart'; ``` ### 🔄 Flux d'erreur corrigĂ© ```mermaid sequenceDiagram participant API as API Server participant Dio as Dio Client participant AS as ApiService participant AE as ApiException participant R as Repository participant UI as Interface UI->>R: updateData() R->>AS: put('/endpoint') AS->>Dio: HTTP PUT Dio->>API: Request alt Code d'erreur (409, 400, etc.) API-->>Dio: Error + JSON body Note over API: {"status": "error",
"message": "Message spécifique"} Dio-->>AS: DioException AS->>AE: fromDioException() Note over AE: Extrait message
depuis response.data AE-->>AS: ApiException("Message spĂ©cifique") AS-->>R: throw ApiException R-->>UI: throw ApiException UI->>UI: showError("Message spĂ©cifique") else SuccĂšs (200, 201) API-->>Dio: Success Dio-->>AS: Response AS-->>R: Response R->>R: Sauvegarde Hive R-->>UI: return true end ``` ### ✅ Checklist de migration Pour chaque repository : - [ ] VĂ©rifier que l'ApiService convertit les DioException en ApiException - [ ] Simplifier le code : supprimer les vĂ©rifications de statut aprĂšs l'appel API - [ ] Propager les exceptions avec `rethrow` - [ ] AmĂ©liorer les logs pour ne pas afficher les dĂ©tails techniques - [ ] Importer `ApiException` si nĂ©cessaire - [ ] Tester avec une erreur 409 pour vĂ©rifier l'affichage du message ### 📊 RĂ©sultat attendu | Avant | AprĂšs | |-------|-------| | "Erreur inattendue" | "Cet email est dĂ©jĂ  utilisĂ© par un autre utilisateur" | | Logs avec stack trace Dio | Message d'erreur simple et clair | | Code complexe avec vĂ©rifications inutiles | Code simplifiĂ© et maintenable | Cette approche garantit que tous les messages d'erreur de l'API sont correctement affichĂ©s Ă  l'utilisateur, amĂ©liorant ainsi l'expĂ©rience utilisateur et facilitant le dĂ©bogage. ## 📝 Service de Logging Intelligent ### 🎯 Vue d'ensemble GEOSECTOR v2.0 implĂ©mente un **LoggerService centralisĂ©** qui dĂ©sactive automatiquement les logs de debug en production, optimisant ainsi les performances et la sĂ©curitĂ© tout en facilitant le dĂ©veloppement. ### 🔍 DĂ©tection automatique de l'environnement Le LoggerService dĂ©tecte automatiquement l'environnement d'exĂ©cution : ```dart // DĂ©tection basĂ©e sur l'URL pour le web if (currentUrl.contains('dapp.geosector.fr')) → DEV if (currentUrl.contains('rapp.geosector.fr')) → REC Sinon → PROD // Pour mobile/desktop : utilise kReleaseMode de Flutter ``` **Comportement par environnement :** | Environnement | Logs Debug | Logs Erreur | Stack Traces | |---------------|------------|-------------|--------------| | **DEV** | ✅ ActivĂ©s | ✅ ActivĂ©s | ✅ ComplĂštes | | **REC** | ✅ ActivĂ©s | ✅ ActivĂ©s | ✅ ComplĂštes | | **PROD** | ❌ DĂ©sactivĂ©s | ✅ ActivĂ©s | ❌ MasquĂ©es | ### đŸ› ïž API du LoggerService #### **MĂ©thodes principales** ```dart // Remplacement direct de debugPrint LoggerService.log('Message simple'); // Logs catĂ©gorisĂ©s avec emojis automatiques LoggerService.info('Information'); // â„č LoggerService.success('OpĂ©ration rĂ©ussie'); // ✅ LoggerService.warning('Attention'); // ⚠ LoggerService.error('Erreur', exception); // ❌ (toujours affichĂ©) LoggerService.debug('Debug', emoji: '🔧'); // 🔧 // Logs spĂ©cialisĂ©s LoggerService.api('RequĂȘte API envoyĂ©e'); // 🔗 LoggerService.database('Box Hive ouverte'); // đŸ’Ÿ LoggerService.navigation('Route: /admin'); // 🧭 LoggerService.performance('Temps: 45ms'); // ⏱ ``` #### **FonctionnalitĂ©s avancĂ©es** ```dart // Logs groupĂ©s pour amĂ©liorer la lisibilitĂ© LoggerService.group('Traitement utilisateur', [ 'Validation des donnĂ©es', 'Appel API', 'Sauvegarde locale', 'Notification envoyĂ©e' ]); // Affiche : // ┌─ Traitement utilisateur // ├─ Validation des donnĂ©es // ├─ Appel API // ├─ Sauvegarde locale // └─ Notification envoyĂ©e // Log JSON formatĂ© LoggerService.json('Payload API', { 'id': 123, 'name': 'Test', 'active': true }); // Affiche : // 📋 Payload API: // id: 123 // name: Test // active: true // Log conditionnel LoggerService.conditional( 'Debug spĂ©cifique', condition: user.role > 2 ); ``` ### 🔄 Migration depuis debugPrint #### **Avant (debugPrint partout)** ```dart debugPrint('🔄 DĂ©but de la crĂ©ation d\'un nouveau membre'); debugPrint('đŸ“€ DonnĂ©es envoyĂ©es Ă  l\'API: $data'); debugPrint('❌ Erreur: $e'); ``` #### **AprĂšs (LoggerService)** ```dart LoggerService.info('DĂ©but de la crĂ©ation d\'un nouveau membre'); LoggerService.api('DonnĂ©es envoyĂ©es Ă  l\'API: $data'); LoggerService.error('Erreur lors de la crĂ©ation', e); ``` ### 📋 Utilisation avec les extensions Pour une syntaxe encore plus concise, utilisez les extensions String : ```dart // Import nĂ©cessaire import 'package:geosector_app/core/services/logger_service.dart'; // Utilisation directe sur les strings 'Connexion rĂ©ussie'.logSuccess(); 'Erreur de validation'.logError(exception); 'RequĂȘte GET /users'.logApi(); 'Box membres ouverte'.logDatabase(); ``` ### 🎯 Bonnes pratiques #### **1. CatĂ©gorisation des logs** ```dart // ✅ BON - Log catĂ©gorisĂ© et clair LoggerService.api('POST /users - CrĂ©ation membre'); LoggerService.database('Sauvegarde dans Box membres'); // ❌ MAUVAIS - Log gĂ©nĂ©rique sans contexte debugPrint('Traitement en cours...'); ``` #### **2. Gestion des erreurs** ```dart try { await operation(); LoggerService.success('OpĂ©ration terminĂ©e'); } catch (e, stackTrace) { // Les erreurs sont TOUJOURS loggĂ©es, mĂȘme en PROD LoggerService.error('Échec de l\'opĂ©ration', e, stackTrace); } ``` #### **3. Logs de performance** ```dart final stopwatch = Stopwatch()..start(); await heavyOperation(); stopwatch.stop(); LoggerService.performance('OpĂ©ration lourde: ${stopwatch.elapsedMilliseconds}ms'); ``` ### 🔒 SĂ©curitĂ© et performances #### **Avantages en production** 1. **SĂ©curitĂ©** : Aucune information sensible exposĂ©e dans la console 2. **Performance** : Pas d'appels inutiles Ă  debugPrint 3. **Taille** : Bundle JavaScript plus lĂ©ger (tree shaking) 4. **Professionnalisme** : Console propre pour les utilisateurs finaux #### **Conservation des logs d'erreur** Les erreurs restent visibles en production pour faciliter le support : ```dart // Toujours affichĂ©, mĂȘme en PROD LoggerService.error('Erreur critique dĂ©tectĂ©e', error); // Mais sans la stack trace complĂšte qui pourrait rĂ©vĂ©ler // des dĂ©tails d'implĂ©mentation ``` ### 📊 Impact sur le codebase | MĂ©trique | Avant | AprĂšs | |----------|-------|-------| | **Logs en PROD** | Tous visibles | Erreurs uniquement | | **Performance web** | debugPrint actifs | DĂ©sactivĂ©s automatiquement | | **Maintenance** | debugPrint dispersĂ©s | Service centralisĂ© | | **LisibilitĂ©** | Emojis manuels | CatĂ©gorisation automatique | ### 🚀 Configuration et initialisation Le LoggerService fonctionne automatiquement sans configuration : ```dart // main.dart - Aucune initialisation requise void main() async { // LoggerService dĂ©tecte automatiquement l'environnement // via ApiService.getCurrentEnvironment() runApp(GeosectorApp()); } // Utilisation immĂ©diate dans n'importe quel fichier LoggerService.info('Application dĂ©marrĂ©e'); ``` Cette architecture garantit un systĂšme de logging professionnel, sĂ©curisĂ© et performant, adaptĂ© aux besoins de dĂ©veloppement tout en protĂ©geant la production. 📝✹ ## 🔐 Gestion des identifiants - Normes NIST SP 800-63B ### 🎯 Vue d'ensemble GEOSECTOR v2.0 implĂ©mente les **normes NIST SP 800-63B** pour la gestion des identifiants (usernames et passwords), offrant une sĂ©curitĂ© renforcĂ©e tout en amĂ©liorant l'expĂ©rience utilisateur avec des rĂšgles plus flexibles et modernes. ### 📋 ConformitĂ© NIST SP 800-63B | Exigence NIST | ImplĂ©mentation | Statut | |---------------|----------------|--------| | **Longueur minimale : 8 caractĂšres** | ✅ MIN = 8 caractĂšres | ✅ CONFORME | | **Longueur maximale : 64 caractĂšres minimum** | ✅ MAX = 64 caractĂšres | ✅ CONFORME | | **Accepter TOUS les caractĂšres ASCII imprimables** | ✅ Aucune restriction sur les caractĂšres | ✅ CONFORME | | **Accepter les espaces** | ✅ Espaces acceptĂ©s (dĂ©but, milieu, fin) | ✅ CONFORME | | **Accepter Unicode (Ă©mojis, accents, etc.)** | ✅ Support UTF-8 complet | ✅ CONFORME | | **VĂ©rifier contre les mots de passe compromis** | ✅ API Have I Been Pwned avec k-anonymity | ✅ CONFORME | | **Pas d'obligation de composition** | ✅ Pas d'erreur si manque majuscules/chiffres/spĂ©ciaux | ✅ CONFORME | | **Pas de changement pĂ©riodique forcĂ©** | ✅ Aucune expiration automatique | ✅ CONFORME | | **Permettre les phrases de passe** | ✅ "Mon chat FĂ©lix a 3 ans!" acceptĂ© | ✅ CONFORME | ### 🔑 RĂšgles pour les identifiants #### **Username (Nom d'utilisateur)** - **Longueur** : 8 Ă  64 caractĂšres - **CaractĂšres acceptĂ©s** : TOUS (lettres, chiffres, espaces, accents, symboles, emojis) - **Exemples valides** : - `jean dupont 75` - `Marie-Claire.2024` - `Pompier Paris 🚒` - `utilisateur@amicale` #### **Password (Mot de passe)** - **Longueur** : 8 Ă  64 caractĂšres - **Aucune rĂšgle de composition obligatoire** (plus besoin de majuscules/minuscules/chiffres/spĂ©ciaux) - **Phrases de passe recommandĂ©es** pour une meilleure mĂ©morisation - **Exemples valides** : - `Mon chat FĂ©lix a 3 ans!` - `J'aime les pizzas du vendredi soir` - `Le camion rouge part Ă  8h30` - `☀ Soleil brillant sur Paris ☀` ### đŸŽČ GĂ©nĂ©rateurs intelligents #### **GĂ©nĂ©rateur de username** CrĂ©e des noms d'utilisateur uniques basĂ©s sur : - Nom/prĂ©nom de la personne - Code postal et ville de l'amicale - NumĂ©ro alĂ©atoire pour l'unicitĂ© - Peut inclure des espaces et sĂ©parateurs (., -, _) #### **GĂ©nĂ©rateur de phrases de passe** GĂ©nĂšre des phrases de passe mĂ©morables en français : - Phrases naturelles et faciles Ă  retenir - Combinaisons variĂ©es (sujets, verbes, complĂ©ments) - Ajout optionnel de caractĂšres spĂ©ciaux ou emojis - Exemples gĂ©nĂ©rĂ©s : - `Le chien Max danse dans le jardin!` - `Mon vĂ©lo rouge vole 42 fois en Ă©tĂ©` - `Luna a 7 ans!☀` ### ⚠ Points importants 1. **Pas de trim()** : Les espaces en dĂ©but/fin sont prĂ©servĂ©s et font partie de l'identifiant 2. **Pas de vĂ©rification password == username** : Sur demande du client, cette rĂšgle a Ă©tĂ© retirĂ©e 3. **Validation cĂŽtĂ© API** : L'API vĂ©rifie les mots de passe contre la base Have I Been Pwned 4. **RĂ©trocompatibilitĂ©** : Les anciens identifiants restent valides ### 🔄 Impact sur l'expĂ©rience utilisateur | Aspect | Avant | AprĂšs NIST | |--------|-------|------------| | **ComplexitĂ©** | RĂšgles strictes difficiles Ă  mĂ©moriser | LibertĂ© totale, phrases naturelles | | **Longueur password** | 12-16 caractĂšres obligatoires | 8-64 caractĂšres flexibles | | **CaractĂšres spĂ©ciaux** | Obligatoires | Optionnels | | **MĂ©morisation** | Mots de passe complexes oubliĂ©s | Phrases personnelles mĂ©morables | | **SĂ©curitĂ©** | RĂšgles arbitraires | VĂ©rification contre bases de donnĂ©es compromises | ## 🎯 Gestion des rĂŽles ### HiĂ©rarchie des permissions Membre (RĂŽle 1) : Consultation et distribution dans ses secteurs Admin Amicale (RĂŽle 2) : Gestion complĂšte de son amicale et ses membres Super Admin (RĂŽle 3+) : Administration globale multi-amicales ### FonctionnalitĂ©s par rĂŽle Admin Amicale - Gestion des membres CrĂ©ation : Nouveaux membres avec attribution de rĂŽle Modification : Informations personnelles, rĂŽle, statut actif Suppression : Avec confirmation obligatoire Validation : ContrĂŽle d'unicitĂ© email/username par l'API ### Interface adaptative SĂ©lecteur de rĂŽle : Visible uniquement pour les admins Checkbox statut actif : ContrĂŽle d'accĂšs aux comptes Édition contextuelle : Champs modifiables selon les permissions Actions conditionnelles : Boutons disponibles selon le niveau d'autorisation ## đŸ‘„ Gestion des membres (Admin Amicale) ### 🎯 Vue d'ensemble La gestion des membres est une fonctionnalitĂ© clĂ© pour les **Admins Amicale** (RĂŽle 2) qui permet une administration complĂšte des Ă©quipes au sein de leur amicale. Cette interface centralise toutes les opĂ©rations liĂ©es aux membres avec une approche sĂ©curisĂ©e et intuitive. ### đŸ“± Interface AdminAmicalePage L'interface principale `admin_amicale_page.dart` offre une vue d'ensemble complĂšte : - **Informations de l'amicale** : Affichage des dĂ©tails de l'amicale courante - **Liste des membres** : Tableau interactif avec actions contextuelles - **Ajout de membres** : Bouton d'action pour crĂ©er de nouveaux comptes - **OpĂ©ration courante** : Indication de l'opĂ©ration active en cours ### ✹ FonctionnalitĂ©s principales #### 🆕 CrĂ©ation de nouveaux membres ```dart // Workflow de crĂ©ation 1. Clic sur "Ajouter un membre" 2. Ouverture du UserFormDialog 3. Formulaire vierge avec valeurs par dĂ©faut 4. SĂ©lection du rĂŽle (Membre/Administrateur) 5. Configuration du statut actif 6. Validation et crĂ©ation via API 7. Attribution automatique Ă  l'amicale courante ``` **Champs obligatoires :** - Email (unique dans le systĂšme) - Au moins un nom (nom de famille OU nom de tournĂ©e) - RĂŽle dans l'amicale **Champs optionnels :** - Nom d'utilisateur (Ă©ditable pour les admins) - PrĂ©nom, tĂ©lĂ©phones, dates - Nom de tournĂ©e (pour identification terrain) #### ✏ Modification des membres existants ```dart // Actions disponibles - Clic sur une ligne → Ouverture du formulaire d'Ă©dition - Modification de tous les champs personnels - Changement de rĂŽle (Membre ↔ Administrateur) - Activation/DĂ©sactivation du compte - Gestion du nom de tournĂ©e ``` **Workflow de modification :** 1. SĂ©lection du membre dans le tableau 2. Ouverture automatique du `UserFormDialog` 3. Formulaire prĂ©-rempli avec donnĂ©es existantes 4. Modification des champs souhaitĂ©s 5. Validation et mise Ă  jour via API 6. Synchronisation automatique avec Hive #### đŸ—‘ïž Suppression intelligente des membres La suppression des membres intĂšgre une **logique mĂ©tier avancĂ©e** pour prĂ©server l'intĂ©gritĂ© des donnĂ©es : ##### 🔍 VĂ©rification des passages ```dart // Algorithme de vĂ©rification 1. RĂ©cupĂ©ration de opĂ©ration courante 2. Analyse des passages du membre pour cette opĂ©ration 3. Classification : passages rĂ©alisĂ©s vs passages Ă  finaliser 4. Comptage total des passages actifs ``` ##### 📊 ScĂ©narios de suppression **Cas 1 : Aucun passage (suppression simple)** ```http DELETE /users/{id} ``` - Confirmation simple - Suppression directe - Aucun transfert nĂ©cessaire **Cas 2 : Passages existants (suppression avec transfert)** ```http DELETE /users/{id}?transfer_to={destinataire}&operation_id={operation} ``` - Dialog d'avertissement avec dĂ©tails - SĂ©lection obligatoire d'un membre destinataire - Transfert automatique de tous les passages - PrĂ©servation de l'historique **Cas 3 : Alternative recommandĂ©e (dĂ©sactivation)** ```dart // Mise Ă  jour du statut membre.copyWith(isActive: false) ``` - PrĂ©servation complĂšte des donnĂ©es - Blocage de la connexion - Maintien de l'historique - RĂ©activation possible ultĂ©rieurement ### 🔐 SĂ©curitĂ© et permissions #### ContrĂŽles d'accĂšs - **Isolation par amicale** : Admins limitĂ©s Ă  leur amicale - **VĂ©rification des rĂŽles** : Validation cĂŽtĂ© client et serveur - **OpĂ©ration courante** : Filtrage par contexte d'opĂ©ration - **Validation API** : ContrĂŽles d'unicitĂ© et cohĂ©rence #### Gestion des erreurs ```mermaid graph TD A[Action utilisateur] --> B[Validation locale] B --> C[Appel API] C --> D{SuccĂšs ?} D -->|Oui| E[Mise Ă  jour Hive] D -->|Non| F[Affichage erreur] E --> G[Notification succĂšs] F --> H[Dialog reste ouvert] ``` ### 🎹 Interface utilisateur #### Tableaux interactifs **MembreTableWidget** - Composant principal : - Colonnes : ID, PrĂ©nom, Nom, Email, RĂŽle, Statut - Actions : Modification, Suppression - Alternance de couleurs pour lisibilitĂ© - Tri et navigation intuitifs **MembreRowWidget** - Ligne individuelle : - Clic pour Ă©dition rapide - Boutons d'action contextuels - Indicateurs visuels de statut - Tooltip informatifs #### Formulaires adaptatifs **UserFormDialog** - Modale rĂ©utilisable : - Layout responsive (>900px vs mobile) - Validation en temps rĂ©el - Gestion des erreurs inline - Sauvegarde avec feedback ### 📡 Synchronisation et rĂ©activitĂ© #### Architecture ValueListenableBuilder ```dart // Écoute automatique des changements ValueListenableBuilder>( valueListenable: membreRepository.getMembresBox().listenable(), builder: (context, membresBox, child) { // Interface mise Ă  jour automatiquement final membres = membresBox.values .where((m) => m.fkEntite == currentUser.fkEntite) .toList(); return MembreTableWidget(membres: membres); }, ) ``` #### Principe "API First" 1. **Validation API** : Tentative sur serveur en prioritĂ© 2. **SuccĂšs** → Sauvegarde locale + mise Ă  jour interface 3. **Erreur** → Affichage message + maintien Ă©tat local 4. **CohĂ©rence** : DonnĂ©es locales toujours synchronisĂ©es ### 🔄 Workflow complet ```mermaid sequenceDiagram participant A as Admin participant UI as Interface participant R as Repository participant API as Serveur participant H as Hive A->>UI: Action membre UI->>R: Appel repository R->>API: RequĂȘte HTTP API-->>R: RĂ©ponse alt SuccĂšs R->>H: Sauvegarde locale H-->>UI: Notification changement UI-->>A: Interface mise Ă  jour else Erreur R-->>UI: Exception UI-->>A: Message d'erreur end ``` ### 🎯 Bonnes pratiques #### Pour les administrateurs 1. **VĂ©rification avant suppression** : Toujours examiner les passages 2. **PrĂ©fĂ©rer la dĂ©sactivation** : Éviter la perte de donnĂ©es 3. **Noms de tournĂ©e** : Utiliser des identifiants terrain clairs 4. **RĂŽles appropriĂ©s** : Limiter les administrateurs aux besoins #### Gestion des erreurs courantes | Erreur | Cause | Solution | | ----------------------- | ------------- | ------------------------ | | Email dĂ©jĂ  utilisĂ© | Duplication | Choisir un autre email | | Membre avec passages | DonnĂ©es liĂ©es | TransfĂ©rer ou dĂ©sactiver | | Aucune opĂ©ration active | Configuration | VĂ©rifier les opĂ©rations | | AccĂšs refusĂ© | Permissions | VĂ©rifier le rĂŽle admin | Cette architecture garantit une gestion des membres robuste, sĂ©curisĂ©e et intuitive, optimisant l'efficacitĂ© administrative tout en prĂ©servant l'intĂ©gritĂ© des donnĂ©es opĂ©rationnelles. đŸ‘„âœš ## đŸ—ș Cartes et gĂ©olocalisation ### 🎯 Architecture cartographique **Flutter Map** : Rendu cartographique haute performance **Providers de tuiles** : Solution hybride Mapbox/OpenStreetMap **GĂ©olocalisation temps rĂ©el** : Suivi GPS des Ă©quipes **Secteurs gĂ©ographiques** : Visualisation et attribution dynamique **Passages gĂ©olocalisĂ©s** : Enregistrement prĂ©cis des distributions ### 🌍 Configuration des tuiles de carte GEOSECTOR v2.0 utilise une **stratĂ©gie diffĂ©renciĂ©e** pour l'affichage des tuiles de carte selon la plateforme : #### **Configuration actuelle** | Plateforme | Provider | URL Template | Raison | |------------|----------|--------------|---------| | **Web** | Mapbox | `https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/` | Token compatible avec l'API styles | | **Mobile** | OpenStreetMap | `https://tile.openstreetmap.org/{z}/{x}/{y}.png` | Gratuit, sans restriction de token | #### **Pourquoi cette approche ?** 1. **ProblĂšme de permissions Mapbox** : Les tokens Mapbox actuels (DEV/REC/PROD) n'ont pas les permissions pour l'API `styles/v1` qui retourne une erreur 403 sur mobile 2. **Solution pragmatique** : OpenStreetMap fonctionne parfaitement sans token et offre une qualitĂ© de carte Ă©quivalente 3. **FacilitĂ© de maintenance** : Pas besoin de gĂ©rer des tokens diffĂ©rents selon les environnements ### đŸ’Ÿ SystĂšme de cache des tuiles Le cache fonctionne **pour les deux providers** (Mapbox et OpenStreetMap) : #### **Configuration du cache** ```dart // Dans mapbox_map.dart CachedTileProvider( store: FileCacheStore(cachePath), maxStale: Duration(days: 30), // Tuiles valides 30 jours ) ``` #### **Caches sĂ©parĂ©s par provider** - **Web (Mapbox)** : Cache dans `MapboxTileCache/` - **Mobile (OSM)** : Cache dans `OSMTileCache/` #### **Avantages du cache** ✅ **Mode hors ligne** : Les zones visitĂ©es restent disponibles sans connexion ✅ **Performance** : Chargement instantanĂ© des tuiles en cache ✅ **Économie de donnĂ©es** : Pas de re-tĂ©lĂ©chargement inutile ✅ **FiabilitĂ©** : Fonctionne mĂȘme avec une connexion instable ### 🔧 Widget MapboxMap centralisĂ© Le widget `MapboxMap` (`lib/presentation/widgets/mapbox_map.dart`) centralise toute la logique cartographique : #### **ParamĂštres principaux** ```dart MapboxMap( initialPosition: LatLng(48.1173, -1.6778), // Rennes initialZoom: 13.0, markers: [...], // Marqueurs (passages, etc.) polygons: [...], // Polygones (secteurs) useOpenStreetMap: !kIsWeb, // OSM sur mobile, Mapbox sur web showControls: true, // Boutons zoom/localisation ) ``` #### **Utilisation dans l'application** - **admin_map_page.dart** : Carte d'administration avec Ă©dition de secteurs - **user_map_page.dart** : Carte utilisateur avec visualisation des passages - **user_field_mode_page.dart** : Mode terrain avec GPS et boussole ### 🔄 Migration future vers Mapbox complet Si vous obtenez un token Mapbox avec les permissions appropriĂ©es : 1. **Retirer le paramĂštre** `useOpenStreetMap: !kIsWeb` dans les pages 2. **Le widget dĂ©tectera automatiquement** et utilisera Mapbox partout 3. **Le cache continuera de fonctionner** avec le nouveau provider ### đŸ“± Mode terrain (Field Mode) Le mode terrain offre des fonctionnalitĂ©s avancĂ©es pour les Ă©quipes sur le terrain : - **Indicateurs GPS** : QualitĂ© du signal (GPS/RĂ©seau) avec actualisation 5s - **Mode boussole** : Orientation de la carte selon le magnĂ©tomĂštre - **Markers optimisĂ©s** : Affichage simplifiĂ© (premiĂšre lettre de rueBis) - **Liste triĂ©e** : Passages organisĂ©s par distance - **Cercles de distance** : Visualisation des zones de proximitĂ© ## 🔄 Synchronisation et rĂ©activitĂ© ### Hive + ValueListenableBuilder RĂ©activitĂ© native : Mise Ă  jour automatique de l'interface Performance optimisĂ©e : Pas de Provider, injection directe Écoute sĂ©lective : RĂ©activitĂ© fine par Box Hive CohĂ©rence des donnĂ©es : Synchronisation bidirectionnelle User/Membre ### Services Singleton CurrentUserService : Gestion de l'utilisateur connectĂ© CurrentAmicaleService : Amicale de l'utilisateur actuel ApiService : Communication centralisĂ©e avec l'API DataLoadingService : Orchestration du chargement des donnĂ©es ## 🚀 Optimisation des performances Hive ### 📈 Gestion des Box Hive avec cache GEOSECTOR v2.0 implĂ©mente une **stratĂ©gie de cache avancĂ©e** pour les Box Hive afin d'Ă©liminer les goulots d'Ă©tranglement de performance lors d'opĂ©rations haute frĂ©quence. #### **🎯 ProblĂšme rĂ©solu** Avant l'optimisation, l'application effectuait jusqu'Ă  **848 vĂ©rifications** `Hive.isBoxOpen()` par chargement de page, causant des ralentissements significatifs lors du rendu des listes et du filtrage des donnĂ©es. #### **💡 Solution : Cache lazy des Box** ```dart // Pattern implĂ©mentĂ© dans tous les repositories class OptimizedRepository { Box? _cachedBox; Box get _modelBox { if (_cachedBox == null) { if (!Hive.isBoxOpen(AppKeys.boxName)) { throw Exception('Box non ouverte'); } _cachedBox = Hive.box(AppKeys.boxName); debugPrint('Repository: Box mise en cache'); } return _cachedBox!; } void _resetCache() { _cachedBox = null; } } ``` #### **🔄 Gestion du cache et rĂ©activitĂ©** **Point critique** : Le cache doit ĂȘtre rĂ©initialisĂ© aprĂšs **toute modification** pour garantir le bon fonctionnement de `ValueListenableBuilder` : ```dart // ✅ OBLIGATOIRE aprĂšs modification Future saveData(ModelType data) async { await _modelBox.put(data.id, data); _resetCache(); // ← Crucial pour la rĂ©activitĂ© UI notifyListeners(); } // ✅ OBLIGATOIRE aprĂšs suppression Future deleteData(int id) async { await _modelBox.delete(id); _resetCache(); // ← Crucial pour la rĂ©activitĂ© UI notifyListeners(); } // ✅ OBLIGATOIRE aprĂšs vidage ou traitement API Future processApiData(List data) async { await _modelBox.clear(); // ... traitement des donnĂ©es _resetCache(); // ← Crucial pour la rĂ©activitĂ© UI notifyListeners(); } ``` #### **📊 Impact performance** | MĂ©trique | Avant optimisation | AprĂšs optimisation | |----------|-------------------|-------------------| | **VĂ©rifications box** | 848 par page | 1 par session | | **Temps de rendu** | 200-500ms | <50ms | | **Filtrage liste** | Lent (check rĂ©pĂ©tĂ©s) | InstantanĂ© | | **MĂ©moire** | Overhead minimal | Impact nĂ©gligeable | #### **đŸ—ïž Repositories optimisĂ©s** L'optimisation est implĂ©mentĂ©e dans tous les repositories critiques : - ✅ **SectorRepository** : Gestion des secteurs gĂ©ographiques - ✅ **PassageRepository** : Suivi des distributions - ✅ **MembreRepository** : Gestion des Ă©quipes - ✅ **OperationRepository** : Campagnes et opĂ©rations - ✅ **AmicaleRepository** : Organisations #### **🎯 RĂšgles d'implĂ©mentation** 1. **Cache systĂ©matique** : Tous les repositories frĂ©quemment utilisĂ©s 2. **Reset obligatoire** : AprĂšs toute opĂ©ration de modification 3. **Getter lazy** : AccĂšs diffĂ©rĂ© Ă  la box uniquement si nĂ©cessaire 4. **Debug logging** : TraçabilitĂ© du cache en dĂ©veloppement 5. **CohĂ©rence** : Pattern appliquĂ© uniformĂ©ment Cette architecture garantit une application performante, maintenable et Ă©volutive avec une excellente expĂ©rience utilisateur. 🚀 ## 🎹 Architecture des Dialogs Auto-GĂ©rĂ©es ### 🎯 Principe de conception GEOSECTOR v2.0 implĂ©mente une **architecture simplifiĂ©e des dialogs** qui Ă©limine la complexitĂ© des callbacks asynchrones et garantit une gestion robuste des formulaires modaux. ### đŸ—ïž Pattern "Dialog Auto-GĂ©rĂ©e" ```mermaid graph TD A[Page Parente] -->|Injection Repository| B[Dialog Auto-GĂ©rĂ©e] B -->|Appel Direct| C[Repository] C -->|API Call| D[Serveur] D -->|RĂ©ponse| C C -->|Sauvegarde| E[Hive Local] B -->|Auto-Fermeture| A B -->|Callback Simple| A E -->|ValueListenableBuilder| A ``` ### ✹ Composants de l'architecture #### **1. Page Parente (ex: AdminOperationsPage)** ```dart // Ouverture simplifiĂ©e de dialog void _showEditOperationDialog(OperationModel op) { showDialog( context: context, builder: (dialogContext) => OperationFormDialog( operation: op, operationRepository: widget.operationRepository, // ← Injection directe onSuccess: () { if (mounted) setState(() {}); // ← Simple rafraĂźchissement }, ), ); } ``` #### **2. Dialog Auto-GĂ©rĂ©e (ex: OperationFormDialog)** ```dart // Gestion complĂšte dans la dialog void _handleSubmit() async { try { // Appel direct du repository final success = await widget.operationRepository.saveOperationFromModel(operationData); if (success && mounted) { // DĂ©lai pour synchronisation Hive Future.delayed(const Duration(milliseconds: 200), () { Navigator.of(context).pop(); // ← Auto-fermeture widget.onSuccess?.call(); // ← Notification simple ApiException.showSuccess(context, "OpĂ©ration sauvegardĂ©e"); }); } } catch (e) { ApiException.showError(context, e); // ← Erreur sans fermeture } } ``` ### 🎯 Avantages de cette approche | Aspect | Avant (Complexe) | AprĂšs (SimplifiĂ©) | | --------------------- | --------------------- | ------------------------------------ | | **Callbacks** | Asynchrones complexes | Simple `onSuccess: () => setState()` | | **Fermeture** | GĂ©rĂ©e par le parent | Auto-fermeture dans la dialog | | **Gestion d'erreurs** | DispersĂ©e | CentralisĂ©e dans la dialog | | **Synchronisation** | ProblĂ©matique | DĂ©lai de 200ms pour Hive | | **Maintenance** | Code dispersĂ© | Logique unifiĂ©e | ### 🔧 ResponsabilitĂ©s claires #### **Page Parente** - ✅ Ouverture des dialogs avec injection de dĂ©pendances - ✅ RafraĂźchissement de l'interface via `setState()` - ✅ Gestion des tableaux et listes intĂ©grĂ©s #### **Dialog Auto-GĂ©rĂ©e** - ✅ Validation et soumission du formulaire - ✅ Appel direct des repositories - ✅ Auto-fermeture en cas de succĂšs - ✅ Gestion des erreurs sans fermeture #### **Repository** - ✅ Logique mĂ©tier (crĂ©ation vs modification) - ✅ Appels API appropriĂ©s - ✅ Sauvegarde locale dans Hive - ✅ Propagation des exceptions ### 🚀 Exemple d'implĂ©mentation ```dart // 1. Page parente - Code minimal void _showCreateDialog() { showDialog( context: context, builder: (context) => OperationFormDialog( title: 'CrĂ©er une opĂ©ration', operationRepository: widget.operationRepository, onSuccess: () => setState(() {}), ), ); } // 2. Dialog - Auto-gestion complĂšte class OperationFormDialog extends StatefulWidget { final OperationRepository operationRepository; final VoidCallback? onSuccess; // Gestion interne : validation, API, fermeture, erreurs } // 3. Repository - Logique mĂ©tier pure Future saveOperationFromModel(OperationModel operation) async { if (operation.id == 0) { return await createOperation(...); // POST } else { return await updateOperation(...); // PUT } } ``` ### ✅ RĂ©sultats obtenus - **🎯 SimplicitĂ©** : Code plus lisible et maintenable - **🔒 Robustesse** : Gestion d'erreurs centralisĂ©e - **⚡ Performance** : Synchronisation optimisĂ©e avec Hive - **🎹 UX** : Fermeture automatique et messages appropriĂ©s - **🔧 Maintenance** : Architecture cohĂ©rente et prĂ©visible Cette approche **"Dialog Auto-GĂ©rĂ©e"** constitue un pattern architectural clĂ© de GEOSECTOR v2.0, garantissant une expĂ©rience utilisateur fluide et un code maintenable. 🎉 ## Fonction de crĂ©ation d'une opĂ©ration ## Fonction de crĂ©ation d'une opĂ©ration ### 🔄 Traitement des donnĂ©es complexes Lors de la crĂ©ation d'une opĂ©ration via `OperationRepository.createOperation()`, l'API retourne en rĂ©ponse **201 Created** ou **200 OK** un payload complexe contenant 4 groupes de donnĂ©es essentiels : ```json { "operations": [...], // 3 derniĂšres opĂ©rations dont la nouvelle active "secteurs": [...], // Secteurs de la nouvelle opĂ©ration active "passages": [...], // Passages de la nouvelle opĂ©ration active "users_sectors": [...] // Associations user-secteurs de la nouvelle opĂ©ration } ``` ### 📩 Groupes de donnĂ©es attendus #### 🎯 Groupe **operations** Contient les **3 derniĂšres opĂ©rations** de l'amicale, incluant celle qui vient d'ĂȘtre créée et qui devient automatiquement active. #### đŸ—ș Groupe **secteurs** Contient tous les **secteurs gĂ©ographiques** associĂ©s Ă  la derniĂšre opĂ©ration créée et active. #### 📍 Groupe **passages** Contient l'ensemble des **passages** gĂ©nĂ©rĂ©s pour cette derniĂšre opĂ©ration créée et active. #### đŸ‘„ Groupe **users_sectors** Contient les **associations utilisateur-secteurs** dĂ©finissant les attributions pour cette derniĂšre opĂ©ration créée et active. ### ⚙ Traitement automatique des donnĂ©es Ces 4 groupes sont traitĂ©s de maniĂšre identique au processus de connexion utilisateur, en utilisant le **DataLoadingService** avec la logique suivante : ```dart // Dans OperationRepository._processCreationResponse() await _processOperationCreationData(responseData); Future _processOperationCreationData(Map data) async { // 1. Vidage des Box Hive concernĂ©es (comme au login) await _clearRelatedBoxes(); // 2. Traitement des 4 groupes via DataLoadingService if (data.containsKey('operations')) { await DataLoadingService.instance.processOperationsFromApi(data['operations']); } if (data.containsKey('secteurs')) { await DataLoadingService.instance.processSectorsFromApi(data['secteurs']); } if (data.containsKey('passages')) { await DataLoadingService.instance.processPassagesFromApi(data['passages']); } if (data.containsKey('users_sectors')) { await DataLoadingService.instance.processUserSectorsFromApi(data['users_sectors']); } } Future _clearRelatedBoxes() async { // Vidage des Box respectives avant rechargement final operationsBox = HiveService.instance.getTypedBox(AppKeys.operationsBoxName); final sectorsBox = HiveService.instance.getTypedBox(AppKeys.sectorsBoxName); final passagesBox = HiveService.instance.getTypedBox(AppKeys.passagesBoxName); final userSectorsBox = HiveService.instance.getTypedBox(AppKeys.userSectorBoxName); await operationsBox.clear(); await sectorsBox.clear(); await passagesBox.clear(); await userSectorsBox.clear(); } ``` ### 🔄 Flux de synchronisation ```mermaid sequenceDiagram participant UI as Interface participant OR as OperationRepository participant API as Serveur API participant HS as HiveService participant DLS as DataLoadingService participant VLB as ValueListenableBuilder UI->>OR: createOperation(newOperation) OR->>API: POST /operations API-->>OR: 201 Created + 4 groupes Note over OR: Traitement des donnĂ©es complexes OR->>HS: clear() sur 4 Box concernĂ©es OR->>DLS: processOperationsFromApi() OR->>DLS: processSectorsFromApi() OR->>DLS: processPassagesFromApi() OR->>DLS: processUserSectorsFromApi() Note over DLS: Sauvegarde dans Hive DLS->>HS: put() dans Box typĂ©es HS-->>VLB: Notifications de changement VLB-->>UI: Mise Ă  jour automatique ``` ### ✅ Avantages de cette approche - **CohĂ©rence totale** : DonnĂ©es locales parfaitement synchronisĂ©es avec le serveur - **Performance optimisĂ©e** : Un seul appel API pour toutes les donnĂ©es nĂ©cessaires - **RĂ©activitĂ© immĂ©diate** : Interface mise Ă  jour automatiquement via ValueListenableBuilder - **Logique centralisĂ©e** : RĂ©utilisation du DataLoadingService existant - **Gestion d'erreurs** : Rollback automatique en cas d'Ă©chec du traitement Cette architecture garantit une synchronisation robuste et performante lors de la crĂ©ation d'opĂ©rations, en maintenant la cohĂ©rence des donnĂ©es tout en optimisant l'expĂ©rience utilisateur. 🚀