Monorepo Compose Layering¶
This document defines the Docker Compose conventions used across the monorepo.
uv Workspace Governance¶
The repository uses a single uv workspace for Python dependency management.
Rules:
- The root
pyproject.tomlis the workspace coordinator and owns shared repo tooling. - Workspace members are defined by
members = ["apps/*"]; every directory underapps/must include apyproject.toml. - Each app owns runtime dependencies in
apps/<name>/pyproject.toml. - Exactly one tracked lockfile is allowed at the root:
uv.lock. - Other dependency-manager files are not allowed (
requirements*.txt,Pipfile,Pipfile.lock,poetry.lock).
Execution conventions:
- Prefer running project commands from the repo root with
uv run --project apps/<name> .... - If running inside a project directory, use
uv run --project . .... - CI and automation must use frozen/locked resolution (
--frozenorUV_FROZEN=true).
Goals¶
- Keep one canonical definition per service.
- Separate base service definitions from environment-specific behavior.
- Make local development, devcontainer startup, and CI stacks composable from the same files.
File Roles¶
infra/docker/compose/compose.yaml- Base shell only.
- Declares shared project-level settings like compose project name and shared networks.
infra/docker/compose/apps/*.yaml- App-specific compose fragments.
- One file per app where practical (for example
api.yaml).
infra/docker/compose/services/*.yaml- Canonical infrastructure service fragments.
- One file per service where practical (for example
postgres.yaml,redis.yaml,docs.yaml). - Should contain stable defaults for that service.
infra/docker/compose/compose.dev.yaml- Local development overlay.
- Contains development-only behavior such as bind mounts, local command overrides, and local environment wiring.
Layering Order¶
Always layer compose files in this order:
- Base shell (
compose.yaml) - App and service fragments (
apps/*.yamlandservices/*.yaml) - Environment overlay (
compose.dev.yaml, or other overlays)
Example local stack:
docker compose \
-f infra/docker/compose/compose.yaml \
-f infra/docker/compose/apps/api.yaml \
-f infra/docker/compose/services/postgres.yaml \
-f infra/docker/compose/services/redis.yaml \
-f infra/docker/compose/compose.dev.yaml \
up --build
Conventions¶
- Do not duplicate a service definition across multiple files.
- Put environment-specific overrides in overlays instead of creating duplicated service variants.
- If
compose.dev.yamladdsdepends_onor environment variables that reference dependencies, include the matching service fragments in the compose invocation. - Keep service fragments reusable by devcontainer, CLI workflows, and CI workflows.
Devcontainer Alignment¶
Project devcontainers should follow the same layering model and include only the fragments they require.
For apps/api, the stack includes:
compose.yamlapps/api.yamlservices/docs.yamlservices/postgres.yamlservices/redis.yamlcompose.dev.yaml
Validation¶
Validate merged compose files before committing:
The repository helper target also validates common combinations: