TheDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/CristianParadaLopez/cv-builder/llms.txt
Use this file to discover all available pages before exploring further.
handleDownloadPDF controller function is implemented in backend/src/controllers/cv.controller.ts and uses headless Chromium via Playwright to convert a CV HTML document into a print-quality A4 PDF. However, this function is not currently registered in backend/src/routes/cv.routes.ts, which means calling POST /api/cv/pdf against the running server will return a 404. The three routes that are registered are /generate, /edit, and /suggest.
What the controller does
handleDownloadPDF accepts a JSON body containing a html string, launches a headless Chromium browser using Playwright, loads the HTML, waits for fonts and styles to settle, generates a PDF in memory, and streams it back to the client as a binary file download. The browser is always closed in a finally block regardless of whether the PDF generation succeeds or fails.
The complete implementation from cv.controller.ts:
How to register the route (self-hosting)
To enable the/api/cv/pdf endpoint, import handleDownloadPDF in cv.routes.ts and add a router.post call:
POST /api/cv/pdf.
Expected request (once registered)
Method:POSTPath:
/api/cv/pdfContent-Type:
application/json
| Field | Type | Required | Description |
|---|---|---|---|
html | string | Yes | The complete HTML document to render. Must be a non-empty string. Pass the html value returned by /api/cv/generate or /api/cv/edit. |
Expected response (once registered)
Status:200 OK
| Header | Value |
|---|---|
Content-Type | application/pdf |
Content-Disposition | attachment; filename="mi-cv-skillara.pdf" |
Content-Length | Byte length of the PDF buffer |
--output in curl or call response.blob() in the browser to capture it.
Expected error responses (once registered)
| Status | Condition |
|---|---|
400 | html is missing or not a string |
500 | Playwright failed to launch Chromium, or the page render timed out |
500 are returned as JSON even though the success response is binary:
Example curl (once registered)
Frontend usage reference
The Skillara React frontend includes adownloadPDF function in frontend/src/pages/services/api.ts that targets this endpoint. This client-side code exists and calls POST /api/cv/pdf, but the call will fail with a 404 until the route is registered on the backend:
PDF generation behavior
Once the route is registered, the controller follows these steps:- Validates input — returns
400immediately ifhtmlis missing or not a string. - Launches headless Chromium via
chromium.launch({ headless: true }). - Loads the HTML with
page.setContent(html, { waitUntil: "networkidle", timeout: 15000 }). Thenetworkidlecondition ensures all inline resources have settled before rendering begins. - Waits 1200 ms for web fonts and CSS animations to finish painting.
- Generates the PDF with
format: "A4",printBackground: true, zero margins, andpreferCSSPageSize: trueto respect@pagerules embedded in the HTML’s<style>block. - Streams the buffer back to the client and closes the browser in the
finallyblock.
Enabling this endpoint requires Playwright and Chromium to be installed on the server. Run
npx playwright install chromium during backend setup. On Render or similar cloud platforms, add this command to your build script or use a Docker image that includes Chromium.The
networkidle wait combined with the 1200 ms font delay means each PDF request can take 3–8 seconds on cold hardware. Consider adding rate limiting before exposing this endpoint publicly.