Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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).