Advanced CMS-Workflow Integration: Quick Reference
π― What's New?β
Three major improvements:
- No More JSON Editing - Beautiful UI replaces raw config JSON
- Advanced Template Rendering - Handlebars/Mustache with filters, loops, conditionals
- CMS Integration - Load templates from ContentData with smart merging
π Quick Startβ
Backend: Register Module Schemaβ
@Component
public class EmailModuleSchemaSetup {
@PostConstruct
public void setup(ModuleConfigSchemaRegistry registry) {
ModuleConfigSchema schema = new ModuleConfigSchema(
"EMAIL", "Email Module", "Send emails with CMS templates"
);
schema.addFields(
new ConfigField("integrationAccountId", "Email Account", FieldType.LOOKUP)
.required(true)
.apiLookup(new ApiLookup("/api/v1/integrationaccounts", "id", "name")
.filterParam("type", "EMAIL")),
new ConfigField("templateId", "Template", FieldType.LOOKUP)
.apiLookup(new ApiLookup("/api/v1/contentdata", "id", "title")
.filterParam("contentType", "template"))
);
registry.registerSchema("EMAIL", schema);
}
}
Frontend: Render Configuration UIβ
const { schema, loading } = useModuleConfigSchema(execModule.moduleType);
<AdvancedModuleDesigner
schema={schema}
currentConfig={JSON.parse(execModule.moduleData || "{}")}
onConfigChange={(newConfig) => {
// Save to backend
updateExecModule(newConfig);
}}
/>;
Database: Use Type-Safe Config Accessβ
@Service
public class MyWorkflowService {
@Autowired
private ExecModuleConfigService configService;
public void executeModule(ExecModule module) {
String templateId = configService.getStringConfig(module, "templateId", "");
boolean escapeHtml = configService.getBooleanConfig(module, "escapeHtml", true);
// Do work...
}
}
π¨ Available Field Typesβ
| Type | Use Case |
|---|---|
| TEXT | Simple text input |
| Email validation | |
| NUMBER | Numeric input |
| TEXTAREA | Multi-line text |
| CHECKBOX | Boolean toggle |
| SELECT | Dropdown (single) |
| MULTISELECT | Dropdown (multiple) |
| LOOKUP | API-powered autocomplete |
| JSON | JSON editor (complex configs) |
| CODE | Code editor (lambda/expressions) |
| TEMPLATE_EDITOR | Handlebars template editor |
| RECIPIENT_LIST | Email recipient list builder |
| DATE | Date picker |
| DATETIME | Date+time picker |
| COLOR | Color picker |
π₯ Template Filters (Handlebars/Mustache)β
Chain multiple filters:
π― Handlebars Control Flowβ
Conditionalsβ
Loopsβ
Loop variables: @index, @key, @first, @last, @odd, @even
π§ Email Module Configurationβ
{
"integrationAccountId": "sendgrid-account-id",
"templateMode": "cms",
"templateId": "template-uuid",
"mergeEngine": "handlebars",
"subjectTemplate": "Welcome {{firstName}}!",
"recipientMode": "dynamic",
"recipientDataPath": "recipients",
"escapeHtml": true
}
π Content Template Module Configurationβ
Single Template:
{
"mode": "single",
"contentId": "template-uuid",
"mergeEngine": "handlebars"
}
Multiple Templates (Compose):
{
"mode": "multiple",
"templateIds": ["header-uuid", "body-uuid", "footer-uuid"],
"mergeEngine": "handlebars"
}
Search by Type:
{
"mode": "search",
"search": {
"type": "template",
"category": "email",
"limit": 10
}
}
π REST Module Configurationβ
{
"url": "https://api.example.com/endpoint",
"method": "POST",
"integrationAccountId": "auth-account",
"headers": { "Content-Type": "application/json" },
"body": "{{payload | json}}",
"responseMapping": {
"userId": "result.id",
"status": "meta.status"
}
}
π API Lookup Configurationβ
Define how dropdown options are fetched:
new ApiLookup("/api/v1/contentdata", "id", "title")
.filterParam("contentType", "template")
.filterParam("category", "email")
.searchable(true)
.searchParamName("q")
.sortBy("title", true)
.pageSize(50)
Query generated:
GET /api/v1/contentdata?contentType=template&category=email&q=welcome
β¨ REST Endpointsβ
GET /api/v1/module-schemas
β All module configuration schemas
GET /api/v1/module-schemas/{moduleType}
β Specific module schema (e.g., EMAIL, REST, CONTENT_TEMPLATE)
Example Response:
{
"moduleType": "EMAIL",
"moduleName": "Email Module",
"description": "Send emails with CMS templates",
"fields": [
{
"name": "integrationAccountId",
"label": "Email Integration",
"fieldType": "LOOKUP",
"required": true,
"section": "Account",
"order": 1,
"apiLookup": {
"endpoint": "/api/v1/integrationaccounts",
"labelField": "accountName",
"valueField": "id",
"filterParams": {"type": "EMAIL"},
"searchable": true
}
}
],
"metadata": {}
}
π§ͺ Testingβ
Validate Configβ
ExecModuleConfigService configService = ...;
ExecModule module = new ExecModule();
module.setModuleType(ModuleTypeEnum.EMAIL);
module.setModuleData("{}");
ValidationResult result = configService.validateConfig(module);
if (!result.isValid()) {
Map<String, String> errors = result.getErrors();
errors.forEach((field, message) ->
System.out.println(field + ": " + message)
);
}
Test Template Renderingβ
// Setup
ContentTemplateAdvancedModule module = new ContentTemplateAdvancedModule();
module.setModuleData(
"{\"mode\": \"single\", \"contentId\": \"...\", \"mergeEngine\": \"handlebars\"}"
);
module.setInputMap(Map.of(
"vars", Map.of("firstName", "John", "isPremium", true)
));
// Execute
module.execute();
// Verify
String rendered = (String) module.getOutputMap().get("template");
assertTrue(rendered.contains("John"));
π― Common Patternsβ
Email with Dynamic Recipientsβ
{
"integrationAccountId": "sendgrid-account",
"templateId": "welcome-template",
"recipientMode": "dynamic",
"recipientDataPath": "users"
}
Input: { "users": [{"email": "john@example.com", "firstName": "John"}, ...] }
Newsletter with Multiple Templatesβ
{
"mode": "multiple",
"templateIds": ["header-uuid", "featured-uuid", "footer-uuid"],
"mergeEngine": "handlebars"
}
Search Templates by Categoryβ
{
"mode": "search",
"search": {
"type": "template",
"category": "promotional"
}
}
π Troubleshootingβ
| Issue | Solution |
|---|---|
| "No schema found" | Check module type is registered in ModuleConfigSchemaRegistry |
| Filter not working | Use correct filter name (see Filters section) |
| Template variables not rendering | Check variable path and context data in input map |
| API lookup returns no options | Verify endpoint, filterParams, valueField, labelField |
| Conditional not rendering | Check condition variable exists in context |
π Full Documentationβ
See ADVANCED_CMS_WORKFLOW_INTEGRATION.md for:
- Complete architecture overview
- Email template walkthrough
- Integration guide for custom modules
- Comprehensive test examples
- Migration guide from raw JSON
Made for developers who hate JSON editing as much as we do! π₯