License Flow
Licenses control which Cloud tenants can log in and which modules they have access to. Management is the source of truth; Cloud enforces the state.
License lifecycle
Section titled “License lifecycle”flowchart TD
A[Operator creates tenant in Management] --> B[Tenant in Management DB - cloud_tenant_id linked]
B --> C[Tenant registers on Cloud - POST /auth/register]
C --> D[Cloud tenant: pending - login blocked]
D --> E[Operator assigns license in Management]
E --> F[Management sends HMAC webhook to Cloud]
F --> G[Cloud updates tenant_licenses and tenant_features]
G --> H[Cloud tenant: active - login allowed]
H --> I{License expires?}
I -->|No| H
I -->|Yes| J[Grace period - features restricted]
J --> K[Operator renews license in Management]
K --> F
License data model
Section titled “License data model”When Cloud receives the webhook, it writes:
tenant_licenses table:
| Column | Description |
|---|---|
tenant_id | UUID — links to tenant |
plan | Plan name (e.g. “standard”, “enterprise”) |
expires_at | License expiry timestamp |
updated_at | Last webhook update |
tenant_features table:
| Column | Description |
|---|---|
tenant_id | UUID — links to tenant |
feature | Feature key (e.g. “security”, “vpn”, “backup”) |
enabled | Boolean |
Enforcement
Section titled “Enforcement”At login time (POST /api/v1/auth/login):
- The
billingdomain checkstenant_licensesfor the tenant - If no active license exists →
403 {"error": "tenant_pending"} - If license found → JWT issued; feature flags loaded from
tenant_features
After login, the SPA calls GET /api/v1/me/features which reads from the cached feature state. Feature-gated API endpoints also check tenant_features on every request.
Dev environment
Section titled “Dev environment”On local dev, you must activate the tenant through Management exactly as in production. Do not use LICENSE_DEV_OVERRIDE — it does not exist. Without license activation, Cloud tenants cannot log in.
Quick local activation:
- Start both Cloud Backend (
:8000) and Management Backend (:8080) - Register a tenant on Cloud (
POST /api/v1/auth/register) - In Management Frontend (
:5173), import or create the tenant and linkcloud_tenant_id - Activate license → webhook fires → Cloud tenant becomes active
Webhook failure handling
Section titled “Webhook failure handling”If the Management → Cloud webhook call fails (e.g. Cloud is unreachable), Management should retry. Cloud’s webhook endpoint is idempotent — re-sending the same license data is safe. The endpoint updates tenant_licenses using an upsert.
See M2M Integration for webhook authentication details.