ADR-084: Full-Stack Docker Compose Topology (API, Viewer, Pipeline)¶
- Status: Accepted
- Date: 2026-05-08
- Authors: Podcast Scraper Team
- Related RFCs: RFC-079
Context & Problem Statement¶
The stack historically ran as separate laptop processes (make serve-api, Vite dev server, ad-hoc
pipeline). That hid production gaps: no Nginx-served Vue build, no single compose story for CI or
VPS deploys, and no shared volume contract between pipeline writers and API readers.
Decision¶
We adopt a three-service Docker Compose reference topology:
viewer— Nginx serves the production Vue build and reverse-proxies/api/*to the API.api— FastAPIpodcast servereads the corpus from a bind-mounted or named volume at/app/output(same layout as local runs), typically--no-staticbecause Nginx owns static assets.pipeline— One-shotdocker compose run(compose profile so it does not start onup); full ML image reusesdocker/pipeline/Dockerfile; writes into the samecorpus_datavolume as the API.
Single source compose file: compose/docker-compose.stack.yml (does not replace
compose/docker-compose.yml, which remains for standalone pipeline workflows).
Optional Docker job execution: When PODCAST_PIPELINE_EXEC_MODE=docker, the API’s job path
delegates to docker compose run against pipeline / pipeline-llm via a factory and
host Docker socket (merge file compose/docker-compose.jobs-docker.yml — see
docs/guides/DOCKER_SERVICE_GUIDE.md). Native subprocess jobs remain the default for local
laptop development.
Rationale¶
- Prod parity — VPS deploys use the same image set and volume semantics as CI and local
make stack-test-*. - Clear boundaries — Nginx never reads corpus files; API + pipeline share data; viewer is static with reverse-proxy only.
- No Kubernetes — Explicit non-goal at this scale; Compose is the orchestration ceiling.
Alternatives Considered¶
- Single mega-container — Rejected; couples API ML deps with pipeline image bloat and slows iteration.
- API serves Vue static in-process everywhere — Rejected for this topology; Nginx matches TLS and caching expectations on tailnet / prod.
- Swarm or Nomad — Rejected for same footprint reasons as Kubernetes.
Consequences¶
- Positive: One
docker compose upstory for demos, CI, and operator docs. - Negative: Large
pipelineimage pulls; disk and CI time must be budgeted. - Neutral:
compose/docker-compose.prod.ymland hostdeploy.shlayer env-specific flags without changing the three-service shape.
Implementation Notes¶
- Paths:
compose/docker-compose.stack.yml,docker/api/Dockerfile,docker/viewer/Dockerfile,docker/pipeline/Dockerfile,compose/docker-compose.jobs-docker.yml - Docs:
docs/guides/DOCKER_SERVICE_GUIDE.md