import
c7fd8a1 parent: de95607 modified
docs/lexique.md +4 -0 | @@ -26,6 +26,10 @@ C'est la distinction la plus importante du lexique — deux familles de concepts | ||
| 26 | 26 | - **promotion** — action de faire remonter un fichier vers une racine. En deux temps pour un dossier parent : racine du sous-dossier d'abord, puis racine du dossier parent (planche-contact globale). |
| 27 | 27 | - **fiche de provenance** — enregistrement créé au moment de la copie vers un projet : dossier source, identifiant pérenne du fichier, nom d'origine. |
| 28 | 28 | - **planche-contact** — terme à trois sens proches, pas encore unifiés en un seul mot (2026-09-18) : (1) niveau de la hiérarchie de sélection, brut → sélection/planche-contact → édition finale ; (2) racine d'un dossier parent, servant de vue d'ensemble sur tout le voyage ; (3) export JPEG généré à la demande, montrant toutes les photos d'un dossier avec cadres (sélection) et étoiles (notation) superposés — cf. `interface-cli-gui-architecture.md` § Planche-contact JPEG annotée. |
| 29 | +- **répertoire racine (archive)** — premier niveau à la racine de l'archive NAS et, en miroir, de l'espace de travail local, sous lequel vit directement un dossier ou un dossier parent (2026-09-18) : soit un répertoire d'année (`AAAA`, cas par défaut), soit un répertoire de catégorie thématique. Un dossier ou dossier parent en a exactement un à la fois — cf. `specs/004-categorisation-dossiers`. | |
| 30 | +- **catégorie thématique** — nom libre choisi par l'utilisateur (mariage, vacances, voyage, anniversaire au départ, liste extensible sans limite fixée) servant de répertoire racine alternatif au répertoire d'année, pour regrouper des dossiers/dossiers parents relevant d'un même type de projet indépendamment de leur année (2026-09-18) — cf. `specs/004-categorisation-dossiers`. | |
| 31 | + | |
| 32 | +**Point de vigilance** : ne pas confondre **répertoire racine (archive)** (premier niveau année/catégorie, ce document) avec **racine** (niveau de sélection à l'intérieur d'un dossier, entrée précédente) — les deux emploient le mot « racine » mais désignent des niveaux différents de la hiérarchie. Désambiguïsé par le qualificatif « (archive) » dans les docs et specs qui en ont besoin. | |
| 29 | 33 | |
| 30 | 34 | ## 3. Fichiers et intégrité |
| 31 | 35 | |
| @@ -26,6 +26,10 @@ C'est la distinction la plus importante du lexique — deux familles de concepts | |||
| 26 | - **promotion** — action de faire remonter un fichier vers une racine. En deux temps pour un dossier parent : racine du sous-dossier d'abord, puis racine du dossier parent (planche-contact globale). | 26 | - **promotion** — action de faire remonter un fichier vers une racine. En deux temps pour un dossier parent : racine du sous-dossier d'abord, puis racine du dossier parent (planche-contact globale). |
| 27 | - **fiche de provenance** — enregistrement créé au moment de la copie vers un projet : dossier source, identifiant pérenne du fichier, nom d'origine. | 27 | - **fiche de provenance** — enregistrement créé au moment de la copie vers un projet : dossier source, identifiant pérenne du fichier, nom d'origine. |
| 28 | - **planche-contact** — terme à trois sens proches, pas encore unifiés en un seul mot (2026-09-18) : (1) niveau de la hiérarchie de sélection, brut → sélection/planche-contact → édition finale ; (2) racine d'un dossier parent, servant de vue d'ensemble sur tout le voyage ; (3) export JPEG généré à la demande, montrant toutes les photos d'un dossier avec cadres (sélection) et étoiles (notation) superposés — cf. `interface-cli-gui-architecture.md` § Planche-contact JPEG annotée. | 28 | - **planche-contact** — terme à trois sens proches, pas encore unifiés en un seul mot (2026-09-18) : (1) niveau de la hiérarchie de sélection, brut → sélection/planche-contact → édition finale ; (2) racine d'un dossier parent, servant de vue d'ensemble sur tout le voyage ; (3) export JPEG généré à la demande, montrant toutes les photos d'un dossier avec cadres (sélection) et étoiles (notation) superposés — cf. `interface-cli-gui-architecture.md` § Planche-contact JPEG annotée. |
| 29 | +- **répertoire racine (archive)** — premier niveau à la racine de l'archive NAS et, en miroir, de l'espace de travail local, sous lequel vit directement un dossier ou un dossier parent (2026-09-18) : soit un répertoire d'année (`AAAA`, cas par défaut), soit un répertoire de catégorie thématique. Un dossier ou dossier parent en a exactement un à la fois — cf. `specs/004-categorisation-dossiers`. | ||
| 30 | +- **catégorie thématique** — nom libre choisi par l'utilisateur (mariage, vacances, voyage, anniversaire au départ, liste extensible sans limite fixée) servant de répertoire racine alternatif au répertoire d'année, pour regrouper des dossiers/dossiers parents relevant d'un même type de projet indépendamment de leur année (2026-09-18) — cf. `specs/004-categorisation-dossiers`. | ||
| 31 | + | ||
| 32 | +**Point de vigilance** : ne pas confondre **répertoire racine (archive)** (premier niveau année/catégorie, ce document) avec **racine** (niveau de sélection à l'intérieur d'un dossier, entrée précédente) — les deux emploient le mot « racine » mais désignent des niveaux différents de la hiérarchie. Désambiguïsé par le qualificatif « (archive) » dans les docs et specs qui en ont besoin. | ||
| 29 | 33 | ||
| 30 | ## 3. Fichiers et intégrité | 34 | ## 3. Fichiers et intégrité |
| 31 | 35 | ||
modified
specs/001-import-photos/checklists/requirements.md +6 -0 | @@ -49,3 +49,9 @@ | ||
| 49 | 49 | de la source est calculée au fil de l'unique lecture de la carte pendant la copie, et seule la |
| 50 | 50 | copie locale (rapide) est relue pour la comparaison, afin de ne pas doubler le temps d'import sur |
| 51 | 51 | une carte à vitesse d'accès faible. |
| 52 | +- **Mise à jour du 2026-09-18 (ter)** : alignement sur `specs/004-categorisation-dossiers` — | |
| 53 | + FR-007 (question de catégorie/année à l'étape de destination), FR-010 (chemin final intégrant le | |
| 54 | + répertoire racine), FR-012 (collision vérifiée au sein du même répertoire racine), FR-018 | |
| 55 | + (répertoire racine affiché dans le résumé de confirmation), Key Entities (Dossier / Dossier | |
| 56 | + parent), Acceptance Scenarios de User Story 3 (héritage du répertoire racine par les | |
| 57 | + sous-dossiers) et Assumptions (dépendance déclarée vers specs/004) mis à jour ; nouveau SC-008. | |
| @@ -49,3 +49,9 @@ | |||
| 49 | de la source est calculée au fil de l'unique lecture de la carte pendant la copie, et seule la | 49 | de la source est calculée au fil de l'unique lecture de la carte pendant la copie, et seule la |
| 50 | copie locale (rapide) est relue pour la comparaison, afin de ne pas doubler le temps d'import sur | 50 | copie locale (rapide) est relue pour la comparaison, afin de ne pas doubler le temps d'import sur |
| 51 | une carte à vitesse d'accès faible. | 51 | une carte à vitesse d'accès faible. |
| 52 | +- **Mise à jour du 2026-09-18 (ter)** : alignement sur `specs/004-categorisation-dossiers` — | ||
| 53 | + FR-007 (question de catégorie/année à l'étape de destination), FR-010 (chemin final intégrant le | ||
| 54 | + répertoire racine), FR-012 (collision vérifiée au sein du même répertoire racine), FR-018 | ||
| 55 | + (répertoire racine affiché dans le résumé de confirmation), Key Entities (Dossier / Dossier | ||
| 56 | + parent), Acceptance Scenarios de User Story 3 (héritage du répertoire racine par les | ||
| 57 | + sous-dossiers) et Assumptions (dépendance déclarée vers specs/004) mis à jour ; nouveau SC-008. | ||
modified
specs/001-import-photos/spec.md +11 -9 | @@ -22,7 +22,7 @@ Un photographe rentre d'une sortie photo avec une carte mémoire. Il demande à | ||
| 22 | 22 | |
| 23 | 23 | 1. **Given** une carte mémoire contenant des photos d'une seule journée, jamais importées auparavant, **When** l'utilisateur lance l'import, **Then** Régine copie les fichiers vers un espace de travail local en vérifiant chaque fichier par somme de contrôle avant de signaler la carte comme sûre à effacer. |
| 24 | 24 | 2. **Given** la copie locale vérifiée d'une carte à une seule journée, **When** Régine analyse les dates de prise de vue, **Then** elle propose un seul groupe couvrant cette journée et invite l'utilisateur à donner un titre. |
| 25 | -3. **Given** un titre saisi par l'utilisateur, **When** Régine construit le nom du dossier, **Then** elle produit un nom au format `AAAA-MM-JJ_Titre`, nettoyé des caractères interdits et des espaces, et vérifie qu'aucun dossier identique n'existe déjà avant de le créer. | |
| 25 | +3. **Given** un titre saisi par l'utilisateur, **When** Régine construit le nom du dossier, **Then** elle produit un nom au format `AAAA-MM-JJ_Titre`, nettoyé des caractères interdits et des espaces, le place sous le répertoire racine déterminé à l'étape de destination (année par défaut, ou catégorie thématique — cf. `specs/004-categorisation-dossiers`), et vérifie qu'aucun dossier identique n'existe déjà sous ce même répertoire racine avant de le créer. | |
| 26 | 26 | 4. **Given** un nom de dossier validé, **When** Régine renomme les fichiers avant archivage, **Then** chaque fichier maître est renommé en `date_titre_nomOrigine.ext` en conservant le nom d'origine du boîtier en suffixe, et tout fichier associé (JPEG jumeau, sidecar) est renommé de façon synchronisée. |
| 27 | 27 | 5. **Given** des fichiers renommés localement, **When** Régine pousse le dossier vers l'archive, **Then** elle présente d'abord un résumé (nombre de fichiers, taille, nom du dossier de destination) et attend une confirmation explicite avant d'écrire quoi que ce soit sur l'archive. |
| 28 | 28 | |
| @@ -55,8 +55,8 @@ Un photographe est en voyage sur plusieurs villes. Pour la deuxième étape, il | ||
| 55 | 55 | |
| 56 | 56 | **Acceptance Scenarios**: |
| 57 | 57 | |
| 58 | -1. **Given** un premier import connu comme le début d'un voyage à plusieurs étapes, **When** l'utilisateur choisit la destination "nouveau dossier parent avec sa première étape", **Then** Régine crée directement une structure à deux niveaux (dossier parent au format `AAAA-MM_Titre`, sous-dossier au format `AAAA-MM-JJ_Titre_Lieu`). | |
| 59 | -2. **Given** un dossier parent de voyage déjà existant, **When** l'utilisateur importe une nouvelle carte pour une étape suivante et choisit "nouveau sous-dossier dans un dossier parent existant", **Then** Régine liste les dossiers parents existants (locaux et archivés) pour que l'utilisateur choisisse le bon, puis crée le sous-dossier à l'intérieur. | |
| 58 | +1. **Given** un premier import connu comme le début d'un voyage à plusieurs étapes, **When** l'utilisateur choisit la destination "nouveau dossier parent avec sa première étape", **Then** Régine crée directement une structure à deux niveaux (dossier parent au format `AAAA-MM_Titre`, sous-dossier au format `AAAA-MM-JJ_Titre_Lieu`) sous le répertoire racine (année ou catégorie thématique) choisi à ce moment pour l'ensemble du voyage (cf. `specs/004-categorisation-dossiers`). | |
| 59 | +2. **Given** un dossier parent de voyage déjà existant, **When** l'utilisateur importe une nouvelle carte pour une étape suivante et choisit "nouveau sous-dossier dans un dossier parent existant", **Then** Régine liste les dossiers parents existants (locaux et archivés) pour que l'utilisateur choisisse le bon, puis crée le sous-dossier à l'intérieur en héritant automatiquement du répertoire racine déjà établi pour ce dossier parent, sans reposer la question (cf. `specs/004-categorisation-dossiers`). | |
| 60 | 60 | 3. **Given** deux cartes mémoire couvrant la même étape (deux boîtiers, ou une carte de secours), **When** l'utilisateur choisit "fusion dans un dossier existant" pour la seconde carte, **Then** Régine ajoute directement les nouveaux fichiers au dossier ciblé, sans créer de sous-dossier supplémentaire, en détectant les doublons éventuels par somme de contrôle. |
| 61 | 61 | 4. **Given** une fusion vers un dossier déjà archivé sur l'archive plutôt que seulement local, **When** Régine prépare la fusion, **Then** elle effectue d'abord un aller-retour de vérification (checkout) sur ce dossier avant d'y intégrer les nouveaux fichiers. |
| 62 | 62 | 5. **Given** deux boîtiers différents produisant chacun un fichier de même nom d'origine au sein d'un même import, **When** Régine détecte la collision par somme de contrôle, **Then** elle désambiguïse par défaut les deux sources à partir du tag EXIF de modèle de chaque fichier, sans exiger de profil de boîtiers préalablement déclaré, et ne sollicite l'utilisateur (profil, numéro de série, étiquetage manuel) que si ce tag ne suffit pas à distinguer les sources (cf. `specs/002-profil-boitiers-optionnel`). |
| @@ -83,18 +83,18 @@ Un photographe est en voyage sur plusieurs villes. Pour la deuxième étape, il | ||
| 83 | 83 | - **FR-004**: Le système DOIT ne prendre en compte, pour l'analyse et le découpage en groupes, que les fichiers réellement nouveaux pour l'import en cours (identifiés par somme de contrôle), à l'exclusion de tout fichier déjà importé lors d'une session précédente et resté sur la carte. |
| 84 | 84 | - **FR-005**: Le système DOIT proposer par défaut un seul groupe couvrant toute la plage de dates contiguë détectée, et permettre à l'utilisateur de détacher un ou plusieurs jours de cette plage pour former des groupes distincts. |
| 85 | 85 | - **FR-006**: Le système PEUT mettre en avant un ou plusieurs jours comme candidats plausibles au détachement (ex. pic de prises de vue isolé), mais ne DOIT jamais détacher un groupe automatiquement sans validation de l'utilisateur. |
| 86 | -- **FR-007**: Pour chaque groupe résultant du découpage, le système DOIT demander explicitement à l'utilisateur sa destination, parmi : nouveau dossier simple, nouveau sous-dossier d'un dossier parent existant, fusion dans un dossier existant, ou nouveau dossier parent avec sa première étape — sans jamais retenir un état "voyage en cours" d'un import à l'autre. | |
| 86 | +- **FR-007**: Pour chaque groupe résultant du découpage, le système DOIT demander explicitement à l'utilisateur sa destination, parmi : nouveau dossier simple, nouveau sous-dossier d'un dossier parent existant, fusion dans un dossier existant, ou nouveau dossier parent avec sa première étape — sans jamais retenir un état "voyage en cours" d'un import à l'autre. Pour un nouveau dossier simple ou un nouveau dossier parent (jamais pour un nouveau sous-dossier ni une fusion, qui héritent du placement déjà établi), le système DOIT également demander si ce dossier relève d'une catégorie thématique ou du placement par défaut par année (cf. `specs/004-categorisation-dossiers`). | |
| 87 | 87 | - **FR-008**: Pour aider l'utilisateur à choisir une destination de sous-dossier ou de fusion, le système DOIT lister les dossiers candidats existants à la fois dans l'espace de travail local et dans l'archive (recherche par titre ou date proche). |
| 88 | 88 | - **FR-009**: Lorsqu'une fusion cible un dossier déjà présent dans l'archive (et pas seulement en local), le système DOIT d'abord effectuer une vérification (checkout) de ce dossier avant d'y intégrer les nouveaux fichiers. |
| 89 | -- **FR-010**: Le système DOIT demander un titre pour chaque groupe, le nettoyer pour en faire un nom de dossier valide (espaces convertis, caractères interdits refusés), puis le combiner avec la plage de dates selon la granularité appropriée (jour unique, plage dans le même mois, plage à cheval sur deux mois/années, ou granularité mois pour un dossier parent de voyage). | |
| 89 | +- **FR-010**: Le système DOIT demander un titre pour chaque groupe, le nettoyer pour en faire un nom de dossier valide (espaces convertis, caractères interdits refusés), puis le combiner avec la plage de dates selon la granularité appropriée (jour unique, plage dans le même mois, plage à cheval sur deux mois/années, ou granularité mois pour un dossier parent de voyage). Le chemin final DOIT également intégrer le répertoire racine déterminé à l'étape FR-007 (répertoire d'année par défaut, ou répertoire de la catégorie thématique choisie), de façon identique dans la copie de travail locale et dans l'archive (cf. `specs/004-categorisation-dossiers`). | |
| 90 | 90 | - **FR-011**: Le système PEUT suggérer automatiquement un lieu à partir de coordonnées GPS présentes dans les métadonnées EXIF, mais cette suggestion reste modifiable et ne DOIT jamais être imposée à l'utilisateur. |
| 91 | -- **FR-012**: Le système DOIT vérifier, avant de créer un dossier final, qu'aucun dossier de nom identique n'existe déjà ; en cas de collision, il DOIT proposer un suffixe ou demander une confirmation explicite plutôt que d'écraser. | |
| 91 | +- **FR-012**: Le système DOIT vérifier, avant de créer un dossier final, qu'aucun dossier de nom identique n'existe déjà sous le même répertoire racine (année ou catégorie thématique — cf. `specs/004-categorisation-dossiers`) ; en cas de collision, il DOIT proposer un suffixe ou demander une confirmation explicite plutôt que d'écraser. | |
| 92 | 92 | - **FR-013**: Le système DOIT renommer chaque fichier maître importé selon la convention `date_titre_nomOrigine.ext`, en conservant le nom d'origine attribué par le boîtier en suffixe, une fois le titre du groupe choisi et juste avant l'archivage. |
| 93 | 93 | - **FR-014**: Le système DOIT renommer de façon synchronisée tout fichier partageant le même nom de base qu'un fichier maître renommé (JPEG jumeau en mode RAW+JPEG, sidecar de réglages), pour préserver leur appariement. |
| 94 | 94 | - **FR-015**: Le système DOIT désambiguïser par défaut deux fichiers de même nom d'origine provenant de boîtiers différents à partir du tag EXIF de modèle de chaque fichier, sans exiger qu'un profil de boîtiers ait été préalablement déclaré ; il ne DOIT solliciter l'utilisateur (profil, numéro de série, étiquetage manuel) qu'au moment où une collision réelle est détectée par somme de contrôle et où ce tag ne suffit pas à distinguer les sources (cf. `specs/002-profil-boitiers-optionnel`, qui définit ce mécanisme de désambiguïsation en détail). |
| 95 | 95 | - **FR-016**: La détection d'un modèle de boîtier jamais rencontré auparavant dans les métadonnées d'un fichier ne DOIT, en l'absence de toute collision réelle, ni interrompre l'import ni exiger une action sur le profil de boîtiers. |
| 96 | 96 | - **FR-017**: Le système DOIT attribuer un identifiant pérenne, indépendant du nom de fichier, à chaque photo importée, et l'inscrire dans les métadonnées embarquées du fichier. |
| 97 | -- **FR-018**: Avant d'écrire quoi que ce soit sur l'archive (création de dossier, archivage des fichiers renommés, fusion dans un dossier existant), le système DOIT présenter à l'utilisateur un résumé de l'opération (nombre de fichiers concernés, dossier de destination) et attendre une confirmation explicite. | |
| 97 | +- **FR-018**: Avant d'écrire quoi que ce soit sur l'archive (création de dossier, archivage des fichiers renommés, fusion dans un dossier existant), le système DOIT présenter à l'utilisateur un résumé de l'opération (nombre de fichiers concernés, dossier de destination, y compris son répertoire racine — année ou catégorie thématique, cf. `specs/004-categorisation-dossiers`) et attendre une confirmation explicite. | |
| 98 | 98 | - **FR-019**: Le système DOIT effectuer le transfert final vers l'archive à partir de la copie de travail locale déjà vérifiée et renommée, plutôt que par une copie directe de la carte mémoire vers l'archive. |
| 99 | 99 | |
| 100 | 100 | ### Key Entities |
| @@ -102,8 +102,8 @@ Un photographe est en voyage sur plusieurs villes. Pour la deuxième étape, il | ||
| 102 | 102 | - **Carte mémoire** : support source d'un import, contenant des fichiers déjà importés lors de sessions précédentes et des fichiers réellement nouveaux à traiter. |
| 103 | 103 | - **Copie de travail locale** : copie temporaire et vérifiée par somme de contrôle des fichiers nouveaux d'une carte, base de toute l'analyse et du renommage avant archivage. |
| 104 | 104 | - **Groupe d'import** : sous-ensemble de fichiers nouvellement importés partageant une plage de dates contiguë, destiné à devenir un dossier ou un sous-dossier de l'archive. |
| 105 | -- **Dossier** : unité d'archive résultant d'un groupe simple, avec sa structure par format et sa racine de sélection. | |
| 106 | -- **Dossier parent / sous-dossier** : structure à deux niveaux résultant d'un import s'intégrant à un voyage en plusieurs étapes. | |
| 105 | +- **Dossier** : unité d'archive résultant d'un groupe simple, avec sa structure par format et sa racine de sélection, vivant sous un répertoire racine (année par défaut ou catégorie thématique — cf. `specs/004-categorisation-dossiers`). | |
| 106 | +- **Dossier parent / sous-dossier** : structure à deux niveaux résultant d'un import s'intégrant à un voyage en plusieurs étapes, partageant le même répertoire racine (année ou catégorie) que le dossier parent qui les englobe. | |
| 107 | 107 | - **Profil de boîtiers** : liste optionnelle d'appareils, alimentée à la demande (cf. `specs/002-profil-boitiers-optionnel`), utilisée pour désambiguïser la source d'un fichier lorsqu'une collision réelle de nom d'origine survient et que le tag de modèle seul ne suffit pas à la résoudre. |
| 108 | 108 | - **Fichier maître** : photo issue directement du boîtier (RAW ou JPEG selon les cas), renommée à l'import et jamais modifiée une fois archivée. |
| 109 | 109 | - **Fichier associé** : fichier partageant le nom de base d'un fichier maître (JPEG jumeau, sidecar de réglages), renommé de façon synchronisée avec lui. |
| @@ -120,6 +120,7 @@ Un photographe est en voyage sur plusieurs villes. Pour la deuxième étape, il | ||
| 120 | 120 | - **SC-005**: 100% des paires de fichiers associés (fichier maître + JPEG jumeau ou sidecar) conservent leur appariement (même nom de base) après renommage à l'import. |
| 121 | 121 | - **SC-006**: Aucune écriture sur l'archive (création de dossier, ajout de fichiers) ne survient sans qu'un résumé de l'opération n'ait été présenté et explicitement confirmé par l'utilisateur. |
| 122 | 122 | - **SC-007**: Un utilisateur qui importe une carte couvrant un voyage en plusieurs étapes peut obtenir une structure à deux niveaux correctement rattachée sans avoir à renommer ou déplacer manuellement de dossier après l'import. |
| 123 | +- **SC-008**: Le répertoire racine de destination (année ou catégorie thématique) est visible dans 100% des résumés présentés avant confirmation d'archivage (cf. `specs/004-categorisation-dossiers`). | |
| 123 | 124 | |
| 124 | 125 | ## Assumptions |
| 125 | 126 | |
| @@ -129,3 +130,4 @@ Un photographe est en voyage sur plusieurs villes. Pour la deuxième étape, il | ||
| 129 | 130 | - Le mécanisme de checkout/réconciliation d'un dossier déjà archivé (utilisé au cas de fusion vers un dossier existant sur l'archive) est une capacité déjà disponible ou livrée avant ou avec ce module ; ce module ne redéfinit pas ce mécanisme, il s'appuie dessus. |
| 130 | 131 | - La suggestion automatique de lieu par coordonnées GPS dépend de la présence de ces coordonnées dans les métadonnées du fichier ; en leur absence, l'utilisateur saisit le lieu librement, sans que cela bloque l'import. |
| 131 | 132 | - Une seule carte mémoire est traitée à la fois par import ; l'import simultané de plusieurs cartes n'est pas couvert par ce module. |
| 133 | +- Le placement racine d'un dossier ou d'un dossier parent (répertoire d'année par défaut, ou répertoire de catégorie thématique) est défini par `specs/004-categorisation-dossiers`, que ce module ne redéfinit pas : il s'appuie dessus pour l'étape de destination (FR-007), la construction du chemin final (FR-010), la vérification de collision (FR-012) et le résumé de confirmation (FR-018). | |
| @@ -22,7 +22,7 @@ Un photographe rentre d'une sortie photo avec une carte mémoire. Il demande à | |||
| 22 | 22 | ||
| 23 | 1. **Given** une carte mémoire contenant des photos d'une seule journée, jamais importées auparavant, **When** l'utilisateur lance l'import, **Then** Régine copie les fichiers vers un espace de travail local en vérifiant chaque fichier par somme de contrôle avant de signaler la carte comme sûre à effacer. | 23 | 1. **Given** une carte mémoire contenant des photos d'une seule journée, jamais importées auparavant, **When** l'utilisateur lance l'import, **Then** Régine copie les fichiers vers un espace de travail local en vérifiant chaque fichier par somme de contrôle avant de signaler la carte comme sûre à effacer. |
| 24 | 2. **Given** la copie locale vérifiée d'une carte à une seule journée, **When** Régine analyse les dates de prise de vue, **Then** elle propose un seul groupe couvrant cette journée et invite l'utilisateur à donner un titre. | 24 | 2. **Given** la copie locale vérifiée d'une carte à une seule journée, **When** Régine analyse les dates de prise de vue, **Then** elle propose un seul groupe couvrant cette journée et invite l'utilisateur à donner un titre. |
| 25 | -3. **Given** un titre saisi par l'utilisateur, **When** Régine construit le nom du dossier, **Then** elle produit un nom au format `AAAA-MM-JJ_Titre`, nettoyé des caractères interdits et des espaces, et vérifie qu'aucun dossier identique n'existe déjà avant de le créer. | 25 | +3. **Given** un titre saisi par l'utilisateur, **When** Régine construit le nom du dossier, **Then** elle produit un nom au format `AAAA-MM-JJ_Titre`, nettoyé des caractères interdits et des espaces, le place sous le répertoire racine déterminé à l'étape de destination (année par défaut, ou catégorie thématique — cf. `specs/004-categorisation-dossiers`), et vérifie qu'aucun dossier identique n'existe déjà sous ce même répertoire racine avant de le créer. |
| 26 | 4. **Given** un nom de dossier validé, **When** Régine renomme les fichiers avant archivage, **Then** chaque fichier maître est renommé en `date_titre_nomOrigine.ext` en conservant le nom d'origine du boîtier en suffixe, et tout fichier associé (JPEG jumeau, sidecar) est renommé de façon synchronisée. | 26 | 4. **Given** un nom de dossier validé, **When** Régine renomme les fichiers avant archivage, **Then** chaque fichier maître est renommé en `date_titre_nomOrigine.ext` en conservant le nom d'origine du boîtier en suffixe, et tout fichier associé (JPEG jumeau, sidecar) est renommé de façon synchronisée. |
| 27 | 5. **Given** des fichiers renommés localement, **When** Régine pousse le dossier vers l'archive, **Then** elle présente d'abord un résumé (nombre de fichiers, taille, nom du dossier de destination) et attend une confirmation explicite avant d'écrire quoi que ce soit sur l'archive. | 27 | 5. **Given** des fichiers renommés localement, **When** Régine pousse le dossier vers l'archive, **Then** elle présente d'abord un résumé (nombre de fichiers, taille, nom du dossier de destination) et attend une confirmation explicite avant d'écrire quoi que ce soit sur l'archive. |
| 28 | 28 | ||
| @@ -55,8 +55,8 @@ Un photographe est en voyage sur plusieurs villes. Pour la deuxième étape, il | |||
| 55 | 55 | ||
| 56 | **Acceptance Scenarios**: | 56 | **Acceptance Scenarios**: |
| 57 | 57 | ||
| 58 | -1. **Given** un premier import connu comme le début d'un voyage à plusieurs étapes, **When** l'utilisateur choisit la destination "nouveau dossier parent avec sa première étape", **Then** Régine crée directement une structure à deux niveaux (dossier parent au format `AAAA-MM_Titre`, sous-dossier au format `AAAA-MM-JJ_Titre_Lieu`). | 58 | +1. **Given** un premier import connu comme le début d'un voyage à plusieurs étapes, **When** l'utilisateur choisit la destination "nouveau dossier parent avec sa première étape", **Then** Régine crée directement une structure à deux niveaux (dossier parent au format `AAAA-MM_Titre`, sous-dossier au format `AAAA-MM-JJ_Titre_Lieu`) sous le répertoire racine (année ou catégorie thématique) choisi à ce moment pour l'ensemble du voyage (cf. `specs/004-categorisation-dossiers`). |
| 59 | -2. **Given** un dossier parent de voyage déjà existant, **When** l'utilisateur importe une nouvelle carte pour une étape suivante et choisit "nouveau sous-dossier dans un dossier parent existant", **Then** Régine liste les dossiers parents existants (locaux et archivés) pour que l'utilisateur choisisse le bon, puis crée le sous-dossier à l'intérieur. | 59 | +2. **Given** un dossier parent de voyage déjà existant, **When** l'utilisateur importe une nouvelle carte pour une étape suivante et choisit "nouveau sous-dossier dans un dossier parent existant", **Then** Régine liste les dossiers parents existants (locaux et archivés) pour que l'utilisateur choisisse le bon, puis crée le sous-dossier à l'intérieur en héritant automatiquement du répertoire racine déjà établi pour ce dossier parent, sans reposer la question (cf. `specs/004-categorisation-dossiers`). |
| 60 | 3. **Given** deux cartes mémoire couvrant la même étape (deux boîtiers, ou une carte de secours), **When** l'utilisateur choisit "fusion dans un dossier existant" pour la seconde carte, **Then** Régine ajoute directement les nouveaux fichiers au dossier ciblé, sans créer de sous-dossier supplémentaire, en détectant les doublons éventuels par somme de contrôle. | 60 | 3. **Given** deux cartes mémoire couvrant la même étape (deux boîtiers, ou une carte de secours), **When** l'utilisateur choisit "fusion dans un dossier existant" pour la seconde carte, **Then** Régine ajoute directement les nouveaux fichiers au dossier ciblé, sans créer de sous-dossier supplémentaire, en détectant les doublons éventuels par somme de contrôle. |
| 61 | 4. **Given** une fusion vers un dossier déjà archivé sur l'archive plutôt que seulement local, **When** Régine prépare la fusion, **Then** elle effectue d'abord un aller-retour de vérification (checkout) sur ce dossier avant d'y intégrer les nouveaux fichiers. | 61 | 4. **Given** une fusion vers un dossier déjà archivé sur l'archive plutôt que seulement local, **When** Régine prépare la fusion, **Then** elle effectue d'abord un aller-retour de vérification (checkout) sur ce dossier avant d'y intégrer les nouveaux fichiers. |
| 62 | 5. **Given** deux boîtiers différents produisant chacun un fichier de même nom d'origine au sein d'un même import, **When** Régine détecte la collision par somme de contrôle, **Then** elle désambiguïse par défaut les deux sources à partir du tag EXIF de modèle de chaque fichier, sans exiger de profil de boîtiers préalablement déclaré, et ne sollicite l'utilisateur (profil, numéro de série, étiquetage manuel) que si ce tag ne suffit pas à distinguer les sources (cf. `specs/002-profil-boitiers-optionnel`). | 62 | 5. **Given** deux boîtiers différents produisant chacun un fichier de même nom d'origine au sein d'un même import, **When** Régine détecte la collision par somme de contrôle, **Then** elle désambiguïse par défaut les deux sources à partir du tag EXIF de modèle de chaque fichier, sans exiger de profil de boîtiers préalablement déclaré, et ne sollicite l'utilisateur (profil, numéro de série, étiquetage manuel) que si ce tag ne suffit pas à distinguer les sources (cf. `specs/002-profil-boitiers-optionnel`). |
| @@ -83,18 +83,18 @@ Un photographe est en voyage sur plusieurs villes. Pour la deuxième étape, il | |||
| 83 | - **FR-004**: Le système DOIT ne prendre en compte, pour l'analyse et le découpage en groupes, que les fichiers réellement nouveaux pour l'import en cours (identifiés par somme de contrôle), à l'exclusion de tout fichier déjà importé lors d'une session précédente et resté sur la carte. | 83 | - **FR-004**: Le système DOIT ne prendre en compte, pour l'analyse et le découpage en groupes, que les fichiers réellement nouveaux pour l'import en cours (identifiés par somme de contrôle), à l'exclusion de tout fichier déjà importé lors d'une session précédente et resté sur la carte. |
| 84 | - **FR-005**: Le système DOIT proposer par défaut un seul groupe couvrant toute la plage de dates contiguë détectée, et permettre à l'utilisateur de détacher un ou plusieurs jours de cette plage pour former des groupes distincts. | 84 | - **FR-005**: Le système DOIT proposer par défaut un seul groupe couvrant toute la plage de dates contiguë détectée, et permettre à l'utilisateur de détacher un ou plusieurs jours de cette plage pour former des groupes distincts. |
| 85 | - **FR-006**: Le système PEUT mettre en avant un ou plusieurs jours comme candidats plausibles au détachement (ex. pic de prises de vue isolé), mais ne DOIT jamais détacher un groupe automatiquement sans validation de l'utilisateur. | 85 | - **FR-006**: Le système PEUT mettre en avant un ou plusieurs jours comme candidats plausibles au détachement (ex. pic de prises de vue isolé), mais ne DOIT jamais détacher un groupe automatiquement sans validation de l'utilisateur. |
| 86 | -- **FR-007**: Pour chaque groupe résultant du découpage, le système DOIT demander explicitement à l'utilisateur sa destination, parmi : nouveau dossier simple, nouveau sous-dossier d'un dossier parent existant, fusion dans un dossier existant, ou nouveau dossier parent avec sa première étape — sans jamais retenir un état "voyage en cours" d'un import à l'autre. | 86 | +- **FR-007**: Pour chaque groupe résultant du découpage, le système DOIT demander explicitement à l'utilisateur sa destination, parmi : nouveau dossier simple, nouveau sous-dossier d'un dossier parent existant, fusion dans un dossier existant, ou nouveau dossier parent avec sa première étape — sans jamais retenir un état "voyage en cours" d'un import à l'autre. Pour un nouveau dossier simple ou un nouveau dossier parent (jamais pour un nouveau sous-dossier ni une fusion, qui héritent du placement déjà établi), le système DOIT également demander si ce dossier relève d'une catégorie thématique ou du placement par défaut par année (cf. `specs/004-categorisation-dossiers`). |
| 87 | - **FR-008**: Pour aider l'utilisateur à choisir une destination de sous-dossier ou de fusion, le système DOIT lister les dossiers candidats existants à la fois dans l'espace de travail local et dans l'archive (recherche par titre ou date proche). | 87 | - **FR-008**: Pour aider l'utilisateur à choisir une destination de sous-dossier ou de fusion, le système DOIT lister les dossiers candidats existants à la fois dans l'espace de travail local et dans l'archive (recherche par titre ou date proche). |
| 88 | - **FR-009**: Lorsqu'une fusion cible un dossier déjà présent dans l'archive (et pas seulement en local), le système DOIT d'abord effectuer une vérification (checkout) de ce dossier avant d'y intégrer les nouveaux fichiers. | 88 | - **FR-009**: Lorsqu'une fusion cible un dossier déjà présent dans l'archive (et pas seulement en local), le système DOIT d'abord effectuer une vérification (checkout) de ce dossier avant d'y intégrer les nouveaux fichiers. |
| 89 | -- **FR-010**: Le système DOIT demander un titre pour chaque groupe, le nettoyer pour en faire un nom de dossier valide (espaces convertis, caractères interdits refusés), puis le combiner avec la plage de dates selon la granularité appropriée (jour unique, plage dans le même mois, plage à cheval sur deux mois/années, ou granularité mois pour un dossier parent de voyage). | 89 | +- **FR-010**: Le système DOIT demander un titre pour chaque groupe, le nettoyer pour en faire un nom de dossier valide (espaces convertis, caractères interdits refusés), puis le combiner avec la plage de dates selon la granularité appropriée (jour unique, plage dans le même mois, plage à cheval sur deux mois/années, ou granularité mois pour un dossier parent de voyage). Le chemin final DOIT également intégrer le répertoire racine déterminé à l'étape FR-007 (répertoire d'année par défaut, ou répertoire de la catégorie thématique choisie), de façon identique dans la copie de travail locale et dans l'archive (cf. `specs/004-categorisation-dossiers`). |
| 90 | - **FR-011**: Le système PEUT suggérer automatiquement un lieu à partir de coordonnées GPS présentes dans les métadonnées EXIF, mais cette suggestion reste modifiable et ne DOIT jamais être imposée à l'utilisateur. | 90 | - **FR-011**: Le système PEUT suggérer automatiquement un lieu à partir de coordonnées GPS présentes dans les métadonnées EXIF, mais cette suggestion reste modifiable et ne DOIT jamais être imposée à l'utilisateur. |
| 91 | -- **FR-012**: Le système DOIT vérifier, avant de créer un dossier final, qu'aucun dossier de nom identique n'existe déjà ; en cas de collision, il DOIT proposer un suffixe ou demander une confirmation explicite plutôt que d'écraser. | 91 | +- **FR-012**: Le système DOIT vérifier, avant de créer un dossier final, qu'aucun dossier de nom identique n'existe déjà sous le même répertoire racine (année ou catégorie thématique — cf. `specs/004-categorisation-dossiers`) ; en cas de collision, il DOIT proposer un suffixe ou demander une confirmation explicite plutôt que d'écraser. |
| 92 | - **FR-013**: Le système DOIT renommer chaque fichier maître importé selon la convention `date_titre_nomOrigine.ext`, en conservant le nom d'origine attribué par le boîtier en suffixe, une fois le titre du groupe choisi et juste avant l'archivage. | 92 | - **FR-013**: Le système DOIT renommer chaque fichier maître importé selon la convention `date_titre_nomOrigine.ext`, en conservant le nom d'origine attribué par le boîtier en suffixe, une fois le titre du groupe choisi et juste avant l'archivage. |
| 93 | - **FR-014**: Le système DOIT renommer de façon synchronisée tout fichier partageant le même nom de base qu'un fichier maître renommé (JPEG jumeau en mode RAW+JPEG, sidecar de réglages), pour préserver leur appariement. | 93 | - **FR-014**: Le système DOIT renommer de façon synchronisée tout fichier partageant le même nom de base qu'un fichier maître renommé (JPEG jumeau en mode RAW+JPEG, sidecar de réglages), pour préserver leur appariement. |
| 94 | - **FR-015**: Le système DOIT désambiguïser par défaut deux fichiers de même nom d'origine provenant de boîtiers différents à partir du tag EXIF de modèle de chaque fichier, sans exiger qu'un profil de boîtiers ait été préalablement déclaré ; il ne DOIT solliciter l'utilisateur (profil, numéro de série, étiquetage manuel) qu'au moment où une collision réelle est détectée par somme de contrôle et où ce tag ne suffit pas à distinguer les sources (cf. `specs/002-profil-boitiers-optionnel`, qui définit ce mécanisme de désambiguïsation en détail). | 94 | - **FR-015**: Le système DOIT désambiguïser par défaut deux fichiers de même nom d'origine provenant de boîtiers différents à partir du tag EXIF de modèle de chaque fichier, sans exiger qu'un profil de boîtiers ait été préalablement déclaré ; il ne DOIT solliciter l'utilisateur (profil, numéro de série, étiquetage manuel) qu'au moment où une collision réelle est détectée par somme de contrôle et où ce tag ne suffit pas à distinguer les sources (cf. `specs/002-profil-boitiers-optionnel`, qui définit ce mécanisme de désambiguïsation en détail). |
| 95 | - **FR-016**: La détection d'un modèle de boîtier jamais rencontré auparavant dans les métadonnées d'un fichier ne DOIT, en l'absence de toute collision réelle, ni interrompre l'import ni exiger une action sur le profil de boîtiers. | 95 | - **FR-016**: La détection d'un modèle de boîtier jamais rencontré auparavant dans les métadonnées d'un fichier ne DOIT, en l'absence de toute collision réelle, ni interrompre l'import ni exiger une action sur le profil de boîtiers. |
| 96 | - **FR-017**: Le système DOIT attribuer un identifiant pérenne, indépendant du nom de fichier, à chaque photo importée, et l'inscrire dans les métadonnées embarquées du fichier. | 96 | - **FR-017**: Le système DOIT attribuer un identifiant pérenne, indépendant du nom de fichier, à chaque photo importée, et l'inscrire dans les métadonnées embarquées du fichier. |
| 97 | -- **FR-018**: Avant d'écrire quoi que ce soit sur l'archive (création de dossier, archivage des fichiers renommés, fusion dans un dossier existant), le système DOIT présenter à l'utilisateur un résumé de l'opération (nombre de fichiers concernés, dossier de destination) et attendre une confirmation explicite. | 97 | +- **FR-018**: Avant d'écrire quoi que ce soit sur l'archive (création de dossier, archivage des fichiers renommés, fusion dans un dossier existant), le système DOIT présenter à l'utilisateur un résumé de l'opération (nombre de fichiers concernés, dossier de destination, y compris son répertoire racine — année ou catégorie thématique, cf. `specs/004-categorisation-dossiers`) et attendre une confirmation explicite. |
| 98 | - **FR-019**: Le système DOIT effectuer le transfert final vers l'archive à partir de la copie de travail locale déjà vérifiée et renommée, plutôt que par une copie directe de la carte mémoire vers l'archive. | 98 | - **FR-019**: Le système DOIT effectuer le transfert final vers l'archive à partir de la copie de travail locale déjà vérifiée et renommée, plutôt que par une copie directe de la carte mémoire vers l'archive. |
| 99 | 99 | ||
| 100 | ### Key Entities | 100 | ### Key Entities |
| @@ -102,8 +102,8 @@ Un photographe est en voyage sur plusieurs villes. Pour la deuxième étape, il | |||
| 102 | - **Carte mémoire** : support source d'un import, contenant des fichiers déjà importés lors de sessions précédentes et des fichiers réellement nouveaux à traiter. | 102 | - **Carte mémoire** : support source d'un import, contenant des fichiers déjà importés lors de sessions précédentes et des fichiers réellement nouveaux à traiter. |
| 103 | - **Copie de travail locale** : copie temporaire et vérifiée par somme de contrôle des fichiers nouveaux d'une carte, base de toute l'analyse et du renommage avant archivage. | 103 | - **Copie de travail locale** : copie temporaire et vérifiée par somme de contrôle des fichiers nouveaux d'une carte, base de toute l'analyse et du renommage avant archivage. |
| 104 | - **Groupe d'import** : sous-ensemble de fichiers nouvellement importés partageant une plage de dates contiguë, destiné à devenir un dossier ou un sous-dossier de l'archive. | 104 | - **Groupe d'import** : sous-ensemble de fichiers nouvellement importés partageant une plage de dates contiguë, destiné à devenir un dossier ou un sous-dossier de l'archive. |
| 105 | -- **Dossier** : unité d'archive résultant d'un groupe simple, avec sa structure par format et sa racine de sélection. | 105 | +- **Dossier** : unité d'archive résultant d'un groupe simple, avec sa structure par format et sa racine de sélection, vivant sous un répertoire racine (année par défaut ou catégorie thématique — cf. `specs/004-categorisation-dossiers`). |
| 106 | -- **Dossier parent / sous-dossier** : structure à deux niveaux résultant d'un import s'intégrant à un voyage en plusieurs étapes. | 106 | +- **Dossier parent / sous-dossier** : structure à deux niveaux résultant d'un import s'intégrant à un voyage en plusieurs étapes, partageant le même répertoire racine (année ou catégorie) que le dossier parent qui les englobe. |
| 107 | - **Profil de boîtiers** : liste optionnelle d'appareils, alimentée à la demande (cf. `specs/002-profil-boitiers-optionnel`), utilisée pour désambiguïser la source d'un fichier lorsqu'une collision réelle de nom d'origine survient et que le tag de modèle seul ne suffit pas à la résoudre. | 107 | - **Profil de boîtiers** : liste optionnelle d'appareils, alimentée à la demande (cf. `specs/002-profil-boitiers-optionnel`), utilisée pour désambiguïser la source d'un fichier lorsqu'une collision réelle de nom d'origine survient et que le tag de modèle seul ne suffit pas à la résoudre. |
| 108 | - **Fichier maître** : photo issue directement du boîtier (RAW ou JPEG selon les cas), renommée à l'import et jamais modifiée une fois archivée. | 108 | - **Fichier maître** : photo issue directement du boîtier (RAW ou JPEG selon les cas), renommée à l'import et jamais modifiée une fois archivée. |
| 109 | - **Fichier associé** : fichier partageant le nom de base d'un fichier maître (JPEG jumeau, sidecar de réglages), renommé de façon synchronisée avec lui. | 109 | - **Fichier associé** : fichier partageant le nom de base d'un fichier maître (JPEG jumeau, sidecar de réglages), renommé de façon synchronisée avec lui. |
| @@ -120,6 +120,7 @@ Un photographe est en voyage sur plusieurs villes. Pour la deuxième étape, il | |||
| 120 | - **SC-005**: 100% des paires de fichiers associés (fichier maître + JPEG jumeau ou sidecar) conservent leur appariement (même nom de base) après renommage à l'import. | 120 | - **SC-005**: 100% des paires de fichiers associés (fichier maître + JPEG jumeau ou sidecar) conservent leur appariement (même nom de base) après renommage à l'import. |
| 121 | - **SC-006**: Aucune écriture sur l'archive (création de dossier, ajout de fichiers) ne survient sans qu'un résumé de l'opération n'ait été présenté et explicitement confirmé par l'utilisateur. | 121 | - **SC-006**: Aucune écriture sur l'archive (création de dossier, ajout de fichiers) ne survient sans qu'un résumé de l'opération n'ait été présenté et explicitement confirmé par l'utilisateur. |
| 122 | - **SC-007**: Un utilisateur qui importe une carte couvrant un voyage en plusieurs étapes peut obtenir une structure à deux niveaux correctement rattachée sans avoir à renommer ou déplacer manuellement de dossier après l'import. | 122 | - **SC-007**: Un utilisateur qui importe une carte couvrant un voyage en plusieurs étapes peut obtenir une structure à deux niveaux correctement rattachée sans avoir à renommer ou déplacer manuellement de dossier après l'import. |
| 123 | +- **SC-008**: Le répertoire racine de destination (année ou catégorie thématique) est visible dans 100% des résumés présentés avant confirmation d'archivage (cf. `specs/004-categorisation-dossiers`). | ||
| 123 | 124 | ||
| 124 | ## Assumptions | 125 | ## Assumptions |
| 125 | 126 | ||
| @@ -129,3 +130,4 @@ Un photographe est en voyage sur plusieurs villes. Pour la deuxième étape, il | |||
| 129 | - Le mécanisme de checkout/réconciliation d'un dossier déjà archivé (utilisé au cas de fusion vers un dossier existant sur l'archive) est une capacité déjà disponible ou livrée avant ou avec ce module ; ce module ne redéfinit pas ce mécanisme, il s'appuie dessus. | 130 | - Le mécanisme de checkout/réconciliation d'un dossier déjà archivé (utilisé au cas de fusion vers un dossier existant sur l'archive) est une capacité déjà disponible ou livrée avant ou avec ce module ; ce module ne redéfinit pas ce mécanisme, il s'appuie dessus. |
| 130 | - La suggestion automatique de lieu par coordonnées GPS dépend de la présence de ces coordonnées dans les métadonnées du fichier ; en leur absence, l'utilisateur saisit le lieu librement, sans que cela bloque l'import. | 131 | - La suggestion automatique de lieu par coordonnées GPS dépend de la présence de ces coordonnées dans les métadonnées du fichier ; en leur absence, l'utilisateur saisit le lieu librement, sans que cela bloque l'import. |
| 131 | - Une seule carte mémoire est traitée à la fois par import ; l'import simultané de plusieurs cartes n'est pas couvert par ce module. | 132 | - Une seule carte mémoire est traitée à la fois par import ; l'import simultané de plusieurs cartes n'est pas couvert par ce module. |
| 133 | +- Le placement racine d'un dossier ou d'un dossier parent (répertoire d'année par défaut, ou répertoire de catégorie thématique) est défini par `specs/004-categorisation-dossiers`, que ce module ne redéfinit pas : il s'appuie dessus pour l'étape de destination (FR-007), la construction du chemin final (FR-010), la vérification de collision (FR-012) et le résumé de confirmation (FR-018). | ||
added
specs/004-categorisation-dossiers/checklists/requirements.md +41 -0 | new file mode 100644 | ||
| @@ -0,0 +1,41 @@ | ||
| 1 | +# Specification Quality Checklist: Catégorisation des dossiers à la racine de l'archive | |
| 2 | + | |
| 3 | +**Purpose**: Validate specification completeness and quality before proceeding to planning | |
| 4 | +**Created**: 2026-09-18 | |
| 5 | +**Feature**: [spec.md](../spec.md) | |
| 6 | + | |
| 7 | +## Content Quality | |
| 8 | + | |
| 9 | +- [x] No implementation details (languages, frameworks, APIs) | |
| 10 | +- [x] Focused on user value and business needs | |
| 11 | +- [x] Written for non-technical stakeholders | |
| 12 | +- [x] All mandatory sections completed | |
| 13 | + | |
| 14 | +## Requirement Completeness | |
| 15 | + | |
| 16 | +- [x] No [NEEDS CLARIFICATION] markers remain | |
| 17 | +- [x] Requirements are testable and unambiguous | |
| 18 | +- [x] Success criteria are measurable | |
| 19 | +- [x] Success criteria are technology-agnostic (no implementation details) | |
| 20 | +- [x] All acceptance scenarios are defined | |
| 21 | +- [x] Edge cases are identified | |
| 22 | +- [x] Scope is clearly bounded | |
| 23 | +- [x] Dependencies and assumptions identified | |
| 24 | + | |
| 25 | +## Feature Readiness | |
| 26 | + | |
| 27 | +- [x] All functional requirements have clear acceptance criteria | |
| 28 | +- [x] User scenarios cover primary flows | |
| 29 | +- [x] Feature meets measurable outcomes defined in Success Criteria | |
| 30 | +- [x] No implementation details leak into specification | |
| 31 | + | |
| 32 | +## Notes | |
| 33 | + | |
| 34 | +- Aucun marqueur [NEEDS CLARIFICATION] nécessaire : les 4 points d'ambiguïté identifiés en amont | |
| 35 | + (liste de catégories fixe ou extensible, granularité du choix pour un dossier parent, | |
| 36 | + recatégorisation a posteriori, sous-organisation par année dans une catégorie) ont été posés | |
| 37 | + directement à l'utilisateur avant la génération de la spec (voir conversation) plutôt que via | |
| 38 | + le mécanisme interne de `/speckit-specify` — réponses intégrées dès la première rédaction. | |
| 39 | +- Dépendance explicite vers `specs/001-import-photos` (à aligner séparément une fois cette spec | |
| 40 | + validée) et vers le mécanisme de réconciliation/déplacement par hash (notes de conception, | |
| 41 | + section 8), pas encore couvert par une spec dédiée — documentée en Assumptions. | |
| new file mode 100644 | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | +# Specification Quality Checklist: Catégorisation des dossiers à la racine de l'archive | ||
| 2 | + | ||
| 3 | +**Purpose**: Validate specification completeness and quality before proceeding to planning | ||
| 4 | +**Created**: 2026-09-18 | ||
| 5 | +**Feature**: [spec.md](../spec.md) | ||
| 6 | + | ||
| 7 | +## Content Quality | ||
| 8 | + | ||
| 9 | +- [x] No implementation details (languages, frameworks, APIs) | ||
| 10 | +- [x] Focused on user value and business needs | ||
| 11 | +- [x] Written for non-technical stakeholders | ||
| 12 | +- [x] All mandatory sections completed | ||
| 13 | + | ||
| 14 | +## Requirement Completeness | ||
| 15 | + | ||
| 16 | +- [x] No [NEEDS CLARIFICATION] markers remain | ||
| 17 | +- [x] Requirements are testable and unambiguous | ||
| 18 | +- [x] Success criteria are measurable | ||
| 19 | +- [x] Success criteria are technology-agnostic (no implementation details) | ||
| 20 | +- [x] All acceptance scenarios are defined | ||
| 21 | +- [x] Edge cases are identified | ||
| 22 | +- [x] Scope is clearly bounded | ||
| 23 | +- [x] Dependencies and assumptions identified | ||
| 24 | + | ||
| 25 | +## Feature Readiness | ||
| 26 | + | ||
| 27 | +- [x] All functional requirements have clear acceptance criteria | ||
| 28 | +- [x] User scenarios cover primary flows | ||
| 29 | +- [x] Feature meets measurable outcomes defined in Success Criteria | ||
| 30 | +- [x] No implementation details leak into specification | ||
| 31 | + | ||
| 32 | +## Notes | ||
| 33 | + | ||
| 34 | +- Aucun marqueur [NEEDS CLARIFICATION] nécessaire : les 4 points d'ambiguïté identifiés en amont | ||
| 35 | + (liste de catégories fixe ou extensible, granularité du choix pour un dossier parent, | ||
| 36 | + recatégorisation a posteriori, sous-organisation par année dans une catégorie) ont été posés | ||
| 37 | + directement à l'utilisateur avant la génération de la spec (voir conversation) plutôt que via | ||
| 38 | + le mécanisme interne de `/speckit-specify` — réponses intégrées dès la première rédaction. | ||
| 39 | +- Dépendance explicite vers `specs/001-import-photos` (à aligner séparément une fois cette spec | ||
| 40 | + validée) et vers le mécanisme de réconciliation/déplacement par hash (notes de conception, | ||
| 41 | + section 8), pas encore couvert par une spec dédiée — documentée en Assumptions. | ||
added
specs/004-categorisation-dossiers/spec.md +118 -0 | new file mode 100644 | ||
| @@ -0,0 +1,118 @@ | ||
| 1 | +# Feature Specification: Catégorisation des dossiers à la racine de l'archive | |
| 2 | + | |
| 3 | +**Feature Branch**: `[004-categorisation-dossiers]` | |
| 4 | + | |
| 5 | +**Created**: 2026-09-18 | |
| 6 | + | |
| 7 | +**Status**: Draft | |
| 8 | + | |
| 9 | +**Input**: User description: "Emplacement de premier niveau des dossiers à la racine de l'archive (NAS) et, en miroir, à la racine de l'espace de travail local : par défaut un répertoire d'année (ex. 2026/), ou pour certains dossiers relevant d'une catégorie thématique (mariage, vacances, voyage, anniversaire, extensible), directement un répertoire de catégorie à la racine, sans passer par l'année. Choix fait à l'import, une seule fois pour un dossier parent (hérité par ses sous-dossiers). Recatégorisation a posteriori couverte par la détection de déplacement par hash déjà en place. Répertoires de catégorie plats, pas de sous-organisation par année pour l'instant." | |
| 10 | + | |
| 11 | +## User Scenarios & Testing *(mandatory)* | |
| 12 | + | |
| 13 | +### User Story 1 - Import standard, placement par année par défaut (Priority: P1) | |
| 14 | + | |
| 15 | +Un photographe importe une carte mémoire pour une sortie ordinaire, sans lien avec un projet particulier. Sans rien choisir de spécial, le dossier résultant est rangé sous un répertoire portant le nom de son année, aussi bien dans l'archive NAS que dans l'espace de travail local. | |
| 16 | + | |
| 17 | +**Why this priority**: C'est le comportement par défaut qui doit continuer de fonctionner pour la majorité des imports ; sans lui, rien d'autre n'a de socle sur lequel s'appuyer. | |
| 18 | + | |
| 19 | +**Independent Test**: Peut être testé en import et une carte produisant un dossier simple d'une seule journée, sans sélectionner de catégorie, puis en vérifiant que le dossier apparaît sous `<racine>/AAAA/AAAA-MM-JJ_Titre/` aussi bien dans l'archive que dans l'espace de travail local. | |
| 20 | + | |
| 21 | +**Acceptance Scenarios**: | |
| 22 | + | |
| 23 | +1. **Given** un groupe d'import ne relevant d'aucune catégorie thématique, **When** l'utilisateur valide sa destination sans choisir de catégorie, **Then** le dossier résultant est placé sous un répertoire portant le nom de son année, à la racine de l'archive. | |
| 24 | +2. **Given** ce même dossier archivé sous un répertoire d'année, **When** l'utilisateur en fait un checkout, **Then** l'espace de travail local reproduit le même chemin relatif (répertoire d'année puis dossier), pas seulement le nom du dossier. | |
| 25 | + | |
| 26 | +--- | |
| 27 | + | |
| 28 | +### User Story 2 - Import relevant d'une catégorie thématique (Priority: P2) | |
| 29 | + | |
| 30 | +Un photographe importe les photos d'un mariage (ou de vacances, d'un voyage simple, d'un anniversaire). Au moment de choisir la destination du groupe, il indique la catégorie concernée : le dossier résultant est rangé directement sous un répertoire portant le nom de cette catégorie, à la racine de l'archive, sans passer par un répertoire d'année. | |
| 31 | + | |
| 32 | +**Why this priority**: C'est la valeur centrale de la fonctionnalité — regrouper les projets thématiques indépendamment de leur année, pour les retrouver facilement (tous les mariages ensemble, tous les voyages ensemble). Dépend du fonctionnement de base (P1) mais ne se limite pas à un raffinement cosmétique. | |
| 33 | + | |
| 34 | +**Independent Test**: Peut être testé en import et une carte, en choisissant la catégorie "mariage" pour le groupe résultant, puis en vérifiant que le dossier apparaît sous `<racine>/mariage/AAAA-MM-JJ_Titre/` — jamais sous un répertoire d'année — aussi bien dans l'archive que dans l'espace de travail local. | |
| 35 | + | |
| 36 | +**Acceptance Scenarios**: | |
| 37 | + | |
| 38 | +1. **Given** un groupe d'import à l'étape de choix de destination, **When** l'utilisateur indique qu'il relève d'une catégorie thématique et en choisit une (parmi les catégories déjà utilisées ou une nouvelle), **Then** le dossier résultant est placé directement sous un répertoire portant le nom de cette catégorie, à la racine de l'archive, sans répertoire d'année intermédiaire. | |
| 39 | +2. **Given** une catégorie jamais utilisée auparavant (ex. "exposition"), **When** l'utilisateur la saisit librement à ce moment, **Then** Régine crée le répertoire de catégorie correspondant sans nécessiter de modification du logiciel ni de configuration préalable. | |
| 40 | +3. **Given** un événement qui pourrait relever de plusieurs catégories à la fois (ex. un mariage pendant un voyage), **When** l'utilisateur choisit sa destination, **Then** il ne peut sélectionner qu'une seule catégorie ; Régine ne propose ni ne devine jamais une double catégorisation. | |
| 41 | + | |
| 42 | +--- | |
| 43 | + | |
| 44 | +### User Story 3 - Héritage de la catégorie par les sous-dossiers d'un voyage (Priority: P3) | |
| 45 | + | |
| 46 | +Un photographe est en voyage sur plusieurs étapes, catégorisé "voyage" dès le premier import qui crée le dossier parent. Pour les étapes suivantes, il importe de nouvelles cartes comme sous-dossiers de ce même dossier parent : la catégorie n'est pas redemandée, chaque étape hérite automatiquement du placement choisi au départ. | |
| 47 | + | |
| 48 | +**Why this priority**: Raffine le cas déjà couvert par `specs/001-import-photos` (User Story 3, import multi-étapes) avec la dimension catégorie ; reste secondaire par rapport à P1/P2 puisqu'il ne concerne que les imports en plusieurs étapes. | |
| 49 | + | |
| 50 | +**Independent Test**: Peut être testé en import et une première carte comme "nouveau dossier parent avec sa première étape" en choisissant la catégorie "voyage", puis en import et une seconde carte comme nouveau sous-dossier de ce même parent, et en vérifiant que le sous-dossier apparaît sous `<racine>/voyage/AAAA-MM_Titre/AAAA-MM-JJ_Titre_Lieu/` sans qu'aucune question de catégorie ne soit reposée. | |
| 51 | + | |
| 52 | +**Acceptance Scenarios**: | |
| 53 | + | |
| 54 | +1. **Given** un dossier parent créé avec une catégorie donnée (ou sans catégorie, donc sous une année) lors du premier import qui l'a fait naître, **When** l'utilisateur importe une carte supplémentaire et choisit "nouveau sous-dossier dans un dossier parent existant" pour ce même parent, **Then** le sous-dossier résultant hérite automatiquement du même placement racine (catégorie ou année), sans que la question ne soit reposée. | |
| 55 | +2. **Given** un dossier parent sous une catégorie, **When** l'utilisateur consulte sa structure complète (parent + sous-dossiers), **Then** l'ensemble vit sous le même répertoire de catégorie, cohérent avec la racine du dossier parent servant de planche-contact globale (déjà définie dans les notes de conception). | |
| 56 | + | |
| 57 | +--- | |
| 58 | + | |
| 59 | +### User Story 4 - Recatégorisation a posteriori (Priority: P4) | |
| 60 | + | |
| 61 | +Un photographe se rend compte, après coup, qu'un dossier rangé par erreur sous une année aurait dû rejoindre une catégorie thématique (ou inversement). Il déplace le dossier vers le bon emplacement racine ; Régine reconnaît ce déplacement comme tel plutôt que comme une anomalie, grâce au mécanisme de détection par contenu déjà en place. | |
| 62 | + | |
| 63 | +**Why this priority**: Cas de correction, moins fréquent que les trois précédents, mais nécessaire pour que la catégorisation ne soit pas une décision figée de façon irréversible dès l'import. | |
| 64 | + | |
| 65 | +**Independent Test**: Peut être testé en déplaçant, dans l'espace de travail local, un dossier déjà archivé sous un répertoire d'année vers un répertoire de catégorie, puis en réconciliant : le déplacement doit être détecté par somme de contrôle (contenu inchangé, chemin différent), jamais signalé comme une anomalie de fichier maître modifié. | |
| 66 | + | |
| 67 | +**Acceptance Scenarios**: | |
| 68 | + | |
| 69 | +1. **Given** un dossier déjà archivé sous un répertoire d'année, **When** l'utilisateur le déplace vers un répertoire de catégorie dans sa copie de travail et réconcilie, **Then** Régine détecte ce déplacement par somme de contrôle de contenu inchangé et met à jour l'emplacement dans l'archive en conséquence, sans le traiter comme une anomalie. | |
| 70 | +2. **Given** ce même mécanisme, **When** le déplacement se fait dans l'autre sens (catégorie vers année) ou d'une catégorie vers une autre, **Then** il est traité de façon identique, sans mécanisme dédié supplémentaire. | |
| 71 | + | |
| 72 | +--- | |
| 73 | + | |
| 74 | +### Edge Cases | |
| 75 | + | |
| 76 | +- Que se passe-t-il si l'utilisateur ne choisit aucune catégorie particulière ? Le dossier est placé par défaut sous un répertoire d'année (comportement de User Story 1). | |
| 77 | +- Que se passe-t-il si l'utilisateur saisit un nom de catégorie proche d'une catégorie déjà utilisée mais orthographié différemment (ex. "Mariage" vs "mariage") ? Régine DOIT proposer les catégories déjà utilisées comme suggestions au moment de la saisie, pour limiter le risque de créer deux répertoires de catégorie équivalents par erreur. | |
| 78 | +- Que se passe-t-il si le répertoire de la catégorie choisie n'existe pas encore à la racine de l'archive ? Régine DOIT le créer, selon la même logique que la création de répertoires déjà prévue pour l'import (pas de confirmation distincte au-delà de la confirmation d'archivage déjà prévue). | |
| 79 | +- Que se passe-t-il si l'utilisateur choisit "fusion dans un dossier existant" (cf. `specs/001-import-photos`) pour un dossier déjà catégorisé ? Le placement racine du dossier ciblé ne change pas ; les nouveaux fichiers rejoignent l'emplacement déjà en place. | |
| 80 | + | |
| 81 | +## Requirements *(mandatory)* | |
| 82 | + | |
| 83 | +### Functional Requirements | |
| 84 | + | |
| 85 | +- **FR-001**: À l'étape de choix de la destination de chaque groupe (déjà définie dans `specs/001-import-photos`), le système DOIT demander en plus si ce groupe relève d'une catégorie thématique ou s'il doit suivre le placement par défaut (par année). | |
| 86 | +- **FR-002**: Par défaut, en l'absence de catégorie choisie, le système DOIT placer le dossier ou dossier parent résultant sous un répertoire portant le nom de son année, à la racine de l'archive et, en miroir, à la racine de l'espace de travail local. | |
| 87 | +- **FR-003**: Lorsqu'une catégorie thématique est choisie pour un dossier ou un dossier parent, le système DOIT le placer directement sous un répertoire portant le nom de cette catégorie, à la racine de l'archive et de l'espace de travail local, sans passer par un répertoire d'année. | |
| 88 | +- **FR-004**: Le système DOIT proposer au minimum les catégories mariage, vacances, voyage et anniversaire comme suggestions, tout en permettant à l'utilisateur de déclarer librement une nouvelle catégorie au moment du choix, sans modification du logiciel ni configuration préalable. | |
| 89 | +- **FR-005**: Un dossier ou dossier parent ne DOIT jamais se voir attribuer plus d'une catégorie à la fois ; le système ne DOIT jamais deviner ou assigner automatiquement une catégorie — le choix (catégorie ou année par défaut) reste toujours une décision explicite de l'utilisateur. | |
| 90 | +- **FR-006**: Pour un dossier parent, le placement racine (catégorie ou année) choisi lors du premier import qui le crée DOIT être traité comme une propriété de ce dossier de plus haut niveau ; tout sous-dossier ajouté ultérieurement à ce même parent DOIT hériter automatiquement de ce placement, sans que la question ne soit reposée. | |
| 91 | +- **FR-007**: Le mécanisme de checkout DOIT conserver et reproduire le chemin relatif complet d'un dossier par rapport à la racine (répertoire d'année ou de catégorie), pas seulement le nom du dossier lui-même. | |
| 92 | +- **FR-008**: Un déplacement d'un dossier existant d'un répertoire d'année vers un répertoire de catégorie, ou inversement, ou d'une catégorie vers une autre, DOIT être reconnu par le mécanisme existant de détection de déplacement par somme de contrôle de contenu, sans nécessiter de mécanisme de recatégorisation dédié. | |
| 93 | +- **FR-009**: Les répertoires de catégorie à la racine de l'archive DOIVENT rester plats (aucune sous-organisation par année à l'intérieur) pour cette itération. | |
| 94 | +- **FR-010**: Le résumé présenté à l'utilisateur avant toute écriture sur l'archive (cf. confirmation explicite déjà requise) DOIT afficher explicitement le répertoire racine de destination (nom de l'année ou de la catégorie), pour que l'utilisateur puisse le vérifier avant de confirmer. | |
| 95 | + | |
| 96 | +### Key Entities | |
| 97 | + | |
| 98 | +- **Catégorie thématique** : nom libre choisi par l'utilisateur (ex. mariage, vacances, voyage, anniversaire, ou tout autre nom déclaré), servant de répertoire racine alternatif au répertoire d'année. Liste extensible, jamais figée. | |
| 99 | +- **Répertoire racine (archive)** : premier niveau sous lequel vit un dossier ou un dossier parent, à la racine de l'archive et de l'espace de travail local — soit un répertoire d'année (`AAAA`), soit un répertoire de catégorie. Un dossier ou dossier parent en a exactement un. À ne pas confondre avec la **racine** de sélection à l'intérieur d'un dossier (cf. `docs/lexique.md`). | |
| 100 | +- **Dossier / Dossier parent** (repris de `specs/001-import-photos` et `docs/lexique.md`, non redéfinis ici) : hérite d'un répertoire racine (archive) unique, choisi à sa création et conservé jusqu'à un éventuel déplacement explicite. | |
| 101 | + | |
| 102 | +## Success Criteria *(mandatory)* | |
| 103 | + | |
| 104 | +### Measurable Outcomes | |
| 105 | + | |
| 106 | +- **SC-001**: 100% des dossiers importés sans catégorie choisie sont placés sous un répertoire d'année, identique dans l'archive et dans l'espace de travail local. | |
| 107 | +- **SC-002**: 100% des dossiers pour lesquels une catégorie est choisie sont placés directement sous le répertoire de cette catégorie, sans jamais passer par un répertoire d'année. | |
| 108 | +- **SC-003**: Un utilisateur peut créer et utiliser une catégorie jamais rencontrée auparavant sans aucune modification du logiciel. | |
| 109 | +- **SC-004**: 100% des sous-dossiers ajoutés ultérieurement à un dossier parent existant héritent du placement racine choisi à la création du parent, sans qu'aucune nouvelle question ne soit posée. | |
| 110 | +- **SC-005**: 100% des déplacements d'un dossier entre un répertoire d'année et un répertoire de catégorie (dans un sens ou dans l'autre) sont détectés comme des déplacements de contenu inchangé, jamais comme des anomalies de fichier maître modifié. | |
| 111 | +- **SC-006**: Le répertoire racine de destination (année ou catégorie) est visible dans 100% des résumés présentés avant une écriture sur l'archive. | |
| 112 | + | |
| 113 | +## Assumptions | |
| 114 | + | |
| 115 | +- Cette spécification étend `specs/001-import-photos` (étape "destination de chaque groupe" et nommage/archivage du dossier) : une fois validée, `specs/001-import-photos` devra être alignée pour inclure cette question de placement racine dans son propre flux — mise à jour à faire séparément, pas incluse dans cette spécification. | |
| 116 | +- Le mécanisme de détection de déplacement par somme de contrôle de contenu et de réconciliation lors d'un checkout (notes de conception, section 8) est supposé disponible indépendamment de cette spécification ; FR-008 s'appuie dessus sans le redéfinir. | |
| 117 | +- Les conventions déjà spécifiées pour le nom du dossier lui-même (`AAAA-MM-JJ_Titre` etc.), sa structure interne par format et sa racine de sélection (`docs/archivage-photo-elements-cles.md` sections 9-10, `specs/001-import-photos`) restent inchangées ; cette spécification ajoute uniquement le niveau racine (année ou catégorie) au-dessus de ces conventions. | |
| 118 | +- Une catégorie est un simple nom de répertoire choisi par l'utilisateur ; Régine n'effectue aucune validation métier de ce qui "compte" comme un mariage ou un voyage, au-delà du nettoyage de nom déjà prévu pour tout nom de dossier (espaces, caractères interdits). | |
| new file mode 100644 | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | +# Feature Specification: Catégorisation des dossiers à la racine de l'archive | ||
| 2 | + | ||
| 3 | +**Feature Branch**: `[004-categorisation-dossiers]` | ||
| 4 | + | ||
| 5 | +**Created**: 2026-09-18 | ||
| 6 | + | ||
| 7 | +**Status**: Draft | ||
| 8 | + | ||
| 9 | +**Input**: User description: "Emplacement de premier niveau des dossiers à la racine de l'archive (NAS) et, en miroir, à la racine de l'espace de travail local : par défaut un répertoire d'année (ex. 2026/), ou pour certains dossiers relevant d'une catégorie thématique (mariage, vacances, voyage, anniversaire, extensible), directement un répertoire de catégorie à la racine, sans passer par l'année. Choix fait à l'import, une seule fois pour un dossier parent (hérité par ses sous-dossiers). Recatégorisation a posteriori couverte par la détection de déplacement par hash déjà en place. Répertoires de catégorie plats, pas de sous-organisation par année pour l'instant." | ||
| 10 | + | ||
| 11 | +## User Scenarios & Testing *(mandatory)* | ||
| 12 | + | ||
| 13 | +### User Story 1 - Import standard, placement par année par défaut (Priority: P1) | ||
| 14 | + | ||
| 15 | +Un photographe importe une carte mémoire pour une sortie ordinaire, sans lien avec un projet particulier. Sans rien choisir de spécial, le dossier résultant est rangé sous un répertoire portant le nom de son année, aussi bien dans l'archive NAS que dans l'espace de travail local. | ||
| 16 | + | ||
| 17 | +**Why this priority**: C'est le comportement par défaut qui doit continuer de fonctionner pour la majorité des imports ; sans lui, rien d'autre n'a de socle sur lequel s'appuyer. | ||
| 18 | + | ||
| 19 | +**Independent Test**: Peut être testé en import et une carte produisant un dossier simple d'une seule journée, sans sélectionner de catégorie, puis en vérifiant que le dossier apparaît sous `<racine>/AAAA/AAAA-MM-JJ_Titre/` aussi bien dans l'archive que dans l'espace de travail local. | ||
| 20 | + | ||
| 21 | +**Acceptance Scenarios**: | ||
| 22 | + | ||
| 23 | +1. **Given** un groupe d'import ne relevant d'aucune catégorie thématique, **When** l'utilisateur valide sa destination sans choisir de catégorie, **Then** le dossier résultant est placé sous un répertoire portant le nom de son année, à la racine de l'archive. | ||
| 24 | +2. **Given** ce même dossier archivé sous un répertoire d'année, **When** l'utilisateur en fait un checkout, **Then** l'espace de travail local reproduit le même chemin relatif (répertoire d'année puis dossier), pas seulement le nom du dossier. | ||
| 25 | + | ||
| 26 | +--- | ||
| 27 | + | ||
| 28 | +### User Story 2 - Import relevant d'une catégorie thématique (Priority: P2) | ||
| 29 | + | ||
| 30 | +Un photographe importe les photos d'un mariage (ou de vacances, d'un voyage simple, d'un anniversaire). Au moment de choisir la destination du groupe, il indique la catégorie concernée : le dossier résultant est rangé directement sous un répertoire portant le nom de cette catégorie, à la racine de l'archive, sans passer par un répertoire d'année. | ||
| 31 | + | ||
| 32 | +**Why this priority**: C'est la valeur centrale de la fonctionnalité — regrouper les projets thématiques indépendamment de leur année, pour les retrouver facilement (tous les mariages ensemble, tous les voyages ensemble). Dépend du fonctionnement de base (P1) mais ne se limite pas à un raffinement cosmétique. | ||
| 33 | + | ||
| 34 | +**Independent Test**: Peut être testé en import et une carte, en choisissant la catégorie "mariage" pour le groupe résultant, puis en vérifiant que le dossier apparaît sous `<racine>/mariage/AAAA-MM-JJ_Titre/` — jamais sous un répertoire d'année — aussi bien dans l'archive que dans l'espace de travail local. | ||
| 35 | + | ||
| 36 | +**Acceptance Scenarios**: | ||
| 37 | + | ||
| 38 | +1. **Given** un groupe d'import à l'étape de choix de destination, **When** l'utilisateur indique qu'il relève d'une catégorie thématique et en choisit une (parmi les catégories déjà utilisées ou une nouvelle), **Then** le dossier résultant est placé directement sous un répertoire portant le nom de cette catégorie, à la racine de l'archive, sans répertoire d'année intermédiaire. | ||
| 39 | +2. **Given** une catégorie jamais utilisée auparavant (ex. "exposition"), **When** l'utilisateur la saisit librement à ce moment, **Then** Régine crée le répertoire de catégorie correspondant sans nécessiter de modification du logiciel ni de configuration préalable. | ||
| 40 | +3. **Given** un événement qui pourrait relever de plusieurs catégories à la fois (ex. un mariage pendant un voyage), **When** l'utilisateur choisit sa destination, **Then** il ne peut sélectionner qu'une seule catégorie ; Régine ne propose ni ne devine jamais une double catégorisation. | ||
| 41 | + | ||
| 42 | +--- | ||
| 43 | + | ||
| 44 | +### User Story 3 - Héritage de la catégorie par les sous-dossiers d'un voyage (Priority: P3) | ||
| 45 | + | ||
| 46 | +Un photographe est en voyage sur plusieurs étapes, catégorisé "voyage" dès le premier import qui crée le dossier parent. Pour les étapes suivantes, il importe de nouvelles cartes comme sous-dossiers de ce même dossier parent : la catégorie n'est pas redemandée, chaque étape hérite automatiquement du placement choisi au départ. | ||
| 47 | + | ||
| 48 | +**Why this priority**: Raffine le cas déjà couvert par `specs/001-import-photos` (User Story 3, import multi-étapes) avec la dimension catégorie ; reste secondaire par rapport à P1/P2 puisqu'il ne concerne que les imports en plusieurs étapes. | ||
| 49 | + | ||
| 50 | +**Independent Test**: Peut être testé en import et une première carte comme "nouveau dossier parent avec sa première étape" en choisissant la catégorie "voyage", puis en import et une seconde carte comme nouveau sous-dossier de ce même parent, et en vérifiant que le sous-dossier apparaît sous `<racine>/voyage/AAAA-MM_Titre/AAAA-MM-JJ_Titre_Lieu/` sans qu'aucune question de catégorie ne soit reposée. | ||
| 51 | + | ||
| 52 | +**Acceptance Scenarios**: | ||
| 53 | + | ||
| 54 | +1. **Given** un dossier parent créé avec une catégorie donnée (ou sans catégorie, donc sous une année) lors du premier import qui l'a fait naître, **When** l'utilisateur importe une carte supplémentaire et choisit "nouveau sous-dossier dans un dossier parent existant" pour ce même parent, **Then** le sous-dossier résultant hérite automatiquement du même placement racine (catégorie ou année), sans que la question ne soit reposée. | ||
| 55 | +2. **Given** un dossier parent sous une catégorie, **When** l'utilisateur consulte sa structure complète (parent + sous-dossiers), **Then** l'ensemble vit sous le même répertoire de catégorie, cohérent avec la racine du dossier parent servant de planche-contact globale (déjà définie dans les notes de conception). | ||
| 56 | + | ||
| 57 | +--- | ||
| 58 | + | ||
| 59 | +### User Story 4 - Recatégorisation a posteriori (Priority: P4) | ||
| 60 | + | ||
| 61 | +Un photographe se rend compte, après coup, qu'un dossier rangé par erreur sous une année aurait dû rejoindre une catégorie thématique (ou inversement). Il déplace le dossier vers le bon emplacement racine ; Régine reconnaît ce déplacement comme tel plutôt que comme une anomalie, grâce au mécanisme de détection par contenu déjà en place. | ||
| 62 | + | ||
| 63 | +**Why this priority**: Cas de correction, moins fréquent que les trois précédents, mais nécessaire pour que la catégorisation ne soit pas une décision figée de façon irréversible dès l'import. | ||
| 64 | + | ||
| 65 | +**Independent Test**: Peut être testé en déplaçant, dans l'espace de travail local, un dossier déjà archivé sous un répertoire d'année vers un répertoire de catégorie, puis en réconciliant : le déplacement doit être détecté par somme de contrôle (contenu inchangé, chemin différent), jamais signalé comme une anomalie de fichier maître modifié. | ||
| 66 | + | ||
| 67 | +**Acceptance Scenarios**: | ||
| 68 | + | ||
| 69 | +1. **Given** un dossier déjà archivé sous un répertoire d'année, **When** l'utilisateur le déplace vers un répertoire de catégorie dans sa copie de travail et réconcilie, **Then** Régine détecte ce déplacement par somme de contrôle de contenu inchangé et met à jour l'emplacement dans l'archive en conséquence, sans le traiter comme une anomalie. | ||
| 70 | +2. **Given** ce même mécanisme, **When** le déplacement se fait dans l'autre sens (catégorie vers année) ou d'une catégorie vers une autre, **Then** il est traité de façon identique, sans mécanisme dédié supplémentaire. | ||
| 71 | + | ||
| 72 | +--- | ||
| 73 | + | ||
| 74 | +### Edge Cases | ||
| 75 | + | ||
| 76 | +- Que se passe-t-il si l'utilisateur ne choisit aucune catégorie particulière ? Le dossier est placé par défaut sous un répertoire d'année (comportement de User Story 1). | ||
| 77 | +- Que se passe-t-il si l'utilisateur saisit un nom de catégorie proche d'une catégorie déjà utilisée mais orthographié différemment (ex. "Mariage" vs "mariage") ? Régine DOIT proposer les catégories déjà utilisées comme suggestions au moment de la saisie, pour limiter le risque de créer deux répertoires de catégorie équivalents par erreur. | ||
| 78 | +- Que se passe-t-il si le répertoire de la catégorie choisie n'existe pas encore à la racine de l'archive ? Régine DOIT le créer, selon la même logique que la création de répertoires déjà prévue pour l'import (pas de confirmation distincte au-delà de la confirmation d'archivage déjà prévue). | ||
| 79 | +- Que se passe-t-il si l'utilisateur choisit "fusion dans un dossier existant" (cf. `specs/001-import-photos`) pour un dossier déjà catégorisé ? Le placement racine du dossier ciblé ne change pas ; les nouveaux fichiers rejoignent l'emplacement déjà en place. | ||
| 80 | + | ||
| 81 | +## Requirements *(mandatory)* | ||
| 82 | + | ||
| 83 | +### Functional Requirements | ||
| 84 | + | ||
| 85 | +- **FR-001**: À l'étape de choix de la destination de chaque groupe (déjà définie dans `specs/001-import-photos`), le système DOIT demander en plus si ce groupe relève d'une catégorie thématique ou s'il doit suivre le placement par défaut (par année). | ||
| 86 | +- **FR-002**: Par défaut, en l'absence de catégorie choisie, le système DOIT placer le dossier ou dossier parent résultant sous un répertoire portant le nom de son année, à la racine de l'archive et, en miroir, à la racine de l'espace de travail local. | ||
| 87 | +- **FR-003**: Lorsqu'une catégorie thématique est choisie pour un dossier ou un dossier parent, le système DOIT le placer directement sous un répertoire portant le nom de cette catégorie, à la racine de l'archive et de l'espace de travail local, sans passer par un répertoire d'année. | ||
| 88 | +- **FR-004**: Le système DOIT proposer au minimum les catégories mariage, vacances, voyage et anniversaire comme suggestions, tout en permettant à l'utilisateur de déclarer librement une nouvelle catégorie au moment du choix, sans modification du logiciel ni configuration préalable. | ||
| 89 | +- **FR-005**: Un dossier ou dossier parent ne DOIT jamais se voir attribuer plus d'une catégorie à la fois ; le système ne DOIT jamais deviner ou assigner automatiquement une catégorie — le choix (catégorie ou année par défaut) reste toujours une décision explicite de l'utilisateur. | ||
| 90 | +- **FR-006**: Pour un dossier parent, le placement racine (catégorie ou année) choisi lors du premier import qui le crée DOIT être traité comme une propriété de ce dossier de plus haut niveau ; tout sous-dossier ajouté ultérieurement à ce même parent DOIT hériter automatiquement de ce placement, sans que la question ne soit reposée. | ||
| 91 | +- **FR-007**: Le mécanisme de checkout DOIT conserver et reproduire le chemin relatif complet d'un dossier par rapport à la racine (répertoire d'année ou de catégorie), pas seulement le nom du dossier lui-même. | ||
| 92 | +- **FR-008**: Un déplacement d'un dossier existant d'un répertoire d'année vers un répertoire de catégorie, ou inversement, ou d'une catégorie vers une autre, DOIT être reconnu par le mécanisme existant de détection de déplacement par somme de contrôle de contenu, sans nécessiter de mécanisme de recatégorisation dédié. | ||
| 93 | +- **FR-009**: Les répertoires de catégorie à la racine de l'archive DOIVENT rester plats (aucune sous-organisation par année à l'intérieur) pour cette itération. | ||
| 94 | +- **FR-010**: Le résumé présenté à l'utilisateur avant toute écriture sur l'archive (cf. confirmation explicite déjà requise) DOIT afficher explicitement le répertoire racine de destination (nom de l'année ou de la catégorie), pour que l'utilisateur puisse le vérifier avant de confirmer. | ||
| 95 | + | ||
| 96 | +### Key Entities | ||
| 97 | + | ||
| 98 | +- **Catégorie thématique** : nom libre choisi par l'utilisateur (ex. mariage, vacances, voyage, anniversaire, ou tout autre nom déclaré), servant de répertoire racine alternatif au répertoire d'année. Liste extensible, jamais figée. | ||
| 99 | +- **Répertoire racine (archive)** : premier niveau sous lequel vit un dossier ou un dossier parent, à la racine de l'archive et de l'espace de travail local — soit un répertoire d'année (`AAAA`), soit un répertoire de catégorie. Un dossier ou dossier parent en a exactement un. À ne pas confondre avec la **racine** de sélection à l'intérieur d'un dossier (cf. `docs/lexique.md`). | ||
| 100 | +- **Dossier / Dossier parent** (repris de `specs/001-import-photos` et `docs/lexique.md`, non redéfinis ici) : hérite d'un répertoire racine (archive) unique, choisi à sa création et conservé jusqu'à un éventuel déplacement explicite. | ||
| 101 | + | ||
| 102 | +## Success Criteria *(mandatory)* | ||
| 103 | + | ||
| 104 | +### Measurable Outcomes | ||
| 105 | + | ||
| 106 | +- **SC-001**: 100% des dossiers importés sans catégorie choisie sont placés sous un répertoire d'année, identique dans l'archive et dans l'espace de travail local. | ||
| 107 | +- **SC-002**: 100% des dossiers pour lesquels une catégorie est choisie sont placés directement sous le répertoire de cette catégorie, sans jamais passer par un répertoire d'année. | ||
| 108 | +- **SC-003**: Un utilisateur peut créer et utiliser une catégorie jamais rencontrée auparavant sans aucune modification du logiciel. | ||
| 109 | +- **SC-004**: 100% des sous-dossiers ajoutés ultérieurement à un dossier parent existant héritent du placement racine choisi à la création du parent, sans qu'aucune nouvelle question ne soit posée. | ||
| 110 | +- **SC-005**: 100% des déplacements d'un dossier entre un répertoire d'année et un répertoire de catégorie (dans un sens ou dans l'autre) sont détectés comme des déplacements de contenu inchangé, jamais comme des anomalies de fichier maître modifié. | ||
| 111 | +- **SC-006**: Le répertoire racine de destination (année ou catégorie) est visible dans 100% des résumés présentés avant une écriture sur l'archive. | ||
| 112 | + | ||
| 113 | +## Assumptions | ||
| 114 | + | ||
| 115 | +- Cette spécification étend `specs/001-import-photos` (étape "destination de chaque groupe" et nommage/archivage du dossier) : une fois validée, `specs/001-import-photos` devra être alignée pour inclure cette question de placement racine dans son propre flux — mise à jour à faire séparément, pas incluse dans cette spécification. | ||
| 116 | +- Le mécanisme de détection de déplacement par somme de contrôle de contenu et de réconciliation lors d'un checkout (notes de conception, section 8) est supposé disponible indépendamment de cette spécification ; FR-008 s'appuie dessus sans le redéfinir. | ||
| 117 | +- Les conventions déjà spécifiées pour le nom du dossier lui-même (`AAAA-MM-JJ_Titre` etc.), sa structure interne par format et sa racine de sélection (`docs/archivage-photo-elements-cles.md` sections 9-10, `specs/001-import-photos`) restent inchangées ; cette spécification ajoute uniquement le niveau racine (année ou catégorie) au-dessus de ces conventions. | ||
| 118 | +- Une catégorie est un simple nom de répertoire choisi par l'utilisateur ; Régine n'effectue aucune validation métier de ce qui "compte" comme un mariage ou un voyage, au-delà du nettoyage de nom déjà prévu pour tout nom de dossier (espaces, caractères interdits). | ||