Pricing & Billing — standalone architecture
Build just this flow: take an accepted risk, rate it, and freeze the premium into a write-once ledger at bind. Advance the maturity stage to add the rate warehouse (a BigQuery store of rate & loss models), then the write-once ledger + billing, then scale.
Stage 1 · MVP. A Cloud Run Pricing API + a Cloud SQL rating worksheet. Reference rates can start as a simple table. You can produce a premium.
Stage 2 · Rate data. Build rate/loss models in BigQuery and project the results to a fast store (BigQuery never on the hot path). Consume DecisionMade; emit MarkedAsSold.
Stage 3 · Freeze & bill. Freeze the premium into a write-once ledger (a legal record) and integrate enterprise billing behind a transactional outbox.
Stage 4 · Scale. Read replicas for rating reads; columnar acceleration if operational pricing analytics grows. The frozen-premium discipline never changes.
📖 Flow story — what really happens
Every cross-flow arrow is the same async handoff — no flow calls another directly. 1. The sending flow commits its data row plus an outbox row in one transaction. 2. A relay publishes the event to the event bus (Pub/Sub on GCP · EventBridge→SQS on AWS). 3. The bus's push-subscription POSTs it to the receiving flow's Cloud Run API, which processes it idempotently (duplicates ignored, deduped on event_id). Synchronous reads (e.g. getProductVersion) are plain request/response.
- Underwriting's accept does NOT call Pricing. It commits two rows in one transaction: a
uw_decisionrow (append-only) and anoutboxrow carryingDecisionMade(accept). - The outbox relay publishes
DecisionMadeto the event bus; Pricing's subscription delivers it by POSTing to the Pricing API (Cloud Run) — async, deduped onevent_idso a redelivery can't double-rate. - Pricing rates the risk: base premium off Coverage A, adjusted by cat-model surcharges, mitigation credits (discounts for risk-reduction work like a fire-rated roof or cleared vegetation), taxes & fees (rate tables warehoused in BigQuery); it writes a
quoterow with the exact factors used. - On bind the premium is frozen — written once to an append-only premium
ledger(write-once); later endorsements/refunds append deltas (change records), never edit the original. - That bind commits its own
outboxrow, soMarkedAsSold{policy_id, premium snapshot} publishes exactly once, atomically (as one all-or-nothing operation) with the commit;BillingInvoiceRequestedgoes to billing. - Servicing's install gate is the next subscriber on
MarkedAsSold— the sold case moves on without Pricing ever waiting.
Interfaces (black-box contract)
| Direction | Contract | Who |
|---|---|---|
| Consumes | DecisionMade(accept); product + rate versions (read) | Underwriting, Product |
| Emits | MarkedAsSold {premium snapshot}, BillingInvoiceRequested | Case, Billing (external) |