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