All checks were successful
PR Check — Frontend / frontend (pull_request) Successful in 2m4s
Follow-ups of the review of PR #418. - check-latest-json.jq wants exactly one document and release.yml calls it with -s: under jq 1.6, the release container's, an empty file passed the check (no output, status 0) and two documents were judged on the last one, so the job would have deleted the published manifest and uploaded the bad one. Two tests cover both cases. - build-latest-json.test.mjs runs the text of release.yml's "Publish latest.json to package registry" step against a fake curl: DELETE then PUT on a valid manifest, exit 1 and no request on a refused one. - check-frontend no longer ignores .claude/** and release.yml (decision of Max): the test reads verify-release.sh and runs the Publish step, so "on every pull request" holds. REVIEW.md, CLAUDE.md and architecture.md follow. - release.yml: stale ".deb fallback" comment fixed. - qa-update-cycle.md: a tauri dev build on Linux shows TargetsNotFound, expected since #418. Refs #461 Resolves #419 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
182 lines
13 KiB
Markdown
182 lines
13 KiB
Markdown
# 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.1
|
|
**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](docs/adr/0019-format-import-persiste.md)
|
|
- **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](docs/adr/0015-balance-detail-par-titre.md). Import : v17 (`import_sources.amount_mode` + `sign_convention`, les deux avec `CHECK`, + `header_signature` + `template_id`) — voir [ADR 0019](docs/adr/0019-format-import-persiste.md)
|
|
- **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](docs/adr/0021-migrations-profils-secondaires.md). 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
|
|
|
|
Les règles de revue des PR (niveaux de risque, ce qui compte par zone, commandes de vérification, pièges) sont dans [`REVIEW.md`](REVIEW.md), à la racine ; un changement qui rend faux un fait qu'il cite le met à jour dans la même PR.
|
|
|
|
**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](https://keepachangelog.com/). 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, une autre que les sept arêtes `windows-sys` à borne large du lock restent sur `0.61.2` ([ADR 0023](docs/adr/0023-windows-sys-pinning.md)), `cargo test` et un `cargo audit` informatif, avec le cache `Swatinem/rust-cache`. Doit être vert avant tout merge. Un `cargo update` qui re-résout ces arêtes (`-p hyper` et `-p h2` l'ont fait) fait rougir le garde `windows-sys` : remettre les arêtes à la main selon l'ADR, ne jamais modifier la liste gardée pour le faire passer.
|
|
- **`check-frontend.yml`** — déclenché sur les PR, sauf si tous les fichiers modifiés sont du Rust, de la doc, du markdown, `check-rust.yml` ou `audit.yml` ; `.claude/**` et `release.yml` le déclenchent, car `scripts/build-latest-json.test.mjs` lit `verify-release.sh` et exécute l'étape « Publish » de `release.yml` (#419). 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` à 0 au 2026-10-10 ([#358](https://git.lacompagniemaximus.com/maximus/simpl-resultat/issues/358)), un constat daté : aucun job ne le fait échouer, mais `npm ci` en imprime le compte à chaque run de `check-frontend`, et le Défenseur relève les advisories de son côté (#358 en vient).
|
|
- **`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](docs/adr/0018-suppression-advisories-non-atteignables.md). 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](https://git.lacompagniemaximus.com/maximus/simpl-resultat/issues/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
|
|
|
|
- [Tauri v2 Docs](https://v2.tauri.app/)
|
|
- [React Docs](https://react.dev/)
|
|
- [SQLite via Tauri](https://github.com/tauri-apps/tauri-plugin-sql)
|
|
- Architecture détaillée : `docs/architecture.md`
|
|
- Décisions techniques : `docs/adr/`
|