version: "3.9" services: db: image: timescale/timescaledb:latest-pg16 container_name: milevault_db restart: unless-stopped environment: POSTGRES_DB: milevault POSTGRES_USER: ${DB_USER:-milevault} POSTGRES_PASSWORD: ${DB_PASSWORD:-milevault} volumes: - db_data:/var/lib/postgresql/data - ./docker/init.sql:/docker-entrypoint-initdb.d/init.sql:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-milevault} -d milevault"] interval: 10s timeout: 5s retries: 10 start_period: 30s redis: image: redis:7-alpine container_name: milevault_redis restart: unless-stopped command: redis-server --requirepass ${REDIS_PASSWORD:-milevault} volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-milevault}", "ping"] interval: 10s timeout: 5s retries: 5 start_period: 10s backend: build: context: ./backend dockerfile: Dockerfile container_name: milevault_backend restart: unless-stopped environment: DATABASE_URL: postgresql+asyncpg://${DB_USER:-milevault}:${DB_PASSWORD:-milevault}@db:5432/milevault REDIS_URL: redis://:${REDIS_PASSWORD:-milevault}@redis:6379/0 SECRET_KEY: ${SECRET_KEY:-changeme_please_set_in_env_file_32chars} ADMIN_USERNAME: ${ADMIN_USERNAME:-admin} ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin} POCKETID_ISSUER: ${POCKETID_ISSUER:-} POCKETID_CLIENT_ID: ${POCKETID_CLIENT_ID:-} POCKETID_CLIENT_SECRET: ${POCKETID_CLIENT_SECRET:-} FILE_STORE_PATH: /data/files ENVIRONMENT: ${ENVIRONMENT:-production} volumes: - file_data:/data/files depends_on: db: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 15s timeout: 5s retries: 10 start_period: 30s worker: build: context: ./backend dockerfile: Dockerfile.worker container_name: milevault_worker restart: unless-stopped environment: DATABASE_URL: postgresql+asyncpg://${DB_USER:-milevault}:${DB_PASSWORD:-milevault}@db:5432/milevault REDIS_URL: redis://:${REDIS_PASSWORD:-milevault}@redis:6379/0 SECRET_KEY: ${SECRET_KEY:-changeme_please_set_in_env_file_32chars} FILE_STORE_PATH: /data/files volumes: - file_data:/data/files depends_on: db: condition: service_healthy redis: condition: service_healthy frontend: build: context: ./frontend dockerfile: Dockerfile args: VITE_API_URL: ${VITE_API_URL:-/api} VITE_MAPBOX_TOKEN: ${VITE_MAPBOX_TOKEN:-} container_name: milevault_frontend restart: unless-stopped nginx: image: nginx:alpine container_name: milevault_nginx restart: unless-stopped ports: - "${HTTP_PORT:-80}:80" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro depends_on: - backend - frontend volumes: db_data: redis_data: file_data: