Implementation Plan: Configuration du contexte de travail de Régine
Branch: 003-config-contexte-travail | Date: 2026-09-18 | Spec: spec.md
Input: Feature specification from /specs/003-config-contexte-travail/spec.md
Summary
Le module de configuration établit le contexte de travail dont dépendent tous les autres modules de Régine : trois emplacements (répertoire temporaire, répertoire de travail local, archive NAS/SMB), l'initialisation d'une base de données de travail à la racine du répertoire de travail local (archivée avec chaque dossier), une base de contexte centralisée alimentée à chaque import avec les références de boîtiers rencontrés (permettant de leur attribuer un nom lisible sans réimport ni parcours du NAS), et une assistance au montage natif du partage SMB quand il est indisponible. Approche technique : un module Python (config) dans le paquet regine-core d'un monorepo à quatre parties (bibliothèque centrale regine-core, façades regine-cli, regine-gui, regine-agent), exposé dans un premier temps via regine-cli (cf. Principe CLI-first et Principe VI de la constitution), stockant son état dans SQLite selon les mêmes conventions que le manifeste persistant par dossier déjà retenu (PRAGMA user_version/application_id).
Extension du 2026-09-21 (User Story 4, clarification post-implémentation) : regine-gui (implémentée entre-temps par specs/006-gui-tri-consultation, avec une fenêtre à onglets Tri/Consultation) reçoit un troisième onglet de configuration, appelant directement les fonctions déjà documentées dans contracts/regine-core-api.md (context.charger_contexte/enregistrer_chemins, cameras_screen.lister_boitiers/nommer_boitier). Aucune nouvelle fonction regine-core requise — tout l'API nécessaire existe et est déjà testée ; ce périmètre est une façade pure (Principe VI), au même titre que tri_view.py/consultation_view.py l'ont déjà été pour leurs propres capacités.
Extension du 2026-09-23/24 (User Story 5, révision post-implémentation FR-006/007/014-017) : écart trouvé par l'utilisateur — db.open_context_db() ouvrait un unique fichier ~/.regine/contexte.sqlite3 mélangeant deux choses de nature différente : (a) les trois chemins de travail, propres à la machine, jamais destinés à être partagés ; (b) le savoir accumulé (boîtiers, catégories, historique d'imports specs/001-import-photos), qui doit au contraire survivre à la perte de la machine puisque les photos elles-mêmes survivent sur le NAS. Cette extension sépare les deux : une configuration globale minimale (nouveau fichier ~/.regine/config.sqlite3, uniquement les chemins) reste propre à la machine ; la base de contexte centralisée (boîtiers/catégories/historique, déjà existante mais renommée/déplacée) migre à la racine de local_work_dir — remplaçant au passage le fichier de manifeste vide et jamais exploité que enregistrer_chemins y créait jusqu'ici (écart déjà noté dans contracts/regine-core-api.md : « le verrou/manifeste vit en réalité uniquement côté archive »). Elle est répliquée vers l'archive à chaque regine reconcile, et restaurée automatiquement à la configuration initiale ou au premier regine checkout sur une machine qui ne l'a pas encore localement. Aucun changement pour regine-gui au-delà de la résolution d'environnement partagée avec la CLI (Principe VI) : les écrans existants (config_view.py, import_view.py, consultation_view.py) continuent d'appeler les mêmes fonctions regine_core.config/camera_profile/import_carte.historique, seule la façon dont la connexion SQLite sous-jacente est résolue change.
Technical Context
Language/Version: Python 3.11+ (langage retenu pour la bibliothèque centrale de Régine, cf. docs/interface-cli-gui-architecture.md)
Primary Dependencies: bibliothèque standard uniquement pour ce module (sqlite3, pathlib, shutil, subprocess pour déclencher le montage natif) ; pas de dépendance tierce nouvelle identifiée (cf. research.md)
Storage: SQLite — révisé le 2026-09-23/24 : désormais deux bases distinctes, à des emplacements différents plutôt qu'une base unique à emplacement unique :
- Configuration globale (
~/.regine/config.sqlite3, nouveau nom de fichier — FR-014) : uniquement les trois chemins de travail et l'état SMB connu (tablecontexte, inchangée dans sa forme). Propre à la machine, jamais répliquée. - Base de contexte centralisée (
<local_work_dir>/contexte.sqlite3— FR-006/FR-015, ex-~/.regine/contexte.sqlite3) : boîtiers (tableboitiers, possédée parcamera_profile, cf.specs/002-profil-boitiers-optionnel/plan.md), catégories (specs/004-categorisation-dossiers), historique des imports (tablechecksums_importes, possédée parimport_carte.historique, cf.specs/001-import-photos). Répliquée vers l'archive NAS à un emplacement fixe (FR-016) et restaurable depuis celle-ci (FR-017).
L'ancienne « base de données de travail par dossier » (schéma manifeste fichiers/verrou, une instance par dossier local) est retirée de ce plan : jamais réellement exploitée (écart déjà documenté dans contracts/regine-core-api.md, le verrou/manifeste vivant en réalité uniquement côté archive, specs/005-checkout-reconciliation) — FR-006 révisée ne désigne plus ce schéma.
Testing: pytest ; tests de contrat sur la surface CLI (entrées/sorties texte, codes de sortie), tests d'intégration sur le cycle configuration → initialisation de la base de travail, tests unitaires sur la validation des chemins et la logique de désambiguïsation de boîtiers
Target Platform: Poste de travail de bureau (macOS en priorité pour cette itération ; Windows/Linux non couverts par ce plan, cf. research.md) — l'abstraction de déclenchement du montage SMB isole ce choix pour ne pas bloquer une extension future
Project Type: Monorepo — une bibliothèque centrale (regine-core) et trois façades indépendantes et installables séparément (regine-cli, regine-gui, regine-agent), conformément au Principe VI de la constitution. Ce plan implémente regine-core (module config) et regine-cli ; regine-agent reste réservé. regine-gui a depuis été implémentée par specs/006-gui-tri-consultation (PySide6, fenêtre à onglets) — ce plan (extension du 2026-09-21) y ajoute un onglet de configuration (User Story 4), sans toucher aux onglets Tri/Consultation déjà livrés.
Performance Goals: Pas de cible chiffrée spécifique ; la détection de boîtiers (FR-008/SC-007) doit rester quasi instantanée car elle ne lit que la base de contexte locale, sans parcours réseau par défaut
Constraints: aucune gestion ni stockage d'identifiants réseau par Régine (FR-004, authentification déléguée à l'OS) ; exécution sans démon, un processus par lancement (contrainte technique de la constitution) ; refus (pas de migration silencieuse) du changement de répertoire de travail local tant qu'un travail n'est pas réconcilié/archivé (FR-010)
Scale/Scope: usage mono-utilisateur, mono-poste ; un seul contexte de travail actif par installation (cf. Assumptions de la spec)
Constitution Check
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
| Principe / contrainte | Évaluation | Justification |
|---|---|---|
| I. Fichier maître intouchable | N/A | Ce module ne lit ni ne modifie de fichier maître ; il ne fait que stocker des chemins et des références de boîtiers. |
| II. Confirmation explicite avant toute action à risque | PASS | Aucune écriture sur l'archive n'est effectuée par ce module (FR-003 propose la création de répertoires locaux, non destructif ; FR-010 refuse plutôt que d'exécuter une migration silencieuse). Les actions à risque restent celles des modules import/archive, déjà couvertes par leurs specs respectives. |
| III. Identité par contenu, jamais par nom de fichier seul | N/A | Hors périmètre : ce module ne détecte ni renommage ni doublon de fichier. |
| IV. Métadonnées ouvertes et embarquées | PASS | Le nom lisible d'un boîtier (FR-009) est une convenance locale d'affichage, pas une métadonnée descriptive/de droits au sens du Principe IV (légende, mots-clés, personnes, crédit, copyright, licence) ; l'identité du boîtier reste fondée sur les tags EXIF déjà embarqués par l'appareil (modèle, numéro de série), lesquels restent la source de vérité portable. |
| V. L'utilisateur décide, Régine suggère | PASS | FR-003 (création de répertoire) et FR-012 (parcours NAS) restent des propositions/actions volontaires, jamais automatiques. |
| VI. Bibliothèque centrale, façades minces | PASS | Le monorepo matérialise physiquement la séparation : regine-core porte toute la logique métier (module config), regine-cli et, depuis l'extension du 2026-09-21, regine-gui ne font qu'appeler regine-core et formatter le résultat — le nouvel onglet de configuration n'introduit aucune règle de validation propre à la GUI (FR-013). regine-agent reste réservé. |
| CLI-first | PASS | Toute capacité de ce module est exposée en CLI avant toute GUI. |
| Exécution sans démon | PASS | Chaque commande CLI est un processus isolé ; le déclenchement du montage SMB est une action ponctuelle, pas un service en arrière-plan. |
| Formats ouverts et documentés | PASS | SQLite, déjà retenu par la constitution pour le manifeste persistant, réutilisé ici avec les mêmes conventions (PRAGMA user_version/application_id). |
Aucune violation identifiée ; la section Complexity Tracking reste vide.
Re-check post Phase 1 (après génération de data-model.md, contracts/cli-config.md, quickstart.md) : le modèle de données (deux bases SQLite distinctes, conventions PRAGMA user_version/application_id réutilisées) et le contrat CLI (protocole texte in/out, refus explicite plutôt que migration silencieuse pour FR-010, parcours NAS non exécuté sans --confirm pour FR-012) confirment chaque évaluation PASS ci-dessus. Aucune violation nouvelle introduite par la conception détaillée.
Re-check post User Story 5 (2026-09-23/24) :
| Principe / contrainte | Évaluation | Justification |
|---|---|---|
| II. Confirmation explicite avant toute action à risque | PASS | La réplication (FR-016) et la restauration (FR-017) écrasent chacune une seule cible bien identifiée (la sauvegarde précédente sur l'archive, ou la base locale absente) — jamais un fichier contenant un travail non confirmé ; aucune des deux n'est une action destructive au sens du Principe II. |
| V. L'utilisateur décide, Régine suggère | PASS | FR-016/FR-017 sont déclenchées par des actions déjà explicites de l'utilisateur (regine reconcile, configuration initiale, regine checkout) — aucun nouveau geste caché, aucune sauvegarde/restauration imposée en dehors de ces moments (tranché explicitement par l'utilisateur pendant /speckit-specify, plutôt que l'option automatique-à-chaque-écriture initialement proposée). |
| VI. Bibliothèque centrale, façades minces | PASS | La réplication/restauration est orchestrée par les façades CLI (archive_cmd.py/config_cmd.py) qui appellent une fonction dédiée de regine_core.config.context — regine_core.archive.checkout/reconciliation (specs/005) restent inchangés et ignorants de config (pas de nouvelle dépendance inter-modules dans le cœur), cohérent avec le style d'orchestration déjà utilisé par import_cmd.py (specs/001). |
| Exécution sans démon | PASS | La réplication/restauration est une copie de fichier ponctuelle exécutée dans le même processus que la commande qui la déclenche, jamais un service en arrière-plan. |
Aucune violation nouvelle ; Complexity Tracking reste vide.
Project Structure
Documentation (this feature)
specs/003-config-contexte-travail/
├── plan.md # This file (/speckit-plan command output)
├── research.md # Phase 0 output (/speckit-plan command)
├── data-model.md # Phase 1 output (/speckit-plan command)
├── quickstart.md # Phase 1 output (/speckit-plan command)
├── contracts/ # Phase 1 output (/speckit-plan command)
│ └── cli-config.md
└── tasks.md # Phase 2 output (/speckit-tasks command - NOT created by /speckit-plan)
Source Code (repository root) — monorepo à 4 parties
packages/
├── regine-core/ # Bibliothèque centrale — toute la logique métier
│ ├── pyproject.toml
│ ├── src/
│ │ └── regine_core/
│ │ ├── __init__.py
│ │ └── config/
│ │ ├── __init__.py
│ │ ├── context.py # Contexte de travail : lecture/écriture des 3 chemins, validation
│ │ ├── db.py # Ouverture/initialisation SQLite (base de contexte centralisée + base de travail par dossier)
│ │ ├── smb.py # Détection de disponibilité + déclenchement du montage natif SMB (research.md)
│ │ └── cameras_screen.py # Écran de nommage (User Story 3) : délègue à regine_core.camera_profile (specs/002), ne possède aucune logique de désambiguïsation propre
│ └── tests/
│ ├── contract/ # Contrats internes de regine_core (objets structurés retournés, cf. Principe VI)
│ ├── integration/
│ │ └── test_config_context.py # Cycle configuration → initialisation base de travail → changement de chemin bloqué
│ └── unit/
│ └── test_context_paths.py # Validation/création des répertoires, cas de collision
│ # La désambiguïsation modèle/numéro de série est testée dans specs/002-profil-boitiers-optionnel
│ # (packages/regine-core/tests/unit/test_resolve_collision.py), pas ici.
│
├── regine-cli/ # Façade CLI — dépend de regine-core, aucune logique métier propre
│ ├── pyproject.toml
│ ├── src/
│ │ └── regine_cli/
│ │ ├── __init__.py
│ │ └── config_cmd.py # Sous-commandes `regine config ...` (cf. contracts/cli-config.md)
│ └── tests/
│ └── contract/
│ └── test_cli_config.py # Contrat de la surface CLI (entrées/sorties texte, codes de sortie)
│
├── regine-gui/ # Façade GUI (PySide6) — implémentée par specs/006, étendue ici
│ ├── pyproject.toml
│ └── src/
│ └── regine_gui/
│ ├── app.py # existant (specs/006) — ajoute un 3e onglet "Configuration"
│ ├── tri_view.py # existant (specs/006), inchangé
│ ├── consultation_view.py # existant (specs/006), inchangé
│ └── config_view.py # NOUVEAU (User Story 4) — appelle regine_core.config
│ (context.charger_contexte/enregistrer_chemins,
│ cameras_screen.lister_boitiers/nommer_boitier),
│ aucune logique de validation propre
│
└── regine-agent/ # Façade agent IA — réservée, non implémentée par ce plan
└── (scaffold vide : pyproject.toml déclarant la dépendance à regine-core, aucun code métier)
Structure Decision: Monorepo à quatre parties (Option 1 adaptée du template, multi-packages plutôt que src/ unique), conformément au Principe VI de la constitution (bibliothèque centrale, façades minces) et à la demande explicite d'organiser dès maintenant la place de la GUI et de l'agent IA. regine-core est le premier package de la bibliothèque centrale de Régine (aucun code existant avant ce plan) et pose la convention packages/<nom>/src/<nom_paquet>/ que les modules métier futurs (import, archive, dossier, metadata, integrity, camera_profile de specs/002) réutiliseront à l'intérieur de regine-core. Ce plan implémente regine-core/config (chemins, montage SMB, écran de nommage des boîtiers) et regine-cli ; regine-gui et regine-agent sont créés comme paquets vides (dépendance déclarée vers regine-core, sans code métier) pour réserver la structure, sans être développés ici. Correction du 2026-09-18 : la logique de désambiguïsation et la table boitiers (initialement esquissées ici sous config/cameras.py) sont possédées par le module regine_core.camera_profile, spécifié séparément par specs/002-profil-boitiers-optionnel/plan.md — config ne fait qu'exposer un écran qui délègue à cette API, cohérent avec le Principe VI (une seule bibliothèque centrale, pas de logique dupliquée entre deux specs). L'outillage de workspace (gestion des dépendances inter-paquets, lockfile commun) est tranché en research.md § 5.
Extension du 2026-09-21 (User Story 4) : regine-gui n'est plus un paquet vide — specs/006-gui-tri-consultation l'a implémenté entre-temps (PySide6, FenetrePrincipale à onglets dans app.py). Cette extension y ajoute un troisième onglet (config_view.py), construit à l'identique de tri_view.py/consultation_view.py (une classe QMainWindow/QWidget qui n'appelle que des fonctions déjà publiques de regine_core.config, jamais de logique propre) — aucun nouveau research nécessaire (aucune inconnue technique introduite), aucun nouveau contrat regine-core-api.md (les fonctions appelées sont déjà toutes documentées).
Extension du 2026-09-23/24 (User Story 5) :
packages/
├── regine-core/
│ └── src/regine_core/
│ ├── config/
│ │ ├── db.py # RÉVISÉ : open_context_db(local_work_dir) exige désormais
│ │ │ local_work_dir explicite (plus de défaut ~/.regine/) ;
│ │ │ nouvelle open_global_config_db(path=None), défaut
│ │ │ ~/.regine/config.sqlite3, table `contexte` uniquement
│ │ │ (chemins), jamais boîtiers/catégories/historique
│ │ ├── environnement.py # NOUVEAU — ouvrir_environnement() : résout la config
│ │ │ globale puis, si local_work_dir déjà configuré, ouvre
│ │ │ la base de contexte centralisée à sa racine (FR-014/015) ;
│ │ │ point d'entrée unique remplaçant les appels épars à
│ │ │ open_context_db(None) dans les façades CLI/GUI
│ │ └── context.py # ÉTENDU — sauvegarder_contexte(local_work_dir, archive_root)
│ │ (FR-016) ; restaurer_contexte_si_absent(local_work_dir,
│ │ archive_root) -> bool (FR-017) ; enregistrer_chemins
│ │ n'initialise plus le manifeste vide à la racine de
│ │ local_work_dir (retiré, cf. Technical Context) — ouvre
│ │ désormais la base de contexte centralisée à cet endroit
│ │ via db.open_context_db, l'y initialise si absente
│ └── import_carte/
│ └── historique.py # INCHANGÉ dans son API (specs/001) — la connexion qu'il
│ reçoit vient désormais de ouvrir_environnement(), pas
│ d'un open_context_db(None) implicite
│
├── regine-cli/
│ └── src/regine_cli/
│ ├── config_cmd.py # ÉTENDU — utilise ouvrir_environnement() ; restauration
│ │ automatique (FR-017) appelée après set-paths si le
│ │ contexte local est absent et l'archive en a une copie
│ ├── archive_cmd.py # ÉTENDU — _cmd_reconcile appelle sauvegarder_contexte()
│ │ après un archivage réussi (FR-016) ; _cmd_checkout
│ │ appelle restaurer_contexte_si_absent() après un premier
│ │ checkout réussi (FR-017)
│ └── import_cmd.py # CORRIGÉ — utilisait déjà (par erreur, avant cette
│ révision) local_root / ".regine-contexte.sqlite3" comme
│ contexte_db par défaut plutôt que le mécanisme partagé ;
│ utilise désormais ouvrir_environnement() comme les autres
│ commandes CLI
│
└── regine-gui/
└── src/regine_gui/
└── app.py # ÉTENDU — FenetrePrincipale résout l'environnement une
fois au démarrage (ouvrir_environnement()) et le propage
aux onglets, plutôt que chaque écran ouvrant lui-même
open_context_db(None) indépendamment
Aucun nouveau paquet, aucune nouvelle dépendance externe — uniquement une réorganisation de la résolution de connexion SQLite déjà en place, et deux fonctions ajoutées à regine_core.config.context.
Complexity Tracking
Aucune violation de gate à justifier — section laissée vide intentionnellement.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
|