DumbWareio_DumbAssets/MAINTENANCE_NOTIFICATION_FIXES.md
2025-05-26 23:05:21 -05:00

10 KiB

🔧 MAINTENANCE NOTIFICATION SYSTEM - CRITICAL FIXES

🚨 CRITICAL DATE CALCULATION BUG - FIXED

ISSUE: "Today" Events Showing as -1 Days Remaining (CRITICAL)

Problem:

  • Warranties and maintenance events expiring "today" were showing as -1 days remaining instead of 0
  • This was causing missed notifications for events due on the current day
  • Root cause: Time-based date comparison instead of date-only comparison

Technical Details:

  • Cron runs at 12:01 PM daily
  • When comparing a warranty expiring "today" (2025-05-26 00:00:00) with current time (2025-05-26 12:01:00)
  • The difference is approximately -0.5 days (12 hours past midnight)
  • Math.floor(-0.5) = -1 instead of expected 0

Solution:

  • Modified both warranty and maintenance date calculations to compare dates at start-of-day level
  • This ensures events due "today" correctly show as 0 days remaining
// OLD (PROBLEMATIC):
const daysOut = Math.floor(expDate.diff(now, 'days').days);
const daysUntilEvent = Math.floor(eventDate.diff(now, 'days').days);

// NEW (FIXED):
const todayStart = now.startOf('day');
const expDateStart = expDate.startOf('day');
const daysOut = Math.floor(expDateStart.diff(todayStart, 'days').days);

const eventDateStart = eventDate.startOf('day');
const daysUntilEvent = Math.floor(eventDateStart.diff(todayStart, 'days').days);

Impact:

  • Warranties expiring today now correctly show 0 days remaining
  • Maintenance events due today now correctly show 0 days remaining
  • All other date calculations remain accurate
  • No missed notifications for events due on current day

🚨 ISSUES IDENTIFIED & RESOLVED

1. TIMEZONE MISMATCH (HIGH RISK) - FIXED

Problem:

  • Dates were compared in UTC (toISOString().split('T')[0]) while cron ran in local timezone
  • Could cause off-by-one day errors where maintenance is missed or triggered on wrong day

Solution:

  • Implemented robust timezone handling using Luxon DateTime library
  • All date operations now use configured timezone (process.env.TZ || 'America/Chicago')
  • Added getTodayString() and toDateString() functions for consistent timezone handling
// OLD (PROBLEMATIC):
const today = now.toISOString().split('T')[0]; // UTC
const dueDateStr = dueDate.toISOString().split('T')[0]; // UTC

// NEW (FIXED):
const today = getTodayString(); // Configured timezone
const dueDateStr = toDateString(dueDate); // Configured timezone

2. DATE PARSING FRAGILITY (HIGH RISK) - FIXED

Problem:

  • Basic new Date() parsing could fail silently with invalid dates
  • No validation of date formats
  • Different parsing methods in different parts of the code

Solution:

  • Created robust parseDate() function that handles multiple formats:
    • ISO format (YYYY-MM-DD)
    • MM/DD/YYYY format
    • Date objects, timestamps
    • Proper error handling and logging
// OLD (PROBLEMATIC):
const dueDate = new Date(nextDueDate);
if (isNaN(dueDate)) // Might miss edge cases

// NEW (FIXED):
const dueDate = parseDate(nextDueDate);
if (!dueDate) // Comprehensive validation

3. DATE CALCULATION ERRORS (MEDIUM-HIGH RISK) - FIXED

Problem:

  • Month arithmetic using setMonth() had edge cases (Jan 31 + 1 month = March 3)
  • No validation of calculated dates
  • Could result in invalid dates or skipped months

Solution:

  • Implemented addTimePeriod() function using Luxon's robust date arithmetic
  • Proper handling of month/year boundaries
  • Validation of calculated results
// OLD (PROBLEMATIC):
switch (frequencyUnit) {
    case 'months':
        nextDate.setMonth(dueDate.getMonth() + parseInt(frequency));
        break;
}

// NEW (FIXED):
const nextDate = addTimePeriod(dueDate, numericFrequency, frequencyUnit);
if (!nextDate) {
    debugLog(`[ERROR] Could not calculate next due date`);
    return false;
}

4. MISSING VALIDATION (MEDIUM RISK) - FIXED

Problem:

  • No validation of frequency being a valid positive number
  • No validation of frequencyUnit being valid
  • No error handling for invalid maintenance event configurations

Solution:

  • Added comprehensive validation in validateMaintenanceEvent() function
  • Validates all required fields before processing
  • Validates frequency numbers and units
  • Proper error logging for debugging

5. TRACKING SYSTEM GAPS (MEDIUM RISK) - FIXED

Problem:

  • Missing events if server was down on exact due date
  • No retry logic or safety nets
  • No cleanup of old tracking records

Solution:

  • Added overdue detection (notifications for 1-3 days past due) REMOVED - Overdue detection removed per user request
  • Implemented tracking record cleanup
  • Added safety checks for past-due maintenance REMOVED - No longer checking for overdue events
  • Enhanced duplicate prevention

6. ERROR HANDLING & MONITORING - ADDED

New Features:

  • Comprehensive error handling throughout the system
  • Detailed logging for debugging
  • Summary reports after each maintenance check
  • Graceful handling of individual failures without stopping the entire process
  • Enhanced warranty notifications with same comprehensive logging and error handling

7. WARRANTY NOTIFICATION ENHANCEMENTS - ADDED

Problem:

  • Warranty notifications had basic logging compared to maintenance notifications
  • No comprehensive error handling or summary reports
  • Missing timezone consistency and robust date parsing

Solution:

  • Applied same robust date parsing using parseDate() function
  • Added comprehensive error handling for individual warranty processing
  • Implemented detailed summary reporting matching maintenance system
  • Added expired warranty detection (1-7 days past expiration)
  • Enhanced logging with asset type differentiation (Asset vs Component)
  • Consolidated notification threshold logic for cleaner code

New Warranty Features:

// Robust date parsing and validation
const expDate = parseDate(warranty.expirationDate);
if (!expDate) {
    debugLog(`[WARNING] Invalid warranty expiration date for ${assetType}: ${asset.name}`);
    return;
}

// Comprehensive summary reporting
debugLog(`[SUMMARY] Warranty check completed for ${today}:`);
debugLog(`  - Assets checked: ${totalChecked} (${assets.length} main assets, ${subAssets.length} components)`);
debugLog(`  - Total warranties: ${totalWarranties}`);
debugLog(`  - Notifications sent successfully: ${successfulNotifications}`);
debugLog(`  - Notification settings: 1M=${notify1Month}, 2W=${notify2Week}, 7D=${notify7Day}, 3D=${notify3Day}`);

// Expired warranty safety checks
if (daysOut >= -7 && daysOut < 0) {
    debugLog(`[WARNING] ${warrantyType} expired ${Math.abs(daysOut)} days ago for ${assetType}: ${asset.name}`);
}

🛡️ SAFETY MECHANISMS ADDED

1. Duplicate Prevention

  • Tracking keys prevent duplicate notifications
  • Separate tracking for advance, due date, and overdue notifications

2. Data Validation

  • All dates parsed and validated before processing
  • Invalid events are skipped with logging
  • Malformed data doesn't crash the system

3. Comprehensive Logging

// Maintenance Summary
debugLog(`[SUMMARY] Maintenance check completed for ${today}:`);
debugLog(`  - Assets checked: ${totalChecked}`);
debugLog(`  - Notifications sent successfully: ${successfulNotifications}`);
debugLog(`  - Notifications failed: ${failedNotifications}`);

// Warranty Summary (NEW)
debugLog(`[SUMMARY] Warranty check completed for ${today}:`);
debugLog(`  - Assets checked: ${totalChecked} (${assets.length} main assets, ${subAssets.length} components)`);
debugLog(`  - Total warranties: ${totalWarranties}`);
debugLog(`  - Notifications queued: ${notificationsToSend.length}`);
debugLog(`  - Notifications sent successfully: ${successfulNotifications}`);
debugLog(`  - Notifications failed: ${failedNotifications}`);
debugLog(`  - Notification settings: 1M=${notify1Month}, 2W=${notify2Week}, 7D=${notify7Day}, 3D=${notify3Day}`);

🧪 TESTING RECOMMENDATIONS

1. Date Edge Cases

Test maintenance events with:

  • February 29th (leap year)
  • Month-end dates (Jan 31 + 1 month)
  • Timezone transitions (DST changes)
  • Invalid date formats

2. Server Downtime Scenarios

  • Test overdue notifications work when server is down on due date
  • Verify no duplicate notifications after restart

3. Data Validation

  • Test with malformed maintenance event data
  • Verify system continues processing other events when one fails

4. Timezone Testing

  • Test with different timezone configurations
  • Verify dates align correctly between frontend and backend

📋 DEPLOYMENT CHECKLIST

  • Verify TZ environment variable is set correctly
  • Test maintenance notifications in staging environment
  • Monitor logs for any date parsing warnings
  • Verify existing maintenance tracking data migrates correctly
  • Test both frequency-based and specific date events
  • Confirm overdue notifications work as expected

🔍 MONITORING POINTS

Watch for these log messages after deployment:

Good Signs:

  • [SUMMARY] Maintenance check completed
  • [SUMMARY] Warranty check completed
  • [DEBUG] Maintenance tracking data saved successfully
  • Maintenance check completed: X/Y notifications sent successfully
  • Warranty check completed: X/Y notifications sent successfully

Warning Signs:

  • [WARNING] Invalid frequency unit
  • [WARNING] Maintenance event missing nextDueDate
  • [WARNING] Invalid warranty expiration date
  • [WARNING] Secondary Warranty expired X days ago
  • [ERROR] Failed to send maintenance notification
  • [ERROR] Failed to send warranty notification

Critical Issues:

  • [ERROR] Date parsing failed
  • [ERROR] Failed to save maintenance tracking data
  • [ERROR] Exception while updating asset files
  • [ERROR] Error processing asset
  • [ERROR] Error processing sub-asset

The maintenance notification system is now robust, with proper timezone handling, comprehensive validation, error recovery, and safety mechanisms to ensure users never miss critical maintenance events.