3
3.1
Create PDF Generation API Route
ready-for-dev
2025-12-01
BMAD Story Context Workflow
docs/sprint-artifacts/3-1-create-pdf-generation-api-route.md
system
a server endpoint that generates PDF from the resume page
users get consistent, high-quality PDF output
- Create API route file at server/api/resume/pdf.get.ts
- Implement Puppeteer PDF generation
- Add error handling with timeout
- Configure for Vercel deployment
- Test API endpoint
Given a GET request to /api/resume/pdf, when the server processes the request, then it returns a PDF binary with Content-Type application/pdf
Response includes Content-Disposition: attachment; filename="Ali_Arghyani_Resume.pdf"
PDF matches the web preview exactly (WYSIWYG)
PDF text is selectable and copy-able (ATS-compatible)
PDF is A4 format (210mm × 297mm)
PDF generation completes in under 3 seconds
Given an error occurs, when caught, then it returns status 500 with JSON error message
Timeout is set to 10 seconds max
docs/architecture.md
Resume Export Feature - Architecture Document
GET /api/resume/pdf returns PDF binary with Content-Type: application/pdf and Content-Disposition header
docs/architecture.md
Resume Export Feature - Architecture Document
Novel Pattern: WYSIWYG PDF Export
Puppeteer navigates to /resume?print=true, waits for networkidle0, generates PDF with format A4 and printBackground true
docs/architecture.md
Resume Export Feature - Architecture Document
Use puppeteer-core + @sparticuz/chromium for Vercel serverless. Memory: 1024MB, maxDuration: 10s
docs/sprint-artifacts/tech-spec-epic-3.md
Epic Technical Specification: PDF Export
GET /api/resume/pdf - Success returns PDF buffer, Error returns 500 with JSON { error, message }
app/pages/resume.vue
Resume page that will be captured by Puppeteer. Supports ?print=true query param.
isPrintMode computed property
app/composables/useResumeData.ts
Provides getPdfFilename() for generating filename
getPdfFilename()
- File location must be server/api/resume/pdf.get.ts (Nuxt server route convention)
- Must use defineEventHandler from Nuxt
- Must detect environment for puppeteer vs puppeteer-core selection
- Must navigate to /resume?print=true (not /resume)
- Must wait for networkidle0 before PDF generation
- Must close browser in finally block to prevent memory leaks
- Timeout must be 10 seconds max
- Memory limit 1024MB on Vercel
defineEventHandler
Nuxt server utility
defineEventHandler(async (event) => { ... })
nitro/runtime
setResponseHeaders
Nuxt server utility
setResponseHeaders(event, { 'Content-Type': string, 'Content-Disposition': string })
h3
getRequestURL
Nuxt server utility
getRequestURL(event): URL
h3
puppeteer.launch
Puppeteer API
puppeteer.launch({ headless: boolean, args?: string[], executablePath?: string }): Promise<Browser>
puppeteer or puppeteer-core
page.pdf
Puppeteer API
page.pdf({ format: 'A4', printBackground: boolean, margin?: object }): Promise<Buffer>
puppeteer
Nuxt server route testing. Test API response headers and PDF content.
server/api/**/*.spec.ts, tests/
Request /api/resume/pdf, verify Content-Type is application/pdf
Verify Content-Disposition header contains correct filename
Open generated PDF, compare visually to web preview
Open PDF in reader, try to select and copy text
Check PDF page dimensions are A4 (210mm × 297mm)
Measure time from request to response, verify under 3 seconds
Simulate error, verify 500 status and JSON response
Verify timeout configuration in code