E0 - 🗄️ Fondations de persistance¶
← Retour au sommaire story mapping · Épopée transverse socle (S1-S5) (S6-S7) (S8)
Portée : tout le travail base de données (schéma SQLite, DAO, persistance des entités cœur, mécanismes de reprise sur erreur). Cette épopée n'est rattachée à aucun parcours spécifique car elle sert toutes les autres épopées : sans elle, aucune story métier n'est livrable.
Justification du regroupement : la couche de persistance (JDBC + SQLite, cf. Contraintes techniques) est un socle technique transverse. La regrouper comme épopée identifiée la rend visible, arbitrable, et donne un point d'entrée clair pour la partie persistance de l'application.
E0.S1 - Initialiser le schéma SQLite et les DAO génériques¶
En tant que développeur de l'application
Je veux disposer d'un schéma SQLite initialisé au premier lancement et de classes DAO génériques
Afin de poser les fondations techniques sur lesquelles toutes les autres stories vont s'appuyer
Critères d'acceptation :
- Au premier lancement, l'application crée un fichier
companion.dbdans le dossier de travail utilisateur si absent. - Le schéma initial contient toutes les tables vides correspondant aux entités du modèle conceptuel (Utilisateur, Site, Point, Passage, Session d'enregistrement, EnregistrementOriginal, SéquenceDÉcoute, JournalCapteur, RelevéClimatique, SélectionDÉcoute, RésultatsIdentification, Observation, Taxon, GroupeTaxonomique).
- Une classe
DaoGenerique<T>ou équivalent fournit les opérations CRUD de base (create,findById,findAll,update,delete). - La connexion JDBC est gérée avec un pool ou un singleton thread-safe.
- Un test d'intégration crée la BD, exécute une opération CRUD, et vérifie le résultat.
Parcours rattaché : aucun (transverse)
Maquettes cibles : aucune
Dépendances : aucune
E0.S2 - Persister les sites de suivi et points d'écoute¶
En tant que développeur
Je veux des DAO opérationnels pour les entités Site et Point d'écoute
Afin que l'épopée E1 puisse créer, lire, mettre à jour et supprimer des sites et points
Critères d'acceptation :
-
SiteDaopermet de créer un site avec son n° de carré, son nom convivial, son protocole. -
PointEcouteDaopermet d'ajouter, modifier, supprimer des points sur un site existant. - Un site supprimé entraîne la suppression en cascade de ses points (ou refus si des passages y sont rattachés - à arbitrer).
- Les contraintes d'unicité sont vérifiées (n° de carré unique, code de point unique par site).
- Tests d'intégration sur les opérations CRUD.
Parcours rattaché : sert P1
Maquettes cibles : aucune (DAO pur)
Dépendances : E0.S1
E0.S3 - Persister les passages avec leurs statuts d'avancement¶
En tant que développeur
Je veux des DAO opérationnels pour l'entité Passage et ses statuts
Afin que les épopées E2 (Import), E3 (Vérification) et E4 (Dépôt) puissent suivre l'avancement d'une nuit dans le cycle
Critères d'acceptation :
-
PassageDaopermet de créer un passage rattaché à un point d'écoute, une année, un n° de passage. - L'unicité du quadruplet
(carré, année, n° passage, point)est garantie au niveau BD (contrainte unique). - Le statut d'avancement est persisté (
Importé,Transformé,Vérifié,Prêt à déposer,Déposé). - Le verdict de vérification est persisté (
OK,Utilisable,Inexploitable, ou null si non vérifié). - L'association
Enregistreur ↔ Site/Point(mémorisée pour faciliter les imports suivants) est persistée. - Tests d'intégration couvrant la création, la transition de statut et le verdict.
Parcours rattaché : sert P2, P3, P4
Maquettes cibles : aucune (DAO pur)
Dépendances : E0.S1, E0.S2
E0.S4 - Persister les sélections d'écoute et leurs séquences¶
En tant que développeur
Je veux des DAO opérationnels pour les entités Sélection d'écoute et Séquence d'écoute
Afin que l'épopée E3 (Vérification) puisse mémoriser quelles séquences l'utilisateur a échantillonnées et écoutées
Critères d'acceptation :
-
SequenceDEcouteDaopermet de stocker les métadonnées de chaque chunk produit lors de la transformation (nom de fichier, index, durée, fichier source). -
SelectionEcouteDaopermet de stocker une sélection (méthode de constitution, taille, séquences rattachées). - Une séquence peut appartenir à 0..N sélections (table de jointure).
- Le statut « écouté oui/non » par séquence dans le contexte d'une sélection est persisté.
- Tests d'intégration.
Parcours rattaché : sert P3
Maquettes cibles : aucune (DAO pur)
Dépendances : E0.S1, E0.S3
E0.S5 - Persister les observations Tadarida importées¶
En tant que développeur
Je veux des DAO opérationnels pour les entités Résultats d'identification, Observation, Taxon et Groupe taxonomique
Afin que l'épopée E7 (Validation Tadarida) puisse importer un CSV de résultats et le présenter à l'utilisateur pour validation
Critères d'acceptation :
-
ResultatsIdentificationDaopermet de créer un import (chemin du CSV source, format détecté, date d'import) rattaché à un passage. -
ObservationDaopermet d'insérer en masse des observations (volumétrie potentielle : 4000+ par passage), avec leur taxon Tadarida, probabilité, séquence rattachée, statut de validation, taxon observateur, commentaire. -
TaxonDaoetGroupeTaxonomiqueDaopermettent de gérer un référentiel des taxons (peuplé une fois pour toutes ou rafraîchi via un fichier de référence). - Insertion en masse (bulk insert) optimisée pour ne pas freezer l'IHM (cf. O3).
- Tests d'intégration avec un jeu de données représentatif (au moins 1000 observations).
Parcours rattaché : sert P7
Maquettes cibles : aucune (DAO pur)
Dépendances : E0.S1, E0.S3
E0.S6 - Reprendre un import interrompu¶
Non livré (cible)
Il n'y a pas de file d'attente d'import persistée à reprendre au démarrage. La reprise d'un import interrompu est idempotente (re-scan qui saute les fichiers déjà copiés, #231), déclenchée par un relancement manuel : rien n'est notifié à l'ouverture de l'application.
En tant que Marie
Je veux que mon import de nuit, s'il est interrompu (crash, fermeture inopinée, batterie à plat), puisse reprendre là où il s'est arrêté
Afin de ne pas avoir à tout recommencer si quelque chose se passe mal
Critères d'acceptation :
- L'import P2 écrit son état d'avancement en BD (file d'attente persistante : fichiers à copier, fichiers copiés, fichiers transformés).
- Au redémarrage de l'application, si un import était en cours, l'utilisateur est notifié et peut choisir de reprendre, abandonner, ou repartir de zéro.
- Les fichiers déjà copiés ne sont pas recopiés.
- Les fichiers déjà transformés ne sont pas re-transformés.
- Le statut d'avancement du passage reste cohérent (
En coursjusqu'à complétion, puisTransformé). - Test d'intégration simulant une interruption à différents moments du pipeline.
Parcours rattaché : transverse à P2
Maquettes cibles : M-Import (modale d'import doit afficher la reprise éventuelle)
Dépendances : E0.S1, E0.S3, E2 (l'import lui-même)
E0.S7 - Reprendre une validation Tadarida en suspens¶
Partiellement livré
Les observations validées ou corrigées sont bien persistées et relues. En revanche le contexte de validation (dernière observation vue, filtres actifs, mode) vit en mémoire de session (MemoireRevueAudio), pas en BD : il n'est pas restauré par passage ni au redémarrage. Les vues de filtres sauvegardées (#623) sont l'exception réellement persistée.
Je veux que ma session de validation Tadarida (P7), si je la quitte avant la fin, puisse être reprise plus tard exactement là où je l'avais laissée
Afin de pouvoir étaler la validation sur plusieurs jours sans rien perdre
Critères d'acceptation :
- Le contexte de validation est persisté en BD : dernière observation vue, filtres actifs (taxon, groupe, seuil de probabilité, plage horaire), mode de validation choisi (inventaire/activité).
✅ Vérifié le 2026-08-05, aucune dérive :
MemoireFiltresse déclare mémoire de session (singleton Guice, #484 généralisé en #3098). Les filtres survivent à un changement d'écran, pas à un redémarrage. La case est donc légitimement décochée, et E7 l'énonce déjà. - Au retour sur l'écran de validation pour le même passage, le contexte est restauré automatiquement.
- Les observations déjà validées ou corrigées sont persistées et conservent leur statut.
- Test d'intégration : validation partielle, fermeture, réouverture, vérification de la restauration.
Parcours rattaché : transverse à P7
Maquettes cibles : M-SonsValidation (la vue de validation doit indiquer si une session est restaurée)
Dépendances : E0.S1, E0.S5, E7 (la validation elle-même)
E0.S8 - Versionner et migrer le schéma de BD¶
En tant que mainteneur de l'application
Je veux un mécanisme de versionning du schéma SQLite et de migration entre versions
Afin de pouvoir faire évoluer le schéma sans casser les BDs existantes des utilisateurs
Critères d'acceptation :
- Une table
schema_versionmémorise la version courante du schéma. - Au démarrage, l'application compare la version code avec la version BD et applique les scripts de migration nécessaires.
- Les scripts de migration sont versionnés dans les sources (ex.
db/migrations/V01__init.sql,V02__add_observations.sql). - Une migration ratée laisse la BD dans son état initial (rollback) et bloque l'application avec un message clair : script et version sont écrits dans la même transaction, et le message nomme le fichier et le rang de l'instruction (#2728).
- Un script publié ne se modifie plus : son empreinte est inscrite avec sa version, et une dérive est un refus au démarrage, pas une divergence silencieuse entre les bases (#2729, ADR 2729).
- Avant la première migration en attente, la base est mise à l'abri dans
sauvegardes/: l'atomicité protège d'une panne, le filet protège aussi d'une migration qui réussit en faisant autre chose que prévu (#2729). - Test d'intégration : créer une BD en V01, lancer l'application qui fait passer en V02, vérifier la cohérence.
Parcours rattaché : transverse (technique pur)
Maquettes cibles : aucune
Dépendances : E0.S1
E0.S9 - Réglages persistés et fonctionnalités désactivables¶
En tant que Samuel
Je veux régler l'application et couper les fonctionnalités dont je n'ai pas besoin
Afin d' adapter l'outil à mon poste et à mon volume
Critères d'acceptation :
- Un écran de réglages présente des onglets auto-découverts (Général, Fonctionnalités, Emplacements, Dépôt, Import, Audio).
- Les réglages typés (booléen / texte / entier) sont persistés dans une table clé/valeur ; une valeur absente ou illisible retombe sur son défaut sans planter ; les énums sont sérialisés par valeur stable (jamais par
name()). - Des fonctionnalités optionnelles ou expérimentales peuvent être désactivées ; une fonctionnalité « cœur » reste toujours active.
- La précédence est explicite : propriété système > alias de désactivation > flag persisté > défaut de la catégorie.
Parcours rattaché : transverse (tous parcours)
Maquettes cibles : écran de réglages non maquetté (cf. #2382)
Dépendances : E0.S1
E0.S10 - Sauvegarder et restaurer la base et l'audio¶
En tant que Samuel
Je veux sauvegarder mon travail et pouvoir le restaurer
Afin de ne pas tout perdre en cas de panne disque ou de fausse manipulation
Critères d'acceptation :
- Sauvegarde « base seule » : instantané cohérent horodaté, même base ouverte (
VACUUM INTO). - Restauration : vérifie la lisibilité, met de côté la base courante (filet), remplace, purge les journaux, et rejoue la migration pour être à jour.
- Sauvegarde / restauration « complète » : base + audio, en disant ce qui n'a pas pu être copié.
- L'emplacement de destination est choisi par l'utilisateur.
- Une sauvegarde complète sait d'où venaient les dossiers de son : deux nuits de même nom sur deux disques ne se confondent plus, et la sauvegarde porte un manifeste (#2726).
- Une restauration complète remet les dossiers là où ils étaient et corrige la base pour les y retrouver ; sur une autre machine, ils reviennent dans le dossier de travail et la base suit. Elle vérifie avant de toucher à quoi que ce soit, et dit ce qui a changé de place (#2727, ADR 2727).
- Une restauration qui échoue en route rend la base d'avant, et une sauvegarde écrite par une version plus récente est refusée sans que rien ne soit touché (#2730).
- Un seul processus écrit dans un dossier de travail : une seconde fenêtre est refusée en nommant l'occupante, et une restauration ne peut pas se lancer pendant qu'un autre processus travaille. Sans cela, toutes les garanties ci-dessus tombent (#2731, ADR 2731).
Parcours rattaché : transverse (tous parcours)
Maquettes cibles : actions de menu non maquettées (cf. #2382)
Dépendances : E0.S1
E0.S11 - Auditer la cohérence et réinitialiser proprement¶
En tant que Samuel
Je veux vérifier que ma base et mes fichiers sont cohérents, et repartir proprement si besoin
Afin de garder une base saine sur la durée
Critères d'acceptation :
- Un audit en lecture seule vérifie, par passage, la présence disque, le préfixe attendu et la cohérence des unités déposées, plus un balayage inverse des orphelins ; en ligne, il confronte le dépôt au serveur et se dégrade proprement hors connexion.
- L'audit confronte aussi les dérivations d'une même donnée quand elles peuvent se contredire : le département d'un point, lu par son carré (R1) et par sa commune (C3). Le carroyage national ignorant les limites administratives (R26), l'écart est souvent légitime : le constat le montre sans le juger, en information, et ne fait donc jamais échouer l'audit.
- Un bilan de récupérabilité classe chaque nuit Disque → Serveur → Perdu (un dépôt ZIP est « perdu » côté serveur) en lisant le mode de dépôt réel, jamais présumé.
- Le reset guidé est ordonné : dire ce qu'on perdrait + acceptation, exiger que la plateforme réponde avant de détruire, sauvegarder, base neuve, repeupler depuis le serveur, audit final.
- Une nuit « perdue » reste navigable en passage archivé, réactivable plus tard (E4.S6).
Parcours rattaché : transverse (maintenance)
Maquettes cibles : écran d'audit non maquetté (cf. #2382)
Dépendances : E0.S1, E9.S5