name: app-pfm-ocr-v2-backend services: nginx: image: nginx:alpine container_name: paddleocr-nginx ports: - "${APP_PORT:-8000}:80" - "8001:8001" volumes: - ./backend/nginx.conf:/etc/nginx/nginx.conf:ro depends_on: - vllm-server - pipeline-api - pfm-web-app restart: unless-stopped vllm-server: build: context: ./backend target: vllm-server container_name: paddleocr-vllm-server image: paddleocr-vllm-server:latest environment: - GENAI_HOST=0.0.0.0 - GENAI_PORT=8118 - GENAI_MODEL=${GENAI_MODEL:-PaddleOCR-VL-1.6-0.9B} - GENAI_BACKEND=${GENAI_BACKEND:-vllm} - VLLM_CONFIG=${VLLM_CONFIG:-config/vllm_config.yaml} - CUDA_VISIBLE_DEVICES=${CUDA_VISIBLE_DEVICES:-0} - PADDLE_PDX_DISABLE_MODEL_SOURCE_CHECK=True deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] volumes: - hf_cache:/root/.cache/huggingface - paddle_cache:/root/.paddleocr - paddlex_cache:/root/.paddlex - ./backend/config:/app/config - ./backend/.env:/app/.env:ro restart: unless-stopped pipeline-api: build: context: ./backend target: pipeline-api container_name: paddleocr-pipeline-api image: paddleocr-pipeline-api:latest environment: - PIPELINE_CONFIG=${PIPELINE_CONFIG:-config/pipeline_config_vllm.yaml} - PIPELINE_HOST=0.0.0.0 - PIPELINE_PORT=8090 - PIPELINE_DEVICE=gpu:0 - CUDA_VISIBLE_DEVICES=${CUDA_VISIBLE_DEVICES:-0} - VLLM_SERVER_URL=http://paddleocr-pfm-web-app:3000/api/vllm-proxy/v1 - PADDLE_PDX_DISABLE_MODEL_SOURCE_CHECK=True deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] volumes: - paddle_cache:/root/.paddleocr - paddlex_cache:/root/.paddlex - ./backend/config:/app/config - ./backend/pfm-web-app/public/produk-pfm/models:/app/pfm-web-app/public/produk-pfm/models:ro - ./backend/.env:/app/.env:ro depends_on: - vllm-server healthcheck: test: ["CMD-SHELL", "curl -s http://localhost:8090/ > /dev/null || exit 1"] interval: 10s timeout: 5s retries: 5 restart: unless-stopped pfm-web-app: build: context: ./backend target: pfm-web-app container_name: paddleocr-pfm-web-app image: paddleocr-pfm-web-app:latest ports: - "3000:3000" command: npm run dev environment: - PIPELINE_URL=http://paddleocr-pipeline-api:8090/layout-parsing - CLASSIFIER_SERVER_URL=http://paddleocr-pipeline-api:8120/classify-ocr - NODE_ENV=development - PGHOST=paddleocr-db - PGPORT=5432 - PGUSER=postgres - PGPASSWORD=postgres - PGDATABASE=dopfm pid: "host" volumes: - ./backend/pfm-web-app:/app - /app/node_modules - /app/.next - ./backend/uploads:/uploads - ./backend/sources:/sources - /var/run/docker.sock:/var/run/docker.sock depends_on: pipeline-api: condition: service_healthy db: condition: service_healthy extra_hosts: - "host.docker.internal:host-gateway" restart: unless-stopped db: image: postgres:15-alpine container_name: paddleocr-db environment: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres - POSTGRES_DB=dopfm volumes: - pgdata:/var/lib/postgresql/data - ./backend/db/migrations:/docker-entrypoint-initdb.d:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres -d dopfm"] interval: 10s timeout: 5s retries: 5 restart: unless-stopped # ─── Dev Tunnel ──────────────────────────────────────────────────────────── # Exposes the app via Cloudflare Quick Tunnel — no account needed. # After startup, run: docker logs paddleocr-tunnel # Look for a line like: https://xxxx-xxxx.trycloudflare.com # Share that URL with Android devices on any network. tunnel: image: cloudflare/cloudflared:latest container_name: paddleocr-tunnel command: tunnel --no-autoupdate --url http://paddleocr-nginx:80 depends_on: - nginx restart: unless-stopped profiles: - tunnel # opt-in: start with docker compose --profile tunnel up volumes: hf_cache: name: paddleocr_hf_cache paddle_cache: name: paddleocr_paddle_cache paddlex_cache: name: paddleocr_paddlex_cache pgdata: name: paddleocr_pgdata