#4234·career-ops

feat(cv): add opt-in GDPR consent footer slot ({{CONSENT}})

Author: drawskiCreated Sep 16, 2026Updated Sep 16, 2026

Problem

EU candidates often need a GDPR consent statement on their CV (e.g., "I consent to the processing of my personal data as described in..."). Currently, CV templates have no footer slot for this — candidates must manually edit HTML or fork templates.

Proposed Solution

Add an opt-in \{\{CONSENT\}\} placeholder to all HTML CV templates, mirroring the existing \{\{PHOTO\}\} slot pattern (#264).

Key properties:

  • Empty by default — existing CVs render unchanged
  • CSS guard: .cv-consent:empty { display: none; } prevents stray horizontal lines when no consent text
  • Payload field: payload.consent (string, optional)
  • Templates covered: cv-template.html, resume-template.html, cv-template.{compact,executive,jake,leadership,modern}.html

Precedent

This follows the exact pattern of \{\{PHOTO\}\} (#264):

  • Optional slot in templates
  • No-op when empty
  • Filled from payload
  • Same CSS discipline (absent = unchanged layout)

Implementation

  • Builder substitution: CONSENT: escapeHtml(payload.consent || '') in renderReport()
  • Schema: 'consent' added to KNOWN_ROOT_KEYS.html
  • Tests: 70 assertions across 7 templates, covering empty-render, escaping, section-strip survival
  • Docs: Updated modes/pdf.md, batch/batch-prompt.md, templates/README.md

Use Case (EU GDPR)

Polish example:

"Wyrażam zgodę na przetwarzanie moich danych osobowych zawartych w aplikacji dla potrzeb niezbędnych do realizacji procesu rekrutacji (zgodnie z ustawą z 10 maja 2018 roku o ochronie danych osobowych i RODO)."

German example:

"Ich willige ein, dass meine personenbezogenen Daten für den Bewerbungsprozess verarbeitet werden gemäß Art. 6 Abs. 1 lit. b DSGVO."

Files Changed

13 files:

  • 7 templates (+CSS +footer div)
  • 1 test file (70 assertions)
  • 3 docs (schema, batch prompt, README)
  • 2 builder/schema (wiring)

Checklist

  • Tests pass (tests/cv-consent-footer.test.mjs)
  • Lint clean
  • No user-layer files touched
  • Atomic commits (conventional commits style)
  • Issue approved by maintainer
  • PR submitted (after approval)