# Email Notification Implementation Plan ## πŸ“Š **Current State Analysis** ### **Existing Notification Types in System:** Based on codebase analysis, your system currently sends **in-app notifications** for: | Notification Type | Current Method | Should Send Email? | |-------------------|----------------|-------------------| | `request_submitted` | In-app | βœ… YES (High) | | `assignment` | In-app | βœ… YES (High) | | `approval` | In-app | βœ… YES (High) | | `rejection` | In-app | βœ… YES (Critical) | | `workflow_paused` | In-app | ⚠️ CONDITIONAL | | `workflow_resumed` | In-app | βœ… YES (High) | | `pause_retrigger_request` | In-app | ⚠️ CONDITIONAL | | `pause_retriggered` | In-app | ❌ NO (In-app only) | | `tat_reminder` (50%) | In-app | βœ… YES (Medium) | | `tat_reminder` (75%) | In-app | βœ… YES (High) | | `tat_breach` (100%) | In-app | βœ… YES (Critical) | | `mention` (work notes) | In-app | ❌ NO (In-app only) | | `comment` | In-app | ❌ NO (In-app only) | | `status_change` | In-app | ❌ NO (In-app only) | | `document_added` | In-app | ❌ NO (In-app only) | | `ai_conclusion_generated` | In-app | ❌ NO (In-app only) | | `summary_generated` | In-app | ❌ NO (In-app only) | | `approval_pending_closure` | In-app | ⚠️ CONDITIONAL | | `auto-resume-workflow` | In-app | ❌ NO (System) | | `closed` | In-app | βœ… YES (Low) | --- ## 🎯 **Email vs In-App Notification Strategy** ### **βœ… SEND EMAIL (High Impact, Action Required)** **Criteria:** - Requires user action - Time-sensitive - Critical for workflow progress - User might not be logged in **Scenarios:** 1. **Request Created** β†’ Send to Initiator (confirmation) 2. **Approval Request** β†’ Send to Approver (action required) 3. **Request Approved** β†’ Send to Initiator (important update) 4. **Request Rejected** β†’ Send to Initiator (critical) 5. **TAT Reminder 50%** β†’ Send to Approver (early warning) 6. **TAT Reminder 75%** β†’ Send to Approver (urgent) 7. **TAT Breached 100%** β†’ Send to Approver + Management (critical) 8. **Workflow Resumed** β†’ Send to Current Approver (action needed) 9. **Request Closed** β†’ Send to All Participants (summary) ### **❌ IN-APP ONLY (Low Impact, Real-time)** **Criteria:** - Real-time collaboration - Minor updates - User likely logged in - Frequent notifications **Scenarios:** 1. **@Mentions in Work Notes** β†’ In-app only 2. **Comments Added** β†’ In-app only 3. **Documents Uploaded** β†’ In-app only 4. **Status Changes** β†’ In-app only 5. **AI Conclusion Generated** β†’ In-app only 6. **Summary Generated** β†’ In-app only 7. **Pause Retriggered** β†’ In-app only ### **⚠️ CONDITIONAL (Based on Settings)** **Scenarios:** 1. **Workflow Paused** β†’ Email if paused > 24 hours 2. **Participant Added** β†’ Email if user preference enabled 3. **Approver Skipped** β†’ Email to skipped approver only --- ## πŸ“‹ **Template Mapping to Scenarios** ### **Critical Priority Emails (Send Immediately)** | Scenario | Template | Trigger Point | Recipients | |----------|----------|---------------|------------| | TAT Breached | `getTATBreachedEmail()` | TAT timer breach | Approver, Management | | Request Rejected | `getRejectionNotificationEmail()` | Approver rejects | Initiator, Spectators | ### **High Priority Emails (Send within 1 minute)** | Scenario | Template | Trigger Point | Recipients | |----------|----------|---------------|------------| | Request Created | `getRequestCreatedEmail()` | Workflow created | Initiator | | Approval Request | `getApprovalRequestEmail()` or `getMultiApproverRequestEmail()` | Level assigned | Approver | | Request Approved | `getApprovalConfirmationEmail()` | Approver approves | Initiator | | TAT Reminder | `getTATReminderEmail()` | 80% TAT elapsed | Approver | | Workflow Resumed | `getWorkflowResumedEmail()` | Workflow resumed | Approver, Initiator | ### **Medium Priority Emails (Send within 5 minutes)** | Scenario | Template | Trigger Point | Recipients | |----------|----------|---------------|------------| | Workflow Paused (>24h) | `getWorkflowPausedEmail()` | Long pause | Approver, Initiator | | Participant Added | `getParticipantAddedEmail()` | User preference | New participant | | Approver Skipped | `getApproverSkippedEmail()` | Skip action | Skipped approver | ### **Low Priority Emails (Batch send)** | Scenario | Template | Trigger Point | Recipients | |----------|----------|---------------|------------| | Request Closed | `getRequestClosedEmail()` | Workflow closed | All participants | --- ## πŸ” **CRITICAL: Email Preference Control** ### **Two-Level Preference System:** ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Email Notification Request β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Admin Level β”‚ β”‚ Enabled? β”‚ ──NO──> ❌ Don't send (admin disabled) β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ YES β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ User Level β”‚ β”‚ Enabled? β”‚ ──NO──> ❌ Don't send (user disabled) β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ YES β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ βœ… Send Email β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ IMPORTANT: Activity logs are ALWAYS captured regardless of preferences! ``` ### **Preference Logic:** ```typescript // Check before sending ANY email const shouldSend = await shouldSendEmail(userId, EmailNotificationType.APPROVAL_REQUEST); if (shouldSend) { await emailService.sendEmail(...); } else { logger.info('Email skipped due to preferences'); } // Activity ALWAYS logged regardless await activityService.log({ type: 'assignment', // ... activity data }); ``` ### **Critical Emails (Override User Preference):** Some emails are TOO important to be disabled by users: - βœ… **Request Rejected** - User must know - βœ… **TAT Breached** - Critical escalation For these, only admin can disable (user preference ignored): ```typescript if (CRITICAL_EMAILS.includes(emailType)) { // Check admin only, ignore user preference const adminEnabled = await isAdminEmailEnabled(emailType); if (adminEnabled) return true; } ``` --- ## πŸ”§ **Implementation Architecture** ### **Phase 0: Preference System (REQUIRED FIRST)** Create preference checking before ANY email: **A. Email Preferences Helper** (`emailPreferences.helper.ts`) βœ… Created **B. System Config Table:** ```sql -- Admin-level email controls INSERT INTO system_configs (config_key, config_value, description) VALUES ('email.enabled', 'true', 'Global email notifications enabled/disabled'), ('email.request_created.enabled', 'true', 'Request created emails'), ('email.approval_request.enabled', 'true', 'Approval request emails'), ('email.request_approved.enabled', 'true', 'Approval confirmation emails'), ('email.request_rejected.enabled', 'true', 'Rejection emails (critical)'), ('email.tat_reminder_50.enabled', 'true', 'TAT 50% reminder emails'), ('email.tat_reminder_75.enabled', 'true', 'TAT 75% reminder emails'), ('email.tat_breached.enabled', 'true', 'TAT breach emails (critical)'), ('email.workflow_resumed.enabled', 'true', 'Workflow resumed emails'), ('email.request_closed.enabled', 'true', 'Request closed emails'); ``` **C. User Preferences Table:** ```json // UserPreference.preferences column (JSONB) { "email": { "enabled": true, // Global email preference "request_created": true, "approval_request": true, "request_approved": true, "request_rejected": true, // Can be overridden for critical "tat_reminder_50": true, "tat_reminder_75": true, "tat_breached": true, // Can be overridden for critical "workflow_resumed": true, "request_closed": false // User can opt-out of closure emails }, "notification": { "enabled": true, "mention": true, "comment": true, "assignment": true, "status_change": true } } ``` ### **Phase 1: Email Service Creation** Create `email.service.ts`: ```typescript import nodemailer from 'nodemailer'; import { getRequestCreatedEmail, getApprovalRequestEmail, // ... all template functions } from '@/emailtemplates'; export class EmailService { private transporter: nodemailer.Transporter; constructor() { this.transporter = nodemailer.createTransport({ host: process.env.SMTP_HOST, port: parseInt(process.env.SMTP_PORT || '587'), secure: process.env.SMTP_SECURE === 'true', auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASSWORD } }); } async sendEmail(to: string, subject: string, html: string): Promise { try { await this.transporter.sendMail({ from: process.env.EMAIL_FROM, to, subject, html }); logger.info(`βœ… Email sent to ${to}: ${subject}`); } catch (error) { logger.error(`❌ Failed to send email to ${to}:`, error); throw error; } } } export const emailService = new EmailService(); ``` ### **Phase 2: Email Notification Service** Create `emailNotification.service.ts`: ```typescript import { emailService } from './email.service'; import { getRequestCreatedEmail, getApprovalRequestEmail, getMultiApproverRequestEmail, getApprovalConfirmationEmail, getRejectionNotificationEmail, getTATReminderEmail, getTATBreachedEmail, getWorkflowPausedEmail, getWorkflowResumedEmail, getParticipantAddedEmail, getApproverSkippedEmail, getRequestClosedEmail, getViewDetailsLink } from '@/emailtemplates'; export class EmailNotificationService { /** * Send request created email to initiator */ async sendRequestCreated(request: any, initiator: any, firstApprover: any) { const data = { recipientName: initiator.name, requestId: request.requestNumber, requestTitle: request.title, initiatorName: initiator.name, firstApproverName: firstApprover.name, requestType: request.type, priority: request.priority, requestDate: formatDate(request.createdAt), requestTime: formatTime(request.createdAt), totalApprovers: request.totalApprovers, expectedTAT: request.tatHours, viewDetailsLink: getViewDetailsLink(request.requestNumber), companyName: 'Royal Enfield' }; const html = getRequestCreatedEmail(data); await emailService.sendEmail( initiator.email, `[${request.requestNumber}] Request Created Successfully`, html ); } /** * Send approval request email to approver */ async sendApprovalRequest(request: any, approver: any, initiator: any, isMultiLevel: boolean) { if (isMultiLevel) { // Use multi-approver template with approval chain const data = { recipientName: approver.name, requestId: request.requestNumber, approverName: approver.name, initiatorName: initiator.name, requestType: request.type, requestDescription: request.description, priority: request.priority, requestDate: formatDate(request.createdAt), requestTime: formatTime(request.createdAt), approverLevel: approver.levelNumber, totalApprovers: request.totalApprovers, approversList: buildApprovalChain(request.approvalLevels, approver.levelNumber), viewDetailsLink: getViewDetailsLink(request.requestNumber), companyName: 'Royal Enfield' }; const html = getMultiApproverRequestEmail(data); await emailService.sendEmail( approver.email, `[${request.requestNumber}] Multi-Level Approval Request - Your Turn`, html ); } else { // Use single approver template const data = { recipientName: approver.name, requestId: request.requestNumber, approverName: approver.name, initiatorName: initiator.name, requestType: request.type, requestDescription: request.description, priority: request.priority, requestDate: formatDate(request.createdAt), requestTime: formatTime(request.createdAt), viewDetailsLink: getViewDetailsLink(request.requestNumber), companyName: 'Royal Enfield' }; const html = getApprovalRequestEmail(data); await emailService.sendEmail( approver.email, `[${request.requestNumber}] Approval Request - Action Required`, html ); } } // ... Add methods for other email types } export const emailNotificationService = new EmailNotificationService(); ``` ### **Phase 3: Integration Points** Update existing services to send emails alongside in-app notifications: #### **A. workflow.service.ts - createWorkflow()** ```typescript // After creating workflow (around line 2362) import { shouldSendEmail, shouldSendInAppNotification, EmailNotificationType } from '@/emailtemplates/emailPreferences.helper'; // Check preferences before sending in-app notification const sendInAppToInitiator = await shouldSendInAppNotification( initiatorId, 'request_submitted' ); if (sendInAppToInitiator) { await notificationService.sendToUsers([initiatorId], { title: 'Request Submitted Successfully', body: `Your request "${workflowData.title}" has been submitted...`, type: 'request_submitted', priority: 'MEDIUM' }); } // Check preferences before sending email const sendEmailToInitiator = await shouldSendEmail( initiatorId, EmailNotificationType.REQUEST_CREATED ); if (sendEmailToInitiator) { await emailNotificationService.sendRequestCreated( workflow, initiator, firstApprover ); } // APPROVER NOTIFICATION const sendInAppToApprover = await shouldSendInAppNotification( approverId, 'assignment' ); if (sendInAppToApprover) { await notificationService.sendToUsers([approverId], { title: 'New Request Assigned', type: 'assignment', priority: 'HIGH', actionRequired: true }); } // Check preferences before sending email to approver const sendEmailToApprover = await shouldSendEmail( approverId, EmailNotificationType.APPROVAL_REQUEST ); if (sendEmailToApprover) { const isMultiLevel = approvalLevels.length > 1; await emailNotificationService.sendApprovalRequest( workflow, approver, initiator, isMultiLevel ); } // ACTIVITY LOG - Always captured regardless of preferences await activityService.log({ requestId: workflow.requestId, type: 'created', user: { userId: initiatorId, name: initiatorName }, timestamp: new Date().toISOString(), action: 'Request created', details: `Request ${requestNumber} created and assigned to ${approverName}` }); ``` #### **B. approval.service.ts - approveRequest()** ```typescript // After approval (around line 134) // EXISTING: In-app notification await notificationService.sendToUsers([initiatorId], { title: 'Request Approved', type: 'approval', priority: 'HIGH' }); // NEW: Send email await emailNotificationService.sendApprovalConfirmation( request, approver, initiator, isFinalApproval, nextApprover ); ``` #### **C. approval.service.ts - rejectRequest()** ```typescript // After rejection (around line 513) // EXISTING: In-app notification await notificationService.sendToUsers([initiatorId], { title: 'Request Rejected', type: 'rejection', priority: 'HIGH' }); // NEW: Send email (CRITICAL) await emailNotificationService.sendRejectionNotification( request, approver, initiator, rejectionReason ); ``` #### **D. tatProcessor.ts - TAT Notifications** ```typescript // TAT Reminder (80%) if (type === 'threshold1') { // In-app notification await notificationService.sendToUsers([approverId], {...}); // Email notification await emailNotificationService.sendTATReminder(request, approver); } // TAT Breached if (type === 'breach') { // In-app notification await notificationService.sendToUsers([approverId], {...}); // Email notification (CRITICAL) await emailNotificationService.sendTATBreached( request, approver, managementUsers // Also notify management ); } ``` #### **E. pause.service.ts - Pause/Resume** ```typescript // Workflow Paused await notificationService.sendToUsers([...], {...}); // Email ONLY if pause > 24 hours const pauseDuration = dayjs(resumeDate).diff(dayjs(), 'hours'); if (pauseDuration > 24) { await emailNotificationService.sendWorkflowPaused(...); } // Workflow Resumed await notificationService.sendToUsers([...], {...}); await emailNotificationService.sendWorkflowResumed(...); ``` --- ## 🎯 **Email Sending Decision Tree** ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Notification Triggered β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Is Critical? β”‚ ──YES──> Send Email Immediately β”‚ (Rejection, β”‚ (Critical Priority) β”‚ TAT Breach) β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ NO β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Requires β”‚ ──YES──> Send Email β”‚ Action? β”‚ (High Priority) β”‚ (Approval, β”‚ β”‚ Assignment) β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ NO β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Important β”‚ ──YES──> Send Email β”‚ Update? β”‚ (Medium Priority) β”‚ (Approved, β”‚ β”‚ Resumed) β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ NO β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Real-time β”‚ ──YES──> In-App ONLY β”‚ Interaction? β”‚ (No email) β”‚ (@mention, β”‚ β”‚ comment, β”‚ β”‚ status) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ“§ **Email Scenarios - Detailed Implementation** ### **Scenario 1: Request Created** **When:** User submits a new workflow request **Template:** `getRequestCreatedEmail()` **Recipients:** Initiator (confirmation) **Priority:** High **Also Send In-App:** Yes **Integration Point:** ```typescript // File: services/workflow.service.ts // Method: createWorkflow() // Line: ~2362-2373 // Add after in-app notification await emailNotificationService.sendRequestCreated( workflow, initiatorUser, firstApproverUser ); ``` --- ### **Scenario 2: Approval Request (Assignment)** **When:** Request assigned to approver **Template:** `getApprovalRequestEmail()` OR `getMultiApproverRequestEmail()` **Recipients:** Approver **Priority:** High **Also Send In-App:** Yes **Action Required:** YES **Decision Logic:** - If `totalApprovers > 1` β†’ Use `MultiApproverRequest` template - If `totalApprovers === 1` β†’ Use `ApprovalRequest` template **Integration Point:** ```typescript // File: services/workflow.service.ts // Method: createWorkflow() // Line: ~2374-2396 // Add after in-app notification to approver const isMultiLevel = approvalLevels.length > 1; await emailNotificationService.sendApprovalRequest( workflow, approverUser, initiatorUser, isMultiLevel ); ``` --- ### **Scenario 3: Request Approved** **When:** Approver approves the request **Template:** `getApprovalConfirmationEmail()` **Recipients:** Initiator **Priority:** High **Also Send In-App:** Yes **Integration Point:** ```typescript // File: services/approval.service.ts // Method: approveRequest() // Line: ~134-145 // Add after in-app notification await emailNotificationService.sendApprovalConfirmation( workflow, approverUser, initiatorUser, isFinalApproval, nextApproverUser ); ``` --- ### **Scenario 4: Request Rejected** **When:** Approver rejects the request **Template:** `getRejectionNotificationEmail()` **Recipients:** Initiator, Spectators **Priority:** CRITICAL **Also Send In-App:** Yes **Integration Point:** ```typescript // File: services/approval.service.ts // Method: rejectRequest() // Line: ~513-525 // Add after in-app notification await emailNotificationService.sendRejectionNotification( workflow, approverUser, initiatorUser, rejectionReason ); ``` --- ### **Scenario 5: TAT Reminders (3 Levels)** **When:** 50%, 75%, and 100% (breach) of TAT elapsed **Template:** `getTATReminderEmail()` (50%, 75%), `getTATBreachedEmail()` (100%) **Recipients:** Approver **Priority:** Medium (50%), High (75%), Critical (100%) **Also Send In-App:** Yes **Integration Point:** ```typescript // File: queues/tatProcessor.ts // Update TAT thresholds to: 50%, 75%, 100% (breach) // TAT 50% - Early Warning if (elapsedPercentage >= 50 && !reminded50) { // In-app notification await notificationService.sendToUsers([approverId], { title: 'TAT Reminder - 50% Elapsed', type: 'tat_reminder_50', priority: 'MEDIUM' }); // Email (check preferences) const shouldEmail = await shouldSendEmail( approverId, EmailNotificationType.TAT_REMINDER_50 ); if (shouldEmail) { await emailNotificationService.sendTATReminder( workflow, approver, { threshold: 50, timeRemaining: '...' } ); } } // TAT 75% - Urgent Warning if (elapsedPercentage >= 75 && !reminded75) { // In-app notification await notificationService.sendToUsers([approverId], { title: 'TAT Reminder - 75% Elapsed', type: 'tat_reminder_75', priority: 'HIGH' }); // Email (check preferences) const shouldEmail = await shouldSendEmail( approverId, EmailNotificationType.TAT_REMINDER_75 ); if (shouldEmail) { await emailNotificationService.sendTATReminder( workflow, approver, { threshold: 75, timeRemaining: '...' } ); } } // TAT 100% - BREACH (Critical) if (elapsedPercentage >= 100) { // In-app notification await notificationService.sendToUsers([approverId], { title: 'TAT BREACHED', type: 'tat_breach', priority: 'URGENT' }); // Email (CRITICAL - check with override) const shouldEmail = await shouldSendEmailWithOverride( approverId, EmailNotificationType.TAT_BREACHED ); if (shouldEmail) { await emailNotificationService.sendTATBreached( workflow, approver, { timeOverdue: '...' } ); // Also notify management const mgmtUsers = await getManagementUsers(); for (const mgmt of mgmtUsers) { await emailNotificationService.sendTATBreached( workflow, mgmt, { timeOverdue: '...' } ); } } } ``` **Note:** Activity logs are captured at ALL TAT thresholds regardless of email/notification preferences! --- ### **Scenario 6: TAT Breached** **When:** TAT deadline passed **Template:** `getTATBreachedEmail()` **Recipients:** Approver, Management (escalation) **Priority:** CRITICAL **Also Send In-App:** Yes **Integration Point:** ```typescript // File: queues/tatProcessor.ts // When: breach occurs // Line: ~250-265 if (type === 'breach') { // Existing in-app notification await notificationService.sendToUsers([...]); // Add email to approver await emailNotificationService.sendTATBreached( workflow, approverUser, tatData ); // Also notify management const managementUsers = await getManagementUsers(); for (const mgmt of managementUsers) { await emailNotificationService.sendTATBreached( workflow, mgmt, tatData ); } } ``` --- ### **Scenario 7: Workflow Resumed** **When:** Paused workflow resumes (auto or manual) **Template:** `getWorkflowResumedEmail()` **Recipients:** Current Approver, Initiator **Priority:** High **Also Send In-App:** Yes **Integration Point:** ```typescript // File: services/pause.service.ts // Method: resumeWorkflow() // Line: ~455-510 // Add after in-app notifications await emailNotificationService.sendWorkflowResumed( workflow, approverUser, initiatorUser, resumedByUser, pauseDuration ); ``` --- ### **Scenario 8: Request Closed** **When:** Initiator closes the request after all approvals **Template:** `getRequestClosedEmail()` **Recipients:** All participants (approvers, spectators) **Priority:** Low (can be batched) **Also Send In-App:** Yes **Integration Point:** ```typescript // File: controllers/conclusion.controller.ts // Method: finalizeConclusion() // Line: ~365-380 // Add after workflow closure const allParticipants = await getRequestParticipants(requestId); for (const participant of allParticipants) { await emailNotificationService.sendRequestClosed( workflow, participant, conclusionData ); } ``` --- ## 🚫 **DO NOT Send Email For:** ### **Real-Time Collaboration (In-App Only):** 1. **@Mentions in Work Notes** - Type: `mention` - Why: Real-time, user is likely active - Keep: In-app notification only 2. **Comments/Work Notes Added** - Type: `comment` - Why: Frequent, real-time discussion - Keep: In-app notification only 3. **Documents Uploaded** - Type: `document_added` - Why: Minor update, user can see in activity - Keep: In-app notification only 4. **Status Changes** - Type: `status_change` - Why: Covered by other email notifications - Keep: In-app notification only 5. **AI/Summary Generation** - Type: `ai_conclusion_generated`, `summary_generated` - Why: Background process, not urgent - Keep: In-app notification only 6. **System Events** - Type: `auto-resume-workflow` - Why: System-triggered, covered by resume email - Keep: In-app notification only --- ## πŸ”„ **Implementation Phases** ### **Phase 1: Core Email Service (Week 1)** - [ ] Create `email.service.ts` - [ ] Configure SMTP with nodemailer - [ ] Test email sending with test account - [ ] Add error handling and retry logic ### **Phase 2: Email Notification Service (Week 1-2)** - [ ] Create `emailNotification.service.ts` - [ ] Implement all 12 template functions - [ ] Add data formatting helpers - [ ] Test with sample data ### **Phase 3: Critical Notifications (Week 2)** - [ ] Integrate TAT Breached emails - [ ] Integrate Rejection emails - [ ] Test critical scenarios ### **Phase 4: High Priority Notifications (Week 2-3)** - [ ] Integrate Request Created emails - [ ] Integrate Approval Request emails - [ ] Integrate Approval Confirmation emails - [ ] Integrate TAT Reminder emails - [ ] Integrate Workflow Resumed emails ### **Phase 5: Medium/Low Priority (Week 3)** - [ ] Integrate Workflow Paused emails (conditional) - [ ] Integrate Participant Added emails (conditional) - [ ] Integrate Approver Skipped emails - [ ] Integrate Request Closed emails ### **Phase 6: Email Queue System (Week 4)** - [ ] Install Bull/BullMQ - [ ] Create email queue - [ ] Implement priority-based sending - [ ] Add retry mechanism - [ ] Monitor email delivery ### **Phase 7: User Preferences (Week 4-5)** - [ ] Add email preferences to user settings - [ ] Allow users to opt-in/out of certain emails - [ ] Keep critical emails always enabled - [ ] Add digest email option (daily summary) --- ## βš™οΈ **Environment Configuration** Add to `.env`: ```env # Email Service SMTP_HOST=smtp.gmail.com SMTP_PORT=587 SMTP_SECURE=false SMTP_USER=notifications@royalenfield.com SMTP_PASSWORD=your-app-specific-password EMAIL_FROM=RE Flow # Email Settings EMAIL_ENABLED=true EMAIL_QUEUE_ENABLED=true EMAIL_BATCH_SIZE=50 EMAIL_RETRY_ATTEMPTS=3 # Application BASE_URL=https://workflow.royalenfield.com COMPANY_NAME=Royal Enfield COMPANY_WEBSITE=https://www.royalenfield.com SUPPORT_EMAIL=support@royalenfield.com ``` --- ## πŸ“Š **Expected Email Volume** Based on typical workflow usage: | Email Type | Frequency | Daily Volume (Est.) | |------------|-----------|-------------------| | Request Created | Per new request | 20-50 | | Approval Request | Per assignment | 20-50 | | Approval Confirmation | Per approval | 15-40 | | Rejection | Occasional | 2-5 | | TAT Reminder | 80% threshold | 5-15 | | TAT Breached | Critical | 1-5 | | Workflow Resumed | Occasional | 2-10 | | Request Closed | Per closure | 10-30 | | **TOTAL** | | **75-205 emails/day** | **No emails** for @mentions, comments, documents (could be 100s per day). --- ## βœ… **Success Metrics** ### **Email Delivery:** - Delivery rate > 98% - Bounce rate < 2% - Open rate > 40% (approvers) - Click rate > 25% (View Details button) ### **User Experience:** - Reduced missed approvals - Faster TAT completion - Better stakeholder awareness - No email fatigue (not too many emails) --- ## πŸš€ **Next Steps** 1. **Review this plan** - Confirm scenarios and priorities 2. **Configure SMTP** - Set up email credentials 3. **Start with Phase 1** - Build email service 4. **Test thoroughly** - Use test account first 5. **Roll out gradually** - Start with critical emails only 6. **Monitor metrics** - Track delivery and engagement 7. **Gather feedback** - Adjust based on user preferences --- **Ready to start implementation?** 🎯