# PdfService Renders a PPMS purchase order to a real **PDF** for the **"Email PO to vendor"** feature — a standalone **Express + Playwright** microservice, mirroring `GstService` / `EpfoService`. The app's `/api/po/:id/export?format=pdf&pdf=1` produces a print-styled HTML page; PdfService loads that URL in **headless Chromium** and prints it to an A4 PDF. The export URL carries a short-lived **`svc` token** so the export route serves the page without a user session (the app's auth middleware allows that one route through when the token matches — see `App/lib/pdf-export-auth.ts`). ## Endpoints | Method | Path | Body / Headers | Returns | |---|---|---|---| | GET | `/health` | — | `{ status, browser }` | | POST | `/pdf` | `{ url }` + header `x-pdf-token` | `application/pdf` (else `401` / `400` / `403` / `502`) | ## Security - **Token** — when `PDF_SERVICE_TOKEN` is set, `/pdf` requires a matching `x-pdf-token` header (the app and PdfService share the secret). - **Origin allow-list (anti-SSRF)** — when `ALLOWED_ORIGIN` is set, PdfService only navigates to URLs whose origin matches it. - Both unset (dev) → checks are skipped. ## Env ``` PORT=3005 PDF_SERVICE_TOKEN= # shared secret with the app (app side: PDF_SERVICE_TOKEN) ALLOWED_ORIGIN= # e.g. http://localhost:3000 (optional) ``` ## Run ``` npm install npm run dev # tsx watch src/index.ts npm run build && npm start # node dist/index.js ``` ## App integration `App/lib/pdf-service.ts` (`renderPoPdf`) POSTs `{ url }` to `/pdf`. The app gates the feature on `PDF_SERVICE_URL` + `PDF_SERVICE_TOKEN` (`isPdfServiceConfigured()`), uploads the returned PDF to R2 at a **per-PO key** (reused across sends), and returns a `mailto:` with a 7-day presigned link. `APP_INTERNAL_URL` is the base URL PdfService reaches the app at (falls back to `NEXTAUTH_URL`). On **pms1** the service is auto-deployed on each release tag via the root `ecosystem.config.js` (pm2 `pdf-service`, port 3005) — see [Deployment and Operations](https://git.pelagiamarine.com/shad0w/pelagia-portal/wiki/Deployment-and-Operations#microservices).