version: "3.8" # PRODUCTION docker-compose # Only nginx is exposed to the host network. # Backend and frontend are internal services accessed via nginx reverse proxy. services: db: image: pgvector/pgvector:pg17 restart: always environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] interval: 10s timeout: 5s retries: 5 redis: image: redis:7-alpine restart: always command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru --requirepass ${REDIS_PASSWORD:-} healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 backend: build: context: ./backend dockerfile: Dockerfile restart: always env_file: - .env environment: - POSTGRES_SERVER=db - REDIS_URL=redis://:${REDIS_PASSWORD:-}@redis:6379/0 expose: - "8000" depends_on: db: condition: service_healthy redis: condition: service_healthy command: > sh -c "uv run alembic upgrade head && uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4" worker: build: context: ./backend dockerfile: Dockerfile restart: always env_file: - .env environment: - POSTGRES_SERVER=db - REDIS_URL=redis://:${REDIS_PASSWORD:-}@redis:6379/0 depends_on: db: condition: service_healthy redis: condition: service_healthy command: uv run celery -A app.worker.celery_config.celery_app worker --loglevel=warning --concurrency=2 beat: build: context: ./backend dockerfile: Dockerfile restart: always env_file: - .env environment: - POSTGRES_SERVER=db - REDIS_URL=redis://:${REDIS_PASSWORD:-}@redis:6379/0 depends_on: db: condition: service_healthy redis: condition: service_healthy command: uv run celery -A app.worker.celery_config.celery_app beat --loglevel=warning frontend: build: context: ./frontend dockerfile: Dockerfile restart: always environment: # Empty = same-origin. Browser calls /api/v1 which nginx proxies to backend. - NEXT_PUBLIC_API_URL= expose: - "3000" depends_on: - backend nginx: image: nginx:alpine restart: always ports: - "80:80" - "443:443" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro depends_on: - frontend - backend volumes: postgres_data: