Compare commits

..

2 commits

Author SHA1 Message Date
f1cbcb1c27 Merge pull request 'docs(balance): ADR 0014 + reject 0012 + guide + changelog' (#209) from issue-205-adr-0014-guide-changelog into main 2026-06-02 01:18:46 +00:00
le king fu
ebc709a277 docs(balance): ADR 0014 + reject 0012 + guide + changelog (#205)
All checks were successful
PR Check / rust (pull_request) Successful in 22m24s
PR Check / frontend (pull_request) Successful in 2m22s
Document Étape 1 of the balance audit (vehicle_type axis), already shipped
in #202/#203/#204:
- ADR 0014 (Accepted): fiscal envelope is an account attribute, the category
  is a pure asset class; Étape 2 (per-security detail) explicitly out of scope.
- ADR 0012 marked Rejected (never accepted, not Superseded) + pointer to 0014.
- User guide (markdown + in-app docs.balance i18n FR/EN): optional fiscal
  envelope, the two chart axes, type renaming, and the historical-reclass note.
- CHANGELOG.md + CHANGELOG.fr.md [Unreleased]: Added (envelope field, envelope
  axis, collapsible returns) + Changed (asset-class category, CELI/REER reclass,
  rename no longer alters translation, historical-reclass note).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 21:15:06 -04:00
7 changed files with 158 additions and 27 deletions

View file

@ -5,10 +5,16 @@
### Ajouté ### Ajouté
- Bilan : la date d'un snapshot existant peut maintenant être déplacée. Le champ date devient modifiable en mode édition — changez-la puis enregistrez, et le snapshot (avec toutes ses lignes) est déplacé à la nouvelle date dans une seule transaction atomique. Si un autre snapshot occupe déjà la date cible, le déplacement est refusé avec un message clair et rien n'est modifié (#200). - Bilan : la date d'un snapshot existant peut maintenant être déplacée. Le champ date devient modifiable en mode édition — changez-la puis enregistrez, et le snapshot (avec toutes ses lignes) est déplacé à la nouvelle date dans une seule transaction atomique. Si un autre snapshot occupe déjà la date cible, le déplacement est refusé avec un message clair et rien n'est modifié (#200).
- Bilan : **enveloppe fiscale sur les comptes**. Un compte peut désormais porter une enveloppe fiscale optionnelle (Non-enregistré, CELI, REER, FERR, CELIAPP, REEE — ou aucune), choisie via un menu déroulant dans le formulaire de compte. C'est un axe distinct du type du compte (la classe d'actif) : un compte d'actions logé dans un CELI est enfin exprimable — type *Actions* + enveloppe *CELI*. La migration v12 ajoute la colonne nullable `balance_accounts.vehicle_type` avec un CHECK sur l'enum et backfille les anciens comptes CELI/REER (#202, #203).
- Bilan : **axe enveloppe du graphique empilé**. Le graphique d'évolution empilé gagne un sous-choix d'axe — **Par classe d'actif** (défaut, comportement inchangé) ou **Par enveloppe** (regroupe par enveloppe fiscale, avec un bucket « Aucune » pour les comptes sans enveloppe). Lisez votre patrimoine par ce que vous détenez *ou* par l'abri fiscal où il se trouve (#204).
- Bilan : **colonnes de rendement repliables**. Les quatre colonnes de rendement Modified Dietz du tableau des comptes (3M / 1A / depuis création / non-ajusté) sont maintenant repliées par défaut derrière un bouton afficher/masquer ; le choix est mémorisé d'une session à l'autre (`user_preferences.balance_show_returns`) pour réduire le bruit visuel chez les utilisateurs qui ne suivent que des valeurs (#204).
### Modifié ### Modifié
- Bilan : terminologie clarifiée. Les regroupements de comptes (Liquidités, CELI, REER, etc.) sont désormais appelés **types** de façon cohérente dans l'interface du bilan et le guide utilisateur, pour éviter la confusion avec les *catégories* de transactions (un autre module). Le type « Encaisse » devient **Liquidités** et « Fonds commun » devient **Fonds / FNB**. Le terme *snapshot* est conservé mais glosé à son premier usage (#198). - Bilan : terminologie clarifiée. Les regroupements de comptes (Liquidités, CELI, REER, etc.) sont désormais appelés **types** de façon cohérente dans l'interface du bilan et le guide utilisateur, pour éviter la confusion avec les *catégories* de transactions (un autre module). Le type « Encaisse » devient **Liquidités** et « Fonds commun » devient **Fonds / FNB**. Le terme *snapshot* est conservé mais glosé à son premier usage (#198).
- Bilan : **un type est désormais une pure classe d'actif**. Les types standard sont les cinq classes d'actif — Liquidités, Fonds / FNB, Actions, Crypto, Autres. Les enveloppes fiscales qui étaient des types (CELI, REER) ne sont plus des types : elles ont migré vers le nouvel attribut d'enveloppe fiscale, porté par le compte. À la migration, les comptes CELI/REER existants sont reclassés dans la classe d'actif **Autres** tout en conservant leur enveloppe (`tfsa`/`rrsp`) ; les types seedés `tfsa`/`rrsp` sont désactivés et disparaissent des menus de types (migrations v12 + v13). Les nouveaux profils seedent cinq classes d'actif ; les comptes de départ CELI/REER passent sous *Autres* avec leur enveloppe renseignée. Vos montants et votre historique ne changent pas — seul le regroupement change (#202).
- Bilan : **note sur les bilans historiques**. L'axe « par classe d'actif » du graphique est recalculé sur le type *actuel* de chaque compte ; un snapshot saisi *avant* cette migration pour un ancien compte CELI/REER apparaît donc désormais sous **Autres** sur cet axe (il ne s'affiche plus sous « CELI »/« REER »). C'est attendu — le nouvel axe **par enveloppe** retrouve bien ces CELI/REER, et aucune valeur ni aucun historique n'est modifié (#204).
- Bilan : **renommer un type ne casse plus la traduction** (correction de bug). Renommer un type écrasait auparavant sa clé i18n avec le texte libre, cassant la traduction FR/EN. Le nom personnalisé est désormais stocké à part dans `balance_categories.custom_label`, et la clé de traduction d'origine n'est jamais touchée (et réapparaît si vous videz le nom personnalisé). La migration v12 récupère aussi, en défense, tout type seedé dont la clé de traduction aurait déjà été écrasée par un renommage antérieur (#202, #203).
### Corrigé ### Corrigé

View file

@ -5,10 +5,16 @@
### Added ### Added
- Balance: an existing snapshot's date can now be moved. The date field is editable in edit mode — change it and save, and the snapshot (with all its lines) is moved to the new date inside a single atomic transaction. If another snapshot already occupies the target date, the move is rejected with a clear message and nothing changes (#200). - Balance: an existing snapshot's date can now be moved. The date field is editable in edit mode — change it and save, and the snapshot (with all its lines) is moved to the new date inside a single atomic transaction. If another snapshot already occupies the target date, the move is rejected with a clear message and nothing changes (#200).
- Balance: **fiscal envelope on accounts**. An account can now carry an optional fiscal envelope (Non-registered, TFSA, RRSP, RRIF, FHSA, RESP — or none), set via a dropdown in the account form. This is a separate axis from the account's type (asset class), so an account holding stocks inside a TFSA is finally expressible — type *Stocks* + envelope *TFSA*. Migration v12 adds the nullable `balance_accounts.vehicle_type` column with a CHECK on the enum and backfills the former TFSA/RRSP accounts (#202, #203).
- Balance: **stacked-chart envelope axis**. The stacked evolution chart gains an axis sub-toggle — **By asset class** (default, unchanged behaviour) or **By envelope** (groups by fiscal envelope, with a "None" bucket for accounts without one). Read your net worth by what you hold *or* by where it's sheltered (#204).
- Balance: **collapsible return columns**. The accounts table's four Modified Dietz return columns (3M / 1Y / since inception / unadjusted) are now collapsed by default behind a show/hide toggle; the choice is persisted across sessions (`user_preferences.balance_show_returns`) to reduce visual noise for users who only track values (#204).
### Changed ### Changed
- Balance: clearer terminology. Account groupings (Cash, TFSA, RRSP, etc.) are now consistently called **types** across the balance UI and user guide, to avoid confusion with transaction *categories* (a separate module). The "Cash" type is now labelled **Cash** (FR: Liquidités) and "Mutual fund" becomes **Funds / ETF** (FR: Fonds / FNB). The wording of *snapshot* is unchanged but glossed on first use (#198). - Balance: clearer terminology. Account groupings (Cash, TFSA, RRSP, etc.) are now consistently called **types** across the balance UI and user guide, to avoid confusion with transaction *categories* (a separate module). The "Cash" type is now labelled **Cash** (FR: Liquidités) and "Mutual fund" becomes **Funds / ETF** (FR: Fonds / FNB). The wording of *snapshot* is unchanged but glossed on first use (#198).
- Balance: **a type is now a pure asset class**. The standard types are the five asset classes — Cash, Funds / ETF, Stocks, Crypto, Other. The fiscal envelopes that used to be types (TFSA, RRSP) are no longer types: they moved to the new per-account fiscal-envelope attribute. On migration, existing TFSA/RRSP accounts are reclassed to the **Other** asset class while carrying their envelope (`tfsa`/`rrsp`); the `tfsa`/`rrsp` seed types are deactivated and disappear from the type dropdowns (migrations v12 + v13). New profiles seed five asset classes; the TFSA/RRSP starter accounts now sit under *Other* with their envelope set. Your amounts and history are unchanged — only the grouping changes (#202).
- Balance: **historical reclass note**. The "by asset class" chart axis is recomputed on each account's *current* type, so a snapshot taken *before* this migration for a former TFSA/RRSP account now appears under **Other** on that axis (it no longer shows under "TFSA"/"RRSP"). This is expected — the new **by envelope** axis still surfaces those CELI/REER, and no value or history is altered (#204).
- Balance: **renaming a type no longer breaks the translation** (bug fix). Renaming a type used to overwrite its i18n key with the free text, clobbering the FR/EN translation. The custom name is now stored separately in `balance_categories.custom_label`, and the original translation key is never touched (and reappears if you clear the custom name). Migration v12 also defensively recovers any seed type whose translation key had already been clobbered by an earlier rename (#202, #203).
### Fixed ### Fixed

View file

@ -1,8 +1,11 @@
# ADR 0012 — Modèle à deux niveaux pour le Bilan (véhicules × compositions) # ADR 0012 — Modèle à deux niveaux pour le Bilan (véhicules × compositions)
- Status: Proposed - Status: **Rejected** (jamais accepté ; reste à l'état de proposition)
- Date: 2026-05-01 - Date: 2026-05-01 (proposé) · 2026-06-01 (rejeté)
- Issue: #179 - Issue: #179
- Rejeté au profit de : [ADR 0014](0014-balance-vehicule-attribut.md)
> **Rejet (2026-06-01).** L'audit Bilan (`docs/audit-bilan-2026-05.md`) a retenu une **trajectoire additive** plutôt que ce modèle à deux tables surdimensionné : l'ADR 0014 fait du véhicule fiscal un simple **attribut nullable du compte** (`vehicle_type`) et de la catégorie une **pure classe d'actif**, sans réécriture de `/balance` ni migration massive. Le grain visé par 0012 (triplet véhicule × *composition*) restait par ailleurs au niveau **classe d'actif**, pas **titre** — il déplaçait le mur sans débloquer le détail par titre. *Rejected* (et non *Superseded*) : 0012 n'a jamais quitté l'état `Proposed`, donc aucune décision active n'est remplacée. La réflexion sur les groupements croisés (`GROUP BY véhicule` / `GROUP BY classe d'actif`) reste valable et est reprise par 0014.
## Contexte ## Contexte

View file

@ -0,0 +1,104 @@
# ADR 0014 — Bilan : le véhicule fiscal est un attribut du compte, la classe d'actif est la catégorie
- Status: **Accepted**
- Date: 2026-06-01
- Rejette: ADR 0012 (modèle à deux niveaux véhicule × composition — voir « Alternatives » ci-dessous)
- Issues: #202 (couche données), #203 (UI saisie), #204 (UI suivi), #205 (cet ADR + doc)
- Audit source: [docs/audit-bilan-2026-05.md](../audit-bilan-2026-05.md)
## Contexte
L'audit critique de la page Bilan (`docs/audit-bilan-2026-05.md`, revue CPA + UX, 2026-05-31) a identifié une **racine unique** (finding A) derrière la plupart des frictions du module : le modèle est *plat*. Une seule « catégorie » (`balance_categories`) encodait simultanément **deux axes orthogonaux** :
- le **véhicule fiscal** / l'enveloppe : CELI, REER, non-enregistré… ;
- la **classe d'actif** : liquidités, fonds/FNB, actions, crypto, autres.
Les 7 catégories seedées par la migration v9 — `cash · tfsa · rrsp · fund · other · stock · crypto` — mélangeaient donc des frères/sœurs de natures incomparables. Conséquences directes mesurées par l'audit :
- **Cas québécois inexprimables** : suivre des actions *dans* un CELI force un choix dégradé (compte `simple` sous `tfsa` → le titre disparaît ; compte `priced` sous `stock` → l'abri CELI disparaît).
- **Empilé « par catégorie » illisible** (finding G) : ni « répartition par classe d'actif », ni « répartition par enveloppe » — un axe bâtard.
- **Bug i18n latent** (finding I) : renommer une catégorie via `window.prompt()` écrasait `i18n_key` avec du texte libre, cassant la traduction FR/EN — une promesse-socle du projet.
L'audit recommandait une **trajectoire additive en trois temps** (Étape 0 quick wins, déjà livrée en #201 ; Étape 1 séparer l'axe véhicule ; Étape 2 détail par titre) explicitement opposée au big-bang de l'ADR 0012. Le présent ADR documente la décision prise pour l'**Étape 1**.
### Pourquoi additif (et pas le modèle deux-tables de l'ADR 0012)
L'ADR 0012 proposait deux tables `balance_vehicles` × `balance_compositions` et une ligne de snapshot devenant un triplet `(vehicle_id, composition_id, value)`. C'est une réécriture quasi totale de `/balance` (grille de saisie 2D imposée à tous, dédoublement des agrégateurs, migration de données massive) pour un grain qui reste la **classe d'actif** — pas le **titre individuel** que l'investisseur attend réellement (audit : « l'ADR 0012 résout le mauvais grain »). L'approche retenue ajoute deux colonnes nullables, ne touche aucun compte simple existant, et garde la grille de saisie à une dimension.
## Décision
**Le véhicule fiscal devient un attribut du compte ; la catégorie devient une pure classe d'actif.**
1. **Nouvelle colonne `balance_accounts.vehicle_type`** — TEXT nullable, enveloppe fiscale, contrainte CHECK sur l'enum réduit courant :
| Code | FR | EN |
|---|---|---|
| `unregistered` | Non-enregistré | Non-registered |
| `tfsa` | CELI | TFSA |
| `rrsp` | REER | RRSP |
| `rrif` | FERR | RRIF |
| `fhsa` | CELIAPP | FHSA |
| `resp` | REEE | RESP |
⚠️ `vehicle_type` = enveloppe **fiscale**, jamais un véhicule automobile. Nullable : un compte chèque ou un wallet crypto n'a pas d'enveloppe (valeur `NULL`, et non `unregistered` — un compte courant n'est pas un placement non-enregistré).
2. **Les catégories sont 5 classes d'actif pures** : Liquidités, Fonds/FNB, Actions, Crypto, Autres. Les ex-catégories-véhicules `tfsa`/`rrsp` ne sont plus des catégories — elles deviennent des `vehicle_type`.
3. **Deux migrations additives** (jamais de modification d'une migration ≤ v11 — checksum SHA-384 sqlx) :
- **v12 (additive)** : ajoute `vehicle_type` (+ CHECK) et `balance_categories.custom_label` ; backfille `vehicle_type='tfsa'`/`'rrsp'` pour les comptes des ex-enveloppes ; les comptes `cash` restent `NULL`. Inclut un **backfill défensif du bug I** : toute catégorie seed dont `i18n_key` avait été écrasé par du texte libre récupère ce texte dans `custom_label`, et son `i18n_key` est restauré depuis `key`.
- **v13 (reclassement, conditionnelle/idempotente)** : re-rattache les comptes ex-`tfsa`/`rrsp` à la classe « Autres » (`other`), gardé par `EXISTS(other) AND is_seed=1` ; désactive (`is_active=0`) les seeds `tfsa`/`rrsp` devenus des véhicules. v12 stampe `vehicle_type` **avant** que v13 ne déplace `balance_category_id` (ordre garanti par le versioning sqlx).
- `consolidated_schema.sql` (profils neufs) et les comptes starter (consolidated + `STARTER_ACCOUNTS` service) sont synchronisés : CELI/REER pointent vers `other` + portent leur `vehicle_type`.
4. **Renommage de catégorie via `custom_label`** (corrige le bug I) : l'affichage suit la règle `custom_label?.trim() || t(i18n_key, { defaultValue: key })`, factorisée dans un helper `renderCategoryLabel`. Le renommage écrit `custom_label` et **ne touche plus jamais `i18n_key`** — la traduction FR/EN reste intacte.
5. **Deux axes de lecture** : le graphique empilé gagne un sous-toggle « Par classe d'actif » (défaut, = comportement existant) / « Par enveloppe » (`getSnapshotTotalsByVehicleAndDate`, bucket `COALESCE(vehicle_type,'none')`). Le tableau des comptes replie ses colonnes de rendement par défaut, avec un toggle dont l'état est persisté (`user_preferences.balance_show_returns`).
### Hors scope (Étape 2 — explicitement exclue de cette décision)
Le **détail par titre** reste hors scope et n'est *pas* tranché par cet ADR :
- pas de table `balance_securities` (symbole normalisé, devise, asset_type) ;
- pas de holdings/positions par titre sous un compte ;
- pas de `book_cost` / PRU (distinction apport vs gain latent) ;
- pas de migration du `kind` (`simple`/`priced`) de la catégorie vers le compte, donc pas encore d'assistant « détailler un compte agrégé en titres » sans rupture d'historique ;
- pas d'import CSV de cours local, pas de multi-devise (reste CAD), pas d'agrégation du rendement par véhicule.
L'Étape 2 fera l'objet d'un ADR distinct quand le besoin sera confirmé (gating de l'audit : trajectoire additive, pas de big-bang). L'Étape 1 ne **ferme aucune** de ces portes — elle pose l'axe véhicule sans présumer du grain titre.
## Alternatives considérées
- **ADR 0012 — modèle à deux niveaux `balance_vehicles` × `balance_compositions`** (rejeté, voir ci-dessus) : surdimensionné, grille 2D imposée, migration massive, grain « classe d'actif » et non « titre ».
- **Tagging multi-axes libre** (alternative A de l'ADR 0012) : aucune contrainte sur les combinaisons, rapports « actions dans CELI » coûteux, vocabulaire divergent entre profils.
- **Sous-comptes (`parent_id`)** (alternative B de l'ADR 0012) : invariant somme parent = somme enfants à maintenir, snapshots dédoublés sans gain expressif.
- **Statu quo** (modèle plat enrichi de catégories user `tfsa_stock`…) : explosion N×M de la taxonomie, friction documentée croissante.
L'attribut nullable sur le compte gagne sur les quatre : migration triviale (2 colonnes), zéro impact sur les comptes simples existants, deux groupements naturels (`GROUP BY category` / `GROUP BY vehicle_type`), et aucune porte fermée pour l'Étape 2.
## Consequences
### Positives
- **Cas québécois exprimables** : « combien dans mon CELI ? » se lit par `vehicle_type`, indépendamment de la classe d'actif détenue.
- **Empilé assaini** (finding G) : deux axes distincts et explicites, défaut « par classe d'actif » (zéro surprise vs l'existant).
- **Bug i18n corrigé** (finding I) : le renommage n'altère plus la traduction ; le backfill défensif v12 répare les profils déjà cassés.
- **Migration sûre** : purement additive, idempotente, gardée ; les comptes simples ne bougent jamais ; `snapshot_lines` référencent `account_id`**historique des valeurs préservé**.
- **Tableau dégonflé** (finding F) : rendements repliés par défaut, état persisté — moins de bruit pour le grand public.
### Négatives / risques actés
- **Historique re-affiché sous « Autres »** : l'axe « par classe d'actif » est recalculé sur la **catégorie courante** du compte. Un snapshot pré-migration d'un compte ex-CELI/REER apparaît donc désormais sous « Autres » (et non plus « CELI »/« REER »). **Comportement attendu**, documenté au CHANGELOG et au guide. La lecture par enveloppe, elle, retrouve bien le CELI/REER via `vehicle_type`.
- **Pas de migration Down** : v12/v13 sont idempotentes et conditionnelles ; toute correction passe par une v14 (jamais d'édition rétroactive).
- **Comptes ex-CELI/REER contenant de vraies actions** : restent un montant agrégé en « Autres » + leur `vehicle_type`. Le détail par titre est l'Étape 2 — non débloqué ici.
- **`vehicle_type` lu comme automobile** : risque d'ambiguïté de nommage (un agent d'exploration a déjà halluciné « car/truck »). Mitigé par le CHECK explicite, le commentaire de migration et la table d'enum ci-dessus.
### Neutre
- L'enum `vehicle_type` couvre le set courant (6 valeurs). Ajouter CRI, RPDB, etc. plus tard = une nouvelle migration qui élargit le CHECK (jamais une édition de v12).
## Liens
- [Audit Bilan 2026-05](../audit-bilan-2026-05.md) — racine (finding A), trajectoire additive en trois temps, recommandation sur l'ADR 0012
- [ADR 0012](0012-balance-two-level-model.md) — modèle à deux niveaux, **Rejected** au profit du présent ADR
- [ADR 0008](0008-modified-dietz-pour-rendement.md) — Modified Dietz par compte (modèle plat préservé : le rendement reste par compte)
- [ADR 0010](0010-fk-restrict-balance-transfers.md) — FK RESTRICT sur transferts (contrainte inchangée)
- Issues #202 / #203 / #204 / #205 — implémentation Étape 1

View file

@ -357,7 +357,13 @@ L'application est atomique : soit toutes les transactions cochées sont recatég
## 10. Bilan ## 10. Bilan
Le **Bilan** est une vue patrimoniale : vous saisissez périodiquement un *snapshot* (relevé daté de votre patrimoine) de l'ensemble de vos comptes (liquidités, REER, CELI, fonds, actions, crypto, autres), vous suivez leur évolution dans le temps, et vous calculez le **vrai rendement** de chaque compte d'investissement en liant les transferts (apports / retraits) aux comptes correspondants. Le **Bilan** est une vue patrimoniale : vous saisissez périodiquement un *snapshot* (relevé daté de votre patrimoine) de l'ensemble de vos comptes, vous suivez leur évolution dans le temps, et vous calculez le **vrai rendement** de chaque compte d'investissement en liant les transferts (apports / retraits) aux comptes correspondants.
Deux notions distinctes structurent le Bilan :
- la **classe d'actif** (le *type* du compte) — Liquidités, Fonds / FNB, Actions, Crypto, Autres ;
- l'**enveloppe fiscale** (le *véhicule*) — Non-enregistré, CELI, REER, FERR, CELIAPP, REEE.
Ce sont deux axes indépendants : un même CELI peut contenir des actions, des fonds et des liquidités. La classe d'actif est portée par le type du compte ; l'enveloppe fiscale est un attribut optionnel du compte. Vous pouvez ainsi lire votre patrimoine *par classe d'actif* OU *par enveloppe fiscale* (voir le graphique d'évolution).
Trois pages composent le module Bilan : Trois pages composent le module Bilan :
- `/balance` — vue d'ensemble (graphique + tableau des comptes) - `/balance` — vue d'ensemble (graphique + tableau des comptes)
@ -368,16 +374,17 @@ L'entrée **Bilan** dans la barre latérale (icône portefeuille) donne accès
### Fonctionnalités ### Fonctionnalités
- 7 types standard pré-installés : Liquidités, CELI, REER, Fonds / FNB, Actions, Crypto, Autres — renommables, non-supprimables (un *type* regroupe des comptes de même nature ; à ne pas confondre avec les catégories de transactions) - 5 types standard pré-installés, qui sont des **classes d'actif** : Liquidités, Fonds / FNB, Actions, Crypto, Autres — renommables, non-supprimables (un *type* regroupe des comptes de même nature ; à ne pas confondre avec les catégories de transactions). Les enveloppes fiscales (CELI, REER…) ne sont plus des types : ce sont désormais un attribut du compte (voir ci-dessous)
- Création de types personnalisés (ex. FERR, RPDB) avec choix `simple` (montant direct) ou `priced` (quantité × prix unitaire) - Création de types personnalisés avec choix `simple` (montant direct) ou `priced` (quantité × prix unitaire)
- Comptes par type : nom, symbole optionnel (même pour les types cotés — il ne sert qu'à la récupération automatique des prix), devise (CAD au MVP), notes - Comptes par type : nom, **enveloppe fiscale optionnelle** (Non-enregistré, CELI, REER, FERR, CELIAPP, REEE — ou aucune, par défaut), symbole optionnel (même pour les types cotés — il ne sert qu'à la récupération automatique des prix), devise (CAD au MVP), notes
- Renommage d'un type sans casser le bilingue : le nom personnalisé est stocké à part, la traduction FR/EN d'origine reste intacte (et réapparaît si vous videz le nom personnalisé)
- Snapshots datés avec contrainte UNIQUE par date — éditer = revenir sur la même date, jamais dupliquer ; la date d'un snapshot existant peut être déplacée (ses lignes sont conservées), tant qu'aucun autre snapshot n'occupe déjà la date cible - Snapshots datés avec contrainte UNIQUE par date — éditer = revenir sur la même date, jamais dupliquer ; la date d'un snapshot existant peut être déplacée (ses lignes sont conservées), tant qu'aucun autre snapshot n'occupe déjà la date cible
- Saisie groupée par type ; pour les types `priced`, le `value` est calculé automatiquement (`quantity × unit_price`) - Saisie groupée par type ; pour les types `priced`, le `value` est calculé automatiquement (`quantity × unit_price`)
- Bouton **Pré-remplir depuis le snapshot précédent** : copie les valeurs simples + les quantités priced (vous remplissez juste les nouveaux prix) - Bouton **Pré-remplir depuis le snapshot précédent** : copie les valeurs simples + les quantités priced (vous remplissez juste les nouveaux prix)
- Liaison de transactions existantes à un compte de bilan (modal avec filtres par période / catégorie / recherche, sens auto-proposé selon le signe) - Liaison de transactions existantes à un compte de bilan (modal avec filtres par période / catégorie / recherche, sens auto-proposé selon le signe)
- Icône d'attribution dans la page Transactions pour les transactions liées à un transfert - Icône d'attribution dans la page Transactions pour les transactions liées à un transfert
- Graphique d'évolution du bilan (mode courbe simple ou aire empilée par catégorie) avec marqueurs verticaux pour les transferts taggés (vert = in, rouge = out) - Graphique d'évolution du bilan : mode courbe simple, ou aire empilée avec un sous-choix d'axe — **Par classe d'actif** (défaut) ou **Par enveloppe** (fiscale). Marqueurs verticaux pour les transferts taggés (vert = in, rouge = out)
- Tableau des comptes avec **3 colonnes de rendement Modified Dietz** (3 mois / 1 an / depuis création) + colonne rendement non-ajusté côte-à-côte - Tableau des comptes avec **3 colonnes de rendement Modified Dietz** (3 mois / 1 an / depuis création) + colonne rendement non-ajusté côte-à-côte. Ces colonnes sont **repliées par défaut** (un bouton les affiche / les masque, votre choix est mémorisé d'une session à l'autre)
- Avertissement si le dernier snapshot remonte à plus de 60 jours - Avertissement si le dernier snapshot remonte à plus de 60 jours
- Soft-delete des comptes (`Archiver`) : masqués des nouveaux snapshots, conservés dans l'historique - Soft-delete des comptes (`Archiver`) : masqués des nouveaux snapshots, conservés dans l'historique
- Suppression d'un snapshot avec double-confirmation (re-saisie de la date) - Suppression d'un snapshot avec double-confirmation (re-saisie de la date)
@ -385,8 +392,8 @@ L'entrée **Bilan** dans la barre latérale (icône portefeuille) donne accès
### Comment faire ### Comment faire
1. Allez dans `/balance/accounts` → onglet Types pour créer si besoin un type supplémentaire (ex. "FERR" en `simple`, ou "Stocks Wealthsimple" en `priced`) 1. Allez dans `/balance/accounts` → onglet Types pour créer si besoin une classe d'actif supplémentaire en `simple` (montant direct) ou `priced` (quantité × prix unitaire). Pour renommer un type standard, double-cliquez son nom — la traduction d'origine est préservée
2. Allez dans l'onglet Comptes pour créer chaque compte (ex. "TFSA Tangerine" rattaché à CELI, "BTC Ledger" rattaché à Crypto avec symbole `BTC` — le symbole reste optionnel) 2. Allez dans l'onglet Comptes pour créer chaque compte (ex. "Tangerine" rattaché à Liquidités, "BTC Ledger" rattaché à Crypto avec symbole `BTC` — le symbole reste optionnel). Si le compte est logé dans une enveloppe fiscale, choisissez-la dans le menu **Enveloppe fiscale** (ex. un compte d'actions dans un CELI : type Actions + enveloppe CELI) ; laissez sur « Aucune » pour un compte courant ou un wallet
3. Cliquez **+ Nouveau snapshot** depuis `/balance` pour ouvrir `/balance/snapshot` à la date du jour 3. Cliquez **+ Nouveau snapshot** depuis `/balance` pour ouvrir `/balance/snapshot` à la date du jour
4. Remplissez les valeurs par compte (groupées par catégorie). Pour les comptes priced, saisissez la quantité et le prix unitaire — la valeur est calculée 4. Remplissez les valeurs par compte (groupées par catégorie). Pour les comptes priced, saisissez la quantité et le prix unitaire — la valeur est calculée
5. Enregistrez. Le graphique sur `/balance` s'actualise immédiatement 5. Enregistrez. Le graphique sur `/balance` s'actualise immédiatement
@ -415,7 +422,8 @@ C'est intentionnellement bloqué : si vous tentez de supprimer une transaction q
- Saisissez vos snapshots à un rythme régulier (mensuel ou trimestriel) — la qualité des rendements dépend directement de la régularité - Saisissez vos snapshots à un rythme régulier (mensuel ou trimestriel) — la qualité des rendements dépend directement de la régularité
- Utilisez le bouton **Pré-remplir** : ça copie tout, vous mettez juste à jour ce qui a changé - Utilisez le bouton **Pré-remplir** : ça copie tout, vous mettez juste à jour ce qui a changé
- Le mode **graphique empilé par catégorie** raconte une histoire différente du mode ligne : il montre la composition de votre patrimoine, pas seulement son total - Le mode **graphique empilé** raconte une histoire différente du mode ligne : il montre la composition de votre patrimoine, pas seulement son total. Basculez l'axe entre **Par classe d'actif** (combien en actions, en liquidités…) et **Par enveloppe** (combien en CELI, en REER, hors enveloppe…) pour lire les deux faces du même patrimoine
- **Note pour les bilans historiques.** Depuis la version qui sépare classe d'actif et enveloppe fiscale, les anciens types « CELI » et « REER » sont devenus des **enveloppes**, et les comptes concernés ont été reclassés en classe d'actif **« Autres »** (en conservant leur enveloppe). L'axe « par classe d'actif » étant recalculé sur la classe **actuelle** du compte, un snapshot saisi *avant* cette migration apparaît désormais sous « Autres » sur cet axe (et non plus sous « CELI »/« REER »). C'est attendu : l'axe **« par enveloppe »**, lui, retrouve bien vos CELI / REER. Vos montants et votre historique ne changent pas — seul le regroupement d'affichage évolue
- Les marqueurs verticaux du graphique (transferts taggés) aident à lire les sauts de valeur — un saut suivi d'un marqueur vert n'est pas une "performance", c'est juste un dépôt - Les marqueurs verticaux du graphique (transferts taggés) aident à lire les sauts de valeur — un saut suivi d'un marqueur vert n'est pas une "performance", c'est juste un dépôt
- L'avertissement "bilan pas à jour" apparaît si votre dernier snapshot remonte à plus de 60 jours — c'est le signe qu'il est temps d'en saisir un nouveau - L'avertissement "bilan pas à jour" apparaît si votre dernier snapshot remonte à plus de 60 jours — c'est le signe qu'il est temps d'en saisir un nouveau
- (À venir Phase 5) **Récupération automatique des prix** pour les comptes Actions / Crypto via un proxy privé (premium-only). Le service interroge un serveur Maximus dédié qui anonymise votre requête (votre IP n'est jamais exposée à Yahoo / CoinGecko). La saisie manuelle reste toujours disponible. - (À venir Phase 5) **Récupération automatique des prix** pour les comptes Actions / Crypto via un proxy privé (premium-only). Le service interroge un serveur Maximus dédié qui anonymise votre requête (votre IP n'est jamais exposée à Yahoo / CoinGecko). La saisie manuelle reste toujours disponible.

View file

@ -945,25 +945,26 @@
}, },
"balance": { "balance": {
"title": "Balance Sheet", "title": "Balance Sheet",
"overview": "The Balance Sheet is a net-worth view: you periodically enter a dated snapshot of all your accounts (cash, RRSP, TFSA, funds, stocks, crypto, other), track their evolution over time, and compute the true return of each investment account by linking transfers (deposits/withdrawals) to the matching accounts.", "overview": "The Balance Sheet is a net-worth view: you periodically enter a dated snapshot of all your accounts, track their evolution over time, and compute the true return of each investment account by linking transfers (deposits/withdrawals) to the matching accounts. Two independent axes: the asset class (the account's type: Cash, Funds / ETF, Stocks, Crypto, Other) and the fiscal envelope (an optional account attribute: TFSA, RRSP, RRIF, FHSA, RESP, or none).",
"features": [ "features": [
"7 standard types pre-installed (Cash, TFSA, RRSP, Funds / ETF, Stock, Crypto, Other) — renameable, non-deletable; a type groups accounts of the same nature (distinct from transaction categories)", "5 standard types pre-installed, which are asset classes (Cash, Funds / ETF, Stocks, Crypto, Other) — renameable, non-deletable; a type groups accounts of the same nature (distinct from transaction categories). Fiscal envelopes are no longer types",
"Custom type creation with simple (direct amount) or priced (quantity × unit price) entry mode", "Custom type creation with simple (direct amount) or priced (quantity × unit price) entry mode",
"Accounts per type: name, optional symbol (even for priced types — it only drives automatic price fetching), currency (CAD at MVP), notes", "Accounts per type: name, optional fiscal envelope (Non-registered, TFSA, RRSP, RRIF, FHSA, RESP, or none by default), optional symbol (even for priced types — it only drives automatic price fetching), currency (CAD at MVP), notes",
"Renaming a type no longer breaks bilingual support: the custom name is stored separately, the original FR/EN translation is preserved",
"Dated snapshots with a UNIQUE constraint per date — editing means revisiting the same date, never duplicating; an existing snapshot's date can be moved (lines preserved) when the target date is free", "Dated snapshots with a UNIQUE constraint per date — editing means revisiting the same date, never duplicating; an existing snapshot's date can be moved (lines preserved) when the target date is free",
"\"Prefill from previous snapshot\" button: copies simple values + priced quantities", "\"Prefill from previous snapshot\" button: copies simple values + priced quantities",
"Linking existing transactions to a balance account (modal with filters and auto-suggested direction)", "Linking existing transactions to a balance account (modal with filters and auto-suggested direction)",
"Attribution icon in the Transactions page for transactions linked to a transfer", "Attribution icon in the Transactions page for transactions linked to a transfer",
"Evolution chart with line or stacked-area-by-type mode + vertical markers for tagged transfers (green = in, red = out)", "Evolution chart with line or stacked-area mode, with an axis sub-toggle: by asset class (default) or by envelope + vertical markers for tagged transfers (green = in, red = out)",
"Accounts table with 3 Modified Dietz return columns (3M / 1Y / since inception) + side-by-side unadjusted return column", "Accounts table with 3 Modified Dietz return columns (3M / 1Y / since inception) + side-by-side unadjusted return column, collapsed by default (toggle, choice remembered)",
"Warning if the latest snapshot is more than 60 days old", "Warning if the latest snapshot is more than 60 days old",
"Soft-delete of accounts (Archive) — hidden from new snapshots, preserved in history", "Soft-delete of accounts (Archive) — hidden from new snapshots, preserved in history",
"Snapshot deletion with double-confirmation by retyping the date", "Snapshot deletion with double-confirmation by retyping the date",
"Privacy-first: everything stays local, no outbound calls at MVP" "Privacy-first: everything stays local, no outbound calls at MVP"
], ],
"steps": [ "steps": [
"Go to /balance/accounts → Types tab to create an extra type if needed (RRIF as simple, or Stocks Wealthsimple as priced)", "Go to /balance/accounts → Types tab to create an extra asset class if needed, as simple (direct amount) or priced (quantity × unit price)",
"Go to the Accounts tab to create each account (TFSA Tangerine under TFSA, BTC Ledger under Crypto with symbol BTC — the symbol stays optional)", "Go to the Accounts tab to create each account (Tangerine under Cash, BTC Ledger under Crypto with symbol BTC — optional). Pick the fiscal envelope if the account sits in a TFSA/RRSP/etc., or leave it on \"None\"",
"Click \"+ New snapshot\" from /balance to open /balance/snapshot at today's date", "Click \"+ New snapshot\" from /balance to open /balance/snapshot at today's date",
"Fill in values per account (grouped by type). For priced accounts, enter quantity and unit price — value is computed", "Fill in values per account (grouped by type). For priced accounts, enter quantity and unit price — value is computed",
"Save. The chart on /balance refreshes immediately", "Save. The chart on /balance refreshes immediately",
@ -978,7 +979,8 @@
"Vertical chart markers help you read value jumps: a jump followed by a green marker isn't \"performance\", it's a deposit", "Vertical chart markers help you read value jumps: a jump followed by a green marker isn't \"performance\", it's a deposit",
"If you try to delete a transaction linked to a balance account, the app asks you to unlink it first — this friction preserves the reproducibility of past returns", "If you try to delete a transaction linked to a balance account, the app asks you to unlink it first — this friction preserves the reproducibility of past returns",
"The \"balance out of date\" warning appears if your latest snapshot is more than 60 days old", "The \"balance out of date\" warning appears if your latest snapshot is more than 60 days old",
"(Coming in Phase 5) Automatic price fetching for Stocks/Crypto via a private proxy (premium-only) that anonymizes your request — manual entry remains always available" "(Coming in Phase 5) Automatic price fetching for Stocks/Crypto via a private proxy (premium-only) that anonymizes your request — manual entry remains always available",
"Toggle the stacked chart axis between \"by asset class\" and \"by envelope\" to read both sides of your net worth. Note: a snapshot taken before the class/envelope split shows under \"Other\" on the by-asset-class axis (the former TFSA/RRSP types became envelopes) — this is expected; the by-envelope axis still surfaces your TFSA/RRSP, and your amounts are unchanged"
] ]
}, },
"settings": { "settings": {

View file

@ -945,25 +945,26 @@
}, },
"balance": { "balance": {
"title": "Bilan", "title": "Bilan",
"overview": "Le Bilan est une vue patrimoniale : vous saisissez périodiquement un snapshot (relevé daté de votre patrimoine) de l'ensemble de vos comptes (liquidités, REER, CELI, fonds, actions, crypto, autres), suivez leur évolution dans le temps et calculez le vrai rendement de chaque compte d'investissement en liant les transferts (apports/retraits) aux comptes correspondants.", "overview": "Le Bilan est une vue patrimoniale : vous saisissez périodiquement un snapshot (relevé daté de votre patrimoine) de l'ensemble de vos comptes, suivez leur évolution dans le temps et calculez le vrai rendement de chaque compte d'investissement en liant les transferts (apports/retraits) aux comptes correspondants. Deux axes indépendants : la classe d'actif (le type du compte : Liquidités, Fonds / FNB, Actions, Crypto, Autres) et l'enveloppe fiscale (un attribut optionnel du compte : CELI, REER, FERR, CELIAPP, REEE, ou aucune).",
"features": [ "features": [
"7 types standard pré-installés (Liquidités, CELI, REER, Fonds / FNB, Actions, Crypto, Autres) — renommables, non-supprimables ; un type regroupe des comptes de même nature (distinct des catégories de transactions)", "5 types standard pré-installés, qui sont des classes d'actif (Liquidités, Fonds / FNB, Actions, Crypto, Autres) — renommables, non-supprimables ; un type regroupe des comptes de même nature (distinct des catégories de transactions). Les enveloppes fiscales ne sont plus des types",
"Création de types personnalisés avec choix simple (montant direct) ou priced (quantité × prix unitaire)", "Création de types personnalisés avec choix simple (montant direct) ou priced (quantité × prix unitaire)",
"Comptes par type : nom, symbole optionnel (même pour les types cotés, il ne sert qu'à la récupération automatique des prix), devise (CAD au MVP), notes", "Comptes par type : nom, enveloppe fiscale optionnelle (Non-enregistré, CELI, REER, FERR, CELIAPP, REEE, ou aucune par défaut), symbole optionnel (même pour les types cotés, il ne sert qu'à la récupération automatique des prix), devise (CAD au MVP), notes",
"Renommer un type ne casse plus le bilingue : le nom personnalisé est stocké à part, la traduction FR/EN d'origine est préservée",
"Snapshots datés avec contrainte UNIQUE par date — éditer = revenir sur la même date, jamais dupliquer ; la date d'un snapshot existant peut être déplacée (lignes conservées) si la date cible est libre", "Snapshots datés avec contrainte UNIQUE par date — éditer = revenir sur la même date, jamais dupliquer ; la date d'un snapshot existant peut être déplacée (lignes conservées) si la date cible est libre",
"Bouton « Pré-remplir depuis le snapshot précédent » : copie les valeurs simples + les quantités priced", "Bouton « Pré-remplir depuis le snapshot précédent » : copie les valeurs simples + les quantités priced",
"Liaison de transactions existantes à un compte de bilan (modal avec filtres et sens auto-proposé)", "Liaison de transactions existantes à un compte de bilan (modal avec filtres et sens auto-proposé)",
"Icône d'attribution dans la page Transactions pour les transactions liées à un transfert", "Icône d'attribution dans la page Transactions pour les transactions liées à un transfert",
"Graphique d'évolution avec mode courbe ou aire empilée par type + marqueurs verticaux pour les transferts (vert = in, rouge = out)", "Graphique d'évolution avec mode courbe ou aire empilée, avec un sous-choix d'axe : par classe d'actif (défaut) ou par enveloppe + marqueurs verticaux pour les transferts (vert = in, rouge = out)",
"Tableau des comptes avec 3 colonnes de rendement Modified Dietz (3M / 1A / depuis création) + colonne rendement non-ajusté côte-à-côte", "Tableau des comptes avec 3 colonnes de rendement Modified Dietz (3M / 1A / depuis création) + colonne rendement non-ajusté côte-à-côte, repliées par défaut (toggle, choix mémorisé)",
"Avertissement si le dernier snapshot remonte à plus de 60 jours", "Avertissement si le dernier snapshot remonte à plus de 60 jours",
"Soft-delete des comptes (Archiver) — masqués des nouveaux snapshots, conservés dans l'historique", "Soft-delete des comptes (Archiver) — masqués des nouveaux snapshots, conservés dans l'historique",
"Suppression d'un snapshot avec double-confirmation par re-saisie de la date", "Suppression d'un snapshot avec double-confirmation par re-saisie de la date",
"Privacy-first : tout est local, aucun appel sortant au MVP" "Privacy-first : tout est local, aucun appel sortant au MVP"
], ],
"steps": [ "steps": [
"Allez dans /balance/accounts → onglet Types pour créer si besoin un type supplémentaire (FERR en simple, ou Stocks Wealthsimple en priced)", "Allez dans /balance/accounts → onglet Types pour créer si besoin une classe d'actif supplémentaire en simple (montant direct) ou priced (quantité × prix unitaire)",
"Allez dans l'onglet Comptes pour créer chaque compte (TFSA Tangerine rattaché à CELI, BTC Ledger rattaché à Crypto avec symbole BTC — le symbole reste optionnel)", "Allez dans l'onglet Comptes pour créer chaque compte (Tangerine rattaché à Liquidités, BTC Ledger rattaché à Crypto avec symbole BTC — optionnel). Choisissez l'enveloppe fiscale si le compte est logé dans un CELI/REER/etc., ou laissez « Aucune »",
"Cliquez « + Nouveau snapshot » depuis /balance pour ouvrir /balance/snapshot à la date du jour", "Cliquez « + Nouveau snapshot » depuis /balance pour ouvrir /balance/snapshot à la date du jour",
"Remplissez les valeurs par compte (groupées par type). Pour les comptes priced, saisissez la quantité et le prix unitaire — la valeur est calculée", "Remplissez les valeurs par compte (groupées par type). Pour les comptes priced, saisissez la quantité et le prix unitaire — la valeur est calculée",
"Enregistrez. Le graphique sur /balance s'actualise immédiatement", "Enregistrez. Le graphique sur /balance s'actualise immédiatement",
@ -978,7 +979,8 @@
"Les marqueurs verticaux du graphique aident à lire les sauts de valeur : un saut suivi d'un marqueur vert n'est pas une « performance », c'est un dépôt", "Les marqueurs verticaux du graphique aident à lire les sauts de valeur : un saut suivi d'un marqueur vert n'est pas une « performance », c'est un dépôt",
"Si vous tentez de supprimer une transaction liée à un compte de bilan, l'app vous demande de la délier d'abord — cette friction préserve la reproductibilité de vos rendements passés", "Si vous tentez de supprimer une transaction liée à un compte de bilan, l'app vous demande de la délier d'abord — cette friction préserve la reproductibilité de vos rendements passés",
"L'avertissement « bilan pas à jour » apparaît si votre dernier snapshot remonte à plus de 60 jours", "L'avertissement « bilan pas à jour » apparaît si votre dernier snapshot remonte à plus de 60 jours",
"(À venir Phase 5) Récupération automatique des prix pour Actions/Crypto via un proxy privé (premium-only) qui anonymise votre requête — la saisie manuelle reste toujours disponible" "(À venir Phase 5) Récupération automatique des prix pour Actions/Crypto via un proxy privé (premium-only) qui anonymise votre requête — la saisie manuelle reste toujours disponible",
"Basculez l'axe du graphique empilé entre « par classe d'actif » et « par enveloppe » pour lire les deux faces du patrimoine. Note : un snapshot saisi avant la séparation classe/enveloppe apparaît sous « Autres » sur l'axe par classe d'actif (les ex-types CELI/REER sont devenus des enveloppes) — c'est attendu, l'axe par enveloppe retrouve bien vos CELI/REER, vos montants ne changent pas"
] ]
}, },
"settings": { "settings": {