Handover: publishpipe CV Tool — 2026-04-13¶
Branch¶
claude/plan-cv-tool-sokBV on SvenRelijveld1995/portfolio
All work is committed and pushed. Working tree is clean.
What was built¶
A full pipeline that generates PDF CVs from Markdown source files using publishpipe (thesethtruth/publishpipe), covering:
| Layer | Description |
|---|---|
| Static build | cv/build.ts renders both English and Dutch CVs to cv/dist/ |
| Runtime API | GET /api/cv/generate?lang=english\|nederlands — feature-flag gated |
| Feature flag | ENABLE_CV_GENERATION=false env var; frontend polls /api/cv/status |
| Frontend | cv-download-dialog.tsx shows generate buttons only when flag is on |
| E2E tests | e2e/cv-download.spec.ts covers flag-off, flag-on, generate, download |
The existing static download flow (/api/download-cv, PDFs in client/public/)
is untouched — publishpipe is purely additive.
Key files¶
| File | Role |
|---|---|
cv/build.ts |
Build script (use this, not publishpipe CLI directly) |
cv/package.json |
Bun workspace; scripts call build.ts |
cv/content/english.md |
Static English CV source |
cv/content/dutch.md |
Static Dutch CV source |
cv/templates/english.md.j2 |
Jinja2 template for API runtime generation |
cv/templates/dutch.md.j2 |
Jinja2 template (Dutch) |
cv/dist/ |
Generated PDFs (gitignored output directory) |
api/main.py |
generate_cv endpoint + /api/cv/status + Jinja2 rendering |
client/src/components/cv-download-dialog.tsx |
Frontend dialog |
e2e/cv-download.spec.ts |
Playwright E2E tests |
Dockerfile.backend |
Multi-stage: bun-stage installs cv/node_modules |
.env.example |
Documents ENABLE_CV_GENERATION=false |
docs/planning/cv-generation.md |
Full 6-phase implementation plan |
How to build CVs locally¶
On Linux without internet, Playwright's bundled Chromium works:
build.ts automatically strips Google Fonts <link> elements and passes
--no-sandbox to Chromium — both are required in sandboxed/root environments.
Known issues fixed in this session¶
| Problem | Root cause | Fix |
|---|---|---|
| 18 pages (1 job per page) | --- in publishpipe markdown = forced page break |
Removed all --- between job entries |
| Duplicate header on page 1 | publishpipe renders frontmatter as header; body also had # Sven Relijveld h1 |
Removed h1 + bold contact line from markdown body |
| Chrome hangs indefinitely | waitForNetworkIdle never resolves; Google Fonts <link rel="preconnect"> creates pending connections |
build.ts strips those links before calling pagedjs-cli |
| Chrome crashes as root | pagedjs-cli doesn't pass --no-sandbox |
build.ts calls pagedjs-cli directly with --no-sandbox,--disable-setuid-sandbox |
Current PDF output¶
Both CVs render to 7 pages in ~120ms. Structure: header (from frontmatter) → Profile → Work Experience (13 entries) → Skills → Certifications → Awards & Recognition. No duplicate header. No spurious page breaks between jobs.
What still needs attention¶
1. Promote generated PDFs to client/public/¶
The E2E tests and /api/download-cv still serve the old hand-crafted PDFs from
client/public/. To replace them with publishpipe-generated ones:
Then update the filename references in api/main.py (STATIC_PDF_DIR) and
any hardcoded filenames in the frontend or E2E tests.
2. CI workflow¶
.github/workflows/generate-cv.yml exists but references npm run cv:generate
(old root package.json script). Update it to:
And set PUPPETEER_EXECUTABLE_PATH to the Chromium installed by the CI runner.
3. API runtime — Jinja2 templates need live data wiring check¶
The api/main.py renders cv/templates/english.md.j2 with experience, skills,
certifications, and awards fetched from the DB. Verify the Jinja2 output looks
correct end-to-end by enabling ENABLE_CV_GENERATION=true and hitting
GET /api/cv/generate?lang=english against a running instance with seeded data.
4. Dutch content review¶
The Dutch cv/content/dutch.md was restructured this session to fix layout
issues. Give it a final read to ensure all translations are accurate.
Environment notes¶
- Chromium in this dev environment:
/opt/pw-browsers/chromium-1194/chrome-linux/chrome(Playwright-bundled, must pass--no-sandboxas root) - bun: Available system-wide, also copied into Docker image from
oven/bun:1-slim PUBLISHPIPE_MOCK_PDF=1: Set this env var to skip Chromium entirely and write a stub PDF — useful for unit testing the API endpoint
Commit log for this feature¶
81b400a fix(cv): replace publishpipe CLI with build.ts wrapper to fix network-restricted builds
185fc5c fix(cv): remove duplicate header and page-break separators from all CV sources
5849c40 feat(cv): add publishpipe CV generation with feature flag
a9dbcfb docs(planning): add Phase 6 — runtime on-demand CV generation
1bfa6e5 docs(planning): add publishpipe CV generation plan