Files
unionflow-mobile-apps/CONTRIBUTING.md
dahoud 5c5ec3ad00 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>
2026-03-16 05:15:38 +00:00

13 KiB

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
  2. Comment Contribuer
  3. Setup Environnement
  4. Standards de Code
  5. Architecture
  6. Workflow Git
  7. Tests
  8. Pull Requests
  9. Code Review
  10. 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

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

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.

# 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

 class DashboardBloc {}
 class dashboardBloc {}
 class Dashboard_Bloc {}

Variables/Fonctions: camelCase

 final userName = 'John';
 void getUserData() {}
 final user_name = 'John';
 void get_user_data() {}

Constantes: lowerCamelCase (pas SCREAMING_CASE en Dart)

 static const baseUrl = 'https://api.lions.dev';
 static const BASE_URL = 'https://api.lions.dev';

Private members: préfixe _

 String _privateVariable;
 void _privateMethod() {}

Documentation

Classes publiques:

/// 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:

/// 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:

// 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:

feature/<issue-number>-<short-description>

Exemples:

feature/123-add-biometric-login
feature/456-fix-dashboard-crash
feature/789-improve-cache-performance

Workflow

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

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:

// 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:

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

# 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

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

// Dupliqué dans 5 fichiers
final baseUrl = 'https://api.lions.dev';

Bon:

// core/config/environment.dart
class AppConfig {
  static String get apiBaseUrl => _apiBaseUrl;
}

KISS (Keep It Simple, Stupid)

Mauvais (sur-ingénierie):

class AbstractFactoryProviderManagerBuilderFactory {
  // 500 lignes de code complexe pour un simple getter
}

Bon:

class CacheService {
  T? get<T>(String key) => _prefs.get(key);
}

YAGNI (You Aren't Gonna Need It)

Mauvais (fonctionnalités inutilisées):

class User {
  // 50 champs dont 40 jamais utilisés
}

Bon:

class User {
  // Seulement les champs nécessaires
  final String id;
  final String email;
  final String name;
}

Const Constructors

Toujours utiliser const quand possible:

const Text('Hello')
const SizedBox(height: 16)
const EdgeInsets.all(8)
const Icon(Icons.home)

Null Safety

Utiliser les opérateurs null-safety:

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


Merci de contribuer à UnionFlow Mobile! 🎉

Document maintenu par l'équipe UnionFlow Development Team