06 β Core Provisioning & Platform Billing
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:
- Records the tenant, decides
sharedvscontainer_per_tenant, and (for dedicated) orchestrates a Kubernetes Deployment/Service/Ingress. - Authors and stores the license (the enabled-module entitlement) β see 04.
- Delegates database creation to the tenant-api over
POST /internal/database/initializeβ the data plane creates and migrates its owntenant_<uuid>DB. - 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:
MonthlyBillingService.calculateMonthlyBillingcomputes a tenant's monthly charge from usage metrics, and returns a result object β it persists no invoice/transaction. (There is noSubscriptionControllerin core-api; the platform-billing surface isLicenseController+LicenseService+MonthlyBillingService.)- Usage metrics flow up from each regional tenant-api: the tenant-api's
metricsmodule collects/aggregates regional usage and submits it to core-api (tenant_usage_metric). - The only cross-plane influence on the data plane is feature-gating: the financial processors check the license (
financials:automated_billing,financials:statement_runs) and skip (never charge) when a feature is off.
Note: the tenant-api's ownSubscriptionControllerendpoints (e.g.GET /public/me/subscription) are member-facing β a member's activeAccountItems 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:
hard_blockβ deny once the cap is hit.soft_warningβ allow but warn.overage_chargeβ allow and bill the overage (the hook by which usage maps to platform billing).
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:
- a distinct compute instance (orchestrated, 02),
- its own database (created by that instance, 03),
- a distinct
REDIS_PREFIXfor queue isolation (the open gap), and - the same license, resolved the same way.
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.