import db from '../database/models/index.js'; const { SLATracking, SLAConfiguration, SLABreach, Application, User } = db; import { Op } from 'sequelize'; import { NotificationService } from './NotificationService.js'; export class SLAService { /** * Periodically check for SLA breaches across all active tracking records */ static async checkBreaches() { console.log('[SLA Service] Starting breach check...'); // Find all active tracking records that are still 'In Progress' (not concluded) const activeTracking = await SLATracking.findAll({ where: { isActive: true, isBreached: false, endTime: null }, include: [ { model: Application, as: 'application' } ] }); const now = new Date(); for (const track of activeTracking) { // Fetch SLA configuration for this specific stage and entity type const config = await SLAConfiguration.findOne({ where: { stageName: track.stageName, entityType: track.entityType, isActive: true } }); if (!config) continue; const startTime = new Date(track.startTime); const slaHours = config.slaHours; const deadline = new Date(startTime.getTime() + (slaHours * 60 * 60 * 1000)); if (now > deadline) { // BREACH DETECTED console.log(`[SLA Service] Breach detected for ${track.entityType}: ${track.application?.applicationId || track.entityId}, Stage: ${track.stageName}`); // Update tracking record await track.update({ isBreached: true }); // Create Breach Record await SLABreach.create({ trackingId: track.id, applicationId: track.applicationId, stageCode: track.stageName, breachedAt: now, severity: 'High', status: 'Open' }); // Notify Stakeholders (Escalation) await this.notifyEscalated(track); } } console.log(`[SLA Service] Breach check completed at ${now.toISOString()}`); } private static async notifyEscalated(track: any) { // Find the assigned user to notify them and potentially their manager const application = await Application.findByPk(track.applicationId, { include: [{ model: User, as: 'assignedToUser' }] }); if (application?.assignedToUser) { const portalBase = process.env.FRONTEND_URL || 'http://localhost:5173'; await NotificationService.notify(application.assignedTo, application.assignedToUser.email, { title: `SLA BREACH: ${track.stageName}`, message: `The application ${application.applicationId} has breached the SLA for ${track.stageName}. Current stage: ${application.currentStage}.`, channels: ['email', 'system'], templateCode: 'SLA_BREACH_WARNING', placeholders: { applicationId: application.applicationId || String(application.id), stageName: track.stageName, currentStage: application.currentStage || '', link: `${portalBase}/applications/${application.id}`, ctaLabel: 'Open application' }, metadata: { type: 'error', applicationId: application.id } }); } } }