Skip to content
Q
QuoteNode

Wiki

PDF Generation Pipeline

How QuoteNode generates branded PDF documents from offer snapshots using Thymeleaf and Gotenberg.

PDF Generation Pipeline

QuoteNode generates print-ready PDF documents from offer data using a two-stage pipeline: HTML rendering via Thymeleaf templates, followed by PDF conversion via Gotenberg.

Pipeline Overview

Offer Snapshot (JSON)


Thymeleaf Template Engine
  ├── Layout fragments (header, items table, totals, footer)
  ├── CSS inlined for Gotenberg compatibility
  ├── Product images embedded as base64 URIs
  └── Pagination support (Page X/Y)


HTML Document (complete, self-contained)


Gotenberg (Chromium-based container)


PDF File (stored with SHA-256 checksum)

Snapshot-Based Rendering

PDFs are always rendered from immutable snapshots, never from live offer data. When an offer is sent:

  1. The system captures a complete JSON snapshot of the offer state
  2. This snapshot includes: customer data, all line items, pricing, FX rates, branding configuration, and template settings
  3. The snapshot is stored and versioned (snapshot_version increments on each resend)

This guarantees that the PDF always represents exactly what was offered on that specific date — regardless of any subsequent changes to catalog prices, customer data, or branding.

Template System

Template Families

The current implementation includes the CLASSIC_B2B_TECHNICAL template family. Future variants are planned:

  • MINIMAL_B2B — clean, minimal layout for simple offers
  • B2C_FRIENDLY — consumer-oriented layout with product images
  • MULTI_CURRENCY — optimized for multi-currency pricing tables
  • SERVICE_HOURS — focused on time-based service offerings

Template Structure

Each PDF template consists of:

  • Header — seller logo, company name, address, and contact details
  • Meta section — recipient address, offer number, salesperson name, date, and validity period
  • Items table — configurable columns with pricing details
  • Totals summary — subtotal, discounts, shipping, VAT breakdown, and grand total
  • Trading conditions — payment terms, warranty, delivery conditions, transport terms
  • Signature block — space for approval signatures
  • Footer — company registration details (NIP, KRS, court of registration)

Configurable Columns

The items table columns are controlled per offer via template settings:

SettingEffect
showSkuShow/hide the SKU column
showImagesDisplay product photos in the table
imageSizeSmall (60px), medium (90px), or none
showDescriptionInclude product descriptions
showUnitShow unit of measure column
showVatColumnShow VAT rate column (auto-detected when multiple rates present)
priceModeNET, GROSS, or NET+VAT+GROSS display
discountDisplayBAKED_IN, SHOW_COLUMN, or HIDDEN

Branding Integration

The PDF automatically applies the tenant’s branding configuration:

  • Logo — company logo (PNG or SVG) placed in the header, automatically sized
  • Primary color — applied to headers, borders, and accents
  • Accent color — applied to secondary elements
  • Company details — name, address, phone, email, registration info
  • Custom offer title — override the default “OFERTA CENOWA” heading
  • “Powered by” badge — displayed on Free edition, removable on Pro+ licenses

Processing Modes

Synchronous (Default)

For offers with fewer than 50 line items:

  1. API request triggers PDF generation
  2. Thymeleaf renders HTML → Gotenberg converts to PDF
  3. PDF stream returned in the same HTTP response
  4. SLA target: p95 < 3 seconds

Asynchronous

For large offers (50+ line items) or when the server is under load:

  1. API request returns HTTP 202 with a jobId
  2. A PdfJob record is created in PostgreSQL with status PENDING
  3. A worker thread picks up the job (SKIP LOCKED pattern, 2 concurrent workers)
  4. On success: PDF stored, status updated to COMPLETED, notification sent to user
  5. On failure: retry with exponential backoff (30s → 120s → 600s, 3 max attempts)
  6. Permanently failed jobs are moved to a Dead Letter Queue (DLQ) table

Storage & Retention

Generated PDFs are stored as files with metadata in the generated_documents table:

  • Filename — unique identifier
  • File size — in bytes
  • SHA-256 checksum — for integrity verification
  • Snapshot version — links back to the offer snapshot used for generation
  • Created at — timestamp of generation

Retention policy: PDFs are retained for 365 days by default (configurable). After the retention period, files are eligible for cleanup but the metadata record is preserved for audit purposes.

Gotenberg Configuration

Gotenberg runs as a separate Docker container in the deployment stack. It uses Chromium for HTML-to-PDF conversion, providing:

  • Accurate CSS rendering (including flexbox, grid, and modern CSS)
  • Pagination with configurable margins
  • Page size support (A4 default, letter, and custom sizes)
  • Header and footer rendering (page numbers)

The backend communicates with Gotenberg via its HTTP API. No direct Chromium interaction is needed.

Last reviewed: Recently