Files
unionflow-server-api/unionflow/unionflow-mobile-apps/README.md
dahoud e8ad874015 feat: WebSocket temps réel + Finance Workflow + corrections
- 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
2026-03-15 02:12:17 +00:00

529 lines
14 KiB
Markdown

# 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<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