Account state machine¶
| ID | MOD-007 |
| System | SD01 |
| Repo | bank-core |
| Build status | Deployed |
| Deployed | Yes |
| Last commit | 35402a8a7d9c6f1e2b5c8d0e4f7a3b6c9d2e5f8a |
Accounts move through defined states: Pending → Active → Restricted → Dormant → Closed. State transitions enforce regulatory rules — a Restricted account cannot originate payments.
State transition model¶
Transitions are evaluated by the pure transition-engine-pure.ts service, which enforces the following rules:
- PENDING → ACTIVE: Standard path requires a matching row in
accounts.kyc_status_mirrorwithstatus = 'VERIFIED'. Multi-party account types (trust, community, joint) bypass the single-party KYC mirror gate when the activation is initiated with an approvedreason_codefrom the multi-party module (see below). - ACTIVE → RESTRICTED: Requires a
restriction_reasonfrom the allowed domain. - RESTRICTED → ACTIVE: Reinstatement — triggered by MOD-007 FR-440 reinstatement flow.
- ACTIVE / RESTRICTED → DORMANT: Triggered when
last_transaction_atcrosses the dormancy threshold. - ANY → CLOSED: Terminal state.
ReasonCode domain¶
The ReasonCode union type in src/types/account-state.ts controls which callers are permitted to drive specific transitions. The following values are defined:
| ReasonCode | Used by | Purpose |
|---|---|---|
TRUST_GATE_PASS |
MOD-133 | Bypass single-party KYC mirror gate on PENDING→ACTIVE for trust accounts; MOD-133 evaluateActivationGate already verified all trustee and BO identities |
COMMUNITY_GATE_PASS |
MOD-134 | Bypass single-party KYC mirror gate on PENDING→ACTIVE for community accounts; MOD-134 evaluateActivationGate verified all signatory identities |
JOINT_GATE_PASS |
MOD-125 | Bypass single-party KYC mirror gate on PENDING→ACTIVE for joint accounts; MOD-125 evaluateActivationGate verified all holder identities |
SIGNATORY_KYC_DEGRADED |
MOD-134 | ACTIVE→RESTRICTED transition when a community account's verified signatory count drops below the signing-rule minimum |
The PENDING→ACTIVE pure validator bypasses the single-party KYC mirror gate when reason_code is TRUST_GATE_PASS, COMMUNITY_GATE_PASS, or JOINT_GATE_PASS. Cross-reference: MOD-133 §Activation gate, MOD-134 §Activation gate, MOD-125 §Activation gate.
RestrictionReason domain¶
The restriction_reason column CHECK on accounts.accounts (and in lockstep on accounts.account_state_history) accepts the following values:
| Value | Set by | Trigger |
|---|---|---|
SANCTIONS |
MOD-013 / compliance staff | Sanctions match confirmed |
FRAUD_INVESTIGATION |
Fraud operations | Manual or automated fraud flag |
HARDSHIP_ARRANGEMENT |
Customer operations | Hardship arrangement in place |
ADMIN |
Platform operations | Administrative hold |
INSUFFICIENT_SIGNATORIES |
MOD-134 | Active verified signatory count drops below the community signing-rule minimum (FR-600). ACTIVE→RESTRICTED. Cleared when KYC is restored and check-signatory-kyc passes. |
Note: Adding a new restriction_reason value requires extending the CHECK constraint on both accounts.accounts and accounts.account_state_history in the same migration (the transition engine writes both rows in the same Postgres transaction — see SD01 data model §DB-enforced invariants).
Hardship-flag service (V007)¶
V007 adds a party-level hardship flag store and four IAM-authenticated Function URL endpoints. The hardship flag is a mutable set/clear record on accounts.party_hardship_flags (one active row per party; see SD01 data model). It is intentionally mutable — the flag is cleared when the hardship arrangement ends, and a party may be re-flagged if a subsequent hardship arrangement is opened.
Endpoints¶
All four endpoints use AuthType=AWS_IAM. Access is controlled by the broader bank-platform IAM layer; no per-Principal resource policies are applied.
| Endpoint | Method | Description | Response codes |
|---|---|---|---|
hardship-flag-set-url |
POST | Sets the hardship flag for a party. Body: { party_id, flagged_by_module, reason }. Idempotent — 200 on first set; 409 HARDSHIP_FLAG_ALREADY_SET if already flagged. Re-flags a previously cleared party (inserts new row). |
200, 409 |
hardship-flag-clear-url |
DELETE | Clears the active hardship flag. Body: { party_id, cleared_by_module }. |
200, 404 |
hardship-flag-read-url |
GET | Returns { flagged: bool, flagged_at?, flagged_by_module?, reason? }. |
200 |
primary-deposit-account-url |
GET | Returns { account_id } for the party's most-recently-opened ACTIVE deposit account (NZ_TRANSACTION_01 / AU_TRANSACTION_01 / NZ_SAVINGS_01 / AU_SAVINGS_01). |
200, 404 |
SSM output paths¶
/bank/{env}/mod-007/hardship-flag-set-url
/bank/{env}/mod-007/hardship-flag-clear-url
/bank/{env}/mod-007/hardship-flag-read-url
/bank/{env}/mod-007/primary-deposit-account-url
/bank/{env}/mod-007/party-hardship-flags-table → "accounts.party_hardship_flags"
Callers¶
- MOD-116 (bank-credit) — Day-7 arrears path POSTs to
hardship-flag-set-url; discharge handler GETsprimary-deposit-account-url. - MOD-117 (bank-credit) — On
consecutive_drawn_days ≥ 60, POSTs tohardship-flag-set-urlwithflagged_by_module='MOD-117'. - MOD-065 (bank-credit) — On HARDSHIP_RESOLUTION case closure, DELETEs via
hardship-flag-clear-url.
Design note: soft FK to SD02¶
accounts.party_hardship_flags.party_id references party.parties in SD02's bank_kyc DB. Cross-DB FKs are not supported in this Neon deployment (same pattern as V005 account_party_relationships). The column accepts the SD02 UUID identifiers; referential integrity is enforced at the service layer.
Module dependencies¶
Depends on¶
| Module | Title | Required? | Contract | Reason |
|---|---|---|---|---|
| MOD-001 | Double-entry posting engine | Required | — | Account state transitions require posting capability — activation and restriction events generate ledger entries. |
| MOD-002 | Immutable transaction log | Required | — | State transitions are persisted in the transaction log for auditability and reversal tracing. |
| MOD-009 | eIDV & document verification | Required | contract/api/ |
KYC verification status from eIDV is a prerequisite gate for the Pending→Active state transition. |
| MOD-104 | AWS shared infrastructure bootstrap | Required | — | AWS shared infrastructure provisioned by MOD-104 (EventBridge buses, S3, KMS, Kinesis, Cognito) is required before this module can be deployed. |
| MOD-103 | Neon database platform bootstrap | Required | — | Neon database and schema provisioned by MOD-103 must exist before this module can read or write Postgres. |
Required by¶
| Module | Title | As | Contract |
|---|---|---|---|
| MOD-008 | Dormancy & escheatment engine | Hard dependency | — |
| MOD-065 | Credit servicing & collections | Hard dependency | — |
| MOD-111 | Term deposit maturity engine | Hard dependency | — |
| MOD-117 | Overdraft management engine | Optional enhancement | — |
| MOD-118 | Member equity and share registry | Hard dependency | — |
| MOD-125 | Joint account management | Hard dependency | — |
| MOD-130 | Notice account management | Hard dependency | — |
| MOD-138 | Deceased customer and estate management | Hard dependency | — |
| MOD-139 | Financial hardship formal variation workflow | Hard dependency | — |
| MOD-159 | Synthetic transaction engine | Hard dependency | — |
Policies satisfied¶
| Policy | Title | Mode | How |
|---|---|---|---|
| AML-002 | Customer Due Diligence (CDD) Policy | GATE |
Account cannot be activated until KYC status is Verified — GATE enforced at state machine level |
| AML-007 | Sanctions Screening Policy | GATE |
Account is automatically restricted if sanctions match is confirmed — no agent override without approval |
| PAY-005 | Payment Fraud Prevention Policy | GATE |
Fraud-flagged account automatically restricted pending investigation |
Capabilities satisfied¶
(No capabilities mapped)
Part of SD01 — Core Banking Platform
Compiled 2026-05-22 from source/entities/modules/MOD-007.yaml