- Task #6: WebSocket /ws/dashboard + Kafka events (5 topics) * Backend: KafkaEventProducer, KafkaEventConsumer * Mobile: WebSocketService (reconnection, heartbeat, typed events) * DashboardBloc: Auto-refresh depuis WebSocket events - Finance Workflow: approbations + budgets (backend + mobile) * Backend: entities, services, resources, migrations Flyway V6 * Mobile: features finance_workflow complète avec BLoC - Corrections DI: interfaces IRepository partout * IProfileRepository, IOrganizationRepository, IMembreRepository * GetIt configuré avec @injectable - Spec-Kit: constitution + templates mis à jour * .specify/memory/constitution.md enrichie * Templates agent, plan, spec, tasks, checklist - Nettoyage: fichiers temporaires supprimés Signed-off-by: lions dev Team
529 lines
14 KiB
Markdown
529 lines
14 KiB
Markdown
# 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](#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<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
|
|
|
|
```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
|
|
<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](../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
|