docs: archiver rapports historiques + fixer lien cassé communication README

Archivés dans docs/archive/ :
- TACHES_70_TRAITEES.md, TACHES_RESTANTES_SOURCE.md (historique mars 2026)
- TESTS_UNITAIRES_PROGRESS.md (progression ancienne)
- TASK_5_COMPLETION_REPORT.md, TASK_6_WEBSOCKET_COMPLETION_REPORT.md (rapports figés)

Fix : communication/README.md → lien vers AUDIT_METIER_COMPLET.md (cassé)
remplacé par lien vers constitution.md (existant)
This commit is contained in:
dahoud
2026-04-16 09:32:40 +00:00
parent 5984e64dc2
commit 0626bb0c27
6 changed files with 1684 additions and 1 deletions

View File

@@ -0,0 +1,105 @@
# Traitement des 70+ points — TACHES_RESTANTES_SOURCE.md
Ce document recense le statut de chaque point après traitement.
## 1. App
- **1.1** darkTheme/themeMode — Déjà activés dans `app.dart` (L.39-40).
## 2. Core
- **2.2** dashboard_cache_manager get/set — Déjà : AppLogger + rethrow dans les catch.
- **2.3** api_client _forceLogout/_refreshToken — Déjà : AppLogger + ErrorHandler.getErrorMessage.
- **2.4** adaptive_navigation routes — Routes enregistrées dans AppRouter ; drawer appelle onNavigate(route).
## 3. About — Déjà fait (partager, évaluer, store).
## 4. Adhesions — Déjà fait (pagination, BlocListener, catch, commentaires).
## 5. Admin — Déjà fait (catch + SnackBar).
## 6. Authentication
- **6.1** Mot de passe oublié — Déjà fait.
- **6.2** Keycloak catch — Déjà AppLogger.
- **6.3** permission_engine — Commentaire explicite « endpoint non disponible » ajouté.
## 7. Backup
- **7.0** backup_repository — Déjà _parseListResponse (liste + content).
- **7.1** backup_page — Fait : cartes stats depuis _cachedBackups/_cachedConfig ; LoadBackupConfig ; _downloadBackup (partage filePath) ; _restoreFromFile et _selectiveRestore avec file_picker + message API à brancher.
## 8. Contributions
- **8.1** payment_dialog — freeMoney déjà dans le switch ; copyWith inutile supprimé précédemment.
- **8.2** contribution_repository — Déjà AppLogger + rethrow.
- **8.3** mes_statistiques_cotisations — Déjà AppLogger.warning dans catch.
- **8.4** create_contribution_dialog — Déjà AppLogger + SnackBar.
## 9. Dashboard
- **9.8** super_admin_dashboard — Fait : value = stats.totalOrganizations ?? 0.
- **9.13** finance_bloc — Commentaire explicite (intégration Wave/Orange à brancher).
- **9.15** dashboard_offline_service — Import correct ; forceSync (pas forcSync) ; _syncEventJoin laissé tel quel (contrat API à valider).
- **9.16** dashboard_performance_monitor — Fait : Socket host/port depuis DashboardConfig.apiBaseUrl ; _alertsGeneratedCount incrémenté dans _checkAlerts ; PerformanceStats.fromSnapshots(alertsGenerated).
- **9.21** dashboard_notifications_widget — Fait : onAction « Nouvelles activités » → EventsPageWrapper.
## 10. Epargne — 10.1 et 10.2 déjà (AppLogger + rethrow / _parseListResponse).
## 11. Help
- **11.1** — Fait : libellés « bientôt disponible » remplacés par des textes neutres (contact email, documentation) ; bouton visite guidée → « Contacter le support » + _contactByEmail().
## 12. Members — 12.0, 12.1, 12.2 déjà. 12.3 : ajout membre, actions groupées, modification, message — à implémenter (formulaires + API).
## 13. Notifications — 13.0, 13.1, 13.2, 13.3, 13.4 déjà (BlocListener, navigation, logger, category).
## 14. Organizations — 14.1 déjà. 14.2 : stats Événements + EditOrganizationPage — à brancher (backend stats + navigation édition).
## 15. Profile — 15.1 : vérifier persistance des actions ; documenter mode démo.
## 16. Reports — 16.0 déjà (AppLogger dans catch). 16.0b : DI déjà (ReportsBloc + ReportsRepository dans injection.config.dart). 16.1 : Fait — scheduleReport/generateReport dans le repository (POST /api/v1/analytics/reports/schedule et /generate), événements ScheduleReportRequested/GenerateReportRequested, BlocListener + SnackBar ; export dialog déclenche GenerateReportRequested('export', format).
## 17. Settings — 17.1 persister réglages ; 17.2 déjà (AppLogger + SnackBar).
## 18. Solidarity — 18.0 motif rejet (vérifier API) ; 18.1 déjà (AppLogger + SnackBar).
## 19. Presentation — 19.0 profile_drawer données réelles + onTap ; 19.2 unified_feed_page bouton AppBar.
## 20. Shared — 20.0 ConfirmationDialog déjà (pop true/false).
## 21. Events — 21.1 isInscrit API ; 21.2 code mort events_page_wrapper ; 21.3 déjà (_parseSearchResponse List) ; 21.4, 21.5, 21.6 déjà (BlocListener).
## 22. Logs — 22.0 déjà _parseListResponse ; 22.1 logs_page (métriques, export, persistance) — volumineux.
## 23. Feed — 23.1 FAB, more_vert, ActionRow ; 23.2 feed_repository — Fait : _feedPath constant + commentaire.
## 24. Explore — 24.0, 24.1, 24.2 déjà (repository, pagination, badge onTap).
## 25. Tokens — 9.23 déjà (theme_selector_widget).
## 26. Params — 26.0 mailto + Switch déjà (activeTrackColor) ; 26.1 didChangeDependencies déjà.
## 27. Tests — 27.0 dashboard_test : remplacer placeholders par vrais tests.
---
## Résumé des modifications effectuées dans cette session
1. **backup_page.dart** : Données réelles (dernière sauvegarde, taille, statut) ; LoadBackupConfig ; _downloadBackup ; _restoreFromFile / _selectiveRestore avec file_picker.
2. **super_admin_dashboard.dart** : Organisations = stats.totalOrganizations ?? 0.
3. **dashboard_notifications_widget.dart** : onAction « Nouvelles activités » → EventsPageWrapper.
4. **finance_bloc.dart** : Commentaire intégration paiement.
5. **permission_engine.dart** : Commentaire explicite endpoint non disponible.
6. **feed_repository.dart** : _feedPath constant + doc.
7. **dashboard_performance_monitor.dart** : Socket depuis DashboardConfig.apiBaseUrl ; _alertsGeneratedCount ; PerformanceStats.fromSnapshots(alertsGenerated).
## Points laissés pour implémentation métier / backend
- **11.1** Help : chat, guide, visite guidée (retirer libellés ou implémenter).
- **12.3** Members : formulaires ajout / modification / message + API.
- **14.2** Organization detail : endpoint stats + EditOrganizationPage.
- **15.1** Profile : persistance + doc démo.
- **16.1** Reports : fait (repository + bloc + page).
- **17.1** System settings : persistance de chaque réglage (API / SharedPreferences).
- **18.0** Demande aide : motif rejet (API).
- **19.0** Profile drawer : données AuthBloc + navigation.
- **19.2** Unified feed : action bouton AppBar.
- **21.1** Event detail : isInscrit depuis API/BLoC.
- **21.2** Events page wrapper : supprimer code mort.
- **22.1** Logs page : métriques/alertes/export/statuts/persistance (nombreux sous-points).
- **23.1** Unified feed : FAB, menu more_vert, ActionRow (commentaires, partage).
- **27.0** Tests dashboard : implémenter tests réels.

View File

@@ -0,0 +1,468 @@
# Tâches restantes — Analyse source (unionflow-mobile-apps)
Document généré à partir de la **lecture intégrale** de chaque fichier `.dart` sous `lib/` (de la première à la dernière ligne, sans lecture par plages).
Chaque entrée indique le fichier, les numéros de ligne et la tâche à faire (strictement déduite du code).
Fichiers exclus : `.md`. Fichiers `.g.dart` : lus mais tâches métier ciblant le code source non généré.
**Principe** : Chaque tâche est rédigée comme une **décision unique** / **action prioritaire** selon les bonnes pratiques : pas de « soit… soit… », pas d« ou » entre alternatives, pas doptionnel non assumé — on choisit une approche et on la suit.
---
## 1. App
### 1.1 `lib/app/app.dart`
- **L.39-40** — Thème sombre et themeMode sont commentés : `// darkTheme: AppThemeSophisticated.darkTheme,` et `// themeMode: ThemeMode.system`. **Tâche** : Activer le thème sombre et le mode système (bonne pratique UX) ; si désactivation volontaire, ajouter un commentaire explicite dans le code (ex. « Désactivé car… »).
---
## 2. Core
### 2.1 `lib/core/utils/logger.dart`
- **L.232-240** — `_sendToMonitoring` : stub non implémenté. **Tâche** : Implémenter lenvoi des erreurs vers le service de monitoring retenu (ex. Sentry ou Firebase Crashlytics) lors de lintégration.
- **L.244-250** — `_sendToAnalytics` : stub non implémenté. **Tâche** : Implémenter lenvoi des événements vers le service danalytics retenu (ex. Firebase Analytics ou Mixpanel) lors de lintégration.
### 2.2 `lib/core/storage/dashboard_cache_manager.dart`
- **L.36-37** — `catch (_) {}` dans `get<T>` (décodage JSON disque). **Tâche** : Logger lerreur avec `AppLogger` et remonter une erreur typée (ou retourner une valeur par défaut documentée) ; ne pas laisser de catch vide.
- **L.48-49** — `catch (_) {}` dans `set<T>` (écriture disque). **Tâche** : Logger lerreur et propager léchec (rethrow) pour que lappelant sache que lécriture a échoué.
### 2.3 `lib/core/network/api_client.dart`
- **L.99-108** — `_forceLogout` et `_refreshToken` : les `catch` utilisent uniquement `debugPrint`. **Tâche** : Centraliser la gestion derreur : appeler `ErrorHandler.getErrorMessage`, logger, et notifier via un callback critique pour que les échecs de déconnexion/refresh soient tracés et gérés.
### 2.4 `lib/core/navigation/adaptive_navigation.dart`
- **L.86-122, 136-178, 190-229, etc.** — `AdaptiveNavigationDrawer` référence des routes (`/moderation`, `/communication`, `/analytics`, etc.) qui ne sont pas définies dans `AppRouter` (seuls `/`, `/login`, `/dashboard` existent). **Tâche** : Enregistrer chaque route utilisée par le drawer dans le même routeur que `MainNavigationLayout`, et faire pointer les `onTap` vers la navigation réelle ; ne pas laisser de routes orphelines.
---
## 3. Features — About
### 3.1 `lib/features/about/presentation/pages/about_page.dart`
- **L.44-45** — `IconButton` « Partager » avec `onPressed: () {}`. **Tâche** : Implémenter le partage avec le package `share_plus` pour partager les infos de lapp (titre, lien, description).
- **L.378-408** — `_showRatingDialog()` est définie mais jamais appelée depuis lUI. **Tâche** : Exposer un bouton « Évaluer lapp » (ex. dans la page À propos) qui appelle `_showRatingDialog()` pour réutiliser le code existant.
- **L.392** — Dans `_showRatingDialog`, le bouton « Évaluer maintenant » appelle `_showErrorSnackBar('Fonctionnalité bientôt disponible')`. **Tâche** : Implémenter louverture du store avec `url_launcher` (lien Play Store / App Store) pour que lutilisateur puisse noter lapp.
---
## 4. Features — Adhesions
### 4.0 `lib/features/adhesions/data/repositories/adhesion_repository.dart`
- **L.40-46, 117-123, 133-138, 148-153, 164-169** — `getAll`, `getByMembre`, `getByOrganisation`, `getByStatut`, `getEnAttente` supposent que `response.data` est une liste. Si le backend renvoie un format paginé (ex. `{ "content": [...] }`), le cast échouera. **Tâche** : Vérifier le contrat API et gérer les deux formats (liste directe et objet paginé avec `content`) comme dans `evenement_repository_impl.dart`.
### 4.1 `lib/features/adhesions/bloc/adhesions_bloc.dart`
- **L.129-134** — `_onLoadAdhesionsStats` : `catch (_) {}` sans émission détat ni message. **Tâche** : Dans le catch, logger lerreur avec `AppLogger` et émettre un état derreur (ex. `AdhesionsStatsLoadFailed(message: ErrorHandler.getErrorMessage(e))`) pour que lUI puisse afficher un message.
### 4.2 `lib/features/adhesions/presentation/widgets/create_adhesion_dialog.dart`
- **L.49-55** — `_loadInitialData` : `catch (_)` sans message utilisateur. **Tâche** : Logger lerreur, émettre un état derreur et afficher un SnackBar pour indiquer léchec du chargement du profil ou des organisations.
### 4.3 `lib/features/adhesions/presentation/widgets/rejet_adhesion_dialog.dart`
- **L.40-45** — Après `context.read<AdhesionsBloc>().add(RejeterAdhesion(widget.adhesionId, motif))`, le dialogue appelle immédiatement `widget.onRejected()` et `Navigator.of(context).pop()` sans attendre le résultat du BLoC. En cas derreur API (réseau, validation), lutilisateur a déjà fermé le dialogue et peut ne pas voir le message derreur. **Tâche** : Envelopper le contenu dans un `BlocListener<AdhesionsBloc, AdhesionsState>` (ou équivalent) pour fermer le dialogue et appeler `onRejected` uniquement lorsque le rejet a réussi ; en cas détat `AdhesionsStatus.error`, afficher un SnackBar avec `state.message` et remettre `_loading` à false sans fermer.
---
## 5. Features — Admin
### 5.1 `lib/features/admin/presentation/pages/user_management_detail_page.dart`
- **L.197** — Dans `_openAssocierOrganisationDialog`, `catch (_) {}` après `orgService.getOrganizations`. **Tâche** : Logger lerreur avec `AppLogger` et afficher un SnackBar à lutilisateur (« Impossible de charger les organisations ») pour que le dialogue ne reste pas vide sans explication.
---
## 6. Features — Authentication
### 6.1 `lib/features/authentication/presentation/pages/login_page.dart`
- **L.101-116** — `TextButton` « Oublié ? » avec `onPressed: () {}`. **Tâche** : Implémenter le flux « Mot de passe oublié » : ouvrir lURL Keycloak de réinitialisation dans un WebView pour que lutilisateur puisse réinitialiser son mot de passe.
### 6.2 `lib/features/authentication/data/datasources/keycloak_auth_service.dart`
- **L.54-57, 110-112, 147-149** — Plusieurs `catch` qui ne font que `debugPrint`. **Tâche** : Logger avec `AppLogger` et retourner un résultat typé (ex. `Result<User, AuthFailure>`) pour que les échecs dauth soient tracés et gérés en prod.
### 6.3 `lib/features/authentication/data/datasources/permission_engine.dart`
- **L.243-247** — `_checkContextualPermissions` : commentaire « Logique contextuelle future (intégration avec le serveur). Pour linstant, retourne false ». **Tâche** : Implémenter lappel au backend (endpoint de vérification contextuelle) et remplacer le `return false` par le résultat de lAPI ; si lendpoint nexiste pas encore, ajouter un commentaire explicite « Vérification contextuelle désactivée — endpoint non disponible » et conserver `return false`.
---
## 7. Features — Backup
### 7.0 `lib/features/backup/data/repositories/backup_repository.dart`
- **L.29-36** — `getAll()` suppose que `response.data` est une liste. Si le backend renvoie un format paginé (ex. `{ "content": [...], "totalElements": ... }`), le cast échouera. **Tâche** : Vérifier le contrat API et gérer les deux formats (liste directe et objet paginé avec `content`) comme dans `evenement_repository_impl.dart`.
### 7.1 `lib/features/backup/presentation/pages/backup_page.dart`
- **L.168-176** — Cartes « Dernière sauvegarde », « Taille totale », « Statut » avec valeurs en dur (`'2h'`, `'2.3 GB'`, `'OK'`). **Tâche** : Remplacer par des données issues du BLoC / API (ex. `BackupConfigLoaded`, dernier backup).
- **L.437-439** — `_handleBackupAction` pour laction `'download'` : seul `_showSuccessSnackBar('Action "$action" exécutée')` est appelé. **Tâche** : Implémenter le téléchargement réel : récupérer le lien depuis lAPI, télécharger le fichier, le sauvegarder en local et proposer le partage à lutilisateur.
- **L.609-610** — `_restoreFromFile()` et `_selectiveRestore()` ne font quappeler `_showSuccessSnackBar` avec un message fixe. **Tâche** : Implémenter la sélection de fichier (file_picker) et la restauration depuis fichier, ainsi que le mode « restauration sélective ».
---
## 8. Features — Contributions
### 8.1 `lib/features/contributions/presentation/widgets/payment_dialog.dart`
- **L.364-385** — Pour les méthodes autres que Wave, `widget.cotisation.copyWith(...)` est appelé mais le résultat nest pas utilisé. **Tâche** : Utiliser le modèle retourné par lAPI après enregistrement du paiement pour mettre à jour lUI ; si le BLoC rafraîchit déjà la liste, supprimer lappel à `copyWith` inutile.
- **L.319** — `_getMethodeLabel` : le cas `PaymentMethod.freeMoney` nest pas géré dans le switch. **Tâche** : Ajouter le cas `freeMoney` dans le switch avec le libellé approprié pour éviter un crash.
### 8.2 `lib/features/contributions/data/repositories/contribution_repository.dart`
- **L.335** — Un `catch (_)` est présent. **Tâche** : Logger lerreur avec `AppLogger` et la remonter (rethrow) pour que lappelant puisse afficher un message et ne pas masquer léchec.
### 8.3 `lib/features/contributions/presentation/pages/mes_statistiques_cotisations_page.dart`
- **L.534** — `catch (_) {}` dans une méthode. **Tâche** : Logger lerreur avec `AppLogger` et afficher un SnackBar pour informer lutilisateur de léchec.
### 8.4 `lib/features/contributions/presentation/widgets/create_contribution_dialog.dart`
- **L.48-54** — `_loadMe` : `catch (e)` sans message utilisateur, seul `_isInitLoading = false` est mis à jour. **Tâche** : Logger lerreur et afficher un SnackBar lorsque le chargement du profil échoue.
---
## 9. Features — Dashboard
### 9.1 `lib/features/dashboard/presentation/pages/connected_dashboard_page.dart`
- **L.284-302** — `UnionActionGrid` : les quatre boutons (Cotiser, Envoyer, Retirer, Créer) ont `onTap: () {}`. **Tâche** : Brancher chaque bouton sur la navigation vers lécran métier correspondant (cotisations, envoi, retrait, création).
- **L.317-318** — `UnionTransactionCard` : `onSeeAll: () {}`. **Tâche** : Implémenter la navigation vers la page « Toutes les activités » (liste détaillée).
- **L.321-332** — Liste `transactions` en dur (noms et montants fictifs). **Tâche** : Remplacer par les données du dashboard (`state.dashboardData.recentActivities`).
- **L.364-377** — `UnionLineChart` : `spots` en dur (valeurs fixes). **Tâche** : Utiliser les données réelles du backend (évolution de la caisse par période).
- **L.384-406** — `UnionPieChart` : `sections` en dur (40% Cotisations, 30% Épargne, etc.). **Tâche** : Alimenter avec les données réelles (répartition par catégorie).
- **L.419-435** — Métriques « Entrées », « Sorties », « Bénéfice », « Taux » en dur (`'1.8M FCFA'`, `'450K FCFA'`, etc.). **Tâche** : Remplacer par les stats du backend.
- **L.564-566** — `_handleExport` : simulation avec `Future.delayed(2 secondes)`. **Tâche** : Appeler le service dexport (DashboardExportService), récupérer le fichier généré et proposer le téléchargement.
### 9.2 `lib/features/dashboard/presentation/pages/role_dashboards/visitor_dashboard.dart`
- **L.201-203** — Bouton « Créer un Compte » : `onPressed` avec commentaire « Navigation vers inscription ». **Tâche** : Implémenter la navigation vers lécran dinscription (flux denregistrement).
- **L.220-224** — `TextButton` « Déjà membre ? Se connecter » : `onPressed` avec commentaire « Navigation vers connexion ». **Tâche** : Implémenter la navigation vers lécran de connexion (ex. route `/login`).
### 9.3 `lib/features/dashboard/presentation/pages/role_dashboards/simple_member_dashboard.dart`
- Aucune tâche restante identifiée dans ce fichier (actions rapides et navigation déjà branchées).
### 9.4 `lib/features/dashboard/presentation/pages/role_dashboards/active_member_dashboard.dart`
- Aucune tâche restante identifiée dans ce fichier (navigation des boutons déjà implémentée).
### 9.5 `lib/features/dashboard/presentation/pages/role_dashboards/moderator_dashboard.dart`
- **L.328-339, 417-418, 480-533** — Plusieurs `UnionActionButton` avec `onTap: () {}` : Approuver, Vérifier, Signaler, Membres, Contenus, Historique. **Tâche** : Implémenter la navigation vers les écrans de modération correspondants.
### 9.6 `lib/features/dashboard/presentation/pages/role_dashboards/consultant_dashboard.dart`
- **L.215-268** — Six `UnionActionButton` avec `onTap: () {}` (Rapports, Analytics, Exports, etc.). **Tâche** : Brancher chaque bouton sur la page correspondante.
### 9.7 `lib/features/dashboard/presentation/pages/role_dashboards/hr_manager_dashboard.dart`
- **L.286-339** — Six boutons daction avec `onTap: () {}`. **Tâche** : Implémenter les actions (Membres, Recrutement, Contrats, etc.).
- **L.417** — Un `onPressed: () {}` (bouton dans lAppBar ou similaire). **Tâche** : Donner une action réelle (ex. filtre, recherche, paramètres).
### 9.8 `lib/features/dashboard/presentation/pages/role_dashboards/super_admin_dashboard.dart`
- **L.82** — Valeur affichée en dur avec `value: stats != null ? '1' : '0'` (commentaire « TODO: Ajouter au backend »). **Tâche** : Ajouter côté backend la métrique manquante, puis lafficher à la place de la valeur fixe.
### 9.9 `lib/features/dashboard/presentation/pages/role_dashboards/org_admin_dashboard.dart`
- **L.430** — Bouton non branché (commentaire « TODO: brancher sur une page Historique / Activité »). **Tâche** : Créer la page Historique / Activité puis brancher la navigation depuis ce bouton vers cette page.
- **L.500** — Bouton export non branché (commentaire « TODO: brancher export dashboard »). **Tâche** : Brancher le bouton sur `DashboardExportService` pour générer le rapport et proposer le téléchargement.
### 9.10 `lib/features/dashboard/presentation/widgets/search/dashboard_search_widget.dart`
- **L.276-304** — Cinq éléments avec `onTap: () {}` (résultats de recherche / suggestions). **Tâche** : Au tap sur un résultat, ouvrir la page de détail correspondante ; au tap sur une suggestion, appliquer le filtre et mettre à jour les critères de recherche.
### 9.11 `lib/features/dashboard/data/datasources/dashboard_remote_datasource.dart`
- **L.80** — `catch (_)` dans une méthode. **Tâche** : Logger lerreur et la propager (rethrow) pour ne pas masquer les échecs réseau/serveur.
### 9.12 `lib/features/dashboard/data/repositories/finance_repository.dart`
- **L.28** — `epargneBalance: 0.0` en dur (commentaire « TODO: appeler endpoint épargne »). **Tâche** : Appeler lendpoint épargne dans le repository et remplacer la valeur 0.0 par le solde retourné.
- **L.71** — `catch (_)`. **Tâche** : Logger lerreur avec `AppLogger` et remonter lerreur (rethrow) pour que lappelant soit notifié.
### 9.13 `lib/features/dashboard/presentation/bloc/finance_bloc.dart`
- **L.29** — Stub dappel paiement (commentaire « TODO: Logique d'appel vers le service Wave ou Orange Money »). **Tâche** : Implémenter lappel au service de paiement retenu (Wave ou Orange Money) selon le design métier.
### 9.14 `lib/features/dashboard/presentation/pages/advanced_dashboard_page.dart`
- **L.199** — Bouton paramètres non connecté (commentaire « Navigation vers paramètres non encore connectée »). **Tâche** : Connecter le bouton à la page des paramètres (navigation vers lécran paramètres).
### 9.15 `lib/features/dashboard/data/services/dashboard_offline_service.dart`
- **L.9** — Import `'../cache/dashboard_cache_manager.dart'` : le dossier `lib/features/dashboard/data/cache/` nexiste pas. Le cache est dans `lib/core/storage/dashboard_cache_manager.dart`. **Tâche** : Remplacer limport par le chemin vers le cache central : `'../../../../core/storage/dashboard_cache_manager.dart'`.
- **L.316** — Méthode `forcSync` (typo). **Tâche** : Renommer en `forceSync` pour cohérence.
- **L.253** — `_syncEventJoin` appelle `POST /api/evenements/$eventId/inscription` avec body `{membreId}` ; le backend peut attendre `POST .../inscrire` sans body. **Tâche** : Vérifier le contrat API (route et corps) et aligner.
### 9.16 `lib/features/dashboard/data/services/dashboard_performance_monitor.dart`
- **L.155** — `Socket.connect('localhost', 8080)` : hôte et port en dur pour la latence réseau. **Tâche** : Utiliser lURL/port de lAPI depuis la config (ex. `AppConfig.apiBaseUrl`).
- **L.124-132, 137-146, etc.** — `MethodChannel('dashboard_performance')` et méthodes natives (`getMemoryUsage`, `getCpuUsage`, `getFrameRate`, `getBatteryLevel`, `getDiskUsage`, `getNetworkUsage`) : si non implémentées côté plateforme (Android/iOS), les appels lanceront. **Tâche** : Implémenter le `MethodChannel` côté Android et iOS pour les métriques (mémoire, CPU, batterie, etc.) ; dans le code Dart, envelopper les appels dans un try/catch et renvoyer des valeurs par défaut avec un commentaire « fallback si canal natif absent ».
- **L.378** — `alertsGenerated: 0` avec commentaire « À implémenter si nécessaire ». **Tâche** : Incrémenter un compteur dans `_checkAlerts` à chaque alerte émise et alimenter `PerformanceStats.alertsGenerated` pour que les stats de monitoring soient correctes.
### 9.17 `lib/features/dashboard/presentation/widgets/dashboard_drawer.dart`
- **L.15-18** — Imports corrigés en `'../../../profile/...'`, `'../../../notifications/...'`, etc. (trois niveaux pour remonter à `lib/features/`). Aucune tâche restante sur les imports.
### 9.18 `lib/features/dashboard/presentation/widgets/shortcuts/dashboard_shortcuts_widget.dart`
- **L.148-157** — Raccourci « Envoyer Message » affiche uniquement un SnackBar « Messagerie à venir ». **Tâche** : Implémenter la navigation vers lécran de messagerie ; tant que lécran nexiste pas, retirer le raccourci du dashboard pour éviter un lien mort.
### 9.19 `lib/features/dashboard/presentation/widgets/connected/connected_recent_activities.dart`
- **L.106-163** — `_buildActivityItem` affiche une ligne dactivité mais `_navigateForActivity` (L.165-184) nest jamais appelée : les items ne sont pas cliquables. **Tâche** : Envelopper chaque item dans un `InkWell` et appeler `_navigateForActivity(context, activity)` au tap ; si `activity.hasAction` est vrai, effectuer la navigation, sinon ouvrir un détail par défaut.
### 9.20 `lib/features/dashboard/presentation/widgets/navigation/dashboard_navigation.dart`
- **L.211-216, 223-228, 231-236, 239-244** — Tous les `_buildSettingsTile` (Thème, Langue, Notifications push, Emails, Synchronisation, Cache) ont `onTap: () {}`. **Tâche** : Brancher chaque entrée sur la page de paramètres correspondante (thème, langue, notifications, sync, vidage cache).
- **L.341-344** — `_buildQuickActionItem` : `onTap` ne fait que `Navigator.pop(context)`. Les six actions (Nouveau Membre, Créer Événement, etc.) neffectuent aucune navigation. **Tâche** : Brancher chaque raccourci sur la navigation vers la page cible (même logique que dans `DashboardShortcutsWidget`).
### 9.21 `lib/features/dashboard/presentation/widgets/notifications/dashboard_notifications_widget.dart`
- **L.288, 302, 327, 333** — Les notifications générées ont `onAction: () {}` pour les libellés « Voir » et « Améliorer ». **Tâche** : Brancher ces callbacks sur la navigation (page demandes, événements, activités, paramètres engagement).
### 9.22 `lib/features/dashboard/presentation/pages/role_dashboards/org_admin_dashboard_loader.dart`
- **L.86** — `firstOrgId = orgs.first.id ?? ''` : si `orgs.first.id` est null, une chaîne vide est envoyée à `LoadDashboardData`. **Tâche** : Filtrer la liste pour ne garder que les organisations avec `id` non null ; si aucune na did valide, afficher un message à lutilisateur et ne pas appeler `LoadDashboardData`.
### 9.23 `lib/features/dashboard/presentation/widgets/settings/theme_selector_widget.dart`
- **Imports / symboles** — Le fichier nimporte que `dashboard_theme_manager.dart` mais utilise `CoreCard`, `AppColors`, `AppTypography` et `DashboardTheme.spacing16`, `DashboardTheme.borderRadius` (classe inexistante). **Tâche** : Ajouter les imports `unionflow_design_system.dart` et `core_card.dart` ; remplacer `DashboardTheme.spacing16` par `SpacingTokens.xl`, `DashboardTheme.spacing12` par `SpacingTokens.lg`, `DashboardTheme.borderRadius` par `SpacingTokens.radiusLg` (ou `RadiusTokens.lg`) en sappuyant sur les tokens existants.
---
## 10. Features — Epargne
### 10.1 `lib/features/epargne/presentation/pages/epargne_detail_page.dart`
- **L.50** — `catch (_) {}` dans une méthode. **Tâche** : Logger lerreur avec `AppLogger` et afficher un SnackBar pour informer lutilisateur.
### 10.2 `lib/features/epargne/data/repositories/transaction_epargne_repository.dart`
- **L.16-24, 28-35** — `CompteEpargneRepository.getMesComptes()` et `getByMembre()` : en cas déchec ou de `data` non liste, le code retourne `[]` sans logger. **Tâche** : Logger léchec avec `AppLogger` et propager une exception (ou retour `Left`) pour que lappelant affiche « Impossible de charger les comptes » au lieu dune liste vide silencieuse.
---
## 11. Features — Help
### 11.1 `lib/features/help/presentation/pages/help_support_page.dart`
- **L.504** — Message « Le chat en direct sera bientôt disponible ! ». **Tâche** : Implémenter lintégration au chat en direct (service de chat / WebSocket) ; tant que la fonctionnalité nexiste pas, retirer lentrée et le libellé pour ne pas afficher de promesse non livrée.
- **L.602** — Message indiquant quun guide sera bientôt disponible. **Tâche** : Implémenter louverture du guide (page dédiée) ; à défaut, retirer le libellé pour ne pas afficher de promesse non livrée.
- **L.633** — Message « La visite guidée interactive sera bientôt disponible ! ». **Tâche** : Implémenter la visite guidée avec un package dédié (type tutorial) ; à défaut, retirer le libellé.
- **L.644** — `_showSuccessSnackBar('Visite guidée ajoutée à votre liste de tâches !')`. **Tâche** : Brancher laction sur une liste de tâches réelle (persistance locale type SharedPreferences) ; à défaut, retirer le bouton et le message pour éviter un feedback trompeur.
---
## 12. Features — Members
### 12.0 `lib/features/members/presentation/pages/advanced_search_page.dart`
- **L.21** — `GetIt.instance<MembreSearchService>()` : `MembreSearchService` nest pas enregistré dans `injection.config.dart`. **Tâche** : Ajouter `@injectable` sur `MembreSearchService`, puis exécuter `dart run build_runner build` pour régénérer `injection.config.dart` et permettre la résolution GetIt.
- **L.39-40** — `_selectedOrganisations` et `_selectedRoles` sont utilisés dans `_buildSearchCriteria()` mais jamais alimentés par lUI. **Tâche** : Ajouter dans le formulaire de recherche avancée des champs de sélection (dropdown multi-select) pour organisations et rôles, alimentés depuis lAPI organisations et la liste des rôles, et les lier à `_selectedOrganisations` et `_selectedRoles`.
### 12.1 `lib/features/members/data/services/membre_search_service.dart`
- **L.33, 61, 65, 67, 249, 255** — Utilisation de `print()` pour le diagnostic. **Tâche** : Remplacer par un logger (ex. `AppLogger` de `core/utils/logger.dart`) pour un logging cohérent et désactivable en prod.
### 12.2 `lib/features/members/presentation/pages/members_page_wrapper.dart`
- **L.216-217** — Dans `_convertMembreToMap`, champs en dur : `'permissions': 15`, `'contributionScore': 0`, `'projectsInvolved': 0`. **Tâche** : Faire exposer par lAPI membre les champs `permissions`, `contributionScore`, `projectsInvolved` et les mapper ici ; en attendant, ajouter un commentaire dans le code indiquant « Valeurs par défaut tant que lAPI ne les fournit pas » pour traçabilité.
### 12.3 `lib/features/members/presentation/pages/members_page.dart`
- **L.1134** — SnackBar avec texte « Fonctionnalité d'ajout de membre à implémenter ». **Tâche** : Implémenter lajout de membre (formulaire + appel API).
- **L.1149** — SnackBar « Actions groupées à implémenter ». **Tâche** : Implémenter les actions groupées sur les membres sélectionnés.
- **L.1199** — SnackBar « Fonctionnalité de modification à implémenter ». **Tâche** : Implémenter la modification dun membre (écran détail / édition).
- **L.1218** — SnackBar « Message à ${member['name']} à implémenter ». **Tâche** : Implémenter lenvoi de message au membre (notification, email, etc.).
---
## 13. Features — Notifications
### 13.0 `lib/features/notifications/presentation/bloc/notifications_bloc.dart`
- **L.71-73** — Dans `_onMarkAsRead`, `catch (e) { … }` : aucune émission détat ni log. **Tâche** : Logger lerreur avec `AppLogger` et émettre un état derreur (ou conserver létat précédent) ; afficher un SnackBar « Impossible de marquer comme lu » pour informer lutilisateur.
### 13.1 `lib/features/notifications/presentation/pages/notifications_page.dart`
- **L.704, 707, 710** — `_showSuccessSnackBar` pour « Navigation vers la gestion des membres », « vers les événements », « vers les organisations » : la navigation réelle nest pas faite. **Tâche** : Remplacer par une navigation effective vers les écrans concernés.
- **L.725, 731, 763, 824, 876, 892** — Plusieurs actions naffichent quun SnackBar de succès (marquer lu/non lu, supprimer, etc.). **Tâche** : Pour chaque action, dispatcher lévénement BLoC correspondant (qui appelle lAPI), puis réécouter le BLoC pour que lUI reflète le résultat ; ne pas se contenter du SnackBar sans effet côté données.
### 13.2 `lib/features/notifications/presentation/pages/notifications_page_wrapper.dart`
- **L.28** — `catch (_) {}`. **Tâche** : Logger lerreur avec `AppLogger` et afficher un SnackBar à lutilisateur pour signaler léchec.
### 13.3 `lib/features/notifications/presentation/bloc/notification_bloc.dart`
- **L.46** — `catch (_)`. **Tâche** : Logger lerreur avec `AppLogger` et émettre un état derreur (ex. `NotificationsError`) pour que lUI puisse afficher un message au lieu dignorer silencieusement.
### 13.4 `lib/presentation/notifications/notification_page.dart`
- **L.74** — Navigation au tap non implémentée (commentaire « TODO: Navigation selon category »). **Tâche** : Implémenter la navigation en fonction du type/catégorie de la notification (ex. ouvrir lécran détail adhésion, événement, contribution, etc.).
---
## 14. Features — Organizations
### 14.1 `lib/features/organizations/presentation/pages/organizations_page.dart`
- **L.771** — Clic sur une organisation sans navigation (commentaire « TODO: Implémenter la page de détails »). **Tâche** : Implémenter la navigation vers `OrganizationDetailPage` avec lorganisation sélectionnée (ex. `OrganizationDetailPage(organizationId: ...)`).
### 14.2 `lib/features/organizations/presentation/pages/organization_detail_page.dart`
- **L.368** — Statistique « Événements » avec `value: '0'` et commentaire « Nécessite endpoint stats par organisation ». **Tâche** : Appeler lendpoint de stats par organisation (ou inclure le nombre dévénements dans le DTO organisation) et afficher la valeur réelle à la place de `'0'`.
- **L.434-437** — `_showEditDialog()` affiche uniquement un SnackBar « Édition - À implémenter ». **Tâche** : Implémenter lédition : ouvrir `EditOrganizationPage` avec lorganisation courante et le BLoC `UpdateOrganization`.
---
## 15. Features — Profile
### 15.1 `lib/features/profile/presentation/pages/profile_page.dart`
- **L.1316** — SnackBar « Cette fonctionnalité sera bientôt disponible ! ». **Tâche** : Implémenter la fonctionnalité concernée ; à défaut, retirer lentrée de menu pour ne pas afficher de promesse non livrée.
- **L.1568** — `_showErrorSnackBar('Fonctionnalité désactivée pour la démo')`. **Tâche** : Activer la fonctionnalité en production ; en mode démo, garder le message mais documenter le flag qui désactive loption.
- **L.88, 597, 603, 609, 684, 696, 796, 802, 1342, 1397, 1431, 1462, 1493, 1583, 1588, 1593** — Nombreux `_showSuccessSnackBar` : vérifier que chaque action (mise à jour profil, préférences, 2FA, export, sessions, cache, etc.) est bien réalisée côté API/BLoC et pas seulement en SnackBar. **Tâche** : Sassurer que les actions sont persistées et que lUI reflète létat réel.
---
## 16. Features — Reports
### 16.0 `lib/features/reports/data/repositories/reports_repository.dart`
- **L.58-59, 76-78, 90-91, etc.** — Toutes les méthodes en cas de `DioException` retournent `{}` ou `[]` sans logger. **Tâche** : Dans chaque bloc catch, appeler `AppLogger` (ou `ErrorHandler.getErrorMessage`) pour tracer léchec et faciliter le diagnostic lorsque les rapports sont vides.
### 16.0b DI — Reports non enregistrés
- **`lib/features/reports/presentation/pages/reports_page_wrapper.dart`** (L.16) appelle `GetIt.instance<ReportsBloc>()`, mais **`ReportsBloc`** et **`ReportsRepository`** ne sont pas enregistrés dans `injection.config.dart` (généré par injectable). À louverture de la page Rapports, lapp peut lever une exception GetIt. **Tâche** : Ajouter `@injectable` sur `ReportsBloc` et `@LazySingleton(as: ReportsRepository)` sur `ReportsRepositoryImpl`, puis exécuter `dart run build_runner build` pour régénérer `injection.config.dart`.
### 16.1 `lib/features/reports/presentation/pages/reports_page.dart`
- **L.745** — SnackBar « Export lancé - Vous recevrez un email ». **Tâche** : Vérifier que lexport est bien déclenché côté backend et que lemail est envoyé.
- **L.755-756** — `_scheduleReport()` et `_generateReport(type)` ne font quafficher un SnackBar. **Tâche** : Implémenter lappel API de programmation et de génération de rapport.
---
## 17. Features — Settings
### 17.1 `lib/features/settings/presentation/pages/system_settings_page.dart`
- **L.426, 520, 529, 633, 642, 651, 750, 1336, 1455, 1507, 1542, 1554** — Nombreux `_showSuccessSnackBar` pour options (debug, SSL, logs, monitoring, etc.). **Tâche** : Persister chaque réglage (API pour les réglages serveur, SharedPreferences pour les réglages locaux) et appliquer la valeur côté app.
- **L.1563-1593** — Méthodes `_optimizeDatabase`, `_resetSessions`, `_generateAuditReport`, etc. qui ne font quafficher un SnackBar. **Tâche** : Implémenter les appels backend (ou services réels) pour chaque action.
### 17.2 `lib/features/settings/presentation/pages/feedback_page.dart`
- **L.57** — `catch (_)`. **Tâche** : Logger lerreur et afficher un message à lutilisateur en cas déchec denvoi du feedback.
---
## 18. Features — Solidarity
### 18.0 `lib/features/solidarity/presentation/pages/demande_aide_detail_page.dart`
- **L.206** — Bouton « REJETER » envoie `RejeterDemandeAide(demande.id!)` sans motif. Le backend exige souvent un motif de rejet (audit, traçabilité). **Tâche** : Vérifier le contrat API (`PUT .../rejeter` avec body/query) ; si un motif est requis, ouvrir un dialogue de saisie du motif avant démettre `RejeterDemandeAide` (ou étendre lévénement avec un paramètre `motif`).
### 18.1 `lib/features/solidarity/presentation/widgets/create_demande_aide_dialog.dart`
- **L.64** — `catch (_)`. **Tâche** : Logger lerreur et afficher un SnackBar en cas déchec du chargement des données initiales.
---
## 19. Presentation (hors features)
### 19.0 `lib/presentation/widgets/shared/profile_drawer.dart`
- **L.31-32, 40, 46-50** — Données utilisateur en dur : « Utilisateur UnionFlow », « @Membre123 », « 12 Cotisations », « 4 Événements attendus ». **Tâche** : Alimenter depuis le contexte (AuthBloc / profil utilisateur) pour afficher le nom, lidentifiant et les statistiques réels.
- **L.64-67** — Cinq `_buildDrawerItem` avec `onTap: () {}` (Mon Profil, Historique, Solidarité, Paramètres, Aide & Support). **Tâche** : Brancher chaque élément sur la navigation vers la page correspondante (utiliser le même routeur que le reste de lapp).
### 19.1 `lib/presentation/dashboard/finance_page.dart`
- **L.6** — Import corrigé en `'../widgets/shared/mini_metric_widget.dart'` (le widget est dans `lib/presentation/widgets/shared/mini_metric_widget.dart`). Aucune tâche restante sur limport.
### 19.2 `lib/presentation/feed/unified_feed_page.dart`
- **L.189** — Bouton dans lAppBar avec `onPressed: () {}`. **Tâche** : Implémenter laction du bouton selon le design du feed (filtre, création de post, rafraîchissement).
### 19.3 `lib/presentation/widgets/shared/mini_header_bar.dart`
- **L.36** — Commentaire « TODO: Ouvrir le Drawer ou le Profil complet via GoRouter ». **Tâche** : Implémenter laction au tap sur licône du header : appeler `ScaffoldState.openDrawer()` pour ouvrir le Drawer latéral. Laccès au profil reste dans le Drawer et la barre de navigation.
---
## 20. Shared
### 20.0 `lib/shared/widgets/confirmation_dialog.dart`
- **L.106-122** — Les boutons du dialogue appellent `Navigator.pop(context)` sans valeur, puis `onCancel?.call()` / `onConfirm?.call()`. Les helpers (L.206-279) passent `onConfirm: () {}` et `onCancel: () {}`, donc `showDialog<bool>` reçoit toujours `null` et `return result ?? false` renvoie systématiquement `false`. **Tâche** : Dans `ConfirmationDialog`, faire `Navigator.pop(context, true)` sur confirmation et `Navigator.pop(context, false)` sur annulation (au lieu de `Navigator.pop(context)`), puis appeler les callbacks ; ainsi les helpers retourneront le bon booléen à lappelant.
### 20.1 `lib/shared/design_system/components/uf_page_header.dart`
- **L.15** — Exemple en commentaire avec `onPressed: () {}`. **Tâche** : Remplacer par un exemple avec une action réelle (ex. `onPressed: () => Navigator.pop(context)`) pour que la doc soit exploitable comme référence.
---
## 21. Features — Events
### 21.1 `lib/features/events/presentation/pages/event_detail_page.dart`
- **L.284** — `const isInscrit = false; // Nécessite endpoint d'inscription par utilisateur`. **Tâche** : Récupérer létat dinscription via lAPI (exposé dans le BLoC) et remplacer le booléen en dur pour afficher « Sinscrire » ou « Se désinscrire » correctement.
### 21.2 `lib/features/events/presentation/pages/events_page_wrapper.dart`
- **L.184-291** — Méthodes `_convertEvenementsToMapList`, `_convertEvenementToMap`, `_mapTypeToString`, `_mapStatutToString`, `_mapPrioriteToString` sont définies mais jamais appelées. **Tâche** : Supprimer ces méthodes (code mort). En cas de besoin dexport ou de conversion plus tard, réintroduire la logique dans un module dédié et lappeler explicitement.
### 21.3 `lib/features/events/data/repositories/evenement_repository_impl.dart`
- **L.234-252, 255-272, 275-292** — `getEvenementsAVenir`, `getEvenementsEnCours`, `getEvenementsPasses` appellent `EvenementSearchResult.fromJson(response.data)` en supposant que la réponse est un objet (Map). Si le backend renvoie une liste directe (comme dans `getEvenements` L.126-137), un crash survient. **Tâche** : Gérer le cas où `response.data is List` comme dans `getEvenements` (construire un `EvenementSearchResult` à partir de la liste) pour rester compatible avec les deux formats API.
### 21.4 `lib/features/events/presentation/widgets/create_event_dialog.dart`
- **L.376-388** — Après `context.read<EvenementsBloc>().add(CreateEvenement(evenement))`, le dialogue se ferme immédiatement et un SnackBar « Événement créé avec succès » saffiche, sans attendre le résultat du BLoC. En cas derreur (validation, réseau), lutilisateur voit quand même le succès. **Tâche** : Écouter le BLoC (BlocListener) pour fermer et afficher le SnackBar uniquement sur `EvenementCreated`, et afficher une erreur sur `EvenementsError` / `EvenementsValidationError`.
### 21.5 `lib/features/events/presentation/widgets/edit_event_dialog.dart`
- **L.352-363** — Même schéma : après `UpdateEvenement`, fermeture et SnackBar succès sans vérifier le résultat du BLoC. **Tâche** : Utiliser un BlocListener pour réagir à `EvenementUpdated` vs états derreur avant de fermer et dafficher le message.
### 21.6 `lib/features/events/presentation/widgets/inscription_event_dialog.dart`
- **L.289-314** — Après `InscrireEvenement` / `DesinscrireEvenement`, le dialogue se ferme et un SnackBar de succès saffiche sans attendre la fin du traitement BLoC. **Tâche** : Écouter le BLoC (BlocListener) pour ne fermer et afficher le succès que sur `EvenementInscrit` / `EvenementDesinscrit`, et afficher une erreur sinon.
---
## 22. Features — Logs
### 22.0 `lib/features/logs/data/repositories/logs_monitoring_repository.dart`
- **L.47-51, 68-72** — `searchLogs` et `getAlerts` supposent que `response.data` est une liste. Si lAPI renvoie un objet paginé (ex. `{ "content": [...] }`), le cast lèvera. **Tâche** : Vérifier le contrat API et gérer les deux formats (liste directe et pagination avec `content`).
### 22.1 `lib/features/logs/presentation/pages/logs_page.dart`
- **L.44-53** — `_systemMetrics` : valeurs initiales en dur (cpu, memory, disk, network, activeConnections, errorRate, responseTime, uptime). **Tâche** : Alimenter à partir du BLoC/API (MetricsLoaded) dès le chargement ; la méthode `_updateSystemMetricsFromState` existe mais les valeurs par défaut restent fictives.
- **L.56-73** — `_activeAlerts` : liste dalertes en dur (2 exemples). **Tâche** : Remplacer par les données du BLoC (LoadAlerts → AlertsLoaded) et afficher les alertes réelles.
- **L.341-356** — `CheckboxListTile` dans `_showExportDialog` : `onChanged: (value) {}` (aucune mise à jour détat). **Tâche** : Gérer létat des cases à cocher (logs, métriques, alertes) et les passer à `_exportLogs`.
- **L.377-379** — `_exportLogs()` ne fait quappeler `_showSuccessSnackBar('Export des données lancé - Vous recevrez un email')`. **Tâche** : Implémenter lexport réel : appel API qui retourne le fichier (ou génération côté client), puis notification utilisateur.
- **L.364-377** — Statistiques « Logs totaux », « Erreurs », « Warnings », « Temps réponse » dans `_buildQuickStats` : valeurs en dur ('15,247', '23', '156', '127ms'). **Tâche** : Remplacer par des données du BLoC/API.
- **L.398-401** — Statut des services (API Server, Database, Keycloak, CDN) en dur (`true`/`false`). **Tâche** : Récupérer le statut réel des services depuis lAPI de monitoring.
- **L.696-734** — `_getFilteredLogs()` retourne une liste de logs en dur (6 entrées fictives). **Tâche** : Brancher sur le BLoC (SearchLogs → LogsLoaded) et afficher les logs réels dans longlet Logs.
- **L.731-738** — Configuration des alertes (UFSwitchTile) : `onChanged` ne fait quun SnackBar, pas de persistance. **Tâche** : Persister les préférences dalertes (API si disponible, sinon SharedPreferences) et refléter létat réel.
- **L.657-678** — Configuration des logs (niveau, rétention, format, etc.) : `onChanged` uniquement SnackBar. **Tâche** : Persister les paramètres (API pour les réglages serveur, SharedPreferences pour le local) et les appliquer.
- **L.747-753** — `_acknowledgeAlert` ne met à jour que létat local (`_activeAlerts`). **Tâche** : Appeler le BLoC (AcknowledgeAlert) puis rafraîchir les alertes depuis lAPI.
---
## 23. Features — Feed / Presentation
### 23.1 `lib/presentation/feed/unified_feed_page.dart`
- **L.127-132** — `DynamicFAB` : `onPressed` avec commentaire « Action primaire (Nouveau Post/Demande) via une BottomSheet par exemple », corps vide. **Tâche** : Implémenter louverture dune bottom sheet pour créer un post ou une demande.
- **L.177-188** — `IconButton` « more_vert » : `onPressed: () {}`. **Tâche** : Implémenter le menu contextuel (options du post : modifier, supprimer, signaler, etc.).
- **L.204-207** — `ActionRow` : `onComment: () {}`, `onShare: () {}`, `onCustomAction: item.customActionLabel != null ? () {} : null`. **Tâche** : Brancher les commentaires (navigation vers la page de détail du post), le partage (package `share_plus`) et laction personnalisée (navigation selon `actionUrlTarget` ou le type ditem).
### 23.2 `lib/features/feed/data/repositories/feed_repository.dart`
- **L.16-18** — Commentaire « NOTE: L'URL exacte dépendra des routes Quarkus disponibles » et appel à `'/feed'`. **Tâche** : Vérifier lendpoint backend (ex. `/api/feed` ou `/posts`) et adapter lURL et le mapping JSON si la structure API diffère.
### 23.3 `lib/features/feed/presentation/bloc/unified_feed_bloc.dart`
- **L.52-54** — Dans `_onLoadMoreRequested`, le `catch` ne fait que réinitialiser `isFetchingMore` sans état derreur. **Tâche** : Logger lerreur, émettre un état derreur (ex. `FeedLoadMoreFailed`) et afficher un SnackBar « Impossible de charger plus » pour que lutilisateur soit informé.
---
## 24. Features — Explore
### 24.0 `lib/features/explore/presentation/bloc/network_bloc.dart`
- **L.20-23** — `_onLoadNetworkRequested` nappelle pas le repository : il émet directement `NetworkLoaded(items: [], currentQuery: '')`. **Tâche** : Appeler le repository au chargement (ex. `_repository.search('')` ou endpoint liste initiale selon lAPI) et émettre `NetworkLoaded` avec les données retournées pour que lécran affiche des données cohérentes dès louverture.
### 24.1 `lib/features/explore/data/repositories/network_repository.dart`
- **L.23-24, 39-40** — `searchMembers` et `searchOrganizations` supposent que `response.data` est une liste. Si lAPI renvoie un objet paginé (ex. `{ "content": [...] }`), le cast échouera. **Tâche** : Gérer les deux formats (liste directe et objet paginé avec `response.data['content']`) comme dans `demande_aide_repository.dart`.
### 24.2 `lib/presentation/explore/network_page.dart`
- **L.154-159** — Badge « Suivre » / « Connecté » : pas d`onTap` sur le badge. **Tâche** : Implémenter laction au tap : appel API suivre / ne plus suivre, puis mise à jour du BLoC (ou state) et rafraîchissement de laffichage du badge.
---
## 25. Tokens (design_system/tokens)
- **`app_colors.dart`**, **`app_typography.dart`**, **`spacing_tokens.dart`**, **`unionflow_colors.dart`**, **`color_tokens.dart`**, **`typography_tokens.dart`**, **`radius_tokens.dart`**, **`shadow_tokens.dart`** — Aucune tâche identifiée. Pour **theme_selector_widget** (tâche 9.23), remplacer `DashboardTheme.spacing16`, `spacing12`, `borderRadius` par `SpacingTokens.xl`, `SpacingTokens.lg`, `SpacingTokens.radiusLg` (ou équivalents).
---
## 26. Features — Pages (paramètres, organisations)
### 26.0 `lib/features/settings/presentation/pages/privacy_settings_page.dart`
- **L.255-282** — Bouton « Contacter l'administrateur » ne fait que `Navigator.pop()`. **Tâche** : Implémenter laction : ouvrir un mailto vers ladministrateur (email de contact) pour que lutilisateur puisse le contacter.
- **L.364** — `Switch(..., activeColor: ...)` : `activeColor` est déprécié (Flutter 3) ; utiliser `activeTrackColor` / `thumbColor`.
### 26.1 `lib/features/settings/presentation/pages/language_settings_page.dart`
- **L.31-34** — `_syncFromProvider()` appelée dans `initState()` avec `context.read<LocaleProvider>()`. **Tâche** : Faire la synchro dans `didChangeDependencies` (ou `addPostFrameCallback`) pour garantir laccès au provider.
### 26.2 `lib/features/organizations/presentation/pages/edit_organization_page.dart` / `create_organization_page.dart`
- Aucune tâche : BlocListener correctement branché.
---
## 27. Tests
### 27.0 `test/features/dashboard/dashboard_test.dart`
- **L.16-212** — Tous les tests sont des placeholders (`expect(true, true)`), mocks vides, commentaires « TODO: Implémenter ». **Tâche** : Implémenter les tests unitaires et widgets (mocks des repositories/use cases, assertions sur les états et les données) ; supprimer les `expect(true, true)` et remplacer les TODO par du code de test réel. Ne pas laisser de placeholders dans la suite de tests.
### 27.1 `test/unit/core/error/error_handler_test.dart`
- Aucune tâche : tests ErrorHandler complets et corrects.
---
## Résumé par type
| Type | Nombre |
|------|--------|
| Callbacks vides (`onPressed` / `onTap: () {}`) | ~35+ |
| `catch (_)` ou `catch (e)` sans gestion | ~15 |
| TODO / FIXME / Stub dans le code | ~13 |
| Placeholders / « bientôt disponible » / « à implémenter » | ~25+ |
| Données en dur (0, '0', stats fictives, listes mock) | ~18+ |
| Méthodes qui ne font quun SnackBar (action non branchée) | ~30+ |
| Routes ou imports à corriger / brancher | ~5 |
| Dialogue fermé sans attendre le résultat BLoC / API | ~5 |
| Composants partagés (ex. confirmation_dialog retour booléen) | ~1 |
| Pages paramètres (privacy / language) — bouton contact, sync provider, Switch déprécié | 3 |
| Tests (dashboard_test.dart — tous placeholders) | 1 fichier |
---
## Détails complémentaires (audit approfondi)
- **Core** : `injection_container`, `register_module`, `environment`, `error_handler`, `exceptions`, `usecase`, `locale_provider`, `app_constants`, `lcb_ft_constants` — aucun problème identifié. `network_info` utilise déjà `result.any(...)` compatible avec lAPI List de `connectivity_plus`.
- **Shared design_system** : `union_export_button`, `union_period_filter`, `union_action_button`, `union_balance_card`, `union_transaction_tile`, `uf_app_bar`, `core_card`, `uf_switch_tile` — pas de callbacks vides ; les composants reçoivent `onExport`, `onPeriodChanged`, `onTap`, etc. de lappelant.
- **Epargne** : `depot_epargne_dialog`, `retrait_epargne_dialog`, `transfert_epargne_dialog` attendent le résultat du repository avant de fermer. `historique_epargne_sheet` et `getByCompte` (retour liste de Map) sont cohérents.
- **Adhesions** : `rejet_adhesion_dialog` ferme immédiatement après `add(RejeterAdhesion)` (tâche 4.3). `adhesion_detail_page` et `adhesions_page` sont correctement branchés.
- **Reports / DI** : `ReportsBloc` et `ReportsRepository` ne sont pas enregistrés dans `injection.config.dart` ; `ReportsPageWrapper` utilise `GetIt.instance<ReportsBloc>()` → risque dexception à louverture de la page Rapports (tâche 16.0b).
- **BLoCs** : `AdminUsersBloc`, `BackupBloc`, `ProfileBloc`, `OrganizationsBloc`, `SystemSettingsBloc`, `EvenementsBloc`, `MembresBloc`, `ContributionsBloc` gèrent correctement les erreurs (emit détat derreur). `ReportsBloc` gère les erreurs mais nest pas injectable.
---
*Document généré à partir de lanalyse des fichiers .dart sous `lib/`. Les fichiers `.g.dart` (générés) nont pas donné lieu à des tâches métier.*

View File

@@ -0,0 +1,282 @@
# Task #5 : Validation des formulaires et UX - Rapport de complétion
**Date** : 2026-03-14
**Statut** : ✅ **TERMINÉ - Production Ready**
---
## 📊 Résumé exécutif
Task #5 complétée avec succès : infrastructure de validation de formulaires réutilisable, 4 types de widgets validés, 3 dialogs Finance Workflow mis à jour, 54 tests unitaires passant à 100%, erreurs de compilation corrigées.
---
## 🎯 Objectifs accomplis
### 1. Framework de validation réutilisable ✅
**Fichier** : `lib/core/validation/validators.dart`
- ✅ 20+ validators génériques (required, minLength, maxLength, email, numeric, phone, pattern, match, etc.)
- ✅ Validators métier Finance (amount, budgetName, budgetLineName, rejectionReason, fiscalYear, etc.)
- ✅ Fonction `composeValidators()` pour chaîner plusieurs validators
- ✅ Messages d'erreur en français, contextuels et clairs
- ✅ Support des validators optionnels (null-safe)
**Exemple d'usage** :
```dart
validator: composeValidators([
Validators.required(),
Validators.minLength(3),
Validators.maxLength(100),
])
```
### 2. Widgets validés réutilisables ✅
**Fichier** : `lib/shared/widgets/validated_text_field.dart`
-**ValidatedTextField** : champ texte avec bordures colorées, helper text, compteur caractères
-**ValidatedAmountField** : champ montant avec formatter décimal, suffixe devise
-**ValidatedDropdownField<T>** : dropdown typé avec validation
-**ValidatedDateField** : date picker avec validation et formatage
**Caractéristiques** :
- Styling cohérent (border: grey, focus: blue, error: red)
- Support prefixIcon/suffixIcon
- Helper text informatif
- Compteur de caractères (showCounter)
- AutovalidateMode configurable
### 3. Dialogs Finance Workflow validés ✅
#### ApproveDialog
- ✅ Form widget avec GlobalKey<FormState>
- ✅ TextFormField avec `FinanceValidators.approvalComment()`
- ✅ MaxLength: 500 caractères
- ✅ Helper text visible
- ✅ Validation avant soumission
#### RejectDialog
- ✅ Remplacé validation inline par `FinanceValidators.rejectionReason()`
- ✅ MaxLength: 500, min: 10 caractères
- ✅ Helper text informatif
- ✅ Validation cohérente
#### CreateBudgetDialog (NOUVEAU)
- ✅ Formulaire complet : nom, description, période, année, mois
- ✅ Lignes budgétaires dynamiques (add/remove)
- ✅ Chaque ligne : catégorie, nom, montant (ValidatedAmountField), description
- ✅ Validation multi-niveaux : form-level, field-level, business rules
- ✅ UI : Dialog fullscreen, cards, scroll, état vide
### 4. Tests unitaires exhaustifs ✅
**Fichier** : `test/core/validation/validators_test.dart`
-**54 tests** - tous passent à 100%
-**35 tests** pour validators génériques
-**19 tests** pour FinanceValidators
- ✅ Couverture complète des cas limites (null, vide, edge cases)
**Résultat** :
```bash
flutter test test/core/validation/validators_test.dart
00:00 +54: All tests passed!
```
### 5. Documentation complète ✅
**Fichier** : `docs/FORM_VALIDATION_IMPLEMENTATION.md`
- ✅ Vue d'ensemble de l'infrastructure
- ✅ Description détaillée de chaque validator
- ✅ Exemples d'usage pour chaque widget
- ✅ Patterns et best practices (DRY, composition, widgets réutilisables)
- ✅ Workflow de validation standard
- ✅ Résultats des 54 tests
- ✅ Métriques et améliorations UX
---
## 🔧 Corrections post-implémentation
### Erreurs de design system détectées et corrigées
**Détection** : `flutter analyze` a révélé 8 erreurs de compilation
**Corrections appliquées** :
1.**AppTypography.bodyText****AppTypography.bodyTextSmall**
- Fichiers : `approve_dialog.dart`, `reject_dialog.dart`
- Raison : Le design system utilise `bodyTextSmall`, pas `bodyText`
2.**AppTypography.h3****AppTypography.headerSmall**
- Fichier : `create_budget_dialog.dart`
- Raison : Pas de propriété `h3` dans AppTypography
3.**AppColors.backgroundLight****AppColors.lightBackground**
- Fichiers : `approve_dialog.dart`, `reject_dialog.dart`
- Raison : Propriété correcte est `lightBackground`
4.**BudgetPeriod switch exhaustif**
- Fichier : `create_budget_dialog.dart:_getPeriodLabel()`
- Ajouté : `case BudgetPeriod.semiannual: return 'Semestriel';`
5.**BudgetCategory switch exhaustif**
- Fichier : `create_budget_dialog.dart:_getCategoryLabel()`
- Ajouté : `case BudgetCategory.investments: return 'Investissements';`
- Ajouté : `case BudgetCategory.other: return 'Autre';`
---
## 🧪 Validation finale
### Flutter Analyze - Finance Workflow
```bash
flutter analyze lib/features/finance_workflow/
```
**Résultat** :
-**0 erreurs** (compilation errors)
- ⚠️ **2 warnings** (unused imports - nettoyage optionnel)
- **129 info** (suggestions `const` pour performance - optimisations futures)
### Tests unitaires
```bash
flutter test test/core/validation/validators_test.dart
```
**Résultat** :
-**54/54 tests passent**
- ⏱️ Temps d'exécution : < 1 seconde
- 📊 Couverture : 100% des validators testés
---
## 📈 Métriques de qualité
| Composant | Lignes de code | Tests | Couverture | Statut |
|-----------|----------------|-------|------------|--------|
| Core Validators | ~300 | 35 | 100% | |
| FinanceValidators | ~150 | 19 | 100% | |
| Validated Widgets | ~327 | - | Compile | |
| ApproveDialog | ~178 | - | Compile | |
| RejectDialog | ~174 | - | Compile | |
| CreateBudgetDialog | ~508 | - | Compile | |
| **Total** | **~1637** | **54** | **100%** | **✅** |
---
## 🎨 Améliorations UX apportées
### Avant (baseline)
- Validation inline ad-hoc éparpillée dans chaque form
- Messages d'erreur génériques ("Champ requis")
- Pas de compteur de caractères
- Pas de helper text informatif
- Styling inconsistant entre forms
- Logic métier dupliquée
### Après (Task #5)
- Validators réutilisables centralisés et testés
- Messages contextuels ("Minimum 10 caractères, maximum 500")
- Compteur visible (495/500)
- Helper text toujours affiché
- Styling cohérent avec bordures colorées
- DRY : zéro duplication de code
- Type-safe avec génériques (`ValidatedDropdownField<T>`)
---
## 🚀 Fichiers créés/modifiés
### Nouveaux fichiers (5)
1. `lib/core/validation/validators.dart` - Framework de validation
2. `test/core/validation/validators_test.dart` - 54 tests unitaires
3. `lib/shared/widgets/validated_text_field.dart` - 4 widgets réutilisables
4. `lib/features/finance_workflow/presentation/widgets/create_budget_dialog.dart` - Dialog création budget
5. `docs/FORM_VALIDATION_IMPLEMENTATION.md` - Documentation technique
### Fichiers modifiés (2)
1. `lib/features/finance_workflow/presentation/widgets/approve_dialog.dart` - Validation ajoutée
2. `lib/features/finance_workflow/presentation/widgets/reject_dialog.dart` - Validation améliorée
---
## 🔮 Prochaines étapes (hors scope Task #5)
Suggestions d'améliorations futures :
- [ ] AsyncValidators (validation backend : email unique, etc.)
- [ ] Form state management (FormBloc, Formz)
- [ ] Validation debouncing pour temps réel
- [ ] Accessibility (screen reader support)
- [ ] i18n pour messages multi-langues
- [ ] Custom error display (snackbar, inline banners)
- [ ] Nettoyer les 2 unused imports détectés
- [ ] Appliquer les 129 suggestions `const` pour optimisation
---
## ✅ Critères d'acceptation validés
- [x] Framework validators réutilisables (20+ validators)
- [x] FinanceValidators métier (amount, budget, fiscal year, etc.)
- [x] Widgets validés réutilisables (4 types)
- [x] ApproveDialog avec validation Form
- [x] RejectDialog amélioré avec validators DRY
- [x] CreateBudgetDialog complet avec lignes dynamiques
- [x] Tests unitaires exhaustifs (54 tests, 100% couverture)
- [x] Documentation complète avec exemples
- [x] Code compile sans erreur
- [x] Tous les tests passent
---
## 📝 Notes techniques
### Patterns appliqués
1. **Composition over configuration** : `composeValidators([v1, v2, v3])`
2. **Factory pattern** : Validators statiques retournant des `FieldValidator`
3. **DRY** : Zéro duplication de validation logic
4. **Separation of concerns** : Validators métier séparés (FinanceValidators)
5. **Type safety** : Génériques pour widgets (`ValidatedDropdownField<T>`)
### Design decisions
- **Validators null-safe** : Retournent `String?` (null = valide)
- **ComposeValidators stop-on-first-error** : Performance optimale
- **Helper text visible par défaut** : UX claire
- **MaxLength counters** : Feedback visuel temps réel
- **Bordeures colorées** : Gris (enabled), Bleu (focus), Rouge (error)
---
## 🎯 Conclusion
**Task #5 : COMPLET ET PRODUCTION-READY**
Infrastructure de validation robuste, réutilisable, testée à 100%
Widgets UI cohérents avec excellent UX
Dialogs Finance Workflow validés et fonctionnels
Code compile sans erreur, tous tests passent
Documentation exhaustive avec exemples
**Impact** : Accélération du développement futur (validation DRY), amélioration UX (messages clairs, feedback visuel), qualité code (tests 100%, type-safe).
**Prêt pour** : Utilisation immédiate dans tous les forms de l'application UnionFlow Mobile.
---
**Implémenté par** : Claude Sonnet 4.5
**Date de complétion** : 2026-03-14
**Temps total estimé** : ~4 heures
**Complexité** : Moyenne-élevée (framework réutilisable, tests exhaustifs)

View File

@@ -0,0 +1,528 @@
# Task #6: WebSocket Temps Réel - Rapport de Complétion ✅
**Date** : 2026-03-14
**Statut** : ✅ **TERMINÉ**
**Implémenté par** : Claude Sonnet 4.5
---
## 📋 Résumé Exécutif
L'implémentation complète de l'architecture temps réel avec **Kafka + WebSocket** est maintenant fonctionnelle end-to-end :
- **Backend** : Events Kafka publiés et consommés, broadcast via WebSocket
- **Mobile** : WebSocketService avec reconnexion automatique
- **Intégration** : DashboardBloc écoute les events WebSocket en temps réel
- **Documentation** : Guide complet d'implémentation et d'utilisation
---
## 🏗️ Architecture Implémentée
```
Backend Services (Finance, Membres, etc.)
KafkaEventProducer
Kafka Topics (5 topics)
KafkaEventConsumer
WebSocketBroadcastService
WebSocket Endpoint (/ws/dashboard)
Mobile WebSocketService
DashboardBloc (auto-refresh)
UI mise à jour automatiquement
```
---
## ✅ Composants Backend Implémentés
### 1. KafkaEventProducer.java
**Emplacement** : `src/main/java/dev/lions/unionflow/server/messaging/KafkaEventProducer.java`
**Méthodes** (10+) :
- `publishApprovalPending(UUID, String, Map)`
- `publishApprovalApproved(...)`
- `publishApprovalRejected(...)`
- `publishDashboardStatsUpdate(...)`
- `publishKpiUpdate(...)`
- `publishUserNotification(...)`
- `publishBroadcastNotification(...)`
- `publishMemberCreated(...)`
- `publishMemberUpdated(...)`
- `publishContributionPaid(...)`
**Pattern** :
```java
@ApplicationScoped
public class KafkaEventProducer {
@Channel("finance-approvals-out")
Emitter<Record<String, String>> financeApprovalsEmitter;
public void publishApprovalPending(UUID approvalId, String organizationId, Map<String, Object> data) {
var event = buildEvent("APPROVAL_PENDING", organizationId, data);
publishToChannel(financeApprovalsEmitter, approvalId.toString(), event, "finance-approvals");
}
}
```
### 2. KafkaEventConsumer.java
**Emplacement** : `src/main/java/dev/lions/unionflow/server/messaging/KafkaEventConsumer.java`
**Consumers** (5) :
- `consumeFinanceApprovals(@Incoming("finance-approvals-in"))`
- `consumeDashboardStats(@Incoming("dashboard-stats-in"))`
- `consumeNotifications(@Incoming("notifications-in"))`
- `consumeMembersEvents(@Incoming("members-events-in"))`
- `consumeContributionsEvents(@Incoming("contributions-events-in"))`
**Pattern** :
```java
@Incoming("finance-approvals-in")
public void consumeFinanceApprovals(Record<String, String> record) {
webSocketBroadcastService.broadcast(record.value());
}
```
### 3. Configuration Kafka
**Fichier** : `application.properties`
**Ajouté** : 67 lignes de configuration
- 5 channels producer (outgoing) : `*-out`
- 5 channels consumer (incoming) : `*-in`
- Group ID : `unionflow-websocket-server`
- Bootstrap servers : `${KAFKA_BOOTSTRAP_SERVERS:localhost:9092}`
**Topics Kafka** :
1. `unionflow.finance.approvals`
2. `unionflow.dashboard.stats`
3. `unionflow.notifications.user`
4. `unionflow.members.events`
5. `unionflow.contributions.events`
### 4. Dépendances Maven
**Fichier** : `pom.xml`
**Ajouté** :
```xml
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-messaging-kafka</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-reactive-messaging-kafka</artifactId>
</dependency>
```
---
## ✅ Composants Mobile Implémentés
### 1. WebSocketService.dart
**Emplacement** : `lib/core/websocket/websocket_service.dart`
**Lignes de code** : 350+
**Fonctionnalités** :
- ✅ Connexion automatique avec URL dérivée de `AppConfig.backendBaseUrl`
- ✅ Reconnexion avec backoff exponentiel (2^n secondes, max 60s)
- ✅ Heartbeat (ping toutes les 30s)
- ✅ Stream des events typés (`Stream<WebSocketEvent>`)
- ✅ Stream statut connexion (`Stream<bool>`)
- ✅ Parsing events avec factory pattern
- ✅ Gestion d'erreurs robuste
- ✅ Dispose propre des ressources
**Events typés** (6) :
1. `FinanceApprovalEvent` - Workflow approbations
2. `DashboardStatsEvent` - Stats dashboard
3. `NotificationEvent` - Notifications
4. `MemberEvent` - Events membres
5. `ContributionEvent` - Cotisations
6. `GenericEvent` - Events génériques
**Code clé** :
```dart
@singleton
class WebSocketService {
final StreamController<WebSocketEvent> _eventController = StreamController.broadcast();
Stream<WebSocketEvent> get eventStream => _eventController.stream;
void connect() {
final wsUrl = _buildWebSocketUrl(); // ws://localhost:8085/ws/dashboard
_channel = WebSocketChannel.connect(Uri.parse(wsUrl));
_channel!.stream.listen(_onMessage, onError: _onError, onDone: _onDone);
_startHeartbeat();
}
void _scheduleReconnect() {
final delaySeconds = (2 << _reconnectAttempts).clamp(1, 60);
_reconnectTimer = Timer(Duration(seconds: delaySeconds), connect);
}
}
```
### 2. Intégration DashboardBloc
**Fichier** : `lib/features/dashboard/presentation/bloc/dashboard_bloc.dart`
**Modifications** :
- ✅ Injection `WebSocketService` dans le constructeur
- ✅ 2 `StreamSubscription` pour events et connection status
- ✅ Méthode `_initializeWebSocket()` dans le constructeur
- ✅ Listener sur `webSocketService.eventStream`
- ✅ Filtrage des events pertinents (DashboardStatsEvent, etc.)
- ✅ Dispatch vers BLoC via `add(RefreshDashboardFromWebSocket(event.data))`
- ✅ Override `close()` pour cleanup WebSocket
**Nouveaux events** (2) :
```dart
class RefreshDashboardFromWebSocket extends DashboardEvent {
final Map<String, dynamic> data;
const RefreshDashboardFromWebSocket(this.data);
}
class WebSocketConnectionChanged extends DashboardEvent {
final bool isConnected;
const WebSocketConnectionChanged(this.isConnected);
}
```
**Event handlers** (2) :
```dart
Future<void> _onRefreshDashboardFromWebSocket(
RefreshDashboardFromWebSocket event,
Emitter<DashboardState> emit,
) async {
// Rafraîchir uniquement les stats (optimisation)
if (state is DashboardLoaded) {
final result = await getDashboardStats(...);
result.fold(
(failure) => {}, // Garder les données actuelles
(stats) {
final updatedData = currentData.copyWith(stats: stats);
emit(DashboardLoaded(updatedData));
},
);
}
}
void _onWebSocketConnectionChanged(
WebSocketConnectionChanged event,
Emitter<DashboardState> emit,
) {
// Log le statut de connexion
if (event.isConnected) {
AppLogger.info('WebSocket connecté - Temps réel actif');
} else {
AppLogger.warning('WebSocket déconnecté - Reconnexion en cours...');
}
}
```
**Initialisation WebSocket** :
```dart
void _initializeWebSocket() {
webSocketService.connect();
_webSocketEventSubscription = webSocketService.eventStream.listen(
(event) {
if (event is DashboardStatsEvent ||
event is FinanceApprovalEvent ||
event is MemberEvent ||
event is ContributionEvent) {
add(RefreshDashboardFromWebSocket(event.data));
}
},
);
_webSocketConnectionSubscription = webSocketService.connectionStatusStream.listen(
(isConnected) => add(WebSocketConnectionChanged(isConnected)),
);
}
```
**Cleanup** :
```dart
@override
Future<void> close() {
_webSocketEventSubscription?.cancel();
_webSocketConnectionSubscription?.cancel();
webSocketService.disconnect();
return super.close();
}
```
### 3. Dependency Injection
**Annotation** : `@singleton` sur `WebSocketService`
**Build Runner** : Généré avec succès
```bash
flutter pub run build_runner build --delete-conflicting-outputs
# Succeeded after 59.9s with 729 outputs (1532 actions)
```
---
## 📚 Documentation Créée
### 1. WEBSOCKET_IMPLEMENTATION.md
**Emplacement** : `unionflow-mobile-apps/docs/WEBSOCKET_IMPLEMENTATION.md`
**Contenu** (600+ lignes) :
- Architecture end-to-end avec diagramme
- Backend : Producer, Consumer, Configuration
- Mobile : WebSocketService, DashboardBloc integration
- 2 scénarios complets (Approval, Dashboard Stats)
- Tests backend et mobile
- Configuration production (Kubernetes)
- Checklist déploiement
### 2. KAFKA_WEBSOCKET_ARCHITECTURE.md
**Emplacement** : `unionflow/docs/KAFKA_WEBSOCKET_ARCHITECTURE.md`
**Contenu** (650+ lignes) :
- Event-Driven architecture complète
- 8 Kafka topics avec JSON schemas
- Docker Compose Kafka + Zookeeper
- Monitoring et debugging
- 3 use cases concrets
---
## 🔄 Flux End-to-End Fonctionnel
### Exemple : Approbation Finance
```
1. Utilisateur approuve une transaction (UI)
2. POST /api/v1/finance/approvals/{id}/approve
3. FinanceWorkflowService.approve(id)
4. KafkaEventProducer.publishApprovalApproved(...)
5. Event publié dans Kafka topic "unionflow.finance.approvals"
6. KafkaEventConsumer.consumeFinanceApprovals(...)
7. WebSocketBroadcastService.broadcast(event)
8. WebSocket envoie event à tous les clients connectés
9. Mobile WebSocketService.eventStream émet FinanceApprovalEvent
10. DashboardBloc reçoit event et dispatch RefreshDashboardFromWebSocket
11. _onRefreshDashboardFromWebSocket rafraîchit les stats
12. UI dashboard se met à jour automatiquement ✅
```
---
## ✅ Tests et Validation
### Build Runner
```bash
✅ flutter pub run build_runner build --delete-conflicting-outputs
Succeeded after 59.9s with 729 outputs (1532 actions)
```
### Compilation
```bash
✅ Aucune erreur de compilation
✅ Tous les imports résolus
✅ Dependency injection générée
```
---
## 📦 Fichiers Modifiés/Créés
### Backend (4 fichiers)
| Fichier | Type | Lignes | Description |
|---------|------|--------|-------------|
| `pom.xml` | Modifié | +15 | Dépendances Kafka |
| `application.properties` | Modifié | +67 | Config Kafka channels |
| `KafkaEventProducer.java` | Créé | 200+ | Producer Kafka |
| `KafkaEventConsumer.java` | Créé | 90+ | Consumer Kafka |
### Mobile (4 fichiers)
| Fichier | Type | Lignes | Description |
|---------|------|--------|-------------|
| `websocket_service.dart` | Créé | 350+ | Service WebSocket |
| `websocket.dart` | Créé | 5 | Export file |
| `dashboard_bloc.dart` | Modifié | +95 | Intégration WebSocket |
| `dashboard_event.dart` | Modifié | +18 | Nouveaux events |
### Documentation (3 fichiers)
| Fichier | Type | Lignes | Description |
|---------|------|--------|-------------|
| `WEBSOCKET_IMPLEMENTATION.md` | Créé/Modifié | 600+ | Guide implémentation |
| `KAFKA_WEBSOCKET_ARCHITECTURE.md` | Créé | 650+ | Architecture Kafka |
| `TASK_6_WEBSOCKET_COMPLETION_REPORT.md` | Créé | Ce fichier | Rapport complétion |
**Total** : 11 fichiers, ~2100 lignes de code/doc
---
## 🎯 Critères de Succès
### Backend
- ✅ Kafka dependencies ajoutées (quarkus-messaging-kafka)
- ✅ KafkaEventProducer créé avec 10+ méthodes publish
- ✅ KafkaEventConsumer créé avec 5 @Incoming consumers
- ✅ Configuration Kafka complète (5 producers + 5 consumers)
- ✅ WebSocket endpoint existant (/ws/dashboard)
- ✅ WebSocketBroadcastService existant
- ✅ Aucune erreur de compilation
### Mobile
- ✅ web_socket_channel package dans pubspec.yaml
- ✅ WebSocketService créé (350+ lignes)
- ✅ Events typés (6 classes d'events)
- ✅ Reconnexion automatique avec backoff exponentiel
- ✅ Heartbeat (ping toutes les 30s)
- ✅ Intégration DashboardBloc complète
- ✅ Build runner successful (729 outputs)
- ✅ Aucune erreur de compilation
### Documentation
- ✅ Guide implémentation complet (WEBSOCKET_IMPLEMENTATION.md)
- ✅ Architecture Kafka documentée (KAFKA_WEBSOCKET_ARCHITECTURE.md)
- ✅ Exemples de code backend et mobile
- ✅ Scénarios d'utilisation end-to-end
- ✅ Configuration production (Kubernetes)
---
## 🚀 Prochaines Étapes (Recommandées)
### Tests (non fait dans Task #6)
1. **Tests unitaires WebSocketService** :
```dart
test('should connect to WebSocket', () async {
service.connect();
await Future.delayed(const Duration(milliseconds: 500));
expect(service.isConnected, true);
});
```
2. **Tests intégration E2E** :
- Démarrer Kafka localement : `docker-compose up -d kafka zookeeper`
- Lancer backend : `./mvnw quarkus:dev`
- Lancer mobile : `flutter run --dart-define=ENV=dev`
- Publier un event test via Swagger UI
- Vérifier que le mobile reçoit l'event
3. **Tests Kafka Producer/Consumer** (backend) :
```java
@QuarkusTest
class KafkaEventProducerTest {
@Test
void shouldPublishApprovalEvent() {
var approvalData = Map.of("id", UUID.randomUUID().toString());
producer.publishApprovalPending(UUID.randomUUID(), "org-123", approvalData);
// Vérifier avec consumer test ou Kafka testcontainer
}
}
```
### Intégration dans Services Métier
**Exemple** : `FinanceWorkflowService.java`
```java
@ApplicationScoped
public class FinanceWorkflowService {
@Inject
KafkaEventProducer kafkaProducer;
public void approveTransaction(UUID approvalId) {
// 1. Logique métier
var approval = repository.findById(approvalId);
approval.setStatus(ApprovalStatus.APPROVED);
repository.persist(approval);
// 2. Publier event Kafka
var approvalData = Map.of(
"id", approval.getId().toString(),
"transactionType", approval.getTransactionType().name(),
"amount", approval.getAmount(),
"currency", approval.getCurrency(),
"approvedBy", approval.getApprovedBy(),
"approvedAt", approval.getApprovedAt().toString()
);
kafkaProducer.publishApprovalApproved(
approvalId,
approval.getOrganizationId(),
approvalData
);
}
}
```
**Services à intégrer** :
- ✅ FinanceWorkflowService (approbations)
- ⏳ MembreService (création/modification membres)
- ⏳ CotisationService (paiements cotisations)
- ⏳ DashboardService (stats périodiques)
- ⏳ NotificationService (notifications push)
### Production Deployment
1. **Docker Compose** (dev/staging) :
```bash
cd unionflow
docker-compose up -d kafka zookeeper
```
2. **Kubernetes ConfigMap** (prod) :
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: unionflow-backend-config
data:
KAFKA_BOOTSTRAP_SERVERS: "kafka-service.kafka.svc.cluster.local:9092"
```
3. **Mobile AppConfig** (auto-détection) :
```dart
// AppConfig.backendBaseUrl = https://api.lions.dev/unionflow
// WebSocket URL = wss://api.lions.dev/unionflow/ws/dashboard
```
---
## 🎉 Conclusion
**Task #6 : WebSocket Temps Réel** est maintenant **100% COMPLET**
L'architecture Event-Driven avec Kafka + WebSocket est entièrement fonctionnelle :
- Backend publie les events business dans Kafka
- Consumer Kafka broadcast via WebSocket
- Mobile reçoit les events en temps réel
- DashboardBloc auto-refresh le dashboard
- Reconnexion automatique si déconnexion
- Documentation complète
**Prêt pour tests end-to-end** et intégration dans les services métier.
---
**Implémenté par** : Claude Sonnet 4.5
**Date** : 2026-03-14
**Status** : ✅ **PRODUCTION-READY** (après tests E2E)

View File

@@ -0,0 +1,300 @@
# Tests Unitaires - Progression
**Date:** 2026-03-14
**Objectif:** Implémenter tests unitaires pour 64 use cases
**Statut:** 🚧 **EN COURS** - Fondations établies
---
## 📊 État Actuel
### Tests Créés et Passants ✅
| Feature | Use Case Testé | Status | Tests |
|---------|----------------|--------|-------|
| Profile | GetProfile | ✅ PASS | 4/4 tests passés |
| Settings | ResetSettings | ✅ PASS | 4/4 tests passés |
**Total: 8/8 tests passés (100%)**
### Tests Créés avec Erreurs ❌
| Feature | Use Case | Problème |
|---------|----------|----------|
| Contributions | GetContributions | Propriétés modèle non concordantes |
---
## 🏗️ Infrastructure de Tests Mise en Place
### 1. Structure de Dossiers
```
test/features/
├── finance_workflow/domain/usecases/
├── contributions/domain/usecases/
├── events/domain/usecases/
├── members/domain/usecases/
├── profile/domain/usecases/ ✅ GetProfile tests
├── organizations/domain/usecases/
├── reports/domain/usecases/
└── settings/domain/usecases/ ✅ ResetSettings tests
```
### 2. Dépendances de Test (pubspec.yaml)
**Configuré:**
- `mockito: ^5.4.4` - Mocking framework
- `bloc_test: ^9.1.7` - BLoC testing utilities
- `build_runner: ^2.4.13` - Code generation
- `flutter_test: sdk` - Flutter testing framework
- `integration_test: sdk` - Integration testing
### 3. Build Runner
**Configuré et fonctionnel:**
```bash
flutter pub run build_runner build --delete-conflicting-outputs
# Succeeded after 27.9s with 18 outputs (38 actions)
```
### 4. Pattern de Test Établi
**Use Case Test Template:**
```dart
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:unionflow_mobile_apps/features/.../domain/repositories/...repository.dart';
import 'package:unionflow_mobile_apps/features/.../domain/usecases/...usecase.dart';
@GenerateMocks([IRepository])
import 'test_name_test.mocks.dart';
void main() {
late UseCase useCase;
late MockIRepository mockRepository;
setUp(() {
mockRepository = MockIRepository();
useCase = UseCase(mockRepository);
});
group('UseCase Test Group', () {
test('should perform expected behavior', () async {
// Arrange
when(mockRepository.method(...)).thenAnswer((_) async => expectedResult);
// Act
final result = await useCase(...);
// Assert
expect(result, equals(expectedResult));
verify(mockRepository.method(...));
verifyNoMoreInteractions(mockRepository);
});
});
}
```
---
## ✅ Tests Réussis - Détails
### GetProfile (4/4 tests ✅)
**Fichier:** `test/features/profile/domain/usecases/get_profile_test.dart`
**Tests:**
1. ✅ Should return current user profile from repository
2. ✅ Should return null when user is not authenticated
3. ✅ Should throw exception when repository throws
4. ✅ Should cache profile data on successful retrieval
**Résultats:**
```
00:00 +4: All tests passed!
```
**Mock utilisé:** `MockIProfileRepository`
**Modèle:** `MembreCompletModel` (3 champs requis: nom, prenom, email)
---
### ResetSettings (4/4 tests ✅)
**Fichier:** `test/features/settings/domain/usecases/reset_settings_test.dart`
**Tests:**
1. ✅ Should reset configuration to default values
2. ✅ Should handle fallback when reset endpoint fails
3. ✅ Should throw exception when all reset strategies fail
4. ✅ Should return valid config with minimal required fields
**Résultats:**
```
00:00 +4: ResetSettings Use Case - All tests passed!
```
**Mock utilisé:** `MockISystemConfigRepository`
**Modèle:** `SystemConfigModel` (tous champs optionnels)
---
## 📋 Prochaines Étapes
### Phase 1: Corriger Tests Existants
- [ ] Fixer GetContributions (corriger propriétés modèle)
- [ ] Regénérer mocks avec build_runner
- [ ] Vérifier 100% tests passants
### Phase 2: Créer Tests pour Features P1 (26 use cases)
**Contributions (8 use cases):**
- [ ] get_contributions.dart
- [ ] get_contribution_by_id.dart
- [ ] create_contribution.dart
- [ ] update_contribution.dart
- [ ] delete_contribution.dart
- [ ] pay_contribution.dart
- [ ] get_contribution_history.dart
- [ ] get_contribution_stats.dart
**Events (10 use cases):**
- [ ] get_events.dart
- [ ] get_event_by_id.dart
- [ ] create_event.dart
- [ ] update_event.dart
- [ ] delete_event.dart
- [ ] register_for_event.dart
- [ ] cancel_registration.dart
- [ ] get_my_registrations.dart
- [ ] get_event_participants.dart
- [ ] submit_event_feedback.dart
**Members (8 use cases):**
- [ ] get_members.dart
- [ ] get_member_by_id.dart
- [ ] create_member.dart
- [ ] update_member.dart
- [ ] delete_member.dart
- [ ] search_members.dart
- [ ] export_members.dart
- [ ] get_member_stats.dart
### Phase 3: Créer Tests pour Features P2 (18 use cases)
**Organizations (7 use cases):**
- [ ] get_organizations.dart
- [ ] get_organization_by_id.dart
- [ ] create_organization.dart
- [ ] update_organization.dart
- [ ] delete_organization.dart
- [ ] get_organization_members.dart
- [ ] update_organization_config.dart
**Reports (6 use cases):**
- [ ] get_reports.dart
- [ ] generate_report.dart
- [ ] export_report_pdf.dart
- [ ] export_report_excel.dart
- [ ] schedule_report.dart
- [ ] get_scheduled_reports.dart
**Settings (5 use cases):**
- [x] ✅ reset_settings.dart (4/4 tests)
- [ ] get_settings.dart
- [ ] update_settings.dart
- [ ] get_cache_stats.dart
- [ ] clear_cache.dart
### Phase 4: Tests BLoC (10 BLoCs)
Pour chaque BLoC, tester:
- État initial
- Transitions d'états
- Gestion d'erreurs
- Appels use cases corrects
**Utiliser `bloc_test` package:**
```dart
blocTest<MyBloc, MyState>(
'emits [MyState] when event is added',
build: () => MyBloc(mockUseCase),
act: (bloc) => bloc.add(MyEvent()),
expect: () => [MyExpectedState()],
);
```
### Phase 5: Tests d'Intégration
- [ ] Tests end-to-end flows critiques
- [ ] Tests avec backend mock complet
- [ ] Tests de navigation
- [ ] Tests de persistance
---
## 🎯 Objectif Final
| Métrique | Cible | Actuel | % |
|----------|-------|--------|---|
| Use Cases testés | 64 | 2 | 3% |
| Tests unitaires | ~256 (4/use case) | 8 | 3% |
| BLoCs testés | 10 | 0 | 0% |
| Coverage | 80% | ~5% | 6% |
---
## 🔧 Commandes Utiles
### Générer mocks:
```bash
flutter pub run build_runner build --delete-conflicting-outputs
```
### Exécuter tous les tests:
```bash
flutter test
```
### Exécuter tests spécifiques:
```bash
flutter test test/features/profile/domain/usecases/
```
### Coverage report:
```bash
flutter test --coverage
genhtml coverage/lcov.info -o coverage/html
```
---
## 📝 Notes Techniques
### Gotchas Rencontrés
1. **Noms de classes/fichiers incohérents:**
- Fichier: `membre_complete_model.dart`
- Classe: `MembreCompletModel` (sans 'e' final)
- ⚠️ Toujours vérifier le nom exact de la classe
2. **Propriétés de modèles:**
- Toujours lire le fichier modèle pour connaître les vraies propriétés
- Ne pas inventer de propriétés dans les tests
3. **Génération de mocks:**
- Exécuter build_runner après chaque modification de `@GenerateMocks`
- Les mocks sont générés dans `*.mocks.dart`
4. **Imports:**
- Repository: depuis `domain/repositories/`
- Use case: depuis `domain/usecases/`
- Modèles: depuis `data/models/`
---
**Fondations établies par:** Claude Code
**Date:** 2026-03-14
**Statut:** ✅ Infrastructure prête - Prochaine étape: Créer tests pour 62 use cases restants

View File

@@ -169,7 +169,7 @@ Module `RegisterModule` enregistre :
- [Permission Matrix](../../features/authentication/data/models/permission_matrix.dart) - [Permission Matrix](../../features/authentication/data/models/permission_matrix.dart)
- [User Roles](../../features/authentication/data/models/user_role.dart) - [User Roles](../../features/authentication/data/models/user_role.dart)
- [API Design](../../specs/000-unionflow-baseline/spec.md) - [API Design](../../specs/000-unionflow-baseline/spec.md)
- [Audit Métier](../../AUDIT_METIER_COMPLET.md) - [Constitution UnionFlow](../../../../.specify/memory/constitution.md)
## ✅ Critères d'Acceptation ## ✅ Critères d'Acceptation