Simpl-Resultat/CLAUDE.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

12 KiB

CLAUDE.md — Simpl'Résultat

@STATE.md

Contexte du projet

Simpl'Résultat est une application de bureau desktop privacy-first pour la gestion des finances personnelles. Elle traite localement les fichiers CSV bancaires sans aucune dépendance cloud. Projet solo entrepreneurial, en développement par Max.

Stack technique : Tauri v2 + React 19 + TypeScript + Tailwind CSS v4 Backend : Rust (commandes Tauri) Stockage : SQLite local (tauri-plugin-sql) Langues supportées : Français (FR) et Anglais (EN) Plateformes : Windows, Linux Version actuelle : 0.17.0 Licence : GPL-3.0-only


Principes fondamentaux

Privacy-first — NON NÉGOCIABLE

  • Zéro donnée envoyée vers un serveur tiers
  • Tout le traitement CSV et toutes les données financières restent en local
  • Aucune télémétrie, aucun analytics cloud

Précision financière

  • Toujours valider les montants selon les règles de parsing configurables (gestion des virgules/points, espaces, symboles monétaires)
  • Gérer l'encodage des fichiers CSV (UTF-8, Windows-1252, ISO-8859-15)

Internationalisation (i18n)

  • Toute chaîne affichée à l'utilisateur doit passer par le système i18n (i18next + react-i18next)
  • Jamais de texte en dur dans les composants React
  • Fichiers de traduction : src/i18n/locales/fr.json et src/i18n/locales/en.json

Architecture & structure du code

src/
├── components/          # 53 composants React organisés par domaine
│   ├── adjustments/     # Ajustements
│   ├── budget/          # Budget
│   ├── categories/      # Catégories hiérarchiques
│   ├── dashboard/       # Tableau de bord
│   ├── import/          # Wizard d'import (14 composants)
│   ├── layout/          # AppShell, Sidebar
│   ├── profile/         # Profils (PIN, formulaire, switcher)
│   ├── reports/         # Graphiques et rapports
│   ├── settings/        # Paramètres
│   ├── shared/          # Composants réutilisables
│   └── transactions/    # Transactions
├── contexts/            # ProfileContext (état global profil)
├── hooks/               # 13 hooks custom (useReducer)
├── pages/               # 11 pages
├── services/            # 14 services métier
├── shared/              # Types et constantes partagés
├── utils/               # Utilitaires (parsing, CSV, charts)
├── i18n/                # Config i18next + locales FR/EN
├── App.tsx              # Router principal (react-router-dom)
└── main.tsx             # Point d'entrée

src-tauri/
├── src/
│   ├── commands/        # 3 modules, 17 commandes Tauri
│   │   ├── fs_commands.rs           # Système de fichiers (6 commandes)
│   │   ├── export_import_commands.rs # Export/import chiffré (5 commandes)
│   │   └── profile_commands.rs      # Gestion des profils (8 commandes)
│   ├── database/        # Schémas SQL et migrations
│   │   ├── schema.sql               # Schéma initial (v1)
│   │   ├── seed_categories.sql      # Seed catégories (v2)
│   │   ├── consolidated_schema.sql  # Schéma complet (nouveaux profils)
│   │   └── profile_db.rs            # Rattrapage des profils secondaires (ADR 0021)
│   ├── lib.rs           # Point d'entrée, 17 migrations inline, plugins
│   └── main.rs
└── Cargo.toml

Règles d'architecture :

  • La logique métier va dans services/, jamais directement dans les composants
  • L'état de chaque domaine est géré par un hook useReducer dédié dans hooks/
  • Les composants React sont responsables de l'affichage uniquement
  • Toute opération sur les fichiers système passe par les commandes Tauri (Rust)
  • Les requêtes SQL passent par les services TypeScript via tauri-plugin-sql

Fonctionnalités principales

  • Import CSV : wizard multi-étapes, détection auto (encodage, délimiteur, colonnes par libellé FR/EN, formats de banques connus) avec score de confiance, aperçu obligatoire à récap signé avant tout import, templates de config, déduplication par fichier. Le format d'import est persisté en entier sur la source et jamais re-deviné — ADR 0019
  • Catégorisation : automatique (mots-clés avec priorité) et manuelle, drag-and-drop pour réorganiser
  • Transactions : filtrage, tri, split sur plusieurs catégories, notes
  • Budget : grille 12 mois, templates réutilisables, budget vs réel
  • Rapports : tendances mensuelles, répartition par catégorie, évolution dans le temps, graphiques interactifs (SVG patterns, menu contextuel)
  • Multi-profils : bases de données séparées, protection par PIN (Argon2), switching rapide
  • Export/Import : JSON/CSV avec chiffrement AES-256-GCM optionnel (format SREF)
  • Mises à jour : auto-updater intégré (tauri-plugin-updater)
  • Changelog bilingue : page /changelog avec historique complet, notes de version dynamiques FR/EN depuis CHANGELOG.md / CHANGELOG.fr.md (bundlés dans public/)

Conventions de code

React / TypeScript

  • Un composant = un fichier .tsx, nommé en PascalCase
  • Hooks custom dans hooks/, services dans services/
  • État local via useReducer dans les hooks de domaine

Rust / Tauri

  • Toutes les commandes Tauri retournent Result<T, String> pour la gestion d'erreurs
  • Documenter chaque commande avec un commentaire sur son rôle

Général

  • Commits en anglais, commentaires de code en anglais
  • Messages d'interface en français ET anglais (via i18n)
  • Tester les cas limites de parsing CSV (montants négatifs, cellules vides, formats inattendus)

Base de données

  • 20 tables SQLite, 24 index (voir docs/architecture.md pour le détail). Le module Bilan en représente 7 tables (balance_categories, balance_accounts, balance_snapshots, balance_snapshot_lines, balance_account_transfers, puis balance_securities + balance_snapshot_holdings ajoutées en Étape 2 — détail par titre) et 9 index. Ces deux comptes sont inchangés depuis v13 : v14-v16 ajoutent 2 tables + 2 index (déjà comptés), v17 est un ALTER TABLE pur
  • 17 migrations inline dans lib.rs (v1→v17, via tauri_plugin_sql::Migration). Étape 2 du Bilan (détail par titre) : v14 (balance_securities + balance_snapshot_holdings + 2 index), v15 (balance_accounts.kind + detailed_since + backfill), v16 (conversion des comptes cotés existants en détaillés 1-position) — voir ADR 0015. Import : v17 (import_sources.amount_mode + sign_convention, les deux avec CHECK, + header_signature + template_id) — voir ADR 0019
  • Schéma consolidé (consolidated_schema.sql) pour l'initialisation des nouveaux profils, suivi de l'historique complet des migrations. tauri-plugin-sql ne migre que le profil par défaut : les profils secondaires rattrapent leurs migrations à chaque ouverture (prepare_profile_db, copie préalable, clés étrangères actives) — voir ADR 0021. Les bases vivent sous app_config_dir() (profile_db_path), qui n'est pas app_data_dir() sous Linux
  • Les migrations appliquées sont protégées par checksum — ne jamais modifier une migration existante, toujours en créer une nouvelle

Documentation technique

La documentation technique est centralisée dans docs/ :

  • docs/architecture.md — Architecture technique complète (stack, BDD, services, hooks, commandes Tauri, routing, i18n, CI/CD)
  • docs/adr/ — Architecture Decision Records (décisions techniques structurantes)
  • docs/guide-utilisateur.md — Guide utilisateur
  • docs/archive/ — Anciennes spécifications archivées

Règle : quand un changement touche l'architecture, mettre à jour la documentation :

  • Nouveau service, hook, commande Tauri, page/route, ou table SQL → mettre à jour docs/architecture.md
  • Décision technique structurante (choix de librairie, pattern architectural, changement de stratégie) → créer un nouvel ADR dans docs/adr/
  • Changement affectant l'utilisation de l'app → mettre à jour docs/guide-utilisateur.md et les traductions i18n correspondantes (src/i18n/locales/fr.json, src/i18n/locales/en.json, clés sous docs.*)

Règle CHANGELOG : tout changement affectant le comportement utilisateur → ajouter une entrée sous ## [Unreleased] dans les deux fichiers :

  • CHANGELOG.md (anglais) — source principale
  • CHANGELOG.fr.md (français) — traduction
  • Catégories : Added/Ajouté, Changed/Modifié, Fixed/Corrigé, Removed/Supprimé
  • Format Keep a Changelog. Le contenu est extrait automatiquement par le CI pour les release notes et affiché dans l'app selon la langue de l'utilisateur.
  • The public/ copies are synced automatically: Vite copies them on dev/build start via syncChangelogs() in vite.config.ts. No manual sync needed.

Points d'attention RS&DE / CRIC

Pour maintenir l'éligibilité aux crédits d'impôt R&D (RS&DE fédéral + CRIC Québec) :

  • Documenter les incertitudes technologiques rencontrées pendant le développement
  • Noter les expérimentations et les approches alternatives testées
  • Garder un journal des avancées techniques (dans /docs/rnd-journal/)
  • Les algorithmes de catégorisation automatique et le parsing multi-format sont des activités R&D éligibles

CI/CD

Workflows Forgejo Actions dans .forgejo/workflows/. Le runner est à capacité 1 — les jobs se suivent, ils ne tournent pas en parallèle.

  • check-rust.yml — déclenché sur les PR touchant src-tauri/** ou .cargo/**, plus chaque lundi à 06:30 UTC sur main et par workflow_dispatch. Lance cargo check, une vérification bloquante que les advisories acceptées restent non atteignables, cargo test et un cargo audit informatif, avec le cache Swatinem/rust-cache. Doit être vert avant tout merge.
  • check-frontend.yml — déclenché sur les PR, sauf si tous les fichiers modifiés sont du Rust, de la doc ou du markdown. Lance npm run build (tsc + vite) et npm test (vitest). Doit être vert avant tout merge. Aucune étape npm audit : les advisories npm ne sont pas un gate de CI. npm audit remonte 2 high en permanence — une seule advisory react-router (mode RSC, inatteignable dans une app de bureau sans serveur), acceptée et suivie en #317.
  • audit.yml — audit RustSec quotidien (06:00 UTC) + workflow_dispatch, pour couvrir les avis de sécurité entre deux PR Rust. Échec bloquant. Un run vert signifie « zéro advisory hors de la liste acceptée », pas « zéro advisory » : cette liste est dans .cargo/audit.toml (preuve de non-atteignabilité et condition de retrait par entrée), encadrée par l'ADR 0018. Ne jamais y ajouter une advisory atteignable ni élargir une entrée à un crate entier.
  • release.yml — déclenché par les tags v*. Build Windows (NSIS .exe) + Linux (.deb, .rpm), signe les binaires et publie le JSON d'updater pour les mises à jour automatiques.

Aucun workflow check-* ne filtre sur branches: : une PR stackée sur une autre branche de feature déclenche donc bien la CI. Le cache Rust passe par Swatinem/rust-cache (#234) : le runner garde ce qu'écrit un run de PR pour cette seule PR, donc c'est le run du lundi (ou un workflow_dispatch) qui alimente le cache partagé que lisent les autres PR. Un run à froid reste normal après une nouvelle version stable de Rust ou une modification de l'env: du job, quand une entrée expire (7 jours sans usage, 30 jours d'âge), ou quand une PR sauvegarde sous la clé de l'entrée partagée et l'évince, le runner ne gardant qu'une entrée par clé. La liste complète est en tête de check-rust.yml ; seul un délai dépassé signale un retour de #234. Pas de cache npm : check-frontend ne tourne que sur des PR, et npm ci y prend 9 s. Le miroir .github/workflows/ est dormant (aucune PR côté GitHub).


Ressources clés