docs(mobile): documentation complète Spec 001 + architecture

Documentation ajoutée :
- ARCHITECTURE.md : Clean Architecture par feature, BLoC pattern
- OPTIMISATIONS_PERFORMANCE.md : Cache multi-niveaux, pagination, lazy loading
- SECURITE_PRODUCTION.md : FlutterSecureStorage, JWT, HTTPS, ProGuard
- CHANGELOG.md : Historique versions
- CONTRIBUTING.md : Guide contribution
- README.md : Mise à jour (build, env config)

Widgets partagés :
- file_upload_widget.dart : Upload fichiers (photos/PDFs)

Cache :
- lib/core/cache/ : Système cache L1/L2 (mémoire/disque)

Dependencies :
- pubspec.yaml : file_picker 8.1.2, injectable, dio

Spec 001 : 27/27 tâches (100%)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
dahoud
2026-03-16 05:15:38 +00:00
parent 775729b4c3
commit 5c5ec3ad00
10 changed files with 3607 additions and 154 deletions

582
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,582 @@
# Guide de Contribution - UnionFlow Mobile
Merci de votre intérêt pour contribuer à UnionFlow Mobile! Ce guide vous aidera à démarrer.
---
## Table des Matières
1. [Code of Conduct](#code-of-conduct)
2. [Comment Contribuer](#comment-contribuer)
3. [Setup Environnement](#setup-environnement)
4. [Standards de Code](#standards-de-code)
5. [Architecture](#architecture)
6. [Workflow Git](#workflow-git)
7. [Tests](#tests)
8. [Pull Requests](#pull-requests)
9. [Code Review](#code-review)
10. [Bonnes Pratiques](#bonnes-pratiques)
---
## Code of Conduct
En contribuant à ce projet, vous acceptez de respecter notre Code de Conduite:
- 🤝 Respecter tous les contributeurs
- 💬 Communication constructive et professionnelle
- 🎯 Focus sur le projet et ses objectifs
- 🚫 Zéro tolérance pour le harcèlement ou discrimination
---
## Comment Contribuer
### Types de Contributions
**Bug Fixes** - Correction de bugs
**Features** - Nouvelles fonctionnalités
**Documentation** - Amélioration de la doc
**Tests** - Ajout ou amélioration des tests
**Performance** - Optimisations
**Refactoring** - Amélioration du code existant
### Avant de Commencer
1. **Vérifier les issues existantes** - Peut-être que quelqu'un travaille déjà dessus
2. **Créer une issue** - Si le bug/feature n'existe pas encore
3. **Discuter** - Commenter l'issue pour proposer votre approche
4. **Assignation** - Se faire assigner l'issue avant de commencer
---
## Setup Environnement
### Prérequis
| Outil | Version Minimale |
|-------|------------------|
| Flutter | 3.5.3+ |
| Dart | 3.5.3+ |
| Git | Latest |
| Android Studio | Latest (pour Android) |
| Xcode | 14+ (pour iOS, macOS uniquement) |
### Installation
```bash
# 1. Cloner le repo
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 (build_runner)
flutter pub run build_runner build --delete-conflicting-outputs
# 4. Vérifier que tout fonctionne
flutter doctor
flutter analyze
flutter test
```
### Configuration Backend Local
Pour développer en local, vous avez besoin du backend Quarkus:
```bash
cd ../unionflow-server-impl-quarkus
mvn clean quarkus:dev
```
Backend disponible sur: `http://localhost:8085`
---
## Standards de Code
### Linting
Nous utilisons **flutter_lints** avec configuration stricte.
```bash
# Analyser le code
flutter analyze
# Formater le code
flutter format lib/
```
### Conventions de Nommage
**Fichiers**: snake_case
```
✅ dashboard_bloc.dart
❌ DashboardBloc.dart
❌ dashboard-bloc.dart
```
**Classes**: PascalCase
```dart
class DashboardBloc {}
class dashboardBloc {}
class Dashboard_Bloc {}
```
**Variables/Fonctions**: camelCase
```dart
final userName = 'John';
void getUserData() {}
final user_name = 'John';
void get_user_data() {}
```
**Constantes**: lowerCamelCase (pas SCREAMING_CASE en Dart)
```dart
static const baseUrl = 'https://api.lions.dev';
static const BASE_URL = 'https://api.lions.dev';
```
**Private members**: préfixe `_`
```dart
String _privateVariable;
void _privateMethod() {}
```
### Documentation
**Classes publiques**:
```dart
/// Service pour gérer l'authentification Keycloak.
///
/// Ce service gère le login, logout et refresh token
/// avec stockage sécurisé des credentials.
class KeycloakAuthService {
// ...
}
```
**Méthodes publiques**:
```dart
/// Authentifie un utilisateur avec username et password.
///
/// Retourne [User] si succès, `null` si échec.
/// Stocke les tokens dans [FlutterSecureStorage].
Future<User?> login(String username, String password) async {
// ...
}
```
**TODO Comments**:
```dart
// TODO(username): Ajouter support biométrique
// FIXME(username): Bug lors du logout après timeout
// HACK(username): Workaround temporaire, à refactoriser
```
---
## Architecture
UnionFlow Mobile suit **Clean Architecture + BLoC**.
### Structure d'une Feature
```
features/
└── my_feature/
├── data/
│ ├── datasources/
│ │ └── my_feature_remote_datasource.dart
│ ├── models/
│ │ ├── my_model.dart
│ │ └── my_model.g.dart
│ └── repositories/
│ └── my_feature_repository_impl.dart
├── domain/
│ ├── entities/
│ │ └── my_entity.dart
│ ├── repositories/
│ │ └── my_feature_repository.dart
│ └── usecases/
│ └── get_my_data.dart
└── presentation/
├── bloc/
│ ├── my_feature_bloc.dart
│ ├── my_feature_event.dart
│ └── my_feature_state.dart
├── pages/
│ └── my_feature_page.dart
└── widgets/
└── my_feature_card.dart
```
### Règles de Dépendance
**Presentation** peut dépendre de **Domain**
**Data** peut dépendre de **Domain**
**Domain** ne doit JAMAIS dépendre de **Data** ou **Presentation**
### Checklist d'une Nouvelle Feature
- [ ] Créer les **Entities** dans `domain/entities/`
- [ ] Créer le **Repository Interface** dans `domain/repositories/`
- [ ] Créer les **Use Cases** dans `domain/usecases/`
- [ ] Créer les **Models** dans `data/models/` avec `@JsonSerializable`
- [ ] Créer le **Data Source** dans `data/datasources/`
- [ ] Implémenter le **Repository** dans `data/repositories/`
- [ ] Créer **Events** dans `presentation/bloc/`
- [ ] Créer **States** dans `presentation/bloc/`
- [ ] Créer le **BLoC** dans `presentation/bloc/`
- [ ] Créer les **Pages** dans `presentation/pages/`
- [ ] Créer les **Widgets** dans `presentation/widgets/`
- [ ] Enregistrer dans **DI** (`core/di/injection_container.dart`)
- [ ] Ajouter **Tests**
- [ ] Mettre à jour **Documentation**
---
## Workflow Git
### Branches
**Branches principales**:
- `main` - Production (protégée)
- `develop` - Développement (protégée)
**Branches de feature**:
```bash
feature/<issue-number>-<short-description>
```
Exemples:
```
feature/123-add-biometric-login
feature/456-fix-dashboard-crash
feature/789-improve-cache-performance
```
### Workflow
```bash
# 1. Créer une branche depuis develop
git checkout develop
git pull origin develop
git checkout -b feature/123-add-biometric-login
# 2. Développer et commiter
git add .
git commit -m "feat: add biometric authentication"
# 3. Pousser la branche
git push origin feature/123-add-biometric-login
# 4. Créer une Pull Request vers develop
```
### Commits
Nous suivons **Conventional Commits**:
**Format**:
```
<type>(<scope>): <description>
[optional body]
[optional footer]
```
**Types**:
- `feat` - Nouvelle fonctionnalité
- `fix` - Correction de bug
- `docs` - Documentation
- `style` - Formatage (pas de changement de code)
- `refactor` - Refactoring (ni bug ni feature)
- `perf` - Optimisation de performance
- `test` - Ajout ou modification de tests
- `chore` - Maintenance (dépendances, config, etc.)
**Exemples**:
```bash
feat(auth): add biometric login support
fix(dashboard): resolve null pointer on stats refresh
docs(readme): update installation instructions
refactor(cache): simplify cache service implementation
test(members): add unit tests for member repository
perf(dashboard): optimize dashboard loading time
chore(deps): upgrade flutter to 3.5.4
```
**Scope**: module concerné (auth, dashboard, members, etc.)
**Description**:
- Impératif ("add" pas "added" ou "adds")
- Minuscule (pas de majuscule en début)
- Pas de point final
- Max 72 caractères
---
## Tests
### Tests Unitaires
**Domain Layer**:
```dart
// test/domain/usecases/get_dashboard_data_test.dart
void main() {
late GetDashboardData useCase;
late MockDashboardRepository mockRepository;
setUp(() {
mockRepository = MockDashboardRepository();
useCase = GetDashboardData(mockRepository);
});
test('should return DashboardEntity when repository call succeeds', () async {
// Arrange
when(mockRepository.getDashboardData())
.thenAnswer((_) async => Right(tDashboardEntity));
// Act
final result = await useCase();
// Assert
expect(result, Right(tDashboardEntity));
verify(mockRepository.getDashboardData());
verifyNoMoreInteractions(mockRepository);
});
}
```
**BLoC Tests**:
```dart
// test/presentation/bloc/dashboard_bloc_test.dart
void main() {
late DashboardBloc bloc;
late MockGetDashboardData mockGetDashboardData;
setUp(() {
mockGetDashboardData = MockGetDashboardData();
bloc = DashboardBloc(getDashboardData: mockGetDashboardData);
});
blocTest<DashboardBloc, DashboardState>(
'emits [Loading, Loaded] when LoadDashboardData succeeds',
build: () {
when(mockGetDashboardData()).thenAnswer(
(_) async => Right(tDashboard),
);
return bloc;
},
act: (bloc) => bloc.add(LoadDashboardData()),
expect: () => [
DashboardLoading(),
DashboardLoaded(tDashboard),
],
verify: (_) {
verify(mockGetDashboardData()).called(1);
},
);
}
```
### Lancer les Tests
```bash
# Tous les tests
flutter test
# Tests avec coverage
flutter test --coverage
# Visualiser coverage
genhtml coverage/lcov.info -o coverage/html
open coverage/html/index.html
```
### Coverage Minimum
**Target**: 80% de coverage minimum pour les nouvelles features
---
## Pull Requests
### Avant de Créer une PR
**Code compilé**: `flutter build apk --debug`
**Linting**: `flutter analyze` sans erreur
**Tests**: `flutter test` 100% pass
**Formaté**: `flutter format lib/`
**Commits propres**: Utiliser Conventional Commits
### Template de PR
```markdown
## Description
Brève description du changement.
## Type de Changement
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
## Issue Liée
Closes #123
## Comment Tester
1. Lancer l'app
2. Naviguer vers Dashboard
3. Vérifier que les stats se chargent
## Checklist
- [ ] Mon code suit les conventions du projet
- [ ] J'ai commenté mon code aux endroits complexes
- [ ] J'ai mis à jour la documentation si nécessaire
- [ ] Mes changements ne génèrent pas de warnings
- [ ] J'ai ajouté des tests qui prouvent mon fix/feature
- [ ] Tous les tests passent localement
- [ ] J'ai vérifié que le code build en release
```
### Taille de PR
**Idéal**: 200-400 lignes
**Max acceptable**: 800 lignes
Si > 800 lignes, découper en plusieurs PRs.
---
## Code Review
### Pour le Reviewer
**Architecture** - Respecte Clean Architecture + BLoC?
**Tests** - Coverage suffisant?
**Performance** - Pas de régressions?
**Sécurité** - Pas de vulnérabilités?
**Lisibilité** - Code compréhensible?
**Documentation** - Suffisamment documenté?
### Pour l'Auteur
**Répondre rapidement** aux commentaires
**Argumenter** les choix techniques
**Ne pas prendre personnellement** les critiques
**Remercier** le reviewer
### Approuver une PR
Nécessite **2 approbations** minimum:
- 1 approbation d'un **Tech Lead**
- 1 approbation d'un **Peer**
---
## Bonnes Pratiques
### DRY (Don't Repeat Yourself)
**Mauvais**:
```dart
// Dupliqué dans 5 fichiers
final baseUrl = 'https://api.lions.dev';
```
**Bon**:
```dart
// core/config/environment.dart
class AppConfig {
static String get apiBaseUrl => _apiBaseUrl;
}
```
### KISS (Keep It Simple, Stupid)
**Mauvais** (sur-ingénierie):
```dart
class AbstractFactoryProviderManagerBuilderFactory {
// 500 lignes de code complexe pour un simple getter
}
```
**Bon**:
```dart
class CacheService {
T? get<T>(String key) => _prefs.get(key);
}
```
### YAGNI (You Aren't Gonna Need It)
**Mauvais** (fonctionnalités inutilisées):
```dart
class User {
// 50 champs dont 40 jamais utilisés
}
```
**Bon**:
```dart
class User {
// Seulement les champs nécessaires
final String id;
final String email;
final String name;
}
```
### Const Constructors
**Toujours utiliser `const`** quand possible:
```dart
const Text('Hello')
const SizedBox(height: 16)
const EdgeInsets.all(8)
const Icon(Icons.home)
```
### Null Safety
**Utiliser les opérateurs null-safety**:
```dart
final name = user?.name ?? 'Unknown';
final length = items?.length ?? 0;
final result = await api.call() ?? defaultValue;
```
---
## Questions?
Si vous avez des questions:
1. **Lire la documentation** - README, ARCHITECTURE, cette doc
2. **Chercher dans les issues** - Peut-être déjà répondu
3. **Demander sur Discord** - #unionflow-dev channel
4. **Créer une issue** - Si toujours bloqué
---
## Ressources
- [Flutter Docs](https://docs.flutter.dev/)
- [Dart Style Guide](https://dart.dev/guides/language/effective-dart/style)
- [BLoC Pattern](https://bloclibrary.dev/)
- [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)
---
**Merci de contribuer à UnionFlow Mobile!** 🎉
*Document maintenu par l'équipe UnionFlow Development Team*