Phase 4 Mobile - Section 4.1 Épargne Nouveaux fichiers : - SeuilLcbFtModel : modèle pour seuil depuis API - ParametresLcbFtRepository : appel /api/parametres-lcb-ft/seuil-justification - @lazySingleton pour injection GetIt Modifications : - DepotEpargneDialog : charge seuil au initState, fallback 500k XOF - RetraitEpargneDialog : idem - Remplace constante kSeuilOrigineFondsObligatoireXOF par valeur dynamique Impact : - Seuil LCB-FT maintenant configurable par organisation - Fallback automatique si API échoue - Messages utilisateur avec montant dynamique Spec : specs/001-mutuelles-anti-blanchiment/spec.md Progression : 16/27 tâches (59%) Signed-off-by: lions dev Team
UnionFlow Mobile - Application Flutter
Application mobile multiplateforme pour la gestion des mutuelles, associations et organisations Lions Club Côte d'Ivoire.
📋 Table des Matières
- Fonctionnalités
- Architecture
- Technologies
- Prérequis
- Installation
- Configuration Environnement
- Build & Release
- Tests
- WebSocket Temps Réel
- Sécurité
✨ Fonctionnalités
Authentification & Sécurité
- ✅ Authentification Keycloak OIDC (via WebView)
- ✅ JWT validation (issuer + expiry mobile-side)
- ✅ Role-based access control (RBAC)
- ✅ Permission engine granulaire
- ✅ Refresh token automatique
Dashboard Intelligent
- ✅ Dashboard rôle-spécifique (8 dashboards)
- ✅ Stats temps réel via WebSocket
- ✅ KPI avec graphiques interactifs
- ✅ Activités récentes
- ✅ Mode offline avec cache
Finance Workflow ⭐ NOUVEAU
- ✅ Approbations de transactions (approve/reject)
- ✅ Gestion budgets avec lignes budgétaires
- ✅ Validation formulaires réutilisable
- ✅ Retry automatique avec backoff exponentiel
- ✅ Offline queue (opérations en attente)
Membres
- ✅ Liste membres avec recherche avancée
- ✅ Profils membres détaillés
- ✅ Création/modification membres
- ✅ Import/export données (futur)
Cotisations
- ✅ Historique cotisations membre
- ✅ Statistiques cotisations
- ✅ Paiement Wave Money (futur)
- ✅ Rappels automatiques
Événements
- ✅ Calendrier événements
- ✅ Inscription événements
- ✅ Détails événement avec participants
- ✅ Notifications rappel
Solidarité
- ✅ Demandes d'aide (création, suivi)
- ✅ Propositions d'aide
- ✅ Workflow validation
- ✅ Commentaires et évaluations
Notifications
- ✅ Notifications push temps réel (WebSocket)
- ✅ Centre de notifications
- ✅ Marquer comme lu
- ✅ Filtres par type
Organisations
- ✅ Multi-organisations
- ✅ Gestion quotas membres
- ✅ Hiérarchie organisations
🏗️ Architecture
Clean Architecture + BLoC Pattern
lib/
├── app/ # Application setup
│ ├── app.dart # MyApp widget
│ └── router/ # Navigation
├── core/ # Core layer (shared)
│ ├── config/
│ │ └── environment.dart # AppConfig (ENV-based)
│ ├── di/
│ │ └── injection_container.dart # GetIt DI
│ ├── network/
│ │ ├── api_client.dart # Dio client
│ │ ├── retry_policy.dart # Retry avec backoff
│ │ └── offline_manager.dart # Offline queue
│ ├── storage/
│ │ ├── dashboard_cache_manager.dart
│ │ └── pending_operations_store.dart
│ ├── validation/
│ │ └── validators.dart # 20+ validators
│ ├── error/
│ │ └── failures.dart # Either<Failure, T>
│ ├── utils/
│ │ └── logger.dart # AppLogger
│ └── websocket/
│ └── websocket_service.dart # WebSocket client
├── features/ # Features (Clean Architecture)
│ ├── authentication/
│ │ ├── data/
│ │ │ ├── datasources/ # Keycloak WebView
│ │ │ ├── models/ # UserRole, Permission
│ │ │ └── repositories/
│ │ ├── domain/
│ │ │ ├── entities/ # User, Permission
│ │ │ ├── repositories/ # Abstract
│ │ │ └── usecases/ # Login, Logout
│ │ └── presentation/
│ │ ├── bloc/ # AuthBloc
│ │ └── pages/ # LoginPage
│ ├── dashboard/
│ │ ├── data/
│ │ │ ├── datasources/ # DashboardRemoteDatasource
│ │ │ ├── models/ # DashboardStatsModel
│ │ │ └── repositories/
│ │ ├── domain/
│ │ │ ├── entities/ # DashboardEntity
│ │ │ ├── repositories/
│ │ │ └── usecases/ # GetDashboardData
│ │ └── presentation/
│ │ ├── bloc/ # DashboardBloc
│ │ ├── pages/
│ │ │ ├── connected_dashboard_page.dart
│ │ │ └── role_dashboards/ # 8 dashboards
│ │ └── widgets/ # Stat cards, charts
│ ├── finance_workflow/ ⭐ **NOUVEAU**
│ │ ├── data/
│ │ │ ├── datasources/
│ │ │ ├── models/
│ │ │ └── repositories/ # Avec retry + offline
│ │ ├── domain/
│ │ │ ├── entities/
│ │ │ │ ├── transaction_approval.dart
│ │ │ │ └── budget.dart
│ │ │ ├── repositories/
│ │ │ └── usecases/
│ │ └── presentation/
│ │ ├── bloc/
│ │ ├── pages/
│ │ │ └── pending_approvals_page.dart
│ │ └── widgets/
│ │ ├── approve_dialog.dart
│ │ ├── reject_dialog.dart
│ │ └── create_budget_dialog.dart
│ ├── members/
│ ├── contributions/
│ ├── events/
│ ├── solidarity/
│ ├── organizations/
│ └── notifications/
├── shared/ # Shared UI components
│ ├── design_system/
│ │ ├── tokens/ # AppColors, AppTypography
│ │ ├── theme/ # AppTheme
│ │ └── components/ # Reusable widgets
│ └── widgets/
│ ├── validated_text_field.dart
│ ├── error_display_widget.dart
│ └── confirmation_dialog.dart
└── main.dart # Entry point
Pattern : Data → Domain → Presentation
- Data Layer : Models, Datasources, Repositories Impl
- Domain Layer : Entities, Use Cases, Repository Interfaces
- Presentation Layer : BLoC, Pages, Widgets
🛠️ Technologies
Core Stack
| Package | Version | Usage |
|---|---|---|
| flutter | 3.5.3+ | Framework UI |
| dart | 3.x | Langage |
| flutter_bloc | ^8.1.0 | State management |
| equatable | ^2.0.5 | Value equality |
| dartz | ^0.10.1 | Functional programming (Either) |
| get_it | ^7.6.0 | Dependency injection |
| injectable | ^2.3.0 | DI code generation |
| dio | ^5.4.0 | HTTP client |
| retrofit | ^4.0.0 | Type-safe REST clients |
| json_annotation | ^4.8.0 | JSON serialization |
| json_serializable | ^6.6.0 | Code generation |
| freezed | ^2.4.0 | Immutable classes |
| shared_preferences | ^2.2.0 | Local storage |
| connectivity_plus | ^5.0.0 | Network status |
| web_socket_channel | ^2.4.0 | WebSocket client |
| fl_chart | ^0.66.0 | Charts |
| intl | ^0.18.0 | Internationalization |
| logger | ^2.0.0 | Logging |
| webview_flutter | ^4.5.0 | Keycloak WebView auth |
Dev Dependencies
- build_runner : Code generation
- flutter_test : Tests unitaires
- mockito : Mocking
- bloc_test : Tests BLoC
- flutter_lints : Linting
📦 Prérequis
Environnement de développement
- Flutter SDK : 3.5.3 ou supérieur
- Dart SDK : 3.x (inclus avec Flutter)
- Android Studio / Xcode (iOS)
- Git : 2.30+
Services externes
- Backend UnionFlow : http://localhost:8085 (dev)
- Keycloak : http://localhost:8180 (dev)
- Kafka : localhost:9092 (optionnel, pour WebSocket)
🚀 Installation
1. Cloner le projet
git clone https://git.lions.dev/lionsdev/unionflow-mobile-apps.git
cd unionflow-mobile-apps
2. Installer les dépendances
flutter pub get
3. Générer le code (DTOs, DI)
flutter pub run build_runner build --delete-conflicting-outputs
4. Lancer l'app
# Dev (ENV=dev par défaut)
flutter run
# Ou avec env spécifique
flutter run --dart-define=ENV=dev
flutter run --dart-define=ENV=staging
flutter run --dart-define=ENV=prod
⚙️ Configuration Environnement
AppConfig (environment.dart)
Fichier : lib/core/config/environment.dart
class AppConfig {
static String get environment => const String.fromEnvironment('ENV', defaultValue: 'dev');
static String get backendBaseUrl {
switch (environment) {
case 'prod':
return 'https://api.lions.dev/unionflow';
case 'staging':
return 'https://staging-api.lions.dev/unionflow';
case 'dev':
default:
return 'http://10.0.2.2:8085'; // Android emulator localhost
}
}
static String get keycloakBaseUrl {
switch (environment) {
case 'prod':
return 'https://security.lions.dev/realms/unionflow';
case 'staging':
return 'https://staging-security.lions.dev/realms/unionflow';
case 'dev':
default:
return 'http://10.0.2.2:8180/realms/unionflow';
}
}
static bool get enableLogging => environment != 'prod';
}
Build avec environnement
# Dev
flutter run --dart-define=ENV=dev
# Staging
flutter run --dart-define=ENV=staging
# Production
flutter run --dart-define=ENV=prod --release
Note : --dart-define valeurs sont compile-time constants via String.fromEnvironment().
📱 Build & Release
Android APK/AAB
# Debug APK
flutter build apk --dart-define=ENV=dev
# Release APK
flutter build apk --release --dart-define=ENV=prod
# Release AAB (Google Play)
flutter build appbundle --release --dart-define=ENV=prod
Output :
- APK :
build/app/outputs/flutter-apk/app-release.apk - AAB :
build/app/outputs/bundle/release/app-release.aab
iOS IPA
# Release build
flutter build ios --release --dart-define=ENV=prod
# Ouvrir Xcode pour archiver
open ios/Runner.xcworkspace
Signing (Android)
Fichier : android/key.properties
storePassword=your-store-password
keyPassword=your-key-password
keyAlias=upload
storeFile=/path/to/keystore.jks
Note : key.properties est gitignored (sécurité).
🧪 Tests
Tests unitaires
# Tous les tests
flutter test
# Tests spécifiques
flutter test test/core/validation/validators_test.dart
# Avec couverture
flutter test --coverage
genhtml coverage/lcov.info -o coverage/html
open coverage/html/index.html
Tests d'intégration
flutter test integration_test/finance_workflow_integration_test.dart
Tests existants
✅ 54 tests validation (validators_test.dart) - 100% ✅ 12 tests retry policy (retry_policy_test.dart) ✅ 8 tests offline manager (offline_manager_test.dart)
🔌 WebSocket Temps Réel
Architecture Kafka → WebSocket → Mobile
Backend Services → Kafka Topics → WebSocket Server → Mobile App
Topics consommés :
unionflow.finance.approvalsunionflow.dashboard.statsunionflow.notifications.user
WebSocketService
Fichier : lib/core/websocket/websocket_service.dart
@singleton
class WebSocketService {
WebSocketChannel? _channel;
void connect() {
final wsUrl = '${AppConfig.backendBaseUrl.replaceFirst('http', 'ws')}/ws/dashboard';
_channel = WebSocketChannel.connect(Uri.parse(wsUrl));
_channel!.stream.listen(
(message) {
// Broadcast event to BLoCs
_messageController.add(message);
},
onError: (error) => _reconnect(),
onDone: () => _reconnect(),
);
}
}
Reconnexion automatique après 5 secondes en cas de déconnexion.
Voir KAFKA_WEBSOCKET_ARCHITECTURE.md pour détails complets.
🔒 Sécurité
Authentification Keycloak OIDC
- Méthode : WebView + Authorization Code Flow
- Tokens : JWT access token + refresh token
- Validation mobile : Issuer + expiry vérifiés localement
- Signature backend : Vérification signature JWT côté serveur
Network Security (Android)
Fichier : android/app/src/main/res/xml/network_security_config.xml
<network-security-config>
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
<!-- Dev only -->
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">10.0.2.2</domain> <!-- Android emulator -->
<domain includeSubdomains="true">localhost</domain>
</domain-config>
</network-security-config>
Production : cleartextTrafficPermitted="false" strict.
ProGuard (Android)
Fichier : android/app/proguard-rules.pro
Règles de minification activées en release.
App Transport Security (iOS)
Fichier : ios/Runner/Info.plist
HTTPS forcé en production.
📊 Performance
Cache Dashboard
TTL : 5 minutes (stats dashboard) Storage : SharedPreferences
Offline Support
- Pending operations : Queue persistée (SharedPreferences)
- Retry automatique : Exponential backoff (3 tentatives)
- Connectivity monitoring : connectivity_plus
📚 Documentation
- Architecture Kafka + WebSocket : KAFKA_WEBSOCKET_ARCHITECTURE.md
- Form Validation : FORM_VALIDATION_IMPLEMENTATION.md
- Error Handling : ERROR_HANDLING_IMPLEMENTATION.md
- Finance Workflow : README.md
📄 Licence
Propriétaire - © 2026 Lions Club Côte d'Ivoire
Version : 2.0.0 Dernière mise à jour : 2026-03-14 Auteur : Équipe UnionFlow