Overdraft management engine¶
| ID | MOD-117 |
| System | SD05 |
| Repo | bank-credit |
| Build status | Deployed |
| Deployed | Yes |
| Last commit | 19b0610 |
Purpose¶
Manages the full lifecycle of a revolving credit limit attached to a transaction account (PRD-019 Linked Transaction Overdraft). Responsibilities include: maintaining the approved limit record, tracking the drawn balance, calculating daily interest on any negative balance, posting monthly interest and facility fee charges, enforcing payment declines at the limit boundary, monitoring for financial hardship indicators, and handling the unarranged overdraft edge case.
MOD-117 operates as a sub-ledger on top of the core balance engine (MOD-003). It does not hold balances directly — all monetary postings flow through MOD-001 (double-entry posting engine). MOD-117 is the authoritative source for facility terms, accrual records, and the facility event log.
Compliance rationale¶
Under the NZ Credit Contracts and Consumer Finance Act 2003 (CCCFA) and the AU National Consumer Credit Protection Act 2009 (NCCP), a linked overdraft is a continuing credit contract. This creates several ongoing obligations that MOD-117 is designed to operationalise:
Responsible lending at origination and limit increase. The bank must perform a creditworthiness and affordability assessment before granting or increasing any limit. MOD-117 enforces this as a hard gate: no facility record can be created and no limit can be increased without a completed assessment reference from MOD-027 and MOD-028.
Persistent overdraft use as a hardship signal. Both CCCFA and NCCP require lenders to act proactively when a borrower shows signs of financial difficulty. A customer who is consistently at or near their overdraft limit for an extended period is exhibiting that signal. MOD-117 monitors consecutive days in a drawn state and emits a hardship flag at the 60-day threshold, triggering the proactive hardship conversation required by CON-008 and CRE-007.
Unarranged overdraft notification. The NZ and AU Banking Codes require prompt notification when a customer enters an unarranged overdraft (a negative balance where no overdraft facility has been granted). MOD-117 detects this condition and triggers an immediate customer notification via MOD-063.
Disclosure before activation. CON-005 requires that the limit, interest rate, and fee are disclosed before the facility is activated. MOD-117 will not create a facility record until MOD-050 confirms that the initial credit disclosure has been delivered and acknowledged.
Commercial rationale¶
Linked overdrafts are a high-margin retail credit product with low origination cost relative to other credit products: no security assessment, no title search, and minimal ongoing servicing overhead. The facility charges daily interest on the drawn balance, and daily interest income on even modest utilisation rates is material at scale.
The retention effect is significant. Customers with an overdraft attached to their transaction account have measurably lower churn than those without, because the overdraft increases the friction of switching to a competing bank (the customer would lose the pre-approved credit line and face a new application elsewhere). The overdraft is therefore both a revenue product and a retention mechanism for the core transaction account relationship.
Data model¶
-- credit.overdraft_facilities
CREATE TABLE credit.overdraft_facilities (
facility_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
account_id UUID NOT NULL REFERENCES core.accounts(account_id),
approved_limit NUMERIC(18,2) NOT NULL,
current_limit NUMERIC(18,2) NOT NULL, -- may differ if partial reduction pending
interest_rate_pct NUMERIC(8,5) NOT NULL,
facility_fee NUMERIC(18,2) NOT NULL,
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','suspended','closed')),
review_date DATE NOT NULL,
activated_at TIMESTAMPTZ NOT NULL,
closed_at TIMESTAMPTZ,
last_assessment_id UUID,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- credit.overdraft_daily_accruals
CREATE TABLE credit.overdraft_daily_accruals (
accrual_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
facility_id UUID NOT NULL REFERENCES credit.overdraft_facilities(facility_id),
accrual_date DATE NOT NULL,
drawn_balance NUMERIC(18,2) NOT NULL,
daily_interest NUMERIC(18,6) NOT NULL,
posted BOOLEAN NOT NULL DEFAULT false,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (facility_id, accrual_date)
);
-- credit.overdraft_events
CREATE TABLE credit.overdraft_events (
event_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
facility_id UUID NOT NULL REFERENCES credit.overdraft_facilities(facility_id),
event_type TEXT NOT NULL CHECK (event_type IN ('limit_set','limit_increased','limit_reduced','limit_suspended','interest_charged','hardship_flag','utilisation_alert','review_due','closed')),
event_data JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
overdraft_facilities is the master record for each facility. current_limit may be lower than approved_limit during a partial reduction notice period. last_assessment_id links to the most recent affordability assessment record in the credit assessment service.
overdraft_daily_accruals stores one row per facility per day on which a negative balance was recorded. The posted flag distinguishes accruals that have been included in a monthly charge from those still pending. The unique constraint on (facility_id, accrual_date) prevents duplicate accrual runs.
overdraft_events is an append-only audit log of all significant lifecycle events on the facility. event_data carries structured JSON payload appropriate to each event type (e.g. old and new limit values for limit_reduced, consecutive days count for hardship_flag).
Key operations¶
1. Available balance¶
MOD-003 calls get_available_balance(account_id) when computing the balance available for a payment or display. MOD-117 returns ledger_balance + current_limit if an active facility exists for the account, or ledger_balance if no active facility exists. This combined figure is what MOD-021 (payment limit and velocity controller) uses to gate payment execution: a payment that would take the resulting balance below zero minus the limit is declined.
2. Daily interest accrual¶
A scheduled job runs at end of each calendar day. For each active facility where the associated account's ledger balance is negative:
A row is inserted into overdraft_daily_accruals with posted = false. If the balance is zero or positive, no accrual row is created for that day. MOD-005 (daily accrual calculator) provides the end-of-day balance snapshot; MOD-117 owns the accrual record.
The consecutive-days-drawn counter is updated on each daily run. If the counter reaches 60, the hardship detection flow (see below) is triggered.
3. Monthly interest charge¶
On the last calendar day of each month, MOD-117 runs the monthly close job for all active facilities:
- Select all
overdraft_daily_accrualsrows for the facility whereposted = false. - Sum
daily_interestacross all selected rows. - Post a single debit entry to the account via MOD-001 for the summed amount, with description identifying the period.
- Mark all selected accrual rows
posted = true. - Insert a
interest_chargedevent intooverdraft_events. - Emit
bank.credit.overdraft_interest_chargeddomain event.
4. Monthly facility fee¶
On the same monthly close run: check whether any overdraft_daily_accruals row exists for the facility in the calendar month (i.e. whether the balance was ever negative). If yes, post a facility fee debit via MOD-001 using the fee amount from overdraft_facilities.facility_fee. If no rows exist (balance was positive throughout the month), the fee is waived: a fee waiver event is logged in MOD-110 and an interest_charged event with zero fee amount is recorded for audit completeness.
5. Hardship detection¶
The daily accrual job tracks the number of consecutive calendar days on which a negative balance was recorded. When this count reaches 60:
- MOD-117 inserts a
hardship_flagevent intooverdraft_eventswith the consecutive-days count inevent_data. - MOD-007 sets the
hardship_review_pendingflag on the account. - MOD-063 dispatches an alert to the back-office operations queue and a customer-facing notification advising them to contact the bank if they are experiencing financial difficulty.
- The consecutive-days counter is not reset until the balance returns to positive and remains positive for at least 5 days, preventing repeated alerts on minor balance oscillations.
The hardship flag does not automatically restrict the account. It creates a task for a human review. The outcome of that review may result in a hardship arrangement under CON-008, at which point MOD-007 applies the appropriate account restrictions.
6. Unarranged overdraft¶
An unarranged overdraft occurs when an account with no active overdraft facility records a negative balance. This is an edge case that can arise from timing issues in payment settlement or fee debits.
On detection (MOD-007 observes a negative balance on an account with no active facility):
- MOD-007 sets the
unarranged_overdraftstate on the account. - MOD-063 dispatches an immediate customer notification.
- MOD-117 creates a flag record for manual operations review.
- If the bank's product rules permit an unarranged overdraft fee (configured in MOD-110), the fee is posted via MOD-001.
- The account is not blocked from incoming credits. The balance is expected to return to positive when the next credit arrives.
If the balance remains negative beyond a configurable threshold period (default 5 business days), the operations queue receives an escalation alert.
FRs satisfied¶
| FR | Description |
|---|---|
| FR-529 | System shall maintain an approved overdraft limit per transaction account and enforce that no payment or debit causes the balance to fall below the negative of that limit. |
| FR-530 | System shall calculate available balance as ledger balance plus undrawn overdraft limit for all accounts with an active overdraft facility, and expose this figure to balance display and payment validation. |
| FR-531 | System shall accrue overdraft interest daily on any negative ledger balance and post a single aggregated interest charge debit on the last calendar day of each month. |
| FR-532 | System shall monitor consecutive days with a negative balance per facility and emit a financial hardship flag when the threshold of 60 consecutive days is reached. |
Module dependencies¶
Depends on¶
| Module | Title | Required? | Contract | Reason |
|---|---|---|---|---|
| MOD-001 | Double-entry posting engine | Required | — | Monthly interest charges and facility fees are posted as ledger entries via the double-entry posting engine. v1 uses ADJUSTMENT posting_type pending ACCRUAL type addition to MOD-001 request enum. |
| MOD-065 | Credit servicing & collections | Required | — | credit.loan_accounts must exist (MOD-065 owns the table) before MOD-117 can create paired OVERDRAFT product_type rows on facility creation. |
| MOD-027 | Affordability calculator | Required | — | Affordability assessment (credit.affordability_assessments) is a hard gate before any facility is created or limit increased — CRE-002 GATE. |
| MOD-003 | Real-time balance engine | Optional | — | v1 stub — current_drawn_balance column on overdraft_facilities mirrors the drawn balance; update-drawn-balance Function URL replaces the real-time feed until MOD-003 ships and a bank.core.balance_updated SQS consumer takes over. |
| MOD-005 | Daily accrual calculator | Optional | — | v1 owns its own daily accrual job following MOD-005 conventions; MOD-005 integration is a v2 enhancement once the shared accrual engine is built. |
| MOD-007 | Account state machine | Optional | — | v1 stub — hardship flag emits event + writes to overdraft_events audit log; MOD-007 account state machine integration wires in v2 when MOD-007 ships. |
| MOD-050 | Disclosure enforcement module | Optional | — | v1 stub — disclosure gate is enforced via caller-asserted disclosure_acknowledged field; MOD-050 delivery confirmation replaces the stub in v2. |
| MOD-063 | Notification orchestration | Optional | — | v1 stub — hardship and unarranged-overdraft alerts use audit-only mode + SNS; live notifications delivered when MOD-063 ships. |
| MOD-110 | Fee engine | Optional | — | v1 stub — fee waiver outcome emits bank.credit.overdraft_fee_assessed with waived=true; MOD-110 fee waiver record API wires in v2. |
Required by¶
(No modules in this wiki currently declare a dependency on this module.)
Policies satisfied¶
| Policy | Title | Mode | How |
|---|---|---|---|
| CRE-002 | Responsible Lending Policy | GATE |
Overdraft limit cannot be set or increased without a completed affordability assessment satisfying responsible lending obligations. |
| CON-005 | Fee & Pricing Transparency Policy | GATE |
The current overdraft limit, interest rate, and monthly facility fee are disclosed to the customer before any limit is activated. |
| CON-008 | Financial Hardship Policy | ALERT |
Customers who are drawn on their overdraft for more than 60 consecutive days are flagged for financial hardship review. |
| PAY-001 | Payment Operations Policy | GATE |
Outgoing payments that would exceed the combined available balance (credit + overdraft limit) are declined before execution. |
| CRE-001 | Credit Risk Management Policy | CALC |
Drawn overdraft balances contribute to credit exposure reporting and concentration risk calculations. |
Capabilities satisfied¶
(No capabilities mapped)
Part of SD05 — Credit Decisioning & Loan Platform
Compiled 2026-05-22 from source/entities/modules/MOD-117.yaml