Skip to main content

Production deployment

A production Fovea install is eight containers wired together by the docker-compose.yml at the repo root: Postgres, Redis, backend, model service, frontend, an OpenTelemetry collector, Prometheus, and Grafana. The last two are part of the default observability stack but can be omitted if you forward telemetry to a remote vendor instead. Everything comes from the same image set that CI publishes on every tagged release; nothing in docker-compose.yml is dev-only.

Prerequisites

  • A Linux host with at least 16 GB RAM. The default docker compose up stack runs the CPU model service (using models-cpu.yaml); GPU inference requires the --profile gpu override, which activates the model-service-gpu variant and selects models.yaml. CPU inference is roughly an order of magnitude slower per video than GPU.
  • Docker and Docker Compose v2.
  • A Postgres-reachable disk volume for persistent data. The default docker-compose.yml mounts a named volume; production installs typically bind a host path so backups are easy.
  • A strong value for SESSION_SECRET. The backend uses session-cookie auth and reads SESSION_SECRET at startup (server/src/app.ts); the compose default is a placeholder that must be overridden in production. The initial admin account is seeded from ADMIN_PASSWORD on first boot; subsequent accounts are minted through the registration form when ALLOW_REGISTRATION=true.

First-time setup

  1. Clone the repo on the host and check out the release tag you plan to run. Tags follow vMAJOR.MINOR.PATCH.
  2. Copy .env.example to .env and fill in the required variables listed in Reference / Environment variables. The variables that almost always need editing are SESSION_SECRET, ADMIN_PASSWORD, DATABASE_URL, STORAGE_PATH, and any external API keys (OPENAI_API_KEY, ANTHROPIC_API_KEY, HF_TOKEN).
  3. docker compose pull to fetch the image set for this tag.
  4. docker compose up -d to start the stack. The backend container's startup command runs prisma migrate deploy and node prisma/seed.cjs before starting the server, so migrations and the RBAC permission catalog are applied automatically on first boot (both steps are idempotent).
  5. Mint the first admin account either by setting ADMIN_PASSWORD in .env before step 4 (the seeder reads it and creates the initial admin) or by temporarily setting ALLOW_REGISTRATION=true and registering through the form.

What runs where

ContainerPort (internal)Purpose
frontend3000nginx serving the React build
backend3001Fastify API + BullMQ queue producers
model-service8000FastAPI inference service
postgres5432Application database
redis6379Queue broker for BullMQ
otel-collector4318OTLP HTTP endpoint for traces and metrics

The frontend container terminates HTTP. In a real deployment you typically front it with a reverse proxy (caddy, nginx, Traefik, an ALB) that holds the TLS certificate and forwards to the frontend container on port 3000. The reverse proxy is the right place to configure rate limits, IP allowlists, and the HSTS / CSP headers Fovea does not set itself.

What to expose

Only the reverse-proxied frontend port should be reachable from the public internet. The backend, model service, and Postgres ports are meant to be private. The OTel collector at 4318 accepts traces from both the backend and the model service; if you forward those to a remote vendor, do it through a private network, not the public internet.

Where data lives

  • Postgres holds every annotation, persona, ontology, world object, claim, summary, and user record. Lose it and you have lost the install's state.
  • The STORAGE_PATH volume holds uploaded videos. Losing it loses the videos but leaves all annotation metadata intact; annotations carry stable video IDs.
  • The model-cache named volume (mounted at /models via TRANSFORMERS_CACHE) holds downloaded model weights. Losing it costs one re-download per model at next use.
  • Redis holds in-flight job state. Losing it cancels any currently-running detection or summarization job; the user retries from the UI.

What to plan for