Envelope (zero-based) budgeting for one Indian household. Self-hosted, server-rendered, installable as a PWA. TypeScript on Node 24+, SQLite, no runtime dependencies.
Pathayam (പത്തായം) is the wooden granary of a Kerala house: filled once at harvest, drawn from deliberately through the year.
2140 tests · 0 runtime dependencies · 59 migrations · 209 routes
- Envelope budgeting. Income is assigned to envelopes until nothing is unassigned. Envelope balances roll over. Overspending is resolved explicitly, under one of two models.
- Credit cards. Spending on a card moves cash into that card's payment envelope. The interface reports how much of a card balance no envelope is funding, and what clears it.
- Indian banking. Statement PDFs from eleven banks, with passwords derived from name, date of birth, PAN and mobile. UPI narration parsing. Reducing- balance and flat loans, rate changes, prepayment comparison, EMI conversion. CAS portfolio import. Realised gains by financial year.
- Per-member privacy. A shared household budget plus an optional personal budget per member, excluded from the other members' lists, reports, exports, activity log and totals.
- Schedules that split. A salary into provident fund, tax and what landed; rent into rent and maintenance. The first envelope takes whatever the later lines do not claim, so a recurring split cannot be quietly wrong every month, and marking the schedule paid records a split transaction.
- Tax estimate. Income tax under both regimes, side by side, with 80C, 80D and the HRA exemption, and capital gains at their own rates rather than at slab rates — an estimate on figures you enter, not a return and not advice. Slabs are data keyed by financial year, so a year the app does not have rates for is refused rather than computed with last year's.
- Financial independence. A target drawn from what the household actually spent, against the assets that could actually fund it — a home is on the net worth statement, not here. Assumes no further earnings, and reports the years a locked provident fund leaves uncovered.
- Ownership. One SQLite file in an open format, complete export, no telemetry, no third-party service holding the data — and no third-party service needed to sign in, either. Password sign-in is built in, any OpenID Connect provider works, and Google is optional.
npm install
npm run dev # http://localhost:8080With 36 months of generated data:
DATA_DIR=./demo-data npm run demo
DATA_DIR=./demo-data DEMO_MODE=1 npm run devWith Docker:
docker compose up -d # production; requires BASE_URL in .env
docker compose --profile dev up # development, with the login bypassConfiguration, sign-in (password, OpenID Connect or Google), backups and restore: docs/operations.md.
| docs/architecture.md | Process model, modules, request lifecycle, storage. |
| docs/data-model.md | Every table and its columns. |
| docs/budgeting.md | Engine definitions, formulas, overspend models, targets. |
| docs/accounts.md | Account kinds, transactions, transfers, splits, reconciliation. |
| docs/money-in.md | CSV, PDF statements, Gmail, duplicates, rules. |
| docs/loans-and-assets.md | Loans, lending, portfolio, net worth. |
| docs/privacy.md | Visibility model and enforcement. |
| docs/security.md | Authentication, authorisation, headers, input handling. |
| docs/screens.md | Every route. |
| docs/operations.md | Deployment, configuration, backup, restore. |
| docs/testing.md | Running and reading the suite. |
| docs/limitations.md | Known constraints. |
| docs/API.md | HTTP API and access tokens. |
docs/archive/ holds the original design specification, cited
from source comments by requirement identifier.
Three invariants are checked mechanically rather than against expected values:
-
The accounting identity — zero residual, in integer paise, for every month in every budget:
Σ budget-account balances + due from other budgets = Σ category balances + Ready to Assign + held for next month + Σ future assignments − unfunded credit absorbed -
Cache against ledger — every month computed from the rollup cache and from the raw ledger, and required to agree.
-
Statement reconciliation — a parsed statement's amounts must satisfy the bank's own printed opening and closing balances.
A 36-month simulation of a household of four exercises every mutating domain function and asserts (1) and (2) after each month. Details: docs/testing.md.
| Screen | Route | What you see |
|---|---|---|
| Budget | / |
The month grid: groups, categories, assigned/activity/available, Ready to Assign, the in-app digest. |
| Accounts | /accounts |
Every account with cleared/uncleared/working balances; each opens a register. |
| Cards | /cards |
Every credit card in the order it falls due: what is owed, what is set aside, what has nothing behind it, and the statement and due date when one has been recorded. |
| Register | /accounts/:id |
A running-balance transaction list for one account, with reconcile. |
| Transaction | /transaction/:id |
Edit, splits, tags, owner; raw imported values; full event history; receipts. |
| Add | /add |
One form for money in, money out and transfers. Envelopes are a list of lines, the first taking the remainder; an expense must name one, income may leave it blank and land in Ready to Assign. |
| Move money | /move |
Move between envelopes, with a note explaining that this never changes Ready to Assign. |
| Hold | /hold |
Keep part of this month’s Ready to Assign for next month — how you get to spending last month’s income. |
| Review | /review |
Everything awaiting a decision: imports, suspected duplicates, uncategorised (filed inline), overspent, unfunded cards, proposed rules, and money you're owed. |
| Import | /import |
CSV paste / statement-PDF upload with password hints; saved mappings. |
| Reports | /reports |
Income vs. spend, category trends, loan interest by FY, realised gains by FY split by holding period. |
| Overview | /overview |
Runway, due-soon bills, the month at a glance. |
| Query | /query |
The filterable, groupable table; CSV export. Totals are summed over every matching row, not the page you can see. |
| Search | /search |
Everything, from one box — reachable with / from any screen. |
| Schedules | /schedules |
Recurring items and the forward cashflow calendar. |
| Goals | /goals |
Long-horizon savings with progress rings. |
| Loans | /loans, /loans/:id |
Each loan's real cost, schedule, drift, prepayment calculator, disbursements. |
| Family lending | /family |
Lent / borrowed, derived balances, write-off. |
| Portfolio | /portfolio |
Holdings as units, XIRR, allocation, CAS import, CSV export. |
| Valuations | /portfolio/valuations |
Every hand-valued pot — gold, retirement, anything outside CAS — updated in one sitting, each showing what it was last worth and when. |
| Net worth | /net-worth |
The four-way decomposition and dated history. |
| Month close | /months |
The monthly ritual and closed-month history. |
| Payees | /payees |
Every payee, what it is usually filed as, and merge. |
| Rules | /rules |
Automatic categorisation: what fires, what the app has proposed from your own filing, and a tester. |
| Categories | /categories |
Rename, set targets, reorder with ↑/↓, hide, delete. Payment and goal envelopes are marked managed by the app. |
| Activity | /activity |
Every change ever made, and the undo for it. Where later edits touched the same record, the undo shows what it would discard first. |
| Settings | /settings |
Household, theme, devices, Gmail connection, statement identity, notification prefs, API tokens. |
| Health | /health |
Backup status, restore verification, price feeds, feature flags, error counts. |
| Terms / Privacy | /terms, /privacy |
Public, signed out — Google's consent screen requires both before it grants gmail.readonly. |
Captured from a running instance with the 36-month demo household, dark theme.
| Portfolio | Net worth |
|---|---|
![]() |
![]() |
| Allocation | Loans |
![]() |
![]() |
| One loan | A rate reset |
|---|---|
![]() |
![]() |
| What a prepayment buys | A charge becoming an EMI |
|---|---|
![]() |
![]() |
| Accounts | Review queue |
![]() |
![]() |
| Import | Schedules |
![]() |
![]() |
| Goals | Reports |
![]() |
![]() |
| Health | Settings |
![]() |
![]() |
| Categories | Overview |
![]() |
![]() |
| Activity | Cards |
![]() |
![]() |
| Query | Valuations |
![]() |
![]() |
Every figure, name and account number is generated. No real financial data appears in this repository.
To regenerate after a UI change:
DATA_DIR=./demo-data npm run demo
DATA_DIR=./demo-data DEMO_MODE=1 PORT=8080 npm run dev
node docs/dev/capture-screenshots.mjs --port 8080It drives headless Chromium over the DevTools protocol with no driver library, signs in through the demo or development door, and removes the deployment banner so the images document the application rather than the instance.
Every chart is server-rendered inline SVG. There is no client-side charting library; the CSP forbids third-party script. Charts follow the theme and each sits beside the same figures as text.
| Allocation — donuts by class, geography and currency |
|---|
![]() |
| Loans — the amortisation curve and tranche drawdown | Reports — income vs spend, net saved |
|---|---|
![]() |
![]() |
| Schedules — the next 60 days of cashflow | Goals — progress rings |
|---|---|
![]() |
![]() |
Reports carries four more that are easier to read in place than cropped out: a spending treemap, a GitHub-style spending calendar heatmap, a Sankey of where the month's money went, and a sparkline per category. Net worth adds an asset-composition donut and a net-worth-over-time line. All of them are in the full-page Reports and Net worth captures.
Fully listed in docs/limitations.md. The principal ones:
- Past months are recomputed from current data rather than frozen; closed months record their figures.
- No bank API connections and no SMS parsing.
- No offline mode; the application requires its server.
- Payee names extracted from some statement PDFs contain spaces inside words.
- The database is not encrypted at rest.
npm run typecheck
npm testBoth must pass. New behaviour requires a test that fails without it. Changes affecting money must leave the accounting identity closing.
Contributions are licensed to Flaxvin Technologies so the licence can be granted on other terms where needed. See CONTRIBUTING.md.
Pathayam is free to run yourself and always will be. If it saves you money or time and you would like to put something back:
UPI: febinnizar-1@okaxis — or
tap to pay on a
phone with a UPI app installed.
Entirely optional. Nothing in the software is gated behind it, no feature depends on it, and nothing asks you for it again. Contributions are a thank-you to the author rather than a purchase — you get no goods, service or support in return, and they are not tax-deductible.
PolyForm Noncommercial License 1.0.0.
Use it, change it and share it for any noncommercial purpose — your own household, study, research, a hobby project, a charity, a school, a government body. All of that is permitted, with no limits and nothing withheld.
Commercial use is not permitted under this licence. That includes running it inside a business, using it to keep the books of a company or a freelance practice, and offering it to anyone else as a product or service. If you want to use it commercially, ask: hello@flaxvin.tech.
Source available, not open source. The noncommercial limit is the difference, and it does not expire.




























