Files
geo/docs/gestion_hive_boxes.md
d6soft 511be5a535 Fix: Hive sync et update entité via API REST
- Correction mapping JSON membres (fk_role, chk_active)
- Ajout traitement amicale au login
- Fix callback onSubmit pour sync Hive après update API
2025-06-09 18:46:49 +02:00

12 KiB

Guide de Gestion des Boîtes Hive dans GeoSector

Ce document explique comment les boîtes Hive sont gérées dans l'application GeoSector, particulièrement pendant les processus de connexion et déconnexion.

Table des matières

  1. Introduction
  2. Boîtes Hive utilisées
  3. Initialisation des boîtes Hive
  4. Services et repositories impliqués
  5. Processus de connexion (login)
  6. Processus de déconnexion (logout)
  7. Problèmes connus et solutions
  8. Bonnes pratiques

Introduction

Hive est une base de données NoSQL légère et rapide utilisée dans GeoSector pour stocker les données localement. Les données sont organisées en "boîtes" (boxes) qui peuvent être typées pour stocker des modèles spécifiques.

Dans cette application, Hive est utilisé pour :

  • Stocker les données utilisateur et maintenir les sessions
  • Conserver les données des opérations, secteurs et passages
  • Permettre l'utilisation de l'application en mode hors ligne

Boîtes Hive utilisées

Les boîtes Hive sont définies dans lib/core/constants/app_keys.dart :

// Noms des boîtes Hive
static const String usersBoxName = 'users';
static const String operationsBoxName = 'operations';
static const String sectorsBoxName = 'sectors';
static const String passagesBoxName = 'passages';
static const String settingsBoxName = 'settings';

Chaque boîte stocke un type spécifique de données :

  • users : Stocke les informations des utilisateurs (UserModel)
  • operations : Stocke les opérations (OperationModel)
  • sectors : Stocke les secteurs (SectorModel)
  • passages : Stocke les passages (PassageModel)
  • settings : Stocke les préférences utilisateur (non typée)

Initialisation des boîtes Hive

Actuellement, les boîtes Hive sont initialisées dès le démarrage de l'application dans main.dart :

// Initialiser Hive
await Hive.initFlutter();

// Enregistrer les adaptateurs Hive
Hive.registerAdapter(UserModelAdapter());
Hive.registerAdapter(OperationModelAdapter());
Hive.registerAdapter(SectorModelAdapter());
Hive.registerAdapter(PassageModelAdapter());

// Ouvrir les boîtes Hive
await Hive.openBox<UserModel>(AppKeys.userBoxName);
await Hive.openBox<OperationModel>(AppKeys.operationsBoxName);
await Hive.openBox<SectorModel>(AppKeys.sectorsBoxName);
await Hive.openBox<PassageModel>(AppKeys.passagesBoxName);
await Hive.openBox(AppKeys.settingsBoxName);

Problème d'initialisation précoce

Cette approche ouvre toutes les boîtes Hive dès le démarrage de l'application, même sur les pages publiques comme LandingPage où elles ne sont pas nécessaires. Cela explique pourquoi vous voyez les messages suivants dans la console :

Got object store box in database users.
Got object store box in database operations.
Got object store box in database sectors.
Got object store box in database passages.
Got object store box in database settings.

Solution recommandée

Pour optimiser l'initialisation des boîtes Hive, il est recommandé de :

  1. N'initialiser que la boîte users au démarrage (pour vérifier si un utilisateur est déjà connecté)
  2. Initialiser les autres boîtes uniquement après une connexion réussie

Modification suggérée pour main.dart :

// Initialiser Hive
await Hive.initFlutter();

// Enregistrer les adaptateurs Hive
Hive.registerAdapter(UserModelAdapter());
Hive.registerAdapter(OperationModelAdapter());
Hive.registerAdapter(SectorModelAdapter());
Hive.registerAdapter(PassageModelAdapter());

// N'ouvrir que la boîte des utilisateurs au démarrage
await Hive.openBox<UserModel>(AppKeys.userBoxName);
await Hive.openBox(AppKeys.settingsBoxName); // Préférences générales

// Les autres boîtes seront ouvertes après connexion dans UserRepository.login()

Services et repositories impliqués

UserRepository

Le UserRepository est le principal gestionnaire des boîtes Hive et de l'authentification. Il est responsable de :

  • L'initialisation des boîtes au démarrage de l'application
  • La gestion des boîtes pendant les processus de connexion et déconnexion
  • Le nettoyage et la recréation des boîtes lorsque nécessaire
  • La gestion complète de l'authentification (connexion et déconnexion)
  • L'affichage des overlays de chargement pendant les opérations d'authentification
  • La redirection vers les pages appropriées après connexion/déconnexion

Note importante : Auparavant, l'application utilisait un service séparé AuthService pour gérer l'authentification. Cette classe a été supprimée et ses fonctionnalités ont été intégrées directement dans UserRepository pour simplifier l'architecture et éviter les problèmes de synchronisation entre les deux classes.

Autres repositories spécialisés

  • OperationRepository : Gère la boîte operations
  • SectorRepository : Gère la boîte sectors
  • PassageRepository : Gère la boîte passages

Ces repositories sont injectés dans le UserRepository pour traiter les données spécifiques à chaque modèle.

Processus de connexion (login)

Le processus de connexion dans UserRepository.login() suit ces étapes :

  1. Nettoyage initial :

    • Suppression des boîtes non référencées (auth, locations, messages)
    • Nettoyage adapté à la plateforme (Web, iOS, Android)
  2. Préparation des boîtes :

    • Appel à _clearAndRecreateBoxes() pour vider et recréer les boîtes sans les fermer
    • Utilisation de _ensureBoxIsOpen() pour garantir que les boîtes sont ouvertes
  3. Appel API et traitement des données :

    • Connexion via l'API
    • Vérification que toutes les boîtes sont ouvertes avant le traitement
    • Traitement des données reçues (opérations, secteurs, passages)
  4. Gestion des erreurs :

    • Tentatives de récupération en cas d'erreur
    • Réouverture des boîtes si nécessaire

Code clé pour la connexion

// S'assurer que les boîtes sont ouvertes
await _ensureBoxIsOpen(AppKeys.operationsBoxName);
await _ensureBoxIsOpen(AppKeys.sectorsBoxName);
await _ensureBoxIsOpen(AppKeys.passagesBoxName);

// Traiter les données
await _processOperations(operationsData);
await _processSectors(sectorsData);
await _processPassages(passagesData);

Processus de déconnexion (logout)

Le processus de déconnexion dans UserRepository.logout() suit ces étapes :

  1. Préparation :

    • Récupération de l'utilisateur actuel avant nettoyage
    • Déconnexion de la session API
    • Réinitialisation du cache de l'utilisateur actuel
  2. Nettoyage des données :

    • Appel à _deepCleanHiveBoxes() pour un nettoyage complet des boîtes Hive

Méthode _deepCleanHiveBoxes

La méthode _deepCleanHiveBoxes() est cruciale pour le processus de déconnexion et suit ces étapes :

  1. Vidage des boîtes :

    • Vidage de toutes les boîtes Hive ouvertes sans les fermer
    • Gestion des erreurs pour chaque boîte avec typage spécifique
  2. Nettoyage spécifique à la plateforme :

    • Nettoyage adapté selon la plateforme (Web, iOS, Android)
    • Utilisation de méthodes spécifiques comme _clearIndexedDB() pour le web
  3. Réinitialisation :

    • Réinitialisation de l'API Service

Code clé pour la déconnexion

// Méthode logout
Future<bool> logout() async {
  try {
    // Récupérer l'utilisateur actuel avant de nettoyer les données
    final currentUser = getCurrentUser();

    // Déconnecter la session API
    if (currentUser?.sessionId != null) {
      await logoutAPI();
    }

    // Supprimer la session API
    setSessionId(null);

    // Réinitialiser le cache de l'utilisateur actuel
    _cachedCurrentUser = null;

    // Nettoyage complet des boîtes Hive
    await _deepCleanHiveBoxes();

    return true;
  } catch (e) {
    return false;
  }
}

// Méthode de nettoyage des boîtes Hive
Future<void> _deepCleanHiveBoxes() async {
  try {
    // 1. Vider toutes les boîtes sans les fermer
    if (Hive.isBoxOpen(AppKeys.userBoxName)) {
      await Hive.box<UserModel>(AppKeys.userBoxName).clear();
    }

    if (Hive.isBoxOpen(AppKeys.operationsBoxName)) {
      await Hive.box<OperationModel>(AppKeys.operationsBoxName).clear();
    }

    if (Hive.isBoxOpen(AppKeys.sectorsBoxName)) {
      await Hive.box<SectorModel>(AppKeys.sectorsBoxName).clear();
    }

    // Vider les autres boîtes...

    // 2. Nettoyage spécifique à la plateforme
    if (kIsWeb) {
      await _clearIndexedDB();
    } else if (Platform.isIOS) {
      await _cleanHiveFilesOnIOS();
    } else if (Platform.isAndroid) {
      await _cleanHiveFilesOnAndroid();
    }

    // 3. Réinitialiser l'API Service
    _apiService.setSessionId(null);
  } catch (e) {
    debugPrint('Erreur lors du nettoyage des boîtes Hive: $e');
  }
}

Problèmes connus et solutions

1. Initialisation précoce des boîtes Hive

Problème : Toutes les boîtes Hive sont ouvertes dès le démarrage de l'application, même sur les pages publiques où elles ne sont pas nécessaires.

Solution : Modifier main.dart pour n'ouvrir que les boîtes essentielles au démarrage (users et settings) et initialiser les autres boîtes uniquement après connexion.

2. Erreur "Box has already been closed"

Problème : Des erreurs se produisent lorsqu'on tente d'accéder à une boîte qui a été fermée prématurément.

Solution :

  • Utiliser la méthode _ensureBoxIsOpen() avant d'accéder à une boîte
  • Éviter de fermer les boîtes qui pourraient être utilisées plus tard
  • Préférer box.clear() à box.close() pour vider les données sans fermer la boîte

3. Persistance indésirable des données entre sessions

Problème : Les données peuvent persister entre les sessions utilisateur, créant des conflits ou des fuites de données.

Solution : Utiliser _clearAndRecreateBoxes() lors de la déconnexion pour vider correctement toutes les boîtes sauf users.

Bonnes pratiques

Initialisation à la demande

  1. Initialiser les boîtes uniquement lorsqu'elles sont nécessaires :

    • N'ouvrir que les boîtes users et settings au démarrage
    • Initialiser les autres boîtes après connexion réussie
    • Utiliser _ensureBoxIsOpen() avant chaque accès à une boîte
  2. Centraliser la gestion des boîtes :

    • Créer un service dédié à la gestion des boîtes Hive
    • Utiliser des méthodes comme openRequiredBoxes() et clearAllBoxes()
  3. Optimiser pour les différentes plateformes :

    • Adapter le nettoyage selon la plateforme (Web, iOS, Android)
    • Utiliser des méthodes spécifiques comme _clearIndexedDB() pour le web

Éviter l'erreur "Box has already been closed"

  1. Ne jamais fermer une boîte qui pourrait être utilisée plus tard :

    • Utiliser _ensureBoxIsOpen() au lieu de fermer et rouvrir les boîtes
    • Vider les boîtes avec box.clear() au lieu de les fermer
  2. Vérifier qu'une boîte est ouverte avant de l'utiliser :

    if (!Hive.isBoxOpen(boxName)) {
      await Hive.openBox<T>(boxName);
    }
    
  3. Gestion des erreurs robuste :

    • Toujours entourer les opérations Hive de blocs try/catch
    • Prévoir des mécanismes de récupération en cas d'erreur

Méthode utilitaire _ensureBoxIsOpen

Cette méthode est cruciale pour garantir qu'une boîte est ouverte avant de l'utiliser :

Future<void> _ensureBoxIsOpen(String boxName) async {
  try {
    if (!Hive.isBoxOpen(boxName)) {
      debugPrint('Ouverture de la boîte $boxName...');
      if (boxName == AppKeys.passagesBoxName) {
        await Hive.openBox<PassageModel>(boxName);
      } else if (boxName == AppKeys.operationsBoxName) {
        await Hive.openBox<OperationModel>(boxName);
      } else if (boxName == AppKeys.sectorsBoxName) {
        await Hive.openBox<SectorModel>(boxName);
      } else if (boxName == AppKeys.userBoxName) {
        await Hive.openBox<UserModel>(boxName);
      } else {
        await Hive.openBox(boxName);
      }
      debugPrint('Boîte $boxName ouverte avec succès');
    }
  } catch (e) {
    debugPrint('Erreur lors de l\'ouverture de la boîte $boxName: $e');
    throw Exception('Impossible d\'ouvrir la boîte $boxName: $e');
  }
}

Ce guide devrait aider à comprendre et maintenir la gestion des boîtes Hive dans l'application GeoSector. Pour toute question ou problème, consultez la documentation de Hive ou contactez l'équipe de développement.