RevRec brainstorm · Research · Architecture notes (early)

02 — Target architecture & compare/migrate

Status: draft
Date: 2026-07-29
Canonical home: this file in revrec-next
Thesis: RevRec can be a simpler, nicer product. Most current complexity is accidental. Design the optimal system first; compare; move pieces only as needed.
Visual: ../visuals/revrec-simple-target.html
Product: 00-product.md · Domain: 01-domain-asc606.md · ADRs: decisions/


1. Product in one sentence

ASC 606 revenue subledger that turns Chargebee (and later other) monetization facts into recognition schedules, deferred/unbilled, close, and clean GL journals — with AR as a sibling view.

Not: a pandas contract-reconstruction factory feeding Camunda file jobs.


2. Optimal architecture (simple)

┌──────────────┐     ┌─────────────────┐     ┌──────────────────────┐
│ Source       │     │ Platform        │     │ Domain               │
│ adapters     │────►│ Temporal runs   │────►│ ASC 606 engine       │
│ (CB first)   │     │ raw lake (S3)   │     │ + AR projector       │
│ bulk|poll|   │     │ cursors (PG)    │     │                      │
│ realtime     │     │                 │     │ ops DB (contracts,   │
└──────────────┘     └────────┬────────┘     │ POs, schedules, AR)  │
                              │              └──────────┬───────────┘
                              │                         │
                              │              ┌──────────▼───────────┐
                              └─────────────►│ Serve                  │
                                             │ API · close · journals │
                                             │ ClickHouse analytics   │
                                             └────────────────────────┘

Four layers only

Layer Job Tech opinion (not locked)
Extract Own Chargebee pull; pluggable later Temporal POC shape (~/work/temporal_poc)
Apply Event → ASC 606 / AR state Python domain services + transactional ops DB
Close Period recognize + recon + GL post Same domain; scheduled workflows
Serve UI/API + waterfalls/metrics API on ops DB; CH for heavy analytics

Domain API (the whole product brain)

open_contract / amend_contract
record_billing / record_payment / record_credit
record_delivery          # only if proportional / PIT needs it
recognize(period)
post_journals(period)

Default path for most SaaS: one PO, ratable over term, invoices update AR/deferred — no joins required.

Complexity (SSP multi-PO, usage, ramps, fancy CN policy) is feature flags on that API, not a second universe of ETL.


3. Compare: accidental now vs optimal

Concern Today (accidental) Target (simple)
Contract Inferred via invoice↔term asof Explicit from sub/terms/catalog (+ CPQ later)
Recognition Buried in sheet builders + Redis SO processing recognize(period) on PO schedules
Billing Same pipeline invents orders Separate record_billing
Orchestration Hotglue + Camunda + governor + locks Temporal per-tenant extract + domain workflows
State Redis + SingleStore + S3 + CSV snapshots Ops DB + raw lake + analytics sink
Scale lever Org-wide job mutex, file splits Event apply + period jobs; parallel by contract
Extensibility New tap = new pandas dialect New SourceAdapter → same events
AC Premium Parallel file dialect + SQL job AR projector on same facts (or shared ledger core)

Most of Hotglue contracts.py / Camunda / dual drivers may never need a 1:1 port — only the accounting outcomes that customers still need.


4. Compare & move — how to migrate without boiling everything

Principle

Target is the north star. Current system is a quarry: steal tests, merchant configs, and edge policies — don’t clone architecture.

Phases

Phase Move Leave behind
A. Extract Temporal + Chargebee adapter → raw lake Hotglue schedule/webhooks (optional: keep Python worker only if needed short-term)
B. Thin engine Single-PO ratable + billing + one amend + one CN policy on ops DB OrderDetails manufacturing
C. Serve/close Period recognize, deferred waterfall, journal export Camunda sync job for that cohort
D. Expand domain Multi-PO/SSP, usage, ramps — only with real demand evidence Remaining reconstruction flags
E. AR / AC AR projector (or shared ledger) AC_* file reshape as permanent design
F. Retire Cut Hotglue/Camunda paths per tenant cohort

Comparison gate (per piece)

Before moving a piece, ask:

  1. Does ASC 606 / close / audit require it?
  2. Does a measurable merchant cohort need it?
  3. Can the target API express it as an event + policy?

If (1) and (2) are no → don’t move it. Document as deprecated behavior.

If yes → implement on target; shadow-compare numbers for a cohort; flip traffic; delete old path.

Shadow compare (the honest bridge)

Same Chargebee tenant
  → old path → old schedules / deferred
  → new path → new schedules / deferred
Diff report (amounts by period, by subscription)

Parity is accounting equality, not Excel sheet equality.


5. What we might never need

Candidates to leave in the quarry (validate with product/finance):


6. Immediate design checklist

  1. Freeze target diagram (this doc) as the architecture we’re building toward.
  2. Spec event catalog Chargebee → open/amend/bill/pay/credit/cancel/usage.
  3. Spec thin engine state machine + 5–8 golden ASC scenarios.
  4. Stand up extract from Temporal POC + CB adapter (no domain yet).
  5. Only then decide what current code is worth reading for policy edge cases.

7. Bottom line

Yes: simpler product, nicer architecture.
Optimal = extract platform + ASC 606 apply API + ops DB + analytics.
Compare against today; move pieces when the target can replace them; leave the rest to die.

Docs in this repo: - Product: 00-product.md - Domain: 01-domain-asc606.md - Events / scenarios (build next): 03, 04 - Extract: 05-extract.md · ~/work/temporal_poc/ - Extend: 06-how-to-extend.md