§ 08 — Infrastructure

Two compose files, one Helm chart.

Local dev runs on Docker Compose, split into a worker stack (Postgres, Redis, API, MCP) and a Langfuse stack (web, ClickHouse, MinIO, its own Postgres + Redis). Production is a single Helm chart with ~30 templates deployed to AKS.

Two compose files — why

The Langfuse stack is heavy. Splitting it out has two reasons:

The worker stack

backend/docker-compose.yml — services on the worker network:

agenticit-postgres
Postgres 16-alpine. Host port ${POSTGRES_HOST_PORT:-5433}:5432. Volume pgdata. Healthcheck via pg_isready.
agenticit-redis
Redis 7-alpine. Internal only — no host port.
agenticit-api
Built from backend/Dockerfile. Host port ${API_HOST_PORT:-8000}:8000. ~200 env vars (LLM, OAuth, MCP entries, Langfuse, feature flags). Volume appdata:/data. Joined to default + langfuse-net.
mcp-service
Built from ../mcp-service/backend/Dockerfile.mcp. Host port ${MCP_HOST_PORT:-8001}:8001. Health endpoint /health with 90 s startup grace. Reads same Postgres for token store.

The Langfuse stack

backend/docker-compose.langfuse.yml

Network: langfuse-net. The worker stack joins it as external: true; setup-worker.sh creates the network if it doesn't exist so workers don't fail when Langfuse isn't running.

Override files

Local secrets live in backend/docker-compose.override.yml — gitignored. Provides the required env vars for Postgres credentials, JWT signing, OpenRouter, OAuth, token encryption, Tavily, and optional Langfuse keys. Full reference: §10·Env vars →.

Migration check

If backend/docker-compose.override.yml contains Langfuse service entries (langfuse-web, langfuse-clickhouse, …) it is in the old single-file format and must be split. See docs/guides/docker-compose-migration.md.

Configuration sources & precedence

  1. OS env vars — highest priority. Read after AddEnvironmentVariables().
  2. .env file — loaded by EnvironmentVariableMapper.LoadDotEnvFile() only if not already in OS env (no overwrite).
  3. Python-style flat env varsEnvironmentVariableMapper.AddPythonEnvVars() maps flat OPENROUTER_API_KEY to hierarchical Llm:AuthToken via a static map.
  4. appsettings.json — fallback defaults loaded by ASP.NET.

The flat-env-var convention means Docker / Kubernetes / shell exports all use the same keys. The hierarchical mapping happens once, in code, in one place.

Where to dive