DocGen & eSign

Docgen & eSign - Document Workflow Generation Module

Overview

A user clicks "Generate Document" quick action on a record. The generation layer consumes template configuration (created by the template module), fetches Salesforce field values, merges them into a PDF or Word document client-side (VF page JavaScript), creates a Document_Workflow__c record to track the document, and optionally sends it for eSignature or creates records. Nothing here modifies templates or mappings — it purely executes pre-built configurations to produce documents.

Object

Holds

docgen_esign__Document_Template__c

Template config (from template module) — used to fetch merge strategy, signer list, field mappings

docgen_esign__Document_Data_Mapping__c

Field bindings (from template module) — used to build dataMap for form population

docgen_esign__Document_Signer_Mapping__c

Signer definitions (from template module) — SOQL queries executed at generation time to resolve email/name

docgen_esign__Document_Workflow__c

Workflow header — created during generation to track document state, parent record, signers, content version

docgen_esign__Document_Workflow_Item__c

Signer queue item — one per signer, created when workflow transitions to Awaiting Signature, tracks individual signing progress

Architecture

┌────────────────────────────────────────────────────────────┐
│              Quick Action: Generate Document               │
│                        ↓                                   │
│         documentGenerationScreen (LWC on quick action)     │
│              (folder picker → template picker)             │
│                        ↓                                   │
│         GenerationScreenController (Apex + VF backing)     │
│              getTemplateData() → loads VF page             │
│                        ↓                                   │
├────────────┬──────────────────────────┬───────────────────┤
│ PDF Path   │ Word Path                │                   │
│            │                          │                   │
│ PDFPreview │ WordDocument             │                   │
│ Screen (VF)│ GenerationScreen (VF)    │                   │
│            │                          │                   │
│ PSPDFKit   │ Word JS API              │                   │
│ merges     │ merges fields            │                   │
│ fields     │ client-side              │                   │
│ client-side│                          │                   │
└────────────┴──────────────────────────┴───────────────────┘
              ↓ postMessage (blob + fieldMap)
         documentGenerationScreen (LWC)
              handleVfMessages()
                  ↓
    GenerationScreenController.generateDocument()
              ↓
    DocumentGenerationService.generateDocument()
              ↓
    Creates: Document_Workflow__c + ContentVersion + Workflow_Items

Key mechanism — client-side merge + server-side workflow.

The document is rendered by PSPDFKit (PDF) or Word JS APIs (Word) inside a Visualforce page. Field merging happens client-side in the VF page JavaScript. When the user clicks Generate, the VF page posts the already-merged blob + fieldMap back to the LWC via window.postMessage. The LWC calls Apex generateDocument(), which receives the blob and creates workflow records. This separation keeps generation responsive and offloads computational work to the client.


Apex — GenerationScreenController

public with sharing. Backs both PDFPreviewScreen and WordDocumentGenerationScreen VF pages. All SOQL via Data wrapper with enforceSharing.

Method

Returns

What it does

getTemplateData()

String

VF page getter. Reads page params recordId, templateId. Calls DocumentGenerationService.getFormData(). Sets VF properties: base64String (document blob), dataMap (field→value JSON), readOnlyFields, requiredFields, dateFields, picklistMap, fieldNameLabelMap, bFlattenOnGeneration, licensekey. Returns 'Success' or 'Error'.

getTemplates(String recordId) @AuraEnabled

Map<String,Object>

Called by LWC on load. Calls DocumentGenerationService.getActiveTemplates(). Returns { templateDetails: Map (label→Id), templateFolders: Map (Id→folder), templateType: Map (Id→isPDF) }.

generateDocument(String templateId, String recordId, String blobValue, Map<String,String> fieldMapping, Boolean bUpdateSalesforceData, String signerConfig) @AuraEnabled

String

Receives base64 blob (already merged by VF JS). Detects PDF vs Word via Is_Document_PDF__c. Calls DocumentGenerationService.generateDocument(). Returns JSON: { Success, workflowId, fileTitle, successMessage, bGenerateDocumentOnly, isGenerateLink }. On error: { Success: false, errMessage }.

getVfOrigin() @AuraEnabled(cacheable)

String

Returns Visualforce_URL org setting. Used by LWC for postMessage origin validation.

checkStoringSalesforceData() @AuraEnabled(cacheable)

Boolean

Queries Enable_Field_Update_On_Generation setting. Controls post-signing field writes.

getTemplateFolders()

List<String>

Wired in LWC. Returns all unique Template_Group_Folder__c values.

getDocumentWorkFlows(String recordId) @AuraEnabled

List<Document_Workflow__c>

Queries workflows linked to recordId. Used by documentWorkFlowIndex LWC to show workflow status list.

getDocumentWorkFlowItems(String recordId) @AuraEnabled

List<Document_Workflow_Item__c>

Queries workflow items for a workflow. Used by documentWorkFlowIndividual to show per-signer queue.

linkDocumentToWorkFlow(String workflowId, String cvId, String parentId, Boolean bGenerateDocumentOnly) @AuraEnabled

void

Called after ContentVersion creation. Links file to workflow. Triggers workflow state transitions.


Apex — DocumentGenerationService

public with sharing. Core generation logic. All SOQL via Data wrapper with enforceSharing.

Method

Returns

What it does

getFormData(Map<String,Object>)

Map<String,Object>

Bootstrap call at VF load. Takes {templateId, recordId}. Queries Document_Template__c + Document_Data_Mapping__c. For each mapping, resolves dot-notation field path, looks up value on record, formats dates, handles child relationships. Returns { Success, dataMap, base64String, readOnlyField, requiredField, dateFields, bFlattenOnGeneration }. Detects null required fields and blocks generation.

getActiveTemplates(Map<String,Object>)

Map<String,Object>

Queries Document_Template__c by Primary_sObject__c = source object type AND Status__c = Active. Calls DocumentGenerationService to build folder/type maps. Enforces licensing (Feature_Entitlement__c).

generateDocument(Map<String,Object>)

Map<String,Object>

Takes {templateId, recordId, base64String (already merged), fieldMap, bUpdateSalesforceData, signerConfig, signatureType}. Creates Document_Workflow__c (status = Document Generated). Creates ContentVersion (merged blob). If Send_Document_For_eSignature__c: queries Document_Signer_Mapping__c, runs each signer's SOQL (ParentId → actual record ID), creates Document_Workflow_Item__c per signer, updates workflow status → Awaiting Signature. Returns { Success, workflowId, fileTitle, bGenerateDocumentOnly, isGenerateLink }.

getTemplateConfigs(String templateId)

Map<String,Object>

Returns { picklistOptions, fieldNameLabelMap, fieldNameDataTypeMap } for VF picklist rendering.

Apex — WordDocumentGenerationService

public with sharing. Handles Word (.docx) server-side field merge (alternative path).

Method

Returns

What it does

generateDocX(Map<String,Object>)

Blob

Takes field map. Iterates .docx XML, finds form fields, replaces with mapped values. Returns modified .docx blob. Word documents not flattened.


Apex — WordDocumentGenerationController

public with sharing. VF page backing class for Word generation flow.

Member

Type

Purpose

getTemplateData()

VF getter

Reads page params templateId, recordId. Calls DocumentGenerationService.getFormData(). Sets VF properties. Returns 'Success' or 'Error'.


Apex — WorkflowTriggerHandler

before insert/update on Document_Workflow__c. Enforces business rules on workflow creation/update.

Method

Behavior

performSystemValidations(List<Document_Workflow__c>)

Validates workflow state transitions, signer configuration validity, template existence. Calls addError on violations.


LWC — documentGenerationScreen

Entry point quick action. Orchestrates template selection → VF page load → blob merge → workflow creation.

Tracked state

Property

Purpose

@api recordId

Injected by quick action framework

@api bReloadScreen

If true, reload parent on success

bShowTemplateGroupScreen

Toggles folder picker UI

bShowTemplateScreen

Toggles template radio-button picker UI

templateOptions[]

Filtered picklist (label→value) of available templates

templateId

Selected template ID

generatedDocumentURL

Routes to PDF or Word VF page URL

documentLoaded

Triggers iframe load when true; shows VF page

bUserAssignedLicense

Licensing gate; blocks UI if false

docTypeMap

Map of template ID → isPDF (true/false)

vfOrigin

Visualforce origin URL for postMessage validation

showEmailGenerationScreen

Toggles email delivery UI after generation

workflowId

Workflow ID returned from generateDocument; used for email delivery

Key functions

Function

Behavior

connectedCallback()

Registers window.addEventListener('message', handleVfMessages). Loads CSS. Calls isLoggedInUserAssignedLicense().

renderedCallback()

On first load: calls getTemplates(recordId) → builds templateOptions, templateGroups, docTypeMap, mapTemplateFolders. Calls getVfOrigin(). Calls checkStoringSalesforceData().

generateDocument()

Checks docTypeMap[templateId]: PDF → /apex/docgen_esign__PDFPreviewScreen?templateId={id}&recordId={recordId}. Word → /apex/docgen_esign__WordDocumentGenerationScreen?templateId={id}&recordId={recordId}. Sets generatedDocumentURL (loads VF in iframe). Sets documentLoaded = true.

selectFolder(event)

Filters templateOptions by Template_Group_Folder__c. 'other' includes unfoldered templates.

handleVfMessages(event)

Listens for postMessage from VF iframe. Two message types: (1) { type: 'Toast', title, variant, message } → displays ShowToastEvent. (2) { type: 'GenerateDocument', template, recordId, fieldMap, blobValue, signerConfig } → calls generateDocument Apex, creates ContentVersion, calls linkDocumentToWorkFlow, fires success event/displays email UI.

isLoggedInUserAssignedLicense()

Checks licensing. On fail, sets bUserAssignedLicense = false.


VF Pages — PDFPreviewScreen

Controller: GenerationScreenController. Hosts PSPDFKit viewer iframe. Receives templateId, recordId as page params.

Flow: Page loads → calls getTemplateData() → PSPDFKit renders PDF with form fields populated → user interactively fills/adjusts values → clicks Generate → VF JavaScript collects field values (already merged by PSPDFKit) → posts blob + fieldMap back to LWC via postMessage.

VF Property

Purpose

base64String

Base64-encoded PDF blob (template file from Document_Template__c)

dataMap

JSON field→value map (from DocumentGenerationService.getFormData)

readOnlyFields

JSON array of read-only field names

requiredFields

JSON array of required-to-generate field names

dateFields

JSON array of date field names (for client-side formatting)

picklistMap

JSON map of picklist options for form dropdowns

fieldNameLabelMap

JSON map of field API name → label (for error display)

bFlattenOnGeneration

If true, PDF form fields will be flattened to static content (generate-only templates)

nullFieldsError

If true, shows error overlay before rendering (required fields are null)

errorMessage

Validation error message

licensekey

PSPDFKit license key from org settings

orgURL

Org URL for origin validation

vfPageURL

Visualforce URL for origin validation


VF Pages — WordDocumentGenerationScreen

Controller: WordDocumentGenerationController. Loads Word template (.docx), allows field editing, posts merged blob back to LWC.

Flow: Similar to PDF. Word form fields populated from dataMap. User adjusts values. On submit, posts blob + fieldMap back to LWC.

VF Property

Purpose

base64String

Base64-encoded .docx blob

dataMap, readOnlyFields, requiredFields, dateFields

Same as PDF

nullFieldsError, errorMessage

Same as PDF

bFlattenOnGeneration

Not used for Word (Word not flattened)

licensekey

License key


VF Pages — WordDocumentGenerationScreen

Read-only component embedded on record page. Shows list of Document_Workflow__c records for the record, with per-signer status.

Method

Behavior

@wire getDocumentWorkFlows(recordId)

Queries workflows for the parent record. Populates lstWorkFlows.

handleSubscribe()

Platform event subscription (DocumentWorkFlow__e). On "Workflow Created" event: refreshes data. On "Workflow Item Created" event: calls child getWorkFlowItems() to refresh signer queue.


LWC — documentWorkFlowIndividual (Single Workflow Card)

Child component inside documentWorkFlowIndex. Shows one workflow's status, progress ring, list of signers with timestamps.

Method

Behavior

@wire getDocumentWorkFlowItems(recordId)

Queries workflow items for this workflow. Builds display name (signer name + event type), formats timestamps, marks which signer is current.

renderedCallback()

Updates progress bar CSS based on workflow.Status__c (Workflow Initiated → Document Generated → Awaiting Signature → Workflow Completed). Sets step number and progress variant.

sendReminder(e)

Calls GenerationScreenController.sendReminderEmail(). Sends reminder to current signer if configured.


Message contract — LWC ↔ VF postMessage

documentGenerationScreen registers window.addEventListener('message', …) in connectedCallback. VF page posts JSON with type field. Origin validated via vfOrigin before processing.

type

Payload

Handling

Toast

{ title, variant, message }

Displays ShowToastEvent (field validation errors from VF)

GenerateDocument

{ template, recordId, fieldMap, blobValue, signerConfig }

Calls generateDocument Apex → creates ContentVersion → links to workflow → fires success event


Cross-cutting conventions

Convention

Detail

PDF vs Word routing

Is_Document_PDF__c checked in LWC.generateDocument() and GenerationScreenController.generateDocument(). Template module sets this from MIME type at upload.

Dot-notation resolution

Simple: Account_Number__c → field get. Lookup: Account.Name → splits dot, loads parent, retrieves. Child: Line_Items__r.Amount__c → queries child records. Composite: Account::AccountId.Phone → reconstructed server-side.

Today sentinel

Salesforce_Field_API_Name__c = 'Today' (case-insensitive) → Date.today() insertion at generation time.

Date formatting

Date_Format__c on each mapping (e.g., MM/DD/YYYY). Applied at merge time. Defaults MM/DD/YYYY if blank.

Required field validation

At getFormData time, service checks Required_To_generate__c fields. If null, sets nullFieldsError = true, blocks rendering with error message.

Flattening

Flatten_document_while_generation__c = true only for generate-only (not eSign) templates. Flattening in VF JavaScript (PSPDFKit for PDF). Word not flattened.

Workflow creation

If Send_Document_For_eSignature__c = true: queries Document_Signer_Mapping__c, runs SOQL per signer (ParentId → actual ID at runtime), creates Workflow_Item per signer.

Field updates post-signing

If Update_Salesforce_data_on_signing__c = true on mapping + bUpdateSalesforceData enabled → value written back to record post-signing (async).

Signer resolution

SOQL in Document_Signer_Mapping__c.Signer_Query__c executed at generation time with ParentId substituted. Email/name extracted from result.

Workflow state machine

Document Generated → Awaiting Signature (if eSign) or Completed (if generate-only) → Workflow Completed (all signers signed) or Failed (error).