Deployment
This page covers what you need to stand up an Enterprise deployment and what happens on first boot. For ongoing operation see Operations.
Deployment shapes
The Enterprise binary ships as a container image. Two paths are supported today:
| Option | Notes |
|---|---|
| Helm chart | deploy/helm/quantumbpm-enterprise deploys the backend + SPA to Kubernetes/OpenShift. This is the recommended path - see the chart's README.md and values-example.yaml. |
| Any container runtime | The image runs anywhere - k8s, Nomad, ECS, bare VMs with systemd. If you need help with a production Kubernetes deployment, contact support@quantumbpm.com. |
QuantumBPM does not ship a Temporal server. If you need BPMN, bring your own Temporal cluster (Temporal Cloud, self-hosted Temporal, etc.) and point the binary at it via TEMPORAL_HOST_PORT (config.temporal.hostPort in the Helm chart). DMN-only deployments can leave it unset.
Required external components
| Component | Notes |
|---|---|
| PostgreSQL | Any recent supported PostgreSQL release. Schema migrations run automatically on every startup. |
| OIDC provider | Any spec-compliant IdP - Keycloak, Okta, Auth0, Azure AD, Zitadel, etc. The discovery endpoint must be reachable from the backend at boot. |
| Temporal cluster | Required only if you use BPMN. See Temporal setup. |
License key
Enterprise deployments require a signed license JWT, presented at startup via LICENSE_KEY.
| Property | Detail |
|---|---|
| Environment variable | LICENSE_KEY |
| Format | JWT signed with RS256 |
Issuer (iss) | QuantumBPM |
| Claims | org (organization name), exp, iat |
Validation behavior:
- Startup - signature, issuer, and expiry are checked. Missing, invalid, or expired license → backend exits with a non-zero status code.
- Daily - a background goroutine re-validates the license every 24 hours. Expiry triggers a graceful shutdown (readiness false → HTTP drain → workers stopped → exit 1).
- Two months before expiry - a warning is logged so you have time to renew without an outage.
To obtain or renew a license, contact your QuantumBPM account contact directly. There is no self-service flow.
Project provisioning
The Enterprise binary reads a YAML file at startup to bootstrap the set of projects. This lets you reproduce identical environments across staging and production with a known, version-controlled project list.
| Setting | Detail |
|---|---|
| Environment variable | PROVISIONING_PATH |
| Default path | projects.yaml (relative to the working directory) |
| Idempotency | Re-read on every startup. Projects whose IDs already exist are left untouched. |
Schema:
projects:
- id: "00000000-0000-0000-0000-000000000001"
name: "Loan Approval"
- id: "00000000-0000-0000-0000-000000000002"
name: "Risk Scoring"
Each entry needs a id (UUID) and name. Other settings (members, RBAC) come from OIDC token claims at request time - see Authentication.
First-boot checklist
Each of these is checked at startup and will fail-fast (the backend won't come up) if it's wrong:
-
LICENSE_KEYis set, signed, and not expired. Without it, the binary exits during startup. -
OIDC_ISSUERis reachable. The backend fetches the discovery document ({issuer}/.well-known/openid-configuration) and aborts if it can't. -
OIDC_CLIENT_ID(orOIDC_AUDIENCES) is set. With neither, no token audience can be accepted, so the backend refuses to start rather than boot into a silent auth outage. - PostgreSQL is reachable and credentials are correct. Internal schema migrations run on boot.
-
PROVISIONING_PATHis present and well-formed (defaultprojects.yaml). A missing file is a warning and provisioning is skipped; a file that exists but is malformed/unreadable fails startup.
Temporal is not checked at boot. When TEMPORAL_HOST_PORT is non-empty the client connects lazily, so an unreachable Temporal does not block startup - it surfaces through the readiness endpoint instead (see below). For DMN-only deployments, set TEMPORAL_HOST_PORT="" to opt out (the default is localhost:7233).
Once the boot checks pass, the backend serves the REST API on REST_API_PORT (default 8080) and metrics on REST_METRICS_PORT (default 9464) when ENABLE_OTEL=true.
Health endpoints
/healthz(liveness) - returns200while the process is up. Intentionally dependency-free: a Postgres or Temporal blip must not restart the pod./readyz(readiness) - returns200only once startup has completed and the dependency probes pass: it pings Postgres and (whenTEMPORAL_HOST_PORTis set) checks Temporal frontend reachability. A failure returns503so a load balancer drains the pod without restarting it. Point your Kubernetes readiness probe here and liveness at/healthz.
Next steps
- Wire up your OIDC provider: Authentication
- See the full set of tunables: Configuration
- Get observability and tuning right: Operations