services: db: image: postgres:16-alpine restart: unless-stopped environment: POSTGRES_USER: taskmanager POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB:-taskmanager} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U taskmanager"] interval: 5s retries: 10 migrate: build: context: . target: operations env_file: ${TASKMANAGER_ENV_FILE:-.env} command: ["sh", "-c", "npx prisma migrate deploy && npx tsx scripts/migrate-access.ts && npx tsx scripts/migrate-uploads.ts && npx tsx prisma/seed.ts"] environment: UPLOAD_DIR: /app/private-uploads LEGACY_UPLOAD_DIR: /app/private-uploads volumes: - uploads:/app/private-uploads depends_on: db: condition: service_healthy app: init: true security_opt: ["no-new-privileges:true"] cap_drop: ["ALL"] read_only: true tmpfs: ["/tmp:rw,noexec,nosuid,size=64m"] build: context: . target: runner restart: unless-stopped env_file: ${TASKMANAGER_ENV_FILE:-.env} environment: UPLOAD_DIR: /app/private-uploads ports: - "127.0.0.1:3000:3000" volumes: - uploads:/app/private-uploads depends_on: migrate: condition: service_completed_successfully worker: init: true security_opt: ["no-new-privileges:true"] cap_drop: ["ALL"] build: context: . target: operations restart: unless-stopped user: "1001:1001" env_file: ${TASKMANAGER_ENV_FILE:-.env} environment: UPLOAD_DIR: /app/private-uploads WORKER_HEARTBEAT_FILE: /tmp/taskmanager-worker-heartbeat command: ["node", "--import", "tsx", "scripts/worker.ts"] # Used only for local health monitoring; contains no account or task data. healthcheck: test: ["CMD", "node", "-e", "const fs=require('fs');process.exit(Date.now()-fs.statSync('/tmp/taskmanager-worker-heartbeat').mtimeMs<180000?0:1)"] interval: 30s timeout: 5s start_period: 60s retries: 3 stop_grace_period: 30s volumes: - uploads:/app/private-uploads depends_on: app: condition: service_healthy volumes: postgres_data: uploads: