# US08-03 — Compose the Runtime and Mount the Library Safely Epic: [E08](../E08-container-deployment.md) As an operator, I want a single compose file that runs the API and the worker against my real library, so a deployment is one command and the safety invariants survive it. ## Context The library process lock (US07-05) assumes both roles see the same lock file, and SQLite in WAL mode assumes a real local filesystem. Container path policy is the same problem as host path policy with a new failure mode: the configured library roots must name the in-container mount paths, not the host paths. ## Acceptance criteria - `docker-compose.yml` runs exactly one `serve` and one `worker` container from the same image and the same data volume, and a second worker is refused by the existing lock rather than by convention. - The library is a bind mount; `PHOTO_PIPELINE_LIBRARY_ROOTS` names the container-side paths, and a mismatch between mounted and configured roots fails at startup with a clear message instead of at the first write. - The data volume holds the database, WAL, thumbnail cache, and backups on a local filesystem; the composition documents that a network mount is unsupported for it. - Migrations run before `serve` and `worker` accept work, using the existing backup-then- migrate path, and an upgrade that fails leaves the previous database intact. - Configuration and secrets come from the environment, never from the image or a committed file; a `.env.example` lists every `PHOTO_PIPELINE_*` variable with safe defaults and no values. - The API port is published to host loopback by default; exposing it publicly requires the configured hostname and access secret from US08-01. - Containers restart automatically, and a restart mid-job resumes exactly as a host restart does today. - Backup, verify-backup, restore, and diagnostics are documented as container commands and work against the mounted volumes. ## Automated tests - An integration test brings the composition up against a temporary fixture library, runs a job, restarts both containers, and asserts the job resumes and the database is intact. - Tests for: second worker refused, library-root mismatch refused at startup, failed migration leaving the previous database restorable. ## Dependencies - US08-01, US08-02