Back to home page

build

Tally

What left your bank and what you actually spent, both answered, for two people sharing money.

the problem

Two people sharing money need two answers from one ledger: what left the bank, and what each person really spent.

why it hurts

Topping up a joint account or settling up looks like spending, so the same dinner gets counted twice and the balance between you drifts.

what i built

Tally, a shared expense tracker for two: merchant memory that fills in the category, account and split, and four numbers worked out when read.

how it works

One ledger, and four numbers worked out when read.

Merchant memory

Type three letters of a shop and it fills in the category, the account and the split, remembered per merchant. It never fills in the amount.

Transfers stay transfers

Topping up the joint account and settling up are transfers, so a dinner already logged is never counted twice.

Four numbers

Cash out, each person's real share, household spend counted once, and the running balance between us.

in detail

Merchant memory: three letters of Sainsbury's and the category, the card and the 50/50 split are filled in. The amount never is. Invented data throughout.

01 / 04

Merchant memory: three letters of Sainsbury's and the category, the card and the 50/50 split are filled in. The amount never is. Invented data throughout.

The four numbers, worked out when read: what left my accounts, my real spend, household spend counted once, and the running balance between us.

02 / 04

The four numbers, worked out when read: what left my accounts, my real spend, household spend counted once, and the running balance between us.

One ledger, searchable: every Sainsbury's shop this month, whoever paid and from whichever card.

03 / 04

One ledger, searchable: every Sainsbury's shop this month, whoever paid and from whichever card.

Settling up is a transfer, not spending: the balance goes to all square and no category moves.

04 / 04

Settling up is a transfer, not spending: the balance goes to all square and no category moves.

why it's useful

In daily use for shared money, with no bank linking, no receipt scanning and no AI coach, by decision.

what i learnt

  • Never prefill an amount: a wrong number can be saved without being read.
  • A prediction has to be cheap to reject. Override it once and autofill stops touching that entry.
  • Personalisation does not need a model. The hard questions are what to learn about someone and what never to presume.

technical specs

React 19TypeScriptViteTailwind CSS v4Supabase (Postgres, magic link auth, row-level security)Installable PWAVercel
  • A transaction stores only what happened: the amount charged, the account it left, who paid, and one row per person for their share.
  • The four numbers are computed at read time, never stored: cash out, each person's real share, household spend counted once, and the running balance between two people. A figure that looks wrong traces back to its rows.
  • Transfers are their own kind of entry, so topping up a joint account or settling up never counts as spending.
  • Merchant memory fills in the category, the account and the split from the merchant, through a pure, unit-tested normalisation module, so "Sainsbury's", "sainsburys" and "SAINSBURYS" are one memory. It never fills in the amount, and an entry overridden once is left alone.
  • Magic link sign-in. Row-level security is scoped to household membership through a single security-definer function, which stops the members policy recursing into itself.
  • Its own Postgres schema with schema-scoped grants.
  • An installable app, phone screens only, with no bank linking, no receipt scanning and no AI, by decision.
Back to home page