# Deployment guide Architecture: **frontend → Vercel**, **backend → a Docker container host** (Render blueprint included). The two talk over HTTPS; the frontend proxies `/api/*` to the backend via a Next.js rewrite, so the browser only ever sees the Vercel origin. ``` Browser ──> Vercel (Next.js) ──/api/* rewrite──> Backend container (FastAPI + Docling) └── persistent disk /data └── models baked into image ``` Why the backend can't be serverless: it bundles Docling + (CPU) torch + ~850 MB of layout/table/OCR models and needs real RAM/disk. Plan for **2 GB minimum, 4 GB recommended**. --- ## 1. Backend → Render (recommended) The image bakes the models in, runs as non-root, exposes a health check, and binds `$PORT`. Everything is described in [`render.yaml`](../render.yaml). 1. **Push this repo to GitHub** (Render deploys from Git): ```bash git remote add origin https://github.com//document-agent.git git push -u origin main ``` 2. In the **Render dashboard → New → Blueprint**, select the repo. Render reads `render.yaml` and provisions a Docker web service + a 10 GB disk at `/data`. 3. When prompted, set the secret env vars: - `OPENAI_API_KEY` — your key - `GEMINI_API_KEY` — optional (leave blank to disable Gemini) 4. After the first deploy, note the URL (e.g. `https://document-agent-backend.onrender.com`) and verify: `GET /api/health` → `{"status":"ok", ...}`. 5. Set `CORS_ORIGINS` to your Vercel domain (see step 2 below) and redeploy. First build is slow (downloads torch + models). Subsequent deploys reuse layers. ### Free option — Hugging Face Spaces (no card required) Render's free plan is 512 MB RAM with no disk and can't run this image. **HF Spaces free CPU tier gives 16 GB RAM** and runs Docker, so it fits — the only loss is persistence (free Spaces have no disk, so uploads/DB reset on restart/rebuild). This repo ships an HF-ready **root `Dockerfile`** (builds the backend with the repo root as context, runs as UID 1000) and the HF config in the **`README.md` frontmatter** (`sdk: docker`, `app_port: 8000`). 1. Create a free account at https://huggingface.co, then **New → Space**: - **SDK: Docker** (blank template), name e.g. `document-agent`, visibility your choice. 2. Push this repo to the Space's git remote: ```bash git remote add space https://huggingface.co/spaces//document-agent git push space main # auth: HF username + an HF access token as password ``` (Create a write token at https://huggingface.co/settings/tokens.) 3. In the Space: **Settings → Variables and secrets**, add as **secrets**: - `OPENAI_API_KEY` (freshly rotated) and/or `GEMINI_API_KEY` - `DEFAULT_LLM_PROVIDER` (`openai` or `gemini`), `ENABLE_OCR` (`true`/`false`) 4. The Space builds (slow first time: torch + ~850 MB models). When live, the URL is `https://-document-agent.hf.space`; verify `GET /api/health`. 5. Use that URL as `NEXT_PUBLIC_API_BASE` on Vercel (step 2 below). > Tip: if free RAM is tight on large scans, set `ENABLE_OCR=false` to cut memory. ### Other alternatives - **Fly.io**: `fly launch` from `./backend` (it detects the Dockerfile), add a volume (`fly volumes create data`) mounted at `/data`, set secrets with `fly secrets set`. - **Railway**: new service from the Dockerfile, add a volume at `/data`, set the env vars. --- ## 2. Frontend → Vercel The frontend is already env-driven — it needs exactly one variable pointing at the backend. ```bash cd frontend vercel # first run: link/create the project # set the backend URL for all environments: vercel env add NEXT_PUBLIC_API_BASE # value: https://document-agent-backend.onrender.com (no trailing slash) vercel --prod # deploy ``` `NEXT_PUBLIC_API_BASE` drives the `/api/:path*` rewrite in [`next.config.mjs`](../frontend/next.config.mjs), so uploads, page images, exports and the chat stream all flow through the same origin — no CORS needed in the common case. > Streaming note: chat uses SSE through the Vercel rewrite. If a host buffers the > stream, switch to direct calls by setting `BASE = process.env.NEXT_PUBLIC_API_BASE` > in `frontend/lib/api.ts` and make sure `CORS_ORIGINS` on the backend lists the > Vercel domain. --- ## 3. Verify locally first (optional but recommended) Build and run the real production image before shipping: ```bash docker compose up --build # backend: http://localhost:8000/api/health ``` `docker-compose.yml` mounts a named volume at `/data` and reads `backend/.env`, so it mirrors production (persistent uploads + sqlite + rendered pages). --- ## Operational notes - **Persistence**: `/data` holds uploads, the SQLite DB, the numpy vector store and rendered page images. Keep it on a mounted disk/volume — without one, data resets on every deploy. - **Models**: baked into the image (not in `/data`), so they survive redeploys with no re-download. - **Secrets**: only ever via host env vars. `backend/.env` is git-ignored. - **Scaling**: state lives on local disk + SQLite, so run a **single instance**. To scale horizontally, move the DB to Postgres and the vector store to pgvector (`services/vectorstore.py` is a drop-in seam) and uploads to object storage. - **Cost guard**: the backend holds your LLM key behind a public URL. Consider adding auth or a rate limit before sharing widely.