fonzarely/regine-photos-archiverpublic Fork
⑂ main
Commits
⬇ Clone ▾
git clone https://git.rickub.com/fonzarely/regine-photos-archiver.git
git clone ssh://git@rickub.com/fonzarely/regine-photos-archiver.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP
refactor 19cf29c · on main · Fabien Champigny · Sep 24, 2026
plan.md · 195 lines · 21.7 KBmarkdown
Blame HistoryOpen raw

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 :

  1. Configuration globale (~/.regine/config.sqlite3, nouveau nom de fichier — FR-014) : uniquement les trois chemins de travail et l'état SMB connu (table contexte, inchangée dans sa forme). Propre à la machine, jamais répliquée.
  2. Base de contexte centralisée (<local_work_dir>/contexte.sqlite3 — FR-006/FR-015, ex-~/.regine/contexte.sqlite3) : boîtiers (table boitiers, possédée par camera_profile, cf. specs/002-profil-boitiers-optionnel/plan.md), catégories (specs/004-categorisation-dossiers), historique des imports (table checksums_importes, possédée par import_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
# Implementation Plan: Configuration du contexte de travail de Régine

**Branch**: `003-config-contexte-travail` | **Date**: 2026-09-18 | **Spec**: [spec.md](./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 :
1. **Configuration globale** (`~/.regine/config.sqlite3`, nouveau nom de fichier — FR-014) : uniquement les trois chemins de travail et l'état SMB connu (table `contexte`, inchangée dans sa forme). Propre à la machine, jamais répliquée.
2. **Base de contexte centralisée** (`<local_work_dir>/contexte.sqlite3` — FR-006/FR-015, ex-`~/.regine/contexte.sqlite3`) : boîtiers (table `boitiers`, possédée par `camera_profile`, cf. `specs/002-profil-boitiers-optionnel/plan.md`), catégories (`specs/004-categorisation-dossiers`), historique des imports (table `checksums_importes`, possédée par `import_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)

```text
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

```text
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)** :

```text
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.*