- TypeScript 59.7%
- Python 38.7%
- CSS 1.1%
- Dockerfile 0.2%
- HTML 0.2%
- Other 0.1%
| .roo/rules | ||
| backend | ||
| frontend | ||
| .env | ||
| .env.example | ||
| ARCHITECT_LOG.md | ||
| docker-compose.yml | ||
| README.md | ||
zBudget
A self-hosted personal finance application with a clean dark and light UI. Track transactions, manage accounts, set budgets, create auto-categorize rules, and view spending reports — all running locally in Docker with no cloud account required.
Features
Dashboard
- Monthly net balance, total spending, total income, and net worth summary cards with month-over-month % change
- Running balance area chart (last 60 days)
- Spending-by-category pie chart for the current month (all categories, no truncation)
- Budget health progress bars with budget alerts (≥80% warning, >100% over-budget)
- Upcoming bills widget — projected future occurrences of recurring transactions plus actual flagged transactions, combined and sorted by date
- Account filter — scope all dashboard stats to a single account or view all accounts combined
- Empty-state CTAs guide new users to set up accounts, categories, and budgets
Transactions
- Add expenses or income with an Expense/Income toggle (sign applied automatically)
- Transaction detail drawer with inline category/account assignment and rule creation
- Inline category and account assignment directly in the table (click to edit)
- Multi-select rows with bulk delete, bulk category, and bulk account assignment
- Split a transaction into multiple line items with individual categories
- Mark transactions as recurring with an interval (weekly, monthly, biweekly, yearly)
- Generate next occurrence — manually advance a recurring transaction to its next date
- Link transactions to an account
- Pagination (20 / 50 / 100 rows per page)
- Search by payee or memo; filter by type, date range, account, and recurring flag
- CSV export of visible transactions
- Import with preview — preview parsed transactions before committing, see which are already imported, and see rule-suggested categories
- Import undo — roll back an entire import batch atomically
- Deduplication — three-layer dedup prevents overlapping statement imports from creating duplicates
- Uncategorized transaction count badge on the sidebar nav item
Accounts
- Create checking, savings, credit card, investment, and other account types
- Real-time balances — each account card shows its computed balance from all linked transactions
- Transfers — transfer money between two accounts with a single form (creates linked debit/credit pair, net worth unchanged)
- Color-coded cards per account type
- Drag to reorder — rearrange account cards; order is saved and shared across the app
- Edit and delete accounts (transactions are unlinked, not deleted)
Budgets
- Set spending limits per category with optional start and end dates
- Progress bars with colour-coded health (green → amber → red) and over-budget indicators
- Budget alerts — the Dashboard highlights budgets at ≥80% consumed (amber) or over 100% (red)
- Drag to reorder — arrange budget cards in any order; persists across sessions
Categories
- Per-user categories — each user creates their own categories, isolated from other users
- Shared system defaults (Housing, Food & Dining, Transport, etc.) visible to all users
- Seed Defaults — populate the 9 default categories in one click
- Edit and delete at any time (transactions and budgets are nullified, not deleted)
Rules
- Create auto-categorize rules that match payee names (contains / exact / starts with)
- Rules are applied automatically when transactions are imported and during preview
- Full CRUD management from the Rules page or inline from the transaction detail drawer
Reports
- Period selector: Last 30 days, 90 days, 6 months, year-to-date, last 12 months
- Summary cards: total spent, total income, net savings, savings rate
- Year-over-year comparison — income, expenses, and net vs. the same period last year with % change
- Monthly income vs. expenses bar chart
- Spending-by-category pie chart
- Category breakdown table with percentages (up to 15 categories)
- Top 10 payees by spend
- Account filter — scope all report data to a single account
- Print / Save as PDF button
Settings
- Change password and update email
- Appearance and preference options
General
- Dark / Light / Auto mode — toggle between dark, light, and system-preference (auto) themes
- Custom confirm modals — all destructive actions use a styled confirmation dialog
- Backup & Restore — export/import full JSON backup from the sidebar or as a dedicated section in Settings
- Rate limiting — login (10/min) and registration (3/hour) are rate-limited per IP
- Refresh tokens —
POST /auth/refreshissues a new access token without re-login - Toast notifications for all user actions
- Fully responsive layout with mobile drawer navigation
- Multi-user — each user's data is fully isolated
Tech Stack
| Layer | Technology |
|---|---|
| Frontend | React 19 + TypeScript, Vite 8, Tailwind CSS v4, Zustand 5, Recharts 2, @dnd-kit, Axios |
| Backend | FastAPI 0.109, Python 3.11, SQLAlchemy 2.0, python-jose (JWT), passlib + bcrypt |
| Database | PostgreSQL 15 |
| Packaging | Docker + Docker Compose |
Quick Start (Docker)
Prerequisites
- Docker and Docker Compose installed
- Port 3000 available on your host (frontend). The backend and database are internal-only via Docker networking.
1. Clone the repository
git clone https://codevault.sh/zypher-systems/zbudget.git
cd zbudget
2. Create your environment file
cp .env.example .env
Open .env and set your values:
# Strong password for the PostgreSQL database
DATABASE_PASSWORD=change_me_strong_password
# Random secret used to sign JWT tokens — generate one with:
# python3 -c "import secrets; print(secrets.token_hex(32))"
SECRET_KEY=change_me_generate_a_random_secret_key
# Origin(s) the browser will connect from (adjust if running on a server)
ALLOWED_ORIGINS=http://localhost:3000
Security note: Never commit your
.envfile. It is already listed in.gitignore.
3. Build and start
docker compose up -d --build
This builds the backend and frontend images, starts PostgreSQL, and launches all three containers. The first build takes a couple of minutes; subsequent starts are near-instant.
4. Open the app
Navigate to http://localhost:3000 in your browser.
Register a new account and you're ready to go. Use Categories → Seed Defaults to populate common spending categories instantly.
Deploying on a Server
To run on a remote server (VPS, home server, etc.):
-
Clone and configure
.envas above, settingALLOWED_ORIGINSto your server's URL:ALLOWED_ORIGINS=https://budget.yourdomain.com -
Place a reverse proxy (nginx, Caddy, Traefik) in front of port 3000 for 80/443 access.
-
Run
docker compose up -d --build.
Container Overview
| Container | Image | Port | Purpose |
|---|---|---|---|
zbudget-frontend |
Built from frontend/ |
3000 | Nginx serving the React SPA; proxies API calls to the backend internally |
zbudget-app |
Built from backend/ |
internal | FastAPI REST API (not exposed externally) |
zbudget-db |
postgres:15-alpine |
127.0.0.1:5432 | PostgreSQL database (data persisted in a named Docker volume; only reachable from host for direct DB access) |
Useful Commands
# Start all containers in the background
docker compose up -d
# Stop all containers
docker compose down
# Wipe database (schema changes)
docker compose down -v
# View live logs
docker compose logs -f
# View backend logs only
docker compose logs -f app
# Rebuild after code changes
docker compose build --no-cache && docker compose up -d
# Open a PostgreSQL shell
docker exec -it zbudget-db psql -U zbudget_user -d zbudget
Using the App
Getting Started
- Visit http://localhost:3000 and click Create one free to register
- Go to Categories → Seed Defaults to add a standard set of categories
- Go to Accounts → New Account to add your bank and credit card accounts
- Start adding transactions or import a bank statement via Transactions → Import
Transactions
- Click + Add Transaction to open the add form
- Choose Expense (red) or Income (green) — sign is applied automatically
- Optionally link to an account and flag as recurring
- Click any transaction row to open the detail drawer for inline editing
- Use the search bar and filter bar to narrow down results
- Select multiple rows for bulk delete, bulk category, or bulk account assignment
- Click Export CSV to download visible transactions
- Import — upload an OFX/QFX or CSV bank statement. A preview shows parsed rows, rule-suggested categories, and which rows are already imported. Confirm to commit.
- Undo import — if you imported the wrong file, undo removes all transactions from that batch.
Accounts
- Go to Accounts and click + New Account
- Choose from: Checking, Savings, Credit Card, Investment, Other
- Each card shows the real-time balance computed from linked transactions
- Use Transfer (≥2 accounts) to move money between accounts
- Drag the
≡handle on any card to reorder
Budgets
- Go to Budgets and click + New Budget
- Set a name, category, amount, and optional date range
- Budgets show how much has been spent with a colour-coded progress bar
- Drag to reorder — the order reflects in the Dashboard budget health list
Rules
- Go to Rules and click + New Rule, or create one from the transaction detail drawer
- A rule matches a payee name pattern (contains / exact / starts with) and assigns a category
- Rules are applied during import and shown in the import preview
Reports
- Go to Reports and select a time period (30d, 90d, 6m, YTD, 1y)
- Use the account dropdown to scope to a single account
- YoY comparison — see how income, expenses, and net compare to the same period last year
- Click Print / Save PDF to export
Dark / Light / Auto Mode
Click the sun/moon/loop icon at the bottom of the sidebar to cycle through dark, light, and auto (follows system preference). The preference is stored in local storage.
Backup & Restore
The sidebar includes a Backup / Restore section (bottom-left):
- Export backup — downloads a
.jsonfile with all your data - Restore backup — upload a
.jsonbackup to fully rebuild your data
Running Tests
cd backend
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
DATABASE_PASSWORD=test SECRET_KEY=test python -m pytest tests/ -v
API Overview
| Prefix | Purpose |
|---|---|
/auth |
Registration, login, token refresh, password/profile management |
/accounts |
CRUD operations + transfers between accounts |
/transactions |
CRUD, split, CSV export, upcoming bills projection, generate next occurrence |
/categories |
CRUD + seed defaults (per-user isolation) |
/budgets |
CRUD |
/rules |
CRUD (auto-categorization) |
/upload |
OFX/CSV import with preview, batch tracking, and undo |
/stats |
Aggregated summary for Dashboard and Reports (single endpoint) |
/backup |
JSON export and restore |
Data & Privacy
All data is stored locally in the PostgreSQL container volume (postgres_data). Nothing is sent to any external service.
License
MIT