Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BananaBook

A forward-looking checkbook for the account that pays your bills. It projects the balance forward and names the exact date it runs dry — so the bills stay funded, and whatever sits in your other account is genuinely yours to spend.

CI License: MIT

The projection view, showing an overdraft four months out

The method

BananaBook is built to support a specific, deliberately simple way of managing money — one designed to reduce financial stress and to minimize the time spent thinking about it at all.

  1. Open a separate account just for recurring bills.
  2. Automatically divert a fixed portion of every paycheck into it, enough to cover those bills as they come due.
  3. Spend freely from whatever is left. The balance in your everyday account is money you can spend without arithmetic, because every bill is already funded from somewhere else.

The appeal is what it removes. No categories, no envelopes, no weekly budget review, no deciding whether this purchase is affordable. One number in one account answers that.

The hard part is step 2 — picking the transfer amount, and knowing whether it is still right six months later. Bills change. Annual costs land in a lump. Set the transfer too low and the bills account quietly drains until something bounces; set it too high and money that could have been spent or invested sits there doing nothing.

That is the job BananaBook does. It models the bills account so you can:

  • Size the transfer — adjust the recurring deposit and watch the projected low point move until it settles where you want it.
  • Reconcile quickly — confirm each bill as it lands, at the estimated amount in one click or at what actually hit the account, so the forecast stays true.
  • See a shortfall coming — with a date attached, months before it happens.
  • Catch over-funding — if the projected low point never dips near zero, you are parking more than you need and can dial the transfer back.

What it looks like

Most budgeting tools are rear-view mirrors: they categorize what already left your account. That is useful for judging the past and useless for answering the question that actually matters — are the bills covered, and for how long?

BananaBook answers with a date. In the screenshot above, the monthly bills account holds $1,647.40 and looks perfectly healthy. It isn't: the transfers are running about $118/month short of what the bills actually cost, so the account drains a little each month and rent is the line that finally bounces. It crosses zero on December 1, 2026 at -$304.60, and keeps sinking to a low of -$1,320.60. That is 134 days of warning — long enough to raise the transfer by a few dollars a paycheck and never notice the problem again.

Nothing in that view is a category or a chart. It is the ledger you would have written out by hand, run forward.

Features

  • Balance projection — every account projected forward from a starting balance plus recurring deposits and expenses, over a horizon you choose (1 month to 2 years).
  • Overdraft date — the headline verdict on every account: how many days until the balance goes negative, on what date, and how deep it goes.
  • Recurring transactions — daily, weekly, bi-weekly, monthly, or yearly, with optional end dates, and the ability to deactivate one without deleting its history.
  • The reconcile loop — confirm each projected item as it happens, either at the estimated amount (one click) or at what actually hit the account. The forecast you trusted last month stays honest this month.
  • Projected vs. actual — reconciling at a different amount records the variance instead of hiding it, and can optionally update the recurring estimate going forward.
  • Lowest projected balance — the floor the account is heading for over the whole horizon, which is what tells you whether you are under- or over-funding the transfer.
  • Multiple accounts — split the bills that are hard to hold in your head from the ones that aren't: a monthly account for the steady stuff, an annual account for the lumps. Each is projected independently.
  • No account linking — nothing connects to your bank. You type the numbers in; they stay on your machine.
  • Light and dark — follows your system theme by default, with a switch in the header to pin either one. The choice is stored in the browser, per device.
The account list: a monthly bills account and an annual bills account

Splitting the bills across two accounts is worth doing because the two kinds fail differently. Monthly bills are steady enough that a shortfall hides for months — the case above. Annual bills do the opposite: nothing happens, nothing happens, and then property tax lands in one lump. Holding them apart means a bad month in one never disguises itself as a good month in the other.

Note what is not here: the everyday spending account. It carries no recurring items and needs no forecast, so BananaBook does not track it at all. Its balance is already the answer — that is the entire point of funding the bills from somewhere else.

Security and threat model

Read this before you deploy anything.

BananaBook has no authentication whatsoever. There are no users, no login, no sessions, and no authorization checks. Anyone who can reach the port can read, edit, and delete every financial record in the database.

That is a deliberate design choice for its intended use — a single self-hosted household instance on a trusted home network, where everyone in the house is meant to see the same numbers. It is emphatically not safe to expose to the internet.

Run it on localhost or a trusted LAN only. If you need remote access, put it behind something that actually does authentication — a VPN such as WireGuard or Tailscale, or a reverse proxy enforcing auth in front of it. Do not simply forward a port.

Also note:

  • There is no rate limiting, CSRF protection, or audit logging.
  • The SQLite database is stored unencrypted on disk.
  • synchronize: true is enabled in TypeORM (see Known limitations).

Found a security problem? See SECURITY.md.

Quick start

Requires Node.js 20 or newer.

git clone https://github.com/majoragee/bananabook.git
cd bananabook
npm install
npm run dev

Open http://localhost:3000. The SQLite database is created automatically on first run; there is no migration step and no seed data.

To set it up the way the method intends: create one account for your bills, set its starting balance to whatever is in the real account today, then add your recurring bills as expenses and the automatic paycheck transfer as a deposit. The projection — and the date you run dry — appears immediately. Adjust the transfer amount until the lowest projected balance sits at a cushion you are comfortable with.

Running the tests

npm test

The suite covers the projection engine — frequency expansion, end dates, the running balance, the overdraft date, and the reconcile loop. It runs against a temporary SQLite database with the clock frozen, so it never touches your data and never depends on today's date.

Docker

A prebuilt image is published to GitHub Container Registry for linux/amd64 and linux/arm64, so it runs on an x86 server or a Raspberry Pi without building anything:

docker run -d \
  --name bananabook \
  -p 3000:3000 \
  -v bananabook-data:/app/data \
  ghcr.io/majoragee/bananabook:latest

Or with compose, building from source instead:

cp docker-compose.yml.example docker-compose.yml
docker compose up -d

Then open http://localhost:3000. Data persists in the bananabook-data volume.

Available tags: latest (most recent release), 0.1.0 / 0.1 (specific versions), main (tip of the default branch), and sha-<commit> (an exact commit). Pin a version tag for anything you care about — main moves.

Full deployment notes, including backup and restore, are in README.docker.md.

Configuration

Copy .env.example to .env for local development.

Variable Default Purpose
NODE_ENV development Standard Node environment flag.
DATA_DIR current directory Where bananabook.db is written. Set to /app/data in Docker.
PORT 3000 The web port — the one you open in a browser.
API_PORT 3001 The internal API port. Change it if something else on the machine already uses 3001.
API_HOST 127.0.0.1 Interface the API binds. Loopback by default; there is rarely a good reason to change it.

PORT and API_PORT are independent, so either can be moved without disturbing the other, and both take effect at startup — no rebuild. If you run BananaBook on bare metal and 3000 or 3001 is already taken, set the one you need:

PORT=8080 API_PORT=8081 npm start

Or put them in a .env file — copy .env.example to .env and edit. Both processes read it, in development and production alike. Anything already set in the environment takes precedence over the file, so Docker's environment: block and a one-off PORT=8080 npm start still win.

The API binds loopback and is reached through the web server's /api proxy, so it is never a published surface: only PORT needs to be reachable from anywhere else.

How the projection works

server/routes/projections.ts builds the forecast for an account:

  1. Start from the account's startingBalance at its startDate.
  2. Expand every active recurring transaction across the requested horizon, stepping by its frequency and stopping at its endDate if it has one.
  3. Replace any projected item that has been reconciled with the real transaction, so actuals always beat estimates.
  4. Sort by date and accumulate a running balance.
  5. Report the first entry where the balance drops below zero — that's the overdraft date.

Tech stack

Frontend Next.js 16 (App Router), React 19, Tailwind CSS 4
Backend Express 5, TypeORM 0.3
Database SQLite via better-sqlite3
Language TypeScript
Deploy Docker, multi-stage build, runs as a non-root user

The design brief the interface is built against lives in PRODUCT.md.

Known limitations

Worth knowing before you trust this with anything important:

  • No authentication. See Security and threat model.
  • synchronize: true. TypeORM alters the SQLite schema to match the entity definitions on every boot. Convenient in development, but it means a future schema change could alter or drop a column on upgrade. Back up bananabook.db before updating. Proper migrations are on the roadmap.
  • Money is stored as floating point. Amounts are decimal columns read back as JS numbers, so arithmetic can drift by fractions of a cent. Display is rounded to two decimals, but the underlying values are not exact. Integer-cents storage is on the roadmap.
  • A monthly item dated the 31st drifts. Months without a 31st roll the occurrence into the following month (Jan 31 → Mar 3), rather than clamping to the last day. There is a test pinning this behaviour so it can be fixed deliberately.
  • Test coverage is partial. The projection engine is covered; the routes around it are not.
  • Single currency, no formatting options. Amounts are rendered as USD.

Roadmap

  • Test coverage for the API routes, not just the projection engine
  • Clamp monthly items to the last day of short months
  • Database migrations, replacing synchronize: true
  • Integer-cents money storage
  • Optional authentication for non-LAN deployments
  • CSV import and export

Contributing

Issues and pull requests are welcome — see CONTRIBUTING.md. This is a personal project built for one household's needs, so it is opinionated about scope; opening an issue before a large PR will save you time.

License

MIT © majoragee

AI disclosure

AI assistance was used in the development of this project.

About

An opinionated forward-looking checkbook register: projects your account balance from recurring income and bills, and tells you the date it goes negative.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages