Authoring
Authoring workflow
How a template you write becomes a signed, printable A4 PDF served to a national.
The path of a document
- 1. A national clicks Download Electronic Copy on demoportal.
- 2. demoportal fetches the underlying register row from Veritas, mints a serial number, computes the SHA-256 hash + HMAC signature + 9-digit control number, writes a row to
issued_documents, and generates a QR SVG for the verify URL. - 3. demoportal POSTs
{ docType, tier, header, subject, parents, envelope }tokaharagia-docgen. - 4. docgen loads your template file, fills the
{{tag}}placeholders with values from the request body, and renders the HTML. - 5. Puppeteer prints the HTML to a single A4 page; docgen returns the PDF bytes.
- 6. demoportal streams the PDF to the national's browser.
Where your template lives
Path/opt/kaharagia/internal/docgen/src/templates/ ├── shared/ │ ├── arms.tsx # coat-of-arms SVG component │ └── envelope-panel.html # auto-injected verify panel ├── birth/ │ ├── certified.html # ← you author this │ └── electronic.html # ← you author this ├── marriage/ │ ├── certified.html │ └── electronic.html └── ... (one folder per doc type)
Per-tier vs shared
You don't need to author two completely separate files per doc type. The recommended layout uses a shared partial for the data sections and tier-specific files just for the chrome:
Handlebars<!-- birth/certified.html --> {{> ceremonial-masthead}} {{!-- centered arms + state name --}} <h1>{{header.document_title}}</h1> {{> birth/data-sections}} {{!-- shared partial --}} {{> signature-and-seal-row}} <div data-envelope-strip></div> <!-- birth/electronic.html --> {{> red-id-bar}} {{> horizontal-masthead}} <h1>{{header.document_title}}</h1> {{> birth/data-sections}} {{!-- same shared partial --}} <div data-envelope-panel></div>
Iteration loop
- Edit the template file under
internal/docgen/src/templates/. - Rebuild + restart docgen:
docker compose build docgen && docker compose up -d --force-recreate --no-deps docgen - Re-render by hitting
POST /api/renderwith the sample request body for that doc type. docgen returns the PDF in < 1s.
While iterating, use POST /api/preview-html with PUBLIC_PREVIEW=1 set on the container to get the HTML output without going through the PDF roundtrip — much faster for layout tweaks.
Things you should never put in your template
- • Page size, margins, A4 enforcement — handled by docgen.
- • Font loading — Noto faces are auto-imported.
- • Security envelope content — use the marker tags, don't try to print the serial/hash/signature individually.
- • Verify URL construction — already in
{{envelope.verify_url}}. - • Coat-of-arms SVG — use the shared component.
- • QR code generation — passed in via
{{envelope.qr_svg}}.