Operations
How to deploy and run the whole platform: deployments, environment conventions, secrets, the first deployment, addresses, probes, metrics, artifacts, versions and rollback. It is for operators; each service's own environment, alerts and runbooks are on its pages, listed under Service pages.
Read byPlatform operator
Service pages#
| Service | Operations | Environment variables |
|---|---|---|
| Gateway | Gateway operations | Gateway configuration |
| Access | Access operations | Access spec: environment |
| Data | Data operations | Data configuration |
| Console | Console operations | Console configuration |
| CLI | CLI usage | CLI spec: profiles |
Deployments#
| Service | Image | Port | Env prefix | State it needs |
|---|---|---|---|---|
| Gateway | ghcr.io/ggpwnkthx/gateway | 8080 | GATEWAY_* | Redis or PostgreSQL: sessions, limits, cached decisions |
| Access | ghcr.io/ggpwnkthx/access | 8081 | ACCESS_* | PostgreSQL for its eight tables; Redis for login codes |
| Data | ghcr.io/ggpwnkthx/data | 8082 | DATA_* | PostgreSQL for business data |
The gateway also runs a control plane, the deployment's administrative surface. It uses the same image with a different command, listens on port 9090, and is never routed through the gateway.
The console is published like the three services: ghcr.io/ggpwnkthx/console. See console operations. Compose stacks and Kubernetes manifests are described in deploy/README.md.
Environment conventions#
Every service reads its environment once at startup and validates it as a whole. It reports every problem before it refuses to start, and any value it cannot parse stops it. The one exception is the log level, because a typo there must not keep a deployment down.
Secrets as files#
Access and Data accept a secret as a file named by a *_FILE variable (ACCESS_SIGNING_KEY_FILE, DATA_CURSOR_KEY_FILE, DATA_ACCESS_CONTEXT_TOKEN_FILE, …). Mount the files your secret manager provides and point those variables at them. The gateway reads its secrets from the environment, except the control plane's token map, which can come from GATEWAY_CONTROL_TOKENS_FILE; the production Compose files take those variables from the shell environment or the --env-file you pass. Security: secrets lists who holds which secret.
First deployment#
Run these steps in order. Each command's manual is in its service's docs, and deployments that run the images run the same commands in the same order.
- Secrets. In production, mount your secret manager's files (Secrets as files).
bun run scripts/dev-keys.tsgenerates development keys..env.minlists the variables a stack refuses to start without. - Database roles. Create Data's separated roles once, with server-administrator credentials:
bun run --cwd packages/data provision. - Schema. Apply migrations with the schema owner's credentials, never the API's:
bun run --cwd packages/data migrate. - Workspace. Register the workspace, the unit of access control. Data reads it before a principal's context exists:
bun run --cwd packages/data workspace create \
--id 11111111-1111-4111-8111-111111111111 \
--tenant 22222222-2222-4222-8222-222222222222 \
--slug acme- Tenant, principals and grants. Create them only through Access's administration API; see Access operations. The cutover suite rehearses these calls.
- Route table. The gateway reads it from a file (
GATEWAY_CONFIG) or from shared state, where the control plane writes revisions. The format is in the gateway spec: configuration file; the deployment's table isdeploy/config/routes.json. - Stack. Start the production stack:
docker compose --env-file .env.min \
-f deploy/compose/production/platform.compose.yaml up -d- Verify. Check each service's health, then send a request through the gateway that Data answers:
curl -sS http://localhost:8080/healthz
curl -sS http://localhost:8081/healthz
curl -sS http://localhost:8082/healthzA successful answer proves three things at once: the caller is authenticated, Access allows the workspace, and Data returns the row.
Addresses#
| Address | Configured by |
|---|---|
| Access issuer | GATEWAY_OIDC_ISSUER, with the deployment's client and redirect |
| Access (from the gateway) | GATEWAY_ACCESS_URL |
| Data upstream | The route's upstream in the gateway route table |
| Access (from Data) | DATA_ACCESS_URL |
| Gateway bindings | DATA_GATEWAY_BINDINGS_FILE |
The bundled services are not the only options: the gateway works with any conforming identity provider, Access and upstream.
Probes#
| Endpoint | Behavior |
|---|---|
GET /healthz | Always 200: the process is alive. |
GET /readyz | 200 when the service can serve requests, 503 otherwise. |
Readiness reports ready, draining or not-ready. What it depends on:
| Service | Ready when |
|---|---|
| Gateway | Shared state works (sessions must be storable) |
| Access | Its database and shared store work |
| Data | Its schema, its connection role and Access's access context work |
Metrics#
Every service exposes Prometheus metrics on /metrics. The gateway and Access require a bearer token, and without one configured the endpoint does not exist. Data reads its token from a file. Metric names are listed in each service's docs.
Images and binaries#
| Artifact | Where |
|---|---|
| Gateway image | ghcr.io/ggpwnkthx/gateway:<version> |
| Access image | ghcr.io/ggpwnkthx/access:<version> |
| Data image | ghcr.io/ggpwnkthx/data:<version> |
| Console image | ghcr.io/ggpwnkthx/console:<version> |
| Digests | digests.json, an asset of the tag's GitHub release |
| Binaries | Assets of the tag's GitHub release |
| Data typed client | data-backend-client-<version>.tgz, and the package registry |
| CLI | platformctl-<version>-<platform>.tar.gz, an asset of the tag |
docker pull ghcr.io/ggpwnkthx/gateway:1.0.0
docker pull ghcr.io/ggpwnkthx/access:1.0.0
docker pull ghcr.io/ggpwnkthx/data:1.0.0
docker pull ghcr.io/ggpwnkthx/console:1.0.0Each release builds its images once, publishes them with provenance and an SBOM, and runs every release gate against that build's digest. Pin the digest in your deployments: the file digests.json of the release names the digest of every image, and the wizard of the deployment reads that file:
platformctl deploy azureBinaries embed the runtime, so nothing else needs installing. The Access archive includes its schema migrations next to the executable; the Data archive includes its manifests and migrations.
Versions#
A release carries all four images at the same version. A deployment may run them at different versions; the compatibility baseline shows which combinations are proven.
Rollback#
Images are tagged with both the release tag and the version. To roll back, deploy the previous release's image:
docker pull ghcr.io/ggpwnkthx/gateway:<previous version>