Skip to content

Docker and Kubernetes

Nextvision Status — Docker and Kubernetes

Production dependencies

Use PostgreSQL 17+, Redis 7+ and an S3-compatible MinIO endpoint with a private bucket. Supply DATABASE_URL, REDIS_URL, MINIO_ENDPOINT, MINIO_ACCESS_KEY, MINIO_SECRET_KEY, MINIO_BUCKET, MINIO_TLS, SMTP settings, PUBLIC_URL and OAUTH_CLIENTS through your secret manager. URL credentials must be percent-encoded.

Use a dedicated schema owner for auth, scheduling and public snapshot construction, plus status_runtime for tenant transactions. The owner does not need SUPERUSER or BYPASSRLS. Provision the NOLOGIN runtime role before migration on managed PostgreSQL, then grant the owner SET ROLE without inheriting runtime privileges. Migrations require ownership/DDL rights; initial role creation requires a separate bootstrap operator if the owner has no CREATEROLE.

Tenant tables retain FORCE RLS. Migration 011 adds explicit policies for the schema owner; switching to status_runtime still enforces organization isolation. Never expose either database credential to clients. Use verified TLS, including the provider CA where required.

Build

docker build --build-arg SOURCE_SHA=SOURCE_SHA -t registry/nextvision-status:SOURCE_SHA .
docker build --build-arg SOURCE_SHA=SOURCE_SHA -t registry/nextvision-status-web:SOURCE_SHA apps/web
docker build --build-arg SOURCE_SHA=SOURCE_SHA \
  --build-arg DOCS_SITE_URL=https://status.nextvisions.ai --build-arg DOCS_BASE=/docs/ \
  -t registry/nextvision-status-docs:SOURCE_SHA apps/docs

Configure web API_INTERNAL_URL and DOCS_URL at runtime; use DOCS_URL=/docs/ for the same-origin deployment. No environment-specific frontend rebuild is required. The API remains internal behind the Next.js proxy. Docs are static, built with /docs/ as their base and the Production canonical URL; Dev sends X-Robots-Tag: noindex, nofollow. Docs may also run separately on Cloudflare.

SMTP accepts SMTP_TLS_MODE=auto|implicit|starttls|none. Port 465 uses implicit with certificate verification; none refuses credentials. Dev uses private Mailpit. Supply Production SMTP credentials through a separate Secret, never through image build arguments.

Helm

Create an existing Kubernetes Secret named status-secrets containing the configuration above. Build/push images and record immutable digests. Copy values.yaml into an environment overlay and replace the image names, public URL, ingress host and TLS secret.

helm lint deploy/helm/nextvision-status
helm template status deploy/helm/nextvision-status -f production-values.yaml

For a standalone self-host installation with gitops.enabled=false, install the reviewed overlay with Helm. For the Nextvision environments, commit rendered manifests to GitOps and let Argo deploy; do not run a parallel Helm upgrade against these namespaces. Enable gitops.enabled and postSync.enabled, with the PostSync test image pinned by digest. Migration is an Argo PreSync Job and acceptance is an Argo PostSync Job. A Helm test hook is not release acceptance evidence.

Services use readiness/liveness checks, non-root processes, read-only filesystems and graceful shutdown. HPA is opt-in. Match NetworkPolicy to the real ingress and database paths: Traefik hostNetwork may arrive from node/tunnel addresses, and PostgreSQL NodePort traffic may be translated to its compute Pod/port. Allow only the environment’s compute. Redis uses AOF/PVC; the configured single Longhorn replica is not HA or a backup.

Start with one worker replica: scheduler/evaluator transactions are safe to retry, but increased replicas require testing contention against your workload. Helm-rendering success does not prove a cluster rollout.

CI and promotion

GitHub is canonical source. Exact dev/main SHAs synchronize to private GitLab. GitLab loads the CI configuration/controller from protected ci-control-v3, runs Go race/vet/integration, non-root libpq, Next.js/Nimbus and Helm/gate tests, then builds immutable backend/web/docs and E2E images. Integration uses disposable PostgreSQL, Redis, MinIO and Mailpit without a Docker daemon.

The release controller commits digests to dev-gitops; Argo must reconcile that exact revision, become Healthy and finish the full sync and PostSync. PostSync tests two organizations, memberships, plans, branding, MCP keys, SQL RLS and snapshot fallback through an API with unavailable DB/Redis. Only then does a GitHub-hosted runner perform read-only public acceptance. Source, tree, jobs, digests, GitOps revision, hook UID/log and external run are retained as evidence.

main does not deploy Production automatically. The designated GitLab Owner manually runs promote-production; the job checks Owner identity, current main HEAD/tree, accepted Dev evidence and Production GitOps HEAD. It reuses the same digests without rebuilding. Production needs its own PostSync/public acceptance before PASS. Missing or failed evidence blocks promotion even when workloads already serve traffic.

Keep Argo cluster watches namespace-scoped when Kubernetes permissions are namespace-scoped. Its AppProject must permit observing Pod/ReplicaSet/ControllerRevision descendants for hook UID/log evidence; Kubernetes RBAC can still deny creating them directly. CI receives only an Argo observer credential, never a Kubernetes writer. See the repository’s docs/devops/ for operational mappings and bootstrap overrides.

Rollback

Commit the previously verified chart/configuration/digests to the environment GitOps branch with a normal push and a current-HEAD check. Argo must complete a full sync with new PostSync evidence and public acceptance. Do not force-push or substitute selective sync. Migrations are forward-only; reverting images/configuration does not restore data. Database recovery needs an explicit backup and recovery-point decision. A configuration rollback drill does not prove image rollback or database restore.

Type to search…

↑↓ navigate↵ selectEsc close