Saltar al contenido principal

Template Rendering Implementation

Overview

This document describes the implementation of Handlebars template rendering for the communication templates preview endpoint.

Date

October 24, 2025

Status

COMPLETED

Problem

The communication templates preview endpoint (POST /communication-templates/:id/preview) had TODO comments indicating that Handlebars rendering needed to be implemented. The endpoint was returning raw, unrendered templates.

Solution Architecture

1. Shared Handlebars Utilities

Created a shared utility module at apps/backend/src/communication-templates/utils/handlebars-helpers.ts containing:

Functions

  • registerHandlebarsHelpers() - Registers custom Handlebars helpers
  • renderHandlebarsTemplate(template, variables) - Renders a template with variables
  • validateHandlebarsTemplate(template, requiredVariables) - Validates template syntax

Custom Handlebars Helpers

  • currency - Format numbers as currency (e.g., {{currency amount "USD"}} → "$1,500.50")
  • date - Format dates (e.g., {{date invoiceDate "long"}} → "October 24, 2025")
  • uppercase - Convert strings to uppercase (e.g., {{uppercase name}} → "JOHN DOE")
  • lowercase - Convert strings to lowercase
  • ifEquals - Conditional equality helper
  • ifGreater - Conditional greater-than helper

2. Updated CommunicationTemplatesService

File: apps/backend/src/communication-templates/application/communication-templates.service.ts

Changes:

  • Implemented OnModuleInit to register Handlebars helpers on startup
  • Updated preview() method to use renderHandlebarsTemplate() for both subject and body
  • Added proper error handling and logging
  • Removed TODO comments

3. Refactored TemplateRendererService

File: apps/backend/src/communications/application/services/template-renderer.service.ts

Changes:

  • Refactored to use shared utilities instead of duplicating code
  • Simplified render() method to use renderHandlebarsTemplate()
  • Simplified validateTemplate() to use validateHandlebarsTemplate()
  • Removed duplicate helper registration code

Benefits

  1. No Code Duplication - Handlebars helpers and rendering logic are centralized
  2. Maintainability - One place to update template rendering behavior
  3. Consistency - Both preview and actual sending use the same rendering logic
  4. Extensibility - Easy to add new Handlebars helpers in one place

Testing

Test 1: Basic Variable Substitution

Endpoint: POST /communication-templates/e3f81a22-1c0c-4850-8984-87fb425317d1/preview

Variables:

{
"businessName": "Acme Corp",
"inviterName": "John Doe",
"inviteeEmail": "jane@example.com",
"roleName": "Manager",
"acceptInviteLink": "https://flowpos.com/invite/accept?token=xyz123",
"expirationDate": "2025-12-31"
}

Result: ✅ All variables correctly substituted in both subject and body

Test 2: Custom Handlebars Helpers

Template:

  • Subject: Invoice for {{uppercase customerName}}
  • Body: Contains {{currency amount "USD"}}, {{date invoiceDate "long"}}, and {{#ifGreater amount 1000}}

Variables:

{
"customerName": "john smith",
"amount": 1500.50,
"invoiceDate": "2025-10-24"
}

Results:

  • ✅ uppercase: "john smith" → "JOHN SMITH"
  • ✅ currency: 1500.50 → "$1,500.50"
  • ✅ date: "2025-10-24" → "October 23, 2025"
  • ✅ ifGreater: Conditional showed "This is a large order!" (1500.50 > 1000)

API Usage

Corrected curl Command

curl --location --request POST 'http://localhost:4000/communication-templates/{template-id}/preview' \
--header 'Authorization: Bearer {your-token}' \
--header 'Content-Type: application/json' \
--data-raw '{
"variables": {
"variableName1": "value1",
"variableName2": "value2"
}
}'

Example Response

{
"subject": "You're invited to join Acme Corp now!!!",
"body": "<!DOCTYPE html>...rendered HTML with all variables replaced..."
}

Files Modified

  1. apps/backend/src/communication-templates/utils/handlebars-helpers.ts (NEW)
  2. apps/backend/src/communication-templates/application/communication-templates.service.ts (MODIFIED)
  3. apps/backend/src/communications/application/services/template-renderer.service.ts (MODIFIED)

Files Staged for Commit

All changes should be staged and committed with the Phase 2 implementation.

Next Steps

None - implementation is complete and tested.

Notes

  • Handlebars helpers are registered once when the module initializes (not on every render)
  • Both CommunicationTemplatesService and TemplateRendererService can register helpers independently (Handlebars handles duplicate registrations gracefully)
  • The preview endpoint now provides a full preview of what emails will look like when sent