A static CV publishing pipeline that:
- Pulls CV records/items from Airtable into normalized JSON.
- Renders CVs for web (
/cv?cv=<slug>), print (/cv-print.html), and external embed (cv-embed.js). - Builds PDF files into
dist/<slug>.pdfusing Vivliostyle. - Optionally generates AI feedback for a single triggering CV and writes it back to Airtable.
scripts/build-cv-json.js— Airtable ➜data/cv/*.jsonexporter.scripts/build-cv-pdf.js— JSON ➜ paginated HTML ➜dist/*.pdfbuilder.scripts/run-cv-ai-feedback.js— Airtable CV ➜ OpenAI feedback ➜ Airtable update (Overall AI Feedback).cv-render.js— browser renderer shared by viewer/print/embed flows.cv.html— viewer page for a single CV with a PDF link.cv-feedback.html— CV + AI feedback review page (overall and item-level feedback side-by-side).cv-print.html+cv-print.css— print-focused paginated view.cv-embed.js+cv-embed.html— non-iframe embeddable widget + usage/instructions page..github/workflows/cv-ai-feedback.yml— issue/manual-trigger workflow for AI feedback runs.
- Data ingest: Airtable records are fetched and normalized into
data/cv/<slug>.json. - Render paths:
- Web viewer (
cv.html) renders CV content client-side. - Print page (
cv-print.html) renders paginated layout client-side. - Embed script (
cv-embed.js) renders inside Shadow DOM on external sites.
- Web viewer (
- PDF build:
scripts/build-cv-pdf.jstransforms JSON into print HTML and runs Vivliostyle to generatedist/<slug>.pdf. - AI feedback (optional): workflow/script fetches the triggering CV, sends structured prompt to OpenAI, writes output to Airtable
Overall AI Feedback.
- Node.js 20+ (ESM project).
- npm.
- Airtable PAT + base/table identifiers for Airtable scripts.
- Optional:
OPENAI_API_KEYfor AI feedback flow.
Install dependencies:
npm installnpm run build:json # Build CV JSON files from Airtable
npm run pdf:build # Build PDFs from data/cv/*.json
npm run pdf:preview # Open Vivliostyle preview for cv-print.html
npm run ai:feedback # Run AI feedback script for the triggering CV- Reads CV header-level data from the
CVstable. - Reads itemized content from the
CV Itemstable. - Normalizes rich-text field variants.
- Writes canonical JSON to
data/cv/<slug>.json.
The script can resolve a specific CV record ID from:
- Issue title pattern like
CV_UPDATE recXXXXXXXXXXXXXX. - Issue body line like
recordid recXXXXXXXXXXXXXX.
If configured, it can also build all published CVs.
Required for Airtable access:
AIRTABLE_PATAIRTABLE_BASE_ID
Optional/config:
CVS_TABLE_NAME(default:CVs)CV_ITEMS_TABLE_NAME(default:CV Items)CVS_TABLE_IDCV_ITEMS_TABLE_IDISSUE_TITLEISSUE_BODYBUILD_ALL_CVS=true|false
build-cv-json reads footer content from the CV table using CV_Footer (also supports fallback matching), and emits it in JSON as section footer for downstream renderers.
- Route format:
/cv?cv=<slug>. - Loads
data/cv/<slug>.json. - Renders CV content using
CvRender.renderStandardCv. - Provides a single action to open
dist/<slug>.pdfin a new tab.
- Route format:
/cv-print.html?cv=<slug>. - Uses paginated rendering (
CvRender.renderPaginatedCv). - CSS defines print-friendly multi-block layout and footer area.
- Intended for previewing/validating print layout behavior and as a design reference for PDF generation.
- Reads each
data/cv/*.jsonfile. - Generates an HTML document with the same layout model as print rendering.
- Calls
npx vivliostyle buildto outputdist/<slug>.pdf(primary five-block layout) anddist/<slug>.secondary.pdf(secondary split layout).
- PDFs are written to
dist/(e.g.,dist/coleman-davis.pdf). - Secondary layout output is written to
dist/<slug>.secondary.pdf.
- This environment may fail during Playwright Chromium download if external mirrors return 403.
- Script-level parse/runtime checks can still be verified with
node --check scripts/build-cv-pdf.js. - Set
CV_PDF_LAYOUTS=primary|secondary|both(default:both) to control which PDF layout(s) are generated. - Secondary layout behavior: page 1 is single-column, while page 2 uses main+rail with main ordering
Work Experience (Cont.),Technical + IT,Recent Projects, and rail orderingSkills, thenEducation.
A non-iframe embed that renders directly in the host page and isolates styles using Shadow DOM.
<div id="cv-embed-target"></div>
<script
src="https://cpd4f.github.io/cv-builder/cv-embed.js"
data-cv="coleman-davis"
data-target="cv-embed-target"
></script>data-cv(required): slug to load (data/cv/<slug>.json).data-target(optional): target container ID.data-base-url(optional): override base URL for self-hosting.
cv-embed.htmlprovides:- Copy-to-clipboard snippet.
- Usage/options guidance.
- Live preview.
- Targets one triggering CV record (resolved from issue/body inputs).
- Converts CV JSON/content into structured prompt text.
- Calls OpenAI using
OPENAI_API_KEY. - Writes response to Airtable field:
Overall AI Feedback. - Then writes targeted CV-table feedback to
AI Feedback Intro,AI Feedback Core Competencies, andAI Feedback Footerwhen those source blocks exist. - Finally (last step) generates item-level feedback for eligible CV Items and writes it to each item's
AI Feedbackfield in theCV Itemstable (excludingEducationandSecond Page Rail).
- Configured for
gpt-5.4per project requirement for overall, CV-table field, and item-level feedback generation.
AIRTABLE_PATAIRTABLE_BASE_IDOPENAI_API_KEY- Issue context (
ISSUE_TITLE/ISSUE_BODY) when running issue-driven targeting.
Workflow triggers:
workflow_dispatchissuesevents: opened / edited / reopened
Behavior:
- Validates guard conditions for issue-triggered runs (title prefix + expected issue author + expected event actor).
- Honors feature toggle
AI_FEEDBACK_ENABLED(GitHub Actions variable, defaulttrue) so AI feedback can be turned on/off without changing code. - Installs dependencies.
- Runs
npm run ai:feedback. - Posts success/failure comment back to the triggering issue.
Feature toggle setup:
- Configure repository variable
AI_FEEDBACK_ENABLEDin Settings → Secrets and variables → Actions → Variables. - Truthy values (
true,1,yes,on) keep AI feedback enabled. - Any other value disables AI feedback execution in the workflow.
npm install- Configure
.env(or export shell vars) for Airtable/OpenAI secrets. npm run build:jsonnpm run pdf:build- Serve repository root with any static server and test:
/cv?cv=coleman-davis/cv-print.html?cv=coleman-davis/cv-feedback.html?cv=coleman-davis/cv-embed.html
This is typically an environment/network limitation when Vivliostyle tries to fetch Chromium. Re-run in an environment with Playwright download access or preinstalled browser binaries.
Confirm the source Airtable field is CV_Footer on the CVs table and rerun npm run build:json. Footer content is optional and only renders when present.
- Check issue title/body includes valid record ID (
rec...). - Confirm secrets are available to workflow (
AIRTABLE_PAT,AIRTABLE_BASE_ID,OPENAI_API_KEY). - Review workflow logs and issue comments for guard/failure reasons.
This repo is designed for static hosting (e.g., GitHub Pages). Ensure the following are published:
data/cv/*.jsondist/*.pdfcv.html,cv-print.html,cv-embed.html,cv-embed.js,cv-render.js,cv-print.css