Data Model
The billing platform’s data model reflects the lifecycle of a billing relationship.
Core Entities
Customer
Customer {
id: CustomerId (UUIDv7)
display_name: String
legal_name: Option<String>
email: String
account_type: Organization | Individual | Subsidiary
status: Active | Suspended | Closed
parent_id: Option<CustomerId> // hierarchy
bill_to_id: Option<CustomerId> // invoice recipient override
consolidation: Standalone | ConsolidateToParent
billing_currency: Currency
payment_terms_days: u32
tax_id: Option<String> // VAT/EIN — exempts from tax
}
Subscription
Subscription {
id: SubscriptionId (UUIDv7)
customer_id: CustomerId
plan_id: PlanId
status: Trialing | Active | PastDue | Paused | Cancelled | Expired
currency: Currency
period_start: DateTime<Utc>
period_end: DateTime<Utc>
charged_through_date: DateTime<Utc> // advance with each billing cycle
trial_days: u32
contract_id: Option<ContractId> // enterprise contract link
billing_cadence: Monthly | Annual | Weekly | Custom
}
Invoice
Invoice {
id: InvoiceId (UUIDv7)
invoice_number: Option<String> // "INV-000001" — assigned on finalization
status: Draft | Open | Paid | Void
invoice_type: Standard | CreditNote | ProForma
customer_id: CustomerId
subscription_id: SubscriptionId
line_items: Vec<InvoiceLineItem>
total_nanos: i128 // pico-units, sum of line items
currency: Currency
period_start: DateTime<Utc>
period_end: DateTime<Utc>
due_date: NaiveDate
applies_to_invoice_id: Option<InvoiceId> // credit notes only
voided_reason: Option<String>
finalized_at: Option<DateTime<Utc>>
created_at: DateTime<Utc>
}
InvoiceLineItem
InvoiceLineItem {
id: InvoiceLineItemId (UUIDv7)
invoice_id: InvoiceId
description: String
quantity: Decimal
unit_amount_nanos: i128
amount_nanos: i128
currency: Currency
is_tax: bool // true for tax lines
}
Contract
Contract {
id: ContractId (UUIDv7)
customer_id: CustomerId
status: Draft | Active | Amended | Expired | Terminated
parent_contract_id: Option<ContractId> // amendment chain
start_date: NaiveDate
end_date: NaiveDate
terms: Vec<ContractTerm> // ramp phases
rate_overrides: Vec<RateOverride> // enterprise custom pricing
escalation: Option<Escalation>
}
Entity Relationships
Customer (1) ──► (*) Subscription
Customer (1) ──► (*) Invoice
Customer (1) ──► (*) Contract
Customer (1) ──► (0-1) CreditWallet (TigerBeetle account)
Subscription (1) ──► (*) Invoice
Subscription (1) ──► (0-1) Contract (via ContractSubscription)
Invoice (1) ──► (*) InvoiceLineItem
Invoice (CreditNote) ──► (1) Invoice (Standard) // applies_to_invoice_id
CockroachDB Schema
Multi-region tables use REGIONAL BY ROW for geo-distributed data locality. Each billing entity is homed in the region closest to the customer’s billing address.
CREATE TABLE subscriptions (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
customer_id UUID NOT NULL,
plan_id UUID NOT NULL,
status subscription_status NOT NULL DEFAULT 'trialing',
currency VARCHAR(3) NOT NULL,
period_start TIMESTAMPTZ NOT NULL,
period_end TIMESTAMPTZ NOT NULL,
charged_through_date TIMESTAMPTZ NOT NULL,
crdb_region crdb_internal_region AS (
CASE WHEN billing_region = 'EU' THEN 'eu-west' ELSE 'us-east' END
) STORED
) LOCALITY REGIONAL BY ROW AS crdb_region;
See infra/crdb-schema/ for the full DDL (6 SQL files).