Most SaaS that produces "signed" PDF reports relies on a headless Chrome rendering an HTML page. That works until your Vercel cold-start blows past the function timeout, or the headless browser image weighs 800 MB and adds 30 seconds of boot per render. NANOTESTING ships report generation in a Node serverless function with zero browser dependencies.
The stack
@react-pdf/renderer- JSX in, PDF buffer out. Runs server-side in a Vercel Node function. No Chrome, no Puppeteer.- Built-in PDF Helvetica + Helvetica-Bold for typography. We started with Inter via jsdelivr but a Vercel-Fly network blip blew up every render; built-in fonts are mandated by the PDF spec and never require a fetch.
- SHA-256 fingerprint on the cover. Inputs:
scan_job_id | finding_count | generated_at[minute] | format_version. Auditors can recompute it. qrcodenpm package for the cover QR. Encodes a verify-this-scan URL. The QR survives a folded print.
The render pipeline
const buffer = await renderToBuffer(<ExecutiveDocument input={input} />);
That single call replaces the entire LaTeX or Chrome path. Output is a buffer we upload to a private Supabase storage bucket and serve via signed URL on download.
The four reports
One scan produces four PDFs from the same data:
- Executive - cover, severity strip, top-5 risks, "what changed since last scan" delta block, what the scanner actually ran.
- Developer remediation - per-finding patch guidance, code-level remediation notes.
- Compliance mapping - OWASP / ISO 27001 Annex A / SOC 2 TSC cross-walk.
- Trend - score over time, MTTR per finding, reopen rate.
Each carries its own sequential NT-REP-YYYY-NNNNNN number from a Postgres sequence + SECURITY DEFINER RPC, the same SHA-256 fingerprint format, and a public verify URL.
What we are NOT doing yet
PDF/A-3 archive format (ISO 19005-3) for enterprise long-term retention requires either pdftron's commercial library or post-render Ghostscript reprocessing. Both add cost and complexity. We will add it when a customer asks for it on a contract.
The whole render pipeline lives in src/lib/reports/. Sample one yourself at nanotesting.com/sample-report.