version: '3.9' services: # ─── PostgreSQL ───────────────────────────────────────── db: image: postgres:16-alpine container_name: coastal-db restart: unless-stopped environment: POSTGRES_USER: coastal POSTGRES_PASSWORD: ${DB_PASSWORD:-coastal_secret} POSTGRES_DB: coastal_timesheet volumes: - pgdata:/var/lib/postgresql/data ports: - '127.0.0.1:5432:5432' healthcheck: test: ['CMD-SHELL', 'pg_isready -U coastal -d coastal_timesheet'] interval: 10s timeout: 5s retries: 5 start_period: 10s networks: - coastal # ─── Backend API ──────────────────────────────────────── backend: build: context: ../ dockerfile: docker/backend/Dockerfile container_name: coastal-backend restart: unless-stopped depends_on: db: condition: service_healthy environment: DATABASE_URL: postgresql://coastal:${DB_PASSWORD:-coastal_secret}@db:5432/coastal_timesheet JWT_SECRET: ${JWT_SECRET:-change-me-in-production-jwt-secret-2026} JWT_REFRESH_SECRET: ${JWT_REFRESH_SECRET:-change-me-in-production-refresh-secret-2026} PORT: '3001' NODE_ENV: ${NODE_ENV:-production} CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost,http://localhost:3000,http://100.94.106.120:8080} SMTP_HOST: ${SMTP_HOST:-} SMTP_PORT: ${SMTP_PORT:-587} SMTP_USER: ${SMTP_USER:-} SMTP_PASS: ${SMTP_PASS:-} SMTP_FROM: ${SMTP_FROM:-} ADMIN_EMAIL: ${ADMIN_EMAIL:-bizzle@coastalcontracting.com} ports: - '127.0.0.1:3001:3001' healthcheck: test: ['CMD', 'node', '-e', "fetch('http://localhost:3001/api/health').then(r=>{if(!r.ok)throw 1}).catch(()=>process.exit(1))"] interval: 15s timeout: 5s retries: 3 start_period: 30s networks: - coastal # ─── Frontend (Nginx) ────────────────────────────────── frontend: build: context: ../ dockerfile: docker/frontend/Dockerfile container_name: coastal-frontend restart: unless-stopped depends_on: backend: condition: service_healthy ports: - '100.94.106.120:8080:80' volumes: - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro healthcheck: test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:80/'] interval: 15s timeout: 5s retries: 3 start_period: 10s networks: - coastal volumes: pgdata: driver: local networks: coastal: driver: bridge