Skip to content
← All projects

Case study · Live

CV as code

My CV lives in one YAML file. A build renders the web version and an ATS-friendly PDF, and GitHub Actions deploys both to Cloudflare Pages. This site reads the same file.

Role
Personal
Status
Live
Links
cv.nguyendinhkha.com

Problem

A CV kept as a Word file, a PDF, a web page and a portfolio drifts: one gets updated and the others don't. Exporting a clean, ATS-friendly PDF by hand after every change is slow and easy to get wrong.

Approach

  1. 01

    One source of truth. The whole CV lives in cv.yaml in the cv repo. Nothing else is edited by hand.

  2. 02

    TypeScript renders it to HTML with print CSS; Playwright prints the PDF, with real selectable text for ATS parsers, page-break rules that keep each project header with its content, and a clickable footer link.

  3. 03

    The build also writes cv.json, which this portfolio reads at build time, so experience and skills here always match the CV.

  4. 04

    GitHub Actions on Node 24 and pnpm type-checks, builds, checks the outputs and deploys to Cloudflare Pages with wrangler. Security headers and the /cv.pdf short link are generated at build.

  5. 05

    After a deploy, the workflow sends a cv-updated event to the portfolio repo so nguyendinhkha.com rebuilds too; a daily scheduled build is the fallback.

Result

One commit to cv.yaml updates cv.nguyendinhkha.com, the PDF and nguyendinhkha.com in a single pipeline run, with no manual export.

  • TypeScript
  • Playwright
  • GitHub Actions
  • Cloudflare Pages

Next

Case studynfascent →