# Billing Current State Gap Matrix v1

## Purpose

This is the implementation inventory for `doc/architecture/Billing_Platform_Overhaul_v1.md`.
It records what exists today, what is read-model only, what is design-only, and what
must be built before the broader billing overhaul starts.

## Current Status

Billing v1 foundation is shipped. The implemented substrate covers allocation
rating, rated-line evidence, explicit ledger posting boundaries, ledger
immutability, per-currency balances, internal draft invoices, notification-only
budgets, refund/dispute foundations, provider-customer identity, and the first
V3 account billing page-contract surface.

This does not mean the billing product is complete. The next required gate is a
workflow proof that exercises the foundation as one customer/operator scenario:
fake reseller account, multi-currency balance, shadow rating, draft invoice
generation, audited refund request, and release evidence from the billing CI
gates. Deferred product areas remain tracked below and must not be collapsed
into "done" status until their owning workflows exist.

## Classification

| Domain | Status | Current implementation | Gap to target |
|---|---|---|---|
| Metering | Implemented for allocation windows; partial for app/runtime usage | `cmd/billing-worker/worker.go` opens allocation `usage_records` on `provisioning.active`, accrues active allocation usage periodically, and closes usage on release/release-failed. `usage_records` already has `usage_source`, `usage_unit`, `app_instance_id`, app runtime fields, metadata, currency, and correlation fields in `doc/architecture/db_schema_v1.sql`. | Source adapters are missing for managed storage, network, Token Factory/model tokens, scheduler jobs, and most app runtime building blocks. Usage records do not yet carry the full canonical billing attribution shape for submitter, route, reseller, or pricing snapshot. |
| Rating | Implemented foundation for allocation usage; broader model pending | `rated_usage_lines` records deterministic allocation GPU-hour rating windows before ledger debit posting. `packages/services/billing/rating.go` owns rating keys, integer minor-unit rounding, overflow checks, and unit tests. `packages/services/billing/posting.go` owns the explicit rated-line persistence boundary used by the billing worker, so rating output and ledger posting are named billing service operations even while one worker still orchestrates both. Billing worker ledger metadata links debits to rated lines. `GET /api/v1/billing/rated-usage` and `GET /api/v1/billing/rated-usage/{rated_usage_line_id}` expose account-scoped rating evidence with ledger and invoice anchors. `POST /api/v1/admin/billing/shadow-rating` dry-runs selected historical allocation `gpu_hour` usage against candidate pricing and returns `ledger_writes=false`/`rated_usage_writes=false`. | Dedicated rating worker process, non-allocation units, and richer posting lag queues are still pending. |
| Ledger | Implemented baseline with database immutability guard and posting boundary | `ledger_entries` is append-only and used for usage debits, Stripe credits, admin credits, refund credits, and adjustments. `ledger_entries_immutable` rejects UPDATE/DELETE by default; corrections must be additive. Balance reads group `ledger_entries` per-currency in `packages/services/billing/service.go`; `GET /api/v1/billing/balance` keeps the compatibility `balance` field and adds canonical `balances[]`. `PostRatedUsageLedgerEntry` centralizes rated-usage ledger posting and rated-line attachment for the allocation path. Payment and usage paths write ledger rows with reference metadata. | No formal correction workflow beyond additive entries. Dedicated ledger-posting worker extraction remains future work. |
| Invoicing | Internal draft lifecycle, worker generation, read API, tax evidence foundation, and V3 read surface implemented | `invoice_headers` and `invoice_lines` exist with period, lifecycle status, currency, total, tax total/treatment/snapshot evidence, line-level tax category/rate/jurisdiction/exempt/reverse-charge evidence, and anchors to rated usage, ledger entries, and payment sessions. `billing_tax_profiles` stores the current tenant tax evidence source; invoice rows snapshot evidence for immutability. `packages/services/billing/invoice.go` can create draft invoices, reconcile header total from lines, read invoice summaries/details, and generate draft invoices from uninvoiced rated usage lines for the previous closed monthly period. `cmd/billing-worker` runs invoice generation after accrual/budget scans and exposes generation metrics. `GET /api/v1/billing/invoices` and `GET /api/v1/billing/invoices/{invoice_id}` expose the account-scoped read surface. V3 account billing renders invoice summaries, detail, line items, and evidence anchors. | No tax calculation engine, invoice evidence export, issue/due/payment transitions, or provider-hosted invoice payment. |
| Payments | Implemented baseline; production provider partial | `packages/services/payments` supports provider abstraction, mock checkout/customer portal creation, real Stripe checkout-session creation when `STRIPE_SECRET_KEY` is configured, and Stripe billing-portal session creation when the account has an active default row in `billing_provider_customers`. `POST /api/v1/payments/checkout-session` records an initiated `payment_sessions` row with provider session id, checkout URL, idempotency key, amount/currency, and correlation id before returning the redirect URL. `POST /api/v1/admin/billing/provider-customers` gives finance operators an API-first path to link or repair tenant-rooted provider customer identities with same-transaction audit. Mock checkout then credits the session immediately for local/dev UX. `cmd/webhook-worker/routes.go` persists Stripe events, finalizes existing payment sessions, writes Stripe credit ledger entries, emits outbox events, and records reconciliation failures. `payment_sessions` supports idempotency key and provider references. `payment_disputes` now provides provider-neutral dispute and chargeback lifecycle evidence linked to provider sessions, Stripe events, and chargeback/reversal ledger entries. Legacy organization/user `stripe_customer_id` fields remain as read fallback during migration. | Payment provider model is Stripe-focused. No automatic provider-customer creation, fully modeled provider refund integration, dispute webhook ingestion, evidence submission workflow, or account restriction policy tied to disputes. Payment-session recovery exists for ops but is not yet a complete finance workflow. |
| Budgets | Notification-only model foundation implemented; posture/read/decision APIs, V3 read surface, worker scan, and notification delivery implemented | `budget_policies` and `budget_events` exist for tenant/project scoped budgets. Budget events use first-seen/last-seen/count semantics and default to `notify_only`. `packages/services/billing/budget.go` evaluates threshold crossings, scans active budget policies against current ledger usage-debit spend, resolves tenant/project budget recipients, and emits `billing.budget_threshold_crossed` outbox events for first-seen crossings without blocking launches. `POST /api/v1/billing/budget-decisions` computes side-effect-free `allow`/`warn`/`would_block` decisions for proposed launch amounts so future enforcement is explicit and auditable. `cmd/billing-worker` runs the scan after periodic accrual and exposes budget-scan metrics. `cmd/notification-relay` delivers budget-threshold notifications to resolved user channels. `GET /api/v1/billing/budget-posture` exposes active budget policies and latest threshold events for account-scoped read models. V3 account billing renders tenant/project budget posture, spend, threshold, and latest event evidence. Billing worker loads low-balance and prepaid runway policy values and emits low-balance, auto-release-pending, and balance-depleted events. | No wiring from launch flows to the budget decision API. Low-balance/balance-depleted notifications do not yet present affected app impact as first-class billing evidence. |
| Delinquency | Financial restriction foundation plus prepaid depletion transition | Balance-depleted events include active allocation ids, active app instance ids where the current app runtime state/placement links to those allocations, selected depleted action, and projected runway evidence. The billing worker routes prepaid depletion through a policy-selected action: default `restrict` writes a user-scoped financial restriction, while `force_release` emits provisioning force-release requests only when policy explicitly selects it. Financial restriction state helpers and admin mutation paths exist. | No explicit billing decision table yet, no audited operator override model beyond the admin financial-restriction mutation, no V3 disabled reasons for financial restrictions, and no monthly invoice/postpaid delinquency trigger path. |
| Currency | Tenant default and FX snapshot foundation implemented; live conversion pending | `sku_catalog`, `usage_records`, `ledger_entries`, `refund_requests`, `payment_sessions`, `commit_contracts`, `invoice_headers`, and `invoice_lines` include `currency` fields. API money shapes use `amount_minor` plus `currency`. User balance exposes per-currency `balances[]` and avoids mixing ledger currencies. `organizations.default_currency` stores the tenant default, `billing_fx_rate_snapshots` records immutable source/target/rate/provider evidence, `rated_usage_lines.fx_snapshot` and `invoice_lines.fx_snapshot` provide future conversion anchors, and `GET /api/v1/billing/currency-settings` exposes tenant currency posture. | No live FX conversion, reseller/end-customer currency split support, or cross-currency presentation policy beyond explicit FX evidence. |
| Tax | Evidence model implemented; calculation disabled | `billing_tax_profiles` captures current tenant tax profile evidence. `invoice_headers` snapshots tax jurisdiction, treatment, seller/customer registrations, tax total, and tax evidence. `invoice_lines` snapshots tax category, rate basis points, jurisdiction, taxable subject-line link, tax-exempt reason, reverse-charge reason, and line evidence. API invoice responses expose these fields. | No jurisdiction-specific tax calculation, tax provider integration, adjustment/credit memo flow, or tax filing export. |
| Reseller | Billing account foundation implemented; channel rating/invoicing pending | `billing_accounts` models tenant, reseller, and end-customer account types without tenant impersonation. It carries parent/reseller/invoice-recipient links, default currency, wholesale and customer-facing pricing-plan anchors, tax responsibility, credit-risk owner, status, and metadata. `GET /api/v1/billing/account` exposes the tenant-scoped billing account shape. | No reseller-specific rating, invoice presentation, RBAC views, partner margin application, or marketplace revenue-share workflow. |
| Refund | Implemented baseline for admin-created refunds | `refund_requests` schema exists with mode, outcome, provider/internal references, correlation, policy applied, and status. Admin refund routes support list/create through `/api/v1/admin/users/{user_id}/refunds` and V3 finance mirrors. Internal credit path writes ledger references where applicable. | Provider refund integration and authorization workflow are incomplete. No partial refund lifecycle beyond amount/reason fields and no customer-facing refund status model. |
| Dispute | Lifecycle evidence foundation implemented; provider ingestion pending | `payment_disputes` records provider-neutral dispute and chargeback state (`opened`, `needs_response`, `evidence_due`, `evidence_submitted`, `won`, `lost`, `closed`) with provider references, evidence due/submitted timestamps, amount/currency, correlation, provider event, and chargeback/reversal ledger anchors. `ledger_entries` accepts `chargeback_debit` and `chargeback_reversal` entry types for additive financial corrections. `GET /api/v1/admin/payments/disputes` and `GET /api/v1/admin/payments/disputes/{dispute_id}` provide finance-ops read surfaces. | No provider dispute webhook ingestion, evidence submission mutation, account restriction policy, or dedicated dispute worker metrics yet. |
| Pricing plans | Snapshot foundation implemented; plan application pending | `pricing_plans`, `pricing_plan_versions`, `subscriptions`, and `commit_contracts` exist in schema. New allocations snapshot `pricing_mode`, `billing_unit_price_minor`, `billing_currency`, optional plan/version identifiers, and `billing_pricing_snapshot`. Billing worker prefers the allocation snapshot and only falls back to `sku_catalog` for older rows. | No tenant pricing-plan assignment, no plan-selection API, no commit application logic, no spot/reserved lifecycle, and no safe rollout/shadow-rating path. |
| Retention | Policy foundation implemented; destructive jobs disabled | `doc/architecture/Billing_Retention_and_Compaction_Policy_v1.md` defines table-by-table retention, raw usage compaction, invoice evidence, dispute evidence, and PII minimization gates. `packages/services/billing/retention.go` exposes the executable policy and a no-delete raw usage compaction decision helper that can only return `compact_candidate` after all gates pass. | No compaction worker, raw usage summary table, policy admin surface, or finance/security review workflow yet. Raw usage deletion remains explicitly blocked. |
| Managed ingress usage | Partial building-block implementation | `packages/services/billing/managed_ingress_usage.go` defines managed-ingress units, required route metadata, converts route touchpoints into the product-neutral `billing.usage.metered` payload shape, and records zero-cost app-runtime `usage_records` through the shared metering ingestion path. `cmd/api/routes_platform_proxy_authz.go` records managed-ingress api-bearer forwarding metrics and calls that billing service path. | Managed-ingress usage is not yet rated or posted to ledger/invoice. Route usage metadata is stored as generic metadata, not first-class usage columns. Browser route usage, high-volume sampling/summary policy, and a durable async consumer for `billing.usage.metered` still need validation. |
| Token Factory | Design-only | Billing target document now defines `token_input` and `token_output` as future units and a Token Factory metering integration direction. | No source adapter, event contract, usage-record writer, rating policy, or V3 evidence for token usage. |
| Finance read models | Implemented for payment/reconciliation support; partial for broader billing | V3 finance routes list payment sessions, payment-session detail, diagnostics, user refunds, and billing reconciliation runs. V3 account billing renders balance, usage, refunds, checkout, portal actions, invoices, and budget posture. Account-scoped invoice, budget posture, rated usage evidence, currency-settings, and billing-account read APIs exist. | No reseller operator views, tax evidence UI, pricing-plan snapshot UI, shadow-rating UI, or delinquency state surfaces. |
| Worker operations | Partial | `cmd/billing-worker` consumes provisioning/payment events, accrues usage, scans budget thresholds, generates internal draft invoices, logs reconciliation mismatches, emits OTel spans, and exposes `/healthz` plus `/metrics` on `BILLING_WORKER_HTTP_ADDR` with processed/failure, accrual/reconcile/budget-scan/invoice-generation timestamp, reconciliation mismatch, budget-scan, invoice-generation, and NATS consumer backlog gauges. `cmd/notification-relay` consumes budget-threshold events alongside existing billing events. `cmd/webhook-worker` exposes payment reconciliation metrics. | No separate rating/posting workers, no dedicated dispute worker metrics, no oldest-unprocessed indicators for future stage queues, and no dry-run/shadow-rating command. |
| Testing | Implemented for current baseline; incomplete for money-domain target | Unit tests cover service helpers, invoice period/generation input helpers, budget threshold/window helpers, notification transforms for budget threshold delivery, managed-ingress metadata, and neutral app-runtime usage payload ingestion helpers. Integration tests cover allocation close idempotency, active usage accrual, usage-ledger reconciliation mismatch detection, and webhook reconcile mismatch. Handler tests cover balance, usage, payments, refunds, admin finance surfaces, and shadow-rating dry-run. Schema-level ledger immutability is encoded through `ledger_entries_immutable`. | No shared money-domain harness, no broader currency/tax rounding suite, no invoice generation integration tests, no budget/delinquency integration tests, and no reseller attribution tests. |

## Current API And Surface Inventory

| Surface | Status | Notes |
|---|---|---|
| `GET /api/v1/billing/balance` | Implemented | User-scoped balance with compatibility `balance` plus canonical per-currency `balances[]`; clients must not sum currencies. |
| `GET /api/v1/billing/currency-settings` | Implemented foundation | Tenant-scoped default currency and latest FX snapshot evidence shape; does not perform live conversion. |
| `GET /api/v1/billing/usage` and `/csv` | Implemented | User-scoped usage list with allocation/app filters and CSV export. |
| `GET /api/v1/billing/invoices` and `GET /api/v1/billing/invoices/{invoice_id}` | Implemented read surface | Account-scoped invoice list/detail over `invoice_headers` and `invoice_lines`, including tax/VAT evidence fields; generation exists, while issue/payment transitions and provider invoices remain pending. |
| `GET /api/v1/billing/budget-posture` | Implemented read surface | Account-scoped tenant/project budget policy list with latest threshold event. Notification-only posture; no launch blocking or suspension behavior in this surface. |
| `GET /api/v1/billing/rated-usage` and `GET /api/v1/billing/rated-usage/{rated_usage_line_id}` | Implemented read surface | Account-scoped rated usage evidence over `rated_usage_lines`, with usage, pricing, ledger, and invoice anchors for support/debug workflows. Rating mutation remains separate work. |
| `POST /api/v1/admin/billing/shadow-rating` | Implemented dry-run surface | Admin-only bounded dry-run over selected historical allocation `gpu_hour` usage records. Returns existing rated totals, candidate totals, deltas, candidate rating keys, and explicit no-write flags. |
| `GET /api/v1/billing/refunds` | Implemented baseline | User refund list path exists through core route registration. |
| `POST /api/v1/payments/checkout-session` | Initiation lifecycle implemented; Stripe checkout provider implemented | Request validates amount/currency and returns URL plus optional platform/provider session identifiers. API records initiated `payment_sessions` before redirect when DB-backed. Mock provider is end-to-end; real Stripe checkout-session creation is available when configured. |
| `POST /api/v1/payments/customer-portal-session` | Mock/dev and Stripe portal implemented with transitional customer identity | Mock provider remains local-friendly. Stripe provider path requires organization/user `stripe_customer_id` and creates a billing portal session through Stripe. |
| `POST /api/v1/payments/webhook` | Implemented | Webhook worker endpoint; raw-body and Stripe event persistence path. |
| `GET/POST /api/v1/admin/users/{user_id}/refunds` | Implemented | Admin refund workflow baseline. |
| `GET /api/v1/admin/payments/disputes` and `GET /api/v1/admin/payments/disputes/{dispute_id}` | Implemented foundation | Admin-only provider-neutral dispute and chargeback lifecycle evidence over `payment_disputes`. Read-only in this slice; provider ingestion and evidence mutations remain pending. |
| `GET/POST /api/v1/admin/billing/reconciliation` | Implemented | Usage-ledger posture and recorded reconciliation run. |
| `GET /api/v1/admin/billing/diagnostics` | Implemented | Correlation-oriented support diagnostics. |
| `/api/v1/v3/platform/finance/*` | Implemented for payment sessions/refunds/reconciliation | V3 finance workbench surfaces payment-session recovery and diagnostics. |
| Pricing-plan and reseller mutation APIs | Missing | Contract-first mutation work remains pending. Invoice mutation/generation APIs are still separate from the read-only invoice surface. |

## Schema Inventory

| Table or shape | Status | Notes |
|---|---|---|
| `usage_records` | Implemented with no-delete retention policy | Allocation and app-runtime capable, but canonical attribution is incomplete. Raw usage can only become a compaction candidate after rating, invoice finalization, dispute-window closure, audit evidence review, and PII minimization review. |
| `ledger_entries` | Implemented | Core financial source of truth; no mutable balance column. |
| `payment_sessions`, `payment_disputes`, `billing_provider_customers`, and `stripe_events` | Implemented foundation | Checkout/session lifecycle, provider-neutral dispute/chargeback lifecycle evidence, tenant-rooted provider customer identity, and webhook idempotency anchors. |
| `refund_requests` | Implemented baseline | Internal/provider refund shape exists. |
| `billing_reconciliation_runs` | Implemented | Ops evidence for usage-ledger posture. |
| `pricing_plans`, `subscriptions`, `commit_contracts` | Schema-only | No runtime integration yet. |
| `invoice_headers`, `invoice_lines` | Schema, read API, and V3 read surface | Invoice tables are readable through account-scoped APIs and V3 account billing; worker generation, lifecycle transitions, provider invoices, and tax remain pending. |
| Retention policy helper | Implemented foundation | `packages/services/billing/retention.go` centralizes retention and raw usage compaction decisions so future workers do not invent table-specific deletion behavior. |
| Reseller tables | Implemented foundation | `billing_accounts` establishes the channel billing account shape; FX snapshot scaffolding exists through `billing_fx_rate_snapshots`, `rated_usage_lines.fx_snapshot`, and `invoice_lines.fx_snapshot`; tax evidence scaffolding exists through `billing_tax_profiles` and invoice tax snapshot columns. Live conversion, tax calculation, reseller margin rating, and channel invoices remain pending. |

## Remaining Priority Gaps

The first implementation pass completed the money-domain harness, allocation
rating foundation, pricing snapshots, notification-only budgets, internal draft
invoices, invoice/budget/rated-usage read APIs, V3 account billing reads,
provider checkout/customer identity, worker metrics, shadow rating, per-currency
balances, and ledger immutability.

The initial queue-backed implementation pass is complete. Follow-up production
gaps move into scoped implementation epics for rating-worker extraction, raw usage
compaction worker design, provider dispute ingestion, tax calculation, reseller
rating/invoicing, and delinquency enforcement.
