feat(balance): schema migration v9 + service skeleton + AccountsPage (#138) #147

Merged
maximus merged 4 commits from issue-138-bilan-1a into main 2026-04-26 13:25:10 +00:00
Owner

Closes #138

Summary

  • Adds migration v9: 5 balance tables (categories, accounts, snapshots, snapshot_lines, account_transfers) + 7 indexes + 7 seed categories (5 simple + 2 priced)
  • Hardcoded currency = 'CAD' CHECK constraint (MVP — v2 will lift it)
  • FK balance_account_transfers.transaction_id ON DELETE RESTRICT (preserves Modified Dietz reproducibility)
  • CHECK kind invariants on balance_snapshot_lines (quantity/unit_price both null OR both set)
  • New balance.service.ts (CRUD section: categories + accounts) via getDb() — TypeScript pattern, no Tauri commands for CRUD
  • New useBalanceAccounts hook (useReducer scoped)
  • New page /balance/accounts with tabs Comptes / Catégories (simple kind only)
  • New AccountForm component (account variant)
  • i18n FR/EN under balance.account.* and balance.category.*
  • CHANGELOG entries (FR + EN) under [Unreleased]

Out of scope (per plan v2)

  • Sidebar "Bilan" entry → Issue #141
  • SnapshotEditPage → Issue #146
  • Priced kind UI → Issue #140

Test plan

  • cargo check
  • cargo test (migration v9 applies cleanly, CHECK/UNIQUE/FK enforced — 13 new co-located rusqlite tests, 47 total)
  • npm run build
  • npm test (CRUD service tests — 19 new vitest cases, 357 total)
  • Manual verification: open app, create profile, create account in seeded category — pending human

Decisions log

See decisions-log.md (uncommitted, on local clone).

Generated autonomously by /autopilot run of 2026-04-25

Closes #138 ## Summary - Adds migration v9: 5 balance tables (categories, accounts, snapshots, snapshot_lines, account_transfers) + 7 indexes + 7 seed categories (5 simple + 2 priced) - Hardcoded `currency = 'CAD'` CHECK constraint (MVP — v2 will lift it) - FK `balance_account_transfers.transaction_id ON DELETE RESTRICT` (preserves Modified Dietz reproducibility) - CHECK kind invariants on `balance_snapshot_lines` (quantity/unit_price both null OR both set) - New `balance.service.ts` (CRUD section: categories + accounts) via `getDb()` — TypeScript pattern, no Tauri commands for CRUD - New `useBalanceAccounts` hook (useReducer scoped) - New page `/balance/accounts` with tabs Comptes / Catégories (simple kind only) - New `AccountForm` component (account variant) - i18n FR/EN under `balance.account.*` and `balance.category.*` - CHANGELOG entries (FR + EN) under [Unreleased] ## Out of scope (per plan v2) - Sidebar "Bilan" entry → Issue #141 - SnapshotEditPage → Issue #146 - Priced kind UI → Issue #140 ## Test plan - [x] cargo check - [x] cargo test (migration v9 applies cleanly, CHECK/UNIQUE/FK enforced — 13 new co-located rusqlite tests, 47 total) - [x] npm run build - [x] npm test (CRUD service tests — 19 new vitest cases, 357 total) - [ ] Manual verification: open app, create profile, create account in seeded category — pending human ## Decisions log See `decisions-log.md` (uncommitted, on local clone). Generated autonomously by /autopilot run of 2026-04-25
maximus added 4 commits 2026-04-25 18:39:06 +00:00
Adds the SQL foundation for the Bilan (balance sheet) feature:

- 5 new tables: balance_categories, balance_accounts, balance_snapshots,
  balance_snapshot_lines, balance_account_transfers
- 7 indexes (category, active partial, snapshot, accounts x2, transaction,
  snapshot_date)
- Seed of 7 standard categories (5 simple + 2 priced) marked is_seed=1
- CHECK(currency = 'CAD') on balance_accounts (MVP — v2 lifts the constraint
  with a multi-currency rate table)
- CHECK kind invariants on balance_snapshot_lines (quantity/unit_price both
  NULL OR both NOT NULL)
- FK transaction_id ON DELETE RESTRICT to preserve reproducibility of
  Modified Dietz returns calculated on past periods

Migration v9 is added inline to the lib.rs Vec<Migration> via a new
constant database::BALANCE_SCHEMA backed by balance_schema.sql. The
schema is mirrored in consolidated_schema.sql so brand-new profiles
get the feature preinstalled without replaying v9.

13 new co-located rusqlite tests validate the migration on a fresh
in-memory DB: schema applies cleanly, 7 categories seeded with correct
kinds, CHECK rejects invalid currency/kind/direction, UNIQUE rejects
duplicate snapshot_date / (snapshot_id,account_id) / (transaction_id,
account_id), FK CASCADE on snapshot delete, FK RESTRICT on transaction
delete and on category with linked accounts, seed idempotent on replay.

Refs #138

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the TypeScript service layer for the Bilan feature, scoped to
Issue #138 (Bilan #1a) — categories + accounts CRUD only. Snapshots,
snapshot lines, transfers and price-fetching land in subsequent issues.

The service uses `getDb()` + tauri-plugin-sql directly per project
convention (96 occurrences across 15 services). No new Tauri commands
introduced — the only future Rust commands are `compute_account_return`
(Issue #142) and `fetch_price` (Issue #144).

API surface:
- listBalanceCategories / getBalanceCategory / createBalanceCategory /
  updateBalanceCategory / deleteBalanceCategory (with seed + has-accounts
  guards)
- listBalanceAccounts (excludes archived by default) / getBalanceAccount
  / createBalanceAccount (CAD-only at MVP) / updateBalanceAccount /
  archiveBalanceAccount / unarchiveBalanceAccount (soft delete)

Typed errors via BalanceServiceError + BalanceErrorCode union so the UI
can render distinct i18n messages. Domain types added under
`src/shared/types/index.ts`: BalanceCategoryKind, BalanceCategory,
BalanceAccount, BalanceAccountWithCategory, BALANCE_CURRENCY_CAD.

19 vitest cases cover: ordering, kind validation, seed protection,
linked-account guard, currency rejection, missing-category lookup,
soft delete + restore round-trip, symbol/notes normalization.

Refs #138

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wires the AccountsPage end-to-end with a new scoped useReducer hook,
the page itself (accessible at /balance/accounts) and the account form.

useBalanceAccounts (src/hooks/useBalanceAccounts.ts):
- Loads accounts (excludes archived by default) + categories in parallel
- Surfaces typed errors from balance.service via state.errorCode so the
  UI can localize them (e.g. seed protection, currency rejection)
- CRUD operations on both domains: addAccount/editAccount/archive/
  unarchiveAccount + addCategory/editCategory/removeCategory

AccountsPage (src/pages/AccountsPage.tsx):
- Two tabs: Comptes + Catégories
- Accounts tab: archive toggle, table of (name, category, symbol,
  currency, status), inline edit/archive/restore
- Categories tab: full list of seeded + user categories. Add new
  simple-kind category (priced creation lands in #140). Rename via
  inline prompt; delete disabled on seeded rows. Errors surfaced via
  i18n keys keyed on BalanceErrorCode.

AccountForm (src/components/balance/AccountForm.tsx):
- Variant=account only (category variant lands in #140)
- Auto-detects priced category to hint the symbol field
- Full FR/EN coverage of labels and validation messages

Per spec-plan-bilan.md v2 the sidebar entry "Bilan" is intentionally
not added in this issue — it lands in #141 (Bilan #3) when the
/balance overview becomes navigable. Until then the route is reachable
directly via URL.

Refs #138

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
feat(balance): add i18n keys + CHANGELOG entry
All checks were successful
PR Check / rust (push) Successful in 22m25s
PR Check / frontend (push) Successful in 2m27s
PR Check / rust (pull_request) Successful in 22m44s
PR Check / frontend (pull_request) Successful in 2m21s
4c71eaca2d
Adds the FR/EN translation namespace `balance.*` covering:
- balance.accountsPage.* (page chrome, tab labels, empty states)
- balance.account.* (table fields, status badges, action labels,
  full account form copy with priced/simple-aware hints)
- balance.category.* (intro text, table fields, kind labels, origin
  labels, action prompts, simple-only creation form, seeded labels
  for the 7 standard categories)
- balance.errors.* (one entry per BalanceErrorCode union member)

CHANGELOG.md and CHANGELOG.fr.md both gain a single entry under
`[Unreleased] / Added` summarising the schema migration v9, the new
balance.service CRUD section and the AccountsPage tabs.

Refs #138

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
maximus added the
autopilot:pending-human
status:approved
labels 2026-04-25 18:39:11 +00:00
maximus merged commit b6387f4b31 into main 2026-04-26 13:25:10 +00:00
maximus deleted branch issue-138-bilan-1a 2026-04-26 13:25:10 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/Simpl-Resultat#147
No description provided.