AUTH4D-38 billing domain (@auth4/billing)

This ticket adds the provider-agnostic billing domain and no public HTTP routes. Management billing routes and the Stitch webhook handler are specified by their owning tickets.

  • Plan catalog (PLAN_CATALOG): free (R0), indie (R199.00 = 19900 cents/month), studio (R999.00 = 99900 cents/month), each with PlanEntitlements. Prices and limits are placeholders pending product confirmation. Tenants without an active or past_due subscription are on free and need no billing account.
  • State machines use the stored 0005 statuses. Illegal transitions throw IllegalTransitionError.
    • Subscription: pending → active | canceled | expired; active → active | past_due | canceled | expired (active → active is a renewal); past_due → active | canceled | expired; expired → active (reactivation by payment); canceled is terminal.
    • Payment: pending → succeeded | failed | canceled | expired; all other states are terminal.
    • Invoice: draft → open | void; open → paid | void | uncollectible; uncollectible → paid | void.
    • Contract mapping: payment succeeded maps to completed; subscription pending maps to incomplete, and expired maps to canceled.
  • Repository (createD1BillingRepository(db)): every read and write requires a customer tenant id and filters on it. recordProviderEvent returns duplicate for a repeated (provider, providerEventId). applyPaymentOutcome records the event, then commits the payment, invoice, subscription and event updates in one guarded D1 batch. A completed payment activates the subscription, or extends it by one interval, exactly once. Repeats and concurrent deliveries return duplicate or ignored, and a reported amount that differs from the stored amount is rejected.
  • External reference sent to the provider: {tenantId}.{paymentId} (createExternalReference / parseExternalReference).
  • Mutations return BillingAuditRecords (names from BILLING_AUDIT_EVENTS) for the caller to append to the audit log.

Source: docs/api-spec/auth4d-38.md