Skip to content

ADR-067: SD06 regulatory dashboard rendering — Recharts and independent Streamlit per module

Status Proposed
Date 2026-05-21
Deciders CTO, Head of Risk Platform, Head of Platform Engineering
Affects repos bank-risk-platform, bank-app

Status: Proposed — 2026-05-21 (amended 2026-05-22)

Context

SD06 modules (MOD-171–MOD-175) produce dashboards for two distinct audiences with different requirements and acceptable quality bars:

  1. Bank staff and back-office operators — accessed via the TypeScript/Vite application (ADR-057). Needs to be product-quality and visually polished. Write-back capability (model parameter overrides, change control approvals) must be governed by maker-checker controls.

  2. Internal risk analysts and data engineers — work natively in Snowflake. Need a quick, functional view of the module's data for operational and exploratory use. Visual polish is not a requirement.

ADR-009 and ADR-057 left the charting library for SD06 undecided. ADR-038 mandated a Snowflake read API service but left it unbuilt. No prior decision addressed the Streamlit in Snowflake (SiS) approach or the use of the native Snowflake semantic layer for back-office dashboard queries.

Decision

1. Charting library: Recharts

Recharts is the charting library for SD06 dashboard components in the TypeScript/Vite application (MOD-177). It is composable at the primitive level, integrates cleanly with Tailwind CSS v3 (ADR-057), and provides the precise control over axes, reference lines, and threshold bands that regulatory charts require. This supersedes the non-binding "Recharts or Tremor" soft preference in ADR-009 for the SD06 context specifically.

2. Two independent renderers — divergence accepted

The React and SiS renderers are built and maintained independently. There is no shared spec, no shared format contract, and no coordination artefact between them. Divergence in layout, chart types, and interaction model between the two renderers is accepted and expected — they serve different audiences with different needs.

There is no @bank-platform/dashboard-spec package. There are no contract/dashboard/ directories.

3. Streamlit in Snowflake — one app per module, simple reporting

Each SD06 module that requires an internal view ships a Streamlit app directly in its source tree alongside its dbt models:

MOD-173-model-risk-register/
  streamlit/
    app.py          ← reads directly from published views in this module's schema
  dbt/
  migrations/
  ...

The app reads from the module's published Snowflake views (ADR-046 schema-as-product). Chart library is the developer's choice within Snowflake's Python channel (altair, plotly, st.bar_chart). These apps are internal tools: functional, not polished.

4. React components — AI-assisted authoring

React/Recharts components for each SD06 module dashboard are authored using a Claude Code session. The session reads the module's semantic view DDL, dbt column descriptions, and wiki module spec, and produces typed React/Recharts components. The developer reviews, edits, and commits the output. Generated components are source code — they live in bank-app (MOD-177), are version-controlled, and are treated as regular TypeScript.

This is a development workflow, not a CI step. No pipeline, no precompile stage, no automation beyond the Claude Code session itself. When SD06 semantic views change materially, the affected components are re-generated via a new session.

5. Data read path — Snowflake semantic layer via MOD-176

React dashboard components do not contain SQL. They reference named metrics, dimensions, and optional filters. At runtime, the component issues a structured query to MOD-176 (Snowflake read API service, SD07):

POST /v1/snowflake/metrics
{ "metric": "model_psi_score", "groupBy": ["model_id", "month"], "filter": { "tier": 1 } }

MOD-176 proxies this to the Snowflake Cortex Analyst REST API, which generates and executes SQL against the SD06 module's CREATE SEMANTIC VIEW objects and returns JSON. This is ADR-038 Tier 3b. MOD-176 enforces RBAC scoping (MOD-044) and query governance logging — MOD-177 holds no Snowflake credentials.

Each SD06 module defines its semantic views (CREATE SEMANTIC VIEW DDL) in its own migrations directory alongside dbt models. SD07 (MOD-176) owns the query proxy; SD06 modules own their metric and dimension definitions.

6. Write-back path — MOD-168 maker-checker

Dashboard write-backs in the React renderer follow ADR-059:

  • Proposals submitted to MOD-168 POST /checker/proposals via MOD-075 (internal API gateway)
  • proposed_by ≠ reviewed_by enforced at database layer — no self-approval
  • Actor identity from Cognito JWT claims (ADR-065)
  • Classification: TIER-3 for model parameter overrides and change control approvals (MOD-175); TIER-2 for threshold changes
  • Approved writes execute via Lambda → Neon Postgres (ADR-047) scoped to the module's schema (ADR-064)

The SiS renderer is read-only. No write-back from Streamlit in v1.

Consequences

Positive: - Each renderer is owned entirely by the team building it. No coordination overhead, no shared package to maintain, no schema drift between renderers. - SiS apps are simple Python scripts that a module developer writes alongside the dbt work — no dependency on bank-app or bank-platform. - React components reference metric names only. If a dbt view column renames, the semantic view definition updates; the React component is unaffected unless the metric itself changes. - Recharts' composable API handles the precision annotation work (threshold bands, reference lines, waterfall) that regulatory chart types require. - MOD-176 provides one auth surface, one circuit breaker, one query governance log for all Tier 3b traffic — consistent with MOD-075 as the equivalent for service-to-service calls.

Negative / trade-offs: - The two renderers will diverge over time. Accepted: the audiences and use cases are different. - React components must be manually re-generated via a new Claude Code session if the underlying semantic view metric definitions change materially. The developer owns the sync. - Cortex Analyst query latency (1–5 s on complex aggregations) is acceptable for back-office but rules out real-time use cases. Real-time data stays on the Tier 3a pre-shaped path. - SiS apps have limited design control and are not suitable for external-facing use. Accepted: they are internal tools only.

Cross-references

ADR-009 (insights visualisation — soft Recharts/Tremor candidates superseded for SD06 by §1) · ADR-038 (three-tier data access — Tier 3b semantic layer sub-pattern added by this ADR) · ADR-046 (SD06 schema-as-product — dbt views that semantic views reference) · ADR-049 (Snowflake Enterprise+ tier confirmed) · ADR-057 (frontend stack — Vite 5, TanStack, Tailwind, Radix) · ADR-059 (maker-checker — MOD-168) · ADR-064 (consolidated Neon — write-back target) · ADR-065 (Cognito custom claims — actor identity) · MOD-075 (internal API gateway) · MOD-168 (maker-checker engine) · MOD-176 (Snowflake read API service) · MOD-177 (SD06 risk dashboard renderer) · MOD-171 · MOD-172 · MOD-173 · MOD-174 · MOD-175


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