ADR-040: SaaS usage metering and multi-tenant cost attribution¶
| Status | Accepted |
| Date | 2026-04-15 |
| Deciders | CTO, Head of Architecture, Head of Data, CFO |
| Affects repos | bank-platform, bank-risk-platform, bank-app |
Status: Accepted — 2026-04-15
Context¶
The bank licenses its platform to smaller financial institutions as modular SaaS (BG-011). Licensees pay a combination of per-customer and per-facility (per-module) charges, plus variable consumption. To operate this commercially and maintain trust with licensees, the bank must:
- Meter actual usage accurately — per licensee, per module, per resource type
- Attribute real infrastructure costs to tenants — AWS and Snowflake
- Produce a transparent, near-real-time cost and usage report that licensees can inspect at any time
- Derive internal unit economics — cost to serve each module per customer, gross margin by licensee
Cost sources are heterogeneous: - AWS infrastructure — Lambda invocations, API Gateway calls, Kinesis throughput, S3 storage/requests, EventBridge, SQS, DynamoDB, Secrets Manager - Snowflake compute — analytics queries, ML inference via Cortex, Dynamic Table refresh cycles, data sharing egress - External data — Snowflake Marketplace subscriptions (market data), enrichment API calls (merchant data, geo), NZFMA direct feed
Options considered:
- Module-level instrumentation only — each module emits usage metrics; no AWS-level cost attribution. Simple but cannot close the loop to actual cost.
- AWS resource tagging + Cost Explorer API — tag all resources with
tenant_id; pull AWS Cost Explorer daily. Provides accurate infrastructure cost attribution with no custom instrumentation at the module layer, but requires disciplined tagging governance. - Third-party FinOps platform (CloudHealth, Apptio Cloudability, etc.) — mature tooling but adds vendor dependency and cost; does not cover Snowflake natively.
- Hybrid: module usage events + AWS tagging + Snowflake metering — module-layer events capture logical usage (API calls, ML inferences); AWS Cost Explorer captures physical infrastructure cost; Snowflake
query_history/metering_historycaptures compute credits. Attribution joins at the Snowflake analytics layer.
Decision¶
Adopt Option 4 — hybrid metering.
Module usage events: All modules emit a structured bank-platform.usage_event EventBridge event on every billable operation. The event schema is standardised (see MOD-097). Events flow via Kinesis Firehose → S3 → Snowflake metering.usage_events. This creates a logical usage ledger independent of infrastructure provider.
AWS resource tagging: Every AWS resource created for a licensee tenant is tagged with tenant_id, module_id, and environment. The tagging contract is enforced via AWS Config rules and IaC (SST/CDK). AWS Cost Explorer is polled daily by MOD-098 and results written to metering.aws_cost_daily in Snowflake.
Snowflake compute attribution: Each licensee is assigned a dedicated Snowflake virtual warehouse for their analytics workloads. The warehouse name encodes the tenant_id. Where shared warehouse is used (small tenants), queries are tagged via ALTER SESSION SET QUERY_TAG = '{"tenant_id": "..."}'' and cost is attributed from snowflake.account_usage.query_history proportionally by credits_used. Results written to metering.snowflake_credit_daily.
Cost attribution model: A rate card (metering.cost_rates) maps resource types to $/unit. The attribution engine (MOD-098) multiplies usage events by the rate card to produce attributed cost. The rate card is updated when underlying AWS/Snowflake pricing changes. Infrastructure cost from Cost Explorer and Snowflake credits is attributed as a passthrough (actuals, not rate card) — licensees can see true cost if they opt into the transparency report.
Billing model:
| Layer | Basis | Unit |
|---|---|---|
| Customer levy | Per active customer on the platform | $/customer/month |
| Facility fee | Per activated module | $/module/month |
| Variable consumption | Per unit above included threshold | $/unit (Snowflake credits, API calls, ML inferences, notifications, storage-GB) |
| Infrastructure passthrough | Actual AWS cost tagged to tenant | $/month (optional transparency feature) |
Consequences¶
Positive: - Licensees can inspect their own usage and cost at any time — builds trust - Internal unit economics are available: gross margin per licensee, cost per module per customer - No single billing source — the hybrid approach survives provider changes - Tagging governance is enforced structurally (IaC + Config rules), not manually
Negative / trade-offs: - AWS Cost Explorer has 24–48 hour latency — infrastructure cost is always slightly retrospective - Snowflake shared-warehouse attribution is proportional (estimated) not exact; dedicated warehouses eliminate this for high-volume tenants - Tagging discipline must be maintained across all future module development — requires a pre-commit check in CI
Risk: If a module is deployed without correct tenant tagging, its AWS costs are unattributed and fall to the platform overhead bucket. Mitigation: IaC lint rule checks for required tags before deployment. Unattributed cost budget is monitored by MOD-098 and alerted if it exceeds a threshold.
Signoff¶
| Name | Role | Date |
|---|---|---|
| Ross Millen | Head of Architecture | 2026-04-15 |
| Ross Millen | Head of Data | 2026-04-15 |
| Ross Millen | CTO | 2026-04-15 |
Capabilities¶
| Capability | Satisfying module | Mode |
|---|---|---|
| CAP-140 SaaS usage metering & cost attribution | MOD-097 Usage event collector | AUTO |
| CAP-140 SaaS usage metering & cost attribution | MOD-098 Cost attribution engine | CALC |
| CAP-140 SaaS usage metering & cost attribution | MOD-099 Usage & billing report | AUTO |
All ADRs
Compiled 2026-05-22 from source/entities/adrs/ADR-040.yaml