Files
geo/app/CLAUDE.md
pierre 2f5946a184 feat: Version 3.5.2 - Configuration Stripe et gestion des immeubles
- Configuration complète Stripe pour les 3 environnements (DEV/REC/PROD)
  * DEV: Clés TEST Pierre (mode test)
  * REC: Clés TEST Client (mode test)
  * PROD: Clés LIVE Client (mode live)
- Ajout de la gestion des bases de données immeubles/bâtiments
  * Configuration buildings_database pour DEV/REC/PROD
  * Service BuildingService pour enrichissement des adresses
- Optimisations pages et améliorations ergonomie
- Mises à jour des dépendances Composer
- Nettoyage des fichiers obsolètes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 18:26:27 +01:00

12 KiB
Executable File

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:

ValueListenableBuilder<Box<UserModel>>(
  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

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

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

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:

flutter packages pub run build_runner build

Run this after modifying any @HiveType models in lib/core/data/models/.

Model Structure

@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
  • app3.geosector.fr → 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

Future<bool> 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

class MyRepository {
  // Cache de la box pour éviter les vérifications répétées
  Box<MyModel>? _cachedBox;
  
  // Getter lazy pour n'accéder à la boîte que lorsque nécessaire
  Box<MyModel> get _myBox {
    if (_cachedBox == null) {
      if (!Hive.isBoxOpen(AppKeys.myBoxName)) {
        throw Exception('La boîte n\'est pas ouverte');
      }
      _cachedBox = Hive.box<MyModel>(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<void> saveItem(MyModel item) async {
    await _myBox.put(item.id, item);
    _resetCache(); // Crucial pour ValueListenableBuilder
    notifyListeners();
  }
}

Widget Error Handling

Future<void> _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

ValueListenableBuilder<Box<ModelType>>(
  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:

class ExampleRepository {
  // Private cached box reference
  Box<ExampleModel>? _cachedBox;
  
  // Lazy getter with caching
  Box<ExampleModel> get _exampleBox {
    if (_cachedBox == null) {
      if (!Hive.isBoxOpen(AppKeys.exampleBoxName)) {
        throw Exception('Box not open: ${AppKeys.exampleBoxName}');
      }
      _cachedBox = Hive.box<ExampleModel>(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:

// REQUIRED: After individual saves
Future<void> saveItem(ExampleModel item) async {
  await _exampleBox.put(item.id, item);
  _resetCache(); // ← Essential for UI reactivity
  notifyListeners();
}

// REQUIRED: After deletions
Future<void> deleteItem(int id) async {
  await _exampleBox.delete(id);
  _resetCache(); // ← Essential for UI reactivity
  notifyListeners();
}

// REQUIRED: After bulk operations
Future<void> clearAll() async {
  await _exampleBox.clear();
  _resetCache(); // ← Essential for UI reactivity
  notifyListeners();
}

// REQUIRED: After API data processing
Future<void> processApiData(List<dynamic> 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.