Skip to content

Billing

Purpose

The platform charges companies (tenants) for using TKT Space. This context owns that revenue stream: subscription state, plan, period, renewal cadence, and the payment history that drives it.

It is intentionally separate from the Companies context even though both Drizzle tables live in companies.schema.ts — billing has its own lifecycle (trial → active → past-due → cancelled), its own cron-driven renewal flow, and a different stakeholder (finance vs CRM).

Boundaries

  • In: SaaS subscription state of a company, payment attempts for that subscription, renewal flag.
  • Out:
    • Per-customer money (wallet balances, top-ups) is in the Wallet context.
    • Gateway-level payment records for everything (bookings, pass purchases, top-ups, and subscription payments) are in the Payments context. Subscription payments here are the billing-side bookkeeping; the actual gateway transaction has its own Payment row.

Entities

IDEntityRole in this context
ENT-001Company subscriptionThe tenant’s current plan + status
ENT-002Subscription paymentPayment attempt against a subscription (initial, renewal, retry)

Backend implementation

  • Module: libs/features/billing/
  • Surface routing: business only — billing-admin.module.ts.
  • Drizzle schema: Physically in libs/shared/data-access-db/src/lib/schema/companies.schema.ts (within pgSchema('companies')), but conceptually a separate context.

Cross-context relationships

  • This context owns companies.company_subscription and companies.subscription_payment.
  • This context references Companies via companyId (FK within the same Postgres schema, ON DELETE CASCADE).
  • This context interacts with Payments — a subscription payment may have a corresponding row in payments.payment via the polymorphic sourceType / sourceId (subscription-payment id as source).

Open questions

  • OPEN: subscription_payment.amount is stored as text (other money fields use numeric/decimal); a future migration may align it — see Subscription payment.
  • OPEN: business OpenAPI lacks explicit subscription-payment DTOs at audit time — verify the admin-panel reads.