feat(prices): i18n FR/EN keys + CHANGELOG entries (#160) #163

Merged
maximus merged 1 commit from issue-160-i18n-changelog into main 2026-04-28 01:06:31 +00:00
4 changed files with 72 additions and 0 deletions

View file

@ -11,6 +11,8 @@
- **Bilan — éditeur de snapshot (type simple)** (route `/balance/snapshot`) : deuxième tranche de la feature *Bilan*. La nouvelle page permet de créer ou modifier un snapshot daté de votre patrimoine : choisissez une date (par défaut aujourd'hui), saisissez la valeur de chaque compte actif groupé par catégorie, puis enregistrez. Le mode est piloté par le paramètre `?date=` de l'URL — si un snapshot existe déjà à cette date, la page bascule automatiquement en mode édition (la contrainte UNIQUE sur `balance_snapshots.snapshot_date` garantit un snapshot par jour). La date d'un snapshot existant est immuable : pour la changer, supprimez puis recréez. Un bouton *Pré-remplir depuis le précédent* copie les valeurs du snapshot antérieur le plus récent (comptes simples uniquement — les comptes cotés seront pris en charge quand l'éditeur coté arrivera). Un bouton *Supprimer* affiche une modal de double confirmation qui exige de retaper la date du snapshot avant d'activer l'action destructive. Seules les valeurs de type simple sont acceptées à ce stade (`quantity` et `unit_price` sont laissés `NULL`) ; l'éditeur coté (quantité × prix unitaire + récupération de prix) arrivera dans une prochaine version. Nouveau hook `useSnapshotEditor` (`useReducer` couvrant tout le cycle de vie) et deux nouveaux composants `SnapshotEditor` + `SnapshotLineRow`. i18n FR/EN sous `balance.snapshot.*` (#146) - **Bilan — éditeur de snapshot (type simple)** (route `/balance/snapshot`) : deuxième tranche de la feature *Bilan*. La nouvelle page permet de créer ou modifier un snapshot daté de votre patrimoine : choisissez une date (par défaut aujourd'hui), saisissez la valeur de chaque compte actif groupé par catégorie, puis enregistrez. Le mode est piloté par le paramètre `?date=` de l'URL — si un snapshot existe déjà à cette date, la page bascule automatiquement en mode édition (la contrainte UNIQUE sur `balance_snapshots.snapshot_date` garantit un snapshot par jour). La date d'un snapshot existant est immuable : pour la changer, supprimez puis recréez. Un bouton *Pré-remplir depuis le précédent* copie les valeurs du snapshot antérieur le plus récent (comptes simples uniquement — les comptes cotés seront pris en charge quand l'éditeur coté arrivera). Un bouton *Supprimer* affiche une modal de double confirmation qui exige de retaper la date du snapshot avant d'activer l'action destructive. Seules les valeurs de type simple sont acceptées à ce stade (`quantity` et `unit_price` sont laissés `NULL`) ; l'éditeur coté (quantité × prix unitaire + récupération de prix) arrivera dans une prochaine version. Nouveau hook `useSnapshotEditor` (`useReducer` couvrant tout le cycle de vie) et deux nouveaux composants `SnapshotEditor` + `SnapshotLineRow`. i18n FR/EN sous `balance.snapshot.*` (#146)
- **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) - **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)
- **Récupération de prix premium pour actions (best-effort) et crypto (exchanges directs)** — vie privée préservée via proxy maximus-api. Toggle dans les Paramètres pour révoquer le consentement. (#160)
### Modifié ### Modifié
- **Clé publique Ed25519 de licence** : la clé embarquée a été rotée pour correspondre au serveur de licences `maximus-api` qui vient d'être déployé en production (live à `https://api.lacompagniemaximus.com`). Aucune licence n'avait été émise en production avec l'ancienne clé, donc ce changement est invisible pour les utilisateurs existants — mais `/licenses/activate` répond désormais, donc l'activation par machine (issue #53) sera débloquée dès la sortie de cette version. La clé privée correspondante vit uniquement sur le serveur (#49) - **Clé publique Ed25519 de licence** : la clé embarquée a été rotée pour correspondre au serveur de licences `maximus-api` qui vient d'être déployé en production (live à `https://api.lacompagniemaximus.com`). Aucune licence n'avait été émise en production avec l'ancienne clé, donc ce changement est invisible pour les utilisateurs existants — mais `/licenses/activate` répond désormais, donc l'activation par machine (issue #53) sera débloquée dès la sortie de cette version. La clé privée correspondante vit uniquement sur le serveur (#49)

View file

@ -11,6 +11,8 @@
- **Balance sheet — snapshot editor (simple kind)** (route `/balance/snapshot`): second slice of the *Bilan* feature. The new page lets you create or edit a dated snapshot of your balance: pick a date (defaulting to today), enter the value of each active account grouped by category, and save. The mode is driven by the `?date=` query parameter — when a snapshot already exists at that date the page automatically flips into edit mode (the underlying `balance_snapshots.snapshot_date` UNIQUE constraint guarantees one snapshot per day). The date of an existing snapshot is immutable: to change it, delete the snapshot and create a new one. A *Prefill from previous snapshot* button copies values from the most recent earlier snapshot (simple-kind accounts only — priced accounts will be handled when the priced editor lands in a later release). A *Delete* button surfaces a double-confirmation modal that requires retyping the snapshot date before the destructive action is enabled. Only simple-kind values are accepted at this stage (`quantity` and `unit_price` are kept `NULL`); the priced editor (quantity × unit price + price fetch) ships in a later release. New `useSnapshotEditor` hook (scoped `useReducer` covering the full lifecycle) and two new components `SnapshotEditor` + `SnapshotLineRow`. FR/EN i18n under `balance.snapshot.*` (#146) - **Balance sheet — snapshot editor (simple kind)** (route `/balance/snapshot`): second slice of the *Bilan* feature. The new page lets you create or edit a dated snapshot of your balance: pick a date (defaulting to today), enter the value of each active account grouped by category, and save. The mode is driven by the `?date=` query parameter — when a snapshot already exists at that date the page automatically flips into edit mode (the underlying `balance_snapshots.snapshot_date` UNIQUE constraint guarantees one snapshot per day). The date of an existing snapshot is immutable: to change it, delete the snapshot and create a new one. A *Prefill from previous snapshot* button copies values from the most recent earlier snapshot (simple-kind accounts only — priced accounts will be handled when the priced editor lands in a later release). A *Delete* button surfaces a double-confirmation modal that requires retyping the snapshot date before the destructive action is enabled. Only simple-kind values are accepted at this stage (`quantity` and `unit_price` are kept `NULL`); the priced editor (quantity × unit price + price fetch) ships in a later release. New `useSnapshotEditor` hook (scoped `useReducer` covering the full lifecycle) and two new components `SnapshotEditor` + `SnapshotLineRow`. FR/EN i18n under `balance.snapshot.*` (#146)
- **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) - **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)
- **Price-fetching premium for stocks (best-effort) and crypto (direct exchanges)** — privacy preserved via maximus-api proxy. Privacy toggle in Settings to revoke consent. (#160)
### Changed ### Changed
- **License Ed25519 public key** rotated to match the freshly deployed `maximus-api` license server (now live at `https://api.lacompagniemaximus.com`). No production licenses had been issued against the previous key, so this change is invisible to existing users — but `/licenses/activate` now answers, so machine activation (Issue #53) is unblocked once this release ships. The matching private key lives only on the server (#49) - **License Ed25519 public key** rotated to match the freshly deployed `maximus-api` license server (now live at `https://api.lacompagniemaximus.com`). No production licenses had been issued against the previous key, so this change is invisible to existing users — but `/licenses/activate` now answers, so machine activation (Issue #53) is unblocked once this release ships. The matching private key lives only on the server (#49)

View file

@ -635,6 +635,15 @@
"Your data is stored locally and is never affected by updates", "Your data is stored locally and is never affected by updates",
"Change the app language using the language selector in the sidebar" "Change the app language using the language selector in the sidebar"
] ]
},
"privacy": {
"priceFetchConsent": {
"label": "Price fetching via Maximus",
"description": "Allow Simpl'Résultat to use the Maximus proxy to fetch asset prices. Privacy: your IP is hidden.",
"confirmRevoke": "The fetch button will ask for consent again next time. Continue?",
"revokeButton": "Revoke consent",
"notPremium": "Premium licenses only"
}
} }
}, },
"charts": { "charts": {
@ -1730,6 +1739,31 @@
"evolution": { "evolution": {
"transferIn": "In", "transferIn": "In",
"transferOut": "Out" "transferOut": "Out"
},
"priceFetching": {
"button": "Fetch price",
"tooltipNotPremium": "Available with premium subscription",
"bestEffortNotice": "Source not guaranteed, may be unavailable. Manual input remains primary.",
"attribution": "via Maximus on {{date}}",
"consent": {
"title": "Price fetching via Maximus",
"body": "By clicking Accept, you authorize Simpl'Résultat to query the Maximus proxy to fetch this price. The proxy hides your IP from data providers. No browsing history is stored.",
"accept": "Accept",
"decline": "Cancel"
},
"errors": {
"invalidSymbol": "Invalid symbol",
"invalidDate": "Invalid date",
"missingParam": "Missing parameter",
"authFailed": "Authentication failed — check your license",
"premiumRequired": "This feature requires a premium subscription",
"licenseRevoked": "License revoked",
"symbolNotFound": "Symbol not found",
"rateLimit": "Too many requests — retry in {{seconds}}s",
"serverUnavailable": "Server unavailable — try again later",
"bestEffortDegraded": "Best-effort price source temporarily unavailable — retry in {{minutes}}min or enter manually",
"sessionCapReached": "Fetch limit reached for this session. Enter remaining prices manually."
}
} }
} }
} }

View file

@ -635,6 +635,15 @@
"Vos données sont stockées localement et ne sont jamais affectées par les mises à jour", "Vos données sont stockées localement et ne sont jamais affectées par les mises à jour",
"Changez la langue de l'application via le sélecteur de langue dans la barre latérale" "Changez la langue de l'application via le sélecteur de langue dans la barre latérale"
] ]
},
"privacy": {
"priceFetchConsent": {
"label": "Récupération de prix via Maximus",
"description": "Permet à Simpl'Résultat d'utiliser le proxy Maximus pour récupérer les prix d'actifs. Privacy : ton IP est masquée.",
"confirmRevoke": "Le bouton de récupération demandera à nouveau ton consentement la prochaine fois. Continuer ?",
"revokeButton": "Révoquer le consentement",
"notPremium": "Réservé aux licences premium"
}
} }
}, },
"charts": { "charts": {
@ -1730,6 +1739,31 @@
"evolution": { "evolution": {
"transferIn": "Entrée", "transferIn": "Entrée",
"transferOut": "Sortie" "transferOut": "Sortie"
},
"priceFetching": {
"button": "Récupérer le prix",
"tooltipNotPremium": "Disponible avec abonnement premium",
"bestEffortNotice": "Source non garantie, peut être indisponible. La saisie manuelle reste prioritaire.",
"attribution": "via Maximus le {{date}}",
"consent": {
"title": "Récupération de prix via Maximus",
"body": "En cliquant sur \"Accepter\", tu autorises Simpl'Résultat à interroger le proxy Maximus pour récupérer ce prix. Le proxy masque ton IP aux fournisseurs de données. Aucun historique de consultation n'est stocké.",
"accept": "Accepter",
"decline": "Annuler"
},
"errors": {
"invalidSymbol": "Symbole invalide",
"invalidDate": "Date invalide",
"missingParam": "Paramètre manquant",
"authFailed": "Échec d'authentification — vérifie ta licence",
"premiumRequired": "Cette fonction nécessite un abonnement premium",
"licenseRevoked": "Licence révoquée",
"symbolNotFound": "Symbole introuvable",
"rateLimit": "Trop de requêtes — réessaie dans {{seconds}} s",
"serverUnavailable": "Serveur indisponible — réessaie plus tard",
"bestEffortDegraded": "Source de prix temporairement indisponible réessayez dans {{minutes}} min ou saisissez manuellement",
"sessionCapReached": "Limite de récupération atteinte pour cette session. Saisissez les prix restants manuellement."
}
} }
} }
} }