Files
geo/app/README-APP.md
pierre 1018b86537 feat: Gestion des secteurs et migration v3.0.4+304
- Ajout système complet de gestion des secteurs avec contours géographiques
- Import des contours départementaux depuis GeoJSON
- API REST pour la gestion des secteurs (/api/sectors)
- Service de géolocalisation pour déterminer les secteurs
- Migration base de données avec tables x_departements_contours et sectors_adresses
- Interface Flutter pour visualisation et gestion des secteurs
- Ajout thème sombre dans l'application
- Corrections diverses et optimisations

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-07 11:01:45 +02:00

1049 lines
36 KiB
Markdown
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 |
### 🏛️ 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é"
## 🎯 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<Box<MembreModel>>(
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
Flutter Map : Rendu cartographique haute performance
Tuiles Mapbox : Cartographie détaillée et personnalisable
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
## 🔄 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<ModelType>? _cachedBox;
Box<ModelType> get _modelBox {
if (_cachedBox == null) {
if (!Hive.isBoxOpen(AppKeys.boxName)) {
throw Exception('Box non ouverte');
}
_cachedBox = Hive.box<ModelType>(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<void> saveData(ModelType data) async {
await _modelBox.put(data.id, data);
_resetCache(); // ← Crucial pour la réactivité UI
notifyListeners();
}
// ✅ OBLIGATOIRE après suppression
Future<void> deleteData(int id) async {
await _modelBox.delete(id);
_resetCache(); // ← Crucial pour la réactivité UI
notifyListeners();
}
// ✅ OBLIGATOIRE après vidage ou traitement API
Future<void> processApiData(List<dynamic> 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<bool> 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<void> _processOperationCreationData(Map<String, dynamic> 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<void> _clearRelatedBoxes() async {
// Vidage des Box respectives avant rechargement
final operationsBox = HiveService.instance.getTypedBox<OperationModel>(AppKeys.operationsBoxName);
final sectorsBox = HiveService.instance.getTypedBox<SectorModel>(AppKeys.sectorsBoxName);
final passagesBox = HiveService.instance.getTypedBox<PassageModel>(AppKeys.passagesBoxName);
final userSectorsBox = HiveService.instance.getTypedBox<UserSectorModel>(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. 🚀