# Production Compose stack — one file for every stage and for self-hosters. # Configuration comes from .env (see .env.example); the host reverse proxy # routes to the two published localhost ports (deployment.md §Compose). # # Networks: `frontend` is what the reverse proxy reaches (via published # ports); `internal` connects api/collab to db and (later) the converter # sidecars, which are never exposed. name: ${COMPOSE_PROJECT_NAME:-dorfteich} x-logging: &logging logging: driver: json-file options: max-size: '10m' max-file: '5' services: web: image: ${IMAGE_PREFIX:-dorfteich}-web:${TAG:-latest} build: context: ../.. dockerfile: apps/web/Dockerfile args: APP_VERSION: ${TAG:-latest} restart: unless-stopped ports: - '127.0.0.1:${WEB_PORT:-8100}:8080' networks: [frontend] depends_on: api: condition: service_started <<: *logging api: image: ${IMAGE_PREFIX:-dorfteich}-api:${TAG:-latest} build: context: ../.. dockerfile: apps/api/Dockerfile args: APP_VERSION: ${TAG:-latest} restart: unless-stopped environment: NODE_ENV: production PORT: '3000' LOG_LEVEL: ${LOG_LEVEL:-info} DATABASE_URL: postgresql://dorfteich:${POSTGRES_PASSWORD:?set in .env}@db:5432/dorfteich ports: - '127.0.0.1:${API_PORT:-8101}:3000' networks: [frontend, internal] volumes: - uploads:/data/uploads depends_on: db: condition: service_healthy <<: *logging db: image: postgres:17.5-alpine restart: unless-stopped environment: POSTGRES_USER: dorfteich POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set in .env} POSTGRES_DB: dorfteich networks: [internal] volumes: - db-data:/var/lib/postgresql/data healthcheck: test: ['CMD-SHELL', 'pg_isready -U dorfteich -d dorfteich'] interval: 10s timeout: 3s retries: 12 <<: *logging networks: frontend: internal: volumes: db-data: uploads: