Skip to content

Diagram — ERD

Logical data model: app.* schema (system of record) and ledger.* schema (double-entry). The two schemas share UUID identifiers between app.account.id and ledger.account.idledger.account is a thin mirror keyed by the same UUID.



  • LEDGER_ACCOUNT is not a separate concept from ACCOUNT — same UUID, two schemas. The ledger schema can run independently of the app schema (this is the boundary that lets TigerBeetle replace ledger.* later — see ADR-0001).
  • LEDGER_ENTRY is append-only. Voiding never deletes entries; it inserts new ones (compensating). See ADR-0016.
  • LEDGER_ACCOUNT_BALANCE.balance_minor is a cache; the source of truth is SUM(direction='C') - SUM(direction='D') over LEDGER_ENTRY per account. Reconciled by trg_transfer_balanced at write time and by a nightly job (Plan 7).

  • SRS section: SRS — Telegram Finance Bot §🗄 Data Model
  • ADRs: ADR-0002 (PostgreSQL system of record), ADR-0008 (DB-level invariants), ADR-0014 (ledger schema design), ADR-0016 (void via compensating entries), ADR-0018 (domain ↔ ORM boundary)
  • Migrations: migrations/versions/0001_initial_app_user_and_processed_update.py, 0002_ledger_schema.py, 0003_app_account_category_budget.py, 0004_seed_default_categories.py