Browse Source

docs: design reconciliation checkpoints

master
Codex 2 months ago
parent
commit
8d5b5adb17
  1. 99
      docs/superpowers/specs/2026-09-08-reconciliation-design.md

99
docs/superpowers/specs/2026-09-08-reconciliation-design.md

@ -0,0 +1,99 @@
# Reconciliation checkpoints design
## Purpose
Add a local reconciliation workflow that compares an institution-reported
balance with Gizmoduck's ledger for one account on one date. It gives the owner
auditable confidence in account balances without changing transactions,
creating clearing state, or depending on a particular import format.
## Scope
The first version supports every active bank or credit-card account and any
chosen as-of date. It records immutable balance checkpoints, shows their
current status, and preserves their original calculation for audit.
It does not clear individual transactions, lock a reconciled period, infer a
balance from source files, create card statements, or modify financial rows.
Those capabilities remain future enhancements.
## Domain model
Add `ReconciliationCheckpoint` to the finance domain:
| Field | Meaning |
| --- | --- |
| `account` | Active account being checked; protected from deletion. |
| `as_of_date` | Inclusive posting-date boundary for the comparison. |
| `institution_balance` | Balance shown by the bank or card institution, in the account currency. Zero is valid. |
| `ledger_balance_at_creation` | Sum of account transaction amounts through `as_of_date` when the checkpoint was recorded. |
| `difference_at_creation` | `institution_balance - ledger_balance_at_creation`. |
| timestamps | Immutable creation and update timestamps inherited from the existing base model. |
There is deliberately no uniqueness constraint on `(account, as_of_date)`.
Entering a corrected balance creates another checkpoint rather than rewriting
or deleting history. The latest checkpoint by creation time is the active
checkpoint for that account and date.
The reconciliation service owns creation. It validates the account is active,
accepts decimal-safe balances including zero, calculates the ledger snapshot in
one database transaction, saves the checkpoint, and writes the existing
`AuditEvent` with the human actor and outcome. No imported source text or
institution credentials are persisted.
## Current status and drift
When displaying a checkpoint, Gizmoduck recalculates the account's live ledger
balance through the inclusive `as_of_date`. It compares that value with the
stored institution balance.
* **Reconciled**: the live difference is zero.
* **Difference**: the live difference is nonzero and the original checkpoint
also did not reconcile.
* **Changed since reconciliation**: the original checkpoint reconciled, but
later backdated activity changed the live ledger balance.
The checkpoint continues to retain its original ledger balance and difference.
This makes late imports and dated manual entries visible without mutating the
historical record. Opening balances participate in the ledger sum exactly like
other transactions; reports still exclude them from income and spending.
## Owner workflow
Add a Reconciliation navigation entry and page.
The page lists active accounts with their most recent checkpoint date and live
status. The owner can select an account, choose an as-of date, and enter the
institution balance. Before submission, the form shows the current ledger
balance and difference for confirmation. Saving records the immutable
checkpoint and redirects to the account's reconciliation history.
History shows each checkpoint's as-of date, institution balance, original
ledger balance, original difference, current ledger balance, current
difference, created time, and status. Amounts never cross currency boundaries.
The existing dashboard retains account balances and gains only a compact latest
reconciliation status per account.
## Error handling and security
Invalid dates and money values receive field-level form errors. Archived or
missing accounts are rejected by the domain service and translated to the
existing safe owner-facing error messages. Forms use the existing CSRF
protection and fixed local `HUMAN/local-owner` actor. Database exceptions and
financial source data are never exposed in responses.
## Verification
Use only synthetic data. Tests cover:
* exact bank and credit-card reconciliation, including a zero institution
balance;
* an initial difference and a later corrected checkpoint for the same date;
* a backdated transaction changing a previously reconciled checkpoint;
* opening balances in reconciliation totals;
* archived account rejection and audit behavior;
* migration constraints, owner form validation, CSRF protection, account
history, and dashboard status rendering.
Run focused domain and web tests, the full pytest suite, Django migration and
system checks, and the existing PostgreSQL permission check.
Loading…
Cancel
Save