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
specs 6ad5e0a · on main · Fabien Champigny · Sep 19, 2026
plan.md · 105 lines · 10.3 KBmarkdown
Blame HistoryOpen raw

Implementation Plan: Importation de photos depuis une carte mémoire

Branch: 001-import-photos | Date: 2026-09-18 | Spec: spec.md

Input: Feature specification from /specs/001-import-photos/spec.md

Summary

Pipeline complet depuis une carte mémoire jusqu'au premier archivage : copie vérifiée par somme de contrôle (une seule lecture de la carte), analyse des dates de prise de vue et découpage en groupes, choix de destination (dossier simple / sous-dossier / fusion / nouveau dossier parent, plus la catégorisation racine de specs/004-categorisation-dossiers), renommage synchronisé des fichiers maîtres et associés, désambiguïsation de boîtiers en cas de collision (specs/002-profil-boitiers-optionnel), attribution d'un identifiant pérenne, puis confirmation explicite et transfert vers l'archive. Approche technique : un nouveau module regine_core.import_carte, premier consommateur réel de regine_core.dossier.root (specs/004), regine_core.camera_profile (specs/002) et regine_core.metadata.exif, exposé via une première commande CLI concrète regine import dans regine-cli.

Technical Context

Language/Version: Python 3.11+ (cohérent avec regine-core, cf. specs/002, specs/003, specs/004)

Primary Dependencies: exiftool (déjà une dépendance actée par specs/002-profil-boitiers-optionnel pour regine_core.metadata.exif, étendu ici pour la lecture de la date de prise de vue et l'écriture de l'identifiant pérenne) ; bibliothèque standard uniquement sinon (hashlib pour les sommes de contrôle, pathlib/shutil pour la copie et le renommage, difflib pour la recherche de dossiers candidats par titre proche, réutilisant la même approche que specs/004-categorisation-dossiers)

Storage: ce module n'introduit aucune nouvelle base ; il consomme la base de contexte centralisée via regine_core.camera_profile (specs/002) et regine_core.config.categories/regine_core.dossier.root (specs/004). Le manifeste persistant par dossier (checksums, réconciliation) est désormais spécifié et planifié par specs/005-checkout-reconciliation (regine_core.archive/regine_core.integrity) ; ce module l'utilise pour FR-009 sans le redéfinir

Testing: pytest ; tests unitaires sur le découpage jour par jour et la détection de dates aberrantes, sur le renommage synchronisé, sur la construction du chemin final (délégué à specs/004) ; tests d'intégration sur le pipeline complet copie→analyse→destination→renommage→confirmation, en répertoires temporaires simulant carte/local/archive (aucune écriture réseau réelle)

Target Platform: poste de travail de bureau, identique aux autres modules de regine-core

Project Type: Monorepo existant (specs/002, specs/003, specs/004) — nouveau module regine_core/import_carte/ et première commande CLI concrète (regine import) dans regine-cli

Performance Goals: aucune lecture de la carte mémoire ne doit dépasser une seule passe par fichier (FR-001/Edge Case déjà tranché) ; pas d'autre cible chiffrée spécifique

Constraints: le sous-scénario de fusion vers un dossier déjà archivé sur le NAS (FR-009, Acceptance Scenario 4 de User Story 3) appelle regine_core.archive.checkout.checkout (specs/005-checkout-reconciliation) sur le dossier ciblé avant d'y intégrer les nouveaux fichiers ; ce plan consomme cette API sans la redéfinir

Scale/Scope: import typique de quelques dizaines à quelques milliers de fichiers par carte mémoire, usage mono-utilisateur

Constitution Check

GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.

Principe / contrainte Évaluation Justification
I. Fichier maître intouchable PASS Un fichier maître n'est renommé qu'une seule fois, avant son premier archivage (FR-013) ; aucune modification après archivage n'est effectuée par ce module (la vérification d'anomalie ultérieure relève de specs/005-checkout-reconciliation, qui l'implémente désormais).
II. Confirmation explicite avant toute action à risque PASS FR-018 : résumé complet (fichiers, taille, dossier de destination, répertoire racine) présenté et confirmé avant toute écriture sur l'archive ; FR-012 : collision de nom traitée par suffixe ou confirmation, jamais écrasement silencieux.
III. Identité par contenu, jamais par nom de fichier seul PASS FR-004 : seuls les fichiers réellement nouveaux (par somme de contrôle) entrent dans l'analyse ; FR-015 : désambiguïsation de boîtiers déléguée à specs/002, elle-même fondée sur les métadonnées, jamais sur le seul nom de fichier.
IV. Métadonnées ouvertes et embarquées PASS FR-017 : l'identifiant pérenne est écrit dans les métadonnées XMP embarquées du fichier (réutilisation du champ standard xmpMM:DocumentID, cf. research.md § 3), pas dans une base séparée.
V. L'utilisateur décide, Régine suggère PASS FR-006 (candidat de détachement suggéré, jamais imposé), FR-011 (lieu GPS suggéré, jamais imposé), FR-007 (catégorie/année toujours une décision explicite, délégué à specs/004).
VI. Bibliothèque centrale, façades minces PASS Toute la logique vit dans regine_core.import_carte, qui consomme regine_core.dossier, regine_core.camera_profile et regine_core.metadata sans dupliquer leur logique ; regine-cli n'orchestre que l'appel et l'affichage.
CLI-first PASS regine import est la première façade construite pour ce pipeline, avant toute GUI.
Exécution sans démon PASS Le pipeline s'exécute intégralement dans le processus de la commande CLI, sans état en arrière-plan.
Formats ouverts et documentés PASS XMP pour l'identifiant pérenne ; aucune base propriétaire introduite.
Vérification d'intégrité systématique PASS FR-001 : vérification par somme de contrôle sur toute copie carte→local et sur le transfert local→archive (FR-019).

Aucune violation identifiée ; la section Complexity Tracking reste vide.

Complexity Tracking

Aucune violation de gate à justifier — section laissée vide intentionnellement.

Re-check post Phase 1 (après génération de data-model.md, contracts/, quickstart.md) : le modèle de données (Groupe d'import, Destination, Renommage) et les contrats (CLI regine import, API interne regine_core.import_carte) confirment chaque évaluation ci-dessus. Le sous-scénario FR-009 est désormais implémentable via specs/005-checkout-reconciliation (cf. contracts/cli-import.md et quickstart.md, mis à jour en conséquence) — plus aucune dépendance manquante.

Project Structure

Documentation (this feature)

specs/001-import-photos/
├── 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-import.md
│   └── regine-core-api.md
└── tasks.md             # Phase 2 output (/speckit-tasks command - NOT created by /speckit-plan)

Source Code (repository root) — extension du monorepo posé par specs/002/003/004

packages/regine-core/
├── src/regine_core/
│   ├── metadata/
│   │   └── exif.py                    # (existant, specs/002) étendu : read_capture_date(), write_document_id()
│   └── import_carte/                  # NOUVEAU module
│       ├── __init__.py
│       ├── copie.py                   # copie vérifiée carte→local, une seule lecture (FR-001), filtrage nouveaux fichiers (FR-004)
│       ├── groupage.py                # répartition jour par jour, détection dates aberrantes, découpage en groupes (FR-002/003/005/006)
│       ├── destination.py             # orchestration destination : simple/sous-dossier/fusion/parent + catégorie (FR-007/008/009), délègue à regine_core.dossier.root et, pour une fusion vers un dossier déjà archivé, à regine_core.archive.checkout (specs/005)
│       ├── nommage.py                 # construction titre/nom dossier, collision (FR-010/012), renommage synchronisé (FR-013/014)
│       ├── identifiant.py             # génération + écriture identifiant pérenne (FR-017)
│       └── push.py                    # résumé + confirmation + transfert final (FR-018/019)
│
└── tests/
    ├── unit/
    │   ├── test_copie_checksum.py     # une seule lecture carte, échec de vérification, carte lente
    │   ├── test_groupage_dates.py     # découpage par défaut, détachement, dates aberrantes, fichiers déjà vus
    │   ├── test_nommage.py            # formats de nom, collision, renommage synchronisé fichiers associés
    │   └── test_identifiant.py        # génération, écriture XMP DocumentID
    └── integration/
        ├── test_pipeline_import_simple.py    # US1 : carte → dossier archivé, résumé confirmé
        ├── test_pipeline_multi_jours.py      # US2 : détachement, groupes multiples
        └── test_pipeline_voyage.py           # US3 : dossier parent + sous-dossier + fusion locale ET fusion vers dossier archivé (via specs/005-checkout-reconciliation) + désambiguïsation boîtiers

packages/regine-cli/
└── src/regine_cli/
    └── import_cmd.py                  # NOUVEAU : commande `regine import <carte>`, premier point d'intégration réel (dossier.root, camera_profile, metadata.exif)

Structure Decision: Extension du monorepo existant — nouveau module regine_core/import_carte/ (aucun code existant avant ce plan pour ce module), et première commande CLI concrète du projet (regine import), qui devient le point d'intégration réel des API déjà contractées par specs/002-profil-boitiers-optionnel et specs/004-categorisation-dossiers (jusqu'ici documentées mais non consommées). regine_core/metadata/exif.py (créé par specs/002) est étendu plutôt que dupliqué. Mise à jour du 2026-09-19 : le sous-scénario FR-009 (fusion vers un dossier déjà archivé) consomme désormais regine_core.archive.checkout (specs/005-checkout-reconciliation, planifiée) au lieu d'être documenté comme bloqué.

  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
# Implementation Plan: Importation de photos depuis une carte mémoire

**Branch**: `001-import-photos` | **Date**: 2026-09-18 | **Spec**: [spec.md](./spec.md)

**Input**: Feature specification from `/specs/001-import-photos/spec.md`

## Summary

Pipeline complet depuis une carte mémoire jusqu'au premier archivage : copie vérifiée par somme de contrôle (une seule lecture de la carte), analyse des dates de prise de vue et découpage en groupes, choix de destination (dossier simple / sous-dossier / fusion / nouveau dossier parent, plus la catégorisation racine de `specs/004-categorisation-dossiers`), renommage synchronisé des fichiers maîtres et associés, désambiguïsation de boîtiers en cas de collision (`specs/002-profil-boitiers-optionnel`), attribution d'un identifiant pérenne, puis confirmation explicite et transfert vers l'archive. Approche technique : un nouveau module `regine_core.import_carte`, premier consommateur réel de `regine_core.dossier.root` (specs/004), `regine_core.camera_profile` (specs/002) et `regine_core.metadata.exif`, exposé via une première commande CLI concrète `regine import` dans `regine-cli`.

## Technical Context

**Language/Version**: Python 3.11+ (cohérent avec `regine-core`, cf. `specs/002`, `specs/003`, `specs/004`)

**Primary Dependencies**: `exiftool` (déjà une dépendance actée par `specs/002-profil-boitiers-optionnel` pour `regine_core.metadata.exif`, étendu ici pour la lecture de la date de prise de vue et l'écriture de l'identifiant pérenne) ; bibliothèque standard uniquement sinon (`hashlib` pour les sommes de contrôle, `pathlib`/`shutil` pour la copie et le renommage, `difflib` pour la recherche de dossiers candidats par titre proche, réutilisant la même approche que `specs/004-categorisation-dossiers`)

**Storage**: ce module n'introduit aucune nouvelle base ; il consomme la base de contexte centralisée via `regine_core.camera_profile` (specs/002) et `regine_core.config.categories`/`regine_core.dossier.root` (specs/004). Le manifeste persistant par dossier (checksums, réconciliation) est désormais spécifié et planifié par `specs/005-checkout-reconciliation` (`regine_core.archive`/`regine_core.integrity`) ; ce module l'utilise pour FR-009 sans le redéfinir

**Testing**: pytest ; tests unitaires sur le découpage jour par jour et la détection de dates aberrantes, sur le renommage synchronisé, sur la construction du chemin final (délégué à `specs/004`) ; tests d'intégration sur le pipeline complet copie→analyse→destination→renommage→confirmation, en répertoires temporaires simulant carte/local/archive (aucune écriture réseau réelle)

**Target Platform**: poste de travail de bureau, identique aux autres modules de `regine-core`

**Project Type**: Monorepo existant (`specs/002`, `specs/003`, `specs/004`) — nouveau module `regine_core/import_carte/` et première commande CLI concrète (`regine import`) dans `regine-cli`

**Performance Goals**: aucune lecture de la carte mémoire ne doit dépasser une seule passe par fichier (FR-001/Edge Case déjà tranché) ; pas d'autre cible chiffrée spécifique

**Constraints**: le sous-scénario de fusion vers un dossier **déjà archivé** sur le NAS (FR-009, Acceptance Scenario 4 de User Story 3) appelle `regine_core.archive.checkout.checkout` (`specs/005-checkout-reconciliation`) sur le dossier ciblé avant d'y intégrer les nouveaux fichiers ; ce plan consomme cette API sans la redéfinir

**Scale/Scope**: import typique de quelques dizaines à quelques milliers de fichiers par carte mémoire, usage mono-utilisateur

## Constitution Check

*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*

| Principe / contrainte | Évaluation | Justification |
|---|---|---|
| I. Fichier maître intouchable | PASS | Un fichier maître n'est renommé qu'une seule fois, avant son premier archivage (FR-013) ; aucune modification après archivage n'est effectuée par ce module (la vérification d'anomalie ultérieure relève de `specs/005-checkout-reconciliation`, qui l'implémente désormais). |
| II. Confirmation explicite avant toute action à risque | PASS | FR-018 : résumé complet (fichiers, taille, dossier de destination, répertoire racine) présenté et confirmé avant toute écriture sur l'archive ; FR-012 : collision de nom traitée par suffixe ou confirmation, jamais écrasement silencieux. |
| III. Identité par contenu, jamais par nom de fichier seul | PASS | FR-004 : seuls les fichiers réellement nouveaux (par somme de contrôle) entrent dans l'analyse ; FR-015 : désambiguïsation de boîtiers déléguée à `specs/002`, elle-même fondée sur les métadonnées, jamais sur le seul nom de fichier. |
| IV. Métadonnées ouvertes et embarquées | PASS | FR-017 : l'identifiant pérenne est écrit dans les métadonnées XMP embarquées du fichier (réutilisation du champ standard `xmpMM:DocumentID`, cf. research.md § 3), pas dans une base séparée. |
| V. L'utilisateur décide, Régine suggère | PASS | FR-006 (candidat de détachement suggéré, jamais imposé), FR-011 (lieu GPS suggéré, jamais imposé), FR-007 (catégorie/année toujours une décision explicite, délégué à `specs/004`). |
| VI. Bibliothèque centrale, façades minces | PASS | Toute la logique vit dans `regine_core.import_carte`, qui consomme `regine_core.dossier`, `regine_core.camera_profile` et `regine_core.metadata` sans dupliquer leur logique ; `regine-cli` n'orchestre que l'appel et l'affichage. |
| CLI-first | PASS | `regine import` est la première façade construite pour ce pipeline, avant toute GUI. |
| Exécution sans démon | PASS | Le pipeline s'exécute intégralement dans le processus de la commande CLI, sans état en arrière-plan. |
| Formats ouverts et documentés | PASS | XMP pour l'identifiant pérenne ; aucune base propriétaire introduite. |
| Vérification d'intégrité systématique | PASS | FR-001 : vérification par somme de contrôle sur toute copie carte→local et sur le transfert local→archive (FR-019). |

Aucune violation identifiée ; la section Complexity Tracking reste vide.

## Complexity Tracking

*Aucune violation de gate à justifier — section laissée vide intentionnellement.*

**Re-check post Phase 1** (après génération de `data-model.md`, `contracts/`, `quickstart.md`) : le modèle de données (Groupe d'import, Destination, Renommage) et les contrats (CLI `regine import`, API interne `regine_core.import_carte`) confirment chaque évaluation ci-dessus. Le sous-scénario FR-009 est désormais implémentable via `specs/005-checkout-reconciliation` (cf. `contracts/cli-import.md` et `quickstart.md`, mis à jour en conséquence) — plus aucune dépendance manquante.

## Project Structure

### Documentation (this feature)

```text
specs/001-import-photos/
├── 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-import.md
│   └── regine-core-api.md
└── tasks.md             # Phase 2 output (/speckit-tasks command - NOT created by /speckit-plan)
```

### Source Code (repository root) — extension du monorepo posé par specs/002/003/004

```text
packages/regine-core/
├── src/regine_core/
│   ├── metadata/
│   │   └── exif.py                    # (existant, specs/002) étendu : read_capture_date(), write_document_id()
│   └── import_carte/                  # NOUVEAU module
│       ├── __init__.py
│       ├── copie.py                   # copie vérifiée carte→local, une seule lecture (FR-001), filtrage nouveaux fichiers (FR-004)
│       ├── groupage.py                # répartition jour par jour, détection dates aberrantes, découpage en groupes (FR-002/003/005/006)
│       ├── destination.py             # orchestration destination : simple/sous-dossier/fusion/parent + catégorie (FR-007/008/009), délègue à regine_core.dossier.root et, pour une fusion vers un dossier déjà archivé, à regine_core.archive.checkout (specs/005)
│       ├── nommage.py                 # construction titre/nom dossier, collision (FR-010/012), renommage synchronisé (FR-013/014)
│       ├── identifiant.py             # génération + écriture identifiant pérenne (FR-017)
│       └── push.py                    # résumé + confirmation + transfert final (FR-018/019)
│
└── tests/
    ├── unit/
    │   ├── test_copie_checksum.py     # une seule lecture carte, échec de vérification, carte lente
    │   ├── test_groupage_dates.py     # découpage par défaut, détachement, dates aberrantes, fichiers déjà vus
    │   ├── test_nommage.py            # formats de nom, collision, renommage synchronisé fichiers associés
    │   └── test_identifiant.py        # génération, écriture XMP DocumentID
    └── integration/
        ├── test_pipeline_import_simple.py    # US1 : carte → dossier archivé, résumé confirmé
        ├── test_pipeline_multi_jours.py      # US2 : détachement, groupes multiples
        └── test_pipeline_voyage.py           # US3 : dossier parent + sous-dossier + fusion locale ET fusion vers dossier archivé (via specs/005-checkout-reconciliation) + désambiguïsation boîtiers

packages/regine-cli/
└── src/regine_cli/
    └── import_cmd.py                  # NOUVEAU : commande `regine import <carte>`, premier point d'intégration réel (dossier.root, camera_profile, metadata.exif)
```

**Structure Decision**: Extension du monorepo existant — nouveau module `regine_core/import_carte/` (aucun code existant avant ce plan pour ce module), et première commande CLI concrète du projet (`regine import`), qui devient le point d'intégration réel des API déjà contractées par `specs/002-profil-boitiers-optionnel` et `specs/004-categorisation-dossiers` (jusqu'ici documentées mais non consommées). `regine_core/metadata/exif.py` (créé par specs/002) est étendu plutôt que dupliqué. **Mise à jour du 2026-09-19** : le sous-scénario FR-009 (fusion vers un dossier déjà archivé) consomme désormais `regine_core.archive.checkout` (`specs/005-checkout-reconciliation`, planifiée) au lieu d'être documenté comme bloqué.