Simpl-Resultat/docs/adr/0005-multi-profile-db.md
le king fu 02fca2ad3c docs: ADR 0021, guide and changelog for the profile catch-up (#390)
ADR 0021 records the catch-up rules and amends ADR 0003 and 0005, whose
claims about secondary profiles were false. architecture.md, CLAUDE.md
and the migration rule describe the two migration paths; the guide tells
where the pre-update copy lives and how to remove a database a deletion
on Linux left behind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 20:35:00 -04:00

3.2 KiB

ADR-0005 : Architecture multi-profils avec bases de données séparées

  • Date : 2025-08
  • Statut : Accepté

Contexte

L'application doit supporter plusieurs profils utilisateur (par exemple, un profil personnel et un profil professionnel) avec une isolation complète des données. Chaque profil a ses propres catégories, transactions, budgets et paramètres.

Les options considérées :

  • Base unique avec colonne profile_id : simple, mais risque de fuite de données entre profils
  • Bases de données séparées : isolation totale, mais gestion plus complexe
  • Schémas SQLite (ATTACH DATABASE) : isolation partielle, API complexe

Décision

Chaque profil possède sa propre base de données SQLite. La liste des profils est stockée dans un fichier profiles.json dans le répertoire de données de l'application.

Architecture :

  • profiles.json : métadonnées des profils (nom, chemin de la BDD, hash du PIN)
  • ProfileContext (React) : état global du profil actif, liste des profils, fonctions de switching
  • ProfileSelectionPage : page affichée quand aucun profil n'est actif (gate)
  • Les nouveaux profils sont initialisés avec consolidated_schema.sql (via la commande get_new_profile_init_sql)
  • Chaque profil peut être protégé par un PIN (hashé avec Argon2)

Conséquences

Positives

  • Isolation totale : aucun risque de fuite de données entre profils
  • Suppression simple : supprimer un profil = supprimer un fichier .db
  • Sauvegarde indépendante : chaque profil peut être exporté/importé séparément
  • Pas de migration croisée : les migrations s'appliquent indépendamment à chaque base

Négatives

  • Reconnexion nécessaire : le changement de profil nécessite la fermeture et la réouverture de la connexion SQLite
  • Pas de vue agrégée : impossible de voir les données de tous les profils en même temps
  • Synchronisation du schéma : chaque base doit être au même niveau de migration (géré par le plugin sql au démarrage)
  • Fichier profiles.json externe : les métadonnées des profils ne sont pas dans SQLite, ce qui crée une dépendance à un fichier JSON séparé

Amendement #390 (2026-10-06)

Deux affirmations des conséquences étaient fausses jusqu'à #390 :

  • « Les migrations s'appliquent indépendamment à chaque base » et « géré par le plugin sql au démarrage » : le plugin ne migre que la base du profil par défaut. Un profil secondaire gardait le schéma de la version qui l'avait créé. Il rattrape désormais ses migrations à chaque ouverture (ADR 0021).
  • « Supprimer un profil = supprimer un fichier .db » : sous Linux, la commande cherchait la base sous app_data_dir() alors que le plugin la range sous app_config_dir(), et le fichier restait sur le disque. La suppression vise désormais le dossier du plugin et emporte aussi les fichiers annexes de SQLite et les copies prises avant un rattrapage.

profiles.json reste dans le répertoire de données de l'application (app_data_dir()) ; les bases sont dans le répertoire de configuration (app_config_dir()), qui n'est le même dossier que sous Windows et macOS.