feat: multi-account financial overview dashboard (#132)#392
Open
sinatragian wants to merge 6 commits intorohitdash08:mainfrom
Open
feat: multi-account financial overview dashboard (#132)#392sinatragian wants to merge 6 commits intorohitdash08:mainfrom
sinatragian wants to merge 6 commits intorohitdash08:mainfrom
Conversation
- Account model (BANK/CREDIT/CASH/INVESTMENT/WALLET/OTHER) - Full CRUD: GET/POST/PATCH/DELETE /accounts - GET /accounts/overview — aggregate balance, income, expenses per account - Net worth = total_assets - total_liabilities (CREDIT accounts = liabilities) - Soft delete (deactivate) to preserve expense history - Expense.account_id FK (nullable, backward-compatible) - Migration 005_accounts.sql - 27 tests covering CRUD, overview, balances, auth Closes rohitdash08#132
…ted_at Fix 1 — N+1 → single GROUP BY query in GET /accounts/overview Previously emitted 2 separate SUM queries per account (O(2n) round-trips). Now a single query groups income/expense amounts by account_id using conditional aggregation (CASE WHEN), then joins back to the account list in Python. The two unassigned-expense scalars are collapsed into one query as well. Fix 2 — GET/PATCH /accounts/<id> returns 404 for deactivated accounts _get_or_404 now checks active=True alongside user ownership. Soft-deleted accounts are inaccessible via the API; historical expense links are preserved in the DB. Explicit comment documents the design decision. Fix 3 — Add updated_at to Account model and migration Added updated_at column (default NOW(), auto-updated via SQLAlchemy onupdate + Postgres trigger in migration). Exposed in _account_to_dict. Migration is idempotent (ALTER TABLE ... ADD COLUMN IF NOT EXISTS). Tests added: - test_overview_no_n_plus_1_with_multiple_accounts (end-to-end GROUP BY) - test_get_deactivated_account_returns_404 - test_patch_deactivated_account_returns_404 - test_account_has_updated_at_field - test_updated_at_changes_on_patch
Author
|
Security note — user_id isolation in all financial queries Every query in this implementation is scoped to the authenticated user's
This means a valid JWT for user A cannot be used to read, modify, or infer the balance of user B's accounts — even if the |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds multi-account financial overview dashboard to fix #132.
Backend
/accounts(list, create, get, update, soft-delete)GET /accounts/overview— single GROUP BY query aggregates income/expenses per account; returns per-account balance +{total_assets, total_liabilities, net_worth, unassigned_income, unassigned_expenses, account_count}updated_atcolumn with Postgres trigger; soft-delete preserves historical expense linksuser_id— no cross-tenant data exposure possibleFrontend
/accounts— Accounts page:app/src/api/accounts.ts(full API layer),app/src/pages/Accounts.tsx, route inApp.tsx, nav link inNavbar.tsxSecurity note
Every query is scoped to the authenticated user's
user_id— list, get, overview GROUP BY, and unassigned totals. A valid JWT for user A cannot read or infer user B's account balances even with a guessedaccount_id.Closes #132