services: # --- Redis --- redis: image: redis:7-alpine ports: - "6379:6379" volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 3s retries: 5 # --- PostgreSQL --- postgres: image: postgres:16-alpine ports: - "5432:5432" environment: - POSTGRES_DB=dociva - POSTGRES_USER=dociva - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-6x3PjV4ghRTQuZ3Q} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U dociva -d dociva"] interval: 10s timeout: 5s retries: 5 restart: unless-stopped # --- Flask Backend --- backend: build: context: ./backend dockerfile: Dockerfile ports: - "5000:5000" env_file: - .env environment: - FLASK_ENV=development - REDIS_URL=redis://redis:6379/0 - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/1 - DATABASE_URL=postgresql://dociva:${POSTGRES_PASSWORD:-6x3PjV4ghRTQuZ3Q}@postgres:5432/dociva volumes: - ./backend:/app - upload_data:/tmp/uploads - output_data:/tmp/outputs depends_on: redis: condition: service_healthy postgres: condition: service_healthy restart: unless-stopped # --- Celery Worker --- celery_worker: build: context: ./backend dockerfile: Dockerfile command: > celery -A celery_worker.celery worker --loglevel=info --concurrency=2 -Q default,convert,compress,image,video,pdf_tools,flowchart,ai_heavy env_file: - .env environment: - FLASK_ENV=development - REDIS_URL=redis://redis:6379/0 - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/1 - DATABASE_URL=postgresql://dociva:${POSTGRES_PASSWORD:-6x3PjV4ghRTQuZ3Q}@postgres:5432/dociva volumes: - ./backend:/app - upload_data:/tmp/uploads - output_data:/tmp/outputs depends_on: redis: condition: service_healthy postgres: condition: service_healthy healthcheck: test: ["CMD", "celery", "-A", "celery_worker.celery", "inspect", "ping"] interval: 30s timeout: 10s retries: 3 start_period: 30s restart: unless-stopped # --- Celery Beat (Scheduled Tasks) --- celery_beat: build: context: ./backend dockerfile: Dockerfile command: > celery -A celery_worker.celery beat --loglevel=info env_file: - .env environment: - FLASK_ENV=development - REDIS_URL=redis://redis:6379/0 - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/1 - DATABASE_URL=postgresql://dociva:${POSTGRES_PASSWORD:-6x3PjV4ghRTQuZ3Q}@postgres:5432/dociva volumes: - ./backend:/app depends_on: redis: condition: service_healthy postgres: condition: service_healthy restart: unless-stopped # --- React Frontend (Vite Dev) --- frontend: build: context: ./frontend dockerfile: Dockerfile target: development ports: - "5173:5173" volumes: - ./frontend:/app - /app/node_modules environment: - NODE_ENV=development - VITE_GA_MEASUREMENT_ID=${VITE_GA_MEASUREMENT_ID:-} - VITE_PLAUSIBLE_DOMAIN=${VITE_PLAUSIBLE_DOMAIN:-} - VITE_PLAUSIBLE_SRC=${VITE_PLAUSIBLE_SRC:-https://plausible.io/js/script.js} - VITE_GOOGLE_SITE_VERIFICATION=${VITE_GOOGLE_SITE_VERIFICATION:-} - VITE_ADSENSE_CLIENT_ID=${VITE_ADSENSE_CLIENT_ID:-} - VITE_ADSENSE_SLOT_HOME_TOP=${VITE_ADSENSE_SLOT_HOME_TOP:-} - VITE_ADSENSE_SLOT_HOME_BOTTOM=${VITE_ADSENSE_SLOT_HOME_BOTTOM:-} - VITE_ADSENSE_SLOT_TOP_BANNER=${VITE_ADSENSE_SLOT_TOP_BANNER:-} - VITE_ADSENSE_SLOT_BOTTOM_BANNER=${VITE_ADSENSE_SLOT_BOTTOM_BANNER:-} - VITE_FEATURE_EDITOR=${VITE_FEATURE_EDITOR:-true} - VITE_FEATURE_OCR=${VITE_FEATURE_OCR:-true} - VITE_FEATURE_REMOVEBG=${VITE_FEATURE_REMOVEBG:-true} - VITE_SITE_DOMAIN=${VITE_SITE_DOMAIN:-} - VITE_SENTRY_DSN=${VITE_SENTRY_DSN:-} # --- Nginx Reverse Proxy --- nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx/nginx.dev.conf:/etc/nginx/conf.d/default.conf:ro - ./certbot/conf:/etc/letsencrypt:ro - ./certbot/www:/var/www/certbot:ro depends_on: - backend - frontend restart: unless-stopped # --- Certbot (Let's Encrypt) --- certbot: image: certbot/certbot volumes: - ./certbot/www:/var/www/certbot - ./certbot/conf:/etc/letsencrypt volumes: redis_data: postgres_data: upload_data: output_data: