# UnionFlow Mobile - Application Flutter ![Flutter](https://img.shields.io/badge/Flutter-3.5.3-blue) ![Dart](https://img.shields.io/badge/Dart-3.x-blue) ![Platform](https://img.shields.io/badge/Platform-Android%20%7C%20iOS-green) ![License](https://img.shields.io/badge/License-Proprietary-red) Application mobile multiplateforme pour la gestion des mutuelles, associations et organisations Lions Club Côte d'Ivoire. --- ## 📋 Table des Matières - [Fonctionnalités](#fonctionnalités) - [Architecture](#architecture) - [Technologies](#technologies) - [Prérequis](#prérequis) - [Installation](#installation) - [Configuration Environnement](#configuration-environnement) - [Build & Release](#build--release) - [Tests](#tests) - [WebSocket Temps Réel](#websocket-temps-réel) - [Sécurité](#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 │ ├── 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 ```bash git clone https://git.lions.dev/lionsdev/unionflow-mobile-apps.git cd unionflow-mobile-apps ``` ### 2. Installer les dépendances ```bash flutter pub get ``` ### 3. Générer le code (DTOs, DI) ```bash flutter pub run build_runner build --delete-conflicting-outputs ``` ### 4. Lancer l'app ```bash # 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` ```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 ```bash # 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 ```bash # 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 ```bash # Release build flutter build ios --release --dart-define=ENV=prod # Ouvrir Xcode pour archiver open ios/Runner.xcworkspace ``` ### Signing (Android) **Fichier** : `android/key.properties` ```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 ```bash # 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 ```bash 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.approvals` - `unionflow.dashboard.stats` - `unionflow.notifications.user` ### WebSocketService **Fichier** : `lib/core/websocket/websocket_service.dart` ```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](../docs/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` ```xml 10.0.2.2 localhost ``` **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](../docs/KAFKA_WEBSOCKET_ARCHITECTURE.md) - **Form Validation** : [FORM_VALIDATION_IMPLEMENTATION.md](docs/FORM_VALIDATION_IMPLEMENTATION.md) - **Error Handling** : [ERROR_HANDLING_IMPLEMENTATION.md](docs/ERROR_HANDLING_IMPLEMENTATION.md) - **Finance Workflow** : [README.md](lib/features/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