Skip to content

feat: multi-account financial overview dashboard (#132)#468

Open
qiridigital wants to merge 1 commit intorohitdash08:mainfrom
qiridigital:feat/multi-account-overview
Open

feat: multi-account financial overview dashboard (#132)#468
qiridigital wants to merge 1 commit intorohitdash08:mainfrom
qiridigital:feat/multi-account-overview

Conversation

@qiridigital
Copy link

Multi-Account Financial Overview Dashboard

closes #132 | /claim #132

Summary

Adds a complete multi-account financial management system allowing users to track balances, transactions, and net worth across multiple accounts simultaneously.

Backend Changes

New model: FinancialAccount

  • Types: CHECKING, SAVINGS, CREDIT, CASH, INVESTMENT, OTHER
  • Tracks: name, currency, initial balance, color, soft-delete flag
  • Expense model extended with optional account_id FK

New endpoints (/accounts):

Method Path Description
GET /accounts List all active accounts with live balances
POST /accounts Create account with optional color/currency
GET /accounts/:id Account detail + 20 most recent transactions
PATCH /accounts/:id Update name, type, color, initial balance
DELETE /accounts/:id Soft delete (preserves history)
GET /accounts/overview Net worth, total assets/liabilities, by-type breakdown

Balance calculation: initial_balance + SUM(income) - SUM(expenses) — always reflects current reality.

Frontend Changes

  • Accounts.tsx — Full dashboard with net worth banner, per-account cards showing live balance, by-type aggregate summary, create form
  • api/accounts.ts — TypeScript API client with complete type definitions
  • Route /accounts added to App.tsx + nav link in Navbar.tsx

Database

CREATE TABLE financial_accounts (
  id, user_id FK, name, account_type, currency,
  initial_balance NUMERIC(12,2), color, active, created_at
);
ALTER TABLE expenses ADD COLUMN account_id INT REFERENCES financial_accounts(id);

Tests

16 pytest tests covering:

  • List/create accounts, validation errors
  • Get account detail with recent transactions
  • Update account fields and type validation
  • Soft delete and auth protection
  • Overview: empty state, multi-account net worth, credit reducing net worth

- Add FinancialAccount model (CHECKING/SAVINGS/CREDIT/CASH/INVESTMENT/OTHER)
- Extend Expense model with optional account_id FK
- CRUD endpoints: GET/POST /accounts, GET/PATCH/DELETE /accounts/:id
- Aggregated GET /accounts/overview with net worth, by-type breakdown
- Real-time balance: initial_balance + income - expenses per account
- Soft delete (active flag) to preserve historical data
- Update schema.sql with financial_accounts table and indexes
- React Accounts page: net worth banner, account cards, type breakdown
- TypeScript API client with full types
- 16 pytest tests covering CRUD, validation, overview and auth

/claim rohitdash08#132
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds multi-account support so users can create/manage financial accounts and view an aggregated net-worth overview across accounts.

Changes:

  • Backend: introduces FinancialAccount model + /accounts CRUD and /accounts/overview endpoints with live balance aggregation.
  • Database: adds financial_accounts table and optional expenses.account_id foreign key.
  • Frontend: adds an Accounts dashboard page, API client module, route, and navbar link.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
packages/backend/tests/test_accounts.py Adds pytest coverage for accounts CRUD, overview, and auth protection.
packages/backend/app/routes/accounts.py Implements /accounts endpoints, balance computation, and overview aggregation.
packages/backend/app/routes/__init__.py Registers the new accounts blueprint.
packages/backend/app/models.py Adds FinancialAccount model and Expense.account_id optional FK.
packages/backend/app/db/schema.sql Defines financial_accounts table + adds/indexes expenses.account_id.
app/src/pages/Accounts.tsx New multi-account overview UI (net worth banner, account cards, create form).
app/src/components/layout/Navbar.tsx Adds “Accounts” navigation entry.
app/src/api/accounts.ts Adds frontend API bindings + types for accounts endpoints.
app/src/App.tsx Adds protected /accounts route.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

result = _account_json(account)
# Recent transactions for this account
recent = (
Expense.query.filter_by(account_id=account_id)
Comment on lines +54 to +71
# ── CRUD ─────────────────────────────────────────────────────────────────────


@bp.get("")
@jwt_required()
def list_accounts():
uid = int(get_jwt_identity())
accounts = (
FinancialAccount.query.filter_by(user_id=uid, active=True)
.order_by(FinancialAccount.created_at.asc())
.all()
)
return jsonify([_account_json(a) for a in accounts])


@bp.post("")
@jwt_required()
def create_account():
api.patch(`/accounts/${id}`, payload).then((r) => r.data);

export const deleteAccount = (id: number): Promise<void> =>
api.delete(`/accounts/${id}`).then((r) => r.data);
Comment on lines +188 to +195
const handleDelete = async (id: number) => {
if (!confirm("Remove this account?")) return;
try {
await deleteAccount(id);
await load();
} catch {
alert("Failed to remove account.");
}
Comment on lines +18 to +31
db.session.query(func.coalesce(func.sum(Expense.amount), 0))
.filter(
Expense.account_id == account.id,
Expense.expense_type == "INCOME",
)
.scalar()
or 0
)
expenses = float(
db.session.query(func.coalesce(func.sum(Expense.amount), 0))
.filter(
Expense.account_id == account.id,
Expense.expense_type != "INCOME",
)
Comment on lines +1 to +3
import api from "./index";

export type AccountType =
Comment on lines +198 to +200
const handleCreate = async (e: React.FormEvent) => {
e.preventDefault();
setSaving(true);
Comment on lines +229 to +252
<div style={{ maxWidth: 900, margin: "0 auto", padding: "2rem 1rem" }}>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 24,
}}
>
<h1 style={{ margin: 0, fontSize: 26, fontWeight: 800, color: "#fff" }}>
My Accounts
</h1>
<button
onClick={() => setShowForm(!showForm)}
style={{
background: "#3F51B5",
color: "#fff",
border: "none",
borderRadius: 8,
padding: "10px 20px",
cursor: "pointer",
fontWeight: 700,
fontSize: 14,
}}
Comment on lines +15 to +36
def _balance(account: FinancialAccount) -> float:
"""Current balance = initial_balance + income - expenses."""
income = float(
db.session.query(func.coalesce(func.sum(Expense.amount), 0))
.filter(
Expense.account_id == account.id,
Expense.expense_type == "INCOME",
)
.scalar()
or 0
)
expenses = float(
db.session.query(func.coalesce(func.sum(Expense.amount), 0))
.filter(
Expense.account_id == account.id,
Expense.expense_type != "INCOME",
)
.scalar()
or 0
)
return round(float(account.initial_balance) + income - expenses, 2)

@jwt_required()
def create_account():
uid = int(get_jwt_identity())
data = request.get_json(force=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multi-account financial overview dashboard

2 participants