Simpl-Resultat/CHANGELOG.md
le king fu 4cd0ac9a13 Merge PR #186: feat(branding) replace default Tauri icon + bundle 64x64
# Conflicts:
#	CHANGELOG.fr.md
#	CHANGELOG.md
2026-05-02 15:46:03 -04:00

42 KiB
Raw Blame History

Changelog

[Unreleased]

Added

  • Bilan: 4 starter accounts (Checking account, TFSA, RRSP, Non-registered account) are seeded for new profiles, and a one-shot opt-in modal proposes them to existing profiles on their first /balance visit. Default-checked checkboxes; existing accounts with the same name + category disable the matching row with a "Already exists" tooltip. Confirming or dismissing both write user_preferences.balance_starter_proposed so the modal never re-appears. ADR 0012 (Proposed) captures the future two-level vehicle × composition model (#179).

Changed

  • App icon — replaced the default Tauri scaffolding icon with a custom design: a robot-faced calculator with a privacy lock on the Enter / = key. Conveys the four product values — robot (assistant), simplicity (geometric shapes), accounting (calculator), privacy (lock). Source SVG kept at src-tauri/icons/icon.svg for future iterations; all 16 platform-specific raster sizes regenerated via tauri icon. Web favicon and window <title> updated too (was "Tauri + React + Typescript" from the default scaffold).
  • Bilan: replaced empty /balance state with a 2-step onboarding card (Create an account → Enter a snapshot) so users no longer see a confusing "no snapshot" screen before any account exists. The "+ New snapshot" button is hidden until at least one account exists. The /balance/snapshot empty-state copy now clarifies what an account is vs. what a snapshot is (#178).

Fixed

  • Bilan: fix SQLite "misuse of aggregate function MIN()" error when loading /balance with existing snapshots; replaced aggregate-in-WHERE pattern with ROW_NUMBER() window function in getAccountsPeriodAnchor (#175).
  • Bilan: snapshot save now uses atomic BEGIN/COMMIT and validates all lines before any DB write, preventing orphan snapshot rows when validation fails. Migration v11 cleans existing orphans (#176).

[0.9.0] - 2026-04-29

Added

  • Balance sheet — asset_type column on priced categories (route /balance/accounts): priced balance categories now carry an explicit asset_type (stock or crypto) that drives PriceFetchControl provider routing without relying on symbol heuristics (e.g. ETH = Ethan Allen NYSE and Ethereum crypto are no longer ambiguous). Migration v10 adds a nullable column and backfills the two seeded priced categories (stock, crypto) with their matching values; legacy custom priced rows stay NULL until a future edit-category UI lets the user fill them in. The category creation form (Categories tab) now shows an asset-type selector when kind = priced and rejects submission until a value is picked. The snapshot editor hides the price-fetch button on priced rows whose asset_type is still NULL — manual entry remains the only path on those legacy rows. (#169)

  • Balance sheet — documentation and ADRs (docs/): closes the Bilan milestone with the documentation pass. docs/architecture.md now lists the 5 new tables (balance_categories, balance_accounts, balance_snapshots, balance_snapshot_lines, balance_account_transfers), the 7 new indexes, the SQL CHECK and FK invariants (CAD-only, kind invariants, RESTRICT on transaction_id for Modified Dietz reproducibility), the balance.service.ts 4-section layout (CRUD / snapshots+lines / returns+transfers / prices), the 3 page-scoped hooks (useBalanceAccounts, useSnapshotEditor, useBalanceOverview), the compute_account_return Tauri command (with the fetch_price future-Phase-5 mention), and the 3 new /balance* routes. Three new ADRs land alongside: 0008 — Modified Dietz (justifies the choice vs. ROI / TWR / IRR with reference to return_calculator.rs); 0009 — Proxy price-fetching via maximus-api (architecture documented now, implementation stays BLOCKED by maximus-api Phase 2 — covers privacy considerations like header stripping, no (symbol, license) log correlation and the fixed simpl-resultat UA, the Yahoo + CoinGecko provider abstraction, the Bearer auth strategy, the client + server rate limiting and the dual-side premium gating); 0010 — FK RESTRICT on balance_account_transfers.transaction_id (justifies the integrity over friction trade-off for Modified Dietz reproducibility). The user guide gains a new Balance sheet section walking through snapshot entry (simple + priced), transfer linking, multi-horizon return reading (3M / 1Y / since inception with the side-by-side unadjusted column), with the price-fetching premium flagged "coming in Phase 5". docs.balance.* i18n keys (FR + EN) ship so the in-app guide reflects the new section (#145)

  • Balance sheet — cross-cutting integration test suite (test infrastructure): closes out the Bilan feature with a layer of integration tests that exercise the whole TypeScript surface in a single happy-path flow (account → priced category → priced snapshot → linked transfer → return) plus dedicated assertions for currency lock (CAD-only at the MVP, rejected at both the service layer and SQL CHECK), priced-kind tolerance safety (a bad save must NOT clear pre-existing lines), computeAccountReturn wiring (active-profile resolution, ISO date forwarding, partial-period payload pass-through). Three new Rust integration tests apply migration v9 on top of a seeded v1 schema with pre-existing transactions to verify (1) no row loss / data mutation, (2) link / unlink transfer round-trip on real transaction ids, (3) the FK RESTRICT chain (linked transaction deletion blocked, unblocked after unlink), (4) the v1 categories.id and v9 balance_categories.id namespaces coexist independently. A non-regression source-level test on TransactionTable.tsx locks down the inlined transfer icon contract: optional prop, optional-chaining short-circuit, i18n keys, aria-label, shared description-cell layout — so the page renders identically when no transfers are linked. (#144)

  • Balance sheet — Modified Dietz returns and transfer linking (route /balance): per-account performance now ships. New Rust module commands/return_calculator.rs implements the Modified Dietz formula R = (V_end V_start ΣCF_i) / (V_start + ΣW_i × CF_i) with day-precision contribution weights W_i = (T t_i) / T, plus (1 + R)^(365/T) 1 annualization. Edge cases — missing endpoint snapshot, no flows tagged in the period, account created mid-period, depleted-then-refilled, zero-length period — are surfaced with explicit is_partial / has_no_transfers_warning flags so the UI shows a clean dash + tooltip instead of a confusing number. The new Tauri command compute_account_return(account_id, period_start, period_end) runs three short SQL reads against the active profile DB (latest snapshot ≤ period start, latest snapshot ≤ period end, transfers JOINed with transactions filtered to the period) and feeds the calculator. Seven co-located TDD tests cover every case before the implementation. The accounts table on /balance now shows four extra columns side-by-side: 3M / 1Y / Since-inception (Modified Dietz) plus an Unadjusted column showing the simple (V_end V_start) / V_start so the user can see at a glance how much of the return came from contribution timing. Each row's actions menu gains a Link transfers item that opens a multi-select modal with date range / category / free-text filters; the modal auto-proposes the direction (in for negative bank amounts, out for positive) and the user can flip it per row before submitting. Transactions linked to one or more balance accounts now show a small Link2 icon next to the description in the Transactions page, with a tooltip listing the account name(s) and direction(s). Bulk transaction-deletion paths (per-imported-file and clear-all) now pre-check for any link in balance_account_transfers and surface a typed TransactionLinkedToBalanceError ("This transaction is linked to balance account X — unlink it before deleting") instead of leaking the raw SQLite FK error. The evolution chart on /balance now overlays vertical reference lines at every linked-transfer date (green for in, red for out). New i18n keys under balance.returns.*, balance.accountsTable.*, balance.transfers.*, balance.evolution.*, transactions.transferIcon.* (FR + EN) (#142)

  • Balance sheet — /balance overview page, evolution chart and sidebar entry (route /balance): fourth slice of the Bilan feature finally surfaces it in the navigation. The new page composes (1) an overview card with the latest aggregate net worth, the Δ% versus the previous chronological snapshot (rendered as "—" when only one snapshot exists), a 60-day staleness warning when the latest snapshot is older than that threshold, and a New snapshot CTA pointing at /balance/snapshot; (2) a period selector (3 months / 6 months / 1 year / 3 years / All) that re-fetches every series in parallel; (3) an evolution chart with two modes — Line (single series of SUM(value) GROUP BY snapshot_date) and Stacked by category (one Recharts <Area stackId> per balance_categories.key); (4) an accounts table listing every active account with its latest snapshot value, the per-account Δ% over the active period (latest value vs the value at the earliest snapshot inside the window — null when no anchor exists, rendered as "—"), and an actions menu (Details placeholder, Archive). Return-metric columns (3M / 1Y / since-creation / unadjusted) are reserved for a later release with a TODO marker. The sidebar now exposes the Balance sheet entry (Wallet icon) between Reports and Settings. The service grows three time-series helpers: getSnapshotTotalsByDate(range?), getSnapshotTotalsByCategoryAndDate(range?), getAccountsLatestSnapshot() and a per-account anchor query getAccountsPeriodAnchor(range) — all guarded by unit tests. New useBalanceOverview hook (scoped useReducer) drives the page state. New i18n keys under balance.overview.*, balance.period.*, balance.chart.* plus nav.balance (FR + EN) (#141)

  • Balance sheet — priced kind (quantity × unit price) (routes /balance/accounts and /balance/snapshot): third slice of the Bilan feature. Categories now expose a kind selector at creation: simple (direct value entry) or priced (quantity × unit_price). Accounts linked to a priced category require a symbol. The snapshot editor dispatches on the account's category kind: simple accounts keep their single value field, priced accounts get three inputs — quantity, unit_price (both required) and a read-only value field computed live from quantity × unit_price (rounded to 2 decimals). A [Manual] / [Manuel] attribution tag is shown on each priced row; the future [via Maximus on YYYY-MM-DD] tag will land with automatic price-fetching. The Prefill from previous button now copies quantities for priced accounts but leaves unit prices blank (a fresh price must be entered each time). The service validates priced lines ahead of the SQL CHECK: kind invariants (priced lines must carry both quantity and unit_price; simple lines must carry neither) and a value-match invariant |value quantity × unit_price| ≤ 0.01 (one cent tolerance to absorb floating-point drift). Category deletion now blocks earlier and surfaces a richer error: a category linked to one or more accounts shows a dismissable banner listing the count and up to three account names so the user knows exactly which accounts to archive first; seeded categories remain protected at the service layer with their button disabled in the UI. New i18n keys balance.category.kind.*, balance.category.form.kindLabel/kindHint*, balance.category.error.has_accounts, balance.snapshot.priced.* (FR + EN) (#140)

  • 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)

  • 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

  • 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)

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)

[0.8.4] - 2026-04-21

Added

  • Settings banner (90-day) and permanent Restore action to roll back a category migration from the automatic pre-migration backup (Settings → Categories): after a v2→v1 migration, a dismissable banner (ShieldCheck icon) now appears at the top of the Categories card for 90 days, pointing at the automatic SREF backup written by categoryBackupService. A dedicated Restore a backup entry stays available below the migrate link as long as a migration is recorded — even past the 90-day window — so the rollback is never lost. The confirm modal reads the last_categories_migration journal for its timestamp and backup path, enforces a two-step confirmation with a red Restore button, falls back to a file picker when the recorded path is missing on disk, prompts for the profile PIN when the SREF file is encrypted, and on success resets categories_schema_version=v2 and stamps reverted_at on the journal before reloading the app. The banner hides automatically once the migration has been reverted. New Tauri command file_exists for the pre-flight presence check, new categoryRestoreService wrapping read_import_file + importTransactionsWithCategories with stable error codes (#122)
  • 3-step category migration page (route /settings/categories/migrate, Settings → Migrate to the standard structure): legacy v2 profiles can now opt in to migrate to the new v1 IPC taxonomy through a guided flow — Discover (read-only tree reused from the guide page), Simulate (3-column dry-run table with high / medium / low / needs-review confidence badges, a clickable side panel showing the first 50 affected transactions per row, inline target picker for unresolved rows, next button blocked until every row is resolved), and Consent (checklist + optional PIN field for protected profiles + 4-step loader). On confirm, the page creates a verified SREF backup via categoryBackupService (mandatory, abort on failure with no DB write) and then runs an atomic SQL transaction via the new categoryMigrationService.applyMigration(plan, backup) — BEGIN → INSERT v1 taxonomy → UPDATE transactions / budgets / budget_templates / keywords / suppliers to the new v1 category ids → reparent custom categories under a new Custom categories (migration) parent → soft-deactivate the v2 seed categories → bump categories_schema_version='v1' and journal the run in user_preferences.last_categories_migration → COMMIT. Any thrown error triggers ROLLBACK so the profile stays in its pre-migration state. Success and error screens surface the backup path and (for success) the counts of rows inserted / transactions, keywords and budgets migrated (#121)
  • Dashboard banner inviting v2 profiles to discover the new v1 IPC category taxonomy: legacy profiles (tagged categories_schema_version='v2') now see a dismissable banner at the top of the Dashboard pointing to the new standard categories guide page. The banner is non-destructive (read-only CTA, no category changes), only shown to v2 profiles (new v1-seeded profiles never see it), and its dismissal is persisted in user_preferences under categories_v1_banner_dismissed so it never reappears once closed (#118)
  • Standard categories guide page (Settings → Standard category structure, route /settings/categories/standard): new read-only page that exposes the full v1 IPC taxonomy as a navigable tree with expand/collapse per root, a live category counter (roots · subcategories · leaves · total), accent-insensitive full-text search over translated names, hover tooltips showing the i18n_key / type / ID of each node, and a Export as PDF button that triggers the browser print dialog. A dedicated @media print rule forces every branch to render fully expanded regardless of the on-screen collapse state. All labels resolve via categoriesSeed.* with name as fallback for future custom rows. No database writes, no destructive actions (#117)
  • IPC-aligned categories seed for new profiles: brand-new profiles are now seeded with the v1 IPC (Indice des prix à la consommation) taxonomy — a structured hierarchy aligned with Statistics Canada consumer price index categories. Category labels are now translated dynamically from the categoriesSeed.* i18n namespace (FR/EN), so seed categories display in the user's current language. Existing profiles remain on the legacy v2 seed, marked via a new categories_schema_version user preference (a later migration wizard will offer the v2→v1 transition). Internally: nullable categories.i18n_key column added in migration v8 (additive only), src/data/categoryTaxonomyV1.json bundled as the TS-side source of truth, CategoryTree and CategoryCombobox renderers fall back to the raw name when no translation key is present (user-created rows) (#115)

[0.8.3] - 2026-04-19

Added

  • Cartes report — Monthly / YTD toggle (/reports/cartes): new segmented toggle next to the reference-month picker flips the four KPI cards (income, expenses, net balance, savings rate) between the reference-month value (unchanged default) and a Year-to-Date cumulative view. In YTD mode, the "current" value sums January → reference month, MoM delta compares it to the same-year Jan → (refMonth 1) window (null for January), YoY delta compares it to Jan → refMonth of the previous year, and the savings rate uses the YTD income/expenses. The 13-month sparkline, top movers, seasonality and budget adherence cards remain monthly regardless of the toggle. The savings-rate tooltip now reflects the active mode. Choice persisted in localStorage (reports-cartes-period-mode) (#102)
  • User guide — Cartes section: new dedicated section documenting the four KPI formulas, the Monthly/YTD toggle, the sparkline, top movers, seasonality and budget adherence rules, along with the savings-rate edge case ("—" when income is zero) (#102)
  • Cartes report: help tooltip on the savings-rate KPI explaining the formula — (income expenses) ÷ income × 100, computed on the reference month (#101)
  • Trends report — by category (/reports/trends): new segmented toggle to switch the category-evolution chart between stacked bars (default, unchanged) and a Recharts stacked-area view (<AreaChart stackId="1">) that shows total composition over time. Both modes share the same category palette and SVG grayscale patterns. The chosen type is persisted in localStorage (reports-trends-category-charttype) (#105)

Changed

  • Category zoom report (/reports/category): the category picker is now a typeable, searchable combobox with accent-insensitive matching, keyboard navigation (↑/↓/Enter/Esc) and hierarchy indentation, replacing the native <select> (#103)
  • Compare report — Actual vs. actual (/reports/compare): the table now mirrors the rich 8-column structure of the Actual vs. budget table, splitting each comparison into a Monthly block (reference month vs. comparison month) and a Cumulative YTD block (progress through the reference month vs. progress through the previous window). MoM cumulative-previous uses Jan → end-of-previous-month of the same year; YoY cumulative-previous uses Jan → same-month of the previous year. The chart remains a monthly-only view (#104)
  • Highlights report (/reports/highlights): the monthly tiles (current-month balance, top movers vs. previous month) now default to the previous calendar month instead of the current one, matching the Cartes and Compare reports. The YTD tile stays pinned to Jan 1st of the current civil year. A new reference-month picker lets you pivot both the monthly balance and the top-movers comparison to any past month; the selection is persisted in the URL via ?refY=YYYY&refM=MM so the view is bookmarkable. The hub highlights panel follows the same default (#106)

Fixed

  • Cartes report: removed the non-functional period selector — the Cartes report is a "month X vs X-1 vs X-12" snapshot, so only the reference-month picker is needed (#101)
  • Cartes report: savings-rate KPI now shows "—" instead of "0 %" when the reference month has no income (division by zero is undefined, not zero) (#101)
  • Cartes report — budget adherence: the card was always saying "no budgeted categories this month" even when budgets were defined on expense categories. Root cause: expense budgets are stored signed-negative, and the filter/comparison used raw values instead of absolutes. Categories, in-target counts, and worst-overrun amounts are now all computed on absolute values (#112)

[0.8.2] - 2026-04-17

Added

  • Feedback Hub widget (Settings → Logs): a Send feedback button in the Logs card opens a dialog to submit suggestions, comments, or bug reports to the central Feedback Hub. A one-time consent prompt explains that submission reaches feedback.lacompagniemaximus.com — an explicit exception to the app's 100% local operation. Three opt-in checkboxes (all unchecked by default): include navigation context (page, theme, viewport, app version, OS), include recent error logs, identify with your Maximus account. Routed through a Rust-side command so nothing is sent unless you press Send (#67)
  • Cartes report (/reports/cartes): new dashboard-style sub-report in the Reports hub. Combines four KPI cards (income, expenses, net balance, savings rate) showing MoM and YoY deltas simultaneously with a 13-month sparkline highlighting the reference month, a 12-month income vs. expenses overlay chart (bars + net balance line), top 5 category increases and top 5 decreases vs. the previous month, a budget-adherence card (N/M on-target plus the three worst overruns with progress bars), and a seasonality card that compares the reference month against the same calendar month from the two previous years. All data comes from a single getCartesSnapshot() service call that runs its queries concurrently (#97)

Changed

  • Compare report (/reports/compare): reduced from three tabs (MoM / YoY / Budget) to two modes (Actual vs. actual / Actual vs. budget). The actual-vs-actual view now has an explicit reference-month dropdown in the header (defaults to the previous month), a MoM ↔ YoY sub-toggle, and a grouped side-by-side bar chart (two bars per category: reference period vs. comparison period). The URL PeriodSelector stays in sync with the reference month picker (#96)

[0.8.0] - 2026-04-14

Added

  • Reports hub: /reports is now a hub surfacing a live highlights panel (current month + YTD net balance with sparklines, top movers vs. last month, top recent transactions) and four navigation cards to dedicated sub-reports (#69#76)
  • Highlights report (/reports/highlights): balance tiles with 12-month sparklines, sortable top movers table, diverging bar chart, recent transactions list with 30/60/90 day window toggle (#71)
  • Trends report (/reports/trends): internal sub-view toggle between global flow (income vs. expenses) and by-category evolution, chart/table toggle on both (#72)
  • Compare report (/reports/compare): tab bar for Month vs. Previous Month, Year vs. Previous Year, and Actual vs. Budget; diverging bar chart centered on zero for the first two modes (#73)
  • Category zoom (/reports/category): single-category drill-down with donut chart of subcategory breakdown, monthly evolution area chart, and filterable transactions table (#74)
  • Contextual keyword editing: right-click any transaction row to add its description as a categorization keyword; a preview dialog shows every transaction that would be recategorized (capped at 50, with an opt-in checkbox for N+) before you confirm. Available on the category zoom, the highlights list, and the main transactions page (#74, #75)
  • Bookmarkable period: the reports period now lives in the URL (?from=YYYY-MM-DD&to=YYYY-MM-DD), so you can copy, paste, and share the link and keep the same state (#70)
  • View mode preference (chart vs. table) is now persisted in localStorage per report section

Changed

  • The legacy monolithic useReports hook has been split into per-domain hooks (useReportsPeriod, useHighlights, useTrends, useCompare, useCategoryZoom) so every sub-report owns only the state it needs (#70)
  • Context menu on reports (right-click) is now a generic ContextMenu shell reused by the existing chart menu and the new keyword dialog (#69)

Removed

  • The dynamic pivot table report was removed. Over 90% of its real usage was zooming into a single category, which is better served by the new Category Zoom report. Git history preserves the old implementation if it ever needs to come back (#69)

Security

  • New AddKeywordDialog enforces a 264 character length bound on user keywords to prevent ReDoS on large transaction sets (CWE-1333), uses parameterized LIKE queries for the preview (CWE-89), wraps its INSERT + per-transaction UPDATEs in an explicit BEGIN/COMMIT/ROLLBACK transaction (CWE-662), renders all untrusted descriptions as React children (CWE-79), and recategorizes only the rows the user explicitly checked — never retroactively. Keyword reassignment across categories requires an explicit confirmation step (#74)
  • getCategoryZoom walks the category tree through a bounded recursive CTE (WHERE depth < 5), protecting against malformed parent_id cycles (CWE-835) (#74)

[0.7.4] - 2026-04-14

Changed

  • OAuth tokens are now stored in the OS keychain (Credential Manager on Windows, Secret Service on Linux) instead of a plaintext JSON file. Existing users are migrated transparently on the next sign-in refresh; the old file is zeroed and removed. A "tokens stored in plaintext fallback" banner appears in Settings if the keychain is unavailable (#66, #78, #79, #81)
  • Cached account info is now HMAC-signed with a keychain-stored key: writing subscription_status to account.json manually can no longer bypass the Premium gate (#80)
  • PIN hashing migrated from SHA-256 to Argon2id for brute-force resistance (CWE-916). Existing SHA-256 PINs are verified transparently and rehashed on next successful unlock; new PINs use Argon2id (#54)

Security

  • Closed CWE-312 (cleartext storage of OAuth tokens), CWE-345 (missing integrity check on the subscription cache), and CWE-916 (weak PIN hashing). Legacy tokens.json and legacy unsigned account.json caches are rejected by the gating path until the next token refresh re-establishes a keychain-anchored trust (#66, #54)

[0.7.3] - 2026-04-13

Fixed

  • Maximus Account sign-in: the deep-link callback now uses the canonical Tauri v2 on_open_url API, so the auth code is properly received by the running app instead of leaving the UI stuck in "loading" (#51, #65)
  • OAuth callbacks containing an error parameter now surface the error to the UI instead of being silently ignored (#51)

[0.7.2] - 2026-04-13

Changed

  • Auto-updates are temporarily open to the Free edition until the license server (issue #49) is live. Gating will be restored once paid activation works end-to-end (#48)

[0.7.1] - 2026-04-13

Fixed

  • Maximus Account sign-in: the OAuth2 callback now correctly returns to the running app instead of launching a second instance and leaving the original one stuck in "loading" (#51, #65)

[0.7.0] - 2026-04-11

Added

  • CI: new check.yml workflow runs cargo check/cargo test and the frontend build on every branch push and PR, catching errors before merge instead of waiting for the release tag (#60)
  • License card in Settings page: shows the current edition (Free/Base/Premium), accepts a license key, and links to the purchase page (#47)
  • Maximus Account card in Settings: optional sign-in via OAuth2 PKCE for Premium features (#51)
  • Machine activation: activate/deactivate machines against the license server, view activated machines in the license card (#53)
  • Daily subscription status check: automatically refreshes account info once per day at launch (#51)

Changed

  • Automatic updates are now gated behind the Base edition entitlement; the Free edition shows an upgrade hint instead of fetching updates (#48)
  • Edition detection now considers Maximus Account subscription: Premium overrides Base when subscription is active (#51)

[0.6.7] - 2026-03-29

Changed

  • Category Over Time report: removed hard-coded expense-only filter, added type selector defaulting to expense (#41)
  • Category Over Time report: added type filter (expense/income/transfer) in the right filter panel (#41)

Fixed

  • Updated picomatch dependency (4.0.3 → 4.0.4) to fix HIGH severity vulnerabilities (#43)

[0.6.6]

Changed

  • Budget table: previous year column now shows actual transactions instead of planned budget (#34)
  • Refactored buildPrevYearTotalMap inline and simplified tests (#39)

Fixed

  • Changelog files synced automatically via Vite plugin, removed stale public/ copies (#37)

[0.6.5]

Added

  • Dashboard: month dropdown selector for the Budget vs Actual section with last completed month as default (#31)

Changed

  • Reports & Dashboard: reduced font size of month dropdown for better visual balance (#31)

[0.6.4]

Added

  • Budget table: previous year total column displayed as first data column for baseline reference (#16)

Fixed

  • Dashboard: level 4+ categories now appear under their parent instead of at the bottom of the section (#23)
  • Dashboard: category hierarchy now supports arbitrary nesting depth (#23)

Changed

  • Dashboard: pie chart takes 1/3 width instead of 1/2, giving more space to the budget table (#23)
  • Dashboard: pie chart labels now shown only on hover via tooltip instead of permanent legend (#23)
  • Budget vs Actual: category column now stays fixed when scrolling horizontally (#29)
  • Budget vs Actual: title changed to "Budget vs Réel pour le mois de [month]" with a dropdown month selector (#29)
  • Budget vs Actual: default month is now the last completed month instead of current month (#29)

[0.6.3]

Added

  • Dashboard: expenses over time stacked bar chart by category and month (#15)
  • Dashboard: budget vs actual table for current month with variance in $ and % (#15)
  • Budget table and Budget vs Actual report: section subtotal formatting with increasing visual weight (#14)

Changed

  • Dashboard: default period changed from "month" to "year to date" (#15)
  • Dashboard: removed recent transactions section (#15)
  • All report tables: grand total rows now use larger font (text-sm), bold weight, and thicker top border for better visual hierarchy (#14)

Fixed

  • Category over time report: all categories now displayed (limit increased from 8 to 50) (#13)
  • Category bar chart: Y-axis labels now use foreground color instead of muted gray (#13)
  • Category over time chart: legend text now uses foreground color instead of inheriting category color (#13)

[0.6.2]

Added

  • Budget table: section subtotals for expenses, income, and transfers displayed after each group (#11)
  • Budget vs Actual report: section subtotals with actual, planned, variation ($) and variation (%) per type (#11)

Fixed

  • Category page: detail panel now stays visible when scrolling through a long category list (#12)

[0.6.1]

Added

  • Changelog page: full version history accessible from Settings at any time
  • Bilingual changelog: release notes displayed in the user's selected language (EN/FR)

Fixed

  • Chart label visibility: amount labels on stacked bar charts now use black text with white outline for better contrast (#8)
  • Budget table: editable cells now show hover background, pointer cursor, and tooltip hint for clearer affordance (#9)

[0.6.0]

Added

  • Reports: toggle between table and chart view for Trends, By Category, and Over Time tabs
  • Reports: "Show amounts" toggle displays values directly on chart bars and area curves
  • Reports: filter panel with category checkboxes (search, select all/none) and source dropdown
  • Reports: source filter applies at SQL level for accurate filtered totals
  • Reports: sticky table headers on all report tables (Dynamic Report, Budget vs Actual)
  • Reports: interactive hover — dimmed non-hovered bars, tooltip filtered to hovered category
  • Reports: legend hover highlights category across all months (Over Time chart)

Fixed

  • Transaction table: comment icon now turns orange (like split icon) when a note is present (#7)

[0.5.0]

Added

  • Error boundary catches React crashes and displays an error page instead of a white screen
  • Startup timeout (10s) on database connection — shows error page instead of infinite spinner
  • Error page with "Refresh", "Check for updates", and contact/issue links
  • Log viewer in settings page — captures console output, filterable by level, copyable, persists across refresh
  • GPL-3.0 license — project is now open source

Changed

  • Report detail modal: sortable columns — click headers to sort by date, description, or amount (#1)
  • Report detail modal: toggle to show/hide amounts column (#3)
  • Budget table: column headers stay fixed when scrolling vertically (#2)

Fixed

  • Auto-updater on Linux: latest.json version field no longer has v prefix, package registry upload is more robust
  • Startup retry: DB connection retries up to 3 times before showing error page (fixes first-launch failure on Windows)
  • Migration checksum mismatch: automatically repairs stale migration 1 checksum on startup

[0.4.4]

Fixed

  • Linux binary now compatible with glibc 2.35+ (Ubuntu 22.04 / Pop!_OS) — CI builds in Ubuntu 22.04 container

[0.4.3]

Fixed

  • Auto-updater endpoint now uses Forgejo package registry for stable URL
  • Linux updater signatures (.AppImage.sig) now correctly collected in CI
  • All platform signatures (.deb.sig, .rpm.sig) now included in release assets

[0.4.2]

Changed

  • Auto-updater now points to self-hosted Forgejo instance
  • Windows builds now cross-compiled via cargo-xwin

[0.4.1]

Fixed

  • App stuck on infinite spinner after updating from v0.3.x (migration checksum mismatch on seed_categories.sql)
  • DB connection errors now logged to console instead of silently failing

[0.4.0]

Added

  • Categories: support for 3 levels of hierarchy (e.g., Dépenses récurrentes → Assurances → Assurance-auto)
  • Dynamic Report: new "Category (Level 3)" pivot field
  • Budget: intermediate subtotals and 3-level indentation for nested categories
  • Categories: automatic is_inputable management when creating/deleting subcategories
  • Categories: depth validation prevents creating a 4th level
  • Seed data: Assurances split into Assurance-auto, Assurance-habitation, Assurance-vie

Fixed

  • Auto-categorization: keywords starting/ending with special characters ([, ], (, ), -, etc.) now match correctly
  • Auto-categorization: pre-compile regex patterns for better batch performance

[0.3.11]

Added

  • Dynamic Report: support multiple column dimensions (composite column keys)

Fixed

  • Dynamic Report: no longer affected by global page date filters — uses only its own panel filters

[0.3.10]

Added

  • Dynamic Report: fields can now be used in multiple zones simultaneously (rows + filters, columns + filters)
  • Dynamic Report: right-click on a filter value to exclude it (shown with strikethrough in red)
  • "This year" period option in reports and dashboard (Jan 1 to today)

[0.3.9]

Added

  • Dynamic Report (pivot table): compose custom reports by assigning dimensions to rows, columns, filters and measures to values
  • Delete keywords from the "All Keywords" view

[0.3.8]

Added

  • Custom date range picker for reports and dashboard
  • Toggle to position subtotals above or below detail rows
  • Display release notes from CHANGELOG in GitHub releases and in-app updater

[0.3.7]

Fixes

  • Remove MSI bundle to prevent updater install path conflict
  • Change Windows updater installMode to basicUi
  • Improve split indicator visibility and adjustments layout

0.3.2

New Features

  • Linux support: Add Linux build (.deb, .rpm, .AppImage) to release workflow
  • Transaction splits on Adjustments page: View transaction split adjustments in a dedicated section on the Adjustments page

Fixes

  • Fix CSV auto-detect edge cases
  • Remove accent from productName for Linux .deb compatibility

0.3.1

Fixes

  • Always show profile switcher in sidebar (#2)

0.3.0

New Features

  • Multiple profiles: Create multiple profiles with separate databases, custom names, and colors
  • PIN protection: Protect profiles with an optional numeric PIN
  • Profile switcher: Quick profile switching from the sidebar
  • Drag-and-drop categories: Reorder categories or change parent via drag-and-drop in the category tree
  • Transaction splits: Split a transaction across multiple categories with adjustable amounts

0.2.10

New Features

  • Period quick-select: Add quick period filter buttons (This month, Last month, etc.) on the Transactions page
  • Budget vs Actual report: Monthly and year-to-date comparison table in Reports
  • Parent category subtotals: Budget page shows aggregated subtotals for parent categories
  • User guide: Complete documentation page accessible from Settings, printable to PDF

Improvements

  • Persist template selection and add Update template button
  • Don't pre-select already-imported files when entering source config
  • Make settings data imports visible in Import History
  • Replace per-template delete buttons with single delete on selection
  • Replace refresh icon with save icon on update template button
  • Add sign convention to budget page

0.2.9

Fixes

  • Allow duplicate-content files with different names (#1)

0.2.8

New Features

  • Data export/import: Export and import your data (transactions, categories, or both) with optional AES-256-GCM encryption (#3)

Fixes

  • Cross-file duplicate detection and per-file import tracking

0.2.5

New Features

  • Import config templates: Save and load import source configurations as reusable templates
  • 12-month budget grid: Full year budget view with monthly cells and annual totals

Fixes

  • Budget and category fixes
  • Migration checksum issue (schema.sql must not be modified after initial release)

0.2.3

New Features

  • Chart patterns: Added SVG fill patterns (diagonal lines, dots, crosshatch, etc.) to differentiate categories in bar charts, pie chart, and stacked bar charts beyond just color
  • Chart context menu: Right-click any category in a chart to hide it or view its transactions in a detail popup
  • Hidden categories: Hidden categories appear as dismissible chips above charts with a "Show all" button to restore them
  • Transaction detail modal: View all transactions composing a category's total directly from any chart
  • Import preview popup: The data preview is now a popup modal instead of a separate wizard step, allowing quick inspection without leaving the configuration page
  • Direct duplicate check: New "Check Duplicates" button on the import configuration page skips directly to duplicate validation without requiring a preview first

Improvements

  • Import wizard flow simplified: source-config → duplicate-check (preview is optional via popup)
  • Duplicate-check back button now returns to source configuration instead of the removed preview step
  • Added categoryIds map to CategoryOverTimeData for proper category resolution in the over-time chart

0.2.2

  • Bump version

0.2.1

  • Add "All Keywords" view on Categories page
  • Add dark mode with warm gray palette
  • Fix orphan categories, persist has_header for imports, add re-initialize
  • Add Budget and Adjustments pages