Skip to content

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.

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

When Cloud receives the webhook, it writes:

tenant_licenses table:

ColumnDescription
tenant_idUUID — links to tenant
planPlan name (e.g. “standard”, “enterprise”)
expires_atLicense expiry timestamp
updated_atLast webhook update

tenant_features table:

ColumnDescription
tenant_idUUID — links to tenant
featureFeature key (e.g. “security”, “vpn”, “backup”)
enabledBoolean

At login time (POST /api/v1/auth/login):

  1. The billing domain checks tenant_licenses for the tenant
  2. If no active license exists → 403 {"error": "tenant_pending"}
  3. 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.

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:

  1. Start both Cloud Backend (:8000) and Management Backend (:8080)
  2. Register a tenant on Cloud (POST /api/v1/auth/register)
  3. In Management Frontend (:5173), import or create the tenant and link cloud_tenant_id
  4. Activate license → webhook fires → Cloud tenant becomes active

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.