Skip to content

Deployment Topology

The whole non-production fleet is described by a single Render Blueprintrender.yaml in luke-platform — that stands up every service across three environments sharing one database instance.

Topology

Environments

EnvironmentPurposeBranch(es)
devIntegration / daily developmentdevelop
qaTest & verificationqa
uatUser-acceptance(promoted)
prodProductionDeliberately excluded from this blueprint (deferred)

Deploy the right branch

Service repos deploy from develop (and qa), not main. A change merged to main for a service repo does not ship. Open PRs against develop (or qa). The one exception is the luke-email library, whose deploy branch is main.

Services per environment

Each environment runs the same six deployables plus shared Postgres:

ServiceTypeNotes
Core EngineDocker web serviceThe engine + capability layer; readiness probe; postgres,prod profile in prod
Auth EngineDocker web serviceStateless WorkOS↔engine gateway
File ProxyDocker web serviceS3 byte-proxy + headless-Chromium PDF render
AgentsRender-native (Python)FastAPI AI agents; no Dockerfile, Render buildpack
Consumer UIStatic siteWith security headers (DENY frame, HSTS, nosniff)
Core UIStatic siteOperator cockpit; CSP currently report-only

All environments share one PostgreSQL instance with per-environment schema-name + table-prefix isolation (see Multi-Tenancy).

The shared database rule

Because dev/qa/uat share one Postgres, each engine instance must set a distinct schema-name + table-prefix. Without it, the second environment to boot crashes creating act_id_user. This is the single most important deployment invariant.

Static apps & vendored bundles

The UIs deploy as Render static sites. Two wrinkles:

  • The public /embed page is a standalone bundle copied into the engine (static/embed-assets) — a Consumer UI push does not update it; you must rebuild the embed bundle, copy it into the engine, and push the engine.
  • The apps consume the headless libraries as vendored built dist, so a library change requires rebuilding the package, re-vendoring, and rebuilding the app.

CORS & edge

The public surface (/api/public/**, /embed*) uses an any-origin / no-credentials carve-out in both engine layers and the auth gateway, because module-script bundle loads send an Origin header even same-origin. The *.lukeflow.com wildcard was intentionally dropped in favor of these explicit carve-outs. See Authentication & Authorization.

Operations tooling

luke-platform also carries the fleet runbooks (DR, rollback, incident triage, scaling/HA), a k6 load-test harness, a ZAP DAST baseline, an S3/IAM provisioning kit, and the merge master prompts. See Platform & Deployment.

See also

Lukeflow Manual · documentation snapshot July 2026