Update documentation to reflect current architecture

SALESFORCE_SETUP.md:
- Rewrite "What was added" to cover all current fields, metadata types,
  Apex classes, LWC components, named credentials, and permission sets
- Add DocusignESignatureServiceTest to the test run command

README.md:
- Replace absolute /home/paulh/... paths with relative ./FILE.md links

CLM_INTEGRATION.md:
- Pattern 1: replace wrong 3-arg trigger callout with correct Queueable pattern
  (triggers cannot make direct callouts)
- Pattern 2: mark LWC quick action as implemented (no longer a recommendation)
- Pattern 3: update REST resource to use CLMAdminService.generateDocument signature
- Payload/request/response: replace old pre-XML format with current
  documentxmlmergetasks JSON and XML structure
- Template design: replace Handlebars syntax with CLM XML merge description

NEXT_STEPS_DOCGEN.md:
- Mark Option B (LWC quick action) as complete
- Replace open-ended "what to confirm" with forward-looking guidance on
  extending to NOD, Education, and Intent to Remove letter types

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
paulh 2026-04-09 20:36:29 -04:00
parent 45814dc2d5
commit fe337efe63
10 changed files with 5408 additions and 249 deletions

View File

@ -1,5 +1,7 @@
# CLM Doc Gen Integration Guide # CLM Doc Gen Integration Guide
> Status note (2026-04-07): the repo is now standardized on the XML merge path built on `AppraiserCasePayloadBuilder` and `CLMDocGenCallout`, using `Appraiser_Case_Deficiency__c` as the canonical child object. See `CURRENT_STATUS.md` before using this guide as the sole source of truth.
## Overview ## Overview
This guide explains how to integrate Salesforce with DocuSign CLM to generate Appraiser Review Letters dynamically from Appraiser Case records. This guide explains how to integrate Salesforce with DocuSign CLM to generate Appraiser Review Letters dynamically from Appraiser Case records.
@ -80,42 +82,57 @@ Recipient Email
## Usage Patterns ## Usage Patterns
### Pattern 1: Apex Trigger (Automatic) ### Pattern 1: Queueable Apex (Automatic/Trigger-Driven)
**Scenario**: Generate letter automatically when Appraiser Case status reaches "Ready for Review" **Scenario**: Generate letter automatically from a trigger or process (callouts cannot be made synchronously from triggers — use a queueable)
```apex ```apex
// In a trigger on Appraiser_Case__c AFTER UPDATE public class AppraiserCaseDocGenJob implements Queueable, Database.AllowsCallouts {
if (oldMap.get(record.Id).Status__c != 'Ready for Review' && private Id caseId;
record.Status__c == 'Ready for Review') { private String accountCode;
private String templateDocHref;
private String destinationFolderHref;
private String destinationDocName;
CLMDocGenCallout.CLMDocGenResponse response = CLMDocGenCallout.generateDocument( public AppraiserCaseDocGenJob(Id caseId, String accountCode,
record.Id, String templateDocHref, String destinationFolderHref, String destinationDocName) {
'TEMPLATE_ID_FROM_CLM', // e.g., '123456' this.caseId = caseId;
record.Reviewer_Email__c this.accountCode = accountCode;
this.templateDocHref = templateDocHref;
this.destinationFolderHref = destinationFolderHref;
this.destinationDocName = destinationDocName;
}
public void execute(QueueableContext ctx) {
CLMDocGenCallout.CLMDocGenResponse response = CLMAdminService.generateDocument(
caseId, templateDocHref, destinationFolderHref, destinationDocName, accountCode
); );
if (!response.success) { if (!response.success) {
// Log error or send notification
System.debug('CLM Doc Gen failed: ' + response.message); System.debug('CLM Doc Gen failed: ' + response.message);
} }
} }
}
// Enqueue from a trigger:
System.enqueueJob(new AppraiserCaseDocGenJob(
record.Id,
'DTC_CLM_Demo',
letterSettings.defaultTemplateDocumentHref,
letterSettings.destinationRootFolderHref,
'Review_' + record.Name + '.docx'
));
``` ```
### Pattern 2: Flow (UI-Driven) ### Pattern 2: LWC Quick Action (UI-Driven) ✅ Implemented
**Scenario**: User clicks button to generate letter on-demand The `clmDocGenWorkbench` component, launched from the **Generate Review Letter** quick action, is the current implemented UI path. It calls `CLMAdminService` to:
- Browse available accounts and letter types
- Browse CLM template and destination folders
- Submit a merge task via `generateDocument()`
- Poll task status via `getTaskStatus()`
- Attach the generated file to the case via `attachGeneratedDocumentToCase()`
1. Create a Record-Triggered Flow on Appraiser_Case__c No additional configuration is needed beyond deploying the metadata and setting up Named Credentials.
2. Add an Action step:
- Action Type: "Apex Action"
- Apex Class: Choose custom Apex action that wraps `CLMDocGenCallout.generateDocument()`
3. Pass:
- recordId (the Appraiser Case)
- templateId (hardcoded or allow user to select)
- recipientEmail (from record or user input)
4. On success: Show toast, store document URL on record
5. On error: Show error message
### Pattern 3: REST API (External System) ### Pattern 3: REST API (External System)
@ -125,12 +142,16 @@ if (oldMap.get(record.Id).Status__c != 'Ready for Review' &&
@RestResource(urlMapping='/appraiser-case-generate-letter') @RestResource(urlMapping='/appraiser-case-generate-letter')
global class AppraiserCaseDocGenRest { global class AppraiserCaseDocGenRest {
@HttpPost @HttpPost
global static void generateLetter(String caseId, String templateId, String recipientEmail) { global static void generateLetter(
CLMDocGenCallout.CLMDocGenResponse response = CLMDocGenCallout.generateDocument( String caseId,
caseId, templateId, recipientEmail String accountCode,
String templateDocHref,
String destinationFolderHref,
String destinationDocName
) {
CLMDocGenCallout.CLMDocGenResponse response = CLMAdminService.generateDocument(
(Id) caseId, templateDocHref, destinationFolderHref, destinationDocName, accountCode
); );
// Return response
RestContext.response.statusCode = response.success ? 200 : 400; RestContext.response.statusCode = response.success ? 200 : 400;
RestContext.response.responseBody = Blob.valueOf(JSON.serialize(response)); RestContext.response.responseBody = Blob.valueOf(JSON.serialize(response));
} }
@ -141,97 +162,72 @@ global class AppraiserCaseDocGenRest {
## Payload Structure ## Payload Structure
### Input ### AppraiserCasePayloadBuilder output (intermediate JSON)
```json ```json
{ {
"AppraiserCaseNumber": "AC-00001", "AppraiserCaseNumber": "AC-000001",
"AppraiserFieldReviewDate": "2026-04-02", "AppraiserFieldReviewDate": "Apr 02, 2026",
"PropertyAddress": "123 Main St, Denver, CO 80202", "LetterSentDate": "Apr 09, 2026",
"FHACaseNumber": "123-4567890",
"AppraiserName": "Jamie Appraiser",
"AppraiserSalutation": "Ms.",
"AppraiserLastName": "Appraiser",
"AppraiserEmail": "jamie@example.com",
"AppraiserAddress": "245 Lexington Ave, New York, NY 10016, USA",
"PropertyAddress": "123 Main St, Denver, CO 80202, USA",
"DeficiencyList": [ "DeficiencyList": [
{ { "deficiencyNumber": 1, "description": "...", "resolution": "...", "reference": "VC-1" }
"deficiencyNumber": 1,
"description": "Missing comparable sale adjustment detail.",
"resolution": "Added adjustment rationale and supporting calculations."
},
{
"deficiencyNumber": 2,
"description": "Neighborhood trend explanation insufficient.",
"resolution": "Expanded market trend narrative with MLS evidence."
},
{
"deficiencyNumber": 3,
"description": "Photo date stamps were not included.",
"resolution": "Re-uploaded photos with date metadata and captions."
}
] ]
} }
``` ```
### CLM API Request (what CLMDocGenCallout sends) ### CLM API Request (what CLMDocGenCallout sends to `/documentxmlmergetasks`)
```json ```json
{ {
"templateId": "TEMPLATE_ID_FROM_CLM", "TemplateDocument": { "Href": "https://.../documents/<template-guid>" },
"mergeData": { ...payload above... }, "DataXML": "<TemplateFieldData><AppraiserCaseNumber>AC-000001</AppraiserCaseNumber>...<DeficiencyList><Deficiency><Number>1</Number>...</Deficiency></DeficiencyList></TemplateFieldData>",
"delivery": { "DestinationDocumentName": "Review_AC-000001.docx",
"recipientEmail": "reviewer@example.com", "DestinationFolder": { "Href": "https://.../folders/<folder-guid>" }
"documentName": "AppraiserReviewLetter_1743724800000"
},
"metadata": {
"salesforceRecordId": "a0wKW000007OIiCYAW",
"generatedAt": "2026-04-02T05:27:44Z"
}
} }
``` ```
### CLM API Response (on success) ### CLM API Response (on success)
```json ```json
{ {
"success": true, "Href": "https://apiuatna11.springcm.com/v2/<account-id>/documentxmlmergetasks/<task-guid>",
"documentUrl": "https://clm-instance.docusign.com/documents/ABC123XYZ", "Status": "Queued",
"documentId": "DOC-001", "Result": { "Href": "https://apiuatna11.springcm.com/v2/<account-id>/documents/<doc-guid>" }
"message": "Document generated successfully"
} }
``` ```
The response is persisted to `Appraiser_Case__c` tracking fields by `CLMAdminService.persistDocGenResult()`.
--- ---
## CLM Template Design ## CLM Template Design
### Template Merge Tags (Handlebars syntax) The implementation uses the DocuSign CLM **XML merge** (`documentxmlmergetasks`) API, not a Handlebars/template-key approach. Template field tags in the `.docx` file use CLM's Word merge syntax (typically `«FieldName»` merge fields or CLM repeat-block markers). Refer to your CLM tenant documentation for the exact syntax.
**Flat fields**: **Flat field example** (Word merge field in the .docx):
```handlebars ```
<p>Case Number: {{AppraiserCaseNumber}}</p> «AppraiserCaseNumber» «AppraiserFieldReviewDate»
<p>Review Date: {{AppraiserFieldReviewDate}}</p> «PropertyAddress»
<p>Property: {{PropertyAddress}}</p>
``` ```
**Deficiency repeat block**: **Deficiency repeat block** — the XML structure sent is:
```handlebars ```xml
<table> <DeficiencyList>
<tr> <Deficiency>
<th>Deficiency #</th> <Number>1</Number>
<th>Description</th> <Description>Missing comparable sale adjustment detail.</Description>
<th>Resolution</th> <Resolution>Added adjustment rationale and supporting calculations.</Resolution>
</tr> <Reference>VC-1</Reference>
{{#each DeficiencyList}} </Deficiency>
<tr> </DeficiencyList>
<td>{{deficiencyNumber}}</td> <DeficiencyCount>1</DeficiencyCount>
<td>{{description}}</td>
<td>{{resolution}}</td>
</tr>
{{/each}}
</table>
``` ```
**Conditional (if no deficiencies)**: Configure a repeat region in your CLM template over `DeficiencyList/Deficiency`, binding `Number`, `Description`, `Resolution`, and `Reference` within the loop.
```handlebars
{{#if DeficiencyList.length}}
<!-- Deficiency table -->
{{else}}
<p>No deficiencies found.</p>
{{/if}}
```
--- ---

View File

@ -1,6 +1,6 @@
# DocuSign CLM Template Mapping Snippet # DocuSign CLM Template Mapping Snippet
This project assumes Salesforce is the system of record and DocuSign CLM doc gen receives a payload built from `Appraiser_Case__c` and its related `Appraiser_Deficiency__c` records. This document reflects an older JSON-oriented payload experiment and is retained only as historical reference. The current working implementation uses `Appraiser_Case__c` and `Appraiser_Case_Deficiency__c` through the XML merge path.
## Suggested Merge Payload ## Suggested Merge Payload
@ -66,6 +66,5 @@ Use the actual DocuSign CLM token syntax used in your tenant, but the field mode
## Notes ## Notes
- Keep `deficiencies` as a repeatable child collection, not a flattened text blob. - Keep deficiency rows as repeatable child data, not a flattened text blob.
- If DocuSign CLM requires a REST callout payload, `AppraiserCaseDocGenService.buildDocGenRequestJson()` is a good source payload to hand to your integration layer. - The active implementation in this repo now uses `AppraiserCasePayloadBuilder` plus `CLMDocGenCallout` rather than `AppraiserCaseDocGenService`.
- If your CLM tenant uses a different collection token syntax, map the same logical field names there.

57
docs/CURRENT_STATUS.md Normal file
View File

@ -0,0 +1,57 @@
# Current Status — 2026-04-09
## Executive summary
The project is now a working Salesforce proof of concept for both DocuSign CLM document generation and basic eSignature API exploration. The app is standardized on `Appraiser_Case__c` plus `Appraiser_Case_Deficiency__c`, uses account-based DocuSign configuration through `CLM_Account_Setting__mdt`, and provides two operator-facing LWCs:
- `clmDocGenWorkbench` for CLM document generation
- `docusignEsignWorkbench` for eSignature API browsing
## What is implemented
- canonical Salesforce parent object:
- `Appraiser_Case__c`
- canonical Salesforce child object:
- `Appraiser_Case_Deficiency__c`
- CLM merge payload builder:
- `AppraiserCasePayloadBuilder`
- CLM callout service:
- `CLMDocGenCallout`
- CLM UI orchestration:
- `CLMAdminService`
- CLM quick-action workbench:
- `clmDocGenWorkbench`
- eSignature service layer:
- `DocusignESignatureService`
- eSignature record-page workbench:
- `docusignEsignWorkbench`
- account-based config through:
- `CLM_Account_Setting__mdt`
- letter-definition config through:
- `CLM_Letter_Definition__mdt`
- task and generated-document tracking on `Appraiser_Case__c`
- generated-document attachment to Salesforce Files
- Apex tests for payload generation, CLM callouts/admin service, and eSignature service
## What is working
- generating CLM review letters from a Salesforce record page
- selecting letter types through metadata-backed defaults while preserving the current appraiser letter
- browsing CLM templates and destination folders by configured account
- polling CLM task status
- attaching generated CLM documents back to the case
- browsing eSignature login info, user info, accounts, templates, and envelopes from Salesforce UI
## What is still not finished
- only the current appraiser review letter is seeded; the additional three letters still need template records and CLM template build-out
- no envelope creation/send workflow yet
- no template detail or envelope detail UI yet
- no long-term productized admin/config UI beyond Salesforce Setup
- some historical docs remain useful but are not authoritative
## Current source of truth
- product-level summary:
- [PRODUCT_SPEC.md](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/docs/PRODUCT_SPEC.md)
- setup and environment notes:
- [SALESFORCE_SETUP.md](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/docs/SALESFORCE_SETUP.md)
- implementation:
- Apex classes and LWCs in `force-app/main/default`
## Immediate recommendation
Treat the codebase as a solid platform baseline. The next phase should focus on product enhancements rather than architecture cleanup: better eSignature workflows, richer record-page UX, and clearer admin/operational controls.

View File

@ -6,29 +6,22 @@ I added a placeholder Quick Action metadata file so there is an explicit place i
DocuSign CLM launch configuration varies by package and org setup. Because of that, the action in this repo is a scaffold/placeholder, not a guaranteed final production action. DocuSign CLM launch configuration varies by package and org setup. Because of that, the action in this repo is a scaffold/placeholder, not a guaranteed final production action.
## Recommended implementation path ## Implementation status
### Option A — Screen Flow (recommended first) ### Option B — LWC / Quick action ✅ Complete
- Create a Screen Flow or autolaunched Flow that accepts `recordId` The `clmDocGenWorkbench` LWC quick action is fully implemented and deployed. It uses `CLMAdminService` and `CLMDocGenCallout` for the full generate → poll → attach workflow.
- Call an Apex invocable or Apex action that builds the payload
- Hand that payload to your DocuSign CLM mechanism
- Redirect user to resulting document or status page
### Option B — LWC / Aura quick action ### Option A — Screen Flow (alternative entry point)
- Use a Lightning Web Component quick action on `Appraiser_Case__c` If a Flow-based launch is preferred (e.g., to add approval steps or prefill inputs):
- Call `AppraiserCaseDocGenService.buildDocGenRequestJson(recordId, templateKey)` - Create a Screen Flow that accepts `recordId`
- Send the payload to the installed DocuSign CLM endpoint or orchestration layer - Call `CLMAdminService.generateDocument()` via an Apex Action step, passing account code, template href, destination folder href, and destination filename
- Show task status by polling `CLMAdminService.getTaskStatus()`
### Option C — Button / URL hack ### Option C — Button / URL hack
- Usually fast, usually brittle. I dont recommend it unless your CLM package explicitly documents it. Not recommended.
## What to confirm in your org ## What to confirm before extending to additional letter types
1. Exact DocuSign CLM package/API available in Salesforce 1. CLM template hrefs for NOD, Education, and Intent to Remove letters
2. Whether generation is initiated by package component, Flow action, Apex callout, or named credential call 2. Whether those letters use the same destination folder structure or need separate `CLM_Letter_Definition__mdt` folder overrides
3. Template identifier format (`templateKey`, template Id, or external document key) 3. Any differences in deficiency display or field set for those letter types
4. Returned artifact behavior (attach to record, email, save to CLM repository, etc.)
## Good next move
Once you know the exact DocuSign package artifact available in the org, I can wire the placeholder into a real Flow/LWC/Apex launch path.

291
docs/PRODUCT_SPEC.md Normal file
View File

@ -0,0 +1,291 @@
# Product Spec — Appraiser Review Letter Platform
## Purpose
This project is a Salesforce-based operator tool for generating appraiser review letters in DocuSign CLM from `Appraiser_Case__c` data, while also serving as a proof-of-concept platform for broader DocuSign API integrations across CLM and eSignature.
## Product goals
- Let a user open an `Appraiser Case` in Salesforce and generate a review letter in DocuSign CLM without using Execute Anonymous.
- Keep CLM account, folder, template, and destination selection configurable per account.
- Persist generation status and generated-document references back to Salesforce.
- Allow operators to browse and test eSignature API data from the same Salesforce app.
- Provide a clean foundation for future workflows such as template selection, envelope creation, and richer document operations.
## Primary users
- Salesforce admins configuring DocuSign connectivity and defaults
- Business users generating review letters from `Appraiser Case` records
- Technical users validating CLM and eSignature API behavior in a safe UI
## Current in-scope workflows
### 1. CLM document generation
- User opens an `Appraiser Case` record.
- User launches the `Generate Review Letter` quick action.
- User selects a configured CLM account.
- User selects a configured letter type.
- User browses CLM folders and templates or uses saved defaults.
- User generates a document through CLM `documentxmlmergetasks`.
- User checks task status.
- User attaches the generated CLM document back to Salesforce as a File.
### 2. eSignature API browsing
- User opens an `Appraiser Case` record.
- User navigates to the `Docusign eSignature` tab on the record page.
- User selects a configured account.
- User loads:
- login information
- OAuth user info
- discovered eSignature accounts
- account templates
- recent envelopes
## Canonical Salesforce data model
### Appraiser Case
`Appraiser_Case__c` is the primary business record.
Current functional fields include:
- `Name`
- `Appraiser_Field_Review_Date__c`
- `Letter_Sent_Date__c`
- `FHA_Case_Number__c`
- `Appraiser_Name__c`
- `Appraiser_Last_Name__c`
- `Appraiser_Street__c`
- `Appraiser_City__c`
- `Appraiser_State_Province__c`
- `Appraiser_Postal_Code__c`
- `Appraiser_Country__c`
- `Property_Street__c`
- `Property_City__c`
- `Property_State_Province__c`
- `Property_Postal_Code__c`
- `Property_Country__c`
Current CLM tracking fields include:
- `Last_CLM_Account_Code__c`
- `Last_DocGen_Status__c`
- `Last_DocGen_Message__c`
- `Last_DocGen_Task_Id__c`
- `Last_DocGen_Task_Url__c`
- `Generated_Document_Id__c`
- `Generated_Document_Url__c`
- `Last_DocGen_Requested_At__c`
- `Last_DocGen_Completed_At__c`
- `Last_Template_Document_Href__c`
- `Last_Destination_Folder_Href__c`
- `Attached_File_Content_Document_Id__c`
- `Attached_File_Url__c`
### Appraiser Case Deficiency
`Appraiser_Case_Deficiency__c` is the canonical child object.
Fields:
- `Appraiser_Case__c`
- `Deficiency_Number__c`
- `Description__c`
- `Reference__c`
- `Resolution__c`
Validation:
- blank deficiency records are blocked by validation
### CLM account configuration
`CLM_Account_Setting__mdt` is the account-level configuration source of truth.
Fields include:
- account identity
- `Account_Code__c`
- `Account_Display_Name__c`
- `Environment_Code__c`
- `Active__c`
- CLM configuration
- `CLM_Account_Id__c`
- `CLM_Api_Named_Credential__c`
- `CLM_Download_Named_Credential__c`
- `Template_Root_Folder_Href__c`
- `Destination_Root_Folder_Href__c`
- `Default_Template_Document_Href__c`
- `Default_Destination_Document_Name_Prefix__c`
- eSignature configuration
- `ESignature_Auth_Named_Credential__c`
- `ESignature_Rest_Named_Credential__c`
- `ESignature_Account_Id__c`
Current active example accounts:
- `DTC CLM Demo`
- `DTC IAM Enterprise`
- `DTC HUD Demo`
### Letter definition configuration
`CLM_Letter_Definition__mdt` is the extensibility layer for letter types.
Each record can define:
- account code
- letter code
- display name
- default flag
- sort order
- default template href
- template root folder href
- destination root folder href
- default filename prefix
Current seeded letter definition:
- `APPRAISER_REVIEW`
Design intent:
- keep the current appraiser review letter working
- allow three additional letters to be added without redesigning the workbench
- support more letters later by metadata rather than code branching
## Canonical CLM architecture
### Payload generation
[AppraiserCasePayloadBuilder.cls](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/force-app/main/default/classes/AppraiserCasePayloadBuilder.cls) builds the document payload from `Appraiser_Case__c` and `Appraiser_Case_Deficiency__c`.
Current payload fields:
- `AppraiserCaseNumber`
- `AppraiserFieldReviewDate`
- `LetterSentDate`
- `FHACaseNumber`
- `AppraiserName`
- `AppraiserLastName`
- `AppraiserStreet`
- `AppraiserCity`
- `AppraiserStateProvince`
- `AppraiserPostalCode`
- `AppraiserCountry`
- `AppraiserAddress`
- `PropertyStreet`
- `PropertyCity`
- `PropertyStateProvince`
- `PropertyPostalCode`
- `PropertyCountry`
- `PropertyAddress`
- `DeficiencyList[]`
### CLM callouts
[CLMDocGenCallout.cls](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/force-app/main/default/classes/CLMDocGenCallout.cls) is the canonical CLM integration class.
Current supported operations:
- submit `documentxmlmergetasks`
- poll task status
- browse folders/documents through generic resource requests
- download generated documents
### CLM orchestration
[CLMAdminService.cls](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/force-app/main/default/classes/CLMAdminService.cls) is the UI-facing orchestration layer.
Current supported operations:
- account selection and defaults
- case context retrieval
- folder/document browsing
- document generation
- task polling
- generated document attachment to Salesforce Files
### CLM UI
[clmDocGenWorkbench](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/force-app/main/default/lwc/clmDocGenWorkbench/clmDocGenWorkbench.js) is the current operator UI.
Current behavior:
- launched from the `Generate Review Letter` quick action
- uses account-based CLM config
- uses account + letter-type selection
- supports template browsing
- supports destination browsing
- supports destination filename selection
- shows case deficiencies before generation
- shows task details and file attachment status
## Canonical eSignature architecture
### eSignature service layer
[DocusignESignatureService.cls](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/force-app/main/default/classes/DocusignESignatureService.cls) is the current eSignature integration layer.
Current supported operations:
- `getAccountConfig`
- `getLoginInformation`
- `getUserInfo`
- `listAccounts`
- `getAccountInformation`
- `listTemplates`
- `listEnvelopes`
### eSignature UI
[docusignEsignWorkbench](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/force-app/main/default/lwc/docusignEsignWorkbench/docusignEsignWorkbench.js) is the current exploratory UI.
Current behavior:
- placed on its own `Docusign eSignature` record tab
- supports account selection
- shows raw login info and user info
- shows discovered eSignature accounts
- shows templates
- shows recent envelopes filtered by `from_date`
## Named credential model
### CLM
- UAT CLM API: `CLMuatNamedCreds`
- UAT CLM download: `CLMuatDownload`
- S1 CLM API: `CLMs1NamedCreds`
- S1 CLM download: `CLMs1Download`
### eSignature
- eSignature REST: `Esignature_Demo_NamedCreds`
- OAuth/account server: `AcctDemo_NamedCreds`
## Current product behavior
### What is working now
- record-based CLM doc generation from Salesforce UI
- XML merge with repeating deficiencies
- account-based CLM config
- metadata-based letter-type selection with backward-compatible default behavior
- generated document status persistence on the case
- generated document attachment to the case as a Salesforce File
- account-based eSignature API exploration
- eSignature template listing
- eSignature envelope listing
### Known limitations
- no end-user workflow yet for creating or sending envelopes
- no template or envelope detail drill-down in the eSignature UI
- no persistent eSignature activity tracking on the case
- no dedicated admin UI yet for managing account configuration beyond Salesforce Setup
- some older docs still contain historical planning content
## Current template contract
### CLM XML merge fields
- `//AppraiserCaseNumber`
- `//AppraiserFieldReviewDate`
- `//PropertyAddress`
- `//PropertyStreet`
- `//PropertyCity`
- `//PropertyStateProvince`
- `//PropertyPostalCode`
- `//PropertyCountry`
### Deficiency repeating block
- row select: `//DeficiencyList/Deficiency`
- fields:
- `./Number`
- `./Description`
- `./Reference`
- `./Resolution`
## Near-term roadmap
- add eSignature detail calls for template detail and envelope detail
- add envelope creation and draft-send flows
- add better operator UX for large account lists and debugging output
- tighten documentation around setup and account configuration
- decide whether to retire `Property_Address__c` completely from metadata
## Out of scope for the current proof of concept
- full production-grade approval workflow
- end-user template authoring inside Salesforce
- large-scale reporting or analytics
- middleware outside Salesforce
---
Last updated: 2026-04-09

View File

@ -1,28 +1,26 @@
# Appraiser Review Letter Generator (Salesforce + DocuSign CLM) # Appraiser Review Letter Generator (Salesforce + DocuSign CLM)
## Welcome!
This project contains documentation and guides for building Appraiser Review Letter templates for use in Salesforce CLM (Contract Lifecycle Management).
---
## Overview ## Overview
This application automates generation of personalized appraiser review letters within Salesforce, merging Q&A responses and related data into a DocuSign CLM-powered letter. Content and layout adjust dynamically to each review scenario. This repo contains a Salesforce metadata project for generating appraiser review letters from `Appraiser_Case__c` data in DocuSign CLM, while also providing a growing proof-of-concept surface for DocuSign eSignature API workflows.
## Architecture Overview ## Current status
- Templates are rendered using dynamic data from Salesforce objects - The repo is standardized on the XML CLM merge path built around `AppraiserCasePayloadBuilder` + `CLMDocGenCallout`.
- All merge fields and arrays are mapped from Salesforce data model - `Appraiser_Case_Deficiency__c` is the canonical child deficiency object used by both the UI and document generation.
- Modular blocks for easy maintenance and expansion - Account-based DocuSign configuration lives in `CLM_Account_Setting__mdt`.
- The current Salesforce UI includes:
- the `Generate Review Letter` quick action for CLM doc gen
- the `Docusign eSignature` record tab for eSignature browsing
- CLM generation, task tracking, file attachment, and eSignature template/envelope browsing are all implemented.
## Key Features ## Read this first
- Dynamic merge of Appraiser Review answers (tables, paragraphs) - [PRODUCT_SPEC.md](./PRODUCT_SPEC.md): current product definition and architecture
- Salesforce-initiated CLM document generation and delivery - [CURRENT_STATUS.md](./CURRENT_STATUS.md): implementation snapshot and current recommendations
- Robust requirements, data, and design documentation - [SALESFORCE_SETUP.md](./SALESFORCE_SETUP.md): metadata and org setup notes
- [CLM_INTEGRATION.md](./CLM_INTEGRATION.md): CLM integration details
- [requirements.md](./requirements.md) and [design.md](./design.md): condensed companion docs aligned to the product spec
## Onboarding ## Documentation note
- Clone docs directory into your Salesforce project repo Older planning docs still exist, but `PRODUCT_SPEC.md`, `CURRENT_STATUS.md`, `SALESFORCE_SETUP.md`, and the source code are now the best reflection of the project.
- Review CLM_TEMPLATE_GUIDE.md for template logic and examples
- See requirements.md for merge field details
--- ---
_Last updated: 2026-02-26 13:23 PM_ _Last updated: 2026-04-09_
_Work in progress: Add quick-start workflow and test recommendations._

View File

@ -1,36 +1,60 @@
# Salesforce Setup — Appraiser Case + DocuSign CLM # Salesforce Setup — Appraiser Case + DocuSign CLM
> Status note (2026-04-07): the project is now standardized on `Appraiser_Case_Deficiency__c` for both UI display and CLM document generation.
## What was added ## What was added
### Custom object: `Appraiser_Case__c` ### Custom object: `Appraiser_Case__c`
- Auto-number name field labeled **Appraiser Case Number** - Auto-number name field labeled **Appraiser Case Number**
- `Appraiser_Field_Review_Date__c` (Date) - Dates: `Appraiser_Field_Review_Date__c`, `Letter_Sent_Date__c`
- `Property_Street__c` (Text 255) - Appraiser identity: `Appraiser_Name__c`, `Appraiser_Last_Name__c`, `Appraiser_Salutation__c`, `Appraiser_Email__c`
- `Property_City__c` (Text 80) - Appraiser address: `Appraiser_Street__c`, `Appraiser_City__c`, `Appraiser_State_Province__c`, `Appraiser_Postal_Code__c`, `Appraiser_Country__c`
- `Property_State_Province__c` (Text 80) - Property address: `Property_Street__c`, `Property_City__c`, `Property_State_Province__c`, `Property_Postal_Code__c`, `Property_Country__c`
- `Property_Postal_Code__c` (Text 20) - Case metadata: `FHA_Case_Number__c`
- `Property_Country__c` (Text 80) - CLM tracking: `Last_CLM_Account_Code__c`, `Last_DocGen_Status__c`, `Last_DocGen_Message__c`, `Last_DocGen_Task_Id__c`, `Last_DocGen_Task_Url__c`, `Last_Template_Document_Href__c`, `Last_Destination_Folder_Href__c`, `Last_DocGen_Requested_At__c`, `Last_DocGen_Completed_At__c`
- Generated document: `Generated_Document_Id__c`, `Generated_Document_Url__c`
- Attached file: `Attached_File_Content_Document_Id__c`, `Attached_File_Url__c`
### Child custom object: `Appraiser_Deficiency__c` ### Child custom object: `Appraiser_Case_Deficiency__c`
- Master-detail to `Appraiser_Case__c` - Master-detail to `Appraiser_Case__c`
- `Deficiency_Number__c` (Text 50) - `Deficiency_Number__c` (Number)
- `Description__c` (Long Text Area) - `Description__c` (Long Text Area)
- `Resolution__c` (Long Text Area) - `Resolution__c` (Long Text Area)
- `Sort_Order__c` (Number) - `Reference__c` (Text)
### Layouts ### Custom metadata types
- Basic page layout for Appraiser Case - `CLM_Account_Setting__mdt` — per-account CLM and eSignature configuration (Named Credentials, folder hrefs, template hrefs)
- Basic page layout for Appraiser Deficiency - `CLM_Letter_Definition__mdt` — per-account letter type definitions with optional folder/template overrides
- `CLM_Environment_Setting__mdt` — legacy environment defaults (UAT/S1); superseded by account settings
### Apex classes
- `AppraiserCasePayloadBuilder.cls` + test
- `CLMDocGenCallout.cls` + test
- `CLMAdminService.cls` + test
- `DocusignESignatureService.cls` + test
### Lightning Web Components
- `clmDocGenWorkbench` — CLM document generation UI (account selection, folder browsing, merge task submission, status polling, file attachment)
- `docusignEsignWorkbench` — eSignature API browsing (accounts, templates, envelopes)
- `clmRequestPreview` — merge request preview utility
### Named credentials
- `CLMuatNamedCreds`, `CLMs1NamedCreds` — CLM API calls
- `CLMuatDownload`, `CLMs1Download` — CLM document downloads
- `Esignature_Demo_NamedCreds` — eSignature REST API
- `AcctDemo_NamedCreds` — eSignature OAuth/userinfo
### Layouts and UI
- Page layouts for `Appraiser_Case__c` and `Appraiser_Case_Deficiency__c`
- Related list on Appraiser Case for deficiencies - Related list on Appraiser Case for deficiencies
- Basic list view on Appraiser Case - Record page: `Appraiser_Case_Record_Page`
- Quick action: `Generate Review Letter` (launches `clmDocGenWorkbench`)
### Tabs and permissions
- Custom tabs for both objects - Custom tabs for both objects
- Permission set: `Appraiser_Case_Admin` - Custom app: `Appraiser_Review`
### Apex ### Permissions
- `AppraiserCaseDocGenService.cls` - `Appraiser_Case_Admin` — full access
- `AppraiserCaseDocGenServiceTest.cls` - `Appraiser_Case_Access` — read/create access
### Sample data ### Sample data
- Anonymous Apex script: `scripts/apex/createSampleAppraiserCase.apex` - Anonymous Apex script: `scripts/apex/createSampleAppraiserCase.apex`
@ -52,7 +76,7 @@ sf project deploy start --source-dir /home/paulh/.openclaw/workspace/projects/sa
## Test Apex ## Test Apex
```bash ```bash
sf apex run test --tests AppraiserCaseDocGenServiceTest --result-format human sf apex run test --tests AppraiserCasePayloadBuilderTest --tests CLMAdminServiceTest --tests CLMDocGenCalloutTest --tests DocusignESignatureServiceTest --result-format human
``` ```
## Load sample data ## Load sample data
@ -73,12 +97,12 @@ sf org assign permset --name Appraiser_Case_Admin
2. Assign permission set. 2. Assign permission set.
3. Run the sample Apex script. 3. Run the sample Apex script.
4. Open the `Appraiser Case` tab and verify the record + related deficiencies. 4. Open the `Appraiser Case` tab and verify the record + related deficiencies.
5. Validate the JSON payload in debug logs or by running the Apex methods directly. 5. Validate the XML merge payload path in debug logs or by running the Apex methods directly.
6. Wire the DocuSign CLM launch path based on the exact package capability in your org. 6. Open an `Appraiser Case` record and use the `Generate Review Letter` action to browse folders/templates and submit a merge task.
## About the quick action ## About the quick action
A placeholder quick action metadata file was added to mark the launch point, but DocuSign CLM launch mechanics vary by package/org. See `docs/NEXT_STEPS_DOCGEN.md` for the practical wiring options. The `Generate Review Letter` quick action is now wired to the `clmDocGenWorkbench` LWC for interactive CLM browsing and merge submission.
## About “page layout” and “default setup” ## About “page layout” and “default setup”

4813
docs/appraiser-llm-chat.md Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,45 +1,48 @@
# Design — Appraiser Review Letter Generator # Design — Appraiser Review Letter Platform
## Architecture This document now serves as a compact architecture summary. The broader current-state reference is [PRODUCT_SPEC.md](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/docs/PRODUCT_SPEC.md).
Describe the template structure, merge field handling logic, and integration with Salesforce CLM.
## Current architecture
### Salesforce records
- `Appraiser_Case__c` is the parent business object
- `Appraiser_Case_Deficiency__c` is the canonical child object
### Configuration
- `CLM_Account_Setting__mdt` stores account-level CLM and eSignature configuration
### CLM path
- [AppraiserCasePayloadBuilder.cls](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/force-app/main/default/classes/AppraiserCasePayloadBuilder.cls)
- [CLMDocGenCallout.cls](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/force-app/main/default/classes/CLMDocGenCallout.cls)
- [CLMAdminService.cls](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/force-app/main/default/classes/CLMAdminService.cls)
- [clmDocGenWorkbench](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/force-app/main/default/lwc/clmDocGenWorkbench/clmDocGenWorkbench.js)
### eSignature path
- [DocusignESignatureService.cls](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/force-app/main/default/classes/DocusignESignatureService.cls)
- [docusignEsignWorkbench](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/force-app/main/default/lwc/docusignEsignWorkbench/docusignEsignWorkbench.js)
## CLM merge design
- Salesforce builds XML merge data from the case and related deficiencies.
- CLM document generation uses `documentxmlmergetasks`.
- Folder and template selection are account-configurable and browsable in the UI.
- Task results and generated-document references are persisted back to `Appraiser_Case__c`.
- Generated CLM output can be downloaded via Named Credential and attached to the case as a Salesforce File.
## eSignature design
- Separate Named Credentials are used for REST calls and account-server OAuth/userinfo calls.
- The service currently supports:
- login information
- OAuth user info
- discovered accounts
- template listing
- envelope listing
- The current eSignature panel is an operator/admin browsing surface, not yet a business workflow.
## Design principles
- prefer account-based config over environment-only config
- keep DocuSign callouts in Apex behind UI-facing service methods
- persist important CLM results onto the business record
- use record-page or action-based LWCs for operator flows instead of Execute Anonymous
--- ---
Last updated: 2026-04-09
## Data Model
- Appraiser_Review__c: main record
- Appraiser_Review_Question__c: child (per Q&A)
## Merge Data (to CLM)
- Flat fields: appraiser, address, etc.
- Collection: reviewQuestions[] with Q, A, comments, etc.
## Template Structure
- Modular blocks (Header/Body/Footer)
- Dynamic sections for deficiencies, comments, summary
- Use of template language (Handlebars/Mustache/etc)
## Merge Logic
- Iterate lists (arrays) for tables
- Conditional display for sections/questions
- Null/empty handling (default text or suppression)
## Example Structure
```handlebars
{{#each DeficiencyList}}
<tr><td>{{DeficiencyType}}</td><td>{{DeficiencyDescription}}</td></tr>
{{/each}}
```
## CLM Template Guidance
- Repeat blocks/tables for reviewQuestions
- Conditional/variable blocks for rich, dynamic output
---
## Questions/Decisions
- Should merge logic be handled in Salesforce or intermediary middleware?
- What template engine is ideal for maintainability and troubleshooting?
---
_Last updated: 2026-02-26 13:20 PM_
_Work in progress: More complete architecture diagrams and template examples forthcoming._

View File

@ -1,47 +1,32 @@
# Requirements — Appraiser Review Letter Generator # Requirements — Appraiser Review Letter Platform
## Purpose This document now serves as a short requirements summary. The full current product specification is in [PRODUCT_SPEC.md](/home/paulh/.openclaw/workspace/projects/salesforce-appraiser-review-letter/docs/PRODUCT_SPEC.md).
Outline technical and functional requirements for Appraiser Review Letter templates in Salesforce CLM. Include assumed merge fields, integration points, edge cases, and design goals.
## Functional requirements
- A user can generate an appraiser review letter from an `Appraiser_Case__c` record in Salesforce.
- The generated CLM document merges property data and a repeating deficiency list from Salesforce.
- The user can choose a configured CLM account instead of hardcoding environment-specific values.
- The user can browse CLM templates and destination folders in the UI.
- The user can track CLM task status and attach the generated document back to the case.
- The system can browse core eSignature account data, templates, and envelopes for configured accounts.
## Non-functional requirements
- Account-specific configuration must be deployable and maintainable through Salesforce metadata.
- The solution must support both UAT and S1 CLM/eSignature account setups.
- The primary document-generation path must be test-covered in Apex.
- The solution should remain usable as a proof-of-concept platform for additional DocuSign API work.
## Canonical requirements decisions
- Canonical parent object: `Appraiser_Case__c`
- Canonical child deficiency object: `Appraiser_Case_Deficiency__c`
- Canonical CLM generation path: XML merge via `documentxmlmergetasks`
- Canonical config source: `CLM_Account_Setting__mdt`
- Structured property address fields are the source of truth; `Property_Address__c` is legacy
## Current open product questions
- What should the first production-grade eSignature workflow be: template detail, envelope detail, draft creation, or send?
- Should eSignature activity be persisted back onto `Appraiser_Case__c` the way CLM activity is?
- Should the eSignature workbench remain a testing/admin surface or evolve into a business-user workflow?
--- ---
Last updated: 2026-04-09
## Functional
- Reviewer completes form Q&A on Appraiser Review
- Each response drives tailored content in final letter (questions, comments, tables/blocks)
- Salesforce triggers CLM letter, merges data fields and Q&A collection
## Non-Functional
- Configurable (new Qs/fields easy to add)
- Audit and status tracking
- Support for complex/dynamic tables in output
## Key Requirements
- Support dynamic template merge fields (arrays/lists, booleans, enums)
- Render tables, paragraphs, and conditional sections
- Handle edge cases: nulls, empty lists, formatting gaps
- Provide fallback text for empty sections (e.g., 'No deficiencies found')
- Enable integration with Salesforce data model (objects: Appraisal, Deficiency, Reviewer)
## Example JSON
```json
{
"AppraisalId": "a1b2c3",
"DeficiencyList": [
{
"DeficiencyType": "Missing Docs",
"DeficiencyDescription": "Appraisal report lacking required documents."
}
],
"ReviewerComments": ["Well organized report."]
}
```
---
## Questions/Decisions
- What is the authoritative object and field schema for merge?
- Are custom field mappings needed for relationships (e.g. lookup fields)?
---
_Last updated: 2026-02-26 10:35 AM_
_Work in progress: Integration and schema expansion next._