RevRec brainstorm · Supporting · Thin engine spec (early)

08 — MVP product & engine spec

Status: draft spec (design lock candidate)
Scope: Thin engine that proves the simple product. Not full multi-PO/SSP/usage day one.

If this MVP covers a large merchant %, most Hotglue complexity was accidental.


1. Goals

ID Goal
G1 Correct ASC 606 for single-PO ratable SaaS from Chargebee
G2 Billing/AR sibling from invoices, payments, credit notes
G3 Period close: recognize + deferred waterfall + exportable journals
G4 Audit: every balance change tied to a source event id
G5 Operable extract (owned), not Hotglue-as-architecture

Non-goals for MVP: multi-PO SSP, usage variable consideration, proportional PS delivery, Hotglue CSV parity, Camunda, Catalyst/ERP.


2. Actors & systems

Actor Responsibility
Chargebee Source of monetization facts
Extract Pull → raw lake + cursors (Temporal)
Apply Map raw → domain events → mutate ops DB
Close Period recognize / lock / journal export
Serve API + reports; ClickHouse for heavy analytics
Finance user Close, recon, drill-down (UI later)

3. Domain entities (MVP)

Entity Key fields (illustrative)
Customer id, source_ref, currency
Contract id, customer_id, source_ref (subscription id), status, start, end?
PerformanceObligation id, contract_id, product_ref, method=ratable, service_start, service_end, allocated_amount
RecognitionScheduleLine po_id, period, amount, status (open/recognized)
BillingDocument id, type=invoice|credit_note, source_ref, customer_id, date, total
BillingLine document_id, amount, optional po_id link
CashApplication payment_ref, invoice_id, amount
JournalBatch period, lines (account, amount, dims), status
AppliedEvent tenant_id, source, source_event_id, type, applied_at — idempotency

Balances derived or maintained: deferred liability, AR, revenue YTD — product choice; must be reconcilable to events.


4. Apply API (normative)

4.1 open_contract

Input: customer, subscription id, items (one plan for MVP), term start/end, TP (sale amount), method=ratable.
Effect: Contract + one PO + allocation 100% + schedule lines (monthly or daily — pick one in ADR).
Idempotent on subscription create event.

4.2 amend_contract (MVP: upgrade/downgrade prospective only)

Input: effective date, new TP for remaining term (or new price × remaining).
Effect: Close/recompute remaining schedule lines; past recognized unchanged.
Out of MVP: cumulative catch-up.

4.3 record_billing

Input: invoice id, lines, amounts, dates, link to contract/subscription.
Effect: BillingDocument + lines; update AR; set/increase deferred as needed per accounting identity.
Does not create POs.

4.4 record_payment

Input: transaction ↔ invoice.
Effect: Cash application; AR ↓.

4.5 record_credit (MVP: one policy)

Default policy cn.refund_unrecog: reduce deferred / remaining schedule; do not reverse already recognized unless CN exceeds unrecognized (then define overflow — TBD ADR).
Effect: BillingDocument credit + schedule adjustment + audit.

4.6 recognize(period)

Input: tenant, period (e.g. 2026-01).
Effect: Sum open schedule lines for period → revenue; deferred ↓; mark lines recognized.
Idempotent for period if not locked.

4.7 post_journals(period)

Input: period.
Effect: Summarized Dr/Cr batch (Revenue, Deferred, AR, Cash) suitable for GL export. Detail stays in subledger.

4.8 Cancel / terminate (MVP)

Remaining open schedule → zero or recognize catch-up per policy term.cancel (choose ADR: recognize remaining vs write off — product).


5. Accounting identities (MVP)

Prepaid annual (example A in 07):

On invoice (paid):  Dr Cash   1200
                    Cr Deferred 1200

On recognize/mo:    Dr Deferred 100
                    Cr Revenue  100

Invoice unpaid then paid: AR instead of Cash on bill; payment clears AR.

Engine must keep: ∑ recognized + deferred_remaining ≈ allocated TP (after amendments/credits per policy).


6. Chargebee coverage (MVP entity set)

Must pull Why
customers Party
subscriptions (+ nested/related contract term) Contract / term
items / item_prices or plans Product + price
invoices Billing
credit_notes Credits
transactions Payments

Nice-to-have later: unbilled_charges, events (realtime), ramps/IBM if first-class in API.

Full mapping: 03-event-catalog.md.


7. Acceptance tests

Scenarios S01–S05 in 04-engine-scenarios.md must pass.
Shadow compare vs old path (optional): amounts by period/subscription within tolerance — not sheet shape.


8. Explicitly deferred (not “forgotten”)

Feature When to pull in
Multi-PO + SSP Cohort evidence + ADR
Usage / variable consideration Cohort + policy
Cumulative catch-up mods Finance ask
Proportional delivery PS merchants
Invoice-as-contract compatibility mode Only if product requires
AC Premium full feature parity After AR projector MVP

9. Architecture binding

This spec assumes the four-layer design in 02-architecture.md and deep dive in 09-architecture-deep.md.
Tech opinions (Temporal, Python, ops DB, ClickHouse) are replaceable; the apply API and entities are not without a new ADR.