diff --git a/docs/tickets/closed/TICKET-001.md b/docs/tickets/closed/TICKET-001.md deleted file mode 100644 index 3edd3d3..0000000 --- a/docs/tickets/closed/TICKET-001.md +++ /dev/null @@ -1,37 +0,0 @@ -# Ticket #001 - -## Titre - -Créer le module Application. - -## Objectif - -Créer le point d’entrée applicatif chargé de gérer le cycle de vie de GTK. - -## Responsabilités - -- créer l’objet GtkApplication ; -- lancer la boucle principale GTK ; -- libérer proprement les ressources ; -- afficher une fenêtre minimale au signal `activate`. - -## Hors périmètre - -- SQLite ; -- ouverture d’une enquête ; -- sélecteur de dossier ; -- logique métier. - -## Critères d’acceptation - -- [ ] Le projet compile en C17. -- [ ] Aucun warning. -- [ ] Aucun état global. -- [ ] Les fonctions publiques sont documentées avec Doxygen. -- [ ] Une fenêtre GTK minimale s’affiche. -- [ ] La fermeture de l’application est propre. - -## Commit attendu - -```text -feat(core): create application lifecycle diff --git a/docs/tickets/closed/TICKET-002.md b/docs/tickets/closed/TICKET-002.md deleted file mode 100644 index 9c2aa82..0000000 --- a/docs/tickets/closed/TICKET-002.md +++ /dev/null @@ -1,38 +0,0 @@ -# Ticket #002 - -## Titre - -Ajouter le sélecteur de dossier d’enquête. - -## Objectif - -Permettre à l’utilisateur de sélectionner un dossier d’enquête au lancement de l’application. - -## Responsabilités - -- afficher un dialogue GTK de sélection de dossier ; -- retourner le dossier sélectionné ; -- gérer l’annulation sans erreur ; -- transmettre le chemin au module Application. - -## Hors périmètre - -- création de `00_BaseDeDonnees` ; -- ouverture de SQLite ; -- initialisation du schéma ; -- validation complète d’une enquête. - -## Critères d’acceptation - -- [ ] Le dialogue s’ouvre au lancement. -- [ ] Un dossier peut être sélectionné. -- [ ] L’annulation est gérée proprement. -- [ ] Le chemin sélectionné est affiché dans la fenêtre. -- [ ] Aucun warning. -- [ ] Les fonctions publiques sont documentées. -- [ ] Aucun état global. - -## Commit attendu - -```text -feat(gui): add investigation folder selector diff --git a/docs/tickets/closed/TICKET-003.md b/docs/tickets/closed/TICKET-003.md deleted file mode 100644 index 413bf29..0000000 --- a/docs/tickets/closed/TICKET-003.md +++ /dev/null @@ -1,57 +0,0 @@ -# Ticket #003 - -## Titre - -Créer le module `Investigation`. - -## Objectif - -Créer l'objet métier représentant une enquête ouverte par Labfy Investigation. - -Le module doit rester indépendant de GTK et de l'interface graphique. - -## Responsabilités - -Le module doit : - -- mémoriser le chemin racine de l'enquête ; -- construire le chemin de la base de données modèle ; -- exposer ces chemins en lecture seule ; -- gérer proprement sa mémoire ; -- vérifier qu'un chemin d'enquête est exploitable. - -## Hors périmètre - -Ce ticket ne doit pas : - -- ouvrir SQLite ; -- créer la base de données ; -- modifier l'arborescence de l'enquête ; -- afficher de message GTK ; -- gérer les preuves ou les entités. - -## Dépendances - -- libc ; -- GLib uniquement si nécessaire pour la gestion des chaînes et chemins. - -Aucune dépendance GTK ou SQLite. - -## API attendue - -Le module doit permettre un usage proche de : - -```c -Investigation *investigation = NULL; - -investigation = investigation_new("/chemin/vers/enquete"); - -if (investigation == NULL) -{ - /* Gestion de l'erreur */ -} - -const char *root_path = investigation_get_root_path(investigation); -const char *database_path = investigation_get_database_path(investigation); - -investigation_free(investigation); diff --git a/docs/tickets/closed/TICKET-004.md b/docs/tickets/closed/TICKET-004.md deleted file mode 100644 index c390f8d..0000000 --- a/docs/tickets/closed/TICKET-004.md +++ /dev/null @@ -1,128 +0,0 @@ -# Ticket #004 - -## Titre - -Créer la fenêtre principale (`MainWindow`). - ---- - -## Objectif - -Créer la fenêtre principale de Labfy Investigation. - -Cette fenêtre deviendra le point central de l'interface utilisateur. - -À ce stade, elle ne contient qu'une structure vide destinée à accueillir les futurs composants. - ---- - -## Responsabilités - -Le module `MainWindow` doit : - -- créer la fenêtre principale ; -- définir son titre ; -- définir sa taille par défaut ; -- afficher une zone centrale vide ; -- afficher une barre d'état. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- afficher l'arborescence des fichiers ; -- ouvrir une enquête ; -- afficher les preuves ; -- communiquer avec SQLite ; -- gérer les menus. - ---- - -## Architecture - -Le module appartient à la couche **Views**. - -Il est responsable uniquement de l'interface graphique. - -Aucune logique métier ne doit être présente dans ce module. - ---- - -## Dépendances - -- GTK4 - -Aucune dépendance vers SQLite. - ---- - -## Fichiers concernés - -```text -include/views/main_window.h -src/views/main_window.c -``` - ---- - -## Interface attendue - -```c -MainWindow *main_window_new(GtkApplication *application); - -GtkWindow *main_window_get_window( - const MainWindow *main_window -); - -void main_window_present(MainWindow *main_window); - -void main_window_free(MainWindow *main_window); -``` - ---- - -## Interface graphique attendue - -```text -┌───────────────────────────────────────────────────────────────┐ -│ Labfy Investigation │ -├───────────────────────────────────────────────────────────────┤ -│ │ -│ │ -│ Zone de travail │ -│ │ -│ │ -├───────────────────────────────────────────────────────────────┤ -│ Aucune enquête ouverte │ -└───────────────────────────────────────────────────────────────┘ -``` - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] Une fenêtre s'ouvre correctement. -- [ ] La fenêtre est créée par le module `MainWindow`. -- [ ] `Application` n'appelle plus directement `gtk_application_window_new()`. -- [ ] Aucun état global. -- [ ] Documentation Doxygen. -- [ ] Gestion mémoire correcte. - ---- - -## Tests - -- Lancement de l'application. -- Fermeture de la fenêtre. -- Vérification de l'absence de fuite mémoire. - ---- - -## Commit attendu - -```text -feat(view): create main window -``` diff --git a/docs/tickets/closed/TICKET-005.md b/docs/tickets/closed/TICKET-005.md deleted file mode 100644 index 6ea9dff..0000000 --- a/docs/tickets/closed/TICKET-005.md +++ /dev/null @@ -1,151 +0,0 @@ -# Ticket #005 - -## Titre - -Créer le panneau de navigation latéral (`Sidebar`). - ---- - -## Objectif - -Créer la structure principale de l'interface avec : - -- un panneau latéral à gauche ; -- une zone de travail à droite ; -- une séparation redimensionnable entre les deux zones. - -Le panneau latéral servira plus tard à afficher l'arborescence du dossier d'enquête. - ---- - -## Responsabilités - -Le module `Sidebar` doit : - -- créer un panneau GTK réutilisable ; -- posséder une largeur initiale raisonnable ; -- afficher temporairement un titre ; -- exposer son widget racine en lecture seule. - -Le module `MainWindow` doit : - -- intégrer le panneau latéral ; -- conserver la zone de travail principale ; -- permettre le redimensionnement des deux zones. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- afficher l'arborescence réelle des fichiers ; -- lire le contenu d'un dossier ; -- surveiller les changements du système de fichiers ; -- créer ou supprimer des fichiers ; -- ajouter le bouton permettant de masquer le panneau ; -- communiquer avec SQLite. - ---- - -## Architecture - -```text -MainWindow -├── Sidebar -├── Workspace -└── StatusLabel -``` - -Le module `Sidebar` appartient à la couche `widgets`. - -Le module ne contient aucune logique métier. - ---- - -## Fichiers concernés - -```text -include/widgets/sidebar.h -src/widgets/sidebar.c - -include/views/main_window.h -src/views/main_window.c -``` - ---- - -## Interface publique attendue - -```c -Sidebar *sidebar_new(void); - -GtkWidget *sidebar_get_widget( - const Sidebar *sidebar -); - -void sidebar_free(Sidebar *sidebar); -``` - ---- - -## Interface graphique attendue - -```text -┌───────────────────────┬──────────────────────────────────────┐ -│ Dossier d'enquête │ │ -│ │ │ -│ │ │ -│ │ Zone de travail │ -│ │ │ -│ │ │ -├───────────────────────┴──────────────────────────────────────┤ -│ Aucune enquête ouverte │ -└──────────────────────────────────────────────────────────────┘ -``` - -La séparation entre le panneau gauche et la zone centrale doit pouvoir être déplacée horizontalement. - ---- - -## Contraintes techniques - -- utiliser GTK4 ; -- utiliser un `GtkPaned` horizontal dans `MainWindow` ; -- ne pas utiliser de variable globale ; -- conserver une structure `Sidebar` opaque ; -- respecter les conventions de nommage du projet ; -- compiler en C17 sans warning. - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] Le panneau latéral apparaît à gauche. -- [ ] La zone de travail apparaît à droite. -- [ ] La séparation peut être déplacée avec la souris. -- [ ] Le panneau est créé par le module `Sidebar`. -- [ ] `MainWindow` ne construit pas directement le contenu interne du panneau. -- [ ] Aucun état global. -- [ ] Les fonctions publiques sont documentées avec Doxygen. -- [ ] La fermeture de l'application ne provoque aucune erreur GTK. - ---- - -## Tests - -- lancer l'application ; -- sélectionner un dossier ; -- déplacer la séparation ; -- agrandir et réduire la fenêtre ; -- fermer l'application ; -- vérifier l'absence de warning ou de message critique. - ---- - -## Commit attendu - -```text -feat(widget): create navigation sidebar -``` diff --git a/docs/tickets/closed/TICKET-006.md b/docs/tickets/closed/TICKET-006.md deleted file mode 100644 index 04d1736..0000000 --- a/docs/tickets/closed/TICKET-006.md +++ /dev/null @@ -1,153 +0,0 @@ -# Ticket #006 - -## Titre - -Créer le module `Workspace`. - ---- - -## Objectif - -Créer un composant graphique représentant la zone principale de travail de Labfy Investigation. - -Le module doit être indépendant du reste de l'interface afin de pouvoir évoluer sans modifier `MainWindow`. - ---- - -## Responsabilités - -Le module `Workspace` doit : - -- créer la zone centrale de l'application ; -- afficher une page d'accueil lorsqu'aucune enquête n'est ouverte ; -- fournir un widget racine réutilisable ; -- gérer uniquement son interface graphique. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- afficher les preuves ; -- afficher les entités ; -- afficher un PDF ; -- afficher une image ; -- communiquer avec SQLite ; -- charger une enquête. - ---- - -## Architecture - -```text -MainWindow -├── Sidebar -├── Workspace -└── StatusBar -``` - -Le module appartient à la couche **Widgets**. - -Aucune logique métier. - ---- - -## Fichiers concernés - -```text -include/widgets/workspace.h -src/widgets/workspace.c -``` - ---- - -## Interface publique - -```c -Workspace *workspace_new(void); - -GtkWidget *workspace_get_widget( - const Workspace *workspace -); - -void workspace_free( - Workspace *workspace -); -``` - ---- - -## Interface graphique attendue - -```text -+-------------------------------------------------------------+ -| | -| | -| Labfy Investigation | -| | -| Aucune enquête ouverte | -| | -| Sélectionnez ou créez une enquête | -| | -| | -+-------------------------------------------------------------+ -``` - ---- - -## Évolutions prévues - -Cette zone accueillera plus tard : - -- visualiseur d'image ; -- lecteur PDF ; -- chronologie ; -- fiche personne ; -- fiche IBAN ; -- fiche email ; -- fiche téléphone ; -- rapports ; -- cartes ; -- résultats OSINT. - -Le module doit donc rester générique. - ---- - -## Contraintes - -- GTK4 uniquement ; -- structure opaque ; -- aucune variable globale ; -- documentation Doxygen ; -- C17 ; -- compilation sans warning. - ---- - -## Critères d'acceptation - -- [ ] Le projet compile. -- [ ] Le Workspace apparaît dans MainWindow. -- [ ] Le texte d'accueil est centré. -- [ ] Sidebar et Workspace sont totalement indépendants. -- [ ] Aucun warning. -- [ ] Aucun Gtk-CRITICAL. - ---- - -## Tests - -- lancement ; -- redimensionnement de la fenêtre ; -- fermeture ; -- vérification visuelle. - ---- - -## Commit attendu - -```text -feat(widget): create workspace -``` diff --git a/docs/tickets/closed/TICKET-007.md b/docs/tickets/closed/TICKET-007.md deleted file mode 100644 index f17f0b8..0000000 --- a/docs/tickets/closed/TICKET-007.md +++ /dev/null @@ -1,184 +0,0 @@ -# Ticket #007 - -## Titre - -Créer le module `InvestigationNode`. - ---- - -## Objectif - -Créer une structure métier représentant un élément de l'arborescence d'une enquête. - -Un nœud peut représenter : - -- un dossier ; -- un fichier. - -Ce module servira de base au futur modèle d'arborescence. - ---- - -## Responsabilités - -Le module `InvestigationNode` doit : - -- mémoriser le nom d'un élément ; -- mémoriser son type ; -- gérer sa propre mémoire ; -- exposer ses informations en lecture seule. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- parcourir le système de fichiers ; -- construire une arborescence complète ; -- stocker des enfants ; -- afficher quoi que ce soit avec GTK ; -- communiquer avec SQLite ; -- ouvrir une enquête. - ---- - -## Architecture - -```text -InvestigationTreeModel - │ - └── InvestigationNode -``` - -Le module appartient à la couche `core`. - -Il ne doit contenir aucune dépendance vers GTK. - ---- - -## Fichiers concernés - -```text -include/core/investigation_node.h -src/core/investigation_node.c -``` - ---- - -## Type attendu - -```c -typedef enum -{ - INVESTIGATION_NODE_DIRECTORY, - INVESTIGATION_NODE_FILE -} InvestigationNodeType; -``` - ---- - -## Interface publique attendue - -```c -InvestigationNode *investigation_node_new( - const char *name, - InvestigationNodeType type -); - -void investigation_node_free( - InvestigationNode *node -); - -const char *investigation_node_get_name( - const InvestigationNode *node -); - -InvestigationNodeType investigation_node_get_type( - const InvestigationNode *node -); -``` - ---- - -## Comportement attendu - -Exemple d'utilisation : - -```c -InvestigationNode *node = NULL; - -node = investigation_node_new( - "01_Preuves_Originales", - INVESTIGATION_NODE_DIRECTORY -); - -if (node == NULL) -{ - /* Gestion de l'erreur */ -} - -const char *name = investigation_node_get_name(node); -InvestigationNodeType type = investigation_node_get_type(node); - -investigation_node_free(node); -``` - ---- - -## Cas à gérer - -- nom valide ; -- nom vide ; -- pointeur `NULL` ; -- type dossier ; -- type fichier ; -- libération avec `NULL`. - ---- - -## Contraintes techniques - -- C17 ; -- structure opaque ; -- aucun état global ; -- aucune dépendance GTK ; -- documentation Doxygen ; -- compilation sans warning ; -- noms conformes à `DEVELOPMENT.md`. - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] La structure `InvestigationNode` est opaque. -- [ ] Un nœud peut représenter un fichier. -- [ ] Un nœud peut représenter un dossier. -- [ ] Le nom est copié et possédé par le nœud. -- [ ] Les getters retournent des données en lecture seule. -- [ ] `investigation_node_free(NULL)` est accepté. -- [ ] Aucun code GTK. -- [ ] Aucun code SQLite. -- [ ] Les fonctions publiques sont documentées avec Doxygen. - ---- - -## Tests - -- créer un nœud dossier ; -- créer un nœud fichier ; -- lire le nom ; -- lire le type ; -- tester un nom vide ; -- tester un nom `NULL` ; -- libérer un nœud valide ; -- appeler `investigation_node_free(NULL)`. - ---- - -## Commit attendu - -```text -feat(core): create investigation node -``` diff --git a/docs/tickets/closed/TICKET-008.md b/docs/tickets/closed/TICKET-008.md deleted file mode 100644 index 11cb581..0000000 --- a/docs/tickets/closed/TICKET-008.md +++ /dev/null @@ -1,158 +0,0 @@ -# Ticket #008 - -## Titre - -Créer le module `InvestigationTreeModel`. - ---- - -## Objectif - -Créer une structure métier représentant le modèle de l'arborescence d'une enquête. - -Le modèle sera propriétaire du nœud racine et servira de base au futur explorateur d'enquête. - ---- - -## Responsabilités - -Le module `InvestigationTreeModel` doit : - -- posséder un nœud racine ; -- gérer le cycle de vie du modèle ; -- exposer le nœud racine en lecture seule. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- parcourir le système de fichiers ; -- créer les enfants d'un nœud ; -- afficher une interface GTK ; -- communiquer avec SQLite ; -- charger une enquête. - ---- - -## Architecture - -```text -Investigation - │ - ▼ -InvestigationTreeModel - │ - ▼ -InvestigationNode -``` - -Le module appartient à la couche **Core**. - -Aucune dépendance vers GTK. - ---- - -## Principe de propriété - -Le module est **propriétaire** du nœud racine. - -À partir du moment où un `InvestigationNode` est transmis au constructeur : - -```c -investigation_tree_model_new(root_node); -``` - -le modèle devient responsable de sa destruction. - -Le code appelant ne doit plus appeler : - -```c -investigation_node_free(root_node); -``` - -La destruction du modèle doit automatiquement détruire son nœud racine. - ---- - -## Fichiers concernés - -```text -include/core/investigation_tree_model.h -src/core/investigation_tree_model.c -``` - ---- - -## Interface publique attendue - -```c -InvestigationTreeModel *investigation_tree_model_new( - InvestigationNode *root_node -); - -void investigation_tree_model_free( - InvestigationTreeModel *tree_model -); - -const InvestigationNode *investigation_tree_model_get_root( - const InvestigationTreeModel *tree_model -); -``` - ---- - -## Comportement attendu - -Le modèle contient uniquement un nœud racine. - -Exemple : - -```text -Template -``` - -Les enfants seront ajoutés dans un ticket ultérieur. - ---- - -## Contraintes techniques - -- C17 -- Structure opaque -- Aucun état global -- Aucune dépendance GTK -- Documentation Doxygen -- Compilation sans warning -- Respect des conventions du projet - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] Le modèle est opaque. -- [ ] Le modèle possède un nœud racine. -- [ ] Le getter retourne le nœud racine. -- [ ] La destruction du modèle détruit également le nœud racine. -- [ ] Aucun code GTK. -- [ ] Aucun code SQLite. - ---- - -## Tests - -- création d'un modèle valide ; -- lecture du nœud racine ; -- destruction du modèle ; -- création avec un nœud NULL ; -- destruction avec NULL. - ---- - -## Commit attendu - -```text -feat(core): create investigation tree model -``` diff --git a/docs/tickets/closed/TICKET-009.5.md b/docs/tickets/closed/TICKET-009.5.md deleted file mode 100644 index 3e06958..0000000 --- a/docs/tickets/closed/TICKET-009.5.md +++ /dev/null @@ -1,103 +0,0 @@ -# Ticket #009.5 - -## Titre - -Ajouter une cible `make test`. - ---- - -## Objectif - -Automatiser la compilation et l'exécution de l'ensemble des tests du projet. - -La commande suivante doit suffire : - -```bash -make test -``` - ---- - -## Responsabilités - -Le système de build doit : - -- compiler chaque fichier de test ; -- lier uniquement les modules nécessaires ; -- exécuter tous les tests ; -- arrêter l'exécution si un test échoue ; -- supprimer les binaires de test avec `make clean`. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- ajouter de nouveaux tests métier ; -- modifier le comportement des modules ; -- introduire un framework de test externe ; -- produire des rapports de couverture ; -- lancer Valgrind automatiquement. - ---- - -## Fichiers concernés - -```text -Makefile -``` - -Éventuellement : - -```text -tests/Makefile -``` - -uniquement si le Makefile principal devient difficile à lire. - ---- - -## Tests concernés - -```text -tests/test_investigation_node.c -tests/test_investigation_tree_model.c -``` - ---- - -## Comportement attendu - -La commande : - -```bash -make test -``` - -doit : - -1. compiler les binaires de test ; -2. exécuter chaque test ; -3. afficher clairement le résultat ; -4. retourner un code d'erreur si un test échoue. - ---- - -## Critères d'acceptation - -- [ ] `make test` compile tous les tests. -- [ ] `make test` exécute tous les tests. -- [ ] Un test en échec arrête la commande. -- [ ] `make clean` supprime les binaires de test. -- [ ] Aucun binaire de test n'est versionné. -- [ ] Le projet principal continue de compiler. -- [ ] Aucun warning. - ---- - -## Commit attendu - -```text -build: add automated test target -``` diff --git a/docs/tickets/closed/TICKET-009.md b/docs/tickets/closed/TICKET-009.md deleted file mode 100644 index e187542..0000000 --- a/docs/tickets/closed/TICKET-009.md +++ /dev/null @@ -1,268 +0,0 @@ -# Ticket #009 - -## Titre - -Ajouter les relations parent/enfants à `InvestigationNode`. - ---- - -## Objectif - -Faire évoluer `InvestigationNode` afin qu'un nœud puisse appartenir à une arborescence. - -Chaque nœud pourra : - -- connaître son parent ; -- posséder plusieurs enfants ; -- exposer ses enfants en lecture seule via une API publique. - ---- - -## Responsabilités - -Le module `InvestigationNode` doit : - -- mémoriser un pointeur vers son parent ; -- posséder un tableau dynamique d'enfants ; -- ajouter un enfant ; -- retourner un enfant par son index ; -- retourner le nombre d'enfants ; -- retourner son parent ; -- détruire récursivement les enfants qu'il possède. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- parcourir le système de fichiers ; -- construire automatiquement une arborescence depuis un dossier ; -- afficher quoi que ce soit avec GTK ; -- communiquer avec SQLite ; -- gérer le tri des enfants ; -- gérer la suppression individuelle d'un enfant ; -- gérer le déplacement d'un nœud entre deux parents. - ---- - -## Architecture - -```text -InvestigationTreeModel - │ - ▼ -InvestigationNode - │ - ├── InvestigationNode - ├── InvestigationNode - └── InvestigationNode -``` - -Le module appartient à la couche `core`. - -Il peut dépendre de GLib, mais jamais de GTK. - ---- - -## Gestion de la propriété - -Un nœud devient propriétaire de chaque enfant ajouté avec : - -```c -investigation_node_add_child(parent, child); -``` - -Après un ajout réussi : - -- `parent` possède `child` ; -- le code appelant ne doit plus libérer `child` directement ; -- `child` conserve une référence non propriétaire vers `parent`. - -Lors de la destruction du parent, tous ses enfants sont détruits récursivement. - ---- - -## Structure interne attendue - -```c -struct InvestigationNode -{ - char *name; - InvestigationNodeType type; - InvestigationNode *parent; - GPtrArray *children; -}; -``` - -La structure reste privée dans `investigation_node.c`. - ---- - -## Interface publique attendue - -Les fonctions existantes sont conservées : - -```c -InvestigationNode *investigation_node_new( - const char *name, - InvestigationNodeType type -); - -void investigation_node_free( - InvestigationNode *node -); - -const char *investigation_node_get_name( - const InvestigationNode *node -); - -InvestigationNodeType investigation_node_get_type( - const InvestigationNode *node -); -``` - -Les fonctions suivantes sont ajoutées : - -```c -bool investigation_node_add_child( - InvestigationNode *parent, - InvestigationNode *child -); - -const InvestigationNode *investigation_node_get_child( - const InvestigationNode *node, - size_t index -); - -size_t investigation_node_get_children_count( - const InvestigationNode *node -); - -const InvestigationNode *investigation_node_get_parent( - const InvestigationNode *node -); -``` - ---- - -## Comportement attendu - -Exemple : - -```c -InvestigationNode *root = NULL; -InvestigationNode *child = NULL; - -root = investigation_node_new( - "Template", - INVESTIGATION_NODE_DIRECTORY -); - -child = investigation_node_new( - "00_BaseDeDonnees", - INVESTIGATION_NODE_DIRECTORY -); - -if (!investigation_node_add_child(root, child)) -{ - investigation_node_free(child); - investigation_node_free(root); - return; -} -``` - -Après l'ajout : - -```text -Template -└── 00_BaseDeDonnees -``` - -Le nœud `root` devient propriétaire de `child`. - -Le nettoyage correct est uniquement : - -```c -investigation_node_free(root); -``` - ---- - -## Règles d'ajout - -`investigation_node_add_child()` doit refuser : - -- un parent `NULL` ; -- un enfant `NULL` ; -- un parent qui représente un fichier ; -- l'ajout d'un nœud comme enfant de lui-même ; -- un enfant possédant déjà un parent. - -En cas d'échec, la propriété de l'enfant reste au code appelant. - ---- - -## Dépendances - -- C17 ; -- GLib. - -Aucune dépendance GTK ou SQLite. - ---- - -## Contraintes techniques - -- structure opaque ; -- aucun état global ; -- utilisation de `GPtrArray` ; -- tableau créé avec une fonction de destruction ; -- documentation Doxygen ; -- compilation sans warning ; -- respect des conventions de nommage ; -- aucune modification directe du tableau en dehors du module. - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] Un dossier peut posséder plusieurs enfants. -- [ ] Un fichier ne peut pas recevoir d'enfant. -- [ ] Un enfant connaît son parent. -- [ ] Le nombre d'enfants est correct. -- [ ] Un enfant peut être récupéré par son index. -- [ ] Un index invalide retourne `NULL`. -- [ ] Un enfant ne peut pas avoir deux parents. -- [ ] Un nœud ne peut pas être son propre enfant. -- [ ] La destruction d'un parent détruit récursivement ses enfants. -- [ ] Aucun code GTK. -- [ ] Aucun code SQLite. - ---- - -## Tests - -- créer un parent dossier ; -- ajouter un enfant dossier ; -- ajouter un enfant fichier ; -- vérifier le nombre d'enfants ; -- récupérer chaque enfant ; -- vérifier le parent d'un enfant ; -- tester un index invalide ; -- refuser l'ajout à un fichier ; -- refuser un parent `NULL` ; -- refuser un enfant `NULL` ; -- refuser l'auto-référence ; -- refuser un enfant possédant déjà un parent ; -- détruire un arbre complet ; -- appeler les getters avec `NULL`. - ---- - -## Commit attendu - -```text -feat(core): add investigation node hierarchy -``` diff --git a/docs/tickets/closed/TICKET-010.md b/docs/tickets/closed/TICKET-010.md deleted file mode 100644 index b4aae49..0000000 --- a/docs/tickets/closed/TICKET-010.md +++ /dev/null @@ -1,243 +0,0 @@ -# Ticket #010 - -## Titre - -Construire l'arborescence d'une enquête depuis le système de fichiers. - ---- - -## Objectif - -Créer le module `InvestigationTreeBuilder`. - -Ce module doit parcourir récursivement le dossier racine d'une enquête et -construire un `InvestigationTreeModel` représentant son contenu. - ---- - -## Responsabilités - -Le module `InvestigationTreeBuilder` doit : - -- recevoir le chemin racine d'une enquête ; -- vérifier que ce chemin désigne un dossier existant ; -- créer le nœud racine ; -- parcourir récursivement les dossiers ; -- créer un `InvestigationNode` pour chaque dossier ; -- créer un `InvestigationNode` pour chaque fichier ; -- assembler les relations parent/enfants ; -- retourner un `InvestigationTreeModel` complet ; -- nettoyer toutes les ressources en cas d'erreur. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- afficher l'arborescence avec GTK ; -- modifier le système de fichiers ; -- créer ou supprimer des fichiers ; -- trier les éléments ; -- filtrer les fichiers cachés ; -- surveiller les changements du disque ; -- suivre les liens symboliques ; -- communiquer avec SQLite. - ---- - -## Architecture - -```text -Investigation - │ - ▼ -InvestigationTreeBuilder - │ - ▼ -InvestigationTreeModel - │ - ▼ -InvestigationNode -``` - -Le module appartient à la couche `core`. - -Il peut utiliser GLib et GIO, mais ne doit jamais dépendre de GTK. - ---- - -## Fichiers concernés - -```text -include/core/investigation_tree_builder.h -src/core/investigation_tree_builder.c -``` - -Les tests seront placés dans : - -```text -tests/test_investigation_tree_builder.c -``` - ---- - -## Interface publique attendue - -```c -InvestigationTreeModel *investigation_tree_builder_build( - const char *root_path -); -``` - ---- - -## Principe de propriété - -En cas de succès, la fonction retourne un nouveau -`InvestigationTreeModel`. - -Le code appelant devient propriétaire du modèle retourné et doit le libérer -avec : - -```c -investigation_tree_model_free(tree_model); -``` - -En cas d'échec, la fonction retourne `NULL` et doit avoir libéré toutes les -ressources créées pendant la construction. - ---- - -## Comportement attendu - -À partir de : - -```text -Enquete_Test/ -├── 00_BaseDeDonnees/ -│ └── Enquete.sqlite -├── 01_Preuves_Originales/ -│ ├── Captures_Ecran/ -│ └── Emails/ -└── README.md -``` - -le module doit construire en mémoire : - -```text -Enquete_Test -├── 00_BaseDeDonnees -│ └── Enquete.sqlite -├── 01_Preuves_Originales -│ ├── Captures_Ecran -│ └── Emails -└── README.md -``` - ---- - -## Gestion des liens symboliques - -Les liens symboliques ne sont pas suivis. - -Cette règle évite : - -- les boucles récursives ; -- la sortie involontaire du dossier d'enquête ; -- l'analyse de fichiers extérieurs à l'enquête. - -Leur prise en charge éventuelle fera l'objet d'un ticket distinct. - ---- - -## Dépendances - -- C17 ; -- GLib ; -- GIO. - -Aucune dépendance GTK ou SQLite. - ---- - -## Contraintes techniques - -- aucune variable globale ; -- aucune modification du système de fichiers ; -- parcours récursif ; -- utilisation de `GFile` et `GFileEnumerator` ; -- libération correcte des `GObject` avec `g_object_unref()` ; -- respect de la règle « le propriétaire détruit » ; -- documentation Doxygen ; -- compilation sans warning ; -- aucune fuite mémoire. - ---- - -## Cas à gérer - -- chemin valide ; -- chemin relatif ; -- chemin `NULL` ; -- chemin vide ; -- chemin inexistant ; -- chemin désignant un fichier ; -- dossier vide ; -- plusieurs niveaux de sous-dossiers ; -- fichiers et dossiers mélangés ; -- erreur rencontrée pendant le parcours. - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] Un dossier valide produit un modèle. -- [ ] Le nom du dossier racine est correct. -- [ ] Les dossiers produisent des nœuds de type `DIRECTORY`. -- [ ] Les fichiers produisent des nœuds de type `FILE`. -- [ ] Les relations parent/enfants sont correctes. -- [ ] Plusieurs niveaux de profondeur sont pris en charge. -- [ ] Un dossier vide est pris en charge. -- [ ] Un chemin invalide retourne `NULL`. -- [ ] Les liens symboliques ne sont pas suivis. -- [ ] Toutes les ressources sont libérées en cas d'erreur. -- [ ] Aucun code GTK. -- [ ] Aucun code SQLite. -- [ ] `make test` exécute le nouveau test. - ---- - -## Tests - -Le test doit créer une arborescence temporaire isolée : - -```text -TestCase/ -├── DirectoryA/ -│ └── FileA.txt -├── DirectoryB/ -└── RootFile.md -``` - -Il doit vérifier : - -- le nom du nœud racine ; -- le nombre d'enfants de la racine ; -- la présence des deux dossiers ; -- la présence du fichier racine ; -- la présence de `FileA.txt` dans `DirectoryA` ; -- le type de chaque nœud ; -- le parent de chaque enfant ; -- la gestion d'un dossier vide ; -- les chemins invalides ; -- la destruction complète du modèle. - ---- - -## Commit attendu - -```text -feat(core): build investigation tree from filesystem -``` diff --git a/docs/tickets/closed/TICKET-011.md b/docs/tickets/closed/TICKET-011.md deleted file mode 100644 index cc14b62..0000000 --- a/docs/tickets/closed/TICKET-011.md +++ /dev/null @@ -1,240 +0,0 @@ -# Ticket #011 - -## Titre - -Connecter le modèle d'arborescence à la `Sidebar`. - ---- - -## Objectif - -Relier l'enquête sélectionnée au panneau latéral. - -Après la sélection d'un dossier, l'application doit : - -1. créer l'objet `Investigation` ; -2. construire son `InvestigationTreeModel` ; -3. transmettre le modèle à la `Sidebar` ; -4. afficher temporairement le nom du nœud racine dans le panneau latéral. - -Ce ticket valide la communication entre le Core et l'interface graphique. - ---- - -## Architecture - -```text -FolderDialog - │ - ▼ -Application - │ - ├── Investigation - │ - └── InvestigationTreeModel - │ - ▼ - Sidebar -``` - -Le module `Application` reste responsable de la coordination. - -La `Sidebar` ne parcourt jamais directement le système de fichiers. - ---- - -## Responsabilités - -### Application - -Le module `Application` doit : - -- recevoir le dossier sélectionné ; -- créer l'objet `Investigation` ; -- construire le modèle avec `InvestigationTreeBuilder` ; -- conserver le modèle pendant toute la durée de l'enquête ; -- transmettre le modèle à `MainWindow` ; -- libérer l'ancien modèle avant d'en ouvrir un nouveau ; -- libérer le modèle à la fermeture de l'application. - -### MainWindow - -Le module `MainWindow` doit : - -- recevoir un modèle d'arborescence ; -- le transmettre au composant `Sidebar`. - -### Sidebar - -Le module `Sidebar` doit : - -- recevoir un `InvestigationTreeModel` en lecture seule ; -- lire le nœud racine ; -- afficher temporairement son nom dans le titre du panneau ; -- ne jamais détruire le modèle reçu. - ---- - -## Principe de propriété - -`Application` est propriétaire de : - -```text -Investigation -InvestigationTreeModel -MainWindow -``` - -La `Sidebar` reçoit uniquement une référence non propriétaire vers le modèle. - -Elle ne doit jamais appeler : - -```c -investigation_tree_model_free(tree_model); -``` - -Le modèle est libéré uniquement par `Application`. - ---- - -## Fichiers concernés - -```text -src/core/application.c - -include/views/main_window.h -src/views/main_window.c - -include/widgets/sidebar.h -src/widgets/sidebar.c -``` - -Aucun nouveau module n'est nécessaire. - ---- - -## Interfaces publiques à ajouter - -### MainWindow - -```c -void main_window_set_tree_model( - MainWindow *main_window, - const InvestigationTreeModel *tree_model -); -``` - -### Sidebar - -```c -void sidebar_set_tree_model( - Sidebar *sidebar, - const InvestigationTreeModel *tree_model -); -``` - ---- - -## Comportement attendu - -Avant l'ouverture d'une enquête, la `Sidebar` affiche : - -```text -Dossier d'enquête -``` - -Après la sélection du dossier : - -```text -Template -``` - -ou le nom réel du dossier racine sélectionné. - -À ce stade, les enfants ne sont pas encore affichés. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- afficher les enfants du nœud racine ; -- utiliser `GtkTreeListModel` ; -- créer un explorateur de fichiers complet ; -- permettre de sélectionner un nœud ; -- ouvrir un fichier ; -- rafraîchir automatiquement le modèle ; -- modifier le système de fichiers ; -- communiquer avec SQLite. - ---- - -## Gestion des erreurs - -Si la construction du modèle échoue : - -- l'application ne doit pas planter ; -- l'ancien modèle doit rester valide jusqu'à son remplacement explicite ; -- un message d'erreur doit être affiché dans le terminal ; -- la `Sidebar` ne doit recevoir aucun pointeur invalide. - -Si une nouvelle enquête est ouverte avec succès : - -1. créer la nouvelle enquête ; -2. construire le nouveau modèle ; -3. seulement ensuite libérer l'ancienne enquête et l'ancien modèle ; -4. installer les nouveaux objets. - -Cette séquence évite de perdre l'enquête actuellement ouverte en cas d'échec. - ---- - -## Contraintes techniques - -- C17 ; -- aucun état global ; -- aucune lecture du système de fichiers dans `Sidebar` ; -- aucun transfert de propriété vers `Sidebar` ; -- documentation Doxygen ; -- compilation sans warning ; -- absence de `Gtk-CRITICAL` ; -- respect des conventions de nommage. - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] `make test` reste valide. -- [ ] La sélection d'un dossier construit un modèle. -- [ ] `Application` conserve le modèle. -- [ ] `MainWindow` transmet le modèle à `Sidebar`. -- [ ] La `Sidebar` affiche le nom du nœud racine. -- [ ] L'ouverture successive de deux dossiers fonctionne. -- [ ] L'ancien modèle est correctement libéré. -- [ ] Une erreur de construction ne provoque pas de crash. -- [ ] La fermeture de l'application libère le modèle. -- [ ] Aucun code de parcours du disque n'apparaît dans `Sidebar`. -- [ ] Aucun enfant n'est encore affiché. - ---- - -## Tests manuels - -1. Lancer l'application. -2. Sélectionner le dossier `Template`. -3. Vérifier que la `Sidebar` affiche `Template`. -4. Fermer l'application. -5. Vérifier l'absence de warning critique. -6. Ouvrir successivement deux dossiers différents. -7. Vérifier que le titre de la `Sidebar` est mis à jour. -8. Vérifier que `make test` reste entièrement valide. - ---- - -## Commit attendu - -```text -feat(gui): connect investigation model to sidebar -``` diff --git a/docs/tickets/closed/TICKET-012.md b/docs/tickets/closed/TICKET-012.md deleted file mode 100644 index 7255571..0000000 --- a/docs/tickets/closed/TICKET-012.md +++ /dev/null @@ -1,167 +0,0 @@ -# Ticket #012 - -## Titre - -Créer le composant `InvestigationTreeView`. - ---- - -## Objectif - -Créer un composant graphique spécialisé chargé d'afficher un -`InvestigationTreeModel` à l'aide des widgets modernes de GTK4. - -Ce composant servira d'adaptateur entre le modèle métier et les widgets GTK. - -À ce stade, il n'est pas encore intégré dans la `Sidebar`. - ---- - -## Architecture - -```text -InvestigationTreeModel - │ - ▼ -InvestigationTreeView - │ - ▼ -GtkTreeListModel - │ - ▼ -GtkListView -``` - -Le composant appartient à la couche graphique. - -Le Core ne dépend jamais de GTK. - ---- - -## Responsabilités - -Le module doit : - -- recevoir un `InvestigationTreeModel` ; -- créer un `GtkTreeListModel` ; -- créer un `GtkListView` ; -- utiliser un `GtkSignalListItemFactory` ; -- utiliser un `GtkTreeExpander` ; -- afficher le nom des nœuds ; -- permettre le développement et le repli des dossiers ; -- fournir un widget GTK réutilisable. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- intégrer le composant dans la Sidebar ; -- permettre la sélection d'un nœud ; -- afficher des icônes ; -- ouvrir des fichiers ; -- modifier l'arborescence ; -- communiquer avec SQLite ; -- rafraîchir automatiquement le modèle. - ---- - -## Principe de propriété - -Le composant ne devient jamais propriétaire du -`InvestigationTreeModel`. - -Il reçoit uniquement une référence. - -En revanche, il est propriétaire de tous les objets GTK qu'il crée. - ---- - -## Fichiers concernés - -```text -include/widgets/investigation_tree_view.h -src/widgets/investigation_tree_view.c -``` - -Aucun autre module ne doit être modifié. - ---- - -## Interface publique - -```c -typedef struct InvestigationTreeView InvestigationTreeView; -``` - -```c -InvestigationTreeView *investigation_tree_view_new(void); -``` - -```c -GtkWidget *investigation_tree_view_get_widget( - const InvestigationTreeView *tree_view -); -``` - -```c -void investigation_tree_view_set_model( - InvestigationTreeView *tree_view, - const InvestigationTreeModel *tree_model -); -``` - -```c -void investigation_tree_view_free( - InvestigationTreeView *tree_view -); -``` - ---- - -## Dépendances GTK - -Le composant doit utiliser exclusivement : - -- GtkTreeListModel -- GtkListView -- GtkTreeExpander -- GtkSignalListItemFactory - -Aucun widget GTK3. - ---- - -## Contraintes techniques - -- C17 -- GTK4 uniquement -- aucune variable globale -- aucune dépendance vers SQLite -- aucune lecture directe du système de fichiers -- documentation Doxygen -- compilation sans warning -- aucune fuite mémoire - ---- - -## Critères d'acceptation - -- [ ] Le projet compile. -- [ ] Le composant peut être créé. -- [ ] Le composant fournit un widget GTK. -- [ ] Un modèle peut être associé. -- [ ] Les dossiers peuvent être développés. -- [ ] Les fichiers apparaissent. -- [ ] Le composant ne possède pas le modèle. -- [ ] Aucun Gtk-CRITICAL. -- [ ] Aucun warning. - ---- - -## Commit attendu - -```text -feat(gui): create investigation tree view -``` diff --git a/docs/tickets/closed/TICKET-013.md b/docs/tickets/closed/TICKET-013.md deleted file mode 100644 index e42ce0e..0000000 --- a/docs/tickets/closed/TICKET-013.md +++ /dev/null @@ -1,217 +0,0 @@ -# Ticket #013 - -## Titre - -Intégrer `InvestigationTreeView` dans la `Sidebar`. - ---- - -## Objectif - -Afficher dans la barre latérale l'arborescence complète de l'enquête ouverte. - -Le composant `InvestigationTreeView` existe déjà. Ce ticket consiste uniquement à l'intégrer dans `Sidebar` et à lui transmettre le modèle métier reçu. - ---- - -## Architecture - -```text -Application - │ - ▼ -MainWindow - │ - ▼ -Sidebar - │ - ▼ -InvestigationTreeView - │ - ▼ -GtkTreeListModel -``` - -La `Sidebar` héberge la vue. - -Elle ne parcourt jamais directement le système de fichiers. - ---- - -## Responsabilités - -### Sidebar - -Le module `Sidebar` doit : - -- créer un `InvestigationTreeView` ; -- intégrer son widget racine sous le titre ; -- transmettre le `InvestigationTreeModel` au composant ; -- libérer la structure `InvestigationTreeView` lors de sa propre destruction. - -### InvestigationTreeView - -Le composant conserve ses responsabilités actuelles : - -- adapter le modèle métier à GTK4 ; -- afficher les nœuds ; -- gérer l'ouverture et le repli des dossiers. - ---- - -## Principe de propriété - -`Sidebar` est propriétaire de : - -```text -InvestigationTreeView -``` - -Elle doit donc appeler : - -```c -investigation_tree_view_free(...) -``` - -lors de sa destruction. - -En revanche, ni `Sidebar` ni `InvestigationTreeView` ne possèdent : - -```text -InvestigationTreeModel -``` - -Le modèle reste la propriété de `Application`. - ---- - -## Fichiers concernés - -```text -src/widgets/sidebar.c -``` - -Éventuellement : - -```text -include/widgets/sidebar.h -``` - -uniquement si l'API publique doit être précisée. - -Aucun changement du Core n'est nécessaire. - ---- - -## Modifications attendues - -La structure privée `Sidebar` doit contenir : - -```c -InvestigationTreeView *tree_view; -``` - -Le constructeur doit : - -1. créer le composant ; -2. récupérer son widget racine ; -3. l'ajouter sous le titre ; -4. lui permettre d'occuper l'espace disponible. - -La fonction : - -```c -sidebar_set_tree_model(...) -``` - -doit transmettre le modèle à : - -```c -investigation_tree_view_set_model(...) -``` - -Le titre de la `Sidebar` peut continuer à afficher le nom du nœud racine. - ---- - -## Interface graphique attendue - -```text -Template - -▸ 00_BaseDeDonnees -▸ 01_Preuves_Originales -▸ 02_Preuves_traitees -▸ 03_Chronologie -▸ 04_Entites -... -``` - -Les dossiers peuvent être développés et repliés. - -Les fichiers apparaissent dans les branches développées. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- permettre la sélection d'un nœud ; -- afficher des icônes ; -- ouvrir un fichier ; -- ajouter un menu contextuel ; -- rafraîchir automatiquement l'arbre ; -- modifier le système de fichiers ; -- communiquer avec SQLite. - ---- - -## Contraintes techniques - -- GTK4 uniquement ; -- aucun `GtkTreeView` ; -- aucune lecture directe du disque dans `Sidebar` ; -- aucun transfert de propriété du modèle métier ; -- aucun état global ; -- documentation cohérente ; -- compilation sans warning ; -- aucun `Gtk-CRITICAL`. - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] `make test` reste entièrement valide. -- [ ] La vue est intégrée dans la `Sidebar`. -- [ ] Le titre affiche le nom de l'enquête. -- [ ] Tous les dossiers racine apparaissent. -- [ ] Les branches peuvent être développées et repliées. -- [ ] Les fichiers apparaissent dans les branches. -- [ ] L'ouverture successive de deux enquêtes reconstruit correctement l'affichage. -- [ ] La fermeture ne produit aucun warning critique. -- [ ] Le Core n'est pas modifié. - ---- - -## Tests manuels - -1. Lancer l'application. -2. Ouvrir le dossier `Template`. -3. Vérifier l'affichage des dossiers racine. -4. Développer `00_BaseDeDonnees`. -5. Vérifier la présence de `Enquete.sqlite`. -6. Développer plusieurs niveaux. -7. Fermer l'application. -8. Rouvrir avec une autre enquête. -9. Vérifier que l'ancien arbre a disparu. -10. Lancer `make test`. - ---- - -## Commit attendu - -```text -feat(gui): integrate investigation tree into sidebar -``` diff --git a/docs/tickets/closed/TICKET-014.md b/docs/tickets/closed/TICKET-014.md deleted file mode 100644 index fd4edb8..0000000 --- a/docs/tickets/closed/TICKET-014.md +++ /dev/null @@ -1,244 +0,0 @@ -# Ticket #014 - -## Titre - -Ajouter la sélection d'un nœud dans l'arborescence. - ---- - -## Objectif - -Permettre à l'utilisateur de sélectionner un dossier ou un fichier dans -`InvestigationTreeView`. - -Le nœud sélectionné doit être transmis jusqu'au module `Application`, qui -reste responsable de la coordination entre l'arborescence et le reste de -l'interface. - -Ce ticket ne doit encore ouvrir aucun fichier. - ---- - -## Architecture - -```text -GtkListView - │ - ▼ -InvestigationTreeView - │ - ▼ -Sidebar - │ - ▼ -MainWindow - │ - ▼ -Application -``` - -Le Core reste indépendant de GTK. - ---- - -## Responsabilités - -### InvestigationTreeView - -Le module doit : - -- remplacer `GtkNoSelection` par `GtkSingleSelection` ; -- détecter les changements de sélection ; -- retrouver le `InvestigationNode` métier correspondant ; -- appeler un callback public avec le nœud sélectionné ; -- transmettre `NULL` lorsqu'aucun nœud n'est sélectionné. - -### Sidebar - -Le module doit : - -- recevoir un callback de sélection ; -- le transmettre à `InvestigationTreeView` ; -- ne contenir aucune logique métier liée à la sélection. - -### MainWindow - -Le module doit : - -- recevoir le callback depuis `Application` ; -- le transmettre à `Sidebar`. - -### Application - -Le module doit : - -- recevoir le nœud sélectionné ; -- afficher temporairement son nom et son type dans le terminal ; -- ne pas modifier ni libérer le nœud reçu. - ---- - -## Principe de propriété - -Le nœud sélectionné appartient toujours au -`InvestigationTreeModel`, lui-même possédé par `Application`. - -Le callback reçoit uniquement une référence non propriétaire : - -```c -const InvestigationNode *node; -``` - -Le code appelé ne doit jamais faire : - -```c -investigation_node_free(node); -``` - -La référence reste valide tant que le modèle courant n'est pas remplacé ou -détruit. - ---- - -## Interfaces publiques à ajouter - -### InvestigationTreeView - -```c -typedef void (*InvestigationTreeViewSelectionCallback)( - const InvestigationNode *node, - gpointer user_data -); -``` - -```c -void investigation_tree_view_set_selection_callback( - InvestigationTreeView *tree_view, - InvestigationTreeViewSelectionCallback callback, - gpointer user_data -); -``` - -### Sidebar - -```c -void sidebar_set_selection_callback( - Sidebar *sidebar, - InvestigationTreeViewSelectionCallback callback, - gpointer user_data -); -``` - -### MainWindow - -```c -void main_window_set_tree_selection_callback( - MainWindow *main_window, - InvestigationTreeViewSelectionCallback callback, - gpointer user_data -); -``` - ---- - -## Comportement attendu - -Lorsque l'utilisateur sélectionne : - -```text -Enquete.sqlite -``` - -le terminal affiche temporairement : - -```text -Nœud sélectionné : Enquete.sqlite -Type : fichier -``` - -Pour un dossier : - -```text -Nœud sélectionné : 00_BaseDeDonnees -Type : dossier -``` - -Lorsqu'aucun élément n'est sélectionné, le callback reçoit `NULL`. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- ouvrir un fichier ; -- modifier le Workspace ; -- afficher un aperçu ; -- sélectionner plusieurs nœuds ; -- ajouter un menu contextuel ; -- afficher des icônes ; -- modifier le Core ; -- modifier le système de fichiers. - ---- - -## Contraintes techniques - -- GTK4 uniquement ; -- utiliser `GtkSingleSelection` ; -- aucun `GtkTreeView` ; -- aucun état global ; -- callback documenté avec Doxygen ; -- aucune destruction du nœud sélectionné ; -- compilation sans warning ; -- aucun `Gtk-CRITICAL`. - ---- - -## Gestion des changements de modèle - -Lorsqu'un nouveau modèle est installé : - -- la sélection précédente doit être supprimée ; -- aucun callback ne doit conserver une référence vers un nœud de l'ancien - modèle ; -- la nouvelle vue doit démarrer sans sélection. - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] `make test` reste entièrement valide. -- [ ] Un seul nœud peut être sélectionné. -- [ ] La sélection d'un dossier est détectée. -- [ ] La sélection d'un fichier est détectée. -- [ ] Le bon `InvestigationNode` est transmis au callback. -- [ ] `Application` reçoit l'événement. -- [ ] Le nom et le type sont affichés dans le terminal. -- [ ] Le changement d'enquête efface l'ancienne sélection. -- [ ] Aucun module graphique ne libère le nœud. -- [ ] Aucun `Gtk-CRITICAL`. - ---- - -## Tests manuels - -1. Lancer l'application. -2. Ouvrir le dossier `Template`. -3. Développer `00_BaseDeDonnees`. -4. Sélectionner `Enquete.sqlite`. -5. Vérifier le nom et le type dans le terminal. -6. Sélectionner un dossier. -7. Vérifier que le type affiché est `dossier`. -8. Ouvrir une autre enquête. -9. Vérifier qu'aucune ancienne sélection n'est conservée. -10. Lancer `make test`. - ---- - -## Commit attendu - -```text -feat(gui): add investigation tree selection -``` diff --git a/docs/tickets/closed/TICKET-015.md b/docs/tickets/closed/TICKET-015.md deleted file mode 100644 index 0493f81..0000000 --- a/docs/tickets/closed/TICKET-015.md +++ /dev/null @@ -1,225 +0,0 @@ -# Ticket #015 - -## Titre - -Afficher le nœud sélectionné dans le `Workspace`. - ---- - -## Objectif - -Afficher dans la zone de travail les informations principales du nœud sélectionné dans l'arborescence. - -Lorsqu'un dossier ou un fichier est sélectionné, le `Workspace` doit afficher : - -- son nom ; -- son type ; -- son parent éventuel ; -- son nombre d'enfants s'il s'agit d'un dossier. - -Aucun fichier ne doit encore être ouvert. - ---- - -## Architecture - -```text -InvestigationTreeView - │ - ▼ -Application - │ - ▼ -MainWindow - │ - ▼ -Workspace -``` - -`Application` reste le coordinateur. - -`InvestigationTreeView` détecte la sélection. - -`Workspace` affiche les informations reçues. - ---- - -## Responsabilités - -### Application - -Le module doit : - -- recevoir le nœud sélectionné ; -- transmettre ce nœud à `MainWindow` ; -- ne pas modifier ni libérer le nœud. - -### MainWindow - -Le module doit : - -- recevoir un nœud en lecture seule ; -- le transmettre au `Workspace`. - -### Workspace - -Le module doit : - -- recevoir un `InvestigationNode` en lecture seule ; -- afficher son nom ; -- afficher son type ; -- afficher le nom de son parent si disponible ; -- afficher le nombre d'enfants pour un dossier ; -- restaurer la page d'accueil si le nœud vaut `NULL`. - ---- - -## Principe de propriété - -Le nœud sélectionné reste la propriété du `InvestigationTreeModel`. - -`Application`, `MainWindow` et `Workspace` ne reçoivent qu'une référence non propriétaire : - -```c -const InvestigationNode *node; -``` - -Aucun de ces modules ne doit appeler : - -```c -investigation_node_free(node); -``` - ---- - -## Fichiers concernés - -```text -include/widgets/workspace.h -src/widgets/workspace.c - -include/views/main_window.h -src/views/main_window.c - -src/core/application.c -``` - -Aucune modification du Core métier n'est nécessaire. - ---- - -## Interfaces publiques à ajouter - -### Workspace - -```c -void workspace_set_selected_node( - Workspace *workspace, - const InvestigationNode *node -); -``` - -### MainWindow - -```c -void main_window_set_selected_node( - MainWindow *main_window, - const InvestigationNode *node -); -``` - ---- - -## Comportement attendu - -### Aucun nœud sélectionné - -```text -Labfy Investigation - -Aucune enquête ouverte - -Sélectionnez ou créez une enquête -``` - -### Dossier sélectionné - -```text -00_BaseDeDonnees - -Type : dossier -Parent : Template -Enfants : 2 -``` - -### Fichier sélectionné - -```text -Enquete.sqlite - -Type : fichier -Parent : 00_BaseDeDonnees -``` - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- ouvrir le contenu d'un fichier ; -- afficher un aperçu ; -- lire les métadonnées du système de fichiers ; -- afficher la taille d'un fichier ; -- communiquer avec SQLite ; -- modifier l'arborescence ; -- gérer plusieurs sélections. - ---- - -## Contraintes techniques - -- C17 ; -- GTK4 uniquement ; -- aucun état global ; -- aucune propriété du nœud transférée au `Workspace` ; -- documentation Doxygen ; -- compilation sans warning ; -- aucun `Gtk-CRITICAL`. - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] `make test` reste valide. -- [ ] La sélection d'un dossier met à jour le `Workspace`. -- [ ] La sélection d'un fichier met à jour le `Workspace`. -- [ ] Le nom est correct. -- [ ] Le type est correct. -- [ ] Le parent est correct. -- [ ] Le nombre d'enfants est correct pour un dossier. -- [ ] Une sélection `NULL` restaure la page d'accueil. -- [ ] Aucun module graphique ne libère le nœud. -- [ ] Aucun `Gtk-CRITICAL`. - ---- - -## Tests manuels - -1. Ouvrir une enquête. -2. Sélectionner un dossier. -3. Vérifier les informations affichées. -4. Sélectionner un fichier. -5. Vérifier les informations affichées. -6. Changer d'enquête. -7. Vérifier que l'ancien nœud n'est plus affiché. -8. Lancer `make test`. - ---- - -## Commit attendu - -```text -feat(gui): display selected node in workspace -``` diff --git a/docs/tickets/closed/TICKET-016.md b/docs/tickets/closed/TICKET-016.md deleted file mode 100644 index 945b6ae..0000000 --- a/docs/tickets/closed/TICKET-016.md +++ /dev/null @@ -1,289 +0,0 @@ -# Ticket #016 - -## Titre - -Structurer le `Workspace` avec `GtkStack`. - ---- - -## Objectif - -Remplacer la gestion manuelle de visibilité des pages du `Workspace` par un -`GtkStack`. - -Le `Workspace` doit pouvoir afficher proprement plusieurs pages internes sans -modifier son API publique actuelle. - -Ce ticket prépare l'ajout futur de nouvelles vues : - -- aperçu texte ; -- aperçu image ; -- aperçu PDF ; -- chronologie ; -- fiches d'entités ; -- rapports. - ---- - -## Architecture - -```text -Workspace -└── GtkStack - ├── WelcomePage - └── NodeInformationPage -``` - -Plus tard : - -```text -Workspace -└── GtkStack - ├── WelcomePage - ├── NodeInformationPage - ├── TextPreviewPage - ├── ImagePreviewPage - ├── PdfPreviewPage - └── EntityPage -``` - -Le `Workspace` reste responsable de son affichage interne. - ---- - -## Responsabilités - -Le module `Workspace` doit : - -- créer un `GtkStack` comme widget racine interne ; -- ajouter une page d'accueil ; -- ajouter une page d'informations sur le nœud sélectionné ; -- afficher la page d'accueil lorsqu'aucun nœud n'est sélectionné ; -- afficher la page d'informations lorsqu'un nœud est sélectionné ; -- conserver l'API publique existante. - ---- - -## API publique conservée - -Aucune nouvelle fonction publique n'est requise. - -L'API reste : - -```c -Workspace *workspace_new(void); - -GtkWidget *workspace_get_widget( - const Workspace *workspace -); - -void workspace_set_selected_node( - Workspace *workspace, - const InvestigationNode *node -); - -void workspace_free( - Workspace *workspace -); -``` - ---- - -## Fichiers concernés - -```text -src/widgets/workspace.c -``` - -Éventuellement : - -```text -include/widgets/workspace.h -``` - -uniquement pour mettre à jour la documentation. - -Aucun autre module ne doit être modifié. - ---- - -## Structure interne attendue - -```c -struct Workspace -{ - GtkWidget *root_widget; - GtkWidget *stack; - - GtkWidget *welcome_page; - GtkWidget *welcome_title_label; - GtkWidget *welcome_status_label; - GtkWidget *welcome_instruction_label; - - GtkWidget *node_page; - GtkWidget *node_name_label; - GtkWidget *node_type_label; - GtkWidget *node_parent_label; - GtkWidget *node_children_label; -}; -``` - -Les noms exacts peuvent varier, mais doivent rester explicites. - ---- - -## Pages attendues - -### Page d'accueil - -Nom interne : - -```text -welcome -``` - -Contenu : - -```text -Labfy Investigation - -Aucune enquête ouverte - -Sélectionnez ou créez une enquête -``` - -### Page d'informations - -Nom interne : - -```text -node-information -``` - -Contenu pour un dossier : - -```text -00_BaseDeDonnees - -Type : dossier -Parent : Template -Enfants : 2 -``` - -Contenu pour un fichier : - -```text -Enquete.sqlite - -Type : fichier -Parent : 00_BaseDeDonnees -``` - ---- - -## Comportement attendu - -Lorsque : - -```c -workspace_set_selected_node(workspace, NULL); -``` - -le `GtkStack` doit afficher : - -```text -welcome -``` - -Lorsqu'un nœud valide est transmis : - -```c -workspace_set_selected_node(workspace, node); -``` - -le `GtkStack` doit afficher : - -```text -node-information -``` - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- ouvrir un fichier ; -- afficher son contenu ; -- ajouter une barre de navigation ; -- ajouter une animation personnalisée ; -- afficher plusieurs nœuds simultanément ; -- modifier le Core ; -- communiquer avec SQLite. - ---- - -## Contraintes techniques - -- GTK4 uniquement ; -- utiliser `GtkStack` ; -- aucune gestion manuelle de visibilité entre les pages ; -- aucun état global ; -- aucun changement de propriété des nœuds ; -- documentation cohérente ; -- compilation sans warning ; -- aucun `Gtk-CRITICAL`. - ---- - -## Gestion de la propriété - -Le `Workspace` possède uniquement sa structure d'encapsulation. - -Les widgets sont gérés par l'arbre GTK une fois intégrés dans la fenêtre. - -Le nœud reçu reste la propriété du `InvestigationTreeModel`. - -Le `Workspace` ne doit jamais appeler : - -```c -investigation_node_free(node); -``` - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] `make test` reste entièrement valide. -- [ ] `GtkStack` est utilisé. -- [ ] La page d'accueil apparaît sans sélection. -- [ ] La page d'informations apparaît après sélection. -- [ ] Le passage d'une page à l'autre fonctionne. -- [ ] Aucun appel manuel à `gtk_widget_set_visible()` n'est utilisé pour changer de page. -- [ ] L'API publique de `Workspace` reste stable. -- [ ] Aucun autre module n'est modifié. -- [ ] Aucun `Gtk-CRITICAL`. - ---- - -## Tests manuels - -1. Lancer l'application. -2. Ouvrir une enquête. -3. Vérifier que la page d'accueil est affichée sans sélection. -4. Sélectionner un dossier. -5. Vérifier l'affichage de la page d'informations. -6. Sélectionner un fichier. -7. Vérifier la mise à jour de la même page. -8. Changer d'enquête. -9. Vérifier le retour à la page d'accueil. -10. Lancer `make test`. - ---- - -## Commit attendu - -```text -refactor(gui): use GtkStack in workspace -``` diff --git a/docs/tickets/closed/TICKET-017.md b/docs/tickets/closed/TICKET-017.md deleted file mode 100644 index e2c234f..0000000 --- a/docs/tickets/closed/TICKET-017.md +++ /dev/null @@ -1,241 +0,0 @@ -# Ticket #017 - -## Titre - -Ajouter le chemin complet à `InvestigationNode`. - ---- - -## Objectif - -Faire évoluer `InvestigationNode` afin que chaque nœud connaisse le chemin -complet qu'il représente sur le système de fichiers. - -Cette information permettra ensuite au `Workspace` et aux futurs visualiseurs -de savoir exactement quel fichier ou dossier est sélectionné. - ---- - -## Responsabilités - -Le module `InvestigationNode` doit : - -- mémoriser un chemin complet ; -- posséder sa propre copie de ce chemin ; -- exposer le chemin en lecture seule ; -- libérer correctement cette chaîne lors de sa destruction. - -Le module `InvestigationTreeBuilder` doit : - -- fournir le chemin complet lors de la création de chaque nœud ; -- construire correctement le chemin des enfants ; -- ne jamais reconstruire le chemin dans la GUI. - ---- - -## Architecture - -```text -InvestigationTreeBuilder - │ - ▼ -InvestigationNode -├── name -├── path -├── type -├── parent -└── children -``` - -Le chemin appartient au Core. - -La couche graphique ne fait que le lire. - ---- - -## Fichiers concernés - -```text -include/core/investigation_node.h -src/core/investigation_node.c - -src/core/investigation_tree_builder.c - -tests/test_investigation_node.c -tests/test_investigation_tree_builder.c -``` - -Aucune modification graphique dans ce ticket. - ---- - -## API publique à faire évoluer - -Le constructeur devient : - -```c -InvestigationNode *investigation_node_new( - const char *name, - const char *path, - InvestigationNodeType type -); -``` - -Un nouveau getter est ajouté : - -```c -const char *investigation_node_get_path( - const InvestigationNode *node -); -``` - ---- - -## Principe de propriété - -Le nœud copie le chemin reçu avec une allocation dédiée. - -Après : - -```c -node = investigation_node_new( - "Enquete.sqlite", - "/home/fy59/Enquetes/Test/00_BaseDeDonnees/Enquete.sqlite", - INVESTIGATION_NODE_FILE -); -``` - -le code appelant peut modifier ou libérer ses propres chaînes. - -Le nœud reste propriétaire de ses copies internes. - ---- - -## Structure interne attendue - -```c -struct InvestigationNode -{ - char *name; - char *path; - InvestigationNodeType type; - InvestigationNode *parent; - GPtrArray *children; -}; -``` - -La structure reste opaque. - ---- - -## Comportement attendu - -Pour le dossier racine : - -```text -Nom : -Test - -Chemin : -/home/fy59/Enquetes/Test -``` - -Pour un fichier enfant : - -```text -Nom : -Enquete.sqlite - -Chemin : -/home/fy59/Enquetes/Test/00_BaseDeDonnees/Enquete.sqlite -``` - ---- - -## Règles de validation - -Le constructeur doit refuser : - -- `name == NULL` ; -- un nom vide ; -- `path == NULL` ; -- un chemin vide. - -Le getter doit retourner : - -```c -NULL -``` - -si le nœud vaut `NULL`. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- afficher le chemin dans le `Workspace` ; -- ouvrir un fichier ; -- normaliser les permissions ; -- résoudre les liens symboliques ; -- calculer un chemin relatif ; -- modifier le système de fichiers ; -- ajouter des métadonnées. - ---- - -## Contraintes techniques - -- C17 ; -- GLib autorisée ; -- aucune dépendance GTK ; -- structure opaque ; -- aucun état global ; -- documentation Doxygen ; -- compilation sans warning ; -- aucune fuite mémoire. - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] `InvestigationNode` possède un chemin. -- [ ] Le chemin est copié. -- [ ] Le getter retourne le bon chemin. -- [ ] Les chemins racine et enfants sont corrects. -- [ ] Les noms invalides sont refusés. -- [ ] Les chemins invalides sont refusés. -- [ ] Le builder construit correctement tous les chemins. -- [ ] Tous les tests existants sont adaptés. -- [ ] `make test` reste entièrement valide. -- [ ] Aucun code GTK n'est modifié. - ---- - -## Tests - -### InvestigationNode - -- créer un nœud avec un chemin valide ; -- lire le chemin ; -- tester `path == NULL` ; -- tester un chemin vide ; -- vérifier que la chaîne est copiée ; -- tester `investigation_node_get_path(NULL)`. - -### InvestigationTreeBuilder - -- vérifier le chemin de la racine ; -- vérifier le chemin de `DirectoryA` ; -- vérifier le chemin de `FileA.txt` ; -- vérifier le chemin de `RootFile.md`. - ---- - -## Commit attendu - -```text -feat(core): add path to investigation nodes -``` diff --git a/docs/tickets/closed/TICKET-018.md b/docs/tickets/closed/TICKET-018.md deleted file mode 100644 index a02d2ae..0000000 --- a/docs/tickets/closed/TICKET-018.md +++ /dev/null @@ -1,196 +0,0 @@ -# Ticket #018 - -## Titre - -Afficher le chemin complet du nœud sélectionné dans le Workspace. - ---- - -## Objectif - -Afficher le chemin complet du fichier ou du dossier actuellement sélectionné. - -Le `Workspace` doit utiliser exclusivement le getter : - -```c -investigation_node_get_path() -``` - -Aucune reconstruction du chemin ne doit être réalisée dans la couche graphique. - ---- - -## Architecture - -```text -InvestigationNode - │ - ▼ -Application - │ - ▼ -MainWindow - │ - ▼ -Workspace -``` - -Le Core reste propriétaire des informations. - -Le `Workspace` les affiche uniquement. - ---- - -## Responsabilités - -### InvestigationNode - -Aucune modification. - -### Application - -Aucune modification. - -### MainWindow - -Aucune modification. - -### Workspace - -Le module doit : - -- afficher le chemin complet du nœud sélectionné ; -- masquer cette information lorsqu'aucun nœud n'est sélectionné. - ---- - -## Fichiers concernés - -```text -src/widgets/workspace.c -``` - -Aucune modification du Core. - ---- - -## Interface publique - -Aucune modification. - -L'API du `Workspace` reste inchangée. - ---- - -## Affichage attendu - -### Dossier - -```text -00_BaseDeDonnees - -Chemin : -/home/fy59/Documents/Enquetes/Test/00_BaseDeDonnees - -Type : -Dossier - -Parent : -Template - -Enfants : -2 -``` - -### Fichier - -```text -Enquete.sqlite - -Chemin : -/home/fy59/Documents/Enquetes/Test/00_BaseDeDonnees/Enquete.sqlite - -Type : -Fichier - -Parent : -00_BaseDeDonnees -``` - ---- - -## Comportement attendu - -Le chemin affiché doit toujours être identique à : - -```c -investigation_node_get_path(node) -``` - -Le `Workspace` ne doit jamais construire lui-même : - -```text -parent + "/" + nom -``` - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- ouvrir le fichier ; -- vérifier que le chemin existe encore ; -- afficher la taille ; -- afficher les permissions ; -- afficher la date de modification ; -- ouvrir le gestionnaire de fichiers. - ---- - -## Contraintes techniques - -- GTK4 uniquement ; -- aucun état global ; -- aucune allocation mémoire supplémentaire pour le chemin ; -- utiliser directement le pointeur retourné par - `investigation_node_get_path()`; -- documentation Doxygen ; -- compilation sans warning. - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] `make test` reste valide. -- [ ] Le chemin du dossier est affiché. -- [ ] Le chemin du fichier est affiché. -- [ ] La page d'accueil reste inchangée. -- [ ] Aucun chemin n'est reconstruit dans la GUI. -- [ ] Aucun `Gtk-CRITICAL`. - ---- - -## Tests - -1. Lancer l'application. -2. Sélectionner un dossier. -3. Vérifier le chemin affiché. -4. Sélectionner un fichier. -5. Vérifier le chemin affiché. -6. Comparer avec : - -```c -investigation_node_get_path(node) -``` - -7. Vérifier que `make test` reste valide. - ---- - -## Commit attendu - -```text -feat(gui): display selected node path -``` diff --git a/docs/tickets/closed/TICKET-019.md b/docs/tickets/closed/TICKET-019.md deleted file mode 100644 index 5612eef..0000000 --- a/docs/tickets/closed/TICKET-019.md +++ /dev/null @@ -1,208 +0,0 @@ -# Ticket #019 - -## Titre - -Afficher une icône selon le type de nœud dans l'arborescence. - ---- - -## Objectif - -Améliorer la lisibilité de `InvestigationTreeView` en affichant une icône -devant chaque dossier ou fichier. - -Les icônes doivent être déterminées uniquement dans la couche graphique. - ---- - -## Architecture - -```text -InvestigationNode - │ - ▼ -InvestigationTreeView - │ - ▼ -GtkImage + GtkLabel -``` - -Le Core fournit : - -- le nom ; -- le chemin ; -- le type. - -La vue choisit l'icône à afficher. - ---- - -## Responsabilités - -### InvestigationTreeView - -Le module doit : - -- afficher une icône devant chaque nœud ; -- utiliser une icône de dossier pour les répertoires ; -- utiliser une icône générique pour les fichiers inconnus ; -- choisir certaines icônes spécialisées selon l'extension ; -- conserver le nom du nœud à côté de l'icône ; -- rester compatible avec `GtkTreeExpander`. - ---- - -## Fichiers concernés - -```text -src/widgets/investigation_tree_view.c -``` - -Éventuellement : - -```text -include/widgets/investigation_tree_view.h -``` - -uniquement si la documentation doit être précisée. - -Aucune modification du Core. - ---- - -## Extensions reconnues - -Première version minimale : - -```text -.sqlite .db -.jpg .jpeg .png .webp -.pdf -.txt .md .log -.csv -.zip .tar .gz .xz -.mp4 .mkv .avi .mov -``` - -Les extensions inconnues utilisent une icône de fichier générique. - -La comparaison doit être insensible à la casse. - ---- - -## Icônes GTK attendues - -Utiliser les noms d'icônes du thème système, par exemple : - -```text -folder-symbolic -text-x-generic-symbolic -application-pdf-symbolic -image-x-generic-symbolic -video-x-generic-symbolic -package-x-generic-symbolic -x-office-spreadsheet-symbolic -folder-database-symbolic -``` - -Si une icône spécialisée n'est pas disponible dans le thème, GTK doit -retomber proprement sur une icône générique. - ---- - -## Structure visuelle d'une ligne - -```text -GtkTreeExpander -└── GtkBox horizontal - ├── GtkImage - └── GtkLabel -``` - -Le label continue d'afficher le nom du nœud. - ---- - -## Fonctions privées suggérées - -```c -static const char *investigation_tree_view_get_icon_name( - const InvestigationNode *node -); -``` - -Cette fonction doit : - -- retourner `folder-symbolic` pour un dossier ; -- inspecter l'extension pour un fichier ; -- retourner une icône générique si aucune extension ne correspond. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- charger des miniatures ; -- analyser le contenu réel des fichiers ; -- lire les types MIME ; -- modifier le Core ; -- ouvrir les fichiers ; -- colorer les lignes ; -- ajouter des badges ; -- ajouter un menu contextuel. - ---- - -## Contraintes techniques - -- GTK4 uniquement ; -- utiliser `GtkImage` ; -- utiliser les icônes du thème système ; -- aucun fichier d'icône embarqué ; -- aucun état global ; -- aucune lecture directe du système de fichiers ; -- compilation sans warning ; -- aucun `Gtk-CRITICAL`. - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] `make test` reste valide. -- [ ] Les dossiers affichent une icône de dossier. -- [ ] Les fichiers génériques affichent une icône de fichier. -- [ ] Les PDF ont une icône dédiée. -- [ ] Les images ont une icône dédiée. -- [ ] Les vidéos ont une icône dédiée. -- [ ] Les archives ont une icône dédiée. -- [ ] Les bases SQLite ont une icône dédiée. -- [ ] Le nom du nœud reste visible. -- [ ] Le développement et le repli fonctionnent toujours. -- [ ] La sélection fonctionne toujours. -- [ ] Aucun code Core n'est modifié. -- [ ] Aucun `Gtk-CRITICAL`. - ---- - -## Tests manuels - -1. Ouvrir une enquête contenant plusieurs types de fichiers. -2. Vérifier l'icône des dossiers. -3. Vérifier une image. -4. Vérifier un PDF. -5. Vérifier une base SQLite. -6. Vérifier une archive. -7. Vérifier un fichier inconnu. -8. Développer et replier plusieurs branches. -9. Sélectionner plusieurs nœuds. -10. Lancer `make test`. - ---- - -## Commit attendu - -```text -feat(gui): add icons to investigation tree -``` diff --git a/docs/tickets/closed/TICKET-020.md b/docs/tickets/closed/TICKET-020.md deleted file mode 100644 index 27f66b5..0000000 --- a/docs/tickets/closed/TICKET-020.md +++ /dev/null @@ -1,257 +0,0 @@ -# Ticket #020 - -## Titre - -Créer une nouvelle enquête. - ---- - -## Objectif - -Ajouter la capacité de créer automatiquement une nouvelle enquête dans un dossier choisi par l'utilisateur. - -La création doit produire une arborescence standard et préparer l'emplacement de la future base SQLite. - -Ce ticket ne crée pas encore le schéma SQL complet. - ---- - -## Architecture - -```text -Application - │ - ▼ -InvestigationProject - │ - ▼ -FileSystem -``` - -Le module `InvestigationProject` devient le point d'entrée métier pour la création d'une enquête. - -La GUI ne doit jamais créer directement les dossiers. - ---- - -## Responsabilités - -### InvestigationProject - -Le module doit : - -- recevoir le chemin du dossier parent ; -- recevoir le nom de la nouvelle enquête ; -- créer le dossier racine de l'enquête ; -- créer l'arborescence standard ; -- créer le dossier `00_BaseDeDonnees` ; -- créer un fichier SQLite vide nommé `Enquete.sqlite` ; -- nettoyer ce qui a été créé en cas d'échec partiel ; -- retourner le chemin complet de l'enquête créée. - ---- - -## Arborescence à créer - -```text -NomEnquete/ -├── 00_BaseDeDonnees/ -│ └── Enquete.sqlite -├── 01_Preuves_Originales/ -│ ├── Captures_Ecran/ -│ ├── Conversations/ -│ ├── Documents/ -│ ├── Emails/ -│ ├── Photos/ -│ └── Videos/ -├── 02_Preuves_Traitees/ -│ ├── Annotations/ -│ ├── Extractions/ -│ ├── OCR/ -│ └── Redactions/ -├── 03_Chronologie/ -├── 04_Entites/ -│ ├── Adresses_Email/ -│ ├── Comptes_Bancaires/ -│ ├── Comptes_Facebook/ -│ ├── Comptes_Instagram/ -│ ├── Documents_Identite/ -│ ├── IBAN/ -│ ├── Personnes/ -│ ├── Pseudonymes/ -│ ├── Telephones/ -│ └── Autres/ -├── 05_Rapports/ -├── 06_Exports/ -├── 07_Notes/ -├── 08_Sources/ -└── 09_Hash/ -``` - -Les noms de dossiers ne doivent pas contenir d'accents. - ---- - -## Interface publique attendue - -Créer : - -```text -include/core/investigation_project.h -src/core/investigation_project.c -``` - -Avec : - -```c -char *investigation_project_create( - const char *parent_directory, - const char *investigation_name -); -``` - ---- - -## Contrat de propriété - -En cas de succès, la fonction retourne une nouvelle chaîne allouée contenant le chemin complet du dossier d'enquête. - -Le code appelant devient propriétaire de cette chaîne et doit la libérer avec : - -```c -g_free(investigation_path); -``` - -En cas d'échec, la fonction retourne : - -```c -NULL -``` - ---- - -## Règles de validation - -La fonction doit refuser : - -- `parent_directory == NULL` ; -- un chemin parent vide ; -- `investigation_name == NULL` ; -- un nom vide ; -- un dossier parent inexistant ; -- un chemin parent qui n'est pas un dossier ; -- un dossier d'enquête qui existe déjà ; -- un nom contenant `/`. - ---- - -## Gestion des erreurs - -Si une étape échoue après la création partielle : - -- tous les fichiers créés par la fonction doivent être supprimés ; -- tous les dossiers créés par la fonction doivent être supprimés ; -- aucun dossier partiel ne doit rester sur le disque ; -- la fonction retourne `NULL`. - -La fonction ne doit jamais supprimer un dossier qui existait avant son appel. - ---- - -## Création de `Enquete.sqlite` - -Pour ce ticket, le fichier doit seulement être créé. - -Le schéma SQLite sera initialisé dans le ticket #022. - -Le fichier attendu est : - -```text -00_BaseDeDonnees/Enquete.sqlite -``` - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- créer les tables SQLite ; -- générer un UUID ; -- créer les métadonnées ; -- importer une enquête existante ; -- modifier l'interface GTK ; -- ouvrir automatiquement l'enquête créée ; -- créer un rapport ; -- copier des preuves. - ---- - -## Dépendances - -- C17 ; -- GLib ; -- GIO autorisé. - -Aucune dépendance GTK ou SQLite requise dans ce ticket. - ---- - -## Contraintes techniques - -- structure modulaire ; -- aucun état global ; -- aucune logique de création dans `Application` ; -- aucune logique de création dans les widgets ; -- documentation Doxygen ; -- compilation sans warning ; -- nettoyage complet en cas d'erreur ; -- noms de fonctions préfixés par `investigation_project_`. - ---- - -## Tests - -Créer : - -```text -tests/test_investigation_project.c -``` - -Le test doit : - -- créer un dossier temporaire ; -- créer une enquête valide ; -- vérifier chaque dossier attendu ; -- vérifier la présence de `Enquete.sqlite` ; -- vérifier que la fonction retourne le bon chemin ; -- vérifier le refus des paramètres `NULL` ; -- vérifier le refus des chaînes vides ; -- vérifier le refus d'un nom contenant `/` ; -- vérifier le refus si le dossier existe déjà ; -- supprimer complètement l'enquête de test ; -- vérifier qu'aucun résidu ne reste. - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] `make test` reste valide. -- [ ] Une enquête complète peut être créée. -- [ ] Tous les dossiers attendus existent. -- [ ] `Enquete.sqlite` existe. -- [ ] Aucun dossier partiel ne reste en cas d'échec. -- [ ] Un dossier existant n'est jamais écrasé. -- [ ] Le chemin retourné est correct. -- [ ] Aucune dépendance GTK. -- [ ] Aucun code SQLite métier. -- [ ] Le nouveau test est intégré à `make test`. - ---- - -## Commit attendu - -```text -feat(core): create investigation project structure -``` diff --git a/docs/tickets/closed/TICKET-021.md b/docs/tickets/closed/TICKET-021.md deleted file mode 100644 index d601285..0000000 --- a/docs/tickets/closed/TICKET-021.md +++ /dev/null @@ -1,254 +0,0 @@ -# Ticket #021 - -## Titre - -Valider une enquête existante. - ---- - -## Objectif - -Ajouter au module `InvestigationProject` la capacité de vérifier qu’un dossier -correspond bien à une enquête Labfy Investigation valide. - -La validation doit contrôler la présence et le type des éléments obligatoires, -sans modifier le contenu du dossier. - ---- - -## Architecture - -```text -Application - │ - ▼ -InvestigationProject - │ - ▼ -FileSystem -``` - -Toute ouverture d’enquête existante doit passer par -`InvestigationProject`. - -La GUI ne doit jamais décider seule si un dossier est valide. - ---- - -## Responsabilités - -### InvestigationProject - -Le module doit : - -- recevoir le chemin d’un dossier ; -- vérifier que le chemin existe ; -- vérifier qu’il désigne un dossier ; -- vérifier la présence de l’arborescence obligatoire ; -- vérifier que les dossiers attendus sont bien des dossiers ; -- vérifier la présence de `00_BaseDeDonnees/Enquete.sqlite` ; -- vérifier que `Enquete.sqlite` est un fichier régulier ; -- retourner un résultat clair sans modifier le dossier. - ---- - -## Interface publique attendue - -Faire évoluer : - -```text -include/core/investigation_project.h -src/core/investigation_project.c -``` - -Ajouter : - -```c -bool investigation_project_validate( - const char *investigation_path -); -``` - ---- - -## Contrat - -La fonction retourne : - -```c -true -``` - -si le dossier est une enquête valide. - -Elle retourne : - -```c -false -``` - -si : - -- le chemin est invalide ; -- le dossier n’existe pas ; -- le chemin désigne un fichier ; -- un dossier obligatoire manque ; -- un élément attendu comme dossier est en réalité un fichier ; -- `Enquete.sqlite` manque ; -- `Enquete.sqlite` n’est pas un fichier régulier. - -La fonction ne doit jamais modifier le système de fichiers. - ---- - -## Structure obligatoire - -Les dossiers suivants doivent exister : - -```text -00_BaseDeDonnees -01_Preuves_Originales -02_Preuves_Traitees -03_Chronologie -04_Entites -05_Rapports -06_Exports -07_Notes -08_Sources -09_Hash -``` - -Les sous-dossiers suivants doivent également exister : - -```text -01_Preuves_Originales/Captures_Ecran -01_Preuves_Originales/Conversations -01_Preuves_Originales/Documents -01_Preuves_Originales/Emails -01_Preuves_Originales/Photos -01_Preuves_Originales/Videos - -02_Preuves_Traitees/Annotations -02_Preuves_Traitees/Extractions -02_Preuves_Traitees/OCR -02_Preuves_Traitees/Redactions - -04_Entites/Adresses_Email -04_Entites/Comptes_Bancaires -04_Entites/Comptes_Facebook -04_Entites/Comptes_Instagram -04_Entites/Documents_Identite -04_Entites/IBAN -04_Entites/Personnes -04_Entites/Pseudonymes -04_Entites/Telephones -04_Entites/Autres -``` - -Le fichier suivant doit exister : - -```text -00_BaseDeDonnees/Enquete.sqlite -``` - ---- - -## Réutilisation de la structure déclarative - -La validation doit réutiliser la même liste de chemins que la création. - -Il ne doit pas exister deux listes indépendantes décrivant l’arborescence. - -La structure de référence doit rester centralisée dans -`investigation_project.c`. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- ouvrir SQLite ; -- lire le schéma SQL ; -- vérifier la version de la base ; -- créer les éléments manquants ; -- réparer une enquête ; -- importer automatiquement des fichiers ; -- modifier GTK ; -- ouvrir automatiquement l’enquête dans l’application. - ---- - -## Gestion des erreurs - -Dans ce ticket, la fonction retourne uniquement un booléen. - -Les détails d’erreur plus précis pourront être ajoutés plus tard avec : - -```c -GError -``` - -ou une énumération métier dédiée. - -La validation ne doit produire aucun `g_warning()` pour un dossier simplement -invalide : un résultat `false` suffit. - ---- - -## Contraintes techniques - -- C17 ; -- GLib autorisée ; -- aucune dépendance GTK ; -- aucune dépendance SQLite requise ; -- aucune écriture sur le disque ; -- aucun état global ; -- documentation Doxygen ; -- compilation sans warning. - ---- - -## Tests - -Faire évoluer : - -```text -tests/test_investigation_project.c -``` - -Le test doit vérifier : - -- une enquête complète est valide ; -- `NULL` est refusé ; -- une chaîne vide est refusée ; -- un chemin inexistant est refusé ; -- un fichier simple est refusé ; -- une enquête sans `Enquete.sqlite` est refusée ; -- une enquête avec un dossier obligatoire manquant est refusée ; -- un élément attendu comme dossier mais remplacé par un fichier est refusé ; -- une enquête valide reste inchangée après validation. - ---- - -## Critères d’acceptation - -- [ ] Le projet compile sans warning. -- [ ] `make test` reste entièrement valide. -- [ ] Une enquête créée par `investigation_project_create()` est valide. -- [ ] Un chemin invalide est refusé. -- [ ] Un dossier incomplet est refusé. -- [ ] Un faux fichier `Enquete.sqlite` incorrect est refusé. -- [ ] Aucun élément n’est créé pendant la validation. -- [ ] Aucun élément n’est supprimé pendant la validation. -- [ ] La structure de référence n’est pas dupliquée. -- [ ] Aucune dépendance GTK. -- [ ] Aucun `Gtk-CRITICAL`. - ---- - -## Commit attendu - -```text -feat(core): validate investigation project structure -``` diff --git a/docs/tickets/closed/TICKET-022.md b/docs/tickets/closed/TICKET-022.md deleted file mode 100644 index 32b2cb5..0000000 --- a/docs/tickets/closed/TICKET-022.md +++ /dev/null @@ -1,368 +0,0 @@ -# Ticket #022 - -## Titre - -Initialiser la base SQLite d'une enquête. - ---- - -## Objectif - -Créer et initialiser correctement le fichier : - -```text -00_BaseDeDonnees/Enquete.sqlite -``` - -avec un premier schéma SQLite versionné. - -La base doit contenir les métadonnées minimales permettant d'identifier -l'enquête et la version du schéma. - ---- - -## Architecture - -```text -InvestigationProject - │ - ▼ -Database - │ - ▼ -SQLite -``` - -`InvestigationProject` orchestre la création de l'enquête. - -Le module `Database` est seul responsable de l'ouverture de SQLite, -de l'exécution du schéma et de la fermeture de la base. - ---- - -## Responsabilités - -### InvestigationProject - -Le module doit : - -- créer l'arborescence ; -- demander au module `Database` d'initialiser `Enquete.sqlite` ; -- considérer la création comme échouée si l'initialisation SQLite échoue ; -- nettoyer toute l'enquête créée en cas d'échec. - -### Database - -Le module doit : - -- ouvrir ou créer le fichier SQLite ; -- démarrer une transaction ; -- créer le schéma initial ; -- insérer les métadonnées ; -- valider la transaction ; -- annuler la transaction en cas d'erreur ; -- fermer proprement la connexion. - ---- - -## Nouveaux fichiers - -```text -include/database/database.h -src/database/database.c -``` - -Éventuellement : - -```text -include/database/schema.h -src/database/schema.c -``` - -si le schéma devient trop volumineux pour rester dans `database.c`. - -Pour ce ticket, un seul module `database.c` est acceptable. - ---- - -## Interface publique attendue - -```c -bool database_initialize( - const char *database_path -); -``` - -La fonction retourne : - -```c -true -``` - -si la base a été correctement initialisée. - -Elle retourne : - -```c -false -``` - -en cas d'erreur. - ---- - -## Schéma initial - -### Table `metadata` - -```sql -CREATE TABLE metadata -( - key TEXT PRIMARY KEY, - value TEXT NOT NULL -); -``` - -### Métadonnées obligatoires - -```text -schema_version -application -created_at -investigation_uuid -``` - -Valeurs attendues : - -```text -schema_version = 1 -application = Labfy Investigation -created_at = date UTC ISO 8601 -investigation_uuid = UUID unique -``` - -Exemple : - -```text -2026-07-14T18:42:15Z -``` - ---- - -## Table `investigation` - -Créer également une table minimale représentant l'enquête : - -```sql -CREATE TABLE investigation -( - id INTEGER PRIMARY KEY CHECK (id = 1), - name TEXT NOT NULL, - root_path TEXT NOT NULL, - created_at TEXT NOT NULL -); -``` - -La table contient une seule ligne correspondant à l'enquête courante. - ---- - -## Données nécessaires - -`database_initialize()` doit recevoir suffisamment d'informations pour -initialiser correctement la base. - -L'interface pourra donc évoluer vers : - -```c -bool database_initialize( - const char *database_path, - const char *investigation_name, - const char *investigation_root_path -); -``` - -Cette signature est préférée pour éviter que le module `Database` -reconstruise ou devine des informations métier. - ---- - -## UUID - -L'UUID doit être généré avec GLib : - -```c -g_uuid_string_random() -``` - -La chaîne retournée doit être libérée avec : - -```c -g_free(uuid); -``` - ---- - -## Date de création - -La date doit être produite en UTC avec GLib. - -Format attendu : - -```text -YYYY-MM-DDTHH:MM:SSZ -``` - -La date doit être enregistrée à la fois : - -- dans `metadata.created_at` ; -- dans `investigation.created_at`. - ---- - -## Transaction - -Toute l'initialisation doit se dérouler dans une transaction : - -```sql -BEGIN IMMEDIATE; -``` - -Puis : - -```sql -COMMIT; -``` - -En cas d'erreur : - -```sql -ROLLBACK; -``` - -Une base partiellement initialisée ne doit jamais être considérée comme valide. - ---- - -## Intégration avec InvestigationProject - -`investigation_project_create()` ne doit plus créer un fichier vide avec : - -```c -g_file_set_contents(...) -``` - -Il doit construire le chemin de la base puis appeler : - -```c -database_initialize( - database_path, - investigation_name, - investigation_path -); -``` - -Si l'appel échoue : - -- le fichier SQLite éventuel est supprimé ; -- tous les dossiers créés sont supprimés ; -- `investigation_project_create()` retourne `NULL`. - ---- - -## Validation - -À partir de ce ticket, `investigation_project_validate()` doit toujours -vérifier la présence du fichier SQLite, mais pas encore son contenu SQL. - -La validation du schéma sera ajoutée dans un prochain ticket dédié. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- créer les tables Preuves ; -- créer les tables Entites ; -- créer les relations ; -- gérer les migrations ; -- ouvrir une enquête existante ; -- modifier GTK ; -- exposer directement `sqlite3 *` hors du module Database. - ---- - -## Contraintes techniques - -- C17 ; -- SQLite3 ; -- GLib ; -- aucune dépendance GTK ; -- aucun état global ; -- requêtes SQL centralisées dans `database.c` ; -- fermeture garantie de la connexion ; -- transaction obligatoire ; -- documentation Doxygen ; -- compilation sans warning. - ---- - -## Tests - -Créer : - -```text -tests/test_database.c -``` - -Le test doit : - -- créer un dossier temporaire ; -- initialiser une base SQLite ; -- vérifier que le fichier existe ; -- ouvrir la base en lecture ; -- vérifier la présence de la table `metadata` ; -- vérifier la présence de la table `investigation` ; -- vérifier `schema_version = 1` ; -- vérifier `application = Labfy Investigation` ; -- vérifier que `created_at` n'est pas vide ; -- vérifier que l'UUID n'est pas vide ; -- vérifier la ligne unique de la table `investigation` ; -- vérifier le nom et le chemin racine ; -- vérifier qu'une initialisation sur un chemin invalide échoue ; -- nettoyer complètement les fichiers temporaires. - -Faire également évoluer : - -```text -tests/test_investigation_project.c -``` - -pour vérifier que la base créée n'est plus vide. - ---- - -## Critères d'acceptation - -- [ ] Le projet compile sans warning. -- [ ] `make test` reste entièrement valide. -- [ ] `Enquete.sqlite` est une vraie base SQLite. -- [ ] La table `metadata` existe. -- [ ] La table `investigation` existe. -- [ ] `schema_version` vaut `1`. -- [ ] Une date UTC est enregistrée. -- [ ] Un UUID est généré. -- [ ] L'enquête est enregistrée dans la base. -- [ ] L'initialisation est transactionnelle. -- [ ] Toute erreur provoque un nettoyage complet. -- [ ] Aucun type `sqlite3 *` n'est exposé publiquement. -- [ ] Aucune dépendance GTK. - ---- - -## Commit attendu - -```text -feat(database): initialize investigation database -``` diff --git a/docs/tickets/closed/TICKET-023.md b/docs/tickets/closed/TICKET-023.md deleted file mode 100644 index 377d2f9..0000000 --- a/docs/tickets/closed/TICKET-023.md +++ /dev/null @@ -1,643 +0,0 @@ -# Ticket #023 - -## Titre - -Consolider le schéma métier initial de l'enquête. - ---- - -## Objectif - -Transformer le schéma SQLite préparé lors des premières phases du projet en -un schéma métier officiel, cohérent, documenté et testable. - -La base existante sert de fondation. - -Le travail ne consiste pas à repartir de zéro, mais à : - -- conserver les concepts métier déjà définis ; -- corriger les incohérences ; -- renforcer les contraintes ; -- uniformiser les conventions ; -- intégrer le schéma au module `Database`. - ---- - -## Base de travail - -La base historique contient notamment les tables suivantes : - -```text -preuves -entites -personnes -chronologie -sources -recherche -hypotheses -journal -tags -types_preuve -types_entite -types_source -types_outils -associations -personnes_entites -entite_tags -preuves_tag -``` - -Les tables créées au ticket #022 restent également obligatoires : - -```text -metadata -investigation -``` - -Le schéma officiel doit donc préserver ces concepts tout en les consolidant. - ---- - -## Architecture - -```text -InvestigationProject - │ - ▼ -Database - │ - ▼ -Schéma SQLite versionné - │ - ├── Métadonnées - ├── Enquête - ├── Preuves - ├── Entités - ├── Personnes - ├── Sources - ├── Chronologie - ├── Recherches - ├── Hypothèses - ├── Journal - └── Tags et relations -``` - -Le module `Database` reste le seul autorisé à exécuter du SQL. - ---- - -## Décisions de conception à officialiser - -### Identifiants - -Les entités métier utiliseront des identifiants texte de type UUID. - -Exemple : - -```text -550e8400-e29b-41d4-a716-446655440000 -``` - -Les identifiants sont générés par l'application avec : - -```c -g_uuid_string_random() -``` - -Les tables de référence simples peuvent utiliser des identifiants entiers. - ---- - -### Dates - -Les dates techniques sont stockées en UTC au format ISO 8601 : - -```text -YYYY-MM-DDTHH:MM:SSZ -``` - -Exemple : - -```text -2026-07-15T08:42:17Z -``` - ---- - -### Nommage - -Les noms SQL utilisent uniquement : - -- des minuscules ; -- du `snake_case` ; -- aucun accent ; -- aucun espace. - -Les noms des tables de liaison sont uniformisés. - -Exemple : - -```text -preuve_tags -entite_tags -personne_entites -``` - -Aucune forme singulier/pluriel incohérente ne doit subsister. - ---- - -### Clés étrangères - -Toutes les relations métier doivent utiliser des clés étrangères explicites. - -Le module `Database` doit activer : - -```sql -PRAGMA foreign_keys = ON; -``` - -à chaque ouverture de connexion. - -Les comportements `ON DELETE` doivent être décidés pour chaque relation. - ---- - -### Tables de liaison - -Chaque table de liaison doit empêcher les doublons grâce à : - -- une clé primaire composite ; -- ou une contrainte `UNIQUE`. - -Exemple : - -```sql -PRIMARY KEY (preuve_id, tag_id) -``` - ---- - -## Tables métier à consolider - -### `preuves` - -Responsabilité : - -- représenter un élément de preuve ; -- mémoriser son nom ; -- son chemin relatif ; -- son type ; -- sa description ; -- ses dates ; -- son hash éventuel ; -- son statut. - -Contraintes minimales : - -- identifiant obligatoire ; -- nom obligatoire ; -- chemin relatif obligatoire ; -- type obligatoire ; -- date de création obligatoire ; -- chemin unique au sein d'une enquête. - ---- - -### `entites` - -Responsabilité : - -- représenter une entité identifiée pendant l'enquête. - -Exemples : - -- adresse email ; -- compte bancaire ; -- profil social ; -- pseudonyme ; -- téléphone ; -- document d'identité. - -Contraintes minimales : - -- identifiant obligatoire ; -- type obligatoire ; -- valeur obligatoire ; -- date de création obligatoire. - ---- - -### `personnes` - -Responsabilité : - -- représenter une personne physique ou un profil humain étudié. - -Le modèle ne doit pas obliger à connaître l'identité civile complète. - -Une personne peut n'avoir qu'un pseudonyme ou une désignation temporaire. - ---- - -### `sources` - -Responsabilité : - -- représenter l'origine d'une information ou d'une preuve. - -Exemples : - -- site web ; -- email ; -- réseau social ; -- document ; -- témoignage ; -- outil OSINT. - ---- - -### `chronologie` - -Responsabilité : - -- mémoriser les événements importants de l'enquête ; -- relier éventuellement un événement à une preuve, une entité ou une source. - ---- - -### `recherches` - -Responsabilité : - -- documenter une opération de recherche ; -- mémoriser la requête ; -- l'outil employé ; -- la date ; -- le résultat ; -- les observations. - ---- - -### `hypotheses` - -Responsabilité : - -- enregistrer une hypothèse de travail ; -- mémoriser son statut ; -- sa justification ; -- les éléments qui la soutiennent ou la contredisent. - ---- - -### `journal` - -Responsabilité : - -- conserver la trace des actions significatives réalisées dans l'enquête. - -Exemples : - -- création d'une preuve ; -- modification d'une entité ; -- calcul d'un hash ; -- génération d'un rapport ; -- import d'un fichier. - ---- - -### `tags` - -Responsabilité : - -- permettre une classification libre des preuves et des entités. - ---- - -## Tables de référence - -Les tables suivantes doivent être consolidées : - -```text -types_preuve -types_entite -types_source -types_outils -``` - -Elles doivent comporter au minimum : - -```sql -id INTEGER PRIMARY KEY -code TEXT NOT NULL UNIQUE -label TEXT NOT NULL -description TEXT -``` - -Les valeurs initiales sont insérées lors de la création de la base. - ---- - -## Tables de liaison - -Les relations suivantes doivent être prévues : - -```text -preuve_tags -entite_tags -personne_entites -``` - -Le schéma existant contient également une table générique : - -```text -associations -``` - -Cette table doit être auditée avant conservation. - -Elle ne doit être gardée que si son rôle est clairement défini et ne fait pas -doublon avec des relations spécialisées. - ---- - -## Audit obligatoire - -Avant d'écrire le schéma définitif, chaque table de la base historique doit -être classée dans l'une des catégories suivantes : - -```text -CONSERVER -MODIFIER -RENOMMER -FUSIONNER -SUPPRIMER -``` - -La décision doit être documentée dans : - -```text -docs/database/SCHEMA_AUDIT_V1.md -``` - -Le document doit contenir au minimum : - -```text -Nom historique -Décision -Nom final -Justification -Modifications prévues -``` - ---- - -## Organisation du module Database - -Le code SQL est organisé par domaine métier. - -``` -include/ -└── database/ - ├── database.h - ├── schema.h - ├── preuve.h - ├── entite.h - ├── personne.h - ├── source.h - ├── chronologie.h - ├── recherche.h - ├── hypothese.h - ├── journal.h - ├── tag.h - ├── type_preuve.h - ├── type_entite.h - ├── type_source.h - └── type_outil.h - -src/ -└── database/ - ├── database.c - ├── schema.c - ├── preuve.c - ├── entite.c - ├── personne.c - ├── source.c - ├── chronologie.c - ├── recherche.c - ├── hypothese.c - ├── journal.c - ├── tag.c - ├── type_preuve.c - ├── type_entite.c - ├── type_source.c - └── type_outil.c - -database/ -├── schema_v1.sql -├── indexes.sql -├── triggers.sql -└── reference_data.sql -``` - ---- - -### Responsabilités - -`database.c` - -- ouverture de SQLite ; -- fermeture ; -- transactions ; -- erreurs ; -- point d'entrée du module Database. - -`schema.c` - -- installation du schéma ; -- migrations ; -- exécution des scripts SQL. - -Chaque module métier est responsable exclusivement de son objet métier. - -Exemple : - -``` -preuve.c -``` - -gère uniquement : - -- création ; -- lecture ; -- modification ; -- suppression logique ; -- gestion des tags de la preuve. - -Les tables de liaison simples ne possèdent pas de module dédié. - -Exemples : - -``` -preuve_tags -personne_entites -entite_tags -``` - -Leur manipulation est réalisée par le module métier correspondant. - ---- - -## Intégration dans `Database` - -Le module `database_initialize()` doit exécuter le schéma officiel contenu -dans : - -```text -database/schema_v1.sql -``` - -Deux approches sont acceptables : - -1. intégrer le schéma au binaire via une ressource GLib ; -2. générer une chaîne C depuis le fichier SQL lors de la compilation. - -Le logiciel installé ne doit pas dépendre d'un chemin relatif fragile vers le -dépôt source. - ---- - -## Principe d'organisation - -Une table métier importante implique systématiquement : - -- une structure C ; -- un module C ; -- des tests ; -- une documentation. - -La correspondance est la suivante : - -| SQL | C | -|-----|---| -| preuves | preuve.c | -| entites | entite.c | -| personnes | personne.c | -| sources | source.c | -| chronologie | chronologie.c | -| journal | journal.c | -| recherches | recherche.c | -| hypotheses | hypothese.c | - ---- - -## Version du schéma - -Le numéro de version reste : - -```text -1 -``` - -tant que Labfy Investigation n'a pas produit de base officiellement publiée. - -Une fois le schéma V1 considéré comme stable et distribué, toute modification -incompatible nécessitera : - -- une nouvelle version ; -- une migration dédiée ; -- une mise à jour de `schema_version`. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- développer les fonctions CRUD ; -- créer les structures C `Preuve`, `Entite` ou `Personne` ; -- connecter les tables à GTK ; -- importer les anciennes données automatiquement ; -- créer les migrations V2 ; -- produire un rapport ; -- ajouter la recherche plein texte. - ---- - -## Contraintes techniques - -- C17 ; -- SQLite3 ; -- GLib ; -- aucune dépendance GTK ; -- toutes les tables utilisent des contraintes explicites ; -- toutes les clés étrangères sont documentées ; -- toutes les tables de liaison empêchent les doublons ; -- aucun SQL métier hors du module `Database` ; -- aucun identifiant généré par SQLite pour les objets métier en UUID ; -- compilation sans warning. - ---- - -## Tests - -Faire évoluer : - -```text -tests/test_database.c -``` - -Les tests doivent vérifier : - -- la présence de toutes les tables officielles ; -- la présence des tables de référence ; -- l'insertion des valeurs initiales ; -- l'activation des clés étrangères ; -- le refus d'une clé étrangère invalide ; -- le refus d'un doublon dans une table de liaison ; -- le refus des colonnes obligatoires manquantes ; -- l'unicité des codes des tables de référence ; -- la valeur `schema_version = 1` ; -- l'intégrité SQLite avec : - -```sql -PRAGMA integrity_check; -``` - ---- - -## Critères d'acceptation - -- [ ] Le schéma historique a été audité. -- [ ] Chaque table possède une décision documentée. -- [ ] Un schéma V1 officiel existe. -- [ ] Les conventions de nommage sont uniformes. -- [ ] Toutes les clés primaires sont explicites. -- [ ] Toutes les clés étrangères sont explicites. -- [ ] Les relations empêchent les doublons. -- [ ] Les colonnes obligatoires utilisent `NOT NULL`. -- [ ] Les tables de référence sont initialisées. -- [ ] `database_initialize()` installe le schéma complet. -- [ ] `PRAGMA integrity_check` retourne `ok`. -- [ ] Tous les tests restent valides. -- [ ] Aucune dépendance GTK. - ---- - -## Livrables - -```text -docs/database/SCHEMA_AUDIT_V1.md -database/schema_v1.sql -include/database/database.h -src/database/database.c -tests/test_database.c -``` - ---- - -## Commit attendu - -```text -feat(database): consolidate initial investigation schema -``` diff --git a/docs/tickets/closed/TICKET-024.md b/docs/tickets/closed/TICKET-024.md deleted file mode 100644 index 82dae89..0000000 --- a/docs/tickets/closed/TICKET-024.md +++ /dev/null @@ -1,436 +0,0 @@ -# Ticket #024 - -## Titre - -Documenter l'architecture de la base de données V1. - ---- - -## Objectif - -Créer une documentation de référence expliquant l'architecture SQLite V1 de -Labfy Investigation. - -Cette documentation doit permettre à un développeur de comprendre : - -- le rôle de chaque table ; -- les relations entre les objets métier ; -- les conventions d'identifiants ; -- les règles sur les dates ; -- la suppression logique ; -- les tables de liaison ; -- les contraintes d'intégrité ; -- la politique de versionnement du schéma. - -Le document ne doit pas recopier intégralement le SQL. - -Il doit expliquer le modèle et les décisions prises. - ---- - -## Livrable principal - -Créer : - -```text -docs/database/DATABASE_ARCHITECTURE.md -``` - ---- - -## Sources de référence - -La documentation doit rester cohérente avec : - -```text -database/schema_v1.sql -docs/database/SCHEMA_AUDIT_V1.md -docs/CONVENTIONS.md -``` - -En cas de contradiction, le schéma SQL exécuté fait foi jusqu'à correction de -la documentation. - ---- - -## Contenu attendu - -### 1. Vue d'ensemble - -Présenter le rôle de la base SQLite dans une enquête. - -Chaque enquête possède sa propre base : - -```text -00_BaseDeDonnees/Enquete.sqlite -``` - -La base est autonome et liée au dossier d'enquête. - ---- - -### 2. Principes généraux - -Documenter les choix suivants : - -- une base par enquête ; -- aucun chemin absolu dans les objets métier ; -- UUID pour les objets métier ; -- identifiants entiers pour les tables de référence ; -- dates UTC au format ISO 8601 ; -- clés étrangères activées ; -- suppression logique ; -- requêtes préparées obligatoires dans le code C ; -- aucune requête SQL métier hors du module Database. - ---- - -### 3. Domaines du modèle - -Présenter les grands ensembles : - -```text -Métadonnées -Référentiels -Collecte -Connaissance -Raisonnement -Traçabilité -Classification -``` - -Exemple de classement : - -```text -Métadonnées -├── metadata -└── investigation - -Référentiels -├── types_preuve -├── types_entite -├── types_source -└── types_outil - -Collecte -├── sources -├── recherches -└── preuves - -Connaissance -├── entites -└── relations - -Raisonnement -└── hypotheses - -Traçabilité -├── chronologie -└── journal - -Classification -├── categories -└── tags -``` - ---- - -### 4. Chaîne d'investigation - -Décrire le flux métier principal : - -```text -Source - ↓ -Recherche - ↓ -Preuve - ↓ -Entité - ↓ -Relation - ↓ -Hypothèse -``` - -Préciser que ce flux n'est pas strictement linéaire. - -Une recherche peut : - -- utiliser une preuve existante ; -- produire plusieurs preuves ; -- découvrir plusieurs entités ; -- confirmer ou contredire une relation ; -- enrichir une hypothèse. - ---- - -### 5. Description des tables métier - -Pour chaque table importante, documenter : - -- responsabilité ; -- identifiant ; -- colonnes principales ; -- relations ; -- suppression ; -- points d'attention. - -Tables concernées : - -```text -investigation -sources -recherches -preuves -entites -relations -chronologie -journal -hypotheses -categories -tags -``` - ---- - -### 6. Tables de liaison - -Documenter le rôle des tables de liaison : - -```text -recherche_preuves -recherche_entites -recherche_relations -recherche_hypotheses - -preuve_entites -relation_preuves - -recherche_chronologie -preuve_chronologie -entite_chronologie -relation_chronologie - -hypothese_preuves -hypothese_entites -hypothese_relations - -tag_preuves -tag_recherches -tag_entites -tag_relations -tag_hypotheses -tag_chronologie -``` - -Expliquer : - -- les clés primaires composites ; -- l'interdiction des doublons ; -- les colonnes `role` lorsqu'elles existent ; -- le comportement `ON DELETE`. - ---- - -### 7. Relations principales - -Inclure un diagramme textuel ou Mermaid. - -Exemple : - -```mermaid -erDiagram - SOURCES ||--o{ RECHERCHES : "interrogee par" - RECHERCHES ||--o{ RECHERCHE_PREUVES : produit - PREUVES ||--o{ RECHERCHE_PREUVES : participe - PREUVES ||--o{ PREUVE_ENTITES : contient - ENTITES ||--o{ PREUVE_ENTITES : est extraite - ENTITES ||--o{ RELATIONS : source - ENTITES ||--o{ RELATIONS : cible - HYPOTHESES ||--o{ HYPOTHESE_PREUVES : s_appuie_sur -``` - -Le diagramme peut être simplifié afin de rester lisible. - ---- - -### 8. Identifiants - -Expliquer : - -```sql -id TEXT PRIMARY KEY -``` - -pour les objets métier. - -Préciser : - -- UUID généré dans l'application ; -- pas de colonne `uuid` supplémentaire ; -- aucune dépendance aux numéros de ligne SQLite ; -- meilleure portabilité pour l'import, l'export et la fusion. - ---- - -### 9. Dates - -Expliquer la différence entre : - -```text -created_at -updated_at -imported_at -file_created_at -started_at -completed_at -event_time -``` - -Toutes les dates techniques sont enregistrées en UTC. - ---- - -### 10. Suppression logique - -Documenter les statuts comme : - -```text -active -archived -deleted -``` - -Préciser que : - -- les preuves originales ne sont pas modifiées ; -- les objets supprimés logiquement restent référencés ; -- les purges physiques sont hors des opérations ordinaires ; -- le journal est append-only dans le fonctionnement normal. - ---- - -### 11. Intégrité - -Documenter : - -- `PRAGMA foreign_keys = ON` ; -- contraintes `NOT NULL` ; -- contraintes `CHECK` ; -- contraintes `UNIQUE` ; -- clés primaires composites ; -- validation applicative complémentaire. - -Préciser que SQLite ne suffit pas à valider : - -- la syntaxe réelle d'un UUID ; -- la validité complète d'une couleur ; -- la normalisation d'une adresse email ; -- la validité d'un IBAN ; -- l'existence d'une référence polymorphe du journal. - ---- - -### 12. Index - -Expliquer que les index couvrent principalement : - -- les clés étrangères ; -- les statuts ; -- les dates ; -- les hashes ; -- les valeurs recherchées ; -- les catégories ; -- les relations orientées. - -Le document ne doit pas recopier chaque index sans explication. - ---- - -### 13. Versionnement - -Documenter : - -```text -schema_version = 1 -``` - -Préciser : - -- aucune modification destructive d'une V1 publiée ; -- toute évolution incompatible nécessite une migration ; -- les migrations devront être transactionnelles ; -- une sauvegarde devra précéder toute migration ; -- le schéma V1 reste la référence jusqu'à publication d'une V2. - ---- - -### 14. Couche C - -Documenter l'organisation prévue : - -```text -include/database/ -src/database/ -``` - -Avec un module par objet métier : - -```text -preuve.c -entite.c -relation.c -source.c -recherche.c -chronologie.c -journal.c -hypothese.c -categorie.c -tag.c -``` - -Le document doit préciser que cette organisation représente la cible -d'architecture, même si tous les modules ne sont pas encore implémentés. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- modifier le schéma SQL ; -- ajouter de table ; -- écrire un CRUD ; -- ajouter une migration ; -- modifier GTK ; -- intégrer GResource ; -- modifier le packaging. - -Toute incohérence réellement détectée doit être documentée avant de faire -l'objet d'un ticket de correction séparé. - ---- - -## Critères d'acceptation - -- [ ] `DATABASE_ARCHITECTURE.md` existe. -- [ ] Le rôle de chaque table métier est expliqué. -- [ ] Les tables de liaison sont documentées. -- [ ] Les UUID sont expliqués. -- [ ] Les dates sont expliquées. -- [ ] La suppression logique est expliquée. -- [ ] Les contraintes d'intégrité sont expliquées. -- [ ] La politique de migrations est définie. -- [ ] Un diagramme global est présent. -- [ ] Le document est cohérent avec `schema_v1.sql`. -- [ ] Aucun changement fonctionnel n'est introduit. -- [ ] `make test` reste entièrement valide. - ---- - -## Commit attendu - -```text -docs(database): document v1 database architecture -``` diff --git a/docs/tickets/closed/TICKET-025.md b/docs/tickets/closed/TICKET-025.md deleted file mode 100644 index e4594b0..0000000 --- a/docs/tickets/closed/TICKET-025.md +++ /dev/null @@ -1,215 +0,0 @@ -# Ticket #025 - -## Titre - -Refactoriser la couche Database et établir l'infrastructure d'accès aux données. - ---- - -## Objectif - -Mettre en place l'architecture définitive de la couche Database afin de fournir -une API interne homogène pour tous les futurs modules métier. - -Ce ticket ne comprend **aucun CRUD métier**. - -Son objectif est uniquement de construire les fondations techniques qui seront -réutilisées par l'ensemble de l'application. - ---- - -## Motivations - -À terme, Labfy Investigation manipulera de nombreux objets métier : - -- investigations ; -- sources ; -- recherches ; -- preuves ; -- entités ; -- relations ; -- chronologie ; -- journal ; -- hypothèses ; -- catégories ; -- tags. - -Sans une couche d'abstraction, chaque module devrait manipuler directement -SQLite, ce qui entraînerait : - -- une forte duplication de code ; -- une gestion incohérente des erreurs ; -- des transactions difficiles à maintenir ; -- une architecture difficile à faire évoluer. - -L'objectif de ce ticket est d'éviter cette dette technique. - ---- - -## Architecture cible - -La couche Database devra évoluer vers l'organisation suivante : - -```text -include/database/ -├── database.h -├── connection.h -├── transaction.h -├── statement.h -├── error.h -├── schema.h -``` - -```text -src/database/ -├── database.c -├── connection.c -├── transaction.c -├── statement.c -├── error.c -├── schema.c -``` - -Les futurs modules métier seront ajoutés ultérieurement. - ---- - -## Structure Database - -Créer un type opaque : - -```c -typedef struct Database Database; -``` - -L'implémentation reste privée. - -La structure interne contiendra au minimum : - -- le pointeur `sqlite3 *`; -- le chemin de la base ; -- l'état de la transaction ; -- la version du schéma. - -Cette abstraction permettra de faire évoluer facilement l'implémentation sans -modifier l'API publique. - ---- - -## Connexion - -Créer les fonctions : - -```c -Database *database_open( - const char *database_path -); - -void database_close( - Database *database -); -``` - -Ces fonctions sont responsables de : - -- l'ouverture de SQLite ; -- l'activation des PRAGMA nécessaires ; -- la fermeture propre de la base. - ---- - -## Transactions - -Créer les fonctions : - -```c -bool database_begin( - Database *database -); - -bool database_commit( - Database *database -); - -bool database_rollback( - Database *database -); -``` - -Toute gestion des transactions devra passer exclusivement par ces fonctions. - ---- - -## Gestion des requêtes préparées - -Créer une couche d'abstraction pour les instructions préparées. - -L'objectif est de centraliser : - -- `sqlite3_prepare_v2()` -- `sqlite3_bind_*()` -- `sqlite3_step()` -- `sqlite3_reset()` -- `sqlite3_finalize()` - -Aucun futur module métier ne devra appeler directement ces fonctions SQLite. - ---- - -## Gestion des erreurs - -Créer un point d'entrée unique pour les erreurs SQLite. - -Toutes les erreurs devront passer par une fonction dédiée. - -Cette centralisation facilitera : - -- le débogage ; -- la journalisation ; -- l'intégration future avec le journal d'audit. - ---- - -## Responsabilités - -À la fin du ticket : - -- la couche Database est la seule autorisée à manipuler SQLite ; -- les autres modules ne connaissent pas `sqlite3`; -- les transactions sont centralisées ; -- les erreurs sont uniformisées ; -- les requêtes préparées sont encapsulées. - ---- - -## Hors périmètre - -Ce ticket ne doit pas : - -- ajouter de nouvelles tables ; -- modifier le schéma SQL ; -- créer un CRUD métier ; -- modifier GTK ; -- implémenter des migrations ; -- ajouter des fonctionnalités d'investigation. - ---- - -## Critères d'acceptation - -- [ ] Création du type opaque `Database`. -- [ ] API publique de connexion disponible. -- [ ] API publique des transactions disponible. -- [ ] Encapsulation des requêtes préparées. -- [ ] Gestion centralisée des erreurs. -- [ ] Aucune utilisation directe de `sqlite3` en dehors du dossier `database`. -- [ ] Documentation des nouvelles API. -- [ ] Tous les tests existants restent valides. - ---- - -## Commit attendu - -```text -refactor(database): introduce database infrastructure layer -``` diff --git a/docs/tickets/closed/TICKET-026.md b/docs/tickets/closed/TICKET-026.md deleted file mode 100644 index 4d56a63..0000000 --- a/docs/tickets/closed/TICKET-026.md +++ /dev/null @@ -1,366 +0,0 @@ -# Ticket #026 — Migrer l’initialisation vers la couche Database - -## Contexte - -Le ticket #025 a introduit l’infrastructure principale de la couche Database : - -- contexte opaque `Database` ; -- ouverture et fermeture des connexions ; -- requêtes préparées avec `DatabaseStatement` ; -- bindings et lecture typée ; -- gestion des transactions ; -- infrastructure d’erreurs. - -Cependant, `database_initialize()` utilise encore directement plusieurs fonctions de l’API SQLite : - -```c -sqlite3_open_v2() -sqlite3_prepare_v2() -sqlite3_bind_text() -sqlite3_step() -sqlite3_reset() -sqlite3_clear_bindings() -sqlite3_finalize() -sqlite3_close() - -La fonction exécute également directement les commandes SQL suivantes : - -```sql - -BEGIN IMMEDIATE; -COMMIT; -ROLLBACK; -``` - -De son côté, `schema_install_v1()` reçoit toujours directement un `sqlite3 *`, ce qui contourne l’abstraction `Database`. - -## Objectif - -Réécrire l’initialisation d’une nouvelle enquête afin qu’elle utilise l’infrastructure créée au ticket #025. - -L’initialisation doit rester atomique : - -- soit la base est entièrement initialisée ; -- soit aucune donnée partielle n’est conservée. - -## Travail à réaliser - -### Adapter l’installation du schéma - -Modifier la signature actuelle : - -```C -bool schema_install_v1( - sqlite3 *database -); -``` - -afin qu’elle reçoive un contexte Database : - -```C -bool schema_install_v1( - Database *database -); -``` - -L’installation du fichier SQL complet pourra continuer à utiliser `sqlite3_exec()` en interne, car le schéma contient plusieurs instructions SQL. - -L’accès au handle SQLite devra passer par l’API interne : - -```C -database_get_handle() -``` - -La fonction ne devra réaliser ni `COMMIT` ni `ROLLBACK`. - -### Migrer l’insertion des métadonnées - -Réécrire les fonctions responsables de l’insertion dans la table `metadata` avec `DatabaseStatement`. - -Les opérations devront utiliser l’API suivante : - -```C -database_statement_prepare() -database_statement_bind_text() -database_statement_step() -database_statement_reset() -database_statement_clear_bindings() -database_statement_finalize() -``` - -Les métadonnées obligatoires restent : - -``` -schema_version -application -created_at -investigation_uuid -``` - -Une seule requête préparée devra pouvoir être réutilisée pour insérer les quatre métadonnées. - -### Migrer l’insertion de l’enquête - -Réécrire l’insertion dans la table `investigation` avec `DatabaseStatement`. - -Les champs insérés restent : - -```C -database_open() -database_transaction_begin() -schema_install_v1() -database_transaction_commit() -database_transaction_rollback() -database_close() -``` - -Le déroulement attendu est : - -``` -validation des paramètres - ↓ -création du timestamp UTC - ↓ -création de l’UUID - ↓ -ouverture de Database - ↓ -début de transaction - ↓ -installation du schéma V1 - ↓ -insertion des métadonnées - ↓ -insertion de l’enquête - ↓ -commit - ↓ -fermeture de Database -``` - -Tout échec après le début de la transaction doit provoquer un rollback. - -### Utiliser l’infrastructure d’erreurs - -Les erreurs rencontrées pendant : - -- l’installation du schéma ; -- la préparation d’une requête ; -- le binding d’un paramètre ; -- l’exécution d’une requête ; -- le début d’une transaction ; -- le commit ; -- le rollback ; - -doivent être enregistrées dans le contexte Database lorsque celui-ci est disponible. - -L’infrastructure interne existante pourra être utilisée : - -```C -database_set_error() -database_clear_error_internal() -``` - -```C -DATABASE_ERROR_SQLITE -``` - -```C -DATABASE_ERROR_INVALID_ARGUMENT -``` - -```C -DATABASE_ERROR_INVALID_STATE -``` - -### Nettoyer l’ancien code SQLite - -Supprimer de la logique d’initialisation les appels directs à : - -```C -sqlite3_open_v2() -sqlite3_prepare_v2() -sqlite3_bind_text() -sqlite3_step() -sqlite3_reset() -sqlite3_clear_bindings() -sqlite3_finalize() -sqlite3_close() -``` - -Supprimer également les commandes manuelles : - -```SQL -BEGIN IMMEDIATE; -COMMIT; -ROLLBACK; -``` - -La fonction utilitaire `database_execute_sql()` pourra être conservée uniquement si elle reste nécessaire à `database_open()` pour l’activation des clés étrangères. - -### Mettre à jour la documentation publique - -Dans `include/database/database.h`, supprimer la mention temporaire : - -``` -Cette fonction conserve temporairement son rôle actuel pendant le -refactoring du ticket #025. -``` - -La documentation de `database_initialize()` devra préciser que : - -- l’initialisation est transactionnelle ; -- un échec provoque un rollback ; -- la base est fermée avant le retour de la fonction. - -## Tests à ajouter ou adapter - -### Initialisation réussie - -Vérifier qu’une initialisation valide crée : - -- le schéma V1 ; -- les tables attendues ; -- les métadonnées obligatoires ; -- une seule ligne dans investigation ; -- le bon nom d’enquête ; -- le bon chemin racine ; -- un UUID non vide ; -- une date de création non vide ; -- une date de modification non vide. - -### Paramètres invalides - -Vérifier le refus des cas suivants : - -``` -database_path == NULL -database_path vide -investigation_name == NULL -investigation_name vide -investigation_root_path == NULL -investigation_root_path vide -``` - -### Rollback - -Provoquer un échec après le démarrage de la transaction. - -Une seconde tentative d’initialisation sur une base déjà initialisée pourra être utilisée pour provoquer une erreur de contrainte ou de création de schéma. - -Après l’échec, vérifier que : - -- aucune donnée partielle supplémentaire n’est conservée ; -- aucune seconde enquête n’est ajoutée ; -- les métadonnées existantes ne sont pas dupliquées ; -- la transaction est annulée ; -- la base reste lisible ; -- la connexion peut être fermée proprement. - -### Régression - -Tous les tests existants doivent rester valides : - -``` -InvestigationNode -InvestigationTreeModel -InvestigationTreeBuilder -InvestigationProject -Database -DatabaseStatement -DatabaseTransaction -DatabaseError -``` - -## Critères d’acceptation - -- [ ] `database_initialize()` n’appelle plus directement `sqlite3_open_v2()`. -- [ ] `database_initialize()` utilise `database_open()`. -- [ ] `database_initialize()` utilise `database_close()`. -- [ ] Les transactions utilisent le module `transaction`. -- [ ] Les insertions utilisent `DatabaseStatement`. -- [ ] `InvestigationNode` Investigation `schema_install_v1()` reçoit un `Database *`. -InvestigationNode -Investigation `schema_install_v1()` reçoit un `Database *`. -- [ ] `schema_install_v1()` récupère le handle avec l’API interne. -- [ ] Aucun `sqlite3_stmt *` n’est manipulé dans le code d’initialisation. -- [ ] Aucun `BEGIN`, `COMMIT` ou `ROLLBACK` manuel ne reste dans `database.c`. -- [ ] Tout échec après le début de la transaction provoque un rollback. -- [ ] Les erreurs sont enregistrées dans la couche Database. -- [ ] Les tests de réussite sont valides. -- [ ] Les tests de paramètres invalides sont valides. -- [ ] Les tests de rollback sont valides. -- [ ] Les tests de régression sont valides. -- [ ] `make` réussit sans erreur. -- [ ] `make test` réussit. -- [ ] `git diff --check` ne retourne aucune erreur. - -## Hors périmètre - -Ce ticket ne doit pas ajouter : - -- de CRUD métier ; -- de dépôt ou repository métier ; -- de migration entre plusieurs versions de schéma ; -- de système GResource pour embarquer `schema_v1.sql` ; -- de création automatique des dossiers parents ; -- de modification du schéma SQL V1 ; -- de nouvelles tables ; -- de logique d’interface graphique ; -- de nouvelles fonctionnalités utilisateur. - -## Fichiers principalement concernés - -```text -include/database/database.h -include/database/schema.h - -src/database/database.c -src/database/database_internal.h -src/database/schema.c - -tests/test_database.c - -Makefile -``` - -## Résultat attendu - -À la fin du ticket, `database_initialize()` doit être un utilisateur normal de la couche Database. - -La fonction ne doit plus contourner cette couche avec des appels SQLite directs. - -L’initialisation d’une enquête doit être entièrement transactionnelle, testée et cohérente avec l’architecture mise en place au ticket #025. - -## Commit attendu - -Une fois tous les critères d’acceptation validés, le ticket pourra être enregistré avec le commit suivant : - -```text -refactor(database): migrate initialization to database layer -``` - -Le commit doit principalement contenir : - -``` -include/database/database.h -include/database/schema.h - -src/database/database.c -src/database/database_internal.h -src/database/schema.c - -tests/test_database.c - -Makefile -``` -Avant le commit, exécuter : - -```bash -make clean -make -make test -git diff --check -git status --short -``` - diff --git a/docs/tickets/closed/TICKET-027.md b/docs/tickets/closed/TICKET-027.md deleted file mode 100644 index 9b22d28..0000000 --- a/docs/tickets/closed/TICKET-027.md +++ /dev/null @@ -1,535 +0,0 @@ -# Ticket #027 — Ajouter le modèle de lecture et le DAO de l’enquête - -## Contexte - -Les tickets précédents ont permis de mettre en place : - -- le schéma SQLite V1 ; -- l’infrastructure `Database` ; -- les requêtes préparées `DatabaseStatement` ; -- les transactions ; -- la gestion centralisée des erreurs ; -- l’initialisation transactionnelle d’une nouvelle enquête. - -La table SQLite : - -```text -investigation -``` -contient les informations principales de l’enquête courante : - -```text -id -name -root_path -created_at -updated_at -``` - -Le projet possède déjà un type : - -```C -Investigation -``` - -dans le module `core`. - -Cet objet représente actuellement le contexte de travail sur le système de -fichiers : - -- chemin racine de l’enquête ; -- chemin du fichier SQLite. - -Il ne doit pas être transformé directement en représentation d’une ligne SQL. - -L’architecture du projet prévoit une séparation entre : - -```text -Core -Models -DAO -Database -SQLite -``` - -Le DAO doit être responsable des requêtes SQL métier. - -## Objectif - -Créer un modèle de données en lecture seule représentant la ligne de la table -investigation, ainsi qu’un DAO permettant de charger cette ligne depuis une -connexion Database. - -Le ticket doit permettre de lire les informations persistées d’une enquête -sans utiliser directement l’API SQLite hors de la couche Database. - -## Architecture attendue - -``` -InvestigationRecord - ↑ - │ construit par - │ -InvestigationDao - │ - ▼ -DatabaseStatement - │ - ▼ -Database - │ - ▼ -SQLite -``` - -## Travail à réaliser - -### Créer le modèle InvestigationRecord - -Créer les fichiers : -```text -include/models/investigation_record.h -src/models/investigation_record.c -``` - -Le modèle doit être opaque : - -```C -typedef struct InvestigationRecord InvestigationRecord; -``` - -Sa représentation privée doit contenir : - -```C -struct InvestigationRecord -{ - char *id; - char *name; - char *root_path; - char *created_at; - char *updated_at; -}; -``` - -Le modèle ne doit dépendre ni de SQLite, ni de GTK. - -### Ajouter le constructeur - -Créer une fonction : - -```C -InvestigationRecord *investigation_record_new( - const char *id, - const char *name, - const char *root_path, - const char *created_at, - const char *updated_at -); -``` - -Le constructeur doit : - -- refuser les pointeurs `NULL` ; -- refuser les chaînes vides ; -- allouer une copie de chaque chaîne ; -- nettoyer correctement toutes les allocations en cas d’échec ; -- retourner `NULL` si les données sont invalides. - -### Ajouter la fonction de libération - -Créer : - -```C -void investigation_record_free( - InvestigationRecord *record -); -``` - -Cette fonction doit : - -- accepter `NULL` ; -- libérer toutes les chaînes ; -- libérer la structure. - -### Ajouter les accesseurs - -Créer les accesseurs en lecture seule : - -```C -const char *investigation_record_get_id( - const InvestigationRecord *record -); - -const char *investigation_record_get_name( - const InvestigationRecord *record -); - -const char *investigation_record_get_root_path( - const InvestigationRecord *record -); - -const char *investigation_record_get_created_at( - const InvestigationRecord *record -); - -const char *investigation_record_get_updated_at( - const InvestigationRecord *record -); -``` - -Les pointeurs retournés appartiennent au modèle et ne doivent pas être libérés. - -Les accesseurs doivent retourner `NULL` si le modèle reçu est `NULL`. - -### Créer le DAO de l’enquête - -Créer les fichiers : - -```text -include/dao/investigation_dao.h -src/dao/investigation_dao.c -``` - -Déclarer la fonction : - -```C -InvestigationRecord *investigation_dao_load( - Database *database -); -``` - -Cette fonction doit charger l’unique ligne de la table : - -```text -investigation -``` - -La requête doit lire : - -```SQL -SELECT - id, - name, - root_path, - created_at, - updated_at -FROM investigation; -``` - -### Utiliser exclusivement DatabaseStatement - -Le DAO doit utiliser : - -```C -database_statement_prepare() -database_statement_step() -database_statement_column_text() -database_statement_finalize() -``` - -Le DAO ne doit pas utiliser directement : - -```C -sqlite3_prepare_v2() -sqlite3_step() -sqlite3_column_text() -sqlite3_finalize() -``` - -Aucun type SQLite ne doit apparaître dans l’interface publique du DAO. - -### Vérifier le nombre de lignes - -La base d’une enquête doit contenir exactement une ligne dans la table -`investigation`. - -Le DAO doit gérer les cas suivants : - -Une ligne -``` -ROW -DONE -``` -Résultat : - -``` -succès -``` - -Le DAO construit et retourne un `InvestigationRecord`. - -#### Aucune ligne - -`DONE` dès le premier step - -Résultat : - -``` -échec -``` - -Le DAO retourne `NULL` et enregistre : - -``` -DATABASE_ERROR_INVALID_STATE -``` - -#### Plusieurs lignes - -``` -ROW -ROW -``` - -Résultat : - -`échec` - -Le DAO libère le modèle temporaire, retourne `NULL` et enregistre : -```C -DATABASE_ERROR_INVALID_STATE -``` - -### Propager les erreurs - -Les erreurs de préparation ou d’exécution provenant de `DatabaseStatement` -doivent rester disponibles dans le contexte `Database`. - -Le DAO doit enregistrer une erreur explicite pour : - -- une table vide ; -- plusieurs lignes dans investigation ; -- une colonne obligatoire invalide ; -- une allocation impossible ; -- un état incohérent. - -Les codes prévus sont : - -```C -DATABASE_ERROR_INVALID_ARGUMENT -DATABASE_ERROR_INVALID_STATE -DATABASE_ERROR_MEMORY -DATABASE_ERROR_SQLITE -``` - -Une lecture réussie doit laisser : - -```C -DATABASE_ERROR_NONE -``` - -### Gérer proprement la mémoire - -Le DAO doit libérer toutes les chaînes temporaires retournées par : - -```C -database_statement_column_text() -``` - -après la construction du modèle. - -Toutes les sorties d’échec doivent : - -- finaliser la requête préparée ; -- libérer les chaînes déjà lues ; -- libérer le modèle partiellement construit ; -- ne provoquer aucune fuite mémoire. -- Tests à ajouter - -#### Test du modèle - -Créer : - -``` -tests/test_investigation_record.c -``` - -Vérifier : - -- la création avec des données valides ; -- la copie des chaînes ; -- les cinq accesseurs ; -- le refus des paramètres `NULL` ; -- le refus des chaînes vides ; -- `investigation_record_free(NULL)`. - -#### Test du DAO - -Créer : - -``` -tests/test_investigation_dao.c -Chargement valide -``` - -Créer une base temporaire avec : - -```C -database_initialize() -``` - -Puis : - -- ouvrir la base avec `database_open()` ; -- charger l’enquête avec `investigation_dao_load()` ; -- vérifier que le modèle n’est pas `NULL` ; -- vérifier l’UUID ; -- vérifier le nom ; -- vérifier le chemin racine ; -- vérifier `created_at` ; -- vérifier `updated_at` ; -- vérifier que l’erreur Database vaut `DATABASE_ERROR_NONE`. - -#### Paramètre invalide - -Vérifier : - -```C -investigation_dao_load(NULL) == NULL -``` - -#### Table vide - -Créer une base contenant la table investigation sans ligne. - -Vérifier : - -``` -résultat == NULL -DATABASE_ERROR_INVALID_STATE -message non vide -``` - -#### Plusieurs lignes - -Créer une base contenant deux lignes dans la table investigation. - -Vérifier : - -``` -résultat == NULL -DATABASE_ERROR_INVALID_STATE -message non vide -``` - -#### Données invalides - -Créer une situation dans laquelle une colonne obligatoire ne peut pas être -correctement lue. - -Vérifier : - -``` -résultat == NULL -erreur enregistrée -aucune fuite de mémoire -``` - -## Makefile - -Ajouter les exécutables : - -``` -tests/test_investigation_record -tests/test_investigation_dao -``` - -Ajouter leurs règles de compilation. - -Les tests du DAO devront notamment compiler avec : - -``` -src/models/investigation_record.c -src/dao/investigation_dao.c -src/database/database.c -src/database/schema.c -src/database/statement.c -src/database/transaction.c -src/database/error.c -``` - -Ajouter les nouveaux tests aux cibles : - -``` -test -clean -``` -### Critères d’acceptation - -- [ ] Le type `InvestigationRecord` est opaque. -- [ ] Le modèle ne dépend ni de SQLite ni de GTK. -- [ ] Le constructeur valide tous les champs obligatoires. -- [ ] Toutes les chaînes sont copiées. -- [ ] Une fonction de libération complète est disponible. -- [ ] Les cinq accesseurs en lecture seule sont disponibles. -- [ ] `investigation_dao_load()` charge l’enquête courante. -- [ ] Le DAO utilise uniquement l’API `DatabaseStatement`. -- [ ] Aucun appel direct à SQLite n’apparaît dans le DAO. -- [ ] Une base contenant exactement une enquête est acceptée. -- [ ] Une table vide est refusée. -- [ ] Plusieurs lignes sont refusées. -- [ ] Les erreurs sont enregistrées dans `Database`. -- [ ] Toutes les ressources temporaires sont libérées. -- [ ] Les tests du modèle sont valides. -- [ ] Les tests du DAO sont valides. -- [ ] Tous les anciens tests restent valides. -- [ ] `make` réussit sans erreur. -- [ ] `make test` réussit. -- [ ] `git diff --check` ne retourne aucune erreur. - -### Hors périmètre - -Ce ticket ne doit pas ajouter : - -- la création d’une enquête par le DAO ; -- la modification du nom de l’enquête ; -- la modification du chemin racine ; -- la suppression d’une enquête ; -- un CRUD complet ; -- l’ouverture automatique dans l’interface GTK ; -- l’affichage des informations dans la fenêtre ; -- les DAO des preuves, sources ou entités ; -- les migrations de schéma ; -- une nouvelle version du schéma SQLite. - -### Fichiers principalement concernés - -``` -include/models/investigation_record.h -include/dao/investigation_dao.h - -src/models/investigation_record.c -src/dao/investigation_dao.c - -tests/test_investigation_record.c -tests/test_investigation_dao.c - -Makefile -``` -## Résultat attendu - -À la fin du ticket, le projet doit être capable de charger les informations -persistées de l’enquête courante dans un modèle C indépendant de SQLite. - -Le DAO devient le premier point d’accès métier structuré à la base de données. - -### Commit attendu - -Une fois tous les critères validés : - -`feat(dao): add investigation record loader` - -Avant le commit : - -```bash -make clean -make -make test -git diff --check -git status --short -git add . -git diff --cached --stat -git diff --cached -git commit -m "feat(dao): add investigation record loader" -git push -``` diff --git a/docs/tickets/closed/TICKET-028.md b/docs/tickets/closed/TICKET-028.md deleted file mode 100644 index c314102..0000000 --- a/docs/tickets/closed/TICKET-028.md +++ /dev/null @@ -1,776 +0,0 @@ -# Ticket #028 — Ajouter l’ouverture d’une enquête existante - -## Contexte - -Les tickets précédents ont permis de mettre en place : - -- la création transactionnelle d’une base d’enquête ; -- la couche `Database` ; -- les requêtes préparées `DatabaseStatement` ; -- la gestion des transactions et des erreurs ; -- le modèle `InvestigationRecord` ; -- le DAO `InvestigationDao` permettant de charger l’unique ligne de la table `investigation`. - -Le projet possède également un type `InvestigationProject` chargé de représenter les chemins du projet sur le système de fichiers, notamment : - -- le dossier racine de l’enquête ; -- le chemin du fichier `Enquete.sqlite`. - -Cependant, l’application ne possède pas encore d’objet représentant une enquête réellement ouverte pendant son exécution. - -Les différentes ressources sont encore séparées : - -```text -InvestigationProject -Database -InvestigationRecord -``` - -Il faut désormais les regrouper dans un contexte cohérent dont la durée de vie correspond à celle d’une enquête ouverte. - -## Objectif - -Créer un type opaque `InvestigationSession` chargé d’ouvrir une enquête existante et de conserver : - -- son contexte de fichiers `InvestigationProject` ; -- sa connexion `Database` ; -- ses informations persistées `InvestigationRecord`. - -L’ouverture doit vérifier que le dossier sélectionné correspond bien aux informations enregistrées dans la base SQLite. - -La connexion SQLite doit rester ouverte pendant toute la durée de vie de la session afin de permettre les futurs appels aux DAO. - -## Architecture attendue - -```text -Application - │ - ▼ -InvestigationSession - ├── InvestigationProject - ├── Database - └── InvestigationRecord - ▲ - │ - InvestigationDao - │ - ▼ - DatabaseStatement - │ - ▼ - SQLite -``` - -## Travail à réaliser - -### 1. Créer le type `InvestigationSession` - -Créer les fichiers : - -```text -include/core/investigation_session.h -src/core/investigation_session.c -``` - -Le type doit être opaque : - -```c -typedef struct InvestigationSession InvestigationSession; -``` - -Sa représentation privée doit contenir au minimum : - -```c -struct InvestigationSession -{ - InvestigationProject *project; - Database *database; - InvestigationRecord *record; -}; -``` - -Le header public ne doit pas exposer cette structure. - -### 2. Définir les erreurs d’ouverture - -Créer une énumération dédiée : - -```c -typedef enum -{ - INVESTIGATION_SESSION_ERROR_INVALID_ARGUMENT, - INVESTIGATION_SESSION_ERROR_ROOT_NOT_FOUND, - INVESTIGATION_SESSION_ERROR_DATABASE_NOT_FOUND, - INVESTIGATION_SESSION_ERROR_PROJECT, - INVESTIGATION_SESSION_ERROR_DATABASE, - INVESTIGATION_SESSION_ERROR_RECORD, - INVESTIGATION_SESSION_ERROR_ROOT_MISMATCH, - INVESTIGATION_SESSION_ERROR_MEMORY -} InvestigationSessionError; -``` - -Définir un domaine d’erreur GLib : - -```c -#define INVESTIGATION_SESSION_ERROR \ - investigation_session_error_quark() - -GQuark investigation_session_error_quark(void); -``` - -Les erreurs doivent être transmises avec un paramètre : - -```c -GError **error -``` - -Lorsqu’une erreur provenant de `Database` doit être propagée, son message doit être copié dans le `GError` avant la fermeture de la connexion. - -### 3. Ajouter la fonction d’ouverture - -Déclarer : - -```c -InvestigationSession *investigation_session_open( - const char *investigation_root_path, - GError **error -); -``` - -La fonction doit ouvrir une enquête déjà existante à partir de son dossier racine. - -Elle ne doit pas créer une nouvelle enquête. - -### 4. Valider les paramètres - -La fonction doit refuser : - -```text -investigation_root_path == NULL -investigation_root_path vide -``` - -Le code d’erreur attendu est : - -```c -INVESTIGATION_SESSION_ERROR_INVALID_ARGUMENT -``` - -Le paramètre `error` peut être `NULL`. - -Si `error` n’est pas `NULL`, il doit respecter les conventions GLib : - -```c -*error == NULL -``` - -au moment de l’appel. - -### 5. Vérifier le dossier racine - -Le chemin fourni doit correspondre à un dossier existant. - -La fonction doit vérifier : - -```c -G_FILE_TEST_IS_DIR -``` - -Un chemin inexistant ou qui ne représente pas un dossier doit produire : - -```c -INVESTIGATION_SESSION_ERROR_ROOT_NOT_FOUND -``` - -Le chemin doit être normalisé avec : - -```c -g_canonicalize_filename() -``` - -La session doit travailler à partir de ce chemin canonique. - -### 6. Construire `InvestigationProject` - -Réutiliser l’API existante de `InvestigationProject`. - -La logique de construction du chemin de la base ne doit pas être dupliquée dans `InvestigationSession`. - -Le chemin attendu reste géré par `InvestigationProject` : - -```text -/00_BaseDeDonnees/Enquete.sqlite -``` - -Si l’API actuelle de `InvestigationProject` ne permet pas de représenter un projet existant, elle peut être étendue de manière minimale. - -Aucune logique SQLite ne doit être ajoutée dans `InvestigationProject`. - -### 7. Vérifier le fichier SQLite - -Avant l’ouverture de la connexion, vérifier que le chemin retourné par `InvestigationProject` correspond à un fichier régulier : - -```c -G_FILE_TEST_IS_REGULAR -``` - -Si le fichier n’existe pas, retourner : - -```c -INVESTIGATION_SESSION_ERROR_DATABASE_NOT_FOUND -``` - -L’ouverture d’une enquête existante ne doit jamais créer silencieusement une nouvelle base vide. - -### 8. Ouvrir la connexion Database - -Utiliser : - -```c -database_open() -``` - -La fonction `investigation_session_open()` ne doit pas appeler directement : - -```c -sqlite3_open() -sqlite3_open_v2() -sqlite3_close() -``` - -Si `database_open()` échoue, retourner : - -```c -INVESTIGATION_SESSION_ERROR_DATABASE -``` - -La connexion doit rester ouverte si la session est créée avec succès. - -### 9. Charger l’enquête persistée - -Utiliser : - -```c -investigation_dao_load() -``` - -Le DAO doit retourner un `InvestigationRecord`. - -Si le chargement échoue : - -- récupérer le code et le message de la dernière erreur `Database` ; -- copier le message dans un `GError` ; -- retourner `NULL` ; -- fermer proprement la connexion ; -- libérer le projet ; -- ne laisser aucune ressource allouée. - -Le code d’erreur de session attendu est : - -```c -INVESTIGATION_SESSION_ERROR_RECORD -``` - -### 10. Vérifier la cohérence du chemin racine - -Le chemin sélectionné doit correspondre au champ persistant : - -```text -investigation.root_path -``` - -Comparer les versions canoniques de : - -```text -chemin racine sélectionné -chemin racine enregistré dans InvestigationRecord -``` - -La comparaison doit être faite après normalisation avec : - -```c -g_canonicalize_filename() -``` - -Si les chemins ne correspondent pas, l’ouverture doit échouer avec : - -```c -INVESTIGATION_SESSION_ERROR_ROOT_MISMATCH -``` - -Cette vérification évite d’ouvrir une base copiée ou déplacée sans détecter l’incohérence. - -Le déplacement volontaire d’une enquête sera traité dans un ticket distinct. - -### 11. Construire la session - -La session ne doit être créée qu’après validation complète : - -```text -dossier racine valide - ↓ -InvestigationProject valide - ↓ -fichier SQLite présent - ↓ -Database ouverte - ↓ -InvestigationRecord chargé - ↓ -chemin racine cohérent - ↓ -InvestigationSession créée -``` - -En cas d’échec d’allocation, retourner : - -```c -INVESTIGATION_SESSION_ERROR_MEMORY -``` - -### 12. Ajouter la fonction de fermeture - -Déclarer : - -```c -void investigation_session_close( - InvestigationSession *session -); -``` - -Cette fonction doit accepter `NULL`. - -Elle doit libérer toutes les ressources possédées par la session : - -```text -InvestigationRecord -Database -InvestigationProject -InvestigationSession -``` - -La session devient propriétaire de ces trois objets dès que son ouverture réussit. - -### 13. Ajouter les accesseurs - -Ajouter : - -```c -const InvestigationProject *investigation_session_get_project( - const InvestigationSession *session -); - -const InvestigationRecord *investigation_session_get_record( - const InvestigationSession *session -); - -Database *investigation_session_get_database( - InvestigationSession *session -); -``` - -Les pointeurs retournés appartiennent à la session et ne doivent pas être libérés par l’appelant. - -Les accesseurs doivent retourner `NULL` si la session reçue est `NULL`. - -`Database` reste non constante car les futurs DAO auront besoin d’une connexion modifiable. - -### 14. Interdire les dépendances SQLite et GTK - -Le module `InvestigationSession` ne doit pas inclure : - -```c -#include -#include -``` - -Il doit exclusivement utiliser les abstractions existantes : - -```text -InvestigationProject -Database -InvestigationDao -InvestigationRecord -GLib -``` - -## Tests à ajouter - -Créer : - -```text -tests/test_investigation_session.c -``` - -### Test d’ouverture valide - -Créer un dossier temporaire. - -Initialiser une base avec : - -```c -database_initialize() -``` - -Ouvrir ensuite l’enquête avec : - -```c -investigation_session_open() -``` - -Vérifier : - -- la session n’est pas `NULL` ; -- aucune erreur n’est produite ; -- le projet est disponible ; -- la connexion Database est disponible ; -- le record est disponible ; -- le nom de l’enquête est correct ; -- le chemin racine est correct ; -- l’UUID est valide ; -- `created_at` n’est pas vide ; -- `updated_at` n’est pas vide ; -- la connexion peut encore être utilisée par un DAO ; -- la fermeture libère correctement les ressources. - -### Test des paramètres invalides - -Vérifier : - -```c -investigation_session_open(NULL, &error) == NULL -investigation_session_open("", &error) == NULL -``` - -Le code attendu est : - -```c -INVESTIGATION_SESSION_ERROR_INVALID_ARGUMENT -``` - -Vérifier également le comportement avec : - -```c -error == NULL -``` - -### Test d’un dossier inexistant - -Utiliser un chemin inexistant. - -Vérifier : - -```text -résultat == NULL -erreur == INVESTIGATION_SESSION_ERROR_ROOT_NOT_FOUND -message non vide -``` - -### Test d’un chemin qui n’est pas un dossier - -Créer un fichier temporaire et utiliser son chemin comme racine. - -Vérifier : - -```text -résultat == NULL -erreur == INVESTIGATION_SESSION_ERROR_ROOT_NOT_FOUND -``` - -### Test d’une base absente - -Créer une structure de projet valide sans fichier : - -```text -00_BaseDeDonnees/Enquete.sqlite -``` - -Vérifier : - -```text -résultat == NULL -erreur == INVESTIGATION_SESSION_ERROR_DATABASE_NOT_FOUND -``` - -La fonction ne doit pas créer de nouveau fichier SQLite. - -### Test d’une base invalide - -Créer un fichier SQLite vide ou une base ne contenant pas la table : - -```text -investigation -``` - -Vérifier : - -```text -résultat == NULL -erreur == INVESTIGATION_SESSION_ERROR_RECORD -message non vide -``` - -### Test d’un chemin racine incohérent - -Créer une base avec un chemin racine enregistré différent du dossier utilisé pour l’ouverture. - -Vérifier : - -```text -résultat == NULL -erreur == INVESTIGATION_SESSION_ERROR_ROOT_MISMATCH -message non vide -``` - -### Test des accesseurs avec NULL - -Vérifier : - -```c -investigation_session_get_project(NULL) == NULL -investigation_session_get_record(NULL) == NULL -investigation_session_get_database(NULL) == NULL -``` - -Vérifier également : - -```c -investigation_session_close(NULL); -``` - -### Test de réutilisation du DAO - -Après l’ouverture valide d’une session, appeler de nouveau : - -```c -investigation_dao_load( - investigation_session_get_database(session) -); -``` - -Vérifier que la connexion reste fonctionnelle pendant toute la durée de vie de la session. - -## Gestion de la mémoire - -Toutes les sorties d’échec de `investigation_session_open()` doivent libérer les ressources déjà créées. - -Le nettoyage doit couvrir les cas suivants : - -```text -échec avant création du projet -échec après création du projet -échec après ouverture de Database -échec après chargement du record -échec lors de la comparaison des chemins -échec lors de l’allocation de la session -``` - -Aucun objet ne doit être libéré deux fois. - -Aucune ressource temporaire ne doit rester allouée : - -```text -chemins canoniques -messages copiés -GError temporaires -InvestigationProject -Database -InvestigationRecord -``` - -## Makefile - -Ajouter : - -```make -TEST_INVESTIGATION_SESSION := tests/test_investigation_session -``` - -Ajouter une règle compilant au minimum : - -```text -tests/test_investigation_session.c - -src/core/investigation_session.c -src/core/investigation_project.c - -src/dao/investigation_dao.c -src/models/investigation_record.c - -src/database/database.c -src/database/schema.c -src/database/statement.c -src/database/transaction.c -src/database/error.c -``` - -Lier avec : - -```text -GLib -SQLite -``` - -Ajouter le test aux cibles : - -```text -test -clean -``` - -La nouvelle sortie attendue est : - -```text -InvestigationSession : tous les tests sont valides. -``` - -## Critères d’acceptation - -- [ ] Le type `InvestigationSession` est opaque. -- [ ] Une session possède un `InvestigationProject`. -- [ ] Une session possède une connexion `Database`. -- [ ] Une session possède un `InvestigationRecord`. -- [ ] Le dossier racine est validé avant l’ouverture. -- [ ] Le chemin racine est normalisé. -- [ ] Le chemin de la base provient de `InvestigationProject`. -- [ ] Le fichier SQLite doit exister avant l’appel à `database_open()`. -- [ ] L’ouverture ne crée jamais silencieusement une nouvelle base. -- [ ] Le record est chargé avec `InvestigationDao`. -- [ ] Le chemin enregistré est comparé au chemin sélectionné. -- [ ] Une incohérence de chemin empêche l’ouverture. -- [ ] La connexion reste ouverte pendant la durée de vie de la session. -- [ ] La fermeture libère toutes les ressources. -- [ ] Les accesseurs acceptent une session `NULL`. -- [ ] Les erreurs sont propagées avec `GError`. -- [ ] Aucun type SQLite n’apparaît dans l’API de la session. -- [ ] Aucune dépendance GTK n’est ajoutée. -- [ ] Les tests d’ouverture valide sont présents. -- [ ] Les tests de paramètres invalides sont présents. -- [ ] Les tests de dossier absent sont présents. -- [ ] Les tests de base absente sont présents. -- [ ] Les tests de base invalide sont présents. -- [ ] Les tests de chemin incohérent sont présents. -- [ ] Les anciens tests restent valides. -- [ ] `make` réussit sans erreur. -- [ ] `make test` réussit. -- [ ] `git diff --check` ne retourne aucune erreur. - -## Audit attendu - -Les commandes suivantes ne doivent rien afficher : - -```bash -rg -n 'sqlite3_|#include |#include -``` - -et ne doit appeler aucune fonction `sqlite3_*`. - -## 3. Ouvrir la session après la sélection du dossier - -Dans : - -```c -application_on_folder_selected() -``` - -remplacer la création de l’ancien objet : - -```c -investigation_new(folder_path) -``` - -par : - -```c -investigation_session_open( - folder_path, - &error -); -``` - -Utiliser des variables temporaires : - -```c -InvestigationSession *new_session = NULL; -InvestigationTreeModel *new_tree_model = NULL; -GError *error = NULL; -``` - -Ne jamais écrire directement dans : - -```c -application->session -application->tree_model -``` - -avant que toute l’ouverture soit validée. - -## 4. Gérer une sélection annulée - -Lorsque : - -```c -folder_path == NULL -``` - -la fonction doit simplement retourner. - -L’enquête déjà ouverte doit rester active. - -Aucune session ne doit être fermée. - -Aucune erreur ne doit être affichée. - -Un message de diagnostic avec `g_print()` reste acceptable : - -```text -Sélection annulée. -``` - -## 5. Gérer l’échec d’ouverture de session - -Si : - -```c -new_session == NULL -``` - -la fonction doit : - -- afficher un avertissement contenant le message du `GError` ; -- libérer le `GError` ; -- conserver l’ancienne session ; -- conserver l’ancien arbre ; -- ne pas modifier la fenêtre principale. - -Exemple de diagnostic acceptable : - -```c -g_warning( - "Impossible d'ouvrir l'enquête : %s", - error != NULL ? error->message : "erreur inconnue" -); -``` - -Le dialogue graphique d’erreur est hors périmètre de ce ticket. - -## 6. Construire l’arborescence depuis la session - -Récupérer le projet de la nouvelle session : - -```c -const InvestigationProject *project = NULL; -``` - -avec : - -```c -project = investigation_session_get_project( - new_session -); -``` - -Récupérer ensuite son chemin racine : - -```c -const char *root_path = NULL; -``` - -avec : - -```c -root_path = investigation_project_get_root_path( - project -); -``` - -Construire le nouvel arbre avec : - -```c -new_tree_model = investigation_tree_builder_build( - root_path -); -``` - -La logique de construction du chemin ne doit pas être dupliquée dans `application.c`. - -## 7. Gérer l’échec de construction de l’arbre - -Si `InvestigationTreeBuilder` échoue après l’ouverture de la session : - -```text -new_session valide -new_tree_model == NULL -``` - -la fonction doit : - -```c -investigation_session_close(new_session); -``` - -puis retourner. - -L’ancienne session et l’ancien arbre doivent rester actifs. - -Le message suivant est acceptable : - -```text -Impossible de construire l'arborescence de l'enquête. -``` - -## 8. Remplacer les anciens objets uniquement après validation - -Lorsque `new_session` et `new_tree_model` sont tous deux valides : - -```c -investigation_tree_model_free( - application->tree_model -); - -investigation_session_close( - application->session -); - -application->tree_model = new_tree_model; -application->session = new_session; -``` - -Après le transfert : - -```c -new_tree_model = NULL; -new_session = NULL; -``` - -Cette remise à `NULL` n’est pas obligatoire si la fonction retourne immédiatement, mais elle est recommandée pour rendre la propriété explicite. - -## 9. Conserver la connexion SQLite ouverte - -Après une ouverture réussie, la session doit rester stockée dans : - -```c -application->session -``` - -Il est interdit de fermer la session à la fin de : - -```c -application_on_folder_selected() -``` - -La connexion `Database` doit rester utilisable pendant toute la durée d’ouverture de l’enquête. - -## 10. Ajouter un accesseur interne ou public - -Ajouter dans : - -```text -include/core/application.h -``` - -la déclaration suivante : - -```c -const InvestigationSession *application_get_session( - const Application *application -); -``` - -Implémenter dans : - -```text -src/core/application.c -``` - -```c -const InvestigationSession *application_get_session( - const Application *application -) -{ - if (application == NULL) - { - return NULL; - } - - return application->session; -} -``` - -Le pointeur retourné appartient à `Application`. - -Le code appelant ne doit pas fermer cette session. - -Cet accesseur servira aux futurs contrôleurs et DAO. - -## 11. Mettre à jour la fenêtre principale - -Ajouter dans : - -```text -include/views/main_window.h -``` - -la fonction : - -```c -void main_window_set_investigation( - MainWindow *main_window, - const char *investigation_name, - const char *investigation_root_path -); -``` - -Implémenter dans : - -```text -src/views/main_window.c -``` - -Cette fonction doit : - -- accepter `main_window == NULL` ; -- accepter des chaînes `NULL` sans planter ; -- mettre à jour le titre de la fenêtre ; -- mettre à jour la barre d’état. - -### Titre attendu - -Lorsque le nom est valide : - -```text -Labfy Investigation — -``` - -Exemple : - -```text -Labfy Investigation — Enquete_Session -``` - -Lorsque le nom est absent : - -```text -Labfy Investigation -``` - -Construire le titre avec GLib : - -```c -g_strdup_printf() -``` - -puis le libérer avec : - -```c -g_free() -``` - -### Barre d’état attendue - -Lorsque l’enquête est ouverte : - -```text -Enquête ouverte : -``` - -Lorsque certaines valeurs sont absentes, utiliser une formulation sûre sans déréférencer `NULL`. - -La barre d’état ne doit pas conserver un pointeur vers une chaîne temporaire. - -`gtk_label_set_text()` copie le texte fourni. - -## 12. Récupérer le nom persistant - -Dans `application_on_folder_selected()`, récupérer : - -```c -const InvestigationRecord *record = NULL; -const char *investigation_name = NULL; -``` - -avec : - -```c -record = investigation_session_get_record( - application->session -); - -investigation_name = investigation_record_get_name( - record -); -``` - -Utiliser les données du `InvestigationRecord`. - -Ne pas reconstruire le nom à partir du dernier composant du chemin. - -## 13. Mettre à jour la fenêtre après le modèle - -Après l’installation de la nouvelle session et du nouvel arbre : - -```c -main_window_set_tree_model( - application->main_window, - application->tree_model -); -``` - -puis : - -```c -main_window_set_investigation( - application->main_window, - investigation_name, - root_path -); -``` - -L’ordre attendu est : - -```text -nouvelle session installée -nouvel arbre installé -sidebar mise à jour -titre et statut mis à jour -``` - -## 14. Fermer la session dans `application_free()` - -Remplacer : - -```c -investigation_free(application->investigation); -``` - -par : - -```c -investigation_session_close( - application->session -); -``` - -L’ordre de nettoyage conseillé est : - -```c -investigation_tree_model_free( - application->tree_model -); - -investigation_session_close( - application->session -); - -main_window_free( - application->main_window -); -``` - -Puis libérer `GtkApplication` et `Application` comme actuellement. - -`application_free(NULL)` doit rester valide. - -## 15. Ne plus utiliser l’ancien objet dans l’application - -À la fin du ticket, les symboles suivants ne doivent plus apparaître dans `application.c` : - -```text -Investigation * -investigation_new -investigation_free -investigation_get_root_path -investigation_get_database_path -``` - -Le module historique `investigation.c` n’est pas supprimé dans ce ticket. - -Sa suppression éventuelle sera effectuée séparément après vérification qu’aucun autre composant ne l’utilise. - ---- - -# Tests et validations - -## 16. Tests automatisés existants - -Aucun nouveau test GTK automatisé n’est obligatoire dans ce ticket. - -Tous les tests existants doivent rester valides : - -```bash -make test -``` - -En particulier : - -```text -InvestigationProject -InvestigationSession -InvestigationTreeBuilder -InvestigationTreeModel -InvestigationDao -``` - -## 17. Test manuel d’ouverture valide - -Créer ou utiliser une enquête valide. - -Lancer : - -```bash -make -make run -``` - -Sélectionner le dossier racine de l’enquête. - -Vérifier : - -- la fenêtre reste ouverte ; -- l’arborescence apparaît dans la sidebar ; -- le titre contient le nom persistant de l’enquête ; -- la barre d’état contient le nom et le chemin racine ; -- aucune erreur SQLite n’apparaît ; -- la session reste active après la fin du callback. - -## 18. Test manuel d’annulation - -Relancer l’application et annuler la sélection. - -Vérifier : - -- aucun crash ; -- aucun warning critique ; -- la fenêtre reste ouverte ; -- la barre d’état reste sur : - -```text -Aucune enquête ouverte -``` - -## 19. Test manuel d’un dossier invalide - -Sélectionner un dossier qui ne contient pas : - -```text -00_BaseDeDonnees/Enquete.sqlite -``` - -Vérifier : - -- aucun crash ; -- un warning explicite est affiché ; -- aucun fichier SQLite n’est créé ; -- la fenêtre reste utilisable ; -- aucune fausse enquête n’apparaît dans la sidebar. - -## 20. Test manuel de remplacement - -Si l’interface permet une seconde sélection pendant la même exécution : - -1. ouvrir une enquête valide A ; -2. tenter d’ouvrir un dossier invalide ; -3. vérifier que A reste affichée ; -4. ouvrir une enquête valide B ; -5. vérifier que B remplace A. - -Si une seconde sélection n’est pas encore accessible dans l’interface, cette validation sera complétée lors de l’ajout de l’action « Ouvrir ». - -La logique du callback doit néanmoins déjà préserver l’ancienne session. - ---- - -# Gestion de la mémoire - -Les propriétaires doivent être clairement définis. - -## `Application` possède - -```text -GtkApplication -MainWindow -InvestigationSession -InvestigationTreeModel -``` - -## `InvestigationSession` possède - -```text -InvestigationProject -Database -InvestigationRecord -``` - -## Variables temporaires du callback - -```text -new_session -new_tree_model -GError -``` - -En cas d’échec : - -```text -new_session fermée si elle existe -new_tree_model libéré si nécessaire -GError libéré -ancienne session conservée -ancien tree model conservé -``` - -En cas de succès : - -```text -anciens objets libérés -nouveaux objets transférés dans Application -aucun double free -``` - ---- - -# Critères d’acceptation - -- [ ] `Application` possède un `InvestigationSession *`. -- [ ] `Application` ne possède plus d’`Investigation *`. -- [ ] Le callback ouvre une session avec `investigation_session_open()`. -- [ ] Le chemin racine provient de `InvestigationProject`. -- [ ] Le nom provient d’`InvestigationRecord`. -- [ ] L’arbre est construit depuis le chemin de la session. -- [ ] L’ancienne session reste active si l’ouverture échoue. -- [ ] L’ancien arbre reste actif si l’ouverture échoue. -- [ ] La nouvelle session est fermée si la construction de l’arbre échoue. -- [ ] Les anciens objets ne sont remplacés qu’après validation complète. -- [ ] La session reste ouverte après le callback. -- [ ] `application_free()` ferme la session. -- [ ] `application_get_session(NULL)` retourne `NULL`. -- [ ] `main_window_set_investigation()` accepte `NULL`. -- [ ] Le titre affiche le nom de l’enquête. -- [ ] La barre d’état affiche le nom et le chemin racine. -- [ ] `application.c` n’appelle aucune fonction SQLite. -- [ ] Aucun chemin SQLite n’est reconstruit dans `application.c`. -- [ ] Les anciens tests restent valides. -- [ ] `make` réussit sans warning. -- [ ] `make test` réussit. -- [ ] Le test manuel d’ouverture valide réussit. -- [ ] Le test manuel d’annulation réussit. -- [ ] Le test manuel de dossier invalide réussit. -- [ ] `git diff --check` ne retourne aucune erreur. - ---- - -# Audit attendu - -La commande suivante ne doit rien afficher : - -```bash -rg -n \ - 'investigation_new|investigation_free|investigation_get_root_path|investigation_get_database_path|Investigation \*' \ - src/core/application.c -``` - -La commande suivante ne doit rien afficher : - -```bash -rg -n \ - 'sqlite3_|#include |00_BaseDeDonnees|Enquete.sqlite' \ - src/core/application.c -``` - -Vérifier la présence de la nouvelle session : - -```bash -rg -n \ - 'InvestigationSession|investigation_session_' \ - src/core/application.c \ - include/core/application.h -``` - -Vérifier la mise à jour de la fenêtre : - -```bash -rg -n \ - 'main_window_set_investigation' \ - include/views/main_window.h \ - src/views/main_window.c \ - src/core/application.c -``` - ---- - -# Hors périmètre - -Ce ticket ne doit pas ajouter : - -- une action de menu « Ouvrir » ; -- un raccourci clavier ; -- un dialogue graphique détaillé pour les erreurs ; -- la création d’une enquête ; -- la fermeture manuelle d’une enquête ; -- la réparation d’un chemin racine incohérent ; -- la modification de la base SQLite ; -- les DAO des preuves ou des entités ; -- la restauration automatique de la dernière enquête ; -- la persistance des préférences utilisateur ; -- le verrouillage multi-instance ; -- la suppression de l’ancien module `Investigation`. - ---- - -# Fichiers principalement concernés - -```text -include/core/application.h -src/core/application.c - -include/views/main_window.h -src/views/main_window.c -``` - -Fichiers utilisés sans modification attendue : - -```text -include/core/investigation_session.h -src/core/investigation_session.c - -include/core/investigation_project.h -src/core/investigation_project.c - -include/models/investigation_record.h -src/models/investigation_record.c - -include/core/investigation_tree_builder.h -src/core/investigation_tree_builder.c -``` - -Le `Makefile` ne devrait pas nécessiter de nouvelle cible, car les sources de production sont détectées automatiquement avec : - -```make -SRC := $(shell find src -name "*.c") -``` - ---- - -# Résultat attendu - -À la fin du ticket, la sélection d’un dossier doit ouvrir une véritable session d’enquête. - -L’application doit conserver ensemble : - -```text -la connexion SQLite -les métadonnées persistées -le contexte de fichiers -l’arborescence -l’état visuel de la fenêtre -``` - -Le flux final doit être : - -```text -sélection du dossier - ↓ -InvestigationSession ouverte - ↓ -InvestigationTreeModel construit - ↓ -session installée dans Application - ↓ -arbre affiché dans MainWindow - ↓ -nom et chemin affichés -``` - ---- - -# Commit attendu - -Avant le commit : - -```bash -make clean -make -make test -git diff --check -git status --short -``` - -Préparer les fichiers : - -```bash -git add \ - include/core/application.h \ - src/core/application.c \ - include/views/main_window.h \ - src/views/main_window.c -``` - -Contrôler : - -```bash -git diff --cached --stat -git diff --cached -``` - -Créer le commit : - -```bash -git commit -m "feat(app): integrate investigation session" -``` - -Puis pousser après validation complète : - -```bash -git push -``` - diff --git a/docs/tickets/closed/TICKET-030.md b/docs/tickets/closed/TICKET-030.md deleted file mode 100644 index a2bd846..0000000 --- a/docs/tickets/closed/TICKET-030.md +++ /dev/null @@ -1,1115 +0,0 @@ -# Ticket #030 — Créer une enquête depuis l’interface GTK - -## Contexte - -Le ticket #029 a intégré `InvestigationSession` au cycle de vie de l’application. - -L’application sait désormais : - -- ouvrir une enquête existante ; -- conserver sa connexion SQLite ; -- charger ses métadonnées persistées ; -- construire son arborescence ; -- afficher son nom et son chemin dans la fenêtre principale ; -- conserver l’ancienne enquête si une nouvelle ouverture échoue. - -Cependant, lorsqu’aucune enquête n’existe encore, l’utilisateur ne peut pas en créer une depuis l’interface. - -Le dossier sélectionné est actuellement toujours interprété comme une enquête existante. Si la base suivante est absente : - -```text -00_BaseDeDonnees/Enquete.sqlite -``` - -l’ouverture échoue, ce qui est volontairement sûr. - -La création d’une nouvelle enquête doit être une action explicite et séparée de l’ouverture. - ---- - -# Objectif - -Ajouter une première fonctionnalité GTK réellement utilisable : - -```text -Créer une nouvelle enquête -``` - -Le flux attendu est : - -```text -clic sur « Nouvelle enquête » - ↓ -sélection du dossier parent - ↓ -saisie du nom de l’enquête - ↓ -validation des paramètres - ↓ -investigation_project_create() - ↓ -investigation_session_open() - ↓ -construction de l’arborescence - ↓ -installation dans Application - ↓ -mise à jour de MainWindow -``` - -L’utilisateur ne doit jamais avoir à créer manuellement : - -```text -00_BaseDeDonnees -Enquete.sqlite -01_Preuves_Originales -... -09_Hash -``` - ---- - -# Architecture attendue - -```text -MainWindow - │ - └── bouton « Nouvelle enquête » - │ - ▼ -CreateInvestigationDialog - │ - ├── dossier parent - ├── nom de l’enquête - └── validation - │ - ▼ -Application - │ - ├── investigation_project_create() - ├── investigation_session_open() - ├── investigation_tree_builder_build() - └── main_window_set_investigation() -``` - ---- - -# Travail à réaliser - -## 1. Créer un module de dialogue dédié - -Créer : - -```text -include/views/create_investigation_dialog.h -src/views/create_investigation_dialog.c -``` - -Le module doit rester indépendant de SQLite. - -Il ne doit pas inclure : - -```c -#include -``` - -Il ne doit pas appeler : - -```text -database_initialize -investigation_project_create -investigation_session_open -``` - -Son rôle est uniquement de recueillir les informations saisies par l’utilisateur. - ---- - -## 2. Définir le callback public - -Dans : - -```text -include/views/create_investigation_dialog.h -``` - -déclarer : - -```c -typedef void (*CreateInvestigationDialogCallback)( - const char *parent_directory, - const char *investigation_name, - gpointer user_data -); -``` - -Puis : - -```c -void create_investigation_dialog_present( - GtkWindow *parent_window, - CreateInvestigationDialogCallback callback, - gpointer user_data -); -``` - -Le callback reçoit : - -```text -parent_directory -investigation_name -user_data -``` - -En cas d’annulation : - -```text -parent_directory == NULL -investigation_name == NULL -``` - -Les chaînes transmises au callback ne restent valides que pendant l’appel. - -Le callback doit les copier s’il souhaite les conserver. - ---- - -## 3. Concevoir le dialogue GTK - -Le dialogue doit contenir au minimum : - -```text -Titre : Nouvelle enquête - -Dossier parent : -[ chemin sélectionné ] [ Parcourir ] - -Nom de l’enquête : -[ ] - -[ Annuler ] [ Créer ] -``` - -Le bouton `Créer` doit être désactivé tant que : - -```text -aucun dossier parent valide n’est sélectionné -ou -le nom est vide -``` - -Le dialogue peut utiliser : - -```text -GtkWindow -GtkBox -GtkLabel -GtkEntry -GtkButton -GtkFileDialog -``` - -Ne pas utiliser les anciennes API GTK3 synchrones. - ---- - -## 4. Sélectionner le dossier parent - -Le bouton : - -```text -Parcourir -``` - -doit ouvrir un sélecteur de dossier GTK4. - -Le dossier choisi représente le parent dans lequel le nouveau dossier d’enquête sera créé. - -Exemple : - -```text -Dossier parent : -/home/fy59/Documents/Enquetes - -Nom : -Arnaque_Billets -``` - -Résultat attendu : - -```text -/home/fy59/Documents/Enquetes/Arnaque_Billets -``` - -Le dossier parent doit déjà exister. - ---- - -## 5. Valider le nom dans le dialogue - -Le nom doit être refusé s’il est : - -```text -NULL -vide -uniquement composé d’espaces -``` - -Il doit aussi être refusé s’il contient un séparateur de chemin : - -```text -/ -``` - -et, pour rester portable : - -```text -\ -``` - -Exemples invalides : - -```text -Enquetes/Test -Enquetes\Test -``` - -Les espaces en début et fin doivent être supprimés avant l’envoi au callback. - -Utiliser : - -```c -g_strstrip() -``` - -sur une copie allouée. - -Le dialogue ne doit pas modifier directement le contenu interne de `GtkEntry`. - ---- - -## 6. Ajouter le bouton dans `MainWindow` - -Modifier : - -```text -include/views/main_window.h -src/views/main_window.c -``` - -Ajouter un bouton visible : - -```text -Nouvelle enquête -``` - -Il peut être placé dans une barre horizontale au-dessus du `GtkPaned`. - -Organisation attendue : - -```text -MainWindow -└── main_box - ├── action_bar - │ └── bouton Nouvelle enquête - ├── main_paned - └── status_label -``` - -Ajouter dans la structure privée : - -```c -GtkWidget *action_bar; -GtkWidget *new_investigation_button; -``` - ---- - -## 7. Ajouter un callback de fenêtre - -Définir dans : - -```text -include/views/main_window.h -``` - -un type de callback : - -```c -typedef void (*MainWindowNewInvestigationCallback)( - gpointer user_data -); -``` - -Ajouter : - -```c -void main_window_set_new_investigation_callback( - MainWindow *main_window, - MainWindowNewInvestigationCallback callback, - gpointer user_data -); -``` - -`MainWindow` ne doit pas créer elle-même l’enquête. - -Elle ne doit faire que transmettre le clic au contrôleur `Application`. - ---- - -## 8. Conserver les données de callback - -Dans la structure privée de `MainWindow`, ajouter : - -```c -MainWindowNewInvestigationCallback - new_investigation_callback; - -gpointer - new_investigation_user_data; -``` - -Le bouton GTK doit être relié à un callback privé : - -```c -static void main_window_on_new_investigation_clicked( - GtkButton *button, - gpointer user_data -); -``` - -Ce callback doit appeler : - -```c -main_window->new_investigation_callback( - main_window->new_investigation_user_data -); -``` - -uniquement si le callback est défini. - ---- - -## 9. Ajouter le contrôleur dans `Application` - -Modifier : - -```text -src/core/application.c -``` - -Ajouter : - -```c -static void application_on_new_investigation_requested( - gpointer user_data -); -``` - -Cette fonction doit ouvrir : - -```c -create_investigation_dialog_present() -``` - -en utilisant : - -```c -main_window_get_window( - application->main_window -); -``` - ---- - -## 10. Traiter le résultat du dialogue - -Ajouter : - -```c -static void application_on_create_investigation( - const char *parent_directory, - const char *investigation_name, - gpointer user_data -); -``` - -En cas d’annulation : - -```c -parent_directory == NULL -investigation_name == NULL -``` - -la fonction doit simplement retourner. - -Aucun état existant ne doit être modifié. - ---- - -## 11. Créer le projet - -Appeler : - -```c -char *created_root_path = NULL; -``` - -puis : - -```c -created_root_path = investigation_project_create( - parent_directory, - investigation_name -); -``` - -Si la création échoue : - -```text -ancienne session conservée -ancien arbre conservé -aucune modification de MainWindow -warning explicite -``` - -Exemple : - -```c -g_warning( - "Impossible de créer l'enquête '%s' dans '%s'.", - investigation_name, - parent_directory -); -``` - ---- - -## 12. Ouvrir immédiatement la nouvelle enquête - -Après une création valide, ouvrir : - -```c -InvestigationSession *new_session = NULL; -GError *error = NULL; -``` - -avec : - -```c -new_session = investigation_session_open( - created_root_path, - &error -); -``` - -La nouvelle enquête doit être utilisable sans redémarrer l’application. - ---- - -## 13. Construire son arbre - -Récupérer : - -```c -const InvestigationProject *project = NULL; -const char *root_path = NULL; -``` - -Puis construire : - -```c -InvestigationTreeModel *new_tree_model = NULL; -``` - -avec : - -```c -new_tree_model = investigation_tree_builder_build( - root_path -); -``` - ---- - -## 14. Factoriser l’installation d’une session - -Le ticket #029 contient déjà une logique de remplacement dans : - -```c -application_on_folder_selected() -``` - -Cette logique ne doit pas être dupliquée. - -Créer une fonction privée : - -```c -static gboolean application_install_session( - Application *application, - InvestigationSession *new_session, - InvestigationTreeModel *new_tree_model -); -``` - -Cette fonction doit : - -1. valider ses paramètres ; -2. récupérer le projet ; -3. récupérer le record ; -4. récupérer le chemin racine ; -5. récupérer le nom ; -6. libérer l’ancien arbre ; -7. fermer l’ancienne session ; -8. installer les nouveaux objets ; -9. mettre à jour la sidebar ; -10. mettre à jour le titre et la barre d’état. - -Elle retourne : - -```text -TRUE en cas de succès -FALSE en cas d’échec -``` - ---- - -## 15. Propriété des objets dans la fonction factorisée - -Avant l’appel réussi à : - -```c -application_install_session() -``` - -le code appelant possède : - -```text -new_session -new_tree_model -``` - -En cas de succès, `Application` devient propriétaire des deux objets. - -En cas d’échec, le code appelant reste propriétaire et doit les libérer. - -Cette règle doit être documentée clairement. - ---- - -## 16. Adapter l’ouverture existante - -Modifier : - -```c -application_on_folder_selected() -``` - -pour utiliser également : - -```c -application_install_session() -``` - -Le flux devient : - -```text -investigation_session_open() - ↓ -investigation_tree_builder_build() - ↓ -application_install_session() -``` - -Cela garantit que l’ouverture et la création utilisent exactement le même mécanisme d’installation. - ---- - -## 17. Gérer un échec après création du projet - -Si le dossier et la base ont été créés avec succès mais que : - -```text -investigation_session_open() -``` - -ou : - -```text -investigation_tree_builder_build() -``` - -échouent, ne pas supprimer automatiquement le nouveau projet. - -Raison : - -```text -la création SQLite a pu réussir -le dossier contient potentiellement déjà des informations utiles -une suppression automatique après création complète serait risquée -``` - -Afficher un warning explicite indiquant que le projet a été créé mais n’a pas pu être ouvert. - -Exemple : - -```text -L’enquête a été créée dans '', mais son ouverture a échoué. -``` - -Le chemin doit être laissé à l’utilisateur pour diagnostic. - ---- - -## 18. Mettre à jour le statut pendant la création - -Optionnel mais recommandé : - -Avant la création : - -```text -Création de l’enquête… -``` - -Après succès : - -```text -Enquête ouverte : -``` - -En cas d’échec, le statut précédent doit être restauré ou conservé. - -Ne pas laisser le statut bloqué sur : - -```text -Création de l’enquête… -``` - -si l’opération échoue. - ---- - -## 19. Ajouter une fonction de statut générique - -Pour éviter que `Application` manipule directement `GtkLabel`, ajouter dans : - -```text -include/views/main_window.h -``` - -```c -void main_window_set_status( - MainWindow *main_window, - const char *status_text -); -``` - -Implémenter dans : - -```text -src/views/main_window.c -``` - -La fonction doit : - -- accepter `main_window == NULL` ; -- accepter `status_text == NULL` ; -- afficher une chaîne sûre ; -- utiliser `gtk_label_set_text()`. - -Pour `status_text == NULL`, afficher : - -```text -Aucune enquête ouverte -``` - ---- - -# Tests manuels - -## 20. Création valide - -Lancer : - -```bash -make -make run -``` - -Cliquer sur : - -```text -Nouvelle enquête -``` - -Sélectionner : - -```text -/home/fy59/Documents/Enquetes -``` - -Saisir par exemple : - -```text -Test_Enquete -``` - -Vérifier la création de : - -```text -/home/fy59/Documents/Enquetes/Test_Enquete/ -``` - -Vérifier la présence de : - -```text -00_BaseDeDonnees/Enquete.sqlite -01_Preuves_Originales -02_Preuves_Traitees -03_Chronologie -04_Entites -05_Rapports -06_Exports -07_Notes -08_Sources -09_Hash -``` - -Vérifier aussi : - -```text -arborescence visible -titre mis à jour -barre d’état mise à jour -aucune erreur SQLite -``` - ---- - -## 21. Nom vide - -Laisser le nom vide. - -Le bouton `Créer` doit rester désactivé. - -Aucun dossier ne doit être créé. - ---- - -## 22. Nom composé d’espaces - -Saisir uniquement : - -```text - -``` - -Le bouton `Créer` doit rester désactivé ou la validation doit refuser l’opération. - -Aucun dossier ne doit être créé. - ---- - -## 23. Nom contenant un séparateur - -Tester : - -```text -Test/Enquete -``` - -puis : - -```text -Test\Enquete -``` - -La création doit être refusée. - ---- - -## 24. Dossier déjà existant - -Créer une première fois : - -```text -Test_Enquete -``` - -Puis tenter de recréer le même nom dans le même dossier parent. - -Vérifier : - -```text -aucun écrasement -aucune modification du projet existant -warning explicite -ancienne session conservée -``` - ---- - -## 25. Annulation du dialogue - -Ouvrir le dialogue puis cliquer sur : - -```text -Annuler -``` - -Vérifier : - -```text -aucun crash -aucun dossier créé -ancienne session conservée -fenêtre toujours utilisable -``` - ---- - -## 26. Création après ouverture d’une enquête - -Lorsque l’action « Nouvelle enquête » est disponible pendant une session active : - -1. ouvrir une enquête A ; -2. créer une enquête B ; -3. vérifier que B remplace A uniquement après création et ouverture complètes. - -Si la création de B échoue, A doit rester active. - ---- - -# Gestion de la mémoire - -## Dialogue - -Le dialogue possède : - -```text -sa fenêtre GTK -ses widgets -ses chaînes temporaires -``` - -Il doit être détruit après : - -```text -création -annulation -fermeture de la fenêtre -``` - -## Application - -`Application` possède après succès : - -```text -InvestigationSession -InvestigationTreeModel -``` - -## Variables temporaires - -Le callback de création possède temporairement : - -```text -created_root_path -new_session -new_tree_model -GError -``` - -Tous les chemins d’échec doivent libérer les ressources qu’ils possèdent encore. - ---- - -# Critères d’acceptation - -- [ ] Un bouton `Nouvelle enquête` est visible. -- [ ] Le bouton ouvre un dialogue dédié. -- [ ] Le dialogue permet de sélectionner un dossier parent. -- [ ] Le dialogue permet de saisir un nom. -- [ ] Le nom vide est refusé. -- [ ] Le nom composé d’espaces est refusé. -- [ ] Les séparateurs `/` et `\` sont refusés. -- [ ] Le bouton `Créer` n’est actif que lorsque les données sont valides. -- [ ] La création utilise `investigation_project_create()`. -- [ ] La nouvelle enquête est ouverte avec `investigation_session_open()`. -- [ ] L’arborescence est construite automatiquement. -- [ ] La session est installée dans `Application`. -- [ ] Le nom et le chemin sont affichés. -- [ ] L’ancienne session est conservée en cas d’échec. -- [ ] L’ancien arbre est conservé en cas d’échec. -- [ ] La logique d’installation n’est pas dupliquée. -- [ ] Le dialogue ne connaît ni SQLite ni `Database`. -- [ ] Aucun dossier existant n’est écrasé. -- [ ] L’annulation ne modifie aucun état. -- [ ] Les anciens tests restent valides. -- [ ] `make` réussit sans warning. -- [ ] `make test` réussit. -- [ ] Le test manuel de création valide réussit. -- [ ] `git diff --check` ne retourne aucune erreur. - ---- - -# Audit attendu - -Le dialogue ne doit contenir aucune dépendance métier : - -```bash -rg -n \ - 'sqlite3_|database_|investigation_project_create|investigation_session_open' \ - include/views/create_investigation_dialog.h \ - src/views/create_investigation_dialog.c -``` - -Résultat attendu : - -```text -aucune sortie -``` - -Vérifier la factorisation : - -```bash -rg -n \ - 'application_install_session' \ - src/core/application.c -``` - -Vérifier que les deux flux l’utilisent : - -```text -application_on_folder_selected -application_on_create_investigation -``` - -Vérifier l’absence de SQLite dans `Application` : - -```bash -rg -n \ - 'sqlite3_|#include ' \ - src/core/application.c -``` - -Résultat attendu : - -```text -aucune sortie -``` - ---- - -# Hors périmètre - -Ce ticket ne doit pas ajouter : - -- une barre de menu complète ; -- un raccourci clavier ; -- la suppression d’une enquête ; -- le renommage d’une enquête ; -- le déplacement d’une enquête ; -- la restauration de la dernière enquête ; -- une liste des enquêtes récentes ; -- une confirmation de fermeture ; -- l’import de preuves ; -- les DAO des preuves ; -- une boîte d’erreur avancée ; -- la gestion de modèles d’enquête personnalisés. - ---- - -# Fichiers principalement concernés - -```text -include/views/create_investigation_dialog.h -src/views/create_investigation_dialog.c - -include/views/main_window.h -src/views/main_window.c - -src/core/application.c -``` - -Le fichier suivant ne devrait pas nécessiter de modification : - -```text -include/core/application.h -``` - -Le `Makefile` de production détecte automatiquement le nouveau fichier `.c` avec : - -```make -SRC := $(shell find src -name "*.c") -``` - -Aucune nouvelle cible de test n’est obligatoire pour ce ticket GTK. - ---- - -# Résultat attendu - -À la fin du ticket, l’utilisateur doit pouvoir lancer l’application sans disposer d’une enquête préalable. - -Il doit pouvoir : - -```text -ouvrir l’application - ↓ -cliquer sur « Nouvelle enquête » - ↓ -choisir ~/Documents/Enquetes - ↓ -saisir un nom - ↓ -créer l’enquête - ↓ -voir immédiatement son arborescence -``` - -Cette fonctionnalité constitue la première opération complète utilisable depuis GTK. - ---- - -# Commit attendu - -Avant le commit : - -```bash -make clean -make -make test -git diff --check -git status --short -``` - -Préparer les fichiers : - -```bash -git add \ - include/views/create_investigation_dialog.h \ - src/views/create_investigation_dialog.c \ - include/views/main_window.h \ - src/views/main_window.c \ - src/core/application.c -``` - -Contrôler : - -```bash -git diff --cached --stat -git diff --cached -``` - -Créer le commit : - -```bash -git commit -m "feat(ui): add investigation creation workflow" -``` - -Puis pousser après validation complète : - -```bash -git push -``` diff --git a/docs/tickets/closed/TICKET-031.1.md b/docs/tickets/closed/TICKET-031.1.md deleted file mode 100644 index dd49b30..0000000 --- a/docs/tickets/closed/TICKET-031.1.md +++ /dev/null @@ -1,280 +0,0 @@ -# Ticket #031.1 — Ajouter une fermeture propre de l’application - -## Contexte - -L’application permet désormais : - -- de créer une enquête ; -- d’ouvrir une enquête existante ; -- de remplacer proprement la session active. - -La fermeture se fait encore avec : - -```text -Ctrl+C -``` - -Cette méthode interrompt brutalement le processus et ne constitue pas un parcours utilisateur normal. - -## Objectif - -Ajouter un bouton : - -```text -Quitter -``` - -permettant de fermer proprement l’application GTK. - -La fermeture doit déclencher le cycle normal de nettoyage : - -```text -GtkApplication - ↓ -fin de la boucle principale - ↓ -application_free() - ↓ -InvestigationTreeModel libéré - ↓ -InvestigationSession fermée - ↓ -Database fermée - ↓ -MainWindow libérée -``` - -## Travail à réaliser - -### 1. Ajouter le bouton dans `MainWindow` - -Modifier : - -```text -include/views/main_window.h -src/views/main_window.c -``` - -La barre d’actions doit devenir : - -```text -[ Nouvelle enquête ] [ Ouvrir une enquête ] [ Quitter ] -``` - -Ajouter dans la structure privée : - -```c -GtkWidget *quit_button; -``` - -### 2. Ajouter le type de callback - -Dans `include/views/main_window.h`, ajouter : - -```c -typedef void (*MainWindowQuitCallback)( - gpointer user_data -); -``` - -Puis déclarer : - -```c -void main_window_set_quit_callback( - MainWindow *main_window, - MainWindowQuitCallback callback, - gpointer user_data -); -``` - -### 3. Conserver le callback dans `MainWindow` - -Ajouter dans la structure privée : - -```c -MainWindowQuitCallback - quit_callback; - -gpointer - quit_user_data; -``` - -### 4. Ajouter le callback privé du bouton - -Dans `src/views/main_window.c`, ajouter : - -```c -static void main_window_on_quit_clicked( - GtkButton *button, - gpointer user_data -); -``` - -Cette fonction doit : - -- accepter `button == NULL` ; -- accepter `main_window == NULL` ; -- ne rien faire si aucun callback n’est défini ; -- appeler le callback configuré sinon. - -### 5. Créer le bouton - -Dans `main_window_new()` : - -```c -main_window->quit_button = - gtk_button_new_with_label( - "Quitter" - ); -``` - -Ajouter le bouton à `action_bar`. - -Relier son signal `clicked` à : - -```c -main_window_on_quit_clicked -``` - -### 6. Ajouter le setter public - -Implémenter : - -```c -void main_window_set_quit_callback( - MainWindow *main_window, - MainWindowQuitCallback callback, - gpointer user_data -) -{ - if (main_window == NULL) - { - return; - } - - main_window->quit_callback = callback; - main_window->quit_user_data = user_data; -} -``` - -### 7. Ajouter le contrôleur dans `Application` - -Dans `src/core/application.c`, ajouter : - -```c -static void application_on_quit_requested( - gpointer user_data -); -``` - -Cette fonction doit utiliser : - -```c -g_application_quit( - G_APPLICATION( - application->gtk_application - ) -); -``` - -Aucun appel direct à `exit()` ne doit être ajouté. - -### 8. Relier le callback dans `application_on_activate()` - -Ajouter : - -```c -main_window_set_quit_callback( - application->main_window, - application_on_quit_requested, - application -); -``` - -## Tests manuels - -### Fermeture sans enquête - -1. lancer l’application ; -2. cliquer sur `Quitter` ; -3. vérifier que le processus se termine normalement. - -### Fermeture avec une enquête ouverte - -1. ouvrir ou créer une enquête ; -2. cliquer sur `Quitter` ; -3. vérifier que la fenêtre se ferme ; -4. vérifier qu’aucun crash n’apparaît ; -5. relancer l’application ; -6. rouvrir la même enquête. - -### Fermeture après remplacement de session - -1. ouvrir une enquête A ; -2. ouvrir une enquête B ; -3. cliquer sur `Quitter` ; -4. vérifier l’absence de crash ou de double libération. - -## Critères d’acceptation - -- [ ] Le bouton `Quitter` est visible. -- [ ] Le bouton ferme l’application. -- [ ] Aucun `exit()` direct n’est utilisé. -- [ ] `g_application_quit()` est utilisé. -- [ ] `MainWindow` ne connaît pas `GtkApplication`. -- [ ] Le nettoyage reste géré par `Application`. -- [ ] La fermeture fonctionne sans enquête ouverte. -- [ ] La fermeture fonctionne avec une enquête ouverte. -- [ ] La fermeture fonctionne après un changement d’enquête. -- [ ] `make` réussit. -- [ ] `make test` réussit. -- [ ] `git diff --check` ne retourne aucune erreur. - -## Audit attendu - -```bash -rg -n \ - 'quit_button|quit_callback|g_application_quit' \ - include/views/main_window.h \ - src/views/main_window.c \ - src/core/application.c -``` - -La commande suivante ne doit rien afficher : - -```bash -rg -n \ - '\bexit\s*\(' \ - src/core/application.c \ - src/views/main_window.c -``` - -## Fichiers concernés - -```text -include/views/main_window.h -src/views/main_window.c -src/core/application.c -``` - -## Commit attendu - -```bash -make clean -make -make test -git diff --check -git status --short -``` - -```bash -git add \ - include/views/main_window.h \ - src/views/main_window.c \ - src/core/application.c -``` - -```bash -git commit -m "feat(ui): add clean application quit action" -git push -``` diff --git a/docs/tickets/closed/TICKET-031.md b/docs/tickets/closed/TICKET-031.md deleted file mode 100644 index 07b4684..0000000 --- a/docs/tickets/closed/TICKET-031.md +++ /dev/null @@ -1,301 +0,0 @@ -# Ticket #031 — Ouvrir une enquête existante depuis GTK - -## Contexte - -Les tickets #029 et #030 ont permis de : - -- créer une enquête depuis GTK ; -- initialiser son arborescence et sa base SQLite ; -- ouvrir une `InvestigationSession` ; -- construire le `InvestigationTreeModel` ; -- installer la session dans `Application` ; -- afficher le nom et le chemin de l’enquête dans `MainWindow`. - -L’application ne permet cependant pas encore d’ouvrir explicitement une enquête existante. - -L’ancien sélecteur automatique au démarrage a été supprimé afin de ne pas forcer l’utilisateur à choisir un dossier à chaque lancement. - -## Objectif - -Ajouter un bouton : - -```text -Ouvrir une enquête -``` - -Ce bouton doit permettre de sélectionner le dossier racine d’une enquête existante, puis de l’ouvrir avec le flux déjà présent : - -```text -FolderDialog - ↓ -investigation_session_open() - ↓ -investigation_tree_builder_build() - ↓ -application_install_session() - ↓ -MainWindow mise à jour -``` - -La logique d’installation d’une session ne doit pas être dupliquée. - -## Travail à réaliser - -### 1. Ajouter le bouton dans `MainWindow` - -Modifier : - -```text -include/views/main_window.h -src/views/main_window.c -``` - -Ajouter un bouton visible dans la barre d’actions : - -```text -Ouvrir une enquête -``` - -La barre doit contenir au minimum : - -```text -[ Nouvelle enquête ] [ Ouvrir une enquête ] -``` - -Ajouter dans la structure privée : - -```c -GtkWidget *open_investigation_button; -``` - -### 2. Ajouter le type de callback - -Dans `include/views/main_window.h`, ajouter : - -```c -typedef void (*MainWindowOpenInvestigationCallback)( - gpointer user_data -); -``` - -Puis déclarer : - -```c -void main_window_set_open_investigation_callback( - MainWindow *main_window, - MainWindowOpenInvestigationCallback callback, - gpointer user_data -); -``` - -### 3. Conserver le callback dans `MainWindow` - -Ajouter dans la structure privée : - -```c -MainWindowOpenInvestigationCallback - open_investigation_callback; - -gpointer - open_investigation_user_data; -``` - -Ajouter un callback privé : - -```c -static void main_window_on_open_investigation_clicked( - GtkButton *button, - gpointer user_data -); -``` - -Il doit appeler le callback configuré uniquement s’il existe. - -`MainWindow` ne doit pas ouvrir elle-même la session. - -### 4. Relier le bouton à `Application` - -Dans `src/core/application.c`, réactiver l’utilisation de : - -```c -#include "views/folder_dialog.h" -``` - -Ajouter : - -```c -static void application_on_open_investigation_requested( - gpointer user_data -); -``` - -Cette fonction doit ouvrir le sélecteur avec : - -```c -folder_dialog_select_folder( - main_window_get_window(application->main_window), - application_on_folder_selected, - application -); -``` - -### 5. Réutiliser `application_on_folder_selected()` - -La fonction doit : - -1. accepter l’annulation ; -2. ouvrir la session avec `investigation_session_open()` ; -3. récupérer le chemin racine depuis `InvestigationProject` ; -4. construire l’arbre avec `investigation_tree_builder_build()` ; -5. installer les objets avec `application_install_session()`. - -En cas d’échec : - -```text -ancienne session conservée -ancien arbre conservé -nouvelle session libérée -nouvel arbre libéré -warning explicite -``` - -### 6. Enregistrer le callback dans `application_on_activate()` - -Après la création de `MainWindow`, appeler : - -```c -main_window_set_open_investigation_callback( - application->main_window, - application_on_open_investigation_requested, - application -); -``` - -Le sélecteur ne doit pas être lancé automatiquement au démarrage. - -## Tests manuels - -### Ouverture valide - -1. lancer l’application ; -2. cliquer sur `Ouvrir une enquête` ; -3. sélectionner une enquête créée avec le ticket #030 ; -4. vérifier l’affichage de l’arborescence ; -5. vérifier le titre ; -6. vérifier la barre d’état ; -7. vérifier l’absence d’erreur SQLite. - -### Annulation - -Ouvrir le sélecteur puis annuler. - -Vérifier : - -```text -aucun crash -aucun changement de session -aucun changement d’arbre -``` - -### Dossier invalide - -Sélectionner un dossier sans base SQLite. - -Vérifier : - -```text -warning explicite -aucune base créée -ancienne session conservée -``` - -### Remplacement - -1. ouvrir une enquête A ; -2. ouvrir une enquête B ; -3. vérifier que B remplace A. - -### Échec pendant le remplacement - -1. ouvrir une enquête valide A ; -2. tenter d’ouvrir un dossier invalide ; -3. vérifier que A reste active. - -## Critères d’acceptation - -- [ ] Le bouton `Ouvrir une enquête` est visible. -- [ ] Le bouton ouvre un sélecteur de dossier. -- [ ] Le sélecteur ne s’ouvre pas automatiquement au démarrage. -- [ ] Une enquête valide peut être ouverte. -- [ ] L’arborescence est affichée. -- [ ] Le titre est mis à jour. -- [ ] La barre d’état est mise à jour. -- [ ] L’annulation ne modifie aucun état. -- [ ] Un dossier invalide est refusé. -- [ ] Une base absente n’est pas créée. -- [ ] L’ancienne session reste active en cas d’échec. -- [ ] L’ancien arbre reste actif en cas d’échec. -- [ ] `application_install_session()` est réutilisée. -- [ ] Aucun appel SQLite direct n’est ajouté. -- [ ] `make` réussit. -- [ ] `make test` réussit. -- [ ] `git diff --check` ne retourne aucune erreur. - -## Audit attendu - -```bash -rg -n 'open_investigation|Ouvrir une enquête' include/views/main_window.h src/views/main_window.c src/core/application.c -``` - -```bash -rg -n 'folder_dialog_select_folder' src/core/application.c -``` - -```bash -rg -n 'sqlite3_|#include ' src/core/application.c src/views/main_window.c -``` - -Résultat attendu pour la dernière commande : - -```text -aucune sortie -``` - -## Fichiers principalement concernés - -```text -include/views/main_window.h -src/views/main_window.c -src/core/application.c -``` - -## Résultat attendu - -À la fin du ticket, l’application doit proposer deux actions explicites : - -```text -Nouvelle enquête -Ouvrir une enquête -``` - -L’utilisateur doit pouvoir créer une enquête, fermer l’application, puis la rouvrir plus tard depuis GTK. - -## Commit attendu - -```bash -make clean -make -make test -git diff --check -git status --short -``` - -```bash -git add include/views/main_window.h src/views/main_window.c src/core/application.c -``` - -```bash -git commit -m "feat(ui): add investigation opening action" -git push -``` - diff --git a/docs/tickets/closed/TICKET-032.md b/docs/tickets/closed/TICKET-032.md deleted file mode 100644 index b11f79f..0000000 --- a/docs/tickets/closed/TICKET-032.md +++ /dev/null @@ -1,537 +0,0 @@ -# Ticket #032 — Factoriser le chargement et l’installation d’une enquête - -## Contexte - -Après le ticket #031.1, l’application sait : - -- créer une enquête ; -- ouvrir une enquête existante ; -- remplacer la session active ; -- fermer proprement l’application. - -Cependant, les flux « Nouvelle enquête » et « Ouvrir une enquête » dupliquent encore une partie importante de la logique : - -```text -investigation_session_open() -→ récupération du projet -→ récupération du chemin racine -→ investigation_tree_builder_build() -→ application_install_session() -→ nettoyage en cas d’échec -``` - -Cette duplication augmentera avec les futures fonctions : - -- enquêtes récentes ; -- ouverture depuis la ligne de commande ; -- restauration de session ; -- ouverture depuis un rapport ou une archive. - -## Objectif - -Créer dans `src/core/application.c` une fonction interne unique qui ouvre et installe une enquête à partir de son dossier racine. - -Contrat attendu : - -```c -static gboolean application_open_and_install_investigation( - Application *application, - const char *root_path, - GError **error -); -``` - -Cette fonction doit garantir : - -```text -succès : - Application devient propriétaire de la nouvelle session - Application devient propriétaire du nouvel arbre - ancienne session libérée - ancien arbre libéré - fenêtre mise à jour - -échec : - ancienne session conservée - ancien arbre conservé - nouvelle session libérée - nouvel arbre libéré - erreur transmise à l’appelant -``` - ---- - -# Travail à réaliser - -## 1. Ajouter un domaine d’erreur privé - -Dans `src/core/application.c`, ajouter un domaine d’erreur uniquement utilisé par le contrôleur. - -Exemple : - -```c -typedef enum -{ - APPLICATION_OPEN_ERROR_INVALID_ARGUMENT, - APPLICATION_OPEN_ERROR_INVALID_PROJECT, - APPLICATION_OPEN_ERROR_TREE_BUILD, - APPLICATION_OPEN_ERROR_INSTALL -} ApplicationOpenError; -``` - -Ajouter : - -```c -#define APPLICATION_OPEN_ERROR \ - application_open_error_quark() -``` - -Puis : - -```c -static GQuark application_open_error_quark(void) -{ - return g_quark_from_static_string( - "labfy-investigation-application-open-error" - ); -} -``` - -Le domaine reste privé à `application.c`. - ---- - -## 2. Créer la fonction factorisée - -Ajouter : - -```c -static gboolean application_open_and_install_investigation( - Application *application, - const char *root_path, - GError **error -); -``` - -La fonction doit : - -1. valider `application` ; -2. valider `application->main_window` ; -3. valider `root_path` ; -4. ouvrir une nouvelle `InvestigationSession` ; -5. récupérer son `InvestigationProject` ; -6. récupérer le chemin racine canonique ; -7. construire un nouvel `InvestigationTreeModel` ; -8. appeler `application_install_session()` ; -9. transférer la propriété uniquement en cas de succès. - -### Règle de propriété - -Avant `application_install_session()` : - -```text -la fonction possède new_session -la fonction possède new_tree_model -``` - -Après succès : - -```text -Application possède new_session -Application possède new_tree_model -``` - -Après échec : - -```text -la fonction doit libérer les objets qu’elle possède encore -``` - -### Validation de `GError` - -La fonction doit respecter la convention GLib : - -```c -g_return_val_if_fail( - error == NULL || *error == NULL, - FALSE -); -``` - -L’utilisation de `g_return_val_if_fail()` est acceptable ici pour vérifier le contrat du développeur. - -Les erreurs utilisateur doivent être produites avec : - -```c -g_set_error() -g_set_error_literal() -g_propagate_prefixed_error() -``` - ---- - -## 3. Propager l’erreur de `InvestigationSession` - -Si : - -```c -investigation_session_open() -``` - -échoue, la fonction doit conserver l’erreur métier d’origine et lui ajouter du contexte. - -Exemple conceptuel : - -```text -Impossible d’ouvrir l’enquête : la base SQLite est absente -``` - -Ne pas remplacer l’erreur précise par un simple : - -```text -Erreur inconnue -``` - -lorsqu’un `GError` est disponible. - ---- - -## 4. Refactoriser l’ouverture d’une enquête existante - -`application_on_folder_selected()` ne doit plus contenir directement : - -```c -investigation_session_open() -investigation_tree_builder_build() -application_install_session() -``` - -Elle doit seulement : - -1. accepter l’annulation ; -2. appeler `application_open_and_install_investigation()` ; -3. journaliser l’erreur ; -4. libérer le `GError`. - -Structure attendue : - -```c -static void application_on_folder_selected( - const char *folder_path, - gpointer user_data -) -{ - Application *application = user_data; - GError *error = NULL; - - if (application == NULL || - folder_path == NULL) - { - return; - } - - if (!application_open_and_install_investigation( - application, - folder_path, - &error - )) - { - g_warning( - "Impossible d'ouvrir l'enquête '%s' : %s", - folder_path, - error != NULL - ? error->message - : "erreur inconnue" - ); - - g_clear_error(&error); - } -} -``` - -L’annulation ne doit pas produire de warning. - ---- - -## 5. Refactoriser la création d’une enquête - -`application_on_create_investigation()` doit conserver uniquement : - -1. la création physique du projet ; -2. l’appel à la fonction factorisée ; -3. le message spécifique indiquant que le projet existe sur le disque si son ouverture échoue. - -Le flux devient : - -```text -investigation_project_create() -→ application_open_and_install_investigation() -``` - -La fonction ne doit plus reconstruire elle-même : - -```text -session -projet -chemin canonique -arbre -installation -``` - -En cas d’échec après création, le dossier créé reste volontairement sur le disque. - -Le message doit être explicite : - -```text -L’enquête a été créée dans « ... », mais son ouverture a échoué : ... -``` - ---- - -## 6. Ne pas modifier `application_install_session()` - -Cette fonction conserve sa responsabilité actuelle : - -- valider les objets prêts à installer ; -- libérer l’ancien état ; -- transférer la propriété ; -- mettre à jour `MainWindow`. - -Le nouveau helper prépare les objets. - -`application_install_session()` réalise le remplacement final. - ---- - -# Pseudo-code de la fonction factorisée - -```c -static gboolean application_open_and_install_investigation( - Application *application, - const char *root_path, - GError **error -) -{ - InvestigationSession *new_session = NULL; - InvestigationTreeModel *new_tree_model = NULL; - const InvestigationProject *project = NULL; - const char *canonical_root_path = NULL; - GError *session_error = NULL; - - valider les arguments; - - new_session = investigation_session_open( - root_path, - &session_error - ); - - si échec : - propager session_error avec contexte; - return FALSE; - - project = investigation_session_get_project( - new_session - ); - - valider project; - - canonical_root_path = - investigation_project_get_root_path(project); - - valider canonical_root_path; - - new_tree_model = - investigation_tree_builder_build( - canonical_root_path - ); - - si échec : - produire GError; - fermer new_session; - return FALSE; - - si application_install_session() échoue : - produire GError; - libérer new_tree_model; - fermer new_session; - return FALSE; - - return TRUE; -} -``` - ---- - -# Tests manuels - -## Création valide - -1. lancer l’application ; -2. créer une enquête ; -3. vérifier le titre ; -4. vérifier la barre d’état ; -5. vérifier l’arborescence. - -## Ouverture valide - -1. fermer et relancer ; -2. ouvrir l’enquête créée ; -3. vérifier le même résultat. - -## Remplacement valide - -1. ouvrir une enquête A ; -2. ouvrir une enquête B ; -3. vérifier que B remplace A. - -## Échec d’ouverture - -1. ouvrir une enquête valide A ; -2. tenter d’ouvrir un dossier invalide ; -3. vérifier que A reste active ; -4. vérifier que l’erreur est journalisée. - -## Échec après création - -Provoquer si possible un échec d’ouverture après création. - -Vérifier : - -- le dossier créé reste présent ; -- l’ancienne session reste active ; -- aucun double `free` ; -- aucun crash. - -## Annulation - -Annuler le sélecteur de dossier. - -Vérifier : - -- aucun warning ; -- aucun changement d’état ; -- aucun crash. - ---- - -# Critères d’acceptation - -- [ ] Une seule fonction ouvre une session et construit son arbre. -- [ ] La création utilise cette fonction. -- [ ] L’ouverture utilise cette fonction. -- [ ] `application_install_session()` n’est pas dupliquée. -- [ ] L’ancienne session reste active en cas d’échec. -- [ ] L’ancien arbre reste actif en cas d’échec. -- [ ] Les nouveaux objets sont libérés en cas d’échec. -- [ ] Les erreurs de `InvestigationSession` sont propagées. -- [ ] L’annulation ne produit pas d’erreur. -- [ ] Aucun code SQLite direct n’est ajouté. -- [ ] Aucun comportement GTK visible n’est cassé. -- [ ] `make` réussit. -- [ ] `make test` réussit. -- [ ] `git diff --check` ne retourne aucune erreur. - ---- - -# Audit attendu - -La logique d’ouverture ne doit apparaître qu’une seule fois : - -```bash -rg -n \ - 'investigation_session_open|investigation_tree_builder_build' \ - src/core/application.c -``` - -Résultat attendu : - -```text -une occurrence de investigation_session_open -une occurrence de investigation_tree_builder_build -``` - -La création et l’ouverture doivent appeler le helper : - -```bash -rg -n \ - 'application_open_and_install_investigation' \ - src/core/application.c -``` - -Vérifier l’absence de SQLite direct : - -```bash -rg -n \ - 'sqlite3_|#include ' \ - src/core/application.c -``` - -Résultat attendu : - -```text -aucune sortie -``` - -Vérifier le format : - -```bash -git diff --check -``` - ---- - -# Fichiers concernés - -```text -src/core/application.c -``` - -Aucune modification publique n’est normalement nécessaire dans : - -```text -include/core/application.h -``` - ---- - -# Commit attendu - -```bash -make clean -make -make test -git diff --check -git status --short -``` - -```bash -git add src/core/application.c -``` - -```bash -git diff --cached --stat -git diff --cached -``` - -```bash -git commit -m "refactor(core): centralize investigation loading" -git push -``` - ---- - -# Résultat attendu - -Après ce ticket, tous les futurs points d’entrée utiliseront le même flux : - -```text -Création -Ouverture manuelle -Enquêtes récentes -Ligne de commande -Restauration de session - ↓ -application_open_and_install_investigation() -``` - -Le ticket #033 pourra ensuite afficher graphiquement les `GError` déjà correctement produits par ce flux. diff --git a/docs/tickets/closed/TICKET-033.md b/docs/tickets/closed/TICKET-033.md deleted file mode 100644 index bec51ae..0000000 --- a/docs/tickets/closed/TICKET-033.md +++ /dev/null @@ -1,694 +0,0 @@ -# Ticket #033 — Afficher les erreurs dans l’interface GTK - -## Contexte - -Le ticket #032 a centralisé le chargement d’une enquête dans : - -```c -application_open_and_install_investigation() -``` - -Cette fonction produit maintenant des `GError` précis et conserve l’ancienne session en cas d’échec. - -Actuellement, les erreurs sont seulement écrites dans le terminal avec : - -```c -g_warning() -``` - -Un utilisateur qui lance Labfy Investigation depuis son menu d’applications ne verra pas ces messages. - -## Objectif - -Créer un module GTK réutilisable capable d’afficher un message d’erreur compréhensible dans une fenêtre modale. - -Le contrôleur doit conserver deux niveaux d’information : - -```text -Terminal : - message technique complet avec g_warning() - -Interface GTK : - titre clair + message compréhensible -``` - -Le module doit rester générique afin de pouvoir afficher plus tard : - -- erreurs ; -- avertissements ; -- informations. - ---- - -# Architecture attendue - -Créer : - -```text -include/views/application_message_dialog.h -src/views/application_message_dialog.c -``` - -Responsabilités : - -```text -Application - ├── décide quand afficher une erreur - ├── fournit le titre - └── fournit le message - -ApplicationMessageDialog - ├── construit la fenêtre GTK - ├── affiche le contenu - └── gère sa fermeture -``` - -Le module de dialogue ne doit connaître ni : - -- `Application` ; -- `InvestigationSession` ; -- SQLite ; -- les règles métier de l’enquête. - ---- - -# Travail à réaliser - -## 1. Créer l’en-tête public - -Créer : - -```text -include/views/application_message_dialog.h -``` - -Contenu attendu : - -```c -/****************************************************************************** - * @file application_message_dialog.h - * @brief Fenêtre modale affichant un message à l'utilisateur. - ******************************************************************************/ - -#ifndef LABFY_INVESTIGATION_APPLICATION_MESSAGE_DIALOG_H -#define LABFY_INVESTIGATION_APPLICATION_MESSAGE_DIALOG_H - -#include - -/** - * @brief Nature du message affiché. - */ -typedef enum -{ - APPLICATION_MESSAGE_DIALOG_ERROR, - APPLICATION_MESSAGE_DIALOG_WARNING, - APPLICATION_MESSAGE_DIALOG_INFORMATION -} ApplicationMessageDialogType; - -/** - * @brief Affiche une fenêtre modale contenant un message. - * - * Les chaînes sont copiées par les widgets GTK. - * - * @param parent_window Fenêtre parente, ou NULL. - * @param message_type Type de message. - * @param title Titre de la fenêtre. - * @param message Message principal. - */ -void application_message_dialog_present( - GtkWindow *parent_window, - ApplicationMessageDialogType message_type, - const char *title, - const char *message -); - -#endif -``` - ---- - -## 2. Créer l’implémentation GTK - -Créer : - -```text -src/views/application_message_dialog.c -``` - -Le dialogue doit être construit avec des widgets GTK4 simples afin de rester indépendant d’une API de dialogue plus récente. - -Structure visuelle recommandée : - -```text -┌─────────────────────────────────────────────┐ -│ Titre │ -│ │ -│ Message pouvant occuper plusieurs lignes │ -│ │ -│ [ Fermer ] │ -└─────────────────────────────────────────────┘ -``` - -Le module doit utiliser au minimum : - -- `GtkWindow` ; -- `GtkBox` ; -- `GtkLabel` ; -- `GtkButton`. - -Propriétés recommandées : - -```c -gtk_window_set_modal(dialog_window, TRUE); -gtk_window_set_destroy_with_parent(dialog_window, TRUE); -gtk_window_set_resizable(dialog_window, FALSE); -``` - -Si `parent_window` n’est pas `NULL` : - -```c -gtk_window_set_transient_for( - dialog_window, - parent_window -); -``` - -Le message doit : - -- revenir automatiquement à la ligne ; -- être aligné à gauche ; -- être sélectionnable pour permettre sa copie ; -- avoir une largeur raisonnable. - -Exemple : - -```c -gtk_label_set_wrap( - GTK_LABEL(message_label), - TRUE -); - -gtk_label_set_selectable( - GTK_LABEL(message_label), - TRUE -); - -gtk_label_set_xalign( - GTK_LABEL(message_label), - 0.0F -); - -gtk_label_set_max_width_chars( - GTK_LABEL(message_label), - 70 -); -``` - ---- - -## 3. Gérer les arguments invalides - -La fonction doit accepter : - -```text -parent_window == NULL -title == NULL -title vide -message == NULL -message vide -``` - -Valeurs de remplacement recommandées : - -```text -Titre : - Erreur - Avertissement - Information - -Message : - Aucun détail supplémentaire n'est disponible. -``` - -Le titre par défaut dépend de `message_type`. - -Une valeur inconnue de `message_type` doit être traitée comme une information ou un avertissement, sans crash. - ---- - -## 4. Ajouter un callback privé de fermeture - -Dans l’implémentation, ajouter : - -```c -static void application_message_dialog_on_close_clicked( - GtkButton *button, - gpointer user_data -); -``` - -Ce callback doit : - -1. ignorer proprement `button` ; -2. vérifier le pointeur de fenêtre ; -3. appeler `gtk_window_destroy()`. - -Exemple : - -```c -static void application_message_dialog_on_close_clicked( - GtkButton *button, - gpointer user_data -) -{ - GtkWindow *dialog_window = user_data; - - (void) button; - - if (dialog_window == NULL) - { - return; - } - - gtk_window_destroy( - dialog_window - ); -} -``` - -Aucune structure allouée manuellement ne doit être nécessaire pour ce premier dialogue. - ---- - -## 5. Différencier visuellement les types - -Le dialogue doit au minimum afficher un libellé distinct : - -```text -Erreur -Avertissement -Information -``` - -Une différenciation légère peut être ajoutée avec des classes CSS GTK existantes sur le titre ou le bouton. - -La couleur ne doit jamais être le seul moyen de distinguer le type. - -Aucune feuille CSS spécifique n’est nécessaire dans ce ticket. - ---- - -## 6. Ajouter la source au Makefile - -Ajouter : - -```text -src/views/application_message_dialog.c -``` - -à la liste des sources de l’application. - -Le module doit être compilé avec les mêmes options strictes : - -```text --std=c17 --Wall --Wextra --Wpedantic --Werror -``` - ---- - -# Intégration dans `Application` - -## 7. Ajouter l’en-tête - -Dans : - -```text -src/core/application.c -``` - -ajouter : - -```c -#include "views/application_message_dialog.h" -``` - ---- - -## 8. Créer un helper privé dans `application.c` - -Ajouter : - -```c -static void application_present_error( - Application *application, - const char *title, - const char *message -); -``` - -Implémentation attendue : - -```c -static void application_present_error( - Application *application, - const char *title, - const char *message -) -{ - GtkWindow *parent_window = NULL; - - if (application != NULL && - application->main_window != NULL) - { - parent_window = main_window_get_window( - application->main_window - ); - } - - application_message_dialog_present( - parent_window, - APPLICATION_MESSAGE_DIALOG_ERROR, - title, - message - ); -} -``` - -Ce helper centralise le choix du parent GTK. - ---- - -## 9. Afficher les erreurs d’ouverture - -Dans : - -```c -application_on_folder_selected() -``` - -conserver le `g_warning()` existant. - -Ajouter ensuite : - -```c -application_present_error( - application, - "Ouverture impossible", - error != NULL - ? error->message - : "L'enquête sélectionnée n'a pas pu être ouverte." -); -``` - -L’erreur doit être affichée avant : - -```c -g_clear_error(&error); -``` - -L’annulation du sélecteur ne doit toujours afficher aucun message. - ---- - -## 10. Afficher les erreurs de création - -Dans : - -```c -application_on_create_investigation() -``` - -traiter les deux échecs. - -### Échec de création physique - -Conserver le `g_warning()` puis afficher : - -```text -Titre : - Création impossible - -Message : - L'enquête n'a pas pu être créée dans le dossier sélectionné. -``` - -Le message peut contenir : - -- le nom de l’enquête ; -- le dossier parent. - -### Projet créé mais impossible à ouvrir - -Conserver le `g_warning()` puis afficher un message indiquant clairement : - -```text -L'enquête a été créée sur le disque, mais Labfy n'a pas pu l'ouvrir. -``` - -Ajouter ensuite le détail du `GError`. - -Le message doit éviter de laisser croire que le dossier créé a été supprimé. - -Une chaîne dynamique peut être construite avec : - -```c -g_strdup_printf() -``` - -Elle doit être libérée après l’appel au dialogue. - ---- - -# Exemple d’intégration - -```c -char *user_message = NULL; - -user_message = g_strdup_printf( - "L'enquête a été créée dans :\n%s\n\n" - "Elle n'a cependant pas pu être ouverte :\n%s", - created_root_path, - error != NULL - ? error->message - : "erreur inconnue" -); - -application_present_error( - application, - "Enquête créée mais non ouverte", - user_message -); - -g_free( - user_message -); -``` - ---- - -# Gestion de plusieurs erreurs - -Ce ticket ne crée pas encore de file de notifications. - -Si plusieurs erreurs surviennent successivement, plusieurs fenêtres peuvent être affichées. - -La gestion centralisée des tâches et notifications arrivera avec les tickets #034 et #035. - ---- - -# Tests manuels - -## Dossier invalide - -1. lancer l’application ; -2. ouvrir une enquête valide A ; -3. cliquer sur `Ouvrir une enquête` ; -4. sélectionner un dossier qui n’est pas une enquête. - -Vérifier : - -- une fenêtre d’erreur apparaît ; -- le message explique l’échec ; -- A reste active ; -- le terminal contient encore le `g_warning()` ; -- aucun crash. - -## Annulation - -1. ouvrir le sélecteur ; -2. annuler. - -Vérifier : - -- aucun dialogue ; -- aucun warning ; -- aucun changement de session. - -## Création dans un emplacement invalide - -Provoquer si possible un échec de création : - -- dossier non accessible en écriture ; -- nom déjà utilisé ; -- emplacement invalide. - -Vérifier : - -- dialogue visible ; -- message compréhensible ; -- aucune session remplacée. - -## Projet créé mais ouverture échouée - -Provoquer si possible un échec après la création. - -Vérifier que le dialogue précise : - -- que le dossier existe ; -- où il se trouve ; -- que seule l’ouverture a échoué. - -## Fermeture du dialogue - -Tester : - -- bouton `Fermer` ; -- bouton de fermeture de la fenêtre ; -- fermeture de la fenêtre principale. - -Aucun segfault ne doit apparaître. - -## Répétition - -Produire plusieurs erreurs successives. - -Vérifier qu’une nouvelle erreur reste affichable après fermeture de la précédente. - ---- - -# Critères d’acceptation - -- [ ] Le module `application_message_dialog` existe. -- [ ] Le module ne dépend pas du cœur métier. -- [ ] Le dialogue est modal. -- [ ] Le dialogue possède une fenêtre parente lorsqu’elle existe. -- [ ] Le message revient à la ligne. -- [ ] Le message est sélectionnable. -- [ ] Les arguments `NULL` sont acceptés. -- [ ] Un bouton `Fermer` fonctionne. -- [ ] Les erreurs d’ouverture sont visibles dans GTK. -- [ ] Les erreurs de création sont visibles dans GTK. -- [ ] Les `g_warning()` techniques sont conservés. -- [ ] L’annulation ne produit aucun dialogue. -- [ ] L’ancienne session est conservée en cas d’échec. -- [ ] Aucun appel SQLite direct n’est ajouté. -- [ ] Aucun `exit()` direct n’est ajouté. -- [ ] `make` réussit. -- [ ] `make test` réussit. -- [ ] `git diff --check` ne retourne aucune erreur. - ---- - -# Audit attendu - -Vérifier l’utilisation du module : - -```bash -rg -n \ - 'application_message_dialog|application_present_error' \ - include/views/application_message_dialog.h \ - src/views/application_message_dialog.c \ - src/core/application.c \ - Makefile -``` - -Vérifier que les erreurs restent journalisées : - -```bash -rg -n \ - 'g_warning' \ - src/core/application.c -``` - -Vérifier l’absence de logique métier dans le dialogue : - -```bash -rg -n \ - 'Investigation|Database|sqlite3_' \ - include/views/application_message_dialog.h \ - src/views/application_message_dialog.c -``` - -Résultat attendu : - -```text -aucune sortie -``` - -Vérifier l’absence de sortie forcée : - -```bash -rg -n \ - '\bexit\s*\(' \ - src/core/application.c \ - src/views/application_message_dialog.c -``` - -Résultat attendu : - -```text -aucune sortie -``` - ---- - -# Fichiers concernés - -```text -include/views/application_message_dialog.h -src/views/application_message_dialog.c -src/core/application.c -Makefile -``` - ---- - -# Commit attendu - -```bash -make clean -make -make test -git diff --check -git status --short -``` - -```bash -git add \ - include/views/application_message_dialog.h \ - src/views/application_message_dialog.c \ - src/core/application.c \ - Makefile -``` - -```bash -git diff --cached --stat -git diff --cached -``` - -```bash -git commit -m "feat(ui): display application errors in GTK" -git push -``` - ---- - -# Résultat attendu - -Après ce ticket, l’utilisateur ne dépendra plus du terminal pour comprendre pourquoi une enquête n’a pas pu être créée ou ouverte. - -Le ticket #034 pourra ensuite introduire le gestionnaire de tâches asynchrones sans mélanger la présentation des erreurs avec l’exécution des traitements longs. diff --git a/docs/tickets/closed/TICKET-034.md b/docs/tickets/closed/TICKET-034.md deleted file mode 100644 index bec3796..0000000 --- a/docs/tickets/closed/TICKET-034.md +++ /dev/null @@ -1,967 +0,0 @@ -# Ticket #034 — Modèle et exécuteur de tâches asynchrones - -## Contexte - -Labfy Investigation va bientôt exécuter des traitements potentiellement longs : - -- calcul d’empreintes ; -- copie de fichiers ; -- extraction de métadonnées ; -- lancement d’outils externes ; -- recherches DNS et réseau ; -- analyse de résultats ; -- génération de rapports. - -Ces opérations ne doivent jamais bloquer la boucle principale GTK. - -Le ticket #035 ajoutera une file de tâches et un panneau d’activité. Avant cela, il faut créer une abstraction asynchrone fiable, indépendante de GTK et réutilisable par tous les futurs modules. - -## Objectif - -Créer un type opaque : - -```c -BackgroundTask -``` - -capable de : - -- exécuter une fonction de travail dans un thread GLib ; -- conserver son état ; -- suivre sa progression ; -- accepter une demande d’annulation ; -- conserver un résultat ; -- conserver une erreur ; -- enregistrer ses dates de début et de fin ; -- appeler un callback de fin sur le contexte principal ; -- garantir une gestion correcte de sa durée de vie. - -Le module doit s’appuyer sur : - -```text -GTask -GCancellable -GMutex -gatomicrefcount -``` - -Il ne doit dépendre ni de GTK, ni de SQLite, ni d’une enquête particulière. - ---- - -# Architecture attendue - -Créer : - -```text -include/core/background_task.h -src/core/background_task.c -tests/test_background_task.c -``` - -Le flux général doit être : - -```text -background_task_new() - ↓ -background_task_start() - ↓ -GTask exécute le worker dans un thread - ↓ -le worker signale sa progression - ↓ -succès / erreur / annulation - ↓ -callback de fin sur le contexte principal - ↓ -background_task_unref() -``` - ---- - -# 1. Définir les états publics - -Dans : - -```text -include/core/background_task.h -``` - -définir : - -```c -typedef enum -{ - BACKGROUND_TASK_STATE_PENDING, - BACKGROUND_TASK_STATE_RUNNING, - BACKGROUND_TASK_STATE_COMPLETED, - BACKGROUND_TASK_STATE_FAILED, - BACKGROUND_TASK_STATE_CANCELLED -} BackgroundTaskState; -``` - -Transitions autorisées : - -```text -PENDING → RUNNING -RUNNING → COMPLETED -RUNNING → FAILED -RUNNING → CANCELLED -``` - -Une tâche terminée ne peut jamais être redémarrée. - ---- - -# 2. Définir le type opaque - -```c -typedef struct BackgroundTask BackgroundTask; -``` - -La structure interne ne doit jamais apparaître dans le header. - ---- - -# 3. Définir le worker - -Ajouter : - -```c -typedef gboolean (*BackgroundTaskWorker)( - BackgroundTask *task, - GCancellable *cancellable, - gpointer worker_data, - gpointer *result, - GError **error -); -``` - -Contrat : - -```text -succès : - retourne TRUE - error reste NULL - result peut être NULL ou contenir un résultat - -échec : - retourne FALSE - error doit normalement être renseignée - result doit rester NULL - -annulation : - retourne FALSE - error appartient au domaine G_IO_ERROR - code G_IO_ERROR_CANCELLED -``` - -Le worker s’exécute dans un thread secondaire. - -Il ne doit jamais : - -- manipuler directement GTK ; -- accéder à un widget ; -- modifier une structure non protégée ; -- appeler le callback final lui-même. - -Le worker peut appeler : - -```c -background_task_report_progress() -``` - -depuis son thread. - ---- - -# 4. Définir le callback final - -Ajouter : - -```c -typedef void (*BackgroundTaskCompletionCallback)( - BackgroundTask *task, - gpointer user_data -); -``` - -Le callback doit être appelé après la mise à jour de l’état final. - -Lorsqu’une tâche est lancée depuis le thread principal GTK, le callback doit revenir sur ce contexte principal grâce au comportement de `GTask`. - ---- - -# 5. Définir le domaine d’erreur - -Ajouter : - -```c -typedef enum -{ - BACKGROUND_TASK_ERROR_INVALID_ARGUMENT, - BACKGROUND_TASK_ERROR_ALREADY_STARTED, - BACKGROUND_TASK_ERROR_WORKER_PROTOCOL -} BackgroundTaskError; -``` - -Puis : - -```c -#define BACKGROUND_TASK_ERROR \ - background_task_error_quark() - -GQuark background_task_error_quark(void); -``` - -Utilisation : - -- argument invalide ; -- seconde tentative de démarrage ; -- worker retournant `FALSE` sans fournir de `GError` ; -- worker retournant `TRUE` tout en fournissant une erreur. - ---- - -# 6. API publique attendue - -## Construction et références - -```c -BackgroundTask *background_task_new( - const char *title -); - -BackgroundTask *background_task_ref( - BackgroundTask *task -); - -void background_task_unref( - BackgroundTask *task -); -``` - -`background_task_new()` doit refuser : - -```text -title == NULL -title vide -``` - -La tâche utilise un comptage de références atomique. - -Ne pas exposer une fonction `background_task_free()`. - -Cette décision est importante : la tâche doit pouvoir rester vivante pendant l’exécution même si son propriétaire visuel disparaît. - ---- - -## Démarrage - -```c -gboolean background_task_start( - BackgroundTask *task, - BackgroundTaskWorker worker, - gpointer worker_data, - GDestroyNotify worker_data_destroy, - GDestroyNotify result_destroy, - BackgroundTaskCompletionCallback completion_callback, - gpointer completion_data, - GDestroyNotify completion_data_destroy, - GError **error -); -``` - -### Propriété des paramètres - -Si le démarrage réussit : - -```text -BackgroundTask prend en charge worker_data -BackgroundTask prend en charge completion_data -BackgroundTask prend en charge le futur result -``` - -Les fonctions de destruction correspondantes seront appelées au moment approprié. - -Si le démarrage échoue : - -```text -l’appelant conserve worker_data -l’appelant conserve completion_data -``` - -### Contraintes - -La fonction doit : - -1. vérifier `task` ; -2. vérifier `worker` ; -3. vérifier la convention `GError` ; -4. refuser une tâche qui n’est plus `PENDING` ; -5. créer un `GCancellable` ; -6. passer l’état à `RUNNING` ; -7. enregistrer la date de début ; -8. lancer le worker avec `g_task_run_in_thread()` ; -9. conserver une référence interne jusqu’au callback final. - ---- - -## Annulation - -```c -void background_task_cancel( - BackgroundTask *task -); - -gboolean background_task_is_cancelled( - const BackgroundTask *task -); -``` - -`background_task_cancel()` exprime une demande. - -Le worker reste responsable de vérifier régulièrement : - -```c -g_cancellable_set_error_if_cancelled() -``` - -ou : - -```c -g_cancellable_is_cancelled() -``` - -L’annulation ne doit jamais tuer brutalement un thread. - ---- - -## Progression - -```c -void background_task_report_progress( - BackgroundTask *task, - double progress, - const char *status_message -); -``` - -Règles : - -- utilisable depuis le worker ; -- protégée par `GMutex` ; -- valeur limitée entre `0.0` et `1.0` ; -- ignorée si la tâche n’est pas `RUNNING` ; -- `status_message` est copié ; -- `status_message == NULL` est accepté. - -Le ticket #035 pourra lire régulièrement ces valeurs pour mettre à jour le panneau d’activité. - ---- - -## Accesseurs - -```c -const char *background_task_get_title( - const BackgroundTask *task -); - -BackgroundTaskState background_task_get_state( - const BackgroundTask *task -); - -double background_task_get_progress( - const BackgroundTask *task -); - -char *background_task_dup_status_message( - const BackgroundTask *task -); - -gint64 background_task_get_started_at_us( - const BackgroundTask *task -); - -gint64 background_task_get_finished_at_us( - const BackgroundTask *task -); - -GError *background_task_dup_error( - const BackgroundTask *task -); - -gpointer background_task_get_result( - const BackgroundTask *task -); -``` - -### Propriété des valeurs - -```text -get_title() : - pointeur emprunté - valide pendant la durée de vie de task - titre immuable - -dup_status_message() : - nouvelle chaîne - l’appelant doit appeler g_free() - -dup_error() : - nouvelle copie - l’appelant doit appeler g_error_free() - -get_result() : - pointeur emprunté - ne doit jamais être libéré par l’appelant -``` - -`get_result()` ne doit être considéré comme valide qu’après l’état : - -```text -BACKGROUND_TASK_STATE_COMPLETED -``` - ---- - -# 7. Structure interne recommandée - -Dans : - -```text -src/core/background_task.c -``` - -la structure peut contenir : - -```c -struct BackgroundTask -{ - gatomicrefcount reference_count; - GMutex mutex; - - char *title; - char *status_message; - - BackgroundTaskState state; - double progress; - - gint64 started_at_us; - gint64 finished_at_us; - - GCancellable *cancellable; - - gpointer result; - GDestroyNotify result_destroy; - - GError *error; - - BackgroundTaskCompletionCallback - completion_callback; - - gpointer completion_data; - GDestroyNotify completion_data_destroy; -}; -``` - -Les champs mutables doivent être protégés par `mutex`. - -Le titre est immuable après construction. - ---- - -# 8. Contexte interne d’exécution - -Créer une structure privée, par exemple : - -```c -typedef struct -{ - BackgroundTask *task; - - BackgroundTaskWorker worker; - - gpointer worker_data; - GDestroyNotify worker_data_destroy; - - GDestroyNotify result_destroy; -} BackgroundTaskRunContext; -``` - -Le `worker_data` doit être détruit lorsque le contexte `GTask` est libéré. - -Le pointeur `task` peut être non propriétaire si une référence interne distincte garantit sa durée de vie jusqu’au callback final. - ---- - -# 9. Fonction exécutée dans le thread - -Créer un trampoline privé compatible avec : - -```c -GTaskThreadFunc -``` - -Il doit : - -1. récupérer le contexte ; -2. appeler le worker ; -3. vérifier le contrat de retour ; -4. retourner le résultat avec `g_task_return_pointer()` ; -5. retourner l’erreur avec `g_task_return_error()` ; -6. créer une erreur `BACKGROUND_TASK_ERROR_WORKER_PROTOCOL` si le worker viole son contrat. - -Cas à traiter : - -```text -FALSE + error valide : - échec normal - -FALSE + error NULL : - erreur de protocole - -TRUE + error non NULL : - erreur de protocole - -TRUE + result quelconque : - succès -``` - -Si un résultat a été produit alors que l’exécution échoue, il doit être détruit avec `result_destroy`. - ---- - -# 10. Callback interne de fin - -Créer un callback privé compatible avec : - -```c -GAsyncReadyCallback -``` - -Il doit : - -1. appeler `g_task_propagate_pointer()` ; -2. déterminer le nouvel état ; -3. conserver le résultat ou l’erreur ; -4. enregistrer la date de fin ; -5. forcer la progression à `1.0` en cas de succès ; -6. appeler le callback utilisateur ; -7. détruire les données du callback utilisateur ; -8. libérer la référence interne de la tâche. - -Détermination de l’état : - -```text -aucune erreur : - COMPLETED - -G_IO_ERROR_CANCELLED : - CANCELLED - -autre erreur : - FAILED -``` - -Le callback utilisateur doit observer un objet déjà entièrement finalisé. - ---- - -# 11. Destruction de la tâche - -Quand la dernière référence est libérée : - -1. vérifier qu’aucune référence interne d’exécution ne subsiste ; -2. détruire `result` avec `result_destroy` ; -3. libérer `error` ; -4. libérer les chaînes ; -5. libérer `GCancellable` ; -6. libérer les éventuelles données de callback restantes ; -7. nettoyer `GMutex` ; -8. libérer la structure. - -L’appel suivant doit être accepté : - -```c -background_task_unref(NULL); -``` - ---- - -# 12. Sécurité des threads - -Les opérations suivantes doivent utiliser `GMutex` : - -- lecture et écriture de l’état ; -- progression ; -- message de progression ; -- dates ; -- résultat ; -- erreur ; -- accès au cancellable si nécessaire. - -Ne jamais conserver le mutex verrouillé pendant : - -- l’appel du worker ; -- l’appel du callback utilisateur ; -- une fonction de destruction fournie par l’appelant ; -- un appel potentiellement bloquant. - ---- - -# 13. Tests unitaires - -Créer : - -```text -tests/test_background_task.c -``` - -Les tests doivent utiliser un `GMainLoop` pour attendre le callback final. - -## Test de construction - -Vérifier : - -```c -background_task_new(NULL) == NULL -background_task_new("") == NULL -``` - -Vérifier qu’une tâche valide commence avec : - -```text -PENDING -progression 0.0 -date de début 0 -date de fin 0 -aucune erreur -aucun résultat -``` - -## Test de succès - -Créer un worker qui : - -1. signale plusieurs progressions ; -2. renvoie une chaîne allouée ; -3. retourne `TRUE`. - -Vérifier dans le callback : - -```text -état COMPLETED -progression 1.0 -résultat correct -erreur NULL -date de début > 0 -date de fin >= date de début -callback appelé une seule fois -``` - -Vérifier que `result_destroy` est appelé lors du dernier `unref`. - -## Test d’échec - -Créer un worker qui retourne : - -```c -FALSE -``` - -avec une erreur : - -```text -G_IO_ERROR_FAILED -``` - -Vérifier : - -```text -état FAILED -résultat NULL -erreur conservée -message conservé -``` - -## Test de protocole invalide - -Créer un worker qui retourne : - -```c -FALSE -``` - -sans renseigner `GError`. - -Vérifier : - -```text -état FAILED -domaine BACKGROUND_TASK_ERROR -code BACKGROUND_TASK_ERROR_WORKER_PROTOCOL -``` - -## Test d’annulation - -Créer un worker qui travaille par petites étapes et vérifie régulièrement le `GCancellable`. - -Programmer : - -```c -background_task_cancel() -``` - -depuis le contexte principal avec `g_timeout_add()`. - -Vérifier : - -```text -état CANCELLED -erreur G_IO_ERROR_CANCELLED -callback final appelé -aucun crash -``` - -## Test de double démarrage - -Démarrer une tâche puis rappeler immédiatement : - -```c -background_task_start() -``` - -Vérifier : - -```text -FALSE -BACKGROUND_TASK_ERROR_ALREADY_STARTED -``` - -La première exécution doit continuer normalement. - -## Test des données utilisateur - -Vérifier que : - -- `worker_data_destroy` est appelé exactement une fois ; -- `completion_data_destroy` est appelé exactement une fois ; -- aucune donnée n’est détruite lorsque `background_task_start()` échoue avant transfert de propriété. - -## Test du comptage de références - -Démarrer une tâche puis libérer immédiatement la référence de l’appelant. - -Vérifier que : - -- la tâche reste vivante jusqu’au callback ; -- aucun accès mémoire invalide n’a lieu ; -- la destruction finale intervient après la fin de l’exécution. - ---- - -# 14. Makefile - -Le code de production est déjà découvert automatiquement si le Makefile utilise : - -```make -SRC := $(shell find src -name "*.c") -``` - -Ajouter toutefois une cible de test dédiée : - -```make -TEST_BACKGROUND_TASK := tests/test_background_task -``` - -La cible doit compiler au minimum : - -```text -tests/test_background_task.c -src/core/background_task.c -``` - -Lier avec les paquets GLib/GIO déjà utilisés par le projet. - -Ajouter le binaire aux cibles : - -```text -test -clean -``` - -Sortie attendue : - -```text -BackgroundTask : tous les tests sont valides. -``` - ---- - -# 15. Hors périmètre - -Ce ticket ne doit pas encore ajouter : - -- de file de tâches ; -- de limite de concurrence ; -- de panneau GTK ; -- de persistance SQLite ; -- de tâche associée à une enquête ; -- d’exécution de commande externe ; -- d’adaptateur ExifTool ; -- de recherche DNS ; -- de système de notifications ; -- de reprise après redémarrage ; -- de priorité entre tâches. - -Ces fonctions viendront dans les tickets suivants. - ---- - -# 16. Critères d’acceptation - -- [ ] `BackgroundTask` est opaque. -- [ ] Le module ne dépend pas de GTK. -- [ ] Le module ne dépend pas de SQLite. -- [ ] Le module utilise `GTask`. -- [ ] Le module utilise `GCancellable`. -- [ ] Le module utilise un comptage de références. -- [ ] Le module protège son état avec `GMutex`. -- [ ] Une tâche ne peut être démarrée qu’une fois. -- [ ] Le worker s’exécute dans un thread secondaire. -- [ ] Le callback final revient sur le contexte principal. -- [ ] La progression est comprise entre `0.0` et `1.0`. -- [ ] L’annulation est coopérative. -- [ ] Le résultat est conservé jusqu’à la destruction. -- [ ] L’erreur est conservée jusqu’à la destruction. -- [ ] Les dates de début et de fin sont enregistrées. -- [ ] Les données utilisateur sont détruites exactement une fois. -- [ ] La tâche reste vivante pendant son exécution. -- [ ] Aucun callback utilisateur n’est appelé sous mutex. -- [ ] Tous les tests unitaires passent. -- [ ] Les anciens tests restent valides. -- [ ] `make` réussit. -- [ ] `make test` réussit. -- [ ] `git diff --check` ne retourne aucune erreur. - ---- - -# 17. Audit attendu - -Vérifier l’absence de GTK et SQLite : - -```bash -rg -n \ - '#include task_manager = - task_manager_new(); -``` - -En cas d’échec, nettoyer l’application. - -Dans `application_on_activate()` : - -```c -application->main_window = main_window_new( - gtk_application, - application->task_manager -); -``` - -Dans `application_free()` : - -1. fermer/détruire `MainWindow` ; -2. libérer `TaskManager` après le panneau ; -3. poursuivre le nettoyage existant. - -L’ordre doit éviter que `TaskPanel` lise un manager déjà détruit. - ---- - -# Phase E — Tâche de démonstration - -## 15. Ajouter temporairement une tâche de test - -Pour valider l’interface, ajouter un bouton temporaire : - -```text -Tâche de test -``` - -Il lance une `BackgroundTask` qui : - -- dure environ deux secondes ; -- progresse de 0 à 100 % ; -- accepte l’annulation ; -- retourne un résultat simple. - -Cette tâche doit être ajoutée au `TaskManager`. - -Le bouton pourra être supprimé lorsque le premier véritable traitement asynchrone sera disponible. - -Le code de démonstration doit rester clairement identifié : - -```c -/* Temporary demonstration task for ticket #035. */ -``` - ---- - -# Hors périmètre - -Ne pas ajouter encore : - -- de limite de concurrence ; -- de priorité ; -- de persistance SQLite ; -- de reprise après redémarrage ; -- d’historique permanent ; -- d’exécution de commandes ; -- de recherche DNS ; -- d’ExifTool ; -- de notifications système ; -- de tri avancé ; -- de pagination. - ---- - -# Critères d’acceptation - -- [ ] `TaskManager` est opaque. -- [ ] `TaskManager` ne dépend pas de GTK. -- [ ] `TaskManager` protège sa collection avec `GMutex`. -- [ ] Le manager conserve une référence par tâche. -- [ ] Une tâche ne peut pas être ajoutée deux fois. -- [ ] Une tâche peut être retirée. -- [ ] Les tâches terminées peuvent être nettoyées. -- [ ] Toutes les tâches actives peuvent être annulées. -- [ ] Le callback de changement fonctionne. -- [ ] `TaskPanel` affiche toutes les tâches. -- [ ] La progression est visible. -- [ ] L’état est lisible. -- [ ] Une tâche active peut être annulée. -- [ ] Les tâches terminées peuvent être supprimées. -- [ ] Le rafraîchissement périodique est correctement détruit. -- [ ] `MainWindow` ne devient pas propriétaire du manager. -- [ ] L’ordre de destruction ne provoque aucun crash. -- [ ] La tâche de démonstration fonctionne. -- [ ] `make` réussit. -- [ ] `make test` réussit. -- [ ] `git diff --check` ne retourne aucune erreur. - ---- - -# Audit attendu - -Vérifier l’indépendance du manager : - -```bash -rg -n \ - '#include - [vim.lsp: textDocument/didSave handler] - Modifié la dernière fois dans ~/.dotfiles/nvim/.config/nvim/init.lua (run Nvim with -V1 for more details -) -nvim.lsp.b_249_save BufWritePost - - [vim.lsp: textDocument/didSave handler] - Modifié la dernière fois dans ~/.dotfiles/nvim/.config/nvim/init.lua (run Nvim with -V1 for more details -) -nvim.lsp.b_252_save BufWritePost - - [vim.lsp: textDocument/didSave handler] - Modifié la dernière fois dans ~/.dotfiles/nvim/.config/nvim/init.lua (run Nvim with -V1 for more details -) -nvim.lsp.b_255_save BufWritePost - - [vim.lsp: textDocument/didSave handler] - Modifié la dernière fois dans ~/.dotfiles/nvim/.config/nvim/init.lua (run Nvim with -V1 for more details -) -nvim.lsp.b_259_save BufWritePost - - [vim.lsp: textDocument/didSave handler] - Modifié la dernière fois dans ~/.dotfiles/nvim/.config/nvim/init.lua (run Nvim with -V1 for more details -) -nvim.lsp.b_262_save BufWritePost - - [vim.lsp: textDocument/didSave handler] - Modifié la dernière fois dans ~/.dotfiles/nvim/.config/nvim/init.lua (run Nvim with -V1 for more details -) -nvim.lsp.b_273_save BufWritePost - - message - : "erreur inconnue" - ); - - g_clear_error( - &error - ); - - return; -} - -stdout_bytes = tool_process_result_ref_stdout( - result -); - -if (!tool_process_result_is_success( - result - )) -{ - g_warning( - "dig a retourné le code %d", - tool_process_result_get_exit_status( - result - ) - ); -} - -g_bytes_unref( - stdout_bytes -); - -tool_process_result_free( - result -); -``` - -L’exemple illustre le comportement attendu. Il ne constitue pas une obligation d’organisation interne. - ---- - -## Intégration future - -Après validation de ce ticket : - -1. création d’une tâche `BackgroundTask` exécutant `ToolProcess` ; -2. interrogation de la version des outils enregistrés ; -3. premier adaptateur OSINT, probablement DNS ; -4. conservation de la commande structurée : - - exécutable ; - - arguments ; - - date ; - - code de sortie ; - - sortie brute ; - - erreur brute ; -5. enregistrement de la provenance ; -6. affichage des résultats dans le panneau de travail ; -7. gestion ultérieure d’une durée maximale ; -8. ajout des dépendances facultatives aux installateurs Ubuntu. - diff --git a/docs/tickets/closed/TICKET-038.md b/docs/tickets/closed/TICKET-038.md deleted file mode 100644 index ef5c1a0..0000000 --- a/docs/tickets/closed/TICKET-038.md +++ /dev/null @@ -1,1083 +0,0 @@ -# TICKET-038 — Exécution d’un outil externe dans une BackgroundTask - -## Statut - -À faire - -## Priorité - -Haute - -## Objectif - -Créer une couche d’intégration permettant d’exécuter un outil externe dans une `BackgroundTask`, puis de suivre cette exécution avec le `TaskManager` et le panneau d’activité. - -Ce ticket doit relier proprement les modules déjà validés : - -```text -ToolRegistry -ToolProcess -BackgroundTask -TaskManager -TaskPanel -``` - -Le résultat attendu est une abstraction réutilisable capable de : - -- sélectionner un outil enregistré ; -- vérifier sa disponibilité ; -- préparer une exécution structurée ; -- lancer cette exécution dans un thread secondaire ; -- transmettre l’annulation ; -- publier un statut compréhensible ; -- conserver le résultat brut de l’outil ; -- signaler proprement les erreurs ; -- rester indépendante de GTK. - ---- - -## Contexte - -Les tickets précédents ont fourni : - -### Ticket #034 - -```text -BackgroundTask -``` - -pour exécuter un travail asynchrone, publier une progression et gérer l’annulation. - -### Ticket #035 - -```text -TaskManager -TaskPanel -``` - -pour conserver, afficher et annuler les tâches. - -### Ticket #036 - -```text -ToolRegistry -ToolInfo -``` - -pour détecter les exécutables disponibles sur la machine. - -### Ticket #037 - -```text -ToolProcess -ToolProcessResult -``` - -pour lancer un exécutable sans shell, capturer ses sorties et gérer son annulation. - -Il manque maintenant une couche métier qui assemble ces briques sans obliger `Application`, les futurs adaptateurs OSINT ou les widgets GTK à connaître tous les détails de leur fonctionnement interne. - ---- - -## Nom proposé du module - -```text -ToolTask -``` - -Fichiers attendus : - -```text -include/core/tool_task.h -src/core/tool_task.c -tests/test_tool_task.c -``` - -Le nom peut être ajusté avant implémentation s’il existe une meilleure proposition cohérente avec le projet. - ---- - -## Responsabilité du module - -`ToolTask` doit représenter une exécution externe préparée pour être lancée dans une `BackgroundTask`. - -Le module devra : - -1. recevoir un `ToolRegistry` ; -2. rechercher un outil par identifiant ; -3. vérifier que l’outil est disponible ; -4. copier les arguments reçus ; -5. copier le dossier de travail facultatif ; -6. créer une `BackgroundTask` ; -7. utiliser `ToolProcess` dans son worker ; -8. transmettre le `GCancellable` fourni par `BackgroundTask` ; -9. publier un statut avant le lancement ; -10. publier un statut après la fin ; -11. transférer un résultat structuré au propriétaire de la tâche ; -12. convertir les erreurs de préparation en erreurs `ToolTask` ; -13. laisser les erreurs d’exécution de l’outil disponibles dans le résultat ou dans la tâche selon leur nature. - ---- - -## Hors périmètre - -Ce ticket ne doit pas encore : - -- ajouter un outil OSINT réel à l’interface ; -- créer un adaptateur DNS ; -- analyser la sortie d’un outil ; -- enregistrer une preuve ; -- écrire les sorties dans SQLite ; -- sauvegarder les résultats bruts sur disque ; -- afficher directement les sorties dans GTK ; -- gérer une limite de temps ; -- gérer stdin ; -- relancer automatiquement une commande ; -- gérer un pipeline entre plusieurs outils ; -- déterminer automatiquement les arguments d’un outil ; -- modifier le `ToolRegistry`. - -Le premier adaptateur OSINT concret viendra après ce ticket. - ---- - -## Contraintes générales - -- C17. -- GLib et GIO. -- Aucune dépendance GTK. -- Compilation stricte : - -```text --Wall -Wextra -Wpedantic -Werror -``` - -- Aucun shell. -- Aucune concaténation de commande. -- Les arguments doivent rester séparés. -- Les structures publiques doivent être opaques. -- Les fonctions doivent être préfixées par : - -```text -tool_task_ -tool_task_result_ -``` - -- Aucun état global mutable. -- Les règles de propriété doivent être documentées. -- Le module doit être testable sans dépendre d’un outil réellement installé. - ---- - -## Modèle public - -### ToolTaskResult - -Créer une structure opaque : - -```c -typedef struct ToolTaskResult ToolTaskResult; -``` - -Cette structure doit conserver au minimum : - -```text -tool_identifier -executable_path -arguments -working_directory -process_result -``` - -Le champ `process_result` doit contenir le `ToolProcessResult` produit par `ToolProcess`. - -Le résultat doit être indépendant du `ToolRegistry` après sa création. - -### ToolTask - -Deux approches sont possibles. - -#### Approche recommandée - -Ne pas créer une structure persistante `ToolTask`. - -Créer directement une `BackgroundTask` configurée à partir d’une requête. - -Exemple : - -```c -BackgroundTask *tool_task_create( - const ToolRegistry *tool_registry, - const char *tool_identifier, - const char *task_title, - const char *const arguments[], - const char *working_directory, - GError **error -); -``` - -Le `BackgroundTask` retourné n’est pas encore démarré. - -Une seconde fonction démarre la tâche : - -```c -gboolean tool_task_start( - BackgroundTask *background_task, - BackgroundTaskCompletedCallback completed_callback, - gpointer completed_user_data, - GDestroyNotify completed_user_data_destroy, - GError **error -); -``` - -#### Approche alternative - -Créer une structure opaque `ToolTask` possédant sa `BackgroundTask`. - -Cette approche n’est acceptable que si elle simplifie clairement la propriété et les tests. - ---- - -## Domaine d’erreur - -Créer : - -```c -#define TOOL_TASK_ERROR \ - tool_task_error_quark() -``` - -Énumération minimale : - -```c -typedef enum -{ - TOOL_TASK_ERROR_INVALID_ARGUMENT, - TOOL_TASK_ERROR_TOOL_NOT_FOUND, - TOOL_TASK_ERROR_TOOL_NOT_CHECKED, - TOOL_TASK_ERROR_TOOL_MISSING, - TOOL_TASK_ERROR_TASK_CREATION, - TOOL_TASK_ERROR_TASK_START, - TOOL_TASK_ERROR_PROCESS -} ToolTaskError; -``` - -Fonction : - -```c -GQuark tool_task_error_quark(void); -``` - ---- - -## Règles de préparation - -### Outil inconnu - -Si l’identifiant n’existe pas dans le registre : - -```text -retour : NULL -erreur : TOOL_TASK_ERROR_TOOL_NOT_FOUND -``` - -### Outil non vérifié - -Si l’état vaut : - -```text -TOOL_AVAILABILITY_UNKNOWN -``` - -la création doit échouer avec : - -```text -TOOL_TASK_ERROR_TOOL_NOT_CHECKED -``` - -Le module ne doit pas appeler automatiquement `tool_registry_refresh()`. - -Cette décision garde les responsabilités séparées. - -### Outil absent - -Si l’état vaut : - -```text -TOOL_AVAILABILITY_MISSING -``` - -la création doit échouer avec : - -```text -TOOL_TASK_ERROR_TOOL_MISSING -``` - -### Outil disponible sans chemin - -Un outil marqué disponible mais sans chemin résolu représente un état incohérent. - -La création doit échouer. - -### Arguments - -Le tableau d’arguments : - -```c -const char *const arguments[] -``` - -peut être `NULL`. - -Lorsqu’il est fourni : - -- chaque chaîne doit être non `NULL` jusqu’au terminateur ; -- les chaînes doivent être dupliquées ; -- leur ordre doit être conservé ; -- aucune interprétation ne doit être faite ; -- le tableau interne doit se terminer par `NULL`. - -### Titre - -Le titre de la tâche doit être non vide. - -Exemple : - -```text -Interrogation DNS de example.org -``` - -Le titre ne doit pas être fabriqué automatiquement par le module. - ---- - -## Cycle de vie recommandé - -### Création - -```c -BackgroundTask *tool_task_create( - const ToolRegistry *tool_registry, - const char *tool_identifier, - const char *task_title, - const char *const arguments[], - const char *working_directory, - GError **error -); -``` - -Comportement : - -1. valider les arguments ; -2. rechercher `ToolInfo` ; -3. vérifier l’état ; -4. récupérer le chemin résolu ; -5. dupliquer : - - identifiant ; - - chemin ; - - arguments ; - - dossier de travail ; -6. créer les données du worker ; -7. créer une `BackgroundTask` ; -8. attacher les données au futur lancement. - -### Démarrage - -```c -gboolean tool_task_start( - BackgroundTask *background_task, - BackgroundTaskCompletedCallback completed_callback, - gpointer completed_user_data, - GDestroyNotify completed_user_data_destroy, - GError **error -); -``` - -Cette fonction doit : - -1. vérifier que la tâche provient bien de `ToolTask` ; -2. appeler `background_task_start()` ; -3. transmettre : - - le worker ; - - les données du worker ; - - leur destructeur ; - - le destructeur du résultat ; - - le callback de fin ; - - ses données utilisateur. - -La fonction ne doit pas ajouter elle-même la tâche dans un `TaskManager`. - -Cette responsabilité reste à l’appelant. - ---- - -## Worker - -Le worker doit respecter la signature actuelle de `BackgroundTask`. - -Comportement attendu : - -1. publier : - -```text -Préparation de l’exécution -``` - -2. publier : - -```text -Exécution de -``` - -3. appeler `tool_process_run()` avec : - - le chemin détecté ; - - les arguments copiés ; - - le dossier de travail ; - - le `GCancellable` reçu ; -4. si l’appel échoue : - - propager une erreur exploitable ; - - ne produire aucun résultat ; -5. si l’appel réussit : - - créer `ToolTaskResult` ; - - y transférer `ToolProcessResult` ; - - publier un statut final ; -6. placer le résultat dans : - -```c -*result -``` - -### Progression - -Une commande externe ne fournit pas toujours une progression mesurable. - -Pour ce ticket, utiliser une progression qualitative : - -```text -0.0 Préparation -0.1 Lancement -0.9 Exécution terminée, traitement du résultat -1.0 Terminé -``` - -Il ne faut pas simuler une progression régulière avec un minuteur. - ---- - -## Code de sortie non nul - -Un programme lancé correctement mais terminant avec un code non nul ne doit pas faire échouer la `BackgroundTask`. - -Dans ce cas : - -```text -BackgroundTask : COMPLETED -ToolTaskResult : disponible -ToolProcessResult : is_success == FALSE -``` - -Le résultat doit conserver : - -- le code de sortie ; -- stdout ; -- stderr. - -Cette distinction est essentielle pour les futurs adaptateurs. - -Exemple : - -```text -dig retourne 9 -``` - -La tâche technique est terminée, mais le résultat fonctionnel signale un échec. - ---- - -## Annulation - -Le `GCancellable` reçu par le worker doit être transmis directement à : - -```c -tool_process_run() -``` - -Si `ToolProcess` retourne : - -```text -TOOL_PROCESS_ERROR_CANCELLED -``` - -le worker doit permettre à `BackgroundTask` d’aboutir à l’état : - -```text -BACKGROUND_TASK_STATE_CANCELLED -``` - -Il ne doit pas transformer l’annulation en erreur métier générique. - -Aucun processus enfant ne doit rester actif. - ---- - -## Résultat - -### Cycle de vie - -```c -void tool_task_result_free( - ToolTaskResult *result -); -``` - -La fonction doit accepter `NULL`. - -### Identifiant - -```c -const char *tool_task_result_get_tool_identifier( - const ToolTaskResult *result -); -``` - -Chaîne empruntée. - -### Chemin de l’exécutable - -```c -const char *tool_task_result_get_executable_path( - const ToolTaskResult *result -); -``` - -Chaîne empruntée. - -### Arguments - -```c -gsize tool_task_result_get_argument_count( - const ToolTaskResult *result -); -``` - -```c -const char *tool_task_result_get_argument( - const ToolTaskResult *result, - gsize index -); -``` - -Chaînes empruntées. - -### Dossier de travail - -```c -const char *tool_task_result_get_working_directory( - const ToolTaskResult *result -); -``` - -Retourne `NULL` si aucun dossier n’a été défini. - -### Résultat du processus - -```c -const ToolProcessResult *tool_task_result_get_process_result( - const ToolTaskResult *result -); -``` - -Pointeur emprunté. - -Une fonction de transfert ou de référence n’est pas nécessaire pour ce ticket. - ---- - -## Propriété des données - -### Données de préparation - -Le module doit copier toutes les données nécessaires avant le démarrage. - -Il ne doit pas dépendre de la durée de vie : - -- du `ToolRegistry` ; -- du `ToolInfo` ; -- du tableau d’arguments d’origine ; -- du titre d’origine ; -- du dossier de travail d’origine. - -### Résultat - -`ToolTaskResult` devient propriétaire de : - -- l’identifiant copié ; -- le chemin copié ; -- la copie des arguments ; -- la copie du dossier de travail ; -- `ToolProcessResult`. - -Le destructeur doit tout libérer. - -### BackgroundTask - -La propriété de la `BackgroundTask` reste conforme au ticket #034. - ---- - -## API publique suggérée - -```c -typedef struct ToolTaskResult ToolTaskResult; - -typedef enum -{ - TOOL_TASK_ERROR_INVALID_ARGUMENT, - TOOL_TASK_ERROR_TOOL_NOT_FOUND, - TOOL_TASK_ERROR_TOOL_NOT_CHECKED, - TOOL_TASK_ERROR_TOOL_MISSING, - TOOL_TASK_ERROR_TASK_CREATION, - TOOL_TASK_ERROR_TASK_START, - TOOL_TASK_ERROR_PROCESS -} ToolTaskError; - -#define TOOL_TASK_ERROR \ - tool_task_error_quark() - -GQuark tool_task_error_quark(void); - -BackgroundTask *tool_task_create( - const ToolRegistry *tool_registry, - const char *tool_identifier, - const char *task_title, - const char *const arguments[], - const char *working_directory, - GError **error -); - -gboolean tool_task_start( - BackgroundTask *background_task, - BackgroundTaskCompletedCallback completed_callback, - gpointer completed_user_data, - GDestroyNotify completed_user_data_destroy, - GError **error -); - -void tool_task_result_free( - ToolTaskResult *result -); - -const char *tool_task_result_get_tool_identifier( - const ToolTaskResult *result -); - -const char *tool_task_result_get_executable_path( - const ToolTaskResult *result -); - -gsize tool_task_result_get_argument_count( - const ToolTaskResult *result -); - -const char *tool_task_result_get_argument( - const ToolTaskResult *result, - gsize index -); - -const char *tool_task_result_get_working_directory( - const ToolTaskResult *result -); - -const ToolProcessResult *tool_task_result_get_process_result( - const ToolTaskResult *result -); -``` - -L’API peut évoluer si l’implémentation de `BackgroundTask` rend une autre forme plus sûre. - ---- - -## Marquage d’une BackgroundTask - -`tool_task_start()` doit pouvoir vérifier que la tâche reçue a été créée par `tool_task_create()`. - -Approches possibles : - -### Structure privée associée - -Conserver les données du worker dans une structure privée connue uniquement de `ToolTask`. - -### Extension de BackgroundTask - -Ajouter un pointeur de contexte privé à `BackgroundTask` uniquement si cela reste générique et justifié. - -### Wrapper opaque - -Créer un `ToolTask` opaque contenant la `BackgroundTask`. - -Cette solution peut être préférable si la vérification devient fragile. - -Le choix final doit privilégier : - -- sécurité de propriété ; -- lisibilité ; -- testabilité ; -- absence de cast dangereux. - ---- - -## Tests unitaires obligatoires - -Les tests doivent créer un faux outil temporaire. - -Ils ne doivent pas dépendre d’un outil réel. - ---- - -### 1. Arguments invalides - -Tester au minimum : - -- registre `NULL` ; -- identifiant `NULL` ; -- identifiant vide ; -- titre `NULL` ; -- titre vide ; -- dossier de travail vide ; -- `GError` déjà initialisé si la convention est vérifiée. - -Résultat attendu : - -```text -TOOL_TASK_ERROR_INVALID_ARGUMENT -``` - ---- - -### 2. Outil inconnu - -Registre valide mais identifiant absent. - -Résultat : - -```text -TOOL_TASK_ERROR_TOOL_NOT_FOUND -``` - ---- - -### 3. Outil non vérifié - -Enregistrer un outil sans appeler `tool_registry_refresh()`. - -Résultat : - -```text -TOOL_TASK_ERROR_TOOL_NOT_CHECKED -``` - ---- - -### 4. Outil absent - -Enregistrer un faux outil absent, puis rafraîchir. - -Résultat : - -```text -TOOL_TASK_ERROR_TOOL_MISSING -``` - ---- - -### 5. Création valide - -Créer un faux outil dans un `PATH` temporaire. - -Vérifier : - -- registre rafraîchi ; -- création de la `BackgroundTask` ; -- titre correct ; -- état initial `PENDING`. - ---- - -### 6. Copie des arguments - -Créer les arguments avec des chaînes dynamiques. - -Créer la tâche, puis libérer les chaînes originales. - -Démarrer la tâche. - -Le résultat doit toujours contenir les bonnes valeurs. - ---- - -### 7. Exécution réussie - -Le faux outil écrit dans stdout et retourne zéro. - -Vérifier : - -- tâche terminée ; -- état `COMPLETED` ; -- résultat non `NULL` ; -- identifiant correct ; -- chemin correct ; -- arguments corrects ; -- `ToolProcessResult` disponible ; -- `is_success == TRUE`. - ---- - -### 8. Code de sortie non nul - -Le faux outil retourne : - -```text -exit 7 -``` - -Vérifier : - -- tâche `COMPLETED` ; -- résultat disponible ; -- code `7` ; -- succès fonctionnel `FALSE`. - ---- - -### 9. Erreur de lancement - -Créer la tâche avec un exécutable détecté, puis supprimer le fichier avant le démarrage. - -Vérifier : - -- tâche `FAILED` ; -- erreur exploitable ; -- aucun résultat. - ---- - -### 10. Annulation - -Créer un faux outil long. - -Démarrer la tâche puis l’annuler. - -Vérifier : - -- état final `CANCELLED` ; -- aucun résultat ; -- aucun processus enfant actif. - ---- - -### 11. Dossier de travail - -Le faux outil affiche son dossier courant. - -Vérifier que le résultat correspond au dossier demandé. - ---- - -### 12. Plusieurs tâches simultanées - -Créer deux tâches à partir du même outil avec des arguments différents. - -Les lancer simultanément. - -Vérifier : - -- deux résultats indépendants ; -- aucun mélange des arguments ; -- aucun partage incorrect des sorties ; -- aucun état global mutable. - ---- - -### 13. Destruction avant démarrage - -Créer une tâche puis la libérer sans la lancer. - -Vérifier : - -- aucune fuite ; -- destruction des copies d’arguments ; -- destruction des données privées. - ---- - -### 14. Destruction après exécution - -Exécuter une tâche, lire le résultat, puis libérer la tâche. - -Vérifier la libération complète. - ---- - -## Noms de tests suggérés - -```text -/tool_task/invalid_arguments -/tool_task/tool_not_found -/tool_task/tool_not_checked -/tool_task/tool_missing -/tool_task/create -/tool_task/argument_ownership -/tool_task/success -/tool_task/nonzero_exit -/tool_task/spawn_failure -/tool_task/cancellation -/tool_task/working_directory -/tool_task/concurrent_tasks -/tool_task/free_before_start -/tool_task/free_after_completion -``` - ---- - -## Synchronisation des tests - -Les tests doivent utiliser une `GMainLoop` pour attendre la fin des `BackgroundTask`. - -Ils ne doivent pas utiliser une attente active infinie. - -Prévoir un timeout de sécurité afin qu’un test défectueux ne bloque pas toute la suite. - -Exemple : - -```text -5 secondes maximum pour un test normal -``` - -Le test d’annulation doit se terminer rapidement. - ---- - -## Makefile - -Ajouter : - -```make -TEST_TOOL_TASK := tests/test_tool_task -``` - -Règle attendue : - -```make -$(TEST_TOOL_TASK): \ - tests/test_tool_task.c \ - src/core/tool_task.c \ - src/core/tool_registry.c \ - src/core/tool_process.c \ - src/core/background_task.c - $(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS) -``` - -Ajouter la cible à : - -```text -make test -make clean -``` - ---- - -## Vérifications manuelles - -```bash -make clean -make -make tests/test_tool_task -./tests/test_tool_task -make test -``` - ---- - -## Vérification mémoire - -```bash -G_DEBUG=gc-friendly \ -G_SLICE=always-malloc \ -valgrind \ - --leak-check=full \ - --show-leak-kinds=all \ - ./tests/test_tool_task -``` - -Surveiller particulièrement : - -- création sans démarrage ; -- échec de démarrage ; -- annulation ; -- résultat avec code non nul ; -- tâches simultanées. - ---- - -## Critères d’acceptation - -Le ticket est validé lorsque : - -- le module compile en C17 strict ; -- aucune dépendance GTK n’est ajoutée ; -- un outil est recherché par identifiant dans `ToolRegistry` ; -- les états `UNKNOWN` et `MISSING` sont correctement refusés ; -- le chemin résolu est copié ; -- les arguments sont copiés ; -- le dossier de travail est copié ; -- la tâche utilise `ToolProcess` dans un thread secondaire ; -- le `GCancellable` est transmis ; -- l’annulation aboutit à `CANCELLED` ; -- un code de sortie non nul produit une tâche `COMPLETED` ; -- le résultat brut est accessible ; -- les résultats sont indépendants du registre après création ; -- plusieurs tâches peuvent fonctionner simultanément ; -- aucun shell n’est utilisé ; -- aucun processus enfant n’est abandonné ; -- aucune fuite mémoire n’est détectée ; -- tous les tests passent ; -- le test est intégré au `Makefile`. - ---- - -## Démonstration finale prévue - -Après validation du module, remplacer temporairement le bouton actuel : - -```text -Tâche de test -``` - -par une vraie démonstration basée sur un faux outil ou un outil stable détecté. - -Cette démonstration devra passer par : - -```text -ToolRegistry -→ ToolTask -→ BackgroundTask -→ TaskManager -→ TaskPanel -``` - -Le bouton temporaire sera supprimé dès que le premier adaptateur OSINT réel sera disponible. - ---- - -## Suite prévue - -Après ce ticket : - -1. ticket #039 — catalogue initial des outils externes ; -2. interrogation de leurs versions ; -3. ticket d’adaptateur DNS ; -4. conservation structurée des exécutions ; -5. stockage des sorties brutes ; -6. création d’observations et de preuves ; -7. affichage dans le workspace ; -8. packaging Ubuntu avec dépendances optionnelles. diff --git a/docs/tickets/closed/TICKET-039.md b/docs/tickets/closed/TICKET-039.md deleted file mode 100644 index 602599c..0000000 --- a/docs/tickets/closed/TICKET-039.md +++ /dev/null @@ -1,515 +0,0 @@ -# TICKET-039 — Catalogue initial des outils externes et détection de leurs versions - -## Statut - -À faire - -## Priorité - -Haute - -## Objectif - -Créer le catalogue initial des outils externes utilisés par Labfy Investigation et fournir une détection fiable de leur version. - -Ce ticket complète les modules déjà validés : - -```text -ToolRegistry -ToolProcess -ToolTask -``` - -Le catalogue décrit les outils connus par l’application. Le registre décrit leur état sur la machine courante. - -```text -ToolCatalog - description statique des outils connus - ↓ -ToolRegistry - disponibilité, chemin résolu, version détectée - ↓ -ToolProcess - exécution sécurisée de la commande de version -``` - -## Contexte - -`ToolRegistry` permet déjà d’enregistrer un outil, de rechercher son exécutable dans le `PATH`, de conserver son chemin résolu et sa version détectée, et de distinguer les états `UNKNOWN`, `AVAILABLE` et `MISSING`. - -Il manque une source centrale définissant : - -- les outils reconnus par l’application ; -- leur identifiant interne ; -- leur nom affiché ; -- leur exécutable ; -- leur importance ; -- les arguments permettant de demander leur version ; -- la manière de normaliser la sortie obtenue. - -Sans catalogue central, chaque fonctionnalité finirait par enregistrer elle-même ses dépendances. - -## Modules attendus - -```text -include/core/tool_catalog.h -src/core/tool_catalog.c -tests/test_tool_catalog.c -``` - -Le ticket ne doit pas modifier l’API publique de `ToolRegistry`, sauf nécessité démontrée pendant l’implémentation. - -## Responsabilités de ToolCatalog - -Le module doit : - -1. conserver une liste statique et immuable des outils connus ; -2. garantir l’unicité de leurs identifiants ; -3. exposer leurs informations descriptives ; -4. enregistrer l’ensemble du catalogue dans un `ToolRegistry` ; -5. définir les arguments de détection de version ; -6. exécuter ces arguments avec `ToolProcess` ; -7. normaliser la sortie de version ; -8. retourner la version détectée sans modifier directement le registre ; -9. gérer l’annulation ; -10. rester indépendant de GTK. - -Le module ne doit pas installer de dépendance, modifier le `PATH`, utiliser un shell, analyser un résultat OSINT ni modifier l’interface graphique. - -## Catalogue initial - -| Identifiant interne | Nom affiché | Exécutable | Importance | Arguments de version | -|---|---|---|---|---| -| `dns.dig` | `dig` | `dig` | optionnel | `-v` | -| `dns.host` | `host` | `host` | optionnel | `-V` | -| `network.whois` | `whois` | `whois` | optionnel | `--version` | -| `http.curl` | `curl` | `curl` | optionnel | `--version` | -| `tls.openssl` | `OpenSSL` | `openssl` | optionnel | `version` | - -Tous ces outils sont optionnels au niveau de l’application entière. - -Ne pas ajouter encore `nslookup`, `traceroute`, `jq`, `file`, `exiftool`, `nmap`, `subfinder`, `amass`, les outils Python ou les outils installés depuis GitHub. - -## Structure ToolCatalogEntry - -Créer une structure opaque : - -```c -typedef struct ToolCatalogEntry ToolCatalogEntry; -``` - -Elle conserve au minimum : - -```text -identifier -display_name -executable_name -requirement -version_arguments -``` - -Les données du catalogue sont statiques et immuables. Elles ne doivent jamais être libérées par l’appelant. - -## Domaine d’erreur - -```c -#define TOOL_CATALOG_ERROR \ - tool_catalog_error_quark() -``` - -```c -typedef enum -{ - TOOL_CATALOG_ERROR_INVALID_ARGUMENT, - TOOL_CATALOG_ERROR_ENTRY_NOT_FOUND, - TOOL_CATALOG_ERROR_REGISTRATION, - TOOL_CATALOG_ERROR_TOOL_NOT_REGISTERED, - TOOL_CATALOG_ERROR_TOOL_NOT_CHECKED, - TOOL_CATALOG_ERROR_TOOL_MISSING, - TOOL_CATALOG_ERROR_INVALID_TOOL_STATE, - TOOL_CATALOG_ERROR_PROCESS, - TOOL_CATALOG_ERROR_VERSION_COMMAND, - TOOL_CATALOG_ERROR_VERSION_OUTPUT, - TOOL_CATALOG_ERROR_CANCELLED -} ToolCatalogError; -``` - -```c -GQuark tool_catalog_error_quark(void); -``` - -## API publique proposée - -### Consultation - -```c -gsize tool_catalog_get_count(void); -``` - -```c -const ToolCatalogEntry *tool_catalog_get_entry( - gsize index -); -``` - -```c -const ToolCatalogEntry *tool_catalog_find( - const char *identifier -); -``` - -### Accesseurs - -```c -const char *tool_catalog_entry_get_identifier( - const ToolCatalogEntry *entry -); -``` - -```c -const char *tool_catalog_entry_get_display_name( - const ToolCatalogEntry *entry -); -``` - -```c -const char *tool_catalog_entry_get_executable_name( - const ToolCatalogEntry *entry -); -``` - -```c -ToolRequirement tool_catalog_entry_get_requirement( - const ToolCatalogEntry *entry -); -``` - -```c -gsize tool_catalog_entry_get_version_argument_count( - const ToolCatalogEntry *entry -); -``` - -```c -const char *tool_catalog_entry_get_version_argument( - const ToolCatalogEntry *entry, - gsize index -); -``` - -### Enregistrement - -```c -gboolean tool_catalog_register_defaults( - ToolRegistry *tool_registry, - GError **error -); -``` - -### Détection d’une version - -```c -gboolean tool_catalog_detect_version( - const ToolRegistry *tool_registry, - const char *identifier, - GCancellable *cancellable, - char **out_version, - GError **error -); -``` - -`out_version` reçoit une chaîne nouvellement allouée, à libérer avec `g_free()`. - -La fonction ne doit pas appeler `tool_registry_set_version()`. - -## Règles d’enregistrement - -`tool_catalog_register_defaults()` doit vérifier avant toute insertion qu’aucun identifiant du catalogue n’existe déjà dans le registre. - -En cas de doublon : - -- aucune entrée ne doit être ajoutée ; -- la fonction retourne `FALSE` ; -- l’erreur vaut `TOOL_CATALOG_ERROR_REGISTRATION`. - -Cette prévalidation évite une insertion partielle, car `ToolRegistry` ne fournit pas de suppression. - -## Validation de la détection - -La fonction doit refuser : - -- un registre `NULL` ; -- un identifiant `NULL` ou vide ; -- un `out_version` égal à `NULL` ; -- un `out_version` pointant déjà vers une chaîne ; -- un `GError` déjà initialisé. - -Au début d’un appel valide : - -```c -*out_version = NULL; -``` - -Cas d’erreur : - -```text -entrée absente du catalogue → TOOL_CATALOG_ERROR_ENTRY_NOT_FOUND -outil absent du registre → TOOL_CATALOG_ERROR_TOOL_NOT_REGISTERED -état UNKNOWN → TOOL_CATALOG_ERROR_TOOL_NOT_CHECKED -état MISSING → TOOL_CATALOG_ERROR_TOOL_MISSING -AVAILABLE sans chemin résolu → TOOL_CATALOG_ERROR_INVALID_TOOL_STATE -``` - -## Exécution de la commande de version - -Utiliser exclusivement : - -```c -tool_process_run() -``` - -avec : - -```text -executable_path = chemin résolu du ToolRegistry -arguments = arguments statiques du ToolCatalogEntry -working_directory = NULL -cancellable = paramètre reçu -``` - -Interdictions : - -- `/bin/sh -c` ; -- `system()` ; -- `popen()` ; -- concaténation d’une ligne de commande ; -- redirections interprétées ; -- ajout ou transformation des arguments. - -## Annulation - -Si `ToolProcess` retourne `TOOL_PROCESS_ERROR_CANCELLED`, la fonction doit produire : - -```text -G_IO_ERROR -G_IO_ERROR_CANCELLED -``` - -Aucune version partielle ne doit être retournée. - -## Code de sortie - -Pour une commande de version, un code de sortie non nul est un échec : - -```text -TOOL_CATALOG_ERROR_VERSION_COMMAND -``` - -Une terminaison par signal produit la même catégorie d’erreur. - -La sortie ne doit pas être interprétée lorsque le processus n’a pas terminé normalement avec le code zéro. - -## Sélection de la sortie - -Règle générique : - -1. prendre la première ligne non vide de stdout ; -2. si stdout ne contient rien d’exploitable, essayer stderr ; -3. si aucun flux ne contient de texte exploitable, échouer. - -Cette règle évite une logique spéciale par outil pendant ce premier ticket. - -## Normalisation - -Le catalogue ne doit pas extraire seulement un numéro sémantique. - -La version conservée est la première ligne descriptive exploitable, par exemple : - -```text -DiG 9.20.8 -curl 8.14.1 (x86_64-pc-linux-gnu) -OpenSSL 3.5.1 1 Jul 2025 -``` - -Algorithme : - -1. obtenir les octets du flux ; -2. inspecter au maximum 4096 octets par flux ; -3. convertir les octets invalides avec `g_utf8_make_valid()` ; -4. séparer les lignes ; -5. ignorer les lignes vides ; -6. choisir la première ligne non vide ; -7. retirer espaces et tabulations en début et fin ; -8. retirer `\r` et `\n` ; -9. refuser un résultat vide ; -10. retourner une nouvelle chaîne. - -## Propriété des données - -Les entrées et chaînes du catalogue sont empruntées et statiques. - -La chaîne placée dans `*out_version` appartient à l’appelant et doit être libérée avec `g_free()`. - -`ToolCatalog` ne devient jamais propriétaire du registre. - -## Contraintes de thread - -Le catalogue statique est immuable. - -`tool_catalog_detect_version()` : - -- ne modifie pas le catalogue ; -- ne modifie pas le registre ; -- copie le chemin nécessaire avant l’exécution ; -- ne conserve aucun pointeur vers `ToolInfo` après la préparation. - -Le stockage avec `tool_registry_set_version()` reste la responsabilité du propriétaire du registre, idéalement dans le thread principal. - -## Tests unitaires obligatoires - -Les tests utilisent uniquement de faux exécutables temporaires. - -Ils ne doivent pas dépendre des outils réellement installés. - -### Tests du catalogue - -1. nombre exact d’entrées ; -2. contenu exact des cinq entrées ; -3. index invalide ; -4. recherche par identifiant ; -5. identifiant inconnu ; -6. unicité des identifiants ; -7. arguments de version ; -8. enregistrement complet dans un registre vide ; -9. état initial `UNKNOWN` ; -10. prévalidation d’un doublon sans insertion partielle. - -### Tests de détection - -11. arguments invalides ; -12. entrée inconnue ; -13. outil non enregistré ; -14. outil non vérifié ; -15. outil absent ; -16. version sur stdout ; -17. version sur stderr ; -18. première ligne non vide ; -19. normalisation des espaces et fins de ligne ; -20. sortie non UTF-8 ; -21. sortie vide ; -22. code de sortie non nul ; -23. terminaison par signal ; -24. annulation ; -25. indépendance du registre ; -26. plusieurs détections successives. - -## Noms de tests suggérés - -```text -/tool_catalog/entries -/tool_catalog/invalid_index -/tool_catalog/find -/tool_catalog/unique_entries -/tool_catalog/register_defaults -/tool_catalog/register_duplicate -/tool_catalog/detect_invalid_arguments -/tool_catalog/detect_unknown_entry -/tool_catalog/detect_unregistered_tool -/tool_catalog/detect_unchecked_tool -/tool_catalog/detect_missing_tool -/tool_catalog/version_stdout -/tool_catalog/version_stderr -/tool_catalog/version_first_nonempty_line -/tool_catalog/version_normalization -/tool_catalog/version_non_utf8 -/tool_catalog/version_empty -/tool_catalog/version_nonzero_exit -/tool_catalog/version_signaled -/tool_catalog/version_cancelled -/tool_catalog/version_registry_independence -/tool_catalog/version_successive_runs -``` - -## Makefile - -```make -TEST_TOOL_CATALOG := tests/test_tool_catalog -``` - -```make -$(TEST_TOOL_CATALOG): \ - tests/test_tool_catalog.c \ - src/core/tool_catalog.c \ - src/core/tool_registry.c \ - src/core/tool_process.c - $(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS) -``` - -Ajouter le binaire à `make test` et `make clean`. - -## Vérifications - -```bash -make clean -make -make tests/test_tool_catalog -./tests/test_tool_catalog -make test -git diff --check -``` - -## Vérification mémoire - -```bash -G_DEBUG=gc-friendly \ -G_SLICE=always-malloc \ -valgrind \ - --leak-check=full \ - --show-leak-kinds=all \ - ./tests/test_tool_catalog -``` - -## Critères d’acceptation - -Le ticket est validé lorsque : - -- le catalogue contient exactement les cinq outils prévus ; -- toutes les entrées sont immuables ; -- tous les identifiants sont uniques ; -- le catalogue s’enregistre dans un registre vide ; -- un doublon empêche toute insertion partielle ; -- la détection utilise `ToolProcess` ; -- aucun shell n’est utilisé ; -- stdout et stderr sont pris en charge ; -- la première ligne non vide est normalisée ; -- une sortie invalide devient un UTF-8 valide ; -- l’inspection est limitée à 4096 octets par flux ; -- un code non nul ou un signal est refusé ; -- l’annulation produit `G_IO_ERROR_CANCELLED` ; -- la fonction ne modifie pas directement le registre ; -- les versions successives sont indépendantes ; -- les tests ne dépendent d’aucun outil installé ; -- tous les tests passent ; -- aucune fuite mémoire n’est détectée ; -- le test est intégré au `Makefile`. - -## Démonstration finale - -Après validation : - -1. créer un `ToolRegistry` ; -2. appeler `tool_catalog_register_defaults()` ; -3. appeler `tool_registry_refresh()` ; -4. afficher les outils présents et absents ; -5. détecter la version d’un outil disponible ; -6. stocker explicitement la version avec `tool_registry_set_version()`. - -Cette démonstration restera hors de l’interface GTK principale. - -## Suite prévue - -```text -#040 — Initialisation des dépendances et analyse asynchrone au démarrage -``` - -Ce ticket devra créer le registre global de l’application, enregistrer le catalogue, rafraîchir les disponibilités hors du thread GTK, détecter les versions et publier une tâche dans `TaskManager`. diff --git a/docs/tickets/open/TICKET-040.md b/docs/tickets/open/TICKET-040.md deleted file mode 100644 index 1b83145..0000000 --- a/docs/tickets/open/TICKET-040.md +++ /dev/null @@ -1,681 +0,0 @@ -# TICKET-040 — Inventaire et qualification de l’arsenal OSINT - -## Statut - -À faire - -## Priorité - -Très haute - -## Nature - -Recherche, audit juridique, architecture et préparation des futures intégrations. - -La présence d’un outil dans cet inventaire ne signifie pas qu’il est approuvé. - ---- - -## Objectif - -Constituer une base large, structurée et maintenable d’outils OSINT pouvant être intégrés à Labfy Investigation afin d’aider à enquêter légalement sur : - -- pseudonymes et comptes publics ; -- adresses e-mail ; -- numéros de téléphone ; -- domaines, IP, certificats et infrastructures publiques ; -- documents, faux papiers, photos et vidéos ; -- historiques de pages supprimées ; -- dépôts publics ; -- IBAN, entreprises et cryptomonnaies ; -- relations entre personnes, comptes, domaines et moyens de paiement ; -- réseaux d’escrocs réutilisant les mêmes identifiants. - -Le résultat doit être traçable, reproductible et présentable à des enquêteurs. - ---- - -## Cadre légal non négociable - -Labfy Investigation reste limité à : - -- sources publiquement accessibles ; -- données remises légalement par une victime ou un enquêteur ; -- API et comptes utilisés conformément à leurs autorisations ; -- collecte sans contournement d’authentification ; -- recherche passive ou explicitement autorisée ; -- conservation de la méthode, de la source et de la sortie brute. - -Sont exclus : - -- intrusion ; -- exploitation de vulnérabilité ; -- brute force d’authentification ; -- credential stuffing ; -- phishing ; -- vol ou réutilisation de jetons ; -- usurpation ; -- social engineering ; -- accès à une ressource privée ; -- modification d’une ressource distante ; -- utilisation de données obtenues illicitement. - ---- - -## Livrables - -```text -docs/osint/TOOL_INVENTORY.md -docs/osint/LEGAL_AND_OPERATIONAL_POLICY.md -data/osint_tools.json -data/osint_tools.csv -``` - -Le JSON deviendra la future source de génération du catalogue étendu. - ---- - -## Schéma d’une fiche outil - -```text -identifier -name -repository -homepage -publisher -category -subcategories -description -license -license_verified -open_source_status -latest_release -last_activity -primary_language -installation_methods -ubuntu_packages -runtime_dependencies -input_types -output_formats -supports_json -supports_csv -supports_stdout -supports_file_output -requires_account -requires_api_key -requires_paid_service -network_activity -collection_mode -authentication_mode -rate_limit_risk -terms_of_service_risk -personal_data_risk -false_positive_risk -evidentiary_value -reproducibility -tool_version_command -integration_mode -integration_priority -legal_status -maintenance_status -decision -decision_reason -notes -reviewed_at -reviewed_by -``` - ---- - -## Valeurs normalisées - -### open_source_status - -```text -OPEN_SOURCE -SOURCE_AVAILABLE -OPEN_CLIENT_CLOSED_SERVICE -CLOSED_SOURCE -UNKNOWN -``` - -### collection_mode - -```text -LOCAL_ONLY -PASSIVE_REMOTE -REMOTE_PUBLIC_REQUESTS -AUTHENTICATED_PUBLIC_API -ACTIVE_LOW_IMPACT -ACTIVE_INTRUSIVE -MIXED -``` - -### legal_status - -```text -APPROVED_PASSIVE -APPROVED_WITH_CONFIGURATION -MANUAL_REVIEW_REQUIRED -RESTRICTED_TO_AUTHORIZED_TARGETS -REJECTED -UNKNOWN -``` - -### integration_mode - -```text -DIRECT_CLI -DIRECT_LIBRARY -LOCAL_SERVICE -REMOTE_API -BROWSER_ASSISTED -EXPORT_IMPORT -REFERENCE_ONLY -REJECTED -``` - -### integration_priority - -```text -P0 -P1 -P2 -P3 -BACKLOG -REJECTED -``` - -### decision - -```text -INTEGRATE -PROTOTYPE -MONITOR -MANUAL_ONLY -REJECT -UNREVIEWED -``` - ---- - -## Notation sur 100 - -- valeur opérationnelle : 30 ; -- intégrabilité : 20 ; -- légalité et maîtrise du risque : 20 ; -- traçabilité : 15 ; -- maintenance : 10 ; -- coût : 5. - -Un outil sous 50/100 ne doit pas être intégré sans justification écrite. - ---- - -# Inventaire initial à auditer - -## A. Pseudonymes, comptes et identités publiques - -| Outil | Dépôt/projet | Usage | Priorité | -|---|---|---|---| -| Sherlock | `sherlock-project/sherlock` | Recherche de pseudonymes | P0 | -| Maigret | `soxoj/maigret` | Recherche approfondie de pseudonymes | P0 | -| Blackbird | `p1ngul1n0/blackbird` | Comptes et enrichissement | P1 | -| WhatsMyName | `WebBreacher/WhatsMyName` | Base de règles de présence | P0 | -| Enola | `theyahya/enola` | Recherche rapide de pseudonymes | P2 | -| Social Analyzer | `qeeqbox/social-analyzer` | Analyse multi-plateformes | P2 | -| socialscan | `iojw/socialscan` | Pseudonymes et e-mails | P1 | -| GHunt | `mxrch/GHunt` | Écosystème Google | P1 | -| GitFive | `mxrch/GitFive` | Corrélation GitHub | P1 | -| Holehe | `megadose/holehe` | Présence d’une adresse sur des services | P0 | -| MOSINT | `alpkeskin/mosint` | Enrichissement d’e-mails | P2 | -| h8mail | `khast3x/h8mail` | Jeux de données autorisés uniquement | P1 restreint | -| Ignorant | `megadose/ignorant` | Présence d’un téléphone sur des services | Revue | -| Instaloader | `instaloader/instaloader` | Contenus Instagram publics | Revue | -| snscrape | `JustAnotherArchivist/snscrape` | Collecte sociale publique | Revue | -| gallery-dl | `mikf/gallery-dl` | Conservation de médias publics | P1 | -| yt-dlp | `yt-dlp/yt-dlp` | Métadonnées et médias publics | P0 | - -## B. E-mails - -| Outil | Usage | Priorité | -|---|---|---| -| Holehe | Présence sur des services | P0 | -| MOSINT | Enrichissement multi-source | P2 | -| h8mail | Recherche dans des sources licites | Restreint | -| GHunt | Enrichissement Google | P1 | -| theHarvester | E-mails liés à un domaine | P0 | -| SpiderFoot | Modules d’enrichissement | P1 | -| Recon-ng | Framework modulaire | P2 | -| python-email-validator | Validation et normalisation | P1 | -| dnspython | Vérification DNS et MX | P1 | -| Clients OpenPGP | Identifiants publiés dans des clés | P2 | - -## C. Téléphones - -| Outil | Dépôt/projet | Usage | Priorité | -|---|---|---|---| -| PhoneInfoga | `sundowndev/phoneinfoga` | Pays, opérateur, formats, sources publiques | P0 | -| libphonenumber | `google/libphonenumber` | Parsing et validation | P0 | -| python-phonenumbers | `daviddrysdale/python-phonenumbers` | Adaptateur Python | P2 | -| Ignorant | `megadose/ignorant` | Présence sur certains services | Revue | -| Normalisation E.164 interne | Labfy | Canonicalisation | P0 | - -Aucun outil ne doit prétendre identifier le titulaire réel d’un numéro sans source officielle ou judiciaire. - -## D. Domaines, DNS, certificats et infrastructures - -| Outil | Dépôt/projet | Usage | Priorité | -|---|---|---|---| -| Amass | `owasp-amass/amass` | Cartographie d’actifs | P1 | -| Subfinder | `projectdiscovery/subfinder` | Sous-domaines passifs | P0 | -| theHarvester | `laramies/theHarvester` | Domaines, e-mails, IP, noms | P0 | -| SpiderFoot | `smicallef/spiderfoot` | Automatisation multi-source | P1 | -| Recon-ng | `lanmaster53/recon-ng` | Framework modulaire | P2 | -| sn0int | `kpcyrd/sn0int` | Framework semi-automatique | P2 | -| BBOT | `blacklanternsecurity/bbot` | Orchestration récursive | Revue | -| dnsx | `projectdiscovery/dnsx` | Requêtes DNS structurées | P1 | -| Findomain | `Findomain/Findomain` | Sous-domaines | P2 | -| assetfinder | `tomnomnom/assetfinder` | Actifs passifs | P2 | -| dnstwist | `elceef/dnstwist` | Typosquatting et variantes | P0 | -| URLCrazy | `urbanadventurer/urlcrazy` | Variantes de domaines | P1 | -| CertStream | `CaliDog/certstream-python` | Certificats publics | P1 | -| massdns | `blechschmidt/massdns` | Résolution de masse | Restreint | -| puredns | `d3mondev/puredns` | Résolution de masse | Restreint | -| shuffledns | `projectdiscovery/shuffledns` | Résolution de masse | Restreint | -| Knockpy | `guelfoweb/knock` | Sous-domaines | Revue | -| Sublist3r | `aboul3la/Sublist3r` | Sous-domaines | Surveillance | -| httpx | `projectdiscovery/httpx` | Qualification HTTP | Restreint | -| httprobe | `tomnomnom/httprobe` | Services HTTP | Restreint | -| Katana | `projectdiscovery/katana` | Exploration Web | Restreint | -| RDAP clients | À sélectionner | Enregistrements normalisés | P0 | -| curl | Projet curl | Requêtes HTTP reproductibles | P0 | -| OpenSSL | Projet OpenSSL | Certificats TLS | P0 | -| dig / host / whois | Paquets système | DNS et enregistrements | P0 | - -Les outils à forte volumétrie sont désactivés par défaut. - -## E. Historique du Web et conservation - -| Outil | Dépôt/projet | Usage | Priorité | -|---|---|---|---| -| waybackurls | `tomnomnom/waybackurls` | URLs Wayback | P0 | -| gau | `lc/gau` | URLs d’archives multiples | P0 | -| waymore | `xnl-h4ck3r/waymore` | Historique approfondi | P1 | -| ArchiveBox | `ArchiveBox/ArchiveBox` | Archivage local | P0 | -| Browsertrix Crawler | `webrecorder/browsertrix-crawler` | WARC/WACZ | P0 | -| Browsertrix | `webrecorder/browsertrix` | Service local | P2 | -| ArchiveWeb.page | `webrecorder/archiveweb.page` | Capture navigateur | P0 | -| pywb | `webrecorder/pywb` | Relecture WARC | P1 | -| warcio | `webrecorder/warcio` | Lecture/écriture WARC | P0 | -| ReplayWeb.page | `webrecorder/replayweb.page` | Relecture d’archives | P1 | -| SingleFile | `gildas-lormeau/SingleFile` | Copie autonome d’une page | P0 | -| monolith | `Y2Z/monolith` | Sauvegarde autonome | P1 | -| grab-site | `ArchiveTeam/grab-site` | Archivage WARC | Revue | -| Heritrix | `internetarchive/heritrix3` | Crawl d’archivage | Restreint | -| waybackpy | `akamhy/waybackpy` | Client Wayback | P2 | -| Perma | `harvard-lil/perma` | Préservation de références | Manuel/API | - -## F. Documents, photos et vidéos - -| Outil | Dépôt/projet | Usage | Priorité | -|---|---|---|---| -| ExifTool | `exiftool/exiftool` | Métadonnées multi-format | P0 | -| MediaInfo | `MediaArea/MediaInfo` | Audio et vidéo | P0 | -| FFmpeg / ffprobe | `FFmpeg/FFmpeg` | Analyse technique | P0 | -| Exiv2 | `Exiv2/exiv2` | Métadonnées d’images | P1 | -| Hachoir | `hachoir/hachoir` | Formats binaires | P1 | -| oletools | `decalage2/oletools` | Documents Office | P0 | -| DidierStevensSuite | `DidierStevens/DidierStevensSuite` | PDF et OLE | P1 | -| Poppler tools | Projet Poppler | PDF, texte et images | P0 | -| qpdf | `qpdf/qpdf` | Structure PDF | P0 | -| Tesseract OCR | `tesseract-ocr/tesseract` | OCR local | P0 | -| ImageMagick | `ImageMagick/ImageMagick` | Inspection de copies | P1 | -| OpenCV | `opencv/opencv` | Comparaison d’images | P2 | -| ImageHash | `JohannesBuchner/imagehash` | Empreintes perceptuelles | P1 | -| pHash | Projet pHash | Empreintes perceptuelles | P2 | -| file/libmagic | Paquet système | Identification de format | P0 | -| strings/binutils | Paquet système | Chaînes de caractères | P1 | -| MAT2 | `jvoisin/mat2` | Métadonnées sur copies | P2 | -| yt-dlp | `yt-dlp/yt-dlp` | Conservation de médias publics | P0 | -| gallery-dl | `mikf/gallery-dl` | Galeries publiques | P1 | -| InVID-WeVerify | Extension/service | Vérification manuelle | Manuel | -| face_recognition | `ageitgey/face_recognition` | Comparaison locale | Restreint | -| DeepFace | `serengil/deepface` | Comparaison locale | Restreint | -| InsightFace | `deepinsight/insightface` | Analyse faciale | Restreint | - -Aucune recherche biométrique massive ne doit être intégrée. - -## G. Dépôts publics et code - -| Outil | Usage | Priorité | -|---|---|---| -| GitFive | Corrélation GitHub | P1 | -| GitHub CLI | API et données publiques | P0 | -| TruffleHog | Dépôts publics autorisés | Revue | -| Gitleaks | Secrets publiés | Revue | -| ggshield | Dépôts autorisés | Revue | -| ripgrep | Recherche locale | P0 | -| git-sizer | Structure de dépôt | P2 | -| Git natif | Historique, auteurs et dates | P0 | - -Un secret découvert ne doit jamais être utilisé pour accéder à un compte. - -## H. Réputation et APIs - -| Outil/client | Usage | Priorité | -|---|---|---| -| vt-cli | VirusTotal | API | -| OTX Python SDK | AlienVault OTX | API | -| urlscan-go | URLScan | API | -| Shodan Python | Shodan | API | -| Censys Python | Censys | API | -| pyGreynoise | GreyNoise | API | -| PyMISP | MISP | P2 | -| OpenCTI client | OpenCTI | P2 | -| YARA | Classement local | P2 | -| capa | Analyse locale | Backlog | - -Toute donnée envoyée à un tiers doit être affichée avant l’appel. - -## I. Corrélation et graphes - -| Outil | Usage | Priorité | -|---|---|---| -| NetworkX | Algorithmes de graphe | P1 | -| igraph | Graphes performants | P2 | -| Graphviz | Rendu | P0 | -| Gephi | Analyse visuelle externe | Export | -| Cytoscape | Analyse visuelle externe | Export | -| OpenCTI | Référence de modèle | Référence | -| MISP | Référence d’indicateurs | Référence | -| Aleph | Recherche documentaire et entités | P1 | -| OpenSanctions | Entités et sanctions publiques | P1 | -| FollowTheMoney | Modèle de relations | P1 | -| Neo4j Community | Base graphe externe | P3 | -| OSINTBuddy | Graphe d’enquête | Surveillance | - -Labfy conserve son propre modèle de données. - -## J. Géolocalisation - -| Outil | Usage | Priorité | -|---|---|---| -| geopy | Géocodage configurable | P2 | -| Nominatim | Géocodage OpenStreetMap | P1 | -| OSMnx | Réseaux géographiques | P3 | -| Overpass API | Données OpenStreetMap | P2 | -| QGIS | Analyse externe | Export | -| SunCalc | Position du soleil | P2 | -| Skyfield | Calculs astronomiques | P3 | -| ExifTool | Coordonnées de médias | P0 | - -## K. IBAN, entreprises et cryptomonnaies - -| Outil | Usage | Priorité | -|---|---|---| -| python-stdnum | Validation IBAN et identifiants | P0 | -| iban4j | Validation IBAN | P3 | -| OpenSanctions | Personnes et organisations | P1 | -| FollowTheMoney | Relations structurées | P1 | -| bitcoin-etl | Données publiques Bitcoin | P2 | -| ethereum-etl | Données publiques Ethereum | P2 | -| GraphSense | Analyse de blockchains | P2 | -| BlockSci | Analyse locale | Surveillance | -| mempool | Explorateur Bitcoin open source | P2 | -| Bitcoin Core | Nœud local | P3 | -| Geth | Nœud Ethereum local | P3 | - -Un IBAN ne permet pas d’identifier publiquement son titulaire. Labfy se limite à la validation, au pays, à la banque lorsqu’elle est publique et aux corrélations entre dossiers. - ---- - -# Outils exclus du mode OSINT standard - -```text -nmap -masscan -naabu -nuclei -gobuster -ffuf -dirsearch -sqlmap -hydra -metasploit -Sn1per -Nikto -WPScan -scanners actifs Burp -outils d’exploitation -outils de credential stuffing -outils de phishing -``` - -Décision initiale : - -```text -integration_mode = REJECTED -decision = REJECT -``` - ---- - -# Vague prioritaire pour l’affaire d’escroquerie - -## P0 - -```text -Sherlock -Maigret -WhatsMyName -Holehe -PhoneInfoga -libphonenumber -GitHub CLI -ExifTool -MediaInfo -ffprobe -Tesseract OCR -Poppler tools -qpdf -oletools -file/libmagic -yt-dlp -waybackurls -gau -ArchiveBox -Browsertrix Crawler -ArchiveWeb.page -warcio -SingleFile -theHarvester -Subfinder -dnstwist -python-stdnum -Graphviz -``` - -## P1 - -```text -Blackbird -GHunt -GitFive -h8mail avec sources licites uniquement -gallery-dl -SpiderFoot -Amass -dnsx -URLCrazy -OpenSanctions -FollowTheMoney -Aleph -NetworkX -ImageHash -VirusTotal CLI -urlscan -``` - ---- - -# Audit obligatoire par outil - -1. données envoyées sur Internet ; -2. domaines et API contactés ; -3. compte, cookie ou jeton requis ; -4. compatibilité avec les CGU ; -5. volume de requêtes ; -6. accès strictement public ; -7. capacité de modifier une ressource distante ; -8. risque de faux positif ; -9. précision des sources ; -10. sortie brute conservable ; -11. reproductibilité ; -12. commande de version ; -13. licence et redistribution ; -14. installation Ubuntu ; -15. dépendances ; -16. coût ou API obligatoire ; -17. activité du projet ; -18. vulnérabilités connues ; -19. télémétrie ; -20. scripts d’installation distants. - -Aucun `curl | sh`, `wget | bash`, `sudo pip install` ou `sudo npm install -g` ne doit être exécuté sans audit. - ---- - -# Modèle de sécurité d’intégration - -```text -arguments séparés -aucun shell -utilisateur non privilégié -dossier temporaire -environnement minimal -timeout -limites stdout/stderr -annulation -journal -empreinte du binaire -version -domaines contactés -sortie brute UTC -SHA-256 -``` - ---- - -# Valeur probatoire - -Labfy doit distinguer : - -```text -résultat de l’outil -source publique -copie locale -interprétation -corrélation -hypothèse -``` - -Chaque exécution doit conserver : - -```text -outil -version -commande -arguments -date UTC -source -URL -sortie brute -capture -archive -SHA-256 -statut HTTP -notes -niveau de confiance -``` - -Un résultat Sherlock, Maigret, Holehe ou PhoneInfoga ne prouve jamais une identité à lui seul. - ---- - -# Phases - -## Phase 1 - -Créer le JSON, le CSV et le schéma. - -## Phase 2 - -Auditer toute la liste P0. - -## Phase 3 - -Auditer la liste P1. - -## Phase 4 - -Attribuer note, priorité, mode d’intégration, statut juridique et décision. - -## Phase 5 - -Produire le rapport des outils retenus, manuels, surveillés et rejetés. - -## Phase 6 - -Validation humaine avant tout passage à `INTEGRATE`. - ---- - -# Contrôles automatisés futurs - -- identifiants uniques ; -- noms non vides ; -- dépôt renseigné ; -- licence vérifiée pour tout outil approuvé ; -- décision renseignée ; -- aucune priorité P0 pour un outil rejeté ; -- aucun outil actif marqué passif ; -- JSON valide ; -- CSV généré depuis le JSON ; -- aucune clé API ; -- aucun secret ; -- aucune donnée issue d’une enquête réelle. - ---- - -# Critères d’acceptation - -- au moins 80 outils ou composants recensés ; -- toutes les catégories couvertes ; -- tous les P0 audités ; -- licences P0 vérifiées ; -- installation Ubuntu P0 documentée ; -- qualification juridique P0 ; -- commande de version P0 ; -- séparation claire passif/actif/intrusif ; -- aucun outil rejeté proposé à l’utilisateur ; -- inventaire Markdown, JSON et CSV ; -- décisions justifiées ; -- feuille de route d’intégration ; -- document présentable à des enquêteurs. - ---- - -# Suite prévue - -```text -#041 — Initialisation asynchrone des dépendances -#042 — Adaptateurs pseudonymes -#043 — Adaptateurs e-mail -#044 — Adaptateurs téléphone -#045 — Documents et métadonnées -#046 — Archivage probatoire du Web -#047 — Domaines et infrastructures passives -#048 — Graphe de corrélation -``` -