648 lines
23 KiB
Markdown
648 lines
23 KiB
Markdown
# Design Document
|
|
|
|
**Project**: Salesforce Composite Envelope Builder
|
|
**Version**: 1.0
|
|
**Date**: February 23, 2026
|
|
**Author**: Paul Huliganga
|
|
|
|
---
|
|
|
|
## 1. Architecture Overview
|
|
|
|
### 1.1 System Context
|
|
|
|
```
|
|
┌──────────────────┐
|
|
│ Salesforce User │
|
|
└────────┬─────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────┐
|
|
│ Salesforce Platform │
|
|
│ ┌──────────────┐ ┌───────────────┐ │
|
|
│ │ Screen Flow │───▶│ Apex Class │ │
|
|
│ │ (Template │ │ (Composite │ │
|
|
│ │ Selection) │ │ Builder) │ │
|
|
│ └──────────────┘ └───────┬───────┘ │
|
|
│ │ │
|
|
└──────────────────────────────┼───────────┘
|
|
│
|
|
▼ HTTPS/REST API
|
|
┌──────────────────────┐
|
|
│ Docusign REST API │
|
|
│ (Composite │
|
|
│ Templates) │
|
|
└──────────────────────┘
|
|
```
|
|
|
|
### 1.2 Component Architecture
|
|
|
|
```
|
|
┌────────────────────────────────────────────────────────┐
|
|
│ Salesforce Org │
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────┐ │
|
|
│ │ Presentation Layer (Screen Flow) │ │
|
|
│ │ - Language selection │ │
|
|
│ │ - Template display (checkbox collection) │ │
|
|
│ │ - Success/error messaging │ │
|
|
│ └──────────────────┬──────────────────────────────┘ │
|
|
│ │ │
|
|
│ ┌─────────────────▼──────────────────────────────┐ │
|
|
│ │ Business Logic Layer (Apex) │ │
|
|
│ │ │ │
|
|
│ │ ┌─────────────────────────────────────────┐ │ │
|
|
│ │ │ DocusignCompositeEnvelopeBuilder │ │ │
|
|
│ │ │ - @InvocableMethod entry point │ │ │
|
|
│ │ │ - Input validation │ │ │
|
|
│ │ │ - Composite JSON construction │ │ │
|
|
│ │ │ - Envelope ID return │ │ │
|
|
│ │ └──────────────────┬──────────────────────┘ │ │
|
|
│ │ │ │ │
|
|
│ │ ┌─────────────────▼──────────────────────┐ │ │
|
|
│ │ │ DocusignAPIService │ │ │
|
|
│ │ │ - API authentication │ │ │
|
|
│ │ │ - HTTP callout construction │ │ │
|
|
│ │ │ - Response parsing │ │ │
|
|
│ │ │ - Error handling │ │ │
|
|
│ │ └──────────────────┬──────────────────────┘ │ │
|
|
│ │ │ │ │
|
|
│ │ ┌─────────────────▼──────────────────────┐ │ │
|
|
│ │ │ DocusignCredentials │ │ │
|
|
│ │ │ - Credential retrieval │ │ │
|
|
│ │ │ - Token management │ │ │
|
|
│ │ └─────────────────────────────────────────┘ │ │
|
|
│ └──────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌──────────────────────────────────────────────┐ │
|
|
│ │ Data Layer │ │
|
|
│ │ - Named Credential (Docusign API creds) │ │
|
|
│ │ - Custom Settings (configuration) │ │
|
|
│ └──────────────────────────────────────────────┘ │
|
|
└───────────────────────────────────────────────────────┘
|
|
│
|
|
▼ HTTPS REST API
|
|
┌──────────────────────┐
|
|
│ Docusign Platform │
|
|
└──────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Detailed Component Design
|
|
|
|
### 2.1 DocusignCompositeEnvelopeBuilder (Main Class)
|
|
|
|
**Purpose**: Invocable Apex class that combines multiple Docusign templates into a single envelope
|
|
|
|
**Responsibilities**:
|
|
- Receive template IDs from Screen Flow
|
|
- Validate inputs
|
|
- Construct composite template JSON
|
|
- Delegate API call to service class
|
|
- Return envelope ID to Flow
|
|
|
|
**Methods**:
|
|
|
|
```apex
|
|
// Flow-invocable entry point
|
|
@InvocableMethod(
|
|
label='Send Composite Docusign Envelope'
|
|
description='Combines multiple templates into one envelope'
|
|
)
|
|
public static List<Result> sendCompositeEnvelope(List<Request> requests)
|
|
|
|
// Private helper methods
|
|
private static String buildCompositeEnvelopeJSON(
|
|
List<String> templateIds,
|
|
String recordId,
|
|
String language,
|
|
Map<String, String> customFields
|
|
)
|
|
|
|
private static void validateInputs(Request req)
|
|
|
|
private static List<String> sortTemplatesAlphabetically(List<String> templateIds)
|
|
```
|
|
|
|
**Inner Classes**:
|
|
|
|
```apex
|
|
public class Request {
|
|
@InvocableVariable(required=true label='Template IDs')
|
|
public List<String> templateIds;
|
|
|
|
@InvocableVariable(required=true label='Salesforce Record ID')
|
|
public String recordId;
|
|
|
|
@InvocableVariable(required=false label='Language')
|
|
public String language; // 'en' or 'es'
|
|
|
|
@InvocableVariable(required=false label='Email Subject')
|
|
public String emailSubject;
|
|
|
|
@InvocableVariable(required=false label='Custom Fields')
|
|
public Map<String, String> customFields; // For merge fields
|
|
}
|
|
|
|
public class Result {
|
|
@InvocableVariable(label='Envelope ID')
|
|
public String envelopeId;
|
|
|
|
@InvocableVariable(label='Success')
|
|
public Boolean success;
|
|
|
|
@InvocableVariable(label='Error Message')
|
|
public String errorMessage;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 2.2 DocusignAPIService (Service Class)
|
|
|
|
**Purpose**: Handles all Docusign REST API interactions
|
|
|
|
**Responsibilities**:
|
|
- Construct HTTP requests
|
|
- Make callouts to Docusign API
|
|
- Parse responses
|
|
- Handle errors and retries
|
|
- Log API interactions
|
|
|
|
**Methods**:
|
|
|
|
```apex
|
|
public static String createCompositeEnvelope(
|
|
String envelopeJSON,
|
|
DocusignCredentials creds
|
|
)
|
|
|
|
public static HttpResponse callDocusignAPI(
|
|
String endpoint,
|
|
String method,
|
|
String body,
|
|
Map<String, String> headers
|
|
)
|
|
|
|
public static String parseEnvelopeId(HttpResponse response)
|
|
|
|
private static void logAPICall(
|
|
HttpRequest req,
|
|
HttpResponse res,
|
|
Long durationMs
|
|
)
|
|
|
|
private static void handleAPIError(HttpResponse response)
|
|
```
|
|
|
|
---
|
|
|
|
### 2.3 DocusignCredentials (Credential Management)
|
|
|
|
**Purpose**: Retrieve and manage Docusign API credentials securely
|
|
|
|
**Responsibilities**:
|
|
- Fetch credentials from Named Credential or Custom Settings
|
|
- Handle token refresh (JWT/OAuth2)
|
|
- Provide credential object to service layer
|
|
|
|
**Methods**:
|
|
|
|
```apex
|
|
public static DocusignCredentials getInstance()
|
|
|
|
public String getAccessToken()
|
|
|
|
public String getAccountId()
|
|
|
|
public String getBaseUrl()
|
|
|
|
private static String refreshAccessToken() // JWT or OAuth2 refresh
|
|
|
|
public class CredentialException extends Exception {}
|
|
```
|
|
|
|
**Properties**:
|
|
|
|
```apex
|
|
public String baseUrl { get; private set; }
|
|
public String accountId { get; private set; }
|
|
public String accessToken { get; private set; }
|
|
public DateTime tokenExpiry { get; private set; }
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Data Flow
|
|
|
|
### 3.1 Sequence Diagram: Send Composite Envelope
|
|
|
|
```
|
|
User Flow Apex Service Docusign API
|
|
│ │ │ │ │
|
|
│ Select │ │ │ │
|
|
│ Templates │ │ │ │
|
|
├────────────▶│ │ │ │
|
|
│ │ │ │ │
|
|
│ │ Invoke Apex │ │ │
|
|
│ │ Action │ │ │
|
|
│ ├──────────────▶│ │ │
|
|
│ │ (templateIds) │ │ │
|
|
│ │ │ │ │
|
|
│ │ │ Validate inputs │ │
|
|
│ │ ├────────┐ │ │
|
|
│ │ │ │ │ │
|
|
│ │ │◀───────┘ │ │
|
|
│ │ │ │ │
|
|
│ │ │ Build JSON │ │
|
|
│ │ ├────────┐ │ │
|
|
│ │ │ │ │ │
|
|
│ │ │◀───────┘ │ │
|
|
│ │ │ │ │
|
|
│ │ │ Get credentials │ │
|
|
│ │ ├───────────────────▶│ │
|
|
│ │ │ │ │
|
|
│ │ │◀───────────────────┤ │
|
|
│ │ │ (creds) │ │
|
|
│ │ │ │ │
|
|
│ │ │ Call API │ │
|
|
│ │ ├───────────────────▶│ │
|
|
│ │ │ (JSON, creds) │ │
|
|
│ │ │ │ │
|
|
│ │ │ │ POST /envelopes │
|
|
│ │ │ ├─────────────────▶│
|
|
│ │ │ │ │
|
|
│ │ │ │ 201 Created │
|
|
│ │ │ │ {envelopeId} │
|
|
│ │ │ │◀─────────────────┤
|
|
│ │ │ │ │
|
|
│ │ │ envelopeId │ │
|
|
│ │ │◀───────────────────┤ │
|
|
│ │ │ │ │
|
|
│ │ Result │ │ │
|
|
│ │ (envelopeId) │ │ │
|
|
│ │◀──────────────┤ │ │
|
|
│ │ │ │ │
|
|
│ Success │ │ │ │
|
|
│ Message │ │ │ │
|
|
│◀────────────┤ │ │ │
|
|
│ │ │ │ │
|
|
```
|
|
|
|
### 3.2 Error Handling Flow
|
|
|
|
```
|
|
Apex Service Docusign API
|
|
│ │ │
|
|
│ Call API │ │
|
|
├────────────────▶│ │
|
|
│ │ POST /envelopes │
|
|
│ ├─────────────────▶│
|
|
│ │ │
|
|
│ │ 400 Bad Request │
|
|
│ │ (error JSON) │
|
|
│ │◀─────────────────┤
|
|
│ │ │
|
|
│ │ Parse error │
|
|
│ ├──────┐ │
|
|
│ │ │ │
|
|
│ │◀─────┘ │
|
|
│ │ │
|
|
│ │ Throw exception │
|
|
│ │ │
|
|
│ Catch exception │ │
|
|
│◀────────────────┤ │
|
|
│ │ │
|
|
│ Log error │ │
|
|
├──────┐ │ │
|
|
│ │ │ │
|
|
│◀─────┘ │ │
|
|
│ │ │
|
|
│ Return Result │ │
|
|
│ (success=false, │ │
|
|
│ errorMessage) │ │
|
|
│ │ │
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Docusign Composite Template JSON Structure
|
|
|
|
### 4.1 Request Format
|
|
|
|
```json
|
|
{
|
|
"status": "sent",
|
|
"emailSubject": "Please review and sign these forms",
|
|
"compositeTemplates": [
|
|
{
|
|
"compositeTemplateId": "1",
|
|
"serverTemplates": [
|
|
{
|
|
"sequence": "1",
|
|
"templateId": "TEMPLATE_ID_FORM_A"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"compositeTemplateId": "2",
|
|
"serverTemplates": [
|
|
{
|
|
"sequence": "2",
|
|
"templateId": "TEMPLATE_ID_FORM_B"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"compositeTemplateId": "3",
|
|
"serverTemplates": [
|
|
{
|
|
"sequence": "3",
|
|
"templateId": "TEMPLATE_ID_FORM_C"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### 4.2 Apex JSON Construction
|
|
|
|
**Approach**: Use `Map<String, Object>` + `JSON.serialize()` for dynamic construction
|
|
|
|
```apex
|
|
List<Object> compositeTemplates = new List<Object>();
|
|
|
|
Integer sequence = 1;
|
|
for (String templateId : sortedTemplateIds) {
|
|
Map<String, Object> template = new Map<String, Object>{
|
|
'compositeTemplateId' => String.valueOf(sequence),
|
|
'serverTemplates' => new List<Object>{
|
|
new Map<String, Object>{
|
|
'sequence' => String.valueOf(sequence),
|
|
'templateId' => templateId
|
|
}
|
|
}
|
|
};
|
|
compositeTemplates.add(template);
|
|
sequence++;
|
|
}
|
|
|
|
Map<String, Object> envelope = new Map<String, Object>{
|
|
'status' => 'sent',
|
|
'emailSubject' => emailSubject,
|
|
'compositeTemplates' => compositeTemplates
|
|
};
|
|
|
|
String envelopeJSON = JSON.serialize(envelope);
|
|
```
|
|
|
|
---
|
|
|
|
## 5. API Integration Details
|
|
|
|
### 5.1 Endpoint
|
|
|
|
**POST** `https://{baseUrl}/restapi/v2.1/accounts/{accountId}/envelopes`
|
|
|
|
Where:
|
|
- `{baseUrl}`: e.g., `na3.docusign.net` (from Named Credential)
|
|
- `{accountId}`: Docusign account GUID (from Named Credential or Custom Settings)
|
|
|
|
### 5.2 Headers
|
|
|
|
```
|
|
Authorization: Bearer {access_token}
|
|
Content-Type: application/json
|
|
Accept: application/json
|
|
```
|
|
|
|
### 5.3 Authentication
|
|
|
|
**JWT (JSON Web Token) - Preferred**:
|
|
- Use RSA key pair stored in Named Credential
|
|
- Generate JWT, exchange for access token
|
|
- Token valid for 1 hour, cache and refresh as needed
|
|
|
|
**OAuth2 Authorization Code - Alternative**:
|
|
- User-based authentication
|
|
- Access token + refresh token
|
|
- Requires user interaction for initial authorization
|
|
|
|
### 5.4 Response Codes
|
|
|
|
| Code | Meaning | Action |
|
|
|------|---------|--------|
|
|
| 201 | Created | Success - parse envelope ID |
|
|
| 400 | Bad Request | Invalid JSON or parameters - log and return error |
|
|
| 401 | Unauthorized | Token expired - refresh and retry |
|
|
| 403 | Forbidden | Insufficient permissions - log and return error |
|
|
| 429 | Too Many Requests | Rate limit - retry after delay |
|
|
| 500 | Server Error | Docusign issue - log and return error |
|
|
|
|
---
|
|
|
|
## 6. Governor Limit Considerations
|
|
|
|
### 6.1 Heap Size
|
|
- **Limit**: 6 MB (synchronous), 12 MB (asynchronous)
|
|
- **Mitigation**:
|
|
- Serialize JSON incrementally
|
|
- Avoid loading large objects into memory
|
|
- Process template IDs in batches if needed (future enhancement)
|
|
|
|
### 6.2 CPU Time
|
|
- **Limit**: 10,000 ms (synchronous)
|
|
- **Mitigation**:
|
|
- Minimize loops and complex logic
|
|
- Delegate heavy work to Docusign API
|
|
|
|
### 6.3 Callouts
|
|
- **Limit**: 100 callouts per transaction, 10-second timeout per callout
|
|
- **Mitigation**:
|
|
- Single API call per envelope
|
|
- Use asynchronous callouts (@future) for bulk operations (future enhancement)
|
|
|
|
### 6.4 SOQL Queries
|
|
- **Limit**: 100 queries per transaction
|
|
- **Mitigation**:
|
|
- Minimize queries in loop (not applicable for this design)
|
|
- Cache credentials if fetched via SOQL
|
|
|
|
---
|
|
|
|
## 7. Security Design
|
|
|
|
### 7.1 Credential Storage
|
|
|
|
**Option 1: Named Credential (Preferred)**
|
|
- Credentials encrypted by Salesforce
|
|
- No code changes needed for credential updates
|
|
- OAuth flows managed by platform
|
|
|
|
**Option 2: Protected Custom Settings**
|
|
- API credentials stored encrypted
|
|
- Accessible only via Apex
|
|
- Manual token refresh required
|
|
|
|
### 7.2 Access Control
|
|
|
|
- Apex class runs in **user context** (sharing rules enforced)
|
|
- Users must have:
|
|
- Permission to execute Flows
|
|
- Read access to Salesforce record
|
|
- Docusign send permission (managed via Docusign)
|
|
|
|
### 7.3 Data Protection
|
|
|
|
- No sensitive data logged in debug statements
|
|
- API credentials never exposed in logs or error messages
|
|
- HTTPS for all API communication
|
|
|
|
---
|
|
|
|
## 8. Testing Strategy
|
|
|
|
### 8.1 Unit Tests
|
|
|
|
**Test Coverage Goal**: >75% (Salesforce requirement)
|
|
|
|
**Test Classes**:
|
|
- `DocusignCompositeEnvelopeBuilderTest`
|
|
- `DocusignAPIServiceTest`
|
|
- `DocusignCredentialsTest`
|
|
|
|
**Test Scenarios**:
|
|
1. **Success case**: 3 templates combined, envelope created
|
|
2. **Edge case**: 1 template (minimum)
|
|
3. **Edge case**: 14 templates (maximum)
|
|
4. **Error case**: Invalid template ID
|
|
5. **Error case**: API returns 400
|
|
6. **Error case**: API returns 401 (token expired)
|
|
7. **Error case**: API timeout
|
|
8. **Mock callouts**: Use `HttpCalloutMock` for Docusign API
|
|
|
|
### 8.2 Integration Tests
|
|
|
|
**Manual Testing**:
|
|
1. Create test Docusign templates in sandbox
|
|
2. Configure Named Credential with sandbox credentials
|
|
3. Execute Screen Flow with various template combinations
|
|
4. Verify envelope creation in Docusign sandbox
|
|
5. Verify documents written back to Salesforce
|
|
|
|
### 8.3 Performance Tests
|
|
|
|
- Test with maximum templates (14)
|
|
- Measure Apex CPU time
|
|
- Verify heap size usage
|
|
- Test concurrent requests (multiple users)
|
|
|
|
---
|
|
|
|
## 9. Deployment Architecture
|
|
|
|
### 9.1 Deployment Components
|
|
|
|
**Metadata to Deploy**:
|
|
1. Apex classes:
|
|
- `DocusignCompositeEnvelopeBuilder.cls`
|
|
- `DocusignAPIService.cls`
|
|
- `DocusignCredentials.cls`
|
|
- Test classes (3 files)
|
|
2. Named Credential configuration
|
|
3. Remote Site Settings (for Docusign API URL)
|
|
4. Permission Sets (optional, for access control)
|
|
|
|
### 9.2 Deployment Steps
|
|
|
|
1. **Sandbox deployment** (via VS Code or CLI):
|
|
```bash
|
|
sf project deploy start --target-org sandbox
|
|
```
|
|
|
|
2. **Run unit tests**:
|
|
```bash
|
|
sf apex run test --wait 5
|
|
```
|
|
|
|
3. **Validate production** (without deployment):
|
|
```bash
|
|
sf project deploy validate --target-org production
|
|
```
|
|
|
|
4. **Deploy to production**:
|
|
```bash
|
|
sf project deploy start --target-org production
|
|
```
|
|
|
|
### 9.3 Rollback Plan
|
|
|
|
- Version control: Git repository tracks all changes
|
|
- Destructive changes: Remove Apex classes if needed
|
|
- Flow modification: Update Flow to call old logic temporarily
|
|
|
|
---
|
|
|
|
## 10. Monitoring & Maintenance
|
|
|
|
### 10.1 Logging
|
|
|
|
**Debug Logs**:
|
|
- Log API request/response (sanitized, no credentials)
|
|
- Log execution time
|
|
- Log errors with stack traces
|
|
|
|
**Custom Object (Optional)**:
|
|
- Store API call history in custom object `Docusign_API_Log__c`
|
|
- Fields: Timestamp, Envelope ID, Template Count, Status, Error Message
|
|
|
|
### 10.2 Alerts
|
|
|
|
- Email alerts for repeated API failures
|
|
- Platform Event for real-time monitoring (future enhancement)
|
|
|
|
### 10.3 Maintenance Tasks
|
|
|
|
- Monitor Docusign API rate limits
|
|
- Review logs for errors
|
|
- Update templates as business needs change
|
|
- Refresh API credentials before expiry
|
|
|
|
---
|
|
|
|
## 11. Future Enhancements
|
|
|
|
### 11.1 Phase 2 Features
|
|
|
|
1. **Dynamic recipient selection**: Override template recipients
|
|
2. **Conditional form selection**: Show/hide forms based on Salesforce data
|
|
3. **Bulk sending**: Send envelopes to multiple records
|
|
4. **Template caching**: Cache template metadata to reduce API calls
|
|
|
|
### 11.2 Technical Improvements
|
|
|
|
1. **Asynchronous processing**: Use `@future` or Queueable for large batches
|
|
2. **Retry logic**: Automatic retry for transient failures
|
|
3. **Rate limit handling**: Intelligent backoff and retry
|
|
4. **Analytics dashboard**: Lightning component for usage reporting
|
|
|
|
---
|
|
|
|
## 12. Glossary
|
|
|
|
| Term | Definition |
|
|
|------|------------|
|
|
| **Composite Template** | Docusign feature to combine multiple templates into one envelope |
|
|
| **Invocable Method** | Apex method callable from Screen Flows, Process Builder |
|
|
| **Named Credential** | Salesforce feature for secure external credential storage |
|
|
| **JWT** | JSON Web Token - authentication method for server-to-server integration |
|
|
| **Governor Limits** | Salesforce platform resource limits (CPU, heap, callouts) |
|
|
|
|
---
|
|
|
|
**Document Status**: Draft
|
|
**Next Steps**: Review with stakeholders, begin Apex development
|
|
**Estimated Effort**: 3-5 days development + 2 days testing
|