services: postgres: image: postgres:17-alpine environment: POSTGRES_DB: docuvault POSTGRES_USER: postgres POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data - ./docker/postgres/initdb.d:/docker-entrypoint-initdb.d:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres -d docuvault"] interval: 10s timeout: 5s retries: 5 start_period: 10s minio: image: minio/minio:latest command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: ${MINIO_ROOT_USER} MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} # RESEARCH.md Finding 3, T-03-09: allow browser CORS preflight for direct PUT uploads. # Use FRONTEND_URL (plain string) not CORS_ORIGINS (pydantic JSON list format). MINIO_API_CORS_ALLOW_ORIGIN: ${FRONTEND_URL:-http://localhost:5173} MINIO_SERVER_URL: http://localhost:9000 ports: - "9000:9000" - "9001:9001" volumes: - minio_data:/data healthcheck: test: ["CMD", "mc", "ready", "local"] interval: 10s timeout: 5s retries: 5 start_period: 15s redis: image: redis:7-alpine command: redis-server --requirepass ${REDIS_PASSWORD} healthcheck: test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] interval: 10s timeout: 3s retries: 5 backend: build: ./backend ports: - "8000:8000" volumes: - ./backend:/app environment: - DATABASE_URL=${DATABASE_URL} - DATABASE_MIGRATE_URL=${DATABASE_MIGRATE_URL} - MINIO_ENDPOINT=${MINIO_ENDPOINT} - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY} - MINIO_SECRET_KEY=${MINIO_SECRET_KEY} - MINIO_BUCKET=${MINIO_BUCKET} - MINIO_PUBLIC_ENDPOINT=${MINIO_PUBLIC_ENDPOINT:-localhost:9000} - REDIS_URL=${REDIS_URL} - SECRET_KEY=${SECRET_KEY} - ADMIN_EMAIL=${ADMIN_EMAIL} - ADMIN_PASSWORD=${ADMIN_PASSWORD} - CORS_ORIGINS=${CORS_ORIGINS:-http://localhost:5173} - FRONTEND_URL=${FRONTEND_URL:-http://localhost:5173} - PYTHONDONTWRITEBYTECODE=1 extra_hosts: - "host.docker.internal:host-gateway" command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload depends_on: postgres: condition: service_healthy minio: condition: service_healthy redis: condition: service_healthy celery-worker: build: ./backend environment: - DATABASE_URL=${DATABASE_URL} - MINIO_ENDPOINT=${MINIO_ENDPOINT} - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY} - MINIO_SECRET_KEY=${MINIO_SECRET_KEY} - MINIO_BUCKET=${MINIO_BUCKET} - REDIS_URL=${REDIS_URL} - CLOUD_CREDS_KEY=${CLOUD_CREDS_KEY} - PYTHONDONTWRITEBYTECODE=1 volumes: - ./backend:/app extra_hosts: - "host.docker.internal:host-gateway" command: celery -A celery_app worker --loglevel=info -Q documents depends_on: postgres: condition: service_healthy minio: condition: service_healthy redis: condition: service_healthy celery-beat: build: ./backend environment: - DATABASE_URL=${DATABASE_URL} - MINIO_ENDPOINT=${MINIO_ENDPOINT} - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY} - MINIO_SECRET_KEY=${MINIO_SECRET_KEY} - MINIO_BUCKET=${MINIO_BUCKET} - REDIS_URL=${REDIS_URL} - PYTHONDONTWRITEBYTECODE=1 extra_hosts: - "host.docker.internal:host-gateway" command: celery -A celery_app beat --loglevel=info depends_on: postgres: condition: service_healthy minio: condition: service_healthy redis: condition: service_healthy frontend: build: ./frontend ports: - "5173:5173" volumes: - ./frontend/src:/app/src - ./frontend/index.html:/app/index.html depends_on: - backend command: npm run dev -- --host 0.0.0.0 volumes: postgres_data: minio_data: