dorfteich/deploy/compose/compose.dev.yml
Claude Fable 5 db4f517e44
All checks were successful
CI / Lint, typecheck, test (pull_request) Successful in 5m32s
CI / Build container images (pull_request) Successful in 1m13s
CI / Auth e2e pack (pull_request) Successful in 8m22s
CI / Import/export fidelity gate (pull_request) Successful in 57s
CD / Build and push images (push) Successful in 16s
CD / Deploy to Test (push) Successful in 56s
CD / Smoke tests against Test (push) Successful in 1m24s
CD / Promote to Int (push) Successful in 52s
CI / Lint, typecheck, test (push) Successful in 5m36s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Successful in 8m3s
CI / Import/export fidelity gate (push) Successful in 57s
#203: pin all third-party deploy images by digest
The four third-party images in the deploy compose (postgres, pandoc,
gotenberg — previously a floating MAJOR tag —, caddy) are now
name:tag@sha256 pins; the tag stays for readability, the digest decides
what runs. The pinned digests are exactly what the stages already run
(verified against the live containers' RepoDigests on ONE), so the next
recreation is byte-identical. A new early CI step fails on any
third-party compose image without a digest; compose.dev.yml is a local
convenience and deliberately exempt (its node helpers now follow the
#236 pin). Update + rollout procedure in deploy/stages.md — CD does not
sync stage composes, so the hand rollout to test/int/prod is part of
this issue's definition of done.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0168Ph5uBmHm8X28CSVpbpnJ
2026-07-31 05:13:13 +02:00

103 lines
3.8 KiB
YAML

# Development overlay: hot-reloading web and api containers with the
# repository mounted, layered over the production stack definition.
#
# Full containerized dev environment (first start installs dependencies):
# cd deploy/compose && cp .env.example .env
# docker compose -f docker-compose.yml -f compose.dev.yml up
# → web http://localhost:5173, api http://localhost:3001, db localhost:5434
#
# Database-only (run web/api natively for the fastest feedback):
# docker compose -f docker-compose.yml -f compose.dev.yml up -d db
# DATABASE_URL=postgresql://dorfteich:dorfteich@localhost:5434/dorfteich \
# PORT=3001 pnpm --filter @dorfteich/api start:dev
# pnpm --filter @dorfteich/web dev
services:
web:
image: node:22.15.1-alpine
build: !reset null
working_dir: /repo
command: sh -c "npm i -g pnpm@11 && pnpm install && pnpm --filter @dorfteich/web dev -- --host 0.0.0.0"
environment:
VITE_API_PROXY_TARGET: http://api:3000
ports: !override
- '127.0.0.1:5173:5173'
volumes:
- ../..:/repo
# Container-local node_modules: the host directories contain
# macOS binaries and must not leak into the Linux containers.
- web-root-modules:/repo/node_modules
- web-app-modules:/repo/apps/web/node_modules
- shared-modules:/repo/packages/shared/node_modules
- pnpm-store:/root/.local/share/pnpm/store
depends_on: !reset []
api:
image: node:22.15.1-alpine
build: !reset null
working_dir: /repo
command: sh -c "npm i -g pnpm@11 && pnpm install && pnpm --filter @dorfteich/shared build && pnpm --filter @dorfteich/api start:dev"
environment:
NODE_ENV: development
PORT: '3000'
DATABASE_URL: postgresql://dorfteich:${POSTGRES_PASSWORD:-dorfteich}@db:5432/dorfteich
# Dev default; overrides the base stack's required form (issue #34).
COLLAB_TOKEN_SECRET: ${COLLAB_TOKEN_SECRET:-dev-insecure-collab-token-secret-change-me}
ports: !override
- '127.0.0.1:3001:3000'
volumes:
- ../..:/repo
- api-root-modules:/repo/node_modules
- api-app-modules:/repo/apps/api/node_modules
- api-shared-modules:/repo/packages/shared/node_modules
- pnpm-store:/root/.local/share/pnpm/store
collab:
image: node:22.15.1-alpine
build: !reset null
working_dir: /repo
command: sh -c "npm i -g pnpm@11 && pnpm install && pnpm --filter @dorfteich/shared build && pnpm --filter @dorfteich/collab start:dev"
environment:
NODE_ENV: development
PORT: '3000'
DATABASE_URL: postgresql://dorfteich:${POSTGRES_PASSWORD:-dorfteich}@db:5432/dorfteich
# Must match the api dev default so tokens verify across the two services.
COLLAB_TOKEN_SECRET: ${COLLAB_TOKEN_SECRET:-dev-insecure-collab-token-secret-change-me}
ports: !override
- '127.0.0.1:3002:3000'
volumes:
- ../..:/repo
- collab-root-modules:/repo/node_modules
- collab-app-modules:/repo/apps/collab/node_modules
- collab-shared-modules:/repo/packages/shared/node_modules
- pnpm-store:/root/.local/share/pnpm/store
# No healthcheck block here: the production image's HEALTHCHECK does not
# apply to this node:alpine dev image, and nothing depends on it.
healthcheck: !reset null
db:
ports:
# 5434 on the host to avoid colliding with other local PostgreSQL
# instances (5432 system, 5433 wochenplan-staging).
- '127.0.0.1:5434:5432'
# Local SMTP catcher: UI on http://localhost:8025, SMTP on 1025 —
# matches the api's SMTP_* defaults.
mailpit:
image: axllent/mailpit:latest
ports:
- '127.0.0.1:1025:1025'
- '127.0.0.1:8025:8025'
volumes:
web-root-modules:
web-app-modules:
shared-modules:
api-root-modules:
api-app-modules:
api-shared-modules:
collab-root-modules:
collab-app-modules:
collab-shared-modules:
pnpm-store: