feat(balance): schema migration v9 + service skeleton + AccountsPage (#138) #147
4 changed files with 196 additions and 0 deletions
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
## [Non publié]
|
||||
|
||||
### Ajouté
|
||||
- **Bilan — fondations du schéma et page Comptes** (route `/balance/accounts`) : première tranche de la nouvelle feature *Bilan*. La migration SQL v9 introduit 5 tables (`balance_categories`, `balance_accounts`, `balance_snapshots`, `balance_snapshot_lines`, `balance_account_transfers`) avec 7 index et seede 7 catégories standard — Encaisse, CELI, REER, Fonds commun, Autre (type simple) + Action et Cryptomonnaie (type coté). La colonne `currency` est verrouillée à `CAD` via une contrainte CHECK au MVP — le support multi-devises arrivera plus tard. La nouvelle page expose deux onglets : *Comptes* (CRUD complet sur les comptes de l'utilisateur, archivage soft plutôt que suppression dure pour préserver les snapshots historiques) et *Catégories* (renommer une catégorie, créer des catégories de type simple, supprimer celles créées par l'utilisateur — les catégories standard sont protégées). Couverture i18n FR/EN complète sous `balance.*`. Snapshots, transferts, rendements et price-fetching premium arriveront dans les prochaines issues ; pour l'instant la route est accessible directement par URL (pas encore d'entrée sidebar) (#138)
|
||||
|
||||
### Corrigé
|
||||
- **Rapport Zoom catégorie** (`/reports/category`) : la liste déroulante du combobox des catégories affiche désormais la liste complète dans un ordre hiérarchique DFS correct — chaque racine est émise avant ses descendants, et les frères et sœurs sont triés par `sort_order` puis nom affiché. Auparavant la liste était triée globalement par `sort_order` (via un `ORDER BY sort_order, name` SQL), ce qui entrelaçait des parents et enfants de sous-arbres différents partageant le même `sort_order`, d'où l'indentation incohérente et l'impression d'arbre cassé. La recherche filtrée (insensible aux accents) conserve le même comportement (#126)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- **Balance sheet — schema foundation and accounts page** (route `/balance/accounts`): first slice of the upcoming *Bilan* feature. New SQL migration v9 introduces 5 tables (`balance_categories`, `balance_accounts`, `balance_snapshots`, `balance_snapshot_lines`, `balance_account_transfers`) with 7 indexes and seeds 7 standard categories — Cash, TFSA, RRSP, Mutual Fund, Other (simple kind) plus Stock and Crypto (priced kind). The `currency` column is hardcoded to `CAD` via a CHECK constraint at the MVP — multi-currency support will come in a later release. The new accounts page exposes two tabs: *Accounts* (full CRUD over the user's holdings, soft-archive instead of hard delete to preserve historic snapshots) and *Categories* (rename any category, create simple-kind ones, delete user-created ones — seeded categories are protected). The full FR/EN i18n coverage uses keys under `balance.*`. Snapshots, transfers, returns and the price-fetching premium remain to ship in upcoming issues; for now the route is reachable directly via URL (no sidebar entry yet) (#138)
|
||||
|
||||
### Fixed
|
||||
- **Category zoom report** (`/reports/category`): the category combobox dropdown now renders the full list in proper hierarchical DFS order — each root is emitted before its descendants, with siblings sorted by `sort_order` then display name. Previously the list was ordered by `sort_order` globally (from a SQL `ORDER BY sort_order, name`), which interleaved parents and children from different sub-trees that shared the same `sort_order`, producing scrambled indentation and a mis-leading tree. Filtering (accent-insensitive search) still behaves identically (#126)
|
||||
|
||||
|
|
|
|||
|
|
@ -1449,5 +1449,100 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"balance": {
|
||||
"accountsPage": {
|
||||
"title": "Balance accounts",
|
||||
"tabs": {
|
||||
"accounts": "Accounts",
|
||||
"categories": "Categories"
|
||||
},
|
||||
"newAccount": "New account",
|
||||
"includeArchived": "Show archived accounts",
|
||||
"empty": "No accounts yet. Click “New account” to start."
|
||||
},
|
||||
"account": {
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"category": "Category",
|
||||
"symbol": "Symbol",
|
||||
"currency": "Currency",
|
||||
"status": "Status",
|
||||
"actions": "Actions"
|
||||
},
|
||||
"status": {
|
||||
"active": "Active",
|
||||
"archived": "Archived"
|
||||
},
|
||||
"actions": {
|
||||
"archive": "Archive",
|
||||
"unarchive": "Restore"
|
||||
},
|
||||
"form": {
|
||||
"createTitle": "New account",
|
||||
"editTitle": "Edit account",
|
||||
"category": "Category",
|
||||
"noCategory": "(no category available)",
|
||||
"name": "Account name",
|
||||
"nameRequired": "Name is required.",
|
||||
"symbol": "Symbol",
|
||||
"symbolPricedHint": "required for priced categories",
|
||||
"symbolPlaceholderSimple": "Optional",
|
||||
"symbolPlaceholderPriced": "e.g. AAPL, BTC-USD",
|
||||
"notes": "Notes",
|
||||
"currencyMvpNotice": "At the MVP, all accounts are in CAD. Multi-currency support will land in a later version.",
|
||||
"save": "Save",
|
||||
"create": "Create account"
|
||||
}
|
||||
},
|
||||
"category": {
|
||||
"intro": "Seeded categories (TFSA, RRSP, Cash, etc.) ship with the app. You can create your own for special cases.",
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"key": "Key",
|
||||
"kind": "Kind",
|
||||
"origin": "Origin",
|
||||
"actions": "Actions"
|
||||
},
|
||||
"kind": {
|
||||
"simple": "Direct amount",
|
||||
"priced": "Quantity × price"
|
||||
},
|
||||
"origin": {
|
||||
"seeded": "Standard",
|
||||
"user": "Custom"
|
||||
},
|
||||
"actions": {
|
||||
"create": "New category",
|
||||
"renamePrompt": "New label for this category",
|
||||
"deleteConfirm": "Delete this category? This cannot be undone.",
|
||||
"deleteSeedHint": "Standard categories cannot be deleted."
|
||||
},
|
||||
"form": {
|
||||
"createTitle": "New category",
|
||||
"key": "Key",
|
||||
"keyPlaceholder": "e.g. lira, prpp",
|
||||
"label": "Label",
|
||||
"labelPlaceholder": "e.g. LIRA, PRPP",
|
||||
"simpleOnlyNotice": "Priced categories (stocks, crypto) will be available in a future release.",
|
||||
"create": "Create category"
|
||||
},
|
||||
"cash": "Cash",
|
||||
"tfsa": "TFSA",
|
||||
"rrsp": "RRSP",
|
||||
"fund": "Mutual fund",
|
||||
"other": "Other",
|
||||
"stock": "Stock",
|
||||
"crypto": "Crypto"
|
||||
},
|
||||
"errors": {
|
||||
"currency_unsupported": "Only CAD is supported at the MVP.",
|
||||
"category_seed_protected": "Standard categories cannot be deleted.",
|
||||
"category_has_accounts": "Cannot delete a category with linked accounts. Move or archive linked accounts first.",
|
||||
"category_not_found": "Category not found.",
|
||||
"account_not_found": "Account not found.",
|
||||
"name_required": "Name is required.",
|
||||
"kind_invalid": "Invalid category kind."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1449,5 +1449,100 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"balance": {
|
||||
"accountsPage": {
|
||||
"title": "Comptes du bilan",
|
||||
"tabs": {
|
||||
"accounts": "Comptes",
|
||||
"categories": "Catégories"
|
||||
},
|
||||
"newAccount": "Nouveau compte",
|
||||
"includeArchived": "Afficher les comptes archivés",
|
||||
"empty": "Aucun compte pour l'instant. Cliquez sur « Nouveau compte » pour commencer."
|
||||
},
|
||||
"account": {
|
||||
"fields": {
|
||||
"name": "Nom",
|
||||
"category": "Catégorie",
|
||||
"symbol": "Symbole",
|
||||
"currency": "Devise",
|
||||
"status": "Statut",
|
||||
"actions": "Actions"
|
||||
},
|
||||
"status": {
|
||||
"active": "Actif",
|
||||
"archived": "Archivé"
|
||||
},
|
||||
"actions": {
|
||||
"archive": "Archiver",
|
||||
"unarchive": "Restaurer"
|
||||
},
|
||||
"form": {
|
||||
"createTitle": "Nouveau compte",
|
||||
"editTitle": "Modifier le compte",
|
||||
"category": "Catégorie",
|
||||
"noCategory": "(aucune catégorie disponible)",
|
||||
"name": "Nom du compte",
|
||||
"nameRequired": "Le nom est obligatoire.",
|
||||
"symbol": "Symbole",
|
||||
"symbolPricedHint": "obligatoire pour cette catégorie cotée",
|
||||
"symbolPlaceholderSimple": "Optionnel",
|
||||
"symbolPlaceholderPriced": "ex. AAPL, BTC-USD",
|
||||
"notes": "Notes",
|
||||
"currencyMvpNotice": "Au MVP, tous les comptes sont en CAD. Le support multi-devises arrivera dans une version ultérieure.",
|
||||
"save": "Enregistrer",
|
||||
"create": "Créer le compte"
|
||||
}
|
||||
},
|
||||
"category": {
|
||||
"intro": "Les catégories seedées (CELI, REER, Encaisse, etc.) sont fournies par l'application. Vous pouvez en créer de nouvelles pour vos cas particuliers.",
|
||||
"fields": {
|
||||
"name": "Nom",
|
||||
"key": "Clé",
|
||||
"kind": "Type",
|
||||
"origin": "Origine",
|
||||
"actions": "Actions"
|
||||
},
|
||||
"kind": {
|
||||
"simple": "Montant direct",
|
||||
"priced": "Quantité × prix"
|
||||
},
|
||||
"origin": {
|
||||
"seeded": "Standard",
|
||||
"user": "Personnalisée"
|
||||
},
|
||||
"actions": {
|
||||
"create": "Nouvelle catégorie",
|
||||
"renamePrompt": "Nouveau libellé pour cette catégorie",
|
||||
"deleteConfirm": "Supprimer cette catégorie ? Cette action est irréversible.",
|
||||
"deleteSeedHint": "Les catégories standard ne peuvent pas être supprimées."
|
||||
},
|
||||
"form": {
|
||||
"createTitle": "Nouvelle catégorie",
|
||||
"key": "Clé",
|
||||
"keyPlaceholder": "ex. ferr, rpdb",
|
||||
"label": "Libellé",
|
||||
"labelPlaceholder": "ex. FERR, RPDB",
|
||||
"simpleOnlyNotice": "Les catégories cotées (actions, crypto) seront disponibles dans une prochaine version.",
|
||||
"create": "Créer la catégorie"
|
||||
},
|
||||
"cash": "Encaisse",
|
||||
"tfsa": "CELI",
|
||||
"rrsp": "REER",
|
||||
"fund": "Fonds commun",
|
||||
"other": "Autre",
|
||||
"stock": "Action",
|
||||
"crypto": "Cryptomonnaie"
|
||||
},
|
||||
"errors": {
|
||||
"currency_unsupported": "Seul le CAD est supporté au MVP.",
|
||||
"category_seed_protected": "Les catégories standard ne peuvent pas être supprimées.",
|
||||
"category_has_accounts": "Impossible de supprimer une catégorie avec des comptes liés. Déplacez ou archivez d'abord les comptes liés.",
|
||||
"category_not_found": "Catégorie introuvable.",
|
||||
"account_not_found": "Compte introuvable.",
|
||||
"name_required": "Le nom est obligatoire.",
|
||||
"kind_invalid": "Type de catégorie invalide."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue