1 changed files with 99 additions and 0 deletions
@ -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…
Reference in new issue