Skip to content

ADR-019: Intelligent customer home screen and financial intelligence layer

Status Accepted
Date 2026-04-10
Deciders CTO, Head of Product, Head of Data
Affects repos bank-app, bank-risk-platform

Status

Accepted — 2026-04-10

Context

Legacy banks show customers a balance and a transaction list. This bank's architecture — real-time ledger, CDC pipeline, Snowflake intelligence models — makes something fundamentally different possible: a home screen that shows what the customer should do next, not just what they have done.

This ADR documents the decision to invest in a proactive intelligence layer that drives the customer home screen, and the architectural approach for doing it without adding latency to the customer-facing API.

Previous drafts of this ADR proposed writing Snowflake-computed insight signals back to Postgres for the home screen to read. That approach has been superseded by ADR-038, which establishes that display and insight data belongs in Tier 3 (Snowflake) and is never replicated into Postgres for rendering purposes. This ADR reflects that revised data path.

Decision

The home screen shows a net worth summary, an account mini-view, and a ranked stack of insight cards driven by Snowflake intelligence models. All intelligence is pre-computed in Snowflake dynamic tables and served via the Snowflake read API with an API-layer cache (Redis / ElastiCache). The home screen API call reads from the cache — it never calls Snowflake live on the request path and never reads insight signals from Postgres.

The one exception is the pre-approved credit decision. A credit pre-approval is an operational decision (not a display signal) — it is published to Neon via the ADR-036 decision inbox. The home screen reads the existence of a decision from Postgres (a single boolean + amount field on the customer record) but reads the detail (rate, term, rationale) from the Snowflake read API.


The five intelligence capabilities

Each capability is a Snowflake dynamic table refreshed on the cadence shown. The Snowflake read API serves the current signal per customer on demand; the API-layer cache absorbs the per-customer load.

1. Smart balance / idle cash detection

Snowflake table: intelligence.customer_signals — fields idle_cash_amount, idle_cash_days

How it works: Snowflake compares the customer's everyday account balance against their 90-day median spending pattern. If the balance has been materially above the typical spending buffer for 7+ days, the idle cash signal fires.

What the customer sees: "NZD 1,200 is earning nothing — Move to savings and earn NZD 4.80/month at 4.8% p.a." One-tap action executes the sweep.

Why it matters: Customers who move idle cash to savings earn more and stay more engaged. The bank builds a more stable deposit base. Both parties benefit.

2. Proactive pre-approved credit

Snowflake table: intelligence.credit_signals — fields pre_approved_amount, pre_approved_rate, pre_approved_term

How it works: MOD-029 runs the full affordability model nightly. Customers who meet the criteria have a decision published to Neon via ADR-036. The home screen reads the existence of a live offer from Postgres (fast boolean check); the offer detail is fetched from the Snowflake read API and cached.

What the customer sees: "You're pre-approved for a NZD 15,000 personal loan at 9.9% p.a. No impact on your credit score to check terms." One-tap to the full offer flow.

Why it matters: Pre-approved offers convert significantly better than cold applications because the credit decision has already been made. The customer receives and accepts rather than applying and waiting.

3. Spend anomaly detection

Snowflake table: intelligence.customer_signals — fields anomalous_merchants[], anomaly_description

How it works: Snowflake compares each merchant category's current month total against the customer's 6-month average. A spike of >30% in any category triggers the anomaly signal. The description is generated from the data — "Contact Energy charged NZD 284 vs your 6-month average of NZD 198."

What the customer sees: "Power bill up 43% this month — This is the 2nd increase in a row. Want to review your utility spend?" One-tap to a filtered transaction view.

Why it matters: Customers value being told something they didn't notice. This is the moment where the bank earns trust.

4. FX rate opportunity alert

Snowflake table: intelligence.fx_signals — fields nzd_aud_rate, rate_vs_3m_percentile, customer_typical_transfer_amount

How it works: Snowflake monitors the live NZD/AUD rate against a 3-month rolling percentile and the customer's own historical transfer rates. When the rate is above the 80th percentile of the last 3 months and the customer typically transfers at this level, the insight fires.

What the customer sees: "Good time to top up your AU account — NZD/AUD is at a 3-month high of 0.9311. Transfer now and get ~1.2% more AUD than last month." One-tap to the FX transfer screen with the current rate pre-loaded.

Why it matters: Customers with dual accounts miss opportunities by checking rates manually. This removes that friction entirely.

5. Payday automation suggestion

Snowflake table: intelligence.customer_signals — fields salary_detected, manual_sweep_count, suggested_rule_amount

How it works: Snowflake detects regular large credits matching a salary pattern. If the customer has manually transferred money to savings 2+ times after salary receipt, the automation suggestion fires with the inferred sweep amount.

What the customer sees: "Automate your payday savings — You've manually moved money to savings 3 times after your salary landed. Set a rule: sweep 20% of income to savings automatically." One-tap to the automation rules engine.

Why it matters: Customers who use automation rules have significantly higher retention and deposit growth.


Architecture: Snowflake presentation layer → read API → home screen

The home screen has two distinct data sources with different latency characteristics:

  • Operational data (balances, account list, recent transactions) — served from Neon via domain APIs. Sub-10ms. Always current.
  • Insight signals (idle cash, anomaly, FX opportunity, payday suggestion, credit offer) — served from Snowflake via the read API. 150–400ms on a warm warehouse.

These are separate API calls. The home screen renders operational data immediately and populates insight cards as the Snowflake response arrives — the insight signals are not on the critical render path.

Neon (operational data)
  → domain APIs → home screen (balance, accounts, transactions)

Snowflake presentation tables (PLATFORM.reporting.home_screen_signals)
  → refreshed on signal cadence (see table below)
  → Snowflake read API (Lambda → dedicated XS warehouse)
  → home screen insight cards

Insight signals never pass through Postgres. Postgres holds only the operational fact that a credit decision exists (set by the ADR-036 decision inbox on the customer record). All signal content — amounts, descriptions, recommendations — lives in Snowflake presentation tables and is queried directly.

No external cache layer. The Snowflake presentation table is pre-shaped to the API response payload — one row per customer. The read API runs a trivial indexed point lookup. The Dynamic Table refresh cadence controls freshness; there is no TTL management, no cache invalidation, and no Redis to operate. The dedicated XS warehouse (ADR-038) stays warm to ensure consistent query latency.

The home screen total load time target is ≤2 seconds TTI on 4G mobile (NFR-017). Operational data from Neon loads in <50ms; insight signals from Snowflake arrive within 150–400ms on a warm warehouse — both well within budget.

Presentation table refresh cadences

Each signal is a column in PLATFORM.reporting.home_screen_signals, refreshed by the relevant Snowflake Dynamic Table on the cadence below. Staleness is bounded by the refresh cadence — no TTL management required.

Signal Refresh cadence Notes
Idle cash detection Nightly Stale-tolerant; underlying balance changes slowly
Pre-approved credit Nightly (MOD-029) Decision existence flag in Postgres; offer detail in this table
Spend anomaly Daily + triggered on significant transaction event EventBridge event triggers an incremental Dynamic Table refresh
FX rate opportunity Every 15 minutes Presentation table updated on each FX feed refresh
Payday automation Triggered on salary credit event EventBridge salary event triggers incremental refresh

Net worth summary

The net worth view reads live account balances from Postgres (Tier 1 — these are operational values, not insights). Net worth = sum of all account balances in NZD equivalent. The FX conversion factor for AU balances is taken from the Snowflake FX signal cache (15-minute TTL).

This hybrid is intentional: balance accuracy requires Tier 1 Postgres; FX rate freshness is adequately served by the 15-minute cache.


Customer experience principles

Cards are actionable, not informational. Every insight card has a one-tap primary action that takes the customer directly to the relevant screen, pre-populated. The card is not an article — it is a gateway to an action.

Cards are dismissible. Every card has a "Not now" or "Dismiss" option. Dismissed cards do not reappear until the underlying signal changes materially. Dismissal is logged — it feeds the signal confidence model over time.

Cards are honest. The pre-approval shows exactly why it was made. The FX insight shows the data behind the suggestion. Customers should be able to verify every claim.

Cards are not marketing. The intelligence layer is funded by the customer's own data to serve the customer's own interests. Pre-approval only fires when the affordability model says the customer can comfortably afford the repayments. FX alerts only fire when the rate is genuinely better than the customer's historical rate.


Phase 2: AI natural language layer

Phase 2 (ADR-009, 3–6 months post-launch) adds a natural language interaction layer on top of the pre-computed intelligence:

  • Customer asks: "Why did my spending go up last month?" — AI generates an explanation from the categorised transaction data in Snowflake
  • Customer asks: "How much have I saved this year?" — AI queries Snowflake directly and produces a natural language answer
  • Back office internal: "Show me customers with credit score above 650 who haven't been offered a loan" — AI generates a Snowflake query and returns results

This is deferred to Phase 2 to keep the initial build focused on pre-computed intelligence rather than generative AI complexity.


Principles alignment

Principle Assessment Notes
AP-001 KISS Pre-computed signals in Snowflake; cache absorbs load; home screen reads cache — no Postgres insight tables
AP-005 Customer driven Every card is an action that benefits the customer
AP-007 Evolution New signals added as new Snowflake models are built; no API change required
AP-008 Real time ~ Intelligence is daily batch; FX rate is near-real-time — appropriate for each signal type

Perspectives

Perspective Assessment Notes
Performance & Scalability Pre-computed; cache absorbs morning burst; ≤200ms achievable on cache hit
Strategy Primary competitive differentiator — legacy banks cannot replicate without platform rebuild
Usability Actionable cards with one-tap flows; dismissible; honest about data behind the insight
Evolution Phase 2 AI layer extensible on same architecture; new Snowflake signals require no Postgres schema changes
Capability Delivers BG-003 (intelligent financial assistant) from day one

See perspectives.md for how to use these evaluation lenses.


Relevant viewpoints

  • Functional viewpoint — Home screen card set; insight signal map; one-tap action flows
  • System viewpoint — Snowflake dynamic tables → Snowflake read API → Redis cache → home screen API
  • Information viewpointintelligence.customer_signals schema; intelligence.fx_signals schema; cache key design
  • Operational viewpoint — Signal staleness monitoring; cache hit rate; card dismissal analytics; model performance tracking

See viewpoints.md for guidance on producing these viewpoints.



Signoff record

Date Name Role Status
2026-04-10 Ross Millen CTO Approved
2026-04-10 Ross Millen Head of Architecture Approved
2026-04-10 Ross Millen Head of Data Approved

Capabilities

Capability Description Relationship
CAP-006 Foreign exchange — live rates, rate lock enabled — FX rate opportunity alert card with one-tap to transfer
CAP-021 Low balance alert enabled — balance threshold signals surfaced as home screen cards
CAP-022 Unusual transaction alert enabled — spend anomaly detection signals displayed as actionable cards
CAP-063 Proactive financial insight engine enabled — five intelligence signals and delivery architecture defined here
CAP-064 Customer automation rules (sweep, round-up, rate alert, safety net) enabled — payday automation suggestion card links to rules engine
CAP-065 Pre-approval engine (nightly eligibility scoring) enabled — pre-approval card on home screen; credit offer detail from Snowflake
CAP-067 Idle cash detection enabled — idle cash signal computed in Snowflake, surfaced via home screen

ADR Title Relationship
ADR-002 Snowflake as the analytics and risk compute platform Snowflake Dynamic Tables are the source for all intelligence signals
ADR-009 Insights and data visualisation approach ADR-009 establishes the embedded chart and read API pattern this ADR uses
ADR-020 Customer financial automation rules engine payday automation insight card links to rules engine
ADR-036 Decision result publication — governed Snowflake → Neon write-back contract credit decision existence flag written to Postgres via decision inbox
ADR-038 Data access tier policy — Snowflake as the reporting and insight layer all insight signals are Tier 3 — served from Snowflake only

All ADRs Compiled 2026-05-22 from source/entities/adrs/ADR-019.yaml