# Workflow Email Service Guide ## Overview This guide explains how to add new workflow-specific email services without breaking existing implementations. The architecture uses a factory pattern with interfaces to ensure isolation between different workflow types. ## Architecture ``` ┌─────────────────────────────────────┐ │ notification.service.ts │ │ (Main Router) │ └──────────────┬──────────────────────┘ │ ▼ ┌─────────────────────────────────────┐ │ workflowEmail.factory.ts │ │ (Factory Pattern) │ └──────────────┬──────────────────────┘ │ ┌───────┴───────┐ │ │ ▼ ▼ ┌──────────────┐ ┌──────────────┐ │ Dealer Claim │ │ Custom/ │ │ Email Service│ │ Default │ └──────────────┘ └──────────────┘ ``` ## Adding a New Workflow Type ### Step 1: Create the Email Service Create a new file: `Re_Backend/src/services/[workflowType]Email.service.ts` Example: `Re_Backend/src/services/vendorPaymentEmail.service.ts` ```typescript import { ApprovalLevel } from '@models/ApprovalLevel'; import { User } from '@models/User'; import logger from '@utils/logger'; import { IWorkflowEmailService } from './workflowEmail.interface'; import { emailNotificationService } from './emailNotification.service'; export class VendorPaymentEmailService implements IWorkflowEmailService { async sendAssignmentEmail( requestData: any, approverUser: User, initiatorData: any, currentLevel: ApprovalLevel | null, allLevels: ApprovalLevel[] ): Promise { try { // Your workflow-specific logic here // Example: Check if it's a vendor-specific step const levelName = currentLevel?.levelName || ''; const isVendorStep = levelName.toLowerCase().includes('vendor'); if (isVendorStep) { // Use vendor-specific template await this.sendVendorSpecificEmail(requestData, approverUser, initiatorData, currentLevel); } else { // Use standard template await this.sendStandardApprovalEmail(requestData, approverUser, initiatorData, currentLevel); } } catch (error) { logger.error(`[VendorPaymentEmail] Error sending assignment email:`, error); throw error; } } private async sendVendorSpecificEmail( requestData: any, vendorUser: User, initiatorData: any, currentLevel: ApprovalLevel | null ): Promise { // Implementation for vendor-specific email } private async sendStandardApprovalEmail( requestData: any, approverUser: User, initiatorData: any, currentLevel: ApprovalLevel | null ): Promise { // Implementation for standard approval email } } export const vendorPaymentEmailService = new VendorPaymentEmailService(); ``` ### Step 2: Register in Factory Update `Re_Backend/src/services/workflowEmail.factory.ts`: ```typescript import { vendorPaymentEmailService } from './vendorPaymentEmail.service'; class WorkflowEmailServiceFactory { getService(workflowType: string): IWorkflowEmailService { switch (workflowType) { case 'CLAIM_MANAGEMENT': return dealerClaimEmailService; case 'VENDOR_PAYMENT': // Add your new workflow type return vendorPaymentEmailService; default: return null as any; } } hasDedicatedService(workflowType: string): boolean { return workflowType === 'CLAIM_MANAGEMENT' || workflowType === 'VENDOR_PAYMENT'; // Add your new workflow type } } ``` ### Step 3: Create Email Templates (if needed) If your workflow needs custom templates, create them in: `Re_Backend/src/emailtemplates/[templateName].template.ts` Then add the send method to `emailNotification.service.ts`: ```typescript async sendVendorPaymentRequired( requestData: any, vendorData: any, initiatorData: any, paymentData?: any ): Promise { // Implementation } ``` ## Benefits of This Architecture 1. **Isolation**: Each workflow type has its own service, preventing cross-workflow breakage 2. **Scalability**: Easy to add new workflow types without modifying existing code 3. **Maintainability**: Changes to one workflow don't affect others 4. **Type Safety**: Interface ensures consistent implementation 5. **Testability**: Each service can be tested independently ## Best Practices 1. **Always implement IWorkflowEmailService**: Ensures consistency 2. **Use levelName, not levelNumber**: Handles additional approvers correctly 3. **Log workflow-specific actions**: Helps with debugging 4. **Handle errors gracefully**: Don't break the entire notification system 5. **Document workflow-specific logic**: Makes it easier for others to understand ## Example: Dealer Claim Service See `dealerClaimEmail.service.ts` for a complete example of: - Dynamic step identification - Multiple template types (proposal, completion, standard) - Additional approver handling - Proper error handling ## Testing When adding a new workflow type: 1. Test assignment emails for all steps 2. Test with additional approvers 3. Test with missing levelName (fallback to levelNumber) 4. Test error handling 5. Verify custom workflows still work (regression test)