services: postgres: image: postgres:16-alpine container_name: vidreview-db environment: POSTGRES_USER: vidreview POSTGRES_PASSWORD: vidreview123 POSTGRES_DB: vidreview ports: - '5432:5432' volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ['CMD-SHELL', 'pg_isready -U vidreview'] interval: 5s timeout: 5s retries: 5 api: build: context: . dockerfile: Dockerfile.api container_name: vidreview-api environment: DATABASE_URL: postgresql://vidreview:vidreview123@postgres:5432/vidreview JWT_SECRET: ${JWT_SECRET:-change-me-in-production} JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d} API_PORT: 3001 NODE_ENV: production UPLOAD_DIR: /app/uploads MAX_FILE_SIZE_MB: 500 ALLOWED_ORIGINS: '*' ports: - '3001:3001' depends_on: postgres: condition: service_healthy volumes: - uploads:/app/uploads healthcheck: test: ['CMD-SHELL', 'wget -qO- http://localhost:3001/health || exit 1'] interval: 10s timeout: 5s retries: 5 # ── Transcode Worker ────────────────────────────────────────────────────── # Standalone Node.js process that polls the DB for pending transcode jobs. # Runs FFmpeg off the main API thread — uploads never block. worker: build: context: . dockerfile: Dockerfile.api container_name: vidreview-worker command: node src/worker/index.js environment: DATABASE_URL: postgresql://vidreview:vidreview123@postgres:5432/vidreview NODE_ENV: production UPLOAD_DIR: /app/uploads POLL_INTERVAL_MS: 2000 depends_on: postgres: condition: service_healthy volumes: - uploads:/app/uploads restart: unless-stopped frontend: build: context: . dockerfile: Dockerfile.frontend container_name: vidreview-frontend environment: NEXT_PUBLIC_API_URL: http://api:3001 NODE_ENV: production ports: - '3000:3000' depends_on: api: condition: service_healthy volumes: postgres_data: uploads: