Skip to content

Product eligibility engine

ID MOD-105
System SD06
Repo bank-risk-platform
Build status Not started
Deployed No

What it does

MOD-105 is the centralised product eligibility gate. Given a party_id and product_id, it returns ELIGIBLE or INELIGIBLE with a structured reason code. It is called at two points: at offer generation time (MOD-108) to determine which products can be offered, and at application time to prevent ineligible customers applying via any channel (app, agent, API).

Why it exists

Compliance. CON-006 (Product suitability and governance) requires that products are only offered to eligible customers. No product offer may be generated without a passing eligibility check. CON-001 (Fair conduct) requires eligibility logic to be documented, auditable, and not discriminatory.

Commercial. Unsuitable product origination is a primary source of early credit losses. A centralised gate ensures that underwriting rules, CDD requirements, and exposure limits are enforced consistently at the point of offer rather than discovered later in the origination flow. MOD-105 also feeds MOD-107 (NBP engine) with the eligible product set for each customer, enabling personalised recommendations scoped to what the customer can actually receive.

Eligibility dimensions

KYC / CDD tier. Each product has a minimum CDD tier requirement (Simplified, Standard, or Enhanced). The customer's current tier is read from banking.customer_relationships.cdd_tier as written by MOD-010. A product with min_cdd_tier = ENHANCED is not offered to a customer at Standard CDD tier. Reason code: CDD_TIER_INSUFFICIENT.

Credit risk rating. Credit and lending products carry a minimum internal credit rating floor on the 1–10 scale produced by MOD-028. A customer whose current rating falls below the floor for a given product is ineligible. Reason code: CREDIT_RATING_BELOW_FLOOR.

Jurisdiction. Each product declares an eligible jurisdiction set (NZ, AU, or NZ+AU). The customer's custom:jurisdiction attribute must be a member of that set. Reason code: JURISDICTION_NOT_ELIGIBLE.

Existing product holdings. Cross-sell eligibility rules encode three constraint types: prerequisite products (some products require another product to already be held — for example, an overdraft facility requires an active everyday account); maximum holdings per customer (some products may only be held once); and mutual exclusion pairs (some products cannot be held simultaneously). Rules are stored in the product_eligibility.eligibility_rules configuration table and evaluated against current holdings at call time. Reason code: PRODUCT_HOLDINGS_CONSTRAINT.

Maximum total credit exposure. For credit products, the proposed new credit limit is added to the sum of all existing credit limits across the customer's portfolio. If this total exceeds the customer's maximum allowable exposure — derived from the affordability assessment in MOD-027 — the product is ineligible. Reason code: TOTAL_EXPOSURE_EXCEEDED.

Customer tenure. Some products have a minimum account tenure requirement before they can be offered (for example, 90 days of active banking relationship). This is evaluated against banking.customer_relationships.onboarded_at. Reason code: TENURE_INSUFFICIENT.

ROTE minimum. For credit and savings products, MOD-106 computes whether the product's projected ROTE exceeds the configured hurdle rate for that product class. Products persistently below hurdle are excluded from the eligible offer set until repriced. This gate is optional per product — products not yet covered by MOD-106 skip this check. Reason code: BELOW_ROTE_HURDLE.

Data model

-- product_eligibility.eligibility_results (Snowflake — batch evaluation, written nightly)
CREATE TABLE product_eligibility.eligibility_results (
  party_id          VARCHAR NOT NULL,
  product_id        VARCHAR NOT NULL,
  jurisdiction      VARCHAR NOT NULL,
  eligible          BOOLEAN NOT NULL,
  reason_code       VARCHAR,           -- NULL if eligible; e.g. CREDIT_RATING_BELOW_FLOOR
  reason_detail     VARCHAR,
  evaluated_at      TIMESTAMP_NTZ NOT NULL,
  model_version     VARCHAR NOT NULL,
  PRIMARY KEY (party_id, product_id, evaluated_at)
);

-- product_eligibility.eligibility_rules (Postgres — bank_risk, read by real-time API)
CREATE TABLE product_eligibility.eligibility_rules (
  product_id          text PRIMARY KEY,
  min_cdd_tier        text,
  min_credit_rating   int,
  jurisdictions       text[],
  min_tenure_days     int,
  max_per_customer    int,
  required_products   text[],
  excluded_products   text[],
  rote_hurdle_rate    numeric(5,4),
  effective_from      date NOT NULL,
  effective_to        date
);

Real-time vs batch evaluation

Nightly batch runs in Snowflake produce the full eligibility matrix across all active customers and products and write results to product_eligibility.eligibility_results. This output is the source for offer generation in MOD-108.

Real-time eligibility checks at application time use a lightweight Postgres read from the cached rules table combined with live state lookups for KYC tier and credit rating. This path must return within p99 ≤ 100 ms to remain non-blocking in the origination flow. The real-time check is considered authoritative at application time — stale batch results are not used for application gating.

Events

MOD-105 publishes product.eligibility_evaluated to the bank-risk-platform EventBridge bus after each nightly batch run completes. The event carries: party_id, eligible_product_count, ineligible_product_count, and evaluated_at. This event is consumed by MOD-107 to trigger refresh of the NBP candidate set for each customer.


Module dependencies

Depends on

Module Title Required? Contract Reason
MOD-010 CDD tier assignment engine Required CDD tier from MOD-010 is an eligibility input — products requiring Standard or Enhanced CDD are gated at this module.
MOD-028 Credit score & risk rating Required Internal credit risk rating from MOD-028 is an eligibility input for all credit and lending products.
MOD-033 RWA & capital ratio engine Optional RWA-based capital allocation from MOD-033 feeds the ROTE minimum threshold check for credit product eligibility.
MOD-104 AWS shared infrastructure bootstrap Required MOD-104 provisions the S3 Iceberg bucket (Snowflake external tables), KMS key, and bank-risk-platform EventBridge bus ARN. Required before this module can be deployed.
MOD-102 Snowflake account configuration & governance Required Snowflake account, BANK_{ENV}_RISK database, BANK_DBT_ROLE, and warehouse must exist before this module can create its schema or run dbt models.
MOD-079 Snowflake decision publication service Required Eligibility decisions are written back to Neon via the decision publication service so that operational systems can gate product presentation in real time (ADR-036). MOD-079 must be deployed before write-back can occur.

Required by

Module Title As Contract
MOD-107 Next best product engine Hard dependency
MOD-108 Product offer engine Hard dependency
MOD-109 Product deal engine Hard dependency
MOD-118 Member equity and share registry Optional enhancement

Policies satisfied

Policy Title Mode How
CON-006 Product suitability and governance GATE Every product offer or application is gated against the eligibility matrix — a customer not eligible for a product cannot be presented with it or apply for it.
CON-001 Customer Fairness & Conduct Policy GATE Eligibility evaluation considers existing exposure, customer segment, and product complexity tier — ensuring products are not offered to customers for whom they are unsuitable.
CRE-001 Credit Risk Management Policy GATE Credit product eligibility enforces maximum DTI, credit tier floor, and CDD tier requirements before the product can be offered or applied for.

Capabilities satisfied

(No capabilities mapped)


Part of SD06 — Snowflake Analytics & Risk Platform Compiled 2026-05-22 from source/entities/modules/MOD-105.yaml