services: # Lightweight proxy: gives Caddy the labels to route klz.localhost → host Mac klz-proxy: image: alpine:latest command: sleep infinity restart: unless-stopped networks: - infra labels: - "caddy=http://${TRAEFIK_HOST:-klz.localhost}" - "caddy.reverse_proxy=http://klz-app:3000" # Full Docker dev (use with `pnpm run dev:docker`) klz-app: build: context: . dockerfile: Dockerfile.dev working_dir: /app restart: unless-stopped networks: default: infra: aliases: - klz.localhost env_file: - ${ENV_FILE:-.env} environment: NODE_ENV: development # Force Garbage Collection before Docker kills the container (OOM) NODE_OPTIONS: "--max-old-space-size=6144" NEXT_TELEMETRY_DISABLED: "1" POSTGRES_URI: postgres://${PAYLOAD_DB_USER:-payload}:${PAYLOAD_DB_PASSWORD:-120in09oenaoinsd9iaidon}@klz-db:5432/${PAYLOAD_DB_NAME:-payload} PAYLOAD_SECRET: ${PAYLOAD_SECRET:-fallback-secret-for-dev} UV_THREADPOOL_SIZE: "1" RAYON_NUM_THREADS: "1" NEXT_PRIVATE_WORKER_THREADS: "false" NPM_TOKEN: ${NPM_TOKEN:-} CI: "true" QDRANT_URL: "http://klz-qdrant:6333" REDIS_URL: "redis://klz-redis:6379" MISTRAL_API_KEY: ${MISTRAL_API_KEY:-} OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-} volumes: - .:/app - klz_node_modules:/app/node_modules - klz_next_cache:/app/.next - klz_turbo_cache:/app/.turbo - klz_pnpm_store:/pnpm - /app/.git - /app/reference - /app/data deploy: resources: limits: memory: 8G command: > sh -c "pnpm install --no-frozen-lockfile && while true; do ( echo '[warmup] Waiting for Next.js to be reachable...' until curl -sf http://localhost:3000 > /dev/null; do sleep 2; done echo '[warmup] Server is up! Pre-compiling routes...' curl -sf http://localhost:3000/de > /dev/null 2>&1 && echo '[warmup] /de ready' curl -sf http://localhost:3000/api/health/cms > /dev/null 2>&1 && echo '[warmup] /api/health/cms ready' curl -sf -X POST -H 'Content-Type: application/json' -d '{\"messages\":[{\"role\":\"user\",\"content\":\"warmup\"}]}' http://localhost:3000/api/ai-search > /dev/null 2>&1 && echo '[warmup] /api/ai-search ready' echo '[warmup] Syncing CMS data to Qdrant...' SYNC_RESULT=$(curl -sf http://localhost:3000/api/sync-qdrant 2>&1) echo \"[warmup] Qdrant sync: $SYNC_RESULT\" echo '[warmup] All routes pre-compiled + Qdrant synced ✓' ) & pnpm next dev --webpack --hostname 0.0.0.0; echo '[klz-app] next dev exited, restarting in 2s...'; sleep 2; done" labels: - "traefik.enable=true" - "traefik.http.services.${PROJECT_NAME:-klz}-app-svc.loadbalancer.server.port=3000" - "traefik.docker.network=infra" klz-db: image: postgres:15-alpine restart: unless-stopped env_file: - ${ENV_FILE:-.env} environment: POSTGRES_DB: ${PAYLOAD_DB_NAME:-payload} POSTGRES_USER: ${PAYLOAD_DB_USER:-payload} POSTGRES_PASSWORD: ${PAYLOAD_DB_PASSWORD:-120in09oenaoinsd9iaidon} # Docker Desktop on Mac routes host connections via external IP, not 127.0.0.1. # Without this, pg_hba.conf rejects the connection as "no encryption". POSTGRES_HOST_AUTH_METHOD: trust volumes: - klz_db_data:/var/lib/postgresql/data networks: - default ports: - "54322:5432" klz-redis: image: redis:7-alpine restart: unless-stopped networks: - default ports: - "16379:6379" klz-qdrant: image: qdrant/qdrant:v1.13.2 restart: unless-stopped volumes: - klz_qdrant_data:/qdrant/storage networks: - default ports: - "16333:6333" networks: default: name: ${PROJECT_NAME:-klz-cables}-internal infra: external: true volumes: klz_db_data: external: false klz_qdrant_data: external: false klz_node_modules: klz_next_cache: klz_turbo_cache: klz_pnpm_store: