lifeos handbook
Reference

Decision records

Twenty-one ADRs, and what each one settles.

The full text lives in docs/adr/ in the repository. This is the index, so the shape of the argument is visible without opening twenty-one files.

Build and platform

#Decision
0001Record architecture decisions
0002Nx over Gradle + Bun, from day one
0003PostgreSQL over MySQL, because this is a money system
0004No :default on any config placeholder — fail loud at boot
0005CI owns deploys; Cloudflare Workers Builds is off
0018Env lives in exactly two places, and never in a root .env

Identity and access

#Decision
0006A thin IAM — no roles, no 2FA, no directory
0007Backend-for-frontend auth, not SPA + PKCE
0008scope == audience == app id — audience is the whole authorisation model

Money

#Decision
0009Transaction + postings, with transaction fees as the residual
0010Prepaid vendors, debts and money lent out are all accounts
0011Cached balances, proved by reconcile()
0012Envelopes are virtual claims on the pooled balance
0013Allocation order on income: tithe on gross, first
0014Recurring bills create a pending item; they never auto-post
0016Money is DECIMAL(18,2) in TZS; timestamps UTC stored, EAT displayed
0017Corrections are edit-in-place with an append-only change log
0020Open at today's balance; reconcile instead of backfilling
0021A transaction has postings against accounts and lines against categories

Scope and process

#Decision
0015Run 1 stops before any finance entity exists
0019Notifications go through a port: email now, in-app feed, Telegram never assumed

What an ADR is for

Not to prove a decision was right — to record what was known when it was made, what the alternatives were, and what it cost. A decision whose reasoning is only in someone's memory gets re-litigated every six months, usually badly.

On this page