# Running on a server Each service is an OS process. Node 20 runs the backend, chat engine, and ingestion CLI. Python 3.13 runs the voice agent. The frontend is the Vite build in `frontend/dist`, served by the same web server that proxies `/api` to Hapi. MySQL, OpenSearch, Bedrock, Transcribe, Polly, and LiveKit stay the services named in each `.env`. The chat engine listens on `127.0.0.1:3001` and has no public origin. Browsers reach Hapi and the LiveKit URL only. ## Processes | Process | Directory | Command | | --- | --- | --- | | Backend | `backend/` | `node src/server.js` | | Chat engine | `chat-engine/` | `node src/cli.js serve` | | Voice agent | `ai_agent/` | `./venv/bin/python agent.py start` | | Ingestion | `ingestion/` | `node src/cli.js run --book-id ID --pdf PATH` | Example systemd units are in `deploy/systemd/`. Point `WorkingDirectory` and `EnvironmentFile` at the install path. Health checks: - backend: `GET /` - chat engine: `GET /health` and `GET /ready` - agent: the LiveKit worker log line that it registered If nginx or another proxy sits in front of Hapi, turn off response buffering for `/api/chat/` and `/api/public/` so server-sent events arrive as they are written (`proxy_buffering off` and `X-Accel-Buffering: no`, which the API already sets). The engine keeps an in-memory cache of at most 8 books. Extra engine processes do not share that cache. Run more agent workers as voice rooms grow. On SIGTERM the engine closes its HTTP server and the agent calls `/internal/sessions/:id/end` for the room it is in. IAM templates are in `deploy/iam/`.