labfy-investigation/docs/database/DATABASE_ARCHITECTURE.md
2026-07-23 14:17:23 +02:00

53 KiB

Architecture de la base de données

Statut : Stable (V1)

Ce document décrit l'architecture de référence de la base de données de Labfy Investigation.

Toute évolution incompatible devra faire l'objet d'une nouvelle version du schéma et d'une migration documentée.

Version

Schéma : V1


1. Introduction

1.1 Objectif

La base de données de Labfy Investigation constitue le cœur du modèle métier de l'application.

Chaque enquête possède sa propre base SQLite, indépendante des autres enquêtes.

Cette base centralise toutes les informations produites ou découvertes pendant une investigation :

  • les sources consultées ;
  • les recherches réalisées ;
  • les preuves collectées ;
  • les entités identifiées ;
  • les relations établies ;
  • les hypothèses formulées ;
  • la chronologie de l'enquête ;
  • le journal d'audit de l'application ;
  • les catégories et les tags.

L'objectif de cette architecture est de fournir un modèle de données robuste, cohérent et facilement extensible, tout en restant suffisamment simple pour être compris et maintenu sur le long terme.

Cette documentation décrit les choix d'architecture retenus pour la première version du schéma de la base de données.

Elle constitue le document de référence pour le développement de la couche Database de Labfy Investigation.


1.2 Philosophie

La conception de cette base de données repose sur plusieurs principes.

Le premier est la séparation des responsabilités.

Chaque table représente un concept métier unique et clairement identifié.

Par exemple :

  • une preuve représente un élément collecté ;
  • une entité représente un objet identifié ;
  • une relation représente un lien entre deux entités ;
  • une hypothèse représente un raisonnement de l'enquêteur.

Aucune table ne doit mélanger plusieurs responsabilités.

Le deuxième principe est la traçabilité.

Toute information importante doit pouvoir être reliée à son origine.

Il doit toujours être possible d'expliquer :

  • d'où provient une information ;
  • quelle recherche l'a produite ;
  • quelles preuves la soutiennent ;
  • quelles relations en découlent ;
  • quelles hypothèses en résultent.

Le troisième principe est l'évolutivité.

Le schéma doit pouvoir évoluer sans remettre en cause les données existantes.

Les nouvelles fonctionnalités devront privilégier l'ajout de nouvelles tables ou de nouvelles relations plutôt que la modification des structures déjà publiées.

Enfin, le schéma privilégie la lisibilité plutôt que la recherche d'une optimisation prématurée.

La compréhension du modèle par les développeurs constitue une priorité.


1.3 Une base par enquête

Chaque enquête est totalement autonome.

Lors de la création d'une nouvelle enquête, Labfy Investigation génère une base SQLite dédiée :

00_BaseDeDonnees/
└── Enquete.sqlite

Toutes les informations propres à cette enquête sont enregistrées dans cette base.

Aucune information métier n'est partagée entre plusieurs enquêtes.

Cette organisation présente plusieurs avantages :

  • chaque enquête est portable ;
  • les sauvegardes sont simplifiées ;
  • l'export d'une enquête est immédiat ;
  • les risques de corruption croisée sont limités ;
  • plusieurs enquêtes peuvent être ouvertes indépendamment.

La base SQLite ne contient jamais les fichiers originaux.

Les preuves (captures d'écran, photographies, vidéos, documents, archives, etc.) restent stockées dans l'arborescence de l'enquête.

La base conserve uniquement les métadonnées nécessaires à leur exploitation.

Cette séparation permet de préserver l'intégrité des fichiers originaux tout en offrant un accès rapide aux informations nécessaires aux traitements réalisés par l'application.


2. Principes généraux

Cette section décrit les conventions utilisées dans toute la couche Database.

Ces règles doivent rester cohérentes dans l'ensemble du projet afin de garantir la lisibilité du code, la stabilité du schéma et la pérennité des données.


2.1 UUID

Tous les objets métier utilisent un identifiant unique universel (UUID) comme clé primaire.

Exemple :

id TEXT PRIMARY KEY

Les UUID sont générés par l'application lors de la création des objets.

Cette approche présente plusieurs avantages :

  • unicité garantie entre plusieurs enquêtes ;
  • simplicité des imports et exports ;
  • possibilité de fusionner plusieurs bases de données ;
  • indépendance vis-à-vis des identifiants internes SQLite.

Les tables de référence utilisent en revanche des identifiants entiers statiques.

Exemples :

  • types_preuve
  • types_entite
  • types_source
  • types_outil

Ces identifiants sont contrôlés par l'application et ne sont pas destinés à être modifiés par les utilisateurs.


2.2 Dates UTC

Toutes les dates enregistrées dans la base utilisent le temps universel (UTC).

Le format retenu est :

YYYY-MM-DDTHH:MM:SSZ

Exemple :

2026-07-15T18:42:10Z

L'utilisation de l'UTC évite les problèmes liés :

  • aux fuseaux horaires ;
  • aux changements d'heure ;
  • aux déplacements géographiques ;
  • aux échanges de bases entre plusieurs machines.

La conversion vers l'heure locale est réalisée uniquement lors de l'affichage dans l'interface utilisateur.


2.3 Suppression logique

Les objets métier ne sont généralement pas supprimés physiquement.

Ils utilisent une suppression logique basée sur la colonne :

status

Les valeurs autorisées dépendent de la table concernée mais utilisent principalement :

active
archived
deleted

Cette approche permet :

  • de préserver l'historique de l'enquête ;
  • d'éviter les suppressions accidentelles ;
  • de conserver la cohérence des relations entre objets ;
  • de restaurer un objet si nécessaire.

Une suppression physique ne doit intervenir que dans le cadre d'opérations d'administration ou de maintenance spécifiques.


2.4 Intégrité référentielle

Les clés étrangères sont activées systématiquement lors de l'ouverture de la base.

PRAGMA foreign_keys = ON;

Toutes les relations entre objets sont protégées par des contraintes d'intégrité.

Selon le contexte, les suppressions utilisent :

  • CASCADE ;
  • RESTRICT ;
  • SET NULL.

Le choix dépend du rôle métier de la relation et non d'une règle unique.


2.5 Transactions

Toutes les opérations critiques sont exécutées dans une transaction SQLite.

La création d'une enquête constitue une transaction unique comprenant :

  • l'installation du schéma ;
  • l'enregistrement des métadonnées ;
  • la création de l'enquête.

En cas d'échec d'une étape, l'ensemble de la transaction est annulé.

Cette stratégie garantit qu'une enquête ne peut jamais être créée dans un état partiellement initialisé.


2.6 Requêtes préparées

Toutes les requêtes contenant des données variables utilisent des requêtes préparées SQLite.

Exemple :

sqlite3_prepare_v2(...)
sqlite3_bind_text(...)
sqlite3_step(...)

La concaténation de chaînes SQL contenant des données utilisateur est interdite.

Cette règle permet :

  • d'éviter les injections SQL ;
  • d'améliorer les performances ;
  • de simplifier la gestion des erreurs.

Les requêtes SQL statiques peuvent être exécutées avec sqlite3_exec().


2.7 Séparation des responsabilités

Le schéma suit une séparation stricte des responsabilités.

Chaque table représente un unique concept métier.

Les relations entre concepts sont modélisées à l'aide de tables de liaison explicites plutôt que par des structures ambiguës ou des colonnes multifonctions.

Cette approche facilite :

  • la maintenance ;
  • les évolutions futures ;
  • les tests unitaires ;
  • la compréhension du modèle.

2.8 Couche Database

L'accès à la base de données est centralisé dans le module database.

Aucun autre composant de l'application ne doit exécuter directement de requêtes SQL.

Toutes les opérations passent par des fonctions dédiées de la couche Database.

Cette règle garantit :

  • une architecture modulaire ;
  • une gestion uniforme des erreurs ;
  • une meilleure testabilité ;
  • une évolution simplifiée du schéma de la base.

3. Vue d'ensemble

Ce chapitre présente l'organisation générale de la base de données.

Le schéma de Labfy Investigation n'a pas été conçu comme un simple ensemble de tables indépendantes.

Chaque objet métier représente une étape du processus d'investigation.

L'ensemble forme un modèle cohérent permettant de suivre le cycle complet d'une enquête, depuis la collecte initiale jusqu'à la formulation d'hypothèses.


3.1 Organisation générale

Le modèle est organisé autour de plusieurs domaines fonctionnels.

Chaque domaine possède une responsabilité clairement définie.

Métadonnées
Référentiels
Collecte
Connaissance
Raisonnement
Traçabilité
Classification

Cette séparation facilite :

  • la compréhension du modèle ;
  • la maintenance du code ;
  • les évolutions futures ;
  • les tests unitaires.

3.2 Domaines fonctionnels

Métadonnées

Les métadonnées décrivent la base de données elle-même.

Elles permettent notamment de connaître :

  • la version du schéma ;
  • l'application ayant créé la base ;
  • la date de création ;
  • l'identifiant de l'enquête.

Tables :

metadata
investigation

Référentiels

Les référentiels regroupent les listes de valeurs stables utilisées dans le reste de la base.

Ils évitent la duplication de chaînes de caractères et garantissent une classification cohérente.

Tables :

types_preuve
types_entite
types_source
types_outil

Collecte

La collecte représente toutes les actions réalisées pour obtenir de nouvelles informations.

Elle comprend :

  • les sources consultées ;
  • les recherches effectuées ;
  • les preuves collectées.

Tables :

sources
recherches
preuves

Connaissance

Les preuves permettent d'identifier des objets réels.

Ces objets deviennent des entités.

Les relations établissent ensuite les liens entre ces entités.

Tables :

entites
relations

Raisonnement

Les hypothèses représentent les conclusions provisoires formulées pendant l'enquête.

Elles s'appuient sur :

  • les preuves ;
  • les recherches ;
  • les relations ;
  • les entités.

Table :

hypotheses

Traçabilité

Deux mécanismes distincts assurent la traçabilité.

La chronologie décrit les événements de l'enquête.

Le journal décrit les actions réalisées dans l'application.

Tables :

chronologie
journal

Classification

La classification facilite l'organisation des informations.

Les catégories structurent les objets.

Les tags permettent une annotation libre.

Tables :

categories
tags

3.3 Flux d'investigation

Le déroulement d'une enquête peut être représenté de manière simplifiée par le schéma suivant :

Source
   │
   ▼
Recherche
   │
   ▼
Preuve
   │
   ▼
Entité
   │
   ▼
Relation
   │
   ▼
Hypothèse

Ce schéma représente uniquement le cheminement principal.

En pratique, une enquête est beaucoup plus dynamique.

Une recherche peut :

  • produire plusieurs preuves ;
  • confirmer une preuve existante ;
  • découvrir plusieurs entités ;
  • modifier une relation ;
  • renforcer ou contredire une hypothèse.

De même :

  • une preuve peut être utilisée dans plusieurs recherches ;
  • une entité peut apparaître dans plusieurs preuves ;
  • une relation peut être soutenue par plusieurs preuves ;
  • une hypothèse peut évoluer tout au long de l'enquête.

Le modèle de données repose donc sur un réseau d'objets reliés entre eux, plutôt que sur une chaîne linéaire.

Les nombreuses tables de liaison présentes dans le schéma permettent de représenter cette richesse tout en conservant un modèle relationnel simple et cohérent.


4. Tables métier

Les tables métier représentent les objets manipulés quotidiennement par l'application.

Contrairement aux tables de référence, elles contiennent les données propres à chaque enquête.

Chaque table possède une responsabilité unique.

Les relations entre ces objets sont assurées par des clés étrangères ou par des tables de liaison dédiées.


4.1 metadata

Responsabilité

La table metadata stocke les informations techniques concernant la base de données.

Elle permet notamment d'identifier :

  • la version du schéma ;
  • la version de l'application ayant créé la base ;
  • les informations nécessaires aux futures migrations.

Cette table ne contient aucune donnée liée à l'enquête elle-même.

Identifiant

La table repose sur des clés textuelles (key / value) et non sur un UUID.

Relations principales

Aucune.

Cycle de vie

Les métadonnées sont créées lors de l'initialisation de la base puis modifiées uniquement lors des migrations ou des mises à jour du schéma.

Points d'attention

Cette table est utilisée pour déterminer la compatibilité entre la base de données et l'application.


4.2 investigation

Responsabilité

La table investigation décrit l'enquête elle-même.

Elle contient les informations générales nécessaires à son identification.

Une base de données ne contient qu'une seule enquête.

Identifiant

UUID.

Relations principales

L'enquête constitue la racine logique de l'ensemble des objets métier.

Les autres tables appartiennent implicitement à cette enquête.

Cycle de vie

Créée automatiquement lors de l'initialisation de la base.

Elle est ensuite très rarement modifiée.

Points d'attention

Aucune seconde enquête ne doit être créée dans la même base SQLite.


4.3 sources

Responsabilité

Une source représente l'origine d'une information.

Une source peut être :

  • un site web ;
  • un réseau social ;
  • une API ;
  • un document ;
  • une base publique ;
  • une personne interrogée.

Identifiant

UUID.

Relations principales

Une source peut être utilisée par plusieurs recherches.

Cycle de vie

Une source peut être enrichie au cours de l'enquête sans perdre son identité.

Points d'attention

Une source ne constitue jamais une preuve.

Elle décrit uniquement l'origine de l'information.


4.4 recherches

Responsabilité

Une recherche représente une action réalisée par l'enquêteur.

Exemples :

  • requête WHOIS ;
  • recherche Google ;
  • interrogation d'une API ;
  • analyse d'un document ;
  • recherche DNS.

Identifiant

UUID.

Relations principales

Une recherche peut :

  • utiliser une source ;
  • produire plusieurs preuves ;
  • identifier des entités ;
  • confirmer une relation ;
  • enrichir une hypothèse ;
  • générer des événements de chronologie.

Cycle de vie

Une recherche est créée lorsqu'une action d'investigation est réalisée.

Elle peut être enrichie ultérieurement.

Points d'attention

Une recherche décrit une action, pas son résultat.

Les résultats sont représentés par d'autres objets.


4.5 preuves

Responsabilité

Une preuve représente un élément collecté pendant l'enquête.

Exemples :

  • capture d'écran ;
  • photographie ;
  • document ;
  • vidéo ;
  • archive ;
  • export JSON.

Identifiant

UUID.

Relations principales

Une preuve peut :

  • provenir de plusieurs recherches ;
  • contenir plusieurs entités ;
  • soutenir plusieurs relations ;
  • soutenir plusieurs hypothèses.

Cycle de vie

Les preuves originales sont conservées.

Les traitements réalisés sur une preuve créent de nouvelles informations mais ne modifient pas le fichier original.

Points d'attention

L'intégrité de la preuve est essentielle.

Les métadonnées permettent notamment de suivre les empreintes cryptographiques.

L'import groupé conserve ce modèle : chaque fichier sélectionné est révisé et importé séparément. Les imports sont exécutés séquentiellement afin d'éviter les écritures SQLite concurrentes. L'échec d'un fichier n'annule pas les preuves déjà importées et apparaît dans le bilan final.

Le classement, la source et la description peuvent être corrigés après l'import. Un changement de type déplace la copie interne vers le dossier adapté dans la même opération logique que la mise à jour SQLite. L'empreinte et la taille sont vérifiées avant et après ; un échec annule la transaction et restaure le chemin initial. L'UUID, le nom interne et la date d'import restent inchangés.


4.6 entites

Responsabilité

Une entité représente un objet identifié.

Exemples :

  • personne ;
  • entreprise ;
  • adresse IP ;
  • adresse email ;
  • nom de domaine ;
  • numéro de téléphone.

Identifiant

UUID.

Relations principales

Les entités peuvent être reliées entre elles par des relations.

Elles peuvent également apparaître dans plusieurs preuves.

Cycle de vie

Une entité peut être enrichie au fur et à mesure de l'enquête.

Points d'attention

Une entité doit représenter un objet unique.

Les doublons doivent être évités.


4.7 relations

Responsabilité

Une relation représente un lien entre deux entités.

Elle permet de formaliser les connaissances acquises.

Identifiant

UUID.

Relations principales

Une relation relie :

  • une entité source ;
  • une entité cible.

Elle peut être soutenue ou contredite par plusieurs preuves.

Cycle de vie

Une relation peut évoluer avec l'arrivée de nouvelles preuves.

Points d'attention

Une relation n'est jamais une hypothèse.

Elle décrit un lien observé.


4.8 chronologie

Responsabilité

La chronologie raconte les événements importants de l'enquête.

Elle permet de reconstruire le déroulement des investigations.

Identifiant

UUID.

Relations principales

Une entrée peut être liée à plusieurs objets métier.

Cycle de vie

Les événements peuvent être créés automatiquement ou manuellement.

Points d'attention

La chronologie décrit l'enquête, pas le fonctionnement interne de l'application.


4.9 journal

Responsabilité

Le journal constitue la trace d'audit des opérations réalisées par l'application.

Identifiant

UUID.

Relations principales

Les références vers les objets utilisent le couple :

  • objet_type ;
  • objet_id.

Cycle de vie

Les entrées sont ajoutées chronologiquement.

Points d'attention

Le journal est conçu selon un modèle append-only.

Les entrées existantes ne doivent pas être modifiées dans le fonctionnement normal.


4.10 hypotheses

Responsabilité

Une hypothèse représente un raisonnement de l'enquêteur.

Elle peut être soutenue, contredite ou confirmée.

Identifiant

UUID.

Relations principales

Une hypothèse peut être liée :

  • aux preuves ;
  • aux entités ;
  • aux relations ;
  • aux recherches.

Cycle de vie

Une hypothèse évolue au cours de l'enquête.

Son niveau de confiance peut être réévalué.

Points d'attention

Une hypothèse ne constitue pas un fait.

Elle représente une conclusion provisoire.


4.11 categories

Responsabilité

Les catégories permettent de classer les objets métier dans un domaine fonctionnel.

Identifiant

UUID.

Relations principales

Une catégorie peut être associée à plusieurs objets.

Chaque objet ne possède qu'une seule catégorie.

Cycle de vie

Les catégories évoluent peu.

Points d'attention

Les catégories structurent les données.

Elles ne remplacent pas les tags.


4.12 tags

Responsabilité

Les tags permettent d'annoter librement les objets métier.

Identifiant

UUID.

Relations principales

Les tags peuvent être associés à plusieurs types d'objets via des tables de liaison.

Cycle de vie

Les utilisateurs peuvent créer ou supprimer leurs propres tags.

Points d'attention

Les tags complètent la classification mais ne modifient pas la structure du modèle métier.


5. Tables de référence

Les tables de référence regroupent les listes de valeurs stables utilisées dans l'ensemble de la base de données.

Contrairement aux tables métier, leur contenu évolue peu.

Leur objectif est de normaliser les données et d'éviter la duplication de chaînes de caractères dans plusieurs tables.

Les objets métier référencent ces tables au moyen d'identifiants entiers.

Cette approche présente plusieurs avantages :

  • cohérence des valeurs utilisées ;
  • réduction des risques de fautes de frappe ;
  • simplification des contrôles d'intégrité ;
  • meilleure lisibilité des données ;
  • évolutions facilitées.

Les tables de référence ne sont pas destinées à contenir des informations propres à une enquête.

Elles décrivent uniquement des classifications communes à toutes les investigations.


5.1 types_preuve

Cette table décrit les différents types de preuves pouvant être enregistrés.

Exemples :

  • capture d'écran ;
  • photographie ;
  • document ;
  • archive ;
  • vidéo ;
  • export JSON.

Les preuves référencent cette table afin d'identifier leur nature.


5.2 types_entite

Cette table définit les différents types d'entités manipulés par l'application.

Exemples :

  • personne ;
  • organisation ;
  • adresse IP ;
  • nom de domaine ;
  • adresse email ;
  • numéro de téléphone ;
  • compte de réseau social.

Chaque entité appartient à un type unique.


5.3 types_source

Cette table décrit les catégories de sources utilisées pendant une enquête.

Exemples :

  • site web ;
  • moteur de recherche ;
  • réseau social ;
  • API ;
  • document ;
  • base publique.

Les recherches utilisent ces informations pour caractériser leurs sources.


5.4 types_outil

Cette table répertorie les outils utilisés pendant les recherches.

Exemples :

  • navigateur web ;
  • dig ;
  • whois ;
  • curl ;
  • nmap ;
  • outil interne de Labfy Investigation.

Cette classification permet de documenter précisément les méthodes employées lors de la collecte d'informations.


Gestion des identifiants

Contrairement aux objets métier, les tables de référence utilisent des identifiants entiers.

Ces identifiants sont définis par l'application.

Ils sont stables et ne doivent pas être modifiés manuellement.

Leur objectif est uniquement de faciliter les références entre les tables.

Ils ne constituent pas des identifiants métier.


Évolutions

L'ajout d'un nouveau type ne nécessite généralement aucune modification du schéma de la base de données.

Il suffit d'ajouter une nouvelle ligne dans la table concernée.

En revanche, la suppression ou la modification d'un type existant doit être réalisée avec précaution afin de préserver la cohérence des données déjà enregistrées.

Traçabilité OSINT structurée — schéma V3

La table osint_executions conserve chaque exécution terminée, y compris lorsque la révision est annulée. Elle contient notamment :

  • l'outil et sa version ;
  • la cible et les arguments de l'exécution ;
  • la date d'exécution ;
  • les sorties standard et d'erreur sous forme de BLOB ;
  • leur empreinte SHA-256.

Les tables osint_execution_entities et osint_execution_relations relient l'exécution aux objets intégrés. Le champ disposition distingue les objets créés des objets réutilisés. Ces liaisons sont ajoutées dans la même transaction que l'intégration DNS.

Les descriptions métier restent présentes pour la lisibilité, mais les entités DNS demeurent des résultats OSINT à vérifier et non des faits établis.

Le menu contextuel du workspace permet de consulter cet historique pour l'entité ou la relation sélectionnée. La vue est strictement en lecture seule et expose les métadonnées, les sorties brutes rendues en UTF-8, l'empreinte et les objets liés avec leur disposition created ou reused.

Depuis ce détail, une vérification explicite recalcule l'empreinte SHA-256 à partir des BLOB stdout_raw et stderr_raw, séparés par l'octet nul défini lors de l'enregistrement. Le résultat indique si les sorties sont intactes, altérées ou impossibles à vérifier. Ce contrôle est strictement en lecture seule : aucune sortie ni empreinte persistée n'est corrigée automatiquement.

Comptes sociaux structurés — schéma V4

La table comptes_sociaux complète une ligne de entites sans dupliquer le nœud affiché dans le graphe. Elle conserve la plateforme, l'URL de profil, le pseudonyme affiché, l'identifiant stable facultatif, la première observation, l'état observé et les notes factuelles. La contrainte unique sur (plateforme, url_profil) évite les doublons.

Une capture, une vidéo ou un courriel déjà importé peut être rattaché au compte via preuve_entites. La création des deux lignes et de cette liaison est transactionnelle : aucun nœud incomplet n'est conservé si une étape échoue.

Rôles d'enquête des personnes — schémas V5 et V6

La table person_roles associe une entité de type personne à une catégorie d'enquête contrôlée : scammer présumé, victime, témoin, suspect, personne liée, identité usurpée ou non catégorisée. La clé étrangère avec suppression en cascade évite les rôles orphelins. Le code stable est persisté ; le libellé et la couleur restent des choix de présentation.

Une personne sans ligne dans cette table est toujours interprétée comme non catégorisée, ce qui garantit la compatibilité avec les enquêtes antérieures.


6. Tables de liaison

Le modèle de données de Labfy Investigation repose largement sur des relations de type plusieurs-à-plusieurs.

Plutôt que de multiplier les colonnes ou de stocker plusieurs valeurs dans un même champ, chaque relation complexe est représentée par une table de liaison dédiée.

Cette approche permet :

  • de conserver un schéma normalisé ;
  • d'éviter les redondances ;
  • de garantir l'intégrité référentielle ;
  • d'ajouter des informations propres à une relation lorsque cela est nécessaire (par exemple une colonne role) ;
  • de faire évoluer le modèle sans modifier les tables métier.

Toutes les tables de liaison utilisent une clé primaire composite afin d'empêcher les doublons.


6.1 Liaisons des recherches

Les recherches constituent le point d'entrée de nombreuses informations.

Une même recherche peut produire plusieurs objets métier.

Inversement, un objet métier peut résulter de plusieurs recherches.

Les tables suivantes modélisent ces relations :

recherche_preuves
recherche_entites
recherche_relations
recherche_hypotheses

Ces tables permettent notamment de répondre aux questions suivantes :

  • quelles preuves ont été produites par cette recherche ?
  • quelles recherches ont conduit à cette preuve ?
  • quelles recherches ont confirmé cette relation ?
  • quelle recherche est à l'origine d'une hypothèse ?

6.2 Liaisons des preuves

Les preuves constituent le socle de l'enquête.

Elles peuvent révéler plusieurs entités.

Inversement, une même entité peut apparaître dans plusieurs preuves.

Les relations suivantes assurent cette représentation :

preuve_entites
relation_preuves

Ces tables permettent notamment de déterminer :

  • quelles entités apparaissent dans une preuve ;
  • quelles preuves soutiennent une relation.

6.3 Liaisons de la chronologie

La chronologie décrit les événements importants de l'enquête.

Un même événement peut être associé à plusieurs objets métier.

Les tables suivantes assurent ces liens :

recherche_chronologie
preuve_chronologie
entite_chronologie
relation_chronologie

Cette architecture permet d'enrichir la chronologie sans modifier les tables métier.


6.4 Liaisons des hypothèses

Les hypothèses constituent le niveau de raisonnement de l'enquête.

Elles peuvent être :

  • soutenues ;
  • contredites ;
  • confirmées ;

par différents objets.

Les tables suivantes représentent ces relations :

hypothese_preuves
hypothese_entites
hypothese_relations

Certaines de ces tables utilisent une colonne :

role

Cette colonne précise le rôle joué par l'objet dans l'hypothèse.

Exemples :

supports
contradicts
confirms

Cette approche offre une grande souplesse tout en conservant un schéma relationnel simple.


6.5 Liaisons des tags

Les tags sont des annotations transversales.

Ils peuvent être associés à plusieurs types d'objets métier.

Les tables de liaison sont :

tag_preuves
tag_recherches
tag_entites
tag_relations
tag_hypotheses
tag_chronologie

Chaque table assure une relation plusieurs-à-plusieurs entre les tags et les objets concernés.

Cette organisation permet de conserver une architecture claire sans ajouter de colonnes spécifiques dans chaque table métier.


Clés primaires composites

Toutes les tables de liaison utilisent une clé primaire composite.

Exemple :

PRIMARY KEY (
    recherche_id,
    preuve_id
)

Cette contrainte garantit qu'une même relation ne peut être enregistrée qu'une seule fois.

Elle évite les doublons sans nécessiter d'identifiant supplémentaire.


Clés étrangères

Les tables de liaison utilisent systématiquement des clés étrangères.

Le comportement associé (CASCADE, RESTRICT ou SET NULL) est choisi en fonction de la signification métier de la relation.

L'objectif est de préserver la cohérence des données tout en limitant les suppressions accidentelles.


Évolutivité

Les tables de liaison constituent l'un des principaux mécanismes d'extension du modèle.

Lorsqu'une nouvelle relation apparaît entre deux objets métier, il est généralement préférable d'ajouter une nouvelle table de liaison plutôt que de modifier les tables existantes.

Cette stratégie limite les impacts sur le reste du schéma et facilite les évolutions futures.


7. Contraintes

La qualité des données repose en grande partie sur les contraintes définies dans le schéma SQL.

Ces contraintes permettent de détecter les incohérences le plus tôt possible, avant même que les données ne soient utilisées par l'application.

Les contraintes SQL ne remplacent pas les validations réalisées dans le code C.

Les deux mécanismes sont complémentaires :

  • SQLite garantit l'intégrité de la base de données ;
  • l'application garantit la cohérence métier.

7.1 Clés primaires

Chaque objet métier possède une clé primaire.

Les objets métier utilisent un UUID :

id TEXT PRIMARY KEY

Les tables de référence utilisent des identifiants entiers.

Les tables de liaison utilisent des clés primaires composites.

Exemple :

PRIMARY KEY (
    preuve_id,
    entite_id
)

Cette approche garantit :

  • l'unicité des objets ;
  • l'absence de doublons dans les relations ;
  • une meilleure portabilité des données.

7.2 Clés étrangères

Les relations entre objets sont protégées par des clés étrangères.

SQLite vérifie automatiquement que les objets référencés existent.

Le comportement lors de la suppression dépend du contexte métier.

Les principales stratégies utilisées sont :

CASCADE

La suppression de l'objet parent entraîne automatiquement la suppression des relations associées.

Cette stratégie est principalement utilisée dans les tables de liaison.


RESTRICT

La suppression est refusée tant que l'objet est encore utilisé.

Cette stratégie protège les données importantes.


SET NULL

La relation est conservée mais devient facultative.

Cette approche est utilisée lorsque l'information reste pertinente même si l'objet référencé disparaît.


7.3 Contraintes CHECK

Les contraintes CHECK assurent la validité élémentaire des données.

Exemples :

  • chaînes non vides ;
  • valeurs comprises dans une plage ;
  • états autorisés ;
  • cohérence entre plusieurs colonnes.

Exemple :

CHECK (
    confiance BETWEEN 0 AND 100
)

Ou :

CHECK (
    status IN (
        'active',
        'archived',
        'deleted'
    )
)

Ces contraintes empêchent l'enregistrement de valeurs incohérentes.


7.4 Contraintes UNIQUE

Certaines informations doivent rester uniques.

Les contraintes UNIQUE permettent d'empêcher les doublons.

Exemples :

  • nom d'une catégorie ;
  • nom d'un tag ;
  • autres identifiants définis comme uniques.

Lorsque cela est pertinent, la comparaison est réalisée sans tenir compte de la casse (COLLATE NOCASE).


7.5 Validation applicative

Toutes les validations ne peuvent pas être exprimées uniquement en SQL.

Certaines règles restent du ressort de l'application.

Exemples :

  • validité d'un UUID ;
  • format d'une adresse email ;
  • validité d'un IBAN ;
  • calcul des empreintes cryptographiques ;
  • contrôle de la taille des fichiers ;
  • vérification du contenu d'une archive.

Le code C complète donc les protections offertes par SQLite.


7.6 Intégrité métier

Certaines règles concernent le fonctionnement même de l'enquête.

Par exemple :

  • une preuve originale ne doit pas être modifiée ;
  • une hypothèse ne constitue jamais un fait établi ;
  • le journal est append-only ;
  • une recherche décrit une action et non son résultat.

Ces règles sont appliquées par la couche métier de l'application et ne peuvent pas être garanties uniquement par le schéma SQL.


7.7 Défense en profondeur

Labfy Investigation applique plusieurs niveaux de validation.

Utilisateur
      │
      ▼
Interface GTK
      │
      ▼
Validation métier
      │
      ▼
Couche Database
      │
      ▼
SQLite

Chaque niveau vérifie les données avant de les transmettre au niveau suivant.

Cette approche permet :

  • de détecter rapidement les erreurs ;
  • de limiter les incohérences ;
  • de protéger la base contre les corruptions accidentelles ;
  • de simplifier le débogage.

8. Index

Les index ont pour objectif d'améliorer les performances des requêtes les plus fréquentes sans modifier le modèle de données.

Ils permettent à SQLite de localiser rapidement les enregistrements recherchés sans parcourir l'intégralité des tables.

Les index sont définis dès la conception du schéma afin de garantir des performances cohérentes, même lorsque les bases de données deviennent volumineuses.

Le choix des index repose sur les usages attendus de Labfy Investigation et non sur une optimisation prématurée.


8.1 Objectifs

Les index sont principalement utilisés pour accélérer les opérations suivantes :

  • recherche d'un objet par son identifiant ;
  • navigation entre les objets liés ;
  • filtrage par statut ;
  • tri chronologique ;
  • recherche par catégorie ;
  • recherche par tag ;
  • consultation de la chronologie ;
  • consultation du journal.

Ils permettent également de limiter le coût des nombreuses jointures entre les tables métier.


8.2 Politique

Les index sont créés selon plusieurs principes.

Clés étrangères

Les colonnes utilisées comme clés étrangères sont systématiquement indexées.

Cette règle améliore les performances des jointures ainsi que les contrôles d'intégrité réalisés par SQLite.


Dates

Les colonnes utilisées pour les tris chronologiques sont indexées.

Exemples :

  • created_at
  • updated_at
  • event_time

Ces index facilitent la consultation des événements récents et des historiques d'une enquête.


États

Les colonnes status sont indexées lorsque leur utilisation est fréquente.

Cela permet notamment de retrouver rapidement les objets :

  • actifs ;
  • archivés ;
  • supprimés logiquement.

Tables de liaison

Les tables de liaison possèdent une clé primaire composite.

Des index complémentaires peuvent être ajoutés lorsque les recherches sont souvent réalisées dans le sens inverse de cette clé.

Exemple :

PRIMARY KEY (
    tag_id,
    preuve_id
)

Un index supplémentaire sur :

preuve_id

permet de retrouver rapidement tous les tags associés à une preuve.


Équilibre

Chaque index améliore certaines requêtes mais augmente également :

  • la taille de la base de données ;
  • le coût des insertions ;
  • le coût des mises à jour.

Les index sont donc créés uniquement lorsqu'ils répondent à un besoin identifié.

Aucun index n'est ajouté sans justification fonctionnelle.


8.3 Évolution

La politique d'indexation pourra évoluer à mesure que l'application grandira.

Toute modification devra être basée sur :

  • des mesures de performances ;
  • des profils d'utilisation réels ;
  • des besoins fonctionnels identifiés.

Les optimisations devront privilégier la simplicité du schéma et préserver la compatibilité avec les versions précédentes de la base de données.


9. Versionnement

Le schéma de la base de données est versionné.

Chaque base SQLite créée par Labfy Investigation possède un numéro de version permettant à l'application de déterminer si elle est compatible avec le logiciel utilisé.

Le versionnement constitue un élément essentiel de la pérennité des données.

Une enquête créée aujourd'hui doit pouvoir être ouverte plusieurs années plus tard par une version plus récente de l'application.


9.1 Version du schéma

La version du schéma est enregistrée dans la table :

metadata

La clé :

schema_version

identifie la version de l'architecture utilisée par la base.

Pour cette première version :

schema_version = 1

Cette valeur constitue la référence de toute la documentation associée à la V1.


9.2 Compatibilité

Le logiciel vérifie la version du schéma avant d'ouvrir une enquête.

Trois situations sont possibles :

Même version

La base est compatible.

L'ouverture de l'enquête peut se poursuivre normalement.


Version plus ancienne

Une migration peut être proposée si elle existe.

La migration permet d'adapter progressivement la base vers une version plus récente du schéma.


Version plus récente

Le logiciel refuse d'ouvrir la base.

Cette situation indique généralement que l'enquête a été créée avec une version plus récente de Labfy Investigation.

Une ancienne version du logiciel ne doit jamais tenter de modifier une base qu'elle ne comprend pas.


9.3 Migrations

Toute évolution incompatible du schéma devra être réalisée à l'aide d'une migration.

Une migration est une opération contrôlée permettant de transformer une base existante vers une nouvelle version du schéma.

Chaque migration devra respecter les règles suivantes :

  • être transactionnelle ;
  • préserver les données existantes ;
  • être documentée ;
  • être reproductible ;
  • pouvoir détecter les erreurs.

Avant toute migration, une sauvegarde complète de la base devra être réalisée.

En cas d'échec, la base devra être restaurée dans son état initial.


9.4 Compatibilité ascendante

Une fois une version du schéma publiée, elle devient une référence.

Les évolutions futures devront privilégier :

  • l'ajout de nouvelles tables ;
  • l'ajout de nouvelles colonnes compatibles ;
  • l'ajout de nouveaux index ;
  • l'ajout de nouvelles contraintes lorsque cela reste compatible.

Les modifications destructives devront être évitées autant que possible.


9.5 Politique d'évolution

Les évolutions du schéma suivent les principes suivants :

  • ne jamais casser une enquête existante sans migration ;
  • documenter chaque changement ;
  • conserver la cohérence du modèle métier ;
  • maintenir la compatibilité avec les outils de développement et de test.

Toute modification du schéma doit être accompagnée :

  • d'une mise à jour de schema_v1.sql (ou de la version concernée) ;
  • d'une mise à jour de la documentation ;
  • d'une adaptation des tests unitaires ;
  • d'une revue d'architecture si le changement impacte le modèle métier.

9.6 Cycle de vie du schéma

Le cycle de vie d'une nouvelle version suit les étapes suivantes :

Conception
      │
      ▼
Validation
      │
      ▼
Implémentation SQL
      │
      ▼
Tests unitaires
      │
      ▼
Documentation
      │
      ▼
Publication
      │
      ▼
Maintenance

Une version publiée ne doit plus être modifiée directement.

Toute évolution ultérieure devra conduire à une nouvelle version du schéma.


9.7 Philosophie

Le schéma de la base de données constitue un contrat entre l'application et les données.

Une évolution du schéma ne doit jamais être décidée uniquement pour simplifier le code.

Au contraire, le code de l'application doit s'adapter au schéma validé.

Cette approche garantit :

  • la stabilité des données ;
  • la lisibilité du projet ;
  • la fiabilité des migrations ;
  • la pérennité des enquêtes.

10. Architecture C

La base de données est entièrement encapsulée dans une couche logicielle dédiée.

Les autres composants de Labfy Investigation ne manipulent jamais directement SQLite.

Cette séparation permet d'isoler les détails d'implémentation de la base de données du reste de l'application.

L'objectif est de garantir une architecture modulaire, testable et facilement maintenable.


10.1 Organisation

La couche Database est répartie entre les répertoires :

include/database/
src/database/

Chaque objet métier possède son propre module.

Cette organisation permet de limiter les dépendances entre les différents composants.

L'ensemble de la couche Database constitue l'unique point d'accès aux données.


10.2 Modules

L'organisation cible est la suivante :

database/
├── database.c
├── database_connection.c
├── schema.c
├── metadata.c
├── investigation.c
├── source.c
├── recherche.c
├── preuve.c
├── entite.c
├── relation.c
├── chronologie.c
├── journal.c
├── hypothese.c
├── categorie.c
└── tag.c

Chaque fichier .c possède son fichier d'en-tête correspondant dans :

include/database/

Cette organisation représente l'architecture cible de la couche Database.

Tous les modules ne sont pas nécessairement implémentés dès la première version de l'application.


10.3 Responsabilités

Chaque module possède une responsabilité clairement définie.

Par exemple :

  • preuve.c gère les preuves ;
  • entite.c gère les entités ;
  • relation.c gère les relations ;
  • source.c gère les sources ;
  • hypothese.c gère les hypothèses.

Un module ne doit jamais gérer plusieurs concepts métier indépendants.

Les opérations transversales sont regroupées dans des modules spécifiques.


10.4 API publique

Les autres composants de l'application utilisent exclusivement les fonctions publiques exposées par les fichiers d'en-tête.

Ils ne doivent jamais :

  • ouvrir directement une base SQLite ;
  • construire une requête SQL ;
  • préparer une instruction SQLite ;
  • manipuler les structures internes de SQLite.

Cette règle garantit une séparation claire entre la logique métier et la persistance des données.


10.5 Gestion des erreurs

Toutes les erreurs provenant de SQLite sont traitées par la couche Database.

Les fonctions publiques retournent des valeurs adaptées à leur usage :

  • bool pour les opérations simples ;
  • pointeurs vers des objets en cas de création ou de lecture ;
  • NULL lorsqu'une opération échoue.

Les messages d'erreur détaillés sont journalisés dans un point unique afin de faciliter le débogage.


10.6 Gestion mémoire

La couche Database respecte les conventions mémoire du projet.

Les objets retournés par l'API possèdent un propriétaire clairement identifié.

Chaque fonction de création possède une fonction de destruction associée.

Exemple :

preuve_new(...)
preuve_free(...)

Cette règle garantit une gestion mémoire simple et prévisible.


10.7 Transactions

Les transactions SQLite sont gérées exclusivement par la couche Database.

Une fonction appelante ne doit jamais ouvrir ou fermer directement une transaction.

Cette centralisation garantit la cohérence des opérations complexes et limite les risques d'états intermédiaires incohérents.


10.8 Évolutivité

L'organisation modulaire permet d'ajouter de nouvelles fonctionnalités sans modifier les modules existants.

L'ajout d'un nouvel objet métier conduit généralement à la création :

  • d'une nouvelle table ;
  • d'un nouveau module .c ;
  • d'un nouveau fichier d'en-tête ;
  • de nouveaux tests unitaires.

Cette approche limite les régressions et facilite la maintenance du projet.


10.9 Tests unitaires

Chaque module Database doit disposer de ses propres tests unitaires.

Les tests vérifient notamment :

  • les créations d'objets ;
  • les lectures ;
  • les mises à jour ;
  • les suppressions logiques ;
  • les contraintes d'intégrité ;
  • les cas d'erreur.

Aucune fonctionnalité de la couche Database ne doit être considérée comme terminée sans tests associés.


10.10 Principe directeur

La couche Database constitue la seule interface entre l'application et les données persistantes.

Les autres composants manipulent uniquement des objets métier et des fonctions publiques.

Cette séparation garantit :

  • une architecture claire ;
  • une meilleure testabilité ;
  • une maintenance simplifiée ;
  • une évolution indépendante de la base de données et de l'interface utilisateur.

11. Diagramme général

Le schéma relationnel complet de Labfy Investigation comporte un nombre important de tables et de relations.

Afin de faciliter sa compréhension, ce document présente une vue simplifiée du modèle métier.

L'objectif de ce diagramme n'est pas de représenter chaque clé étrangère mais de montrer la circulation de l'information au sein d'une enquête.


11.1 Vue métier

                            Investigation
                                  │
      ┌───────────────────────────┼───────────────────────────┐
      │                           │                           │
      ▼                           ▼                           ▼
  Métadonnées                 Collecte                  Classification
      │                           │                           │
      │                     ┌─────┴─────┐               ┌─────┴─────┐
      │                     ▼           ▼               ▼           ▼
      │                 Sources    Recherches     Catégories      Tags
      │                                  │
      │                                  ▼
      │                              Preuves
      │                                  │
      │                         ┌────────┴────────┐
      │                         ▼                 ▼
      │                     Entités          Chronologie
      │                         │
      │                         ▼
      │                     Relations
      │                         │
      │                         ▼
      │                    Hypothèses
      │
      ▼
    Journal

11.2 Cycle d'une investigation

Le déroulement d'une enquête suit généralement les étapes suivantes.

Source
    │
    ▼
Recherche
    │
    ▼
Preuve
    │
    ▼
Entité
    │
    ▼
Relation
    │
    ▼
Hypothèse

Ce cycle représente uniquement le cheminement principal.

En pratique, une enquête est itérative.

Une nouvelle recherche peut :

  • confirmer une preuve existante ;
  • découvrir une nouvelle entité ;
  • modifier une relation ;
  • renforcer ou affaiblir une hypothèse.

Le modèle de données a été conçu pour permettre ces allers-retours sans perdre la traçabilité des informations.


11.3 Traçabilité

Chaque information importante peut être reliée à son origine.

Source
    │
    ▼
Recherche
    │
    ▼
Preuve
    │
    ▼
Entité
    │
    ▼
Relation
    │
    ▼
Hypothèse

En parallèle :

Recherche
      │
      ├──────────────► Chronologie
      │
      └──────────────► Journal

La chronologie décrit les événements de l'enquête.

Le journal enregistre les actions réalisées dans le logiciel.

Ces deux mécanismes sont volontairement séparés.


11.4 Philosophie du modèle

Le modèle de Labfy Investigation repose sur plusieurs principes.

Les objets métier représentent les concepts manipulés par les enquêteurs.

Les relations entre ces objets sont explicites et documentées.

Les fichiers originaux restent inchangés.

Toutes les informations produites pendant une enquête demeurent traçables.

Le modèle privilégie :

  • la clarté ;
  • la cohérence ;
  • l'intégrité des données ;
  • l'évolutivité.

L'objectif est de permettre à l'application de reproduire fidèlement le raisonnement suivi pendant une investigation, plutôt que de simplement stocker des fichiers ou des notes.


11.5 Disposition générique du graphe

La disposition visuelle du graphe est un état de présentation et non une donnée métier. Elle est stockée dans graph_layout_positions, séparément des tables entites et relations.

Chaque ligne associe un UUID de nœud à des coordonnées logiques et à une date UTC de mise à jour. Un nœud peut représenter une entité ou une relation. SQLite ne proposant pas de clé étrangère polymorphe, l'intégrité de ce stockage est assurée par deux triggers qui suppriment la position correspondante lors de la suppression physique d'une entité ou d'une relation.

La table historique graph_node_positions ne référençait que entites(id). À l'ouverture d'une enquête, ses lignes sont copiées de manière idempotente vers graph_layout_positions, puis retirées de la table historique afin qu'une réinitialisation volontaire de la disposition ne puisse pas restaurer des coordonnées obsolètes.

Cette stratégie préserve les positions existantes tout en permettant aux nœuds de relation de suivre exactement le même cycle de chargement, d'enregistrement et de réinitialisation que les nœuds d'entité.

Le cadrage global est stocké séparément dans la ligne unique de graph_viewport. Elle conserve le niveau de zoom et les décalages horizontal et vertical du canevas. Ces valeurs sont enregistrées à la fermeture de l'enquête et restaurées lors de son premier chargement, afin que la vue réapparaisse exactement à l'endroit où l'utilisateur l'avait laissée.


12. Conclusion

La base de données de Labfy Investigation constitue bien davantage qu'un simple espace de stockage.

Elle représente le modèle métier de l'application.

Chaque décision d'architecture a été prise afin de répondre à trois objectifs principaux :

  • préserver l'intégrité des données ;
  • garantir leur traçabilité ;
  • permettre l'évolution du logiciel sur le long terme.

Le schéma V1 repose sur une séparation claire des responsabilités.

Chaque table représente un concept métier unique.

Les relations entre ces concepts sont explicites et documentées.

Les contraintes SQL assurent la cohérence des données tandis que la couche Database applique les règles métier qui ne peuvent être exprimées dans le schéma relationnel.

Cette architecture permet de représenter fidèlement le déroulement d'une investigation numérique :

Source
    │
    ▼
Recherche
    │
    ▼
Preuve
    │
    ▼
Entité
    │
    ▼
Relation
    │
    ▼
Hypothèse

À chaque étape, les informations restent reliées à leur origine et peuvent être replacées dans leur contexte grâce à la chronologie et au journal d'audit.

Le choix d'utiliser une base SQLite autonome pour chaque enquête garantit la portabilité, facilite les sauvegardes et simplifie les échanges entre enquêteurs.

Le schéma V1 constitue désormais la référence de développement de Labfy Investigation.

Toute évolution future devra respecter les principes définis dans cette documentation :

  • documenter les besoins avant toute modification ;
  • préserver la compatibilité des données ;
  • privilégier l'ajout de nouveaux objets plutôt que la modification des objets existants ;
  • accompagner toute évolution d'une migration, d'une documentation et de tests adaptés.

Le schéma SQL, la documentation et les tests unitaires forment un ensemble indissociable.

Aucun de ces éléments ne doit évoluer indépendamment des autres.

L'objectif final n'est pas uniquement de stocker des données, mais de fournir une base solide permettant de développer un logiciel d'investigation fiable, maintenable et pérenne.


Statut

À la publication de ce document :

  • le schéma V1 est considéré comme stable ;
  • il constitue la référence officielle de la couche Database ;
  • toute évolution incompatible devra faire l'objet d'une nouvelle version du schéma et d'une migration documentée.

Références

Documents associés :

  • database/schema_v1.sql
  • docs/database/SCHEMA_AUDIT_V1.md
  • docs/database/DATABASE_ARCHITECTURE.md
  • docs/CONVENTIONS.md

Ces documents constituent ensemble la documentation de référence de l'architecture de la base de données de Labfy Investigation.