A lightweight, high-performance personal budget application designed for resource-constrained environments. It features a modern React/TypeScript frontend powered by Vite and TailwindCSS, and a Go backend implementing Clean Architecture to ensure scalability and maintainability.
The system is built to run on low-memory VPS instances by utilizing SQLite with efficient memory management, while providing advanced multi-currency tracking, customizable entities, and flexible "NoSQL-like" capabilities for transaction metadata.
This application provides a secure and highly customizable way for users to:
- Fully Custom Entities: Users can create custom categories, currencies, and accounts (payment methods) without being constrained to standard lists.
- Smart Multi-Currency Tracking: Set custom exchange rates to convert transactions from various currencies into a single unified currency for effortless global wealth tracking.
- Automated Account Balances: Track balances across different accounts (payment methods). Creating or updating a transaction automatically adjusts the corresponding account balance.
- Filter & Search: Retrieve transactions based on custom date ranges, categories, currencies, or payment methods.
- Analyze Habits: View statistical breakdowns of spending and income habits over specific periods.
- Flexible Metadata: Attach arbitrary tags, memos, or location data to any transaction without altering the database schema.
The project uses SQLite. To maximize flexibility, I intentionally avoid strict foreign keys, meaning if you delete a custom category or currency, your historical transaction records remain completely intact.
| Column | Type | Description |
|---|---|---|
id |
INTEGER PK |
Auto-incrementing primary key. |
user_id |
TEXT |
Firebase UID to enforce data isolation per user. |
amount |
INTEGER |
Stored in cents/smallest unit to avoid floating-point errors. |
currency |
TEXT |
Code mapping to user's custom currency (e.g., USD, EUR). |
type |
TEXT |
Transaction type: income or expense. |
category |
TEXT |
User-defined category name (e.g., Food, Salary). |
payment_method |
TEXT |
Maps to the user's account name (e.g., Credit Card). |
transaction_at |
DATETIME |
The actual time the transaction occurred. |
metadata |
JSON |
Flexible attributes. Stores optional data (tags, location). |
Tracks real-time balances per payment method and currency.
id,user_id,name(payment method name),currency,balance(auto-updated INTEGER).- Unique Constraint:
(user_id, name, currency)
Stores user-defined custom categories.
id,user_id,name,type(incomeorexpense).- Unique Constraint:
(user_id, name, type)
Stores user-defined custom currencies.
id,user_id,code.- Unique Constraint:
(user_id, code)
The database utilizes heavily optimized indexes for frequently queried patterns:
transactions: Indexed byuser_id,(user_id, transaction_at),(user_id, type),(user_id, category).- User Preferences: Indexed by
user_idacrosscategories,currencies, andaccounts.
The backend exposes a RESTful API. Below is the mapping of Controller Endpoints to the underlying Business Logic.
POST /: Create a transaction. Automatically updates the linked account's balance.GET /: Retrieve a list of transactions. Supports extensive filtering:start_date,end_date,currency,type,category,payment_method,limit, andcursor(for high-performance pagination).PUT /:id: Update an existing transaction. Automatically recalculates and adjusts the affected account balances.DELETE /:id: Remove a transaction and revert the balance adjustment on the associated account.
GET /summary: Get total income, total expense, and net balance for a specific period (start_date,end_date).GET /category: Breakdown of spending/income by category (for pie charts). Filterable bystart_date,end_date, andtype.
These endpoints allow users to fully customize their financial environment. All follow standard CRUD (POST /, GET /, GET /:id, PUT /:id, DELETE /:id).
- Currencies (
/api/v1/currencies): Manage custom currencies. - Categories (
/api/v1/categories): Manage custom categories (filterable bytypein theGETlist endpoint). - Accounts (
/api/v1/accounts): Manage accounts/payment methods and view their running balances.
The project follows Clean Architecture to maintain separation of concerns:
budget-app/
βββ backend/
β βββ cmd/api/ # Application Entry Point
β βββ internal/
β β βββ domain/ # Structs: Transaction, Account, Filters
β β βββ usecase/ # Logic: Balance recalculation, validation
β β βββ repository/ # Data: SQLite implementation
β β βββ delivery/http/ # Transport: Echo handlers, Request parsing
β βββ pkg/
β β βββ firebase/ # Firebase Auth client
β β βββ database/ # SQLite connection
β βββ ...
βββ frontend/ # React + TypeScript + Vite + Tailwind
βββ .env.example # Environment template
- Vite & TailwindCSS (Frontend): Transitioned to Vite for significantly faster HMR and build times. TailwindCSS is used for a utility-first, highly responsive, and maintainable styling system.
- Go (Backend): Chosen for its low memory footprint (10-30MB RAM) and high concurrency performance, making it ideal for the target micro-server environment.
- SQLite (Database): Selected to avoid the memory overhead of running a dedicated DB process. The database lives in a single file, simplifying backups.
- No Foreign Keys: Deliberately omitted database-level foreign keys for
categories,currencies, andpayment_method. This offers maximum flexibility: users can write records easily, and deleting a custom category or currency will not break or cascade-delete historical transaction records. - JSON Column: Used to store variable attributes without needing complex join tables, offering a "NoSQL" experience within SQL.
- Go 1.21+
- Node.js 18+
- Firebase Project Credentials
- Navigate to
backend/. - Check env variables in main.go
- Install dependencies:
go mod tidy. - Run the server:
go run cmd/api/main.go
- Navigate to
frontend/. - Install dependencies:
npm install. - Ensure your
.envcontains the correct Firebase config and Backend API URLs. - Start the Vite development server:
npm start





