06 β€” Core Provisioning & Platform Billing

← Index

This document covers the control-plane responsibilities that surround a tenant's lifecycle β€” and clarifies a point that's easy to get wrong: how the platform bills a tenant is completely separate from how a tenant bills its members (05).

The two planes are decoupled

Provisioning, licensing, and platform-billing live in core-api. Member/customer billing lives in tenant-api. They are connected by exactly one thread: the license entitlement. There is no flow where core-api writes into a tenant's ledger, and no flow where the tenant-api creates platform charges.

core-api (control plane)                         tenant-api (data plane)
────────────────────────                         ───────────────────────
createTenant / deployment / orchestration   ──►  /internal/database/initialize (creates+migrates DB)
generate+store license  ───────────────────────► checkModuleAccess gates every request
meter tenant usage β†’ MonthlyBillingService       FinancialService / BillingJobProcessor (members)
   (what the TENANT owes the PLATFORM)              (what MEMBERS owe the TENANT)

Provisioning recap

The full creation flow is in 02. In summary, core-api TenantProvisioningService.createTenant:

  1. Records the tenant, decides shared vs container_per_tenant, and (for dedicated) orchestrates a Kubernetes Deployment/Service/Ingress.
  2. Authors and stores the license (the enabled-module entitlement) β€” see 04.
  3. Delegates database creation to the tenant-api over POST /internal/database/initialize β€” the data plane creates and migrates its own tenant_<uuid> DB.
  4. Bootstraps an admin user and primes the license cache.

The deployment strategy (determineDeploymentType) is the decision point that ties the drivers (compliance, scale, region) to the deployment shape. Compliance/residency and noisy-neighbour/scale are what push a tenant to container_per_tenant.

Platform billing (what the tenant owes the platform)

Platform-level billing of tenants lives entirely in core-api and does not touch the tenant-api ledger:

Note: the tenant-api's own SubscriptionController endpoints (e.g. GET /public/me/subscription) are member-facing β€” a member's active AccountItems on their account β€” and are unrelated to platform plans.

Module limits & enforcement

A license's module_limits[] (see 04) can cap records/API calls/storage per module, each with an EnforcementStrategy:

These are the lever connecting entitlement to platform billing: usage beyond entitlement can become an overage metric that MonthlyBillingService prices.

What this means for the per-tenant-instance model

Because the data plane already owns its own schema and migrations and is gated purely by the license, moving a tenant from shared to container_per_tenant requires no change to billing or feature logic β€” only:

The platform-billing path is unchanged: usage still meters up to core-api regardless of deployment shape.


Key source paths: src/core-api/src/services/tenant/TenantProvisioningService.ts, src/core-api/src/services/**/MonthlyBillingService.*, src/core-api/src/services/**/LicenseService.*, src/tenant-api/src/controllers/metrics/*, src/tenant-api/src/services/license/TenantLicenseService.ts.

Next: 07 β€” Tenant API module catalog β†’