# 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<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**
```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
- `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**
```dart
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**
```dart
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**
```dart
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**
```dart
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:**
```dart
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:

```dart
// 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.