{"id":49401373,"url":"https://github.com/portwood-global-solutions/docgen","last_synced_at":"2026-06-14T05:01:29.054Z","repository":{"id":347405995,"uuid":"1193964007","full_name":"Portwood-Global-Solutions/DocGen","owner":"Portwood-Global-Solutions","description":"Free, native document generation for Salesforce. PDF, DOCX, XLSX, PPTX — merge tags, images, barcodes, QR codes, bulk generation, Flow actions. 100% Apex + LWC, zero external dependencies.","archived":false,"fork":false,"pushed_at":"2026-06-08T15:58:18.000Z","size":15842,"stargazers_count":78,"open_issues_count":4,"forks_count":20,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-06-08T17:31:54.321Z","etag":null,"topics":["apex","barcode","bulk-generation","document-generation","docx","flow-actions","lwc","merge-tags","open-source","pdf","qr-code","salesforce","salesforce-accelerator","salesforce-package"],"latest_commit_sha":null,"homepage":"https://portwood.dev","language":"Apex","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Portwood-Global-Solutions.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"buy_me_a_coffee":"portwooddocgen"}},"created_at":"2026-03-27T19:13:37.000Z","updated_at":"2026-06-08T15:58:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Portwood-Global-Solutions/DocGen","commit_stats":null,"previous_names":["portwood-global-solutions/portwood-docgen","portwood-global-solutions/docgen"],"tags_count":103,"template":false,"template_full_name":null,"purl":"pkg:github/Portwood-Global-Solutions/DocGen","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Portwood-Global-Solutions%2FDocGen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Portwood-Global-Solutions%2FDocGen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Portwood-Global-Solutions%2FDocGen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Portwood-Global-Solutions%2FDocGen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Portwood-Global-Solutions","download_url":"https://codeload.github.com/Portwood-Global-Solutions/DocGen/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Portwood-Global-Solutions%2FDocGen/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34309655,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-14T02:00:07.365Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apex","barcode","bulk-generation","document-generation","docx","flow-actions","lwc","merge-tags","open-source","pdf","qr-code","salesforce","salesforce-accelerator","salesforce-package"],"created_at":"2026-04-28T18:04:36.853Z","updated_at":"2026-06-14T05:01:29.044Z","avatar_url":"https://github.com/Portwood-Global-Solutions.png","language":"Apex","funding_links":["https://buymeacoffee.com/portwooddocgen"],"categories":[],"sub_categories":[],"readme":"# Portwood DocGen — Free Document Generation for Salesforce\n\nGenerate PDFs and Word docs from any Salesforce record. Merge PDFs, add barcodes and QR codes, compute totals — 100% native: no external services, no callouts, your data never leaves Salesforce. 100% free forever. All features, all users, no paid tiers. PowerPoint and Excel coming soon.\n\n[Join the Community Channel](https://portwood.dev/community) | [Website](https://portwood.dev) | [Roadmap](https://portwood.dev/roadmap)\n\n[![Version](https://img.shields.io/badge/version-3.14.0-blue.svg)](#install)\n[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)\n[![Platform](https://img.shields.io/badge/platform-Salesforce-00A1E0.svg)](https://www.salesforce.com)\n[![Namespace](https://img.shields.io/badge/namespace-portwoodglobal-purple.svg)](#install)\n[![Apex Tests](https://img.shields.io/badge/Apex_Tests-1490_passing-brightgreen)](#code-quality)\n[![Coverage](https://img.shields.io/badge/Coverage-76%25-brightgreen)](#code-quality)\n[![Security](https://img.shields.io/badge/Code_Analyzer-0%2F0%2F0-brightgreen)](#security)\n[![Website](https://img.shields.io/badge/website-portwood.dev-blue)](https://portwood.dev)\n\n---\n\n## Install\n\n```bash\nsf package install --package 04tVx000000nPGbIAM --wait 10 --target-org \u003cyour-org\u003e\n```\n\n[Install in Production](https://login.salesforce.com/packaging/installPackage.apexp?p0=04tVx000000nPGbIAM) | [Install in Sandbox](https://test.salesforce.com/packaging/installPackage.apexp?p0=04tVx000000nPGbIAM)\n\n**Then:** Assign **DocGen Admin** permission set | Enable **Blob.toPdf() Release Update** | Open the **DocGen** app\n\n---\n\n## Quick Start\n\n1. **Create a template** — pick Word, Excel, PowerPoint, or HTML. Choose your Salesforce object.\n2. **Select your fields** — use the visual query builder, or paste a full SOQL statement for complex nested relationships.\n3. **Add tags and upload** — type `{Name}` where you want data. Upload the file (or a Google Docs \"Download → Web Page\" zip for HTML templates).\n4. **Generate** — from any record page, in bulk, or from a Flow.\n\nDownload example templates from [portwood.dev](https://portwood.dev).\n\n---\n\n## What You Can Do\n\n### Template Formats\n\n| Format            | Template                | Output Options | Best For                                                   |\n| ----------------- | ----------------------- | -------------- | ---------------------------------------------------------- |\n| **Word**          | `.docx`                 | PDF or DOCX    | Contracts, proposals, invoices, letters                    |\n| **HTML** (v1.61+) | `.html`, `.htm`, `.zip` | PDF            | Google Docs, Notion, ChatGPT, Apple Pages, any HTML source |\n| **PDF** (v3.03+)  | `.pdf`                  | PDF            | Fillable PDF forms / AcroForm mapping (testing)            |\n| **Excel**         | `.xlsx`                 | XLSX           | Data exports, reports, financial summaries                 |\n| **PowerPoint**    | `.pptx`                 | PPTX           | Presentations, slide decks                                 |\n\nWord and HTML both support images, rich text, headers/footers, and PDF output. Word adds barcodes and QR codes. Excel and PowerPoint render in their native formats only.\n\n**HTML templates** accept Google Docs \"Download → Web Page\" zips directly — the admin UI unzips client-side, extracts each image into a ContentVersion, and rewrites the HTML to reference them. Inline `data:image/...` URIs from Notion / ChatGPT / rich-text paste are handled the same way. Optional `Header HTML` / `Footer HTML` fields with a WYSIWYG editor (and a **Show HTML** toggle for raw-source edits) support merge tags including `{PageNumber}` and `{TotalPages}`.\n\n### Merge Tags\n\n| Tag                             | What It Does                         | Example                                                      |\n| ------------------------------- | ------------------------------------ | ------------------------------------------------------------ |\n| `{FieldName}`                   | Insert a field value                 | `{Name}`, `{Email}`, `{Phone}`                               |\n| `{Parent.Field}`                | Pull from a related record           | `{Account.Name}`, `{Owner.Email}`                            |\n| `{#ChildList}...{/ChildList}`   | Repeat for each child record         | `{#Contacts}{FirstName}{/Contacts}`                          |\n| `{#BoolField}...{/BoolField}`   | Show/hide based on checkbox          | `{#IsActive}Active member{/IsActive}`                        |\n| `{#Field}...{:else}...{/Field}` | Show/hide with fallback              | `{#Industry}Sector: {Industry}{:else}No industry{/Industry}` |\n| `{^Field}...{/Field}`           | Show when field is false/blank       | `{^HasDiscount}No discount applied{/HasDiscount}`            |\n| `{#IF Field op Value}...{/IF}`  | Compare field against value          | `{#IF Amount \u003e 50000}Premium{:else}Standard{/IF}`            |\n| `{RichTextField}`               | Rich text with formatting and images | `{Description}` renders bold, italic, lists                  |\n\n### Formatting\n\n| Tag                      | Output                     |\n| ------------------------ | -------------------------- |\n| `{CloseDate:MM/dd/yyyy}` | 03/18/2026                 |\n| `{Amount:currency}`      | $500,000.00                |\n| `{Rate:percent}`         | 15.5%                      |\n| `{Quantity:number}`      | 1,234                      |\n| `{IsActive:checkbox}`    | [X] or [ ]                 |\n| `{StageName:label}`      | User-facing picklist label |\n\n### Aggregates\n\nPlace these **outside** the loop to compute totals from child records:\n\n| Tag                                     | Example                                |\n| --------------------------------------- | -------------------------------------- |\n| `{SUM:List.Field}`                      | `{SUM:QuoteLineItems.TotalPrice}`      |\n| `{COUNT:List}`                          | `{COUNT:Contacts}`                     |\n| `{AVG:List.Field}`                      | `{AVG:OpportunityLineItems.UnitPrice}` |\n| `{MIN:List.Field}` / `{MAX:List.Field}` | `{MIN:QuoteLineItems.Quantity}`        |\n\n### Images\n\nStore a ContentVersion ID (starts with `068`) in a text field, then use `{%FieldName}` in your template:\n\n| Tag                     | What It Does                                   |\n| ----------------------- | ---------------------------------------------- |\n| `{%Logo__c}`            | Insert image at original size                  |\n| `{%Logo__c:200x60}`     | Fixed size: 200px wide, 60px tall              |\n| `{%Logo__c:100%x}`      | Full page width, keep aspect ratio             |\n| `{%Logo__c:m100%xm50%}` | Shrink to fit within page width and 50% height |\n\nImages work in both **PDF** and **DOCX** output. You can also embed images directly in your Word template — they render in PDFs automatically.\n\n### Rich Text Fields\n\nRich text fields render with full formatting (bold, italic, lists, images) in PDF output. Images inside rich text fields work in PDFs. For DOCX output, use `{%FieldName}` image tags instead of rich text images.\n\n### Barcodes \u0026 QR Codes\n\nPDF output only. No external services required.\n\n| Tag                             | What You Get                     |\n| ------------------------------- | -------------------------------- |\n| `{*ProductCode}`                | Code 128 barcode                 |\n| `{*ProductCode:code128:300x80}` | Barcode at 300px wide, 80px tall |\n| `{*Website:qr}`                 | QR code (150px default)          |\n| `{*TrackingUrl:qr:200}`         | QR code at 200px square          |\n\nQR codes are generated natively in Salesforce with Level Q error correction and support values up to 600 characters. For printed or mailed documents, short URLs or tokens under 120 characters scan most reliably at 1 inch square.\n\n### Charts (v1.99+)\n\nNine chart styles, one tag, every output format. Pure-Apex PNG rasterization — no `\u003ccanvas\u003e`, no external services, no JavaScript libraries. Works in HTML→PDF (Flying Saucer), Word DOCX, Word→PDF, PowerPoint PPTX, and server-side Flow / batch / Queueable contexts.\n\n```\n{Chart:Survey_Responses__r:Selected_Answer__c}                                                            ← bar (default)\n{Chart:Survey_Responses__r:Department__c:pie:title=Department Share}\n{Chart:Survey_Responses__r:Selected_Answer__c:stacked:groupBy=Department__c\u0026colSort=Eng,Sales,Marketing}\n{Chart:Survey_Responses__r:Selected_Answer__c:line:groupBy=Department__c\u0026colSort=Eng,Sales,Marketing}\n```\n\n| Style       | Visual                                               | Best for                                      |\n| ----------- | ---------------------------------------------------- | --------------------------------------------- |\n| `bar`       | Horizontal bars, label + count + percent             | One dimension, long labels                    |\n| `column`    | Vertical bars                                        | One dimension, short labels                   |\n| `pie`       | Pie + right-side legend                              | Share of total, ≤8 slices                     |\n| `donut`     | Pie with center hole                                 | Pie, lighter visual                           |\n| `pivot`     | Cross-tab table with Total column                    | Numeric matrix readout                        |\n| `stacked`   | Horizontal stacked bar segmented by `groupBy`        | \"How does each row split across dimension 2?\" |\n| `clustered` | Vertical clustered bars, mini-bar per col            | Side-by-side comparison                       |\n| `line`      | Polyline through (bucket index, count), multi-series | Trend / ordering matters                      |\n| `area`      | Line + semi-transparent fill below each series       | Trend + accumulated volume                    |\n\nComposable modifiers: `title=`, `width=`, `height=`, `where=` (SOQL fragment), `groupBy=`, `colSort=`, `colors=` (hex palette), `split=` (multi-select delimiter), `scale=`, `htmlRender=svg`. Aggregates via SOQL `GROUP BY` — constant cost regardless of row count (verified end-to-end at 30,000 child rows). Full reference + LLM authoring prompt in `UserGuide.md` §7.6; reference templates ship in `docs/ChartEngineShowcase.{html,docx}`.\n\n### Repeating Tables\n\nTo repeat rows inside a table (not the whole table), put the loop tags in the data row:\n\n| Name                                | Title     | Email                |\n| ----------------------------------- | --------- | -------------------- |\n| `{#Contacts}{FirstName} {LastName}` | `{Title}` | `{Email}{/Contacts}` |\n\nThe `{#Contacts}` goes in the first cell and `{/Contacts}` goes in the last cell of the same row. The header row stays fixed, and the data row repeats for each record.\n\n### Cover Pages \u0026 Section Breaks\n\n- **Title pages** — If your Word template has \"Different First Page\" enabled, the PDF will suppress headers and footers on page 1. Your cover page stays clean.\n- **Section breaks** — Section breaks in your Word template create proper page breaks in the PDF.\n\n### Page Breaks in Loops\n\nPut a page break inside a loop to give each child record its own page:\n\n```\n{#Opportunities}\nCustomer: {Account.Name}\nAmount:   {Amount:currency}\n                              ← page break here (Insert → Page Break in Word)\n{/Opportunities}\n```\n\n### PDF Merger\n\nFive ways to combine PDFs:\n\n| Mode                  | What It Does                                                               |\n| --------------------- | -------------------------------------------------------------------------- |\n| **Generate \u0026 Merge**  | Generate a doc, then append existing PDFs from the record                  |\n| **Document Packets**  | Generate from multiple templates, merge into one PDF                       |\n| **Merge Only**        | Combine existing PDFs on the record with drag-and-drop ordering            |\n| **Child Record PDFs** | Pull PDFs from child records (e.g., all Opportunity PDFs under an Account) |\n| **Bulk Merge**        | After bulk generation, merge all generated PDFs into one download          |\n\n### Giant Query Engine\n\nRecords with **2,000 to 50,000+ child records** are detected automatically. Same template, same button — the engine handles pagination and async processing behind the scenes.\n\n### E-Signatures\n\nCollect legally valid electronic signatures directly from DocGen — no third-party tools required. Built-in Simple Electronic Signature (SES) support that's valid under the US ESIGN Act and UETA. Guided field-to-field signing **on the actual PDF** — **draw or type** signatures and initials — date stamps, document packets, parallel / sequential / single multi-signer flows, decline flow, sender **and signer** completion notifications, and a **Certificate of Completion** (signed timestamps, IP, consent, document hash) — all 100% native. Send from the **Signature Sender** UI or trigger from a **Flow / platform event** — both take the same guided experience. Signed documents follow your template's **Document Title Format** naming, and each signature lands as a clean, professional signature stamp card.\n\n**Signature tag syntax:** `{@Signature_Role:Order:Type}`\n\n| Type       | What It Does                       | Example                         |\n| ---------- | ---------------------------------- | ------------------------------- |\n| `Full`     | Signer types their full legal name | `{@Signature_Buyer:1:Full}`     |\n| `Initials` | Signer types their initials        | `{@Signature_Buyer:2:Initials}` |\n| `Date`     | Auto-filled server timestamp       | `{@Signature_Buyer:3:Date}`     |\n| `DatePick` | Signer selects a date              | `{@Signature_Buyer:4:DatePick}` |\n\nBackward compatible: `{@Signature_Buyer}` still works (treated as `:1:Full`).\n\n**How it works:**\n\n1. Add signature tags to your Word template — DocGen auto-detects roles and placement types\n2. Select template(s) from the Send For Signature tab — preview the merged document before sending\n3. Each signer receives a branded email with a secure link\n4. Signers verify their email with a 6-digit PIN, then walk through each placement step by step — an arrow points to where they need to sign, initial, or add a date\n5. The document updates live as each placement is confirmed — signers can leave and resume later\n6. After all signers complete, DocGen generates a signed PDF with an Electronic Signature Certificate\n\n**Key features:**\n\n- **Guided signing** — step-by-step walk-through with live document updates and arrow indicators\n- **Document packets** — send multiple templates as one signing session (e.g., NDA + Contract + Addendum)\n- **Sequential signing** — signers go one at a time in order (next signer notified after previous completes)\n- **Decline flow** — signers can decline with a reason; sender is notified immediately\n- **Sender notifications** — email alerts when each signer completes, when all are done, or when someone declines\n- **Sender preview** — see the fully merged document with highlighted signature placements before sending\n- **Resume support** — per-placement persistence; signers pick up exactly where they left off\n- **Automated reminders** — configurable reminder emails for signers who haven't responded\n- **Setup validation** — automated checklist verifies site, permissions, OWA, and email deliverability\n\n**What's captured for every signature:**\n\n| Data Point         | How                                                                    |\n| ------------------ | ---------------------------------------------------------------------- |\n| Signer identity    | Email PIN verification (SHA-256 hashed, 10-min expiry, 3 attempts max) |\n| Consent            | Explicit checkbox — timestamp recorded                                 |\n| IP address         | Server-side capture via request headers, shown on PDF certificate      |\n| User agent         | Browser fingerprint                                                    |\n| Document integrity | SHA-256 hash of the final PDF                                          |\n| Tamper evidence    | Field history tracking on all audit fields                             |\n\n**Verification:** Every signed PDF includes a certificate page with signer details (name, role, email, IP address, timestamps) and a verification URL. The verify page lets anyone upload a PDF to check its hash against the audit record — the file never leaves the browser.\n\n**Admin setup:** Configure a Salesforce Site, assign the Guest Signature permission set, set an Org-Wide Email Address, and customize email branding — all from the Signatures tab in the Command Hub. An automated setup checklist shows green/red status for each requirement. See the Learning Center for step-by-step instructions.\n\n### Query Builder\n\nThe query builder accepts full SOQL statements with unlimited nesting depth. Paste a query like:\n\n```sql\nSELECT Name, Industry,\n    (SELECT FirstName, LastName, Account.Name FROM Contacts),\n    (SELECT Name, Amount,\n        (SELECT Quantity, Product2.Name FROM OpportunityLineItems)\n    FROM Opportunities WHERE StageName = 'Closed Won')\nFROM Account\n```\n\nThe builder parses the query, displays the field tree with parent lookups highlighted, and generates copy-paste merge tags for your template. Outer `SELECT` / `FROM` clauses are stripped automatically — DocGen always runs against a specific record.\n\n**Tips:**\n\n- Test your query in Developer Console or tools like [Salesforce Inspector](https://chromewebstore.google.com/detail/salesforce-inspector-reloaded/hpijlohoihegkfehhibggnkbjhoemldh) before pasting.\n- Use AI to help build complex queries — Agentforce, ChatGPT, Gemini, and Claude can all generate valid SOQL with nested relationships.\n- Subqueries support WHERE, ORDER BY, and LIMIT clauses.\n- Parent lookups (e.g., `Account.Name`, `Product2.Family`) work at every nesting level.\n\n### Automation\n\n| Action                 | Inputs                     | Use In                               |\n| ---------------------- | -------------------------- | ------------------------------------ |\n| `DocGenFlowAction`     | templateId, recordId       | Record-Triggered Flows, Screen Flows |\n| `DocGenBulkFlowAction` | templateId, queryCondition | Scheduled Flows, Bulk Processing     |\n\n### Bulk Generation\n\nGenerate documents for hundreds of records at once. Enter a filter condition, click Submit. Real-time progress tracking in the app.\n\n---\n\n## What Works in PDF vs DOCX\n\n| Feature                                        | PDF                          | DOCX                           |\n| ---------------------------------------------- | ---------------------------- | ------------------------------ |\n| All merge tags and formatting                  | Yes                          | Yes                            |\n| Bold, italic, underline, colors, font sizes    | Yes                          | Yes                            |\n| Tables with borders, shading, column widths    | Yes                          | Yes                            |\n| Template-embedded images                       | Yes                          | Yes                            |\n| Dynamic images from record fields (`{%Field}`) | Yes                          | Yes                            |\n| Rich text field formatting                     | Yes                          | Yes                            |\n| Rich text images                               | Yes                          | No — use `{%Field}` image tags |\n| Barcodes and QR codes                          | Yes                          | No                             |\n| Page numbers in headers/footers                | Yes                          | N/A (Word handles natively)    |\n| Cover page (no header on page 1)               | Yes                          | N/A (Word handles natively)    |\n| Custom fonts (Calibri, branded, etc.)          | No — falls back to Helvetica | Yes — preserves original fonts |\n| Clickable hyperlinks                           | No — rendered as styled text | Yes                            |\n\n---\n\n## PDF Font Support\n\nSalesforce's PDF engine supports these fonts:\n\n| Font                 | CSS Name     | When It's Used                                  |\n| -------------------- | ------------ | ----------------------------------------------- |\n| **Helvetica**        | `sans-serif` | Default for all text                            |\n| **Times**            | `serif`      | If explicitly set in template                   |\n| **Courier**          | `monospace`  | Fixed-width text                                |\n| **Arial Unicode MS** | (automatic)  | Chinese, Japanese, Korean, Thai, Arabic, Hebrew |\n\nCustom fonts from your Word template (Calibri, Cambria, branded typefaces) **fall back to Helvetica** in PDF output. If custom fonts matter, generate as DOCX — Word preserves the original fonts.\n\nStarting with Spring '26, the renderer supports expanded multibyte character rendering for international scripts.\n\n---\n\n## What PDF Can't Do\n\nThese are Salesforce platform limitations, not DocGen bugs:\n\n| Not Supported            | Why                                                                                                  | Workaround                                    |\n| ------------------------ | ---------------------------------------------------------------------------------------------------- | --------------------------------------------- |\n| Custom fonts             | `Blob.toPdf()` only has 4 built-in fonts                                                             | Generate as DOCX                              |\n| `@font-face` CSS         | Not supported by the PDF renderer                                                                    | Generate as DOCX                              |\n| Text boxes and shapes    | Word drawing objects aren't converted to HTML                                                        | Use tables for layout                         |\n| SmartArt and charts      | Not rendered in the HTML conversion                                                                  | Insert as images in your template             |\n| Clickable hyperlinks     | PDF renderer outputs styled text, not links                                                          | Links work in DOCX                            |\n| CSS Grid / Flexbox       | The PDF renderer supports CSS 2.1 only                                                               | Use tables                                    |\n| JavaScript               | Ignored by the renderer                                                                              | N/A                                           |\n| Even/odd page headers    | Not currently supported                                                                              | Same header on all pages                      |\n| Multiple section headers | One header/footer set per document                                                                   | Use page breaks, not section-specific headers |\n| Multi-column layouts     | CSS columns not supported by the PDF engine                                                          | Use tables for column layouts                 |\n| E-signatures (QES)       | SES signatures are built-in; Qualified Electronic Signatures (EU eIDAS) require a certified provider | Use built-in SES for most use cases           |\n\n---\n\n## Governor Limits\n\n| Limit                     | Details                    | How DocGen Handles It                                             |\n| ------------------------- | -------------------------- | ----------------------------------------------------------------- |\n| **6 MB heap (sync)**      | Single document generation | DOCX uses client-side assembly; PDF uses zero-heap image pipeline |\n| **12 MB heap (async)**    | Bulk batch generation      | Batch size 1 = fresh heap per record                              |\n| **~3 MB PDF save**        | Saving PDF to a record     | Download has no size limit                                        |\n| **4 MB Aura payload**     | Saving DOCX to a record    | Download works for any size                                       |\n| **100 SOQL queries**      | Per transaction            | Multi-level queries use 1 SOQL per relationship depth             |\n| **50,000+ child records** | Giant datasets             | Auto-detected, processed async with cursor pagination             |\n\n---\n\n## Architecture\n\n```\nTemplate (.docx/.xlsx/.pptx)\n    ↓\nDecompress → Merge XML tags → Recompress\n    ↓                              ↓\n  DOCX/XLSX/PPTX              PDF path:\n  (client-side ZIP)     DocGenHtmlRenderer → Blob.toPdf()\n```\n\n| Class                         | Role                                                                 |\n| ----------------------------- | -------------------------------------------------------------------- |\n| `DocGenService`               | Core merge engine — tags, loops, images, aggregates, barcodes        |\n| `DocGenHtmlRenderer`          | DOCX XML → HTML for PDF rendering                                    |\n| `DocGenDataRetriever`         | Multi-level SOQL with query tree stitching                           |\n| `BarcodeGenerator`            | Code 128 + QR code generation (pure Apex)                            |\n| `DocGenController`            | LWC controller — template CRUD, generation endpoints                 |\n| `DocGenBatch`                 | Batch Apex for bulk document generation                              |\n| `DocGenSignatureController`   | Signing page — token validation, PIN verification, signature capture |\n| `DocGenSignatureService`      | Typed-name stamping, PDF generation, verification certificate        |\n| `DocGenSignatureEmailService` | Branded signature request and PIN emails with OWA support            |\n| `docGenPdfMerger.js`          | Client-side PDF merge engine (pure JS)                               |\n| `docGenZipWriter.js`          | Client-side DOCX/XLSX assembly (pure JS)                             |\n\n---\n\n## Releases\n\nDocGen ships on a **biweekly release cycle**. Latest release: **v3.11.0 — Shared Template Image Rendering**.\n\nSee [CHANGELOG.md](CHANGELOG.md) for full version history.\n\n---\n\n## Community\n\nDocGen is 100% free, open source, and community-driven. Published through [Portwood Global Solutions](https://portwood.dev).\n\n| Channel                                                                     | What It's For                                      |\n| --------------------------------------------------------------------------- | -------------------------------------------------- |\n| [Community Channel](https://portwood.dev/community)                         | Real-time help, feature requests, template sharing |\n| [GitHub Issues](https://github.com/Portwood-Global-Solutions/DocGen/issues) | Bug reports and tracked feature requests           |\n| [Roadmap](https://portwood.dev/changelog)                                   | What's shipped and what's coming next              |\n| [Website](https://portwood.dev)                                             | Install links, feature overview                    |\n\nNeed dedicated support? Contact us at [hello@portwood.dev](mailto:hello@portwood.dev).\n\n## Contributing\n\nWe welcome contributions — see [CONTRIBUTING.md](CONTRIBUTING.md) for setup instructions.\n\n## Security\n\n### Code Analyzer Results\n\nWe run the [Salesforce Code Analyzer](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-sfge.html) with **Security + AppExchange** rule selectors on every release.\n\n| Severity     | Count | Status                         |\n| ------------ | ----- | ------------------------------ |\n| **Critical** | 0     | Clean                          |\n| **High**     | 0     | Clean                          |\n| **Moderate** | 41    | All documented false positives |\n| **Low**      | 0     | Not flagged                    |\n\nThe 41 moderate findings are all PMD false positives that cannot be suppressed inline:\n\n- **29** `ProtectSensitiveData` — PMD flags field names containing \"Token\", \"Signature\", \"Email\", \"Hash\", \"PIN\" in XML metadata. These are signature system fields plus the v1.9x signature-email branding settings (Signature_Email_Subject/Message/Footer/Logo/Brand_Color, Signature_OWA_Id, reminder fields). All intentionally sensitive, protected by permission sets, sharing model, and field history tracking.\n- **12** `AvoidLwcBubblesComposedTrue` — Required for recursive tree node event propagation in the visual query builder, plus the v1.9x runner LWC's cross-boundary events (chart-resolution status, signature-placement events, giant-query progress). Events must cross shadow DOM boundaries in nested components.\n\nSee [`code-analyzer.yml`](code-analyzer.yml) for full documentation of each accepted finding.\n\n### How Access Is Enforced\n\n| Layer                      | Mechanism                                                                                                                             |\n| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |\n| **Object CRUD**            | `DocGen_Admin` and `DocGen_User` permission sets (platform-enforced)                                                                  |\n| **Field-level security**   | Same permission sets (platform-enforced)                                                                                              |\n| **Record sharing**         | Admin-context classes use `with sharing`; signature classes use `without sharing` with access gated by cryptographic token validation |\n| **Standard objects**       | `USER_MODE` + `Security.stripInaccessible()` (code-enforced)                                                                          |\n| **Signature guest access** | `SYSTEM_MODE` with 64-char SHA-256 token + email PIN verification                                                                     |\n\nNo user can access DocGen data without an explicitly assigned permission set. Signature guest users can only access records matching their validated cryptographic token.\n\n### E-Signature Security\n\n| Control            | Implementation                                                                       |\n| ------------------ | ------------------------------------------------------------------------------------ |\n| Token generation   | `Crypto.generateAesKey(256)` + SHA-256 hash (64-char hex)                            |\n| Token expiry       | 48 hours from creation                                                               |\n| PIN verification   | 6-digit code, SHA-256 hashed (plaintext never stored), 10-min expiry, 3 attempts max |\n| Consent            | Explicit checkbox with audit trail entry                                             |\n| Document integrity | SHA-256 hash of final PDF stored on audit record                                     |\n| Tamper evidence    | Field history tracking on all audit fields                                           |\n| IP capture         | Server-side via `X-Forwarded-For` / `True-Client-IP` headers                         |\n\nFound a vulnerability? See [SECURITY.md](SECURITY.md).\n\n## Version History\n\n| Version | Channel                                 | Package ID           |\n| ------- | --------------------------------------- | -------------------- |\n| v3.11.0 | **Latest (Released)**                   | `04tVx000000nPGbIAM` |\n| v3.10.0 | Previous                                | `04tVx000000nOh7IAE` |\n| v3.09.0 | Previous                                | `04tVx000000nOdtIAE` |\n| v3.08.0 | Previous                                | `04tVx000000nOFhIAM` |\n| v3.07.0 | Previous                                | `04tVx000000nLOHIA2` |\n| v3.06.0 | Previous                                | `04tVx000000nIv4IAE` |\n| v3.05.0 | Previous                                | `04tVx000000nI5RIAU` |\n| v3.04.0 | Previous                                | `04tVx000000nGZtIAM` |\n| v3.03.0 | Previous                                | `04tVx000000nEHxIAM` |\n| v3.02.0 | Previous                                | `04tVx000000muJFIAY` |\n| v3.01.0 | Previous                                | `04tVx000000hWJBIA2` |\n| v3.0.0  | Previous                                | `04tVx000000a8blIAA` |\n| v2.9.0  | Previous                                | `04tVx000000a7fhIAA` |\n| v2.8.0  | Previous                                | `04tVx000000a7e5IAA` |\n| v2.7.0  | Previous                                | `04tVx000000a1IXIAY` |\n| v2.6.0  | Previous                                | `04tVx000000a037IAA` |\n| v2.5.0  | Previous                                | `04tVx000000ZyyzIAC` |\n| v2.4.0  | Previous                                | `04tVx000000ZyanIAC` |\n| v2.3.0  | Previous                                | `04tVx000000ZxDJIA0` |\n| v2.2.0  | Previous                                | `04tVx000000ZxBhIAK` |\n| v2.1.0  | Previous                                | `04tVx000000Zw5xIAC` |\n| v2.0.0  | Previous                                | `04tVx000000ZqBpIAK` |\n| v1.99.0 | Previous                                | `04tVx000000ZVFRIA4` |\n| v1.98.0 | Previous                                | `04tVx000000Si9NIAS` |\n| v1.97.0 | Previous                                | `04tVx000000SFovIAG` |\n| v1.96.0 | Previous                                | `04tVx000000SFH3IAO` |\n| v1.95.0 | Previous                                | `04tVx000000SFDpIAO` |\n| v1.94.0 | Previous                                | `04tVx000000SExhIAG` |\n| v1.93.0 | Previous                                | `04tVx000000SDOvIAO` |\n| v1.92.0 | Previous                                | `04tVx000000S9I5IAK` |\n| v1.91.0 | Previous                                | `04tVx000000RvbhIAC` |\n| v1.90.0 | Previous                                | `04tVx000000R8cbIAC` |\n| v1.89.0 | Previous                                | `04tVx000000Qu1lIAC` |\n| v1.88.0 | Previous                                | `04tVx000000Qu09IAC` |\n| v1.87.0 | Previous                                | `04tVx000000QtqTIAS` |\n| v1.86.0 | Previous                                | `04tVx000000QtorIAC` |\n| v1.85.0 | Previous                                | `04tVx000000QlePIAS` |\n| v1.84.0 | Previous                                | `04tVx000000QL2PIAW` |\n| v1.83.0 | Previous                                | `04tVx000000QKRJIA4` |\n| v1.82.0 | Previous                                | `04tal000006rKBdAAM` |\n| v1.81.0 | Previous                                | `04tal000006rKA1AAM` |\n| v1.80.0 | Previous                                | `04tal000006rJkDAAU` |\n| v1.79.0 | Previous                                | `04tal000006rD8XAAU` |\n| v1.77.0 | Previous                                | `04tal000006rCxFAAU` |\n| v1.76.0 | Previous                                | `04tal000006rCu1AAE` |\n| v1.75.0 | Previous                                | `04tal000006rCZ3AAM` |\n| v1.74.0 | Previous                                | `04tal000006rBTJAA2` |\n| v1.73.0 | Previous                                | `04tal000006rAYrAAM` |\n| v1.72.0 | Previous                                | `04tal000006r0xiAAA` |\n| v1.71.0 | Previous                                | `04tal000006r0jBAAQ` |\n| v1.70.0 | Previous                                | `04tal000006qyhNAAQ` |\n| v1.69.0 | Previous                                | `04tal000006qyB7AAI` |\n| v1.68.0 | Previous                                | `04tal000006qt1lAAA` |\n| v1.67.0 | Previous                                | `04tal000006qqOrAAI` |\n| v1.66.0 | Previous                                | `04tal000006qiUXAAY` |\n| v1.65.0 | Previous                                | `04tal000006qiG1AAI` |\n| v1.64.0 | Previous                                | `04tal000006qhYTAAY` |\n| v1.63.0 | Previous                                | `04tal000006qZmEAAU` |\n| v1.62.0 | Previous                                | `04tal000006q929AAA` |\n| v1.61.0 | Previous                                | `04tal000006pzu1AAA` |\n| v1.60.0 | Previous                                | `04tal000006lrGjAAI` |\n| v1.59.0 | Previous                                | `04tal000006lrDVAAY` |\n| v1.58.0 | Previous                                | `04tal000006lpoPAAQ` |\n| v1.57.0 | Superseded (install validator rejected) | `04tal000006lplBAAQ` |\n| v1.56.0 | Previous                                | `04tal000006i1rNAAQ` |\n| v1.55.0 | Previous                                | `04tal000006i0thAAA` |\n| v1.54.0 | Previous                                | `04tal000006i0qTAAQ` |\n| v1.53.0 | Previous                                | `04tal000006hyYXAAY` |\n| v1.52.0 | Previous                                | `04tal000006hyVJAAY` |\n| v1.51.0 | Previous                                | `04tal000006hyThAAI` |\n| v1.50.0 | Previous                                | `04tal000006hyNFAAY` |\n| v1.49.0 | Previous                                | `04tal000006hlZhAAI` |\n| v1.48.0 | Previous                                | `04tal000006hhhNAAQ` |\n| v1.47.0 | Previous                                | `04tal000006hQwfAAE` |\n| v1.46.0 | Previous                                | `04tal000006hQ73AAE` |\n| v1.45.0 | Previous (tester rollout)               | `04tal000006hOZtAAM` |\n| v1.43.0 | Previous                                | `04tal000006hLTxAAM` |\n| v1.42.0 | Previous                                | `04tal000006UkpxAAC` |\n| v1.41.0 | Previous                                | `04tal000006UiubAAC` |\n\nSee [CHANGELOG.md](CHANGELOG.md) for full release notes.\n\n## License\n\nApache License, Version 2.0. See [LICENSE](LICENSE).\n\n---\n\nBuilt by [Portwood Global Solutions](https://portwood.dev)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fportwood-global-solutions%2Fdocgen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fportwood-global-solutions%2Fdocgen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fportwood-global-solutions%2Fdocgen/lists"}