The balance rule lives in the database
Most landlord software stores transactions in a flat list and sums columns to produce a report. That is fine until one write goes wrong, and then nothing tells you. Here, an entry whose debits and credits do not match is rejected by Postgres itself, at commit time.
- Enforced by a deferred constraint trigger, not by application code
- Applies to every write path — imports, integrations, and future features alike
- An entry must have at least two lines; a lone dangling line cannot exist
- Verified by tests that deliberately bypass the application layer and still fail to corrupt the books
Money is counted in whole cents
Amounts are stored as integers, never as binary decimal fractions. This sounds like a detail until you add twelve months of figures together and find the total is off by a few cents with no explanation. Integer arithmetic simply does not drift.
History is never rewritten
Entries are immutable once posted. Correcting one records a reversing entry that mirrors the original, so the trail shows what was recorded and what corrected it. That is what an accountant, a lender, or an auditor will ask to see — and it is impossible to reconstruct after the fact if you allowed edits.
One payment, several properties
An insurance premium covering three buildings is one payment and three expenses. Each line of an entry carries its own property, so a shared cost splits properly instead of being dumped on whichever property you happened to pick.
Bring transactions in the way that suits you
Type them in, or import a CSV export from your bank. Imports validate every row before writing anything — if a row references an unknown category or a malformed date, the import stops and tells you which line, rather than half-applying itself.
- Quoted fields, embedded commas, and CRLF line endings handled correctly
- Amounts with sub-cent precision are rejected rather than silently rounded
- A row whose sign disagrees with its category is caught before posting
- All-or-nothing: a failed import leaves your books untouched
Default chart of accounts
- Operating bank account1000
- Rent receivable1200
- Security deposits held2100
- Mortgage payable2200
- Owner contributions3000
- Rent income4000
- Late fee income4100
- Insurance5090
- Repairs5140
- Utilities5170
Seeded automatically when you create your workspace. Add your own accounts at any time; the seeded ones can be deactivated but never deleted, so historical entries always resolve.