# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Instructions générales pour Claude ### Langue de communication - **TOUJOURS répondre en français** sauf si explicitement demandé autrement - Utiliser un langage technique approprié en français ### Méthodologie de travail - **Travailler par étapes** : Ne jamais se lancer directement dans la modification du code - **Présenter et proposer** : Toujours expliquer ce que je compte faire AVANT de le faire - **Demander validation** : Attendre l'accord de l'utilisateur avant de procéder aux modifications - **Structure de réponse** : 1. Analyser la demande 2. Proposer une solution détaillée 3. Lister les fichiers qui seront modifiés 4. Attendre la validation 5. Implémenter les changements ## Build Commands - **Run app**: `flutter run` - start the Flutter app in debug mode - **Build for release**: `flutter build apk` (Android), `flutter build ios` (iOS), `flutter build web` (Web) - **Run tests**: `flutter test` - run all unit tests - **Run specific test**: `flutter test test/widget_test.dart` - run a specific test file - **Analyze code**: `flutter analyze` - check for errors, warnings, and lints - **Format code**: `flutter format lib/` - format all Dart files - **Generate code**: `flutter packages pub run build_runner build` - generate Hive adapters and JSON serialization - **Clean build**: `flutter clean && flutter pub get` - clean and reinstall dependencies - **Update dependencies**: `flutter pub upgrade` - update all packages - **Launcher icons**: `flutter pub run flutter_launcher_icons:main` - generate app icons ## Code Architecture ### Core Architecture Pattern The app follows a **Repository Pattern** with singleton services and reactive UI updates: ``` UI Layer (ValueListenableBuilder) ↓ Repository Layer (Business Logic) ↓ Service Layer (API + Hive Storage) ``` ### Key Architectural Components #### **Singleton Services** (lib/core/services/) - `ApiService` - HTTP client with environment auto-detection (DEV/REC/PROD) - `HiveService` - Local database management with typed Box handling - `CurrentUserService` - User session and authentication state - `CurrentAmicaleService` - Current organization context - `DataLoadingService` - Orchestrates API data synchronization to Hive #### **Repository Pattern** (lib/core/repositories/) - `UserRepository` - User management and authentication - `OperationRepository` - Operations and campaigns - `MembreRepository` - Team member management - `PassageRepository` - Distribution tracking - `SectorRepository` - Geographic sectors - `AmicaleRepository` - Organization management #### **Reactive UI Pattern** Uses `ValueListenableBuilder` with Hive boxes for automatic UI updates: ```dart ValueListenableBuilder>( valueListenable: userRepository.getUsersBox().listenable(), builder: (context, box, child) { // UI automatically updates when data changes }, ) ``` ### Data Flow Architecture #### **"API First" Principle** 1. UI action triggers repository method 2. Repository attempts API call first 3. On success → Save to Hive → UI auto-updates via ValueListenableBuilder 4. On error → Show error message, no local changes #### **Hive Storage Strategy** - **TypeId Management**: Models use specific typeIds (UserModel: 0, OperationModel: 1, etc.) - **Typed Boxes**: Each model has its own strongly-typed Hive box - **Auto-sync**: Data automatically syncs between API and local storage - **Offline-ready**: App functions with cached data when offline - **Box Caching Optimization**: Repositories use cached Box references to prevent repeated access checks ### Error Handling Architecture #### **Centralized Error Management** - `ApiException` class extracts meaningful error messages from API responses - `showError()` and `showSuccess()` methods provide consistent user feedback - Repository methods propagate exceptions to UI layer for handling #### **Error Flow Pattern** ```dart try { final result = await repository.updateUser(user); ApiException.showSuccess(context, "User updated successfully"); } catch (e) { ApiException.showError(context, e); // Handles all error types } ``` #### **Smart Dialog Detection** ApiException automatically detects when called from within a Dialog and adjusts message positioning: - **Normal context**: Uses standard SnackBar - **Dialog context**: Uses overlay SnackBar positioned above the Dialog - **Mobile/Web aware**: Automatically adapts presentation for each platform - **Consistent styling**: Unified colors, icons, and behavior across all contexts ```dart // Same API works everywhere - smart context detection if (validationFails) { ApiException.showError(context, Exception("Validation failed")); return; // Dialog stays open for corrections } // Success handling with auto-close if (success) { Navigator.pop(context); // Close dialog first ApiException.showSuccess(context, "Operation completed"); } ``` ### State Management Strategy #### **No Provider/Bloc** - Direct Reactive Pattern - Uses `ValueListenableBuilder` directly with Hive boxes - Singleton services maintain global state - `ChangeNotifier` only for specific repository loading states #### **Dialog Auto-Management Pattern** Dialogs handle their own submission and closing: ```dart // Dialog manages its own lifecycle void _handleSubmit() async { try { await repository.saveData(data); Navigator.pop(context); // Auto-close on success widget.onSuccess?.call(); // Simple callback } catch (e) { ApiException.showError(context, e); // Error without closing } } ``` ### Multi-Role Permission System #### **Role Hierarchy** - **Role 1** (Membre): Field operations, distribution tracking - **Role 2** (Admin Amicale): Organization management, member administration - **Role 3+** (Super Admin): Global system administration #### **Permission Checks** ```dart final currentUser = CurrentUserService.instance; if (currentUser.canAccessAdmin) { // Show admin features } if (currentUser.isSuperAdmin) { // Show super admin features } ``` ### Code Generation Requirements #### **Hive Adapters** Models require code generation for Hive serialization: ```bash flutter packages pub run build_runner build ``` Run this after modifying any `@HiveType` models in `lib/core/data/models/`. #### **Model Structure** ```dart @HiveType(typeId: X) class MyModel extends HiveObject { @HiveField(0) final int id; @HiveField(1) final String name; } ``` ### Development Workflow #### **Working with Repositories** 1. Always inject repositories via constructor or global instances from `app.dart` 2. Use `try/catch` blocks for all repository calls 3. Show loading states during async operations 4. Handle errors with `ApiException.showError()` 5. Implement Hive box caching to avoid repeated access checks during high-frequency operations #### **Adding New Features** 1. Create/modify models in `lib/core/data/models/` 2. Run `build_runner` to generate Hive adapters 3. Add repository methods in `lib/core/repositories/` 4. Create UI widgets in `lib/presentation/widgets/` 5. Wire up with `ValueListenableBuilder` for reactivity #### **Testing Strategy** - Unit tests for repositories and services - Widget tests for UI components - Integration tests for complete user flows - Use `flutter test` for running tests ### Environment Configuration #### **Auto-Detection** The app automatically detects environment based on URL: - `dapp.geosector.fr` → DEV environment - `rapp.geosector.fr` → REC environment - Production → PROD environment - Non-web platforms → DEV by default #### **API Configuration** Environment-specific API endpoints are configured in `ApiService` automatically. ### Common Patterns to Follow #### **Repository Method Pattern** ```dart Future updateUser(UserModel user) async { try { final response = await ApiService.instance.put('/users/${user.id}', user.toJson()); final updatedUser = UserModel.fromJson(response.data); await _saveUserToHive(updatedUser); return true; } catch (e) { throw ApiException.fromDioException(e); } } ``` #### **Hive Box Caching Pattern** ```dart class MyRepository { // Cache de la box pour éviter les vérifications répétées Box? _cachedBox; // Getter lazy pour n'accéder à la boîte que lorsque nécessaire Box get _myBox { if (_cachedBox == null) { if (!Hive.isBoxOpen(AppKeys.myBoxName)) { throw Exception('La boîte n\'est pas ouverte'); } _cachedBox = Hive.box(AppKeys.myBoxName); } return _cachedBox!; } // Méthode pour réinitialiser le cache après modification void _resetCache() { _cachedBox = null; } // Sauvegarder avec réinitialisation du cache Future saveItem(MyModel item) async { await _myBox.put(item.id, item); _resetCache(); // Crucial pour ValueListenableBuilder notifyListeners(); } } ``` #### **Widget Error Handling** ```dart Future _handleSave() async { try { setState(() => _isLoading = true); await repository.saveData(data); ApiException.showSuccess(context, "Saved successfully"); } catch (e) { ApiException.showError(context, e); } finally { setState(() => _isLoading = false); } } ``` #### **ValueListenableBuilder Usage** ```dart ValueListenableBuilder>( valueListenable: repository.getBox().listenable(), builder: (context, box, child) { final items = box.values.where((item) => filterCondition).toList(); return ListView.builder( itemCount: items.length, itemBuilder: (context, index) => ItemWidget(item: items[index]), ); }, ) ``` ### Hive Box Performance Management #### **Box Caching Strategy** Repositories implement a caching pattern to optimize Hive box access and prevent performance issues during high-frequency operations: **Problems Solved:** - Eliminates repeated `Hive.isBoxOpen()` checks (up to 848 checks per page load) - Improves performance during list rendering and filtering operations - Maintains thread-safe access to Hive boxes **Implementation Pattern:** ```dart class ExampleRepository { // Private cached box reference Box? _cachedBox; // Lazy getter with caching Box get _exampleBox { if (_cachedBox == null) { if (!Hive.isBoxOpen(AppKeys.exampleBoxName)) { throw Exception('Box not open: ${AppKeys.exampleBoxName}'); } _cachedBox = Hive.box(AppKeys.exampleBoxName); debugPrint('Repository: Box ${AppKeys.exampleBoxName} cached'); } return _cachedBox!; } // Cache reset for ValueListenableBuilder notifications void _resetCache() { _cachedBox = null; } } ``` #### **When to Reset Cache** Cache reset is **essential** after any database modification to ensure ValueListenableBuilder and other Hive listeners detect changes: ```dart // REQUIRED: After individual saves Future saveItem(ExampleModel item) async { await _exampleBox.put(item.id, item); _resetCache(); // ← Essential for UI reactivity notifyListeners(); } // REQUIRED: After deletions Future deleteItem(int id) async { await _exampleBox.delete(id); _resetCache(); // ← Essential for UI reactivity notifyListeners(); } // REQUIRED: After bulk operations Future clearAll() async { await _exampleBox.clear(); _resetCache(); // ← Essential for UI reactivity notifyListeners(); } // REQUIRED: After API data processing Future processApiData(List data) async { await _exampleBox.clear(); for (final item in data) { await _exampleBox.put(item.id, ExampleModel.fromJson(item)); } _resetCache(); // ← Essential for UI reactivity notifyListeners(); } ``` #### **Performance Impact** | Scenario | Without Caching | With Caching | |----------|-----------------|--------------| | Loading 848 passages | 848 box checks | 1 box access | | List filtering | Check per item | Cached access | | ValueListenableBuilder | Repeated verification | Optimized access | | Memory usage | Minimal overhead | Negligible cache | #### **Best Practices** 1. **Always cache** in repositories that handle frequently accessed data 2. **Always reset cache** after any modification operation 3. **Use lazy getters** to avoid unnecessary box access 4. **Include debug prints** to monitor caching behavior during development 5. **Apply pattern consistently** across all repositories for maintainability This architecture ensures type safety, reactivity, offline capability, and maintainable code structure across the entire application.