services: # ─── PostgreSQL with pgvector ─────────────────────────── db: image: pgvector/pgvector:pg17 restart: unless-stopped environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: hp_prod_tracker ports: - "5432:5432" volumes: - pgdata:/var/lib/postgresql/data - ./docker/db-init.sql:/docker-entrypoint-initdb.d/01-pgvector.sql:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 5s retries: 5 # ─── Ollama (local AI — embeddings + chat fallback) ──── ollama: image: ollama/ollama:latest restart: unless-stopped entrypoint: ["/bin/bash", "/entrypoint.sh"] ports: - "11434:11434" volumes: - ollama_data:/root/.ollama - ./docker/ollama-entrypoint.sh:/entrypoint.sh:ro healthcheck: test: ["CMD-SHELL", "curl -sf http://localhost:11434/api/tags || exit 1"] interval: 10s timeout: 5s retries: 12 start_period: 30s # Uncomment for GPU acceleration (requires nvidia-container-toolkit): # deploy: # resources: # reservations: # devices: # - driver: nvidia # count: 1 # capabilities: [gpu] # ─── Next.js app (production) ────────────────────────── app: build: context: . dockerfile: Dockerfile restart: unless-stopped ports: - "3000:3000" environment: DATABASE_URL: postgresql://postgres:postgres@db:5432/hp_prod_tracker?schema=public OLLAMA_HOST: http://ollama:11434 OLLAMA_EMBED_MODEL: nomic-embed-text OLLAMA_LLM_MODEL: qwen3:1.7b NODE_ENV: production AUTH_SECRET: ${AUTH_SECRET} AUTH_TRUST_HOST: "true" AUTH_MICROSOFT_ENTRA_ID_ID: ${AUTH_MICROSOFT_ENTRA_ID_ID} AUTH_MICROSOFT_ENTRA_ID_SECRET: ${AUTH_MICROSOFT_ENTRA_ID_SECRET} AUTH_MICROSOFT_ENTRA_ID_TENANT_ID: ${AUTH_MICROSOFT_ENTRA_ID_TENANT_ID} CRON_SECRET: ${CRON_SECRET:-change-me} volumes: - uploads_data:/data/uploads depends_on: db: condition: service_healthy ollama: condition: service_healthy healthcheck: test: ["CMD-SHELL", "wget -q --spider http://localhost:3000/api/health || exit 1"] interval: 15s timeout: 5s retries: 3 start_period: 30s profiles: - production # ─── Cloudflare Tunnel (HTTPS access without port forwarding) ── tunnel: image: cloudflare/cloudflared:latest restart: unless-stopped command: tunnel run environment: TUNNEL_TOKEN: ${CLOUDFLARE_TUNNEL_TOKEN} depends_on: app: condition: service_healthy profiles: - production volumes: pgdata: ollama_data: uploads_data: