4.3 KiB
Financial Domain Implementation Plan
Spec: Approved domain design Goal: Deliver the financial models, constraints, service boundary and PostgreSQL verification. Architecture: finance/models for persistence; finance/services for audited atomic writes; tests/finance for synthetic acceptance and concurrency checks.
Interfaces
Models: Account(name,kind,currency,archived), Payee(name,archived), Category(name,kind,archived), CardStatement(account,period_start,period_end,due_date,statement_balance), InstallmentPlan(account,description,total_installments), Transaction(account,amount,posting_date,occurrence_date,description,kind,payee,category,statement,refund_of,installment_plan,installment_number), Transfer(outgoing,incoming), SourceRecord(transaction,document_hash,source_format,parser_version,item_locator), AuditEvent(actor_kind,actor_identifier,operation,target_id,outcome,changed_fields,error_code). All identifiers UUID; timestamps created_at/updated_at except immutable provenance/audit created_at.
Public services take actor=Actor(kind,identifier). Create operations take model scalar fields, related UUID arguments named account_id etc. create_transfer takes outgoing_account_id, incoming_account_id, positive amount, outgoing_date, incoming_date. match_transfer takes outgoing_id/incoming_id. annotate_transaction takes transaction_id and description/payee_id/category_id only. archive takes entity. attach_source takes transaction_id and source metadata. DomainError.code is stable and sanitized.
- Task 1: Implement models and PostgreSQL constraints; create migrations. Owned files finance/models and finance/migrations. Check constraint rejection using direct ORM writes, including sign, uniqueness, and protected deletion.
- Task 2: Implement services for ordinary posting, reference data, statements, plans and audit. Owned files finance/services. Validate Decimal precision before persistence, serialize references and record success atomically; failures recorded after rollback.
- Task 3: Implement transfer/refund/installment/provenance operations and synthetic acceptance tests, including concurrent matching in separate PostgreSQL connections. Tests written before service implementation and run red, then green.
- Task 4: Integrate finance in settings and Docker context, verify fresh/existing migrations and runtime privileges; review code and document developer contracts. Run full pytest, check, makemigrations --check, migrate --check and HTTP health.
Ruling: public write operations own their outermost database transaction. Reject invocation inside an existing atomic block so failure audit events can persist independently after rollback. Composite operations call private helpers in one public transaction, never public services recursively. Ruling: archived reference data cannot be newly assigned, but existing historical assignments can remain when only a description is updated. Ruling: retain the existing working directory and branch because all previous work is uncommitted here; workers own disjoint files, no overlapping implementation.
Completion evidence
- 83 PostgreSQL tests passed, including database constraints, relationship validation, audit rollback, source identity and two-session concurrent matching.
- Initial service run exposed audit field suffix mismatch (79 passed/1 failed); normalized audit field names and reran successfully.
- Review found Decimal-context rounding in transfer negation. Both new regressions failed before the fix; copy_negate() corrected creation and matching. Scoped re-review reported no remaining findings.
- Finance migration applied to the existing skeleton database and a fresh gizmoduck-domain-verify database. Runtime grants and synthetic account DML passed on both. The verification database container is stopped; its synthetic volume is retained. No real financial data was used.
- Django checks passed with no migration drift or pending migrations.
- Candidate Git files checked for local secrets; migration/source files remain trackable. Documentation links and whitespace verified.
- Financial APIs and transaction-boundary limits documented in docs/financial-domain.md. No financial HTTP UI or import parser added.
- Changes remain local and uncommitted alongside the prior foundation/skeleton.