SYSTEM ARCHITECTURE
The Three Areas
Three billing areas form a dependency triangle bound by shared mutable state. Each is a distinct failure domain with different integration mechanisms. No area can be extracted independently — the center must be decoupled first.
- 79
- A1 touchpoints
- 126
- A2 touchpoints
- 196
- A3 event types
A directed cycle. Each area depends on the next through a different integration mechanism — Twirp RPC, PGQ triggers, and HTTP callbacks. All three reach inward to the same shared mutable state. The coupling is in the data, not the code paths.
| From | To | Mechanism | Data / Effect | Seam Type |
|---|---|---|---|---|
| A1 Account Mgmt | A2 Sub Commerce | Twirp RPC | PM type determines collection path — card vs. invoice vs. ACH routing | Inter-area |
| A2 Sub Commerce | A3 Auto Billing | PGQ trigger | Subscription changes trigger billing recalculation and invoice generation | Inter-area |
| A3 Auto Billing | A1 Account Mgmt | HTTP call | Dunning escalation flags trigger ban/unban — bad_debt status propagation | Inter-area |
Customers and support see billing state without understanding it. 23 Dashboard endpoints, 38 iAPI Gateway endpoints, 18 NinjaPanel endpoints. Billing history showed "Paid / Paid" for resolved bad debt. No observability.
Every subscription mutation flows through a unified 4-stage pipeline. The system committed state before payment — then attempted to roll everything back on failure. The rollback path was incomplete.
196 Stripe event types compress through a single surface before fanning out to 5 subsystems. 27 webhook handlers, five stores — but no handler reads all five.
Three areas, one dependency triangle. The coupling is in the data — five shared tables at the gravitational center. Every area reads and writes directly, with no API abstraction layer. See Shared State for the full access matrix.