KassenKnoten

KassenKnoten

Two incomes, one household, one clear plan.

The household planner for people who share costs unevenly — and want the maths to be right. Rent by income, electricity down the middle, the gym only one of you uses. Every item gets its own rule, and both of you see what it costs while you type.

Exact to the cent — no float ever touches money One container for amd64 and arm64 No telemetry, no external calls MIT licence
The overview: income, fixed costs, variable costs, savings rate and free cash as headline figures, with the per-person breakdown and costs by category beneath.
The current month at a glance — and any other month, because every entry knows which months it applies to.

The problem

Every tool gets this half right.

Splitting apps assume one rule for everything. Spreadsheets can express it — until one cell slips and the formula is quietly wrong for months. KassenKnoten makes the split a deliberate choice per item, computes it to the cent, and shows you the result while you type.

Every cost its own rule

Fixed quota or proportional to income — chosen per item, never assumed. The household default only pre-fills the form.

Exact to the cent

Amounts are whole cents, shares are basis points. 39,99 € down the middle becomes 20,00 € and 19,99 € — never 39,98 €. The calculation engine is a pure, tested module.

The past stays honest

Every entry carries the months it applies to. A raise in September leaves August reporting August — and the app asks whether a change is new from now on or was always true.

Variable costs, two ways

Groceries, fuel, going out: either the plan counts — or every receipt with its date, and the plan becomes the budget you measure against.

Every rhythm normalised

A 132,00 € yearly insurance sits next to everything else as 11,00 € a month. Nobody divides by twelve in their head again.

Save on purpose

Savings pots with a monthly rate, a balance and an optional target — owned by one person or by the household.

Calm warnings

Negative free cash, a savings rate above income, an overspent budget — as a calm banner, not a modal. Deleting offers “Undo” instead of asking “are you sure?”.

Installable as an app

Own icon on the home screen, opens without an address bar. Browsers that cannot install a web app are told where the option lives in their own menu.

English or German

Chosen when you set up and changed whenever you like. The language belongs to the household, not to a browser — the tablet in the kitchen speaks the same one as the laptop.

Extend it with your own code

Upload an extension and it contributes cards to the overview. It runs on your server with full access — install only what you have read, or what comes from someone you trust.

Your data stays yours

One SQLite file on a volume you control. Versioned JSON backups and CSV export; restoring runs in a single transaction.

Shared fixed costs

Who pays what — and why.

Every shared item shows both shares in euros and percent, and which rule produced them. The split is previewed as you type, by the same function that later saves it — a preview that calculates a second way is a preview that can disagree with the result.

  • Fixed quota or by income, decided per item
  • Largest remainder: the shares always add back up to the total
  • Private and shared kept cleanly apart
Shared fixed costs: every row shows both members' shares in euros and percent, and the split rule that produced them.

Variable costs

A plan, or every receipt.

Anything that is not the same every month gets a budget — and you decide per budget how it is kept. Plan counts the figure you set and asks nothing more. Detailed counts what was actually booked, every expense with its date.

  • The mode is a badge on the card, not a setting in a dialog
  • Booked against planned, always side by side
  • Split between you exactly like a fixed cost
Variable costs: a shared budget in detailed mode with a progress bar, both members' shares, and the individual expenses with their dates.

Savings

Saving you can see.

Pots with a rate, a balance and an optional target. Progress is a bar rather than mental arithmetic — and when a pot passes its target, the overview says so kindly.

Savings pots with a monthly rate, current balance, target and a progress bar.

On a phone

Designed at 375 px, not shrunk to it.

A household plan gets opened in the kitchen, not at a desk. Same features, navigation within thumb reach, an amount field that brings up the number pad, and a design that follows the system theme.

  • Light and dark, following the system
  • Installable as an app, with its own icon
  • Offline it says so, instead of showing yesterday's figures
The overview on a phone in dark mode. The sign-in screen with the household password and the field for the one-time code.

Security

They are your figures. They are treated that way.

Password and a second factor

One household password, hashed with argon2id and read from the environment — a copy of the database is not a copy of the password. Optionally a code from any authenticator app (TOTP, RFC 6238). A code that has been used is refused.

Encrypted session

The session cookie is encrypted, not merely signed (JWE, A256GCM), httpOnly, SameSite=Lax und Secure over HTTPS.

Everything closed but what must be open

Every route but the login and the health check requires a session — deny by default, so a new page cannot accidentally be public. Server actions check again themselves.

Nothing from outside

A Content-Security-Policy with a per-request nonce, self-hosted fonts, no CDNs, no telemetry. The container runs as an unprivileged user.

Self-hosting

Docker and two minutes.

No checkout, no Node, no build: the image is published for amd64 and arm64, so a Raspberry Pi is as much a target as a NUC. Download two files, generate two secrets — the scripts for that run inside the image — and start. The database is created and migrated on first use.

mkdir kassenknoten && cd kassenknoten
curl -LO https://github.com/jankln/KassenKnoten/releases/latest/download/docker-compose.yml
curl -L -o .env https://github.com/jankln/KassenKnoten/releases/latest/download/env.example

# a session secret
echo "SESSION_SECRET=$(openssl rand -base64 32)" >> .env

# your household password, hashed
docker run -it --rm ghcr.io/jankln/kassenknoten:latest \
  node scripts/hash-password.ts

# optional: a second factor, prints a QR code into your terminal
docker run -it --rm ghcr.io/jankln/kassenknoten:latest \
  node scripts/totp-secret.ts

docker compose up -d

Then open http://127.0.0.1:3000 — a three-step wizard sets up the household. For access from outside the machine, put a reverse proxy with TLS in front.