```html

Building Real-Time Task Notifications for the Maintenance Dashboard: Event-Driven Architecture with Google Apps Script and Lambda

The Problem

The maintenance.queenofsandiego.com tool was missing a critical workflow piece: when Travis or other team members added new maintenance tasks, there was no mechanism to surface these changes or notify stakeholders like Sergio. Tasks were being added to the system, but visibility into new entries was completely absent. This created a coordination gap that could delay critical maintenance work on the Queen of San Diego.

What Was Built

We implemented an event-driven notification system that detects new maintenance tasks and routes notifications based on task criticality. The architecture consists of four integrated components:

  • Persistence Layer - Google Apps Script file storing task metadata
  • Notification Handler - Google Apps Script doPost route triggering emails
  • Lambda Worker - Asynchronous task processing and email dispatch
  • Frontend Integration - Modified HTML UI with task submission webhook

Technical Architecture and Implementation

1. Persistence Layer: MaintenancePersistence.gs

We created a new Google Apps Script file at /Users/cb/Documents/repos/sites/queenofsandiego.com/MaintenancePersistence.gs to serve as the single source of truth for task metadata. This file handles:

// Structure for task tracking
function getLastProcessedTaskId() {
  const cache = CacheService.getDocumentCache();
  return cache.get('lastProcessedTaskId') || '0';
}

function setLastProcessedTaskId(taskId) {
  const cache = CacheService.getDocumentCache();
  cache.put('lastProcessedTaskId', taskId, 21600); // 6-hour cache
}

This approach uses Google's built-in CacheService to track which tasks have already generated notifications, preventing duplicate emails. The 6-hour cache window ensures we capture all new tasks even if the system restarts.

2. Notification Routing in BookingAutomation.gs

We added a new route to the existing BookingAutomation.gs doPost handler that intercepts maintenance task submissions:

} else if (params.action === 'log_maintenance') {
  const result = handleMaintenanceNotification(params);
  return ContentService.createTextOutput(JSON.stringify(result))
    .setMimeType(ContentService.MimeType.JSON);
}

This handler extracts task details (description, criticality level, assigned personnel) and immediately invokes an AWS Lambda function via HTTPS, creating an asynchronous processing pipeline. By offloading to Lambda, we prevent the GAS execution from timing out on email operations.

3. Lambda Worker for Email Dispatch

Following existing Lambda deployment patterns in the queenofsandiego.com infrastructure, we created a Lambda function that handles the actual email delivery. The function receives task metadata and:

  • Validates task criticality to determine notification urgency
  • Routes messages to appropriate stakeholders (Sergio receives all critical tasks, daily digest for standard)
  • Uses SES (Simple Email Service) for reliable delivery
  • Logs delivery status back to CloudWatch

The Lambda IAM role uses the existing pattern defined for similar functions like tips-box, with permissions limited to SES:SendEmail and logs:CreateLogGroup/CreateLogStream.

4. Frontend Integration in staging-index.html

Modified /Users/cb/Documents/repos/sites/queenofsandiego.com/tools/maintenance/staging-index.html to include a webhook call after task submission:

// After task is validated and saved to the DOM
fetch('https://script.google.com/macros/d/{SCRIPT_ID}/usercache/call', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'log_maintenance',
    taskId: newTask.id,
    description: newTask.description,
    criticality: newTask.level,
    addedBy: currentUser,
    timestamp: new Date().toISOString()
  })
}).catch(err => console.log('Task logged:', err));

This fires asynchronously without blocking the UI, so users get immediate feedback while notifications process in the background.

Infrastructure and Deployment

CloudFront Distribution Management

The staging maintenance tool lives at a CloudFront distribution origin pointing to an S3 bucket. We invalidated the cache path /tools/maintenance/staging-index.html after each deployment to ensure users receive the latest version:

aws cloudfront create-invalidation \
  --distribution-id E1ABCD1234EFG \
  --paths "/tools/maintenance/*"

This prevents serving stale HTML that lacks the new notification webhook.

Google Apps Script Deployment

We pushed changes to the GAS project using clasp, Google's command-line deployment tool. The key challenge was ensuring the new MaintenancePersistence.gs file was tracked:

clasp push --force

The --force flag was necessary because MaintenancePersistence.gs was initially created but not detected by clasp's automatic tracking. After verifying the file appeared in `clasp status`, we confirmed the push succeeded and the new version was live in the GAS console.

Notification Strategy: Data-Driven Decision Making

Rather than implementing immediate per-task notifications (which would create notification fatigue), we adopted a criticality-based approach supported by fleet management best practices:

  • Critical Tasks (e.g., safety issues, propulsion failures) - Immediate email to Sergio
  • Standard Tasks - Daily digest at 6 PM with all new items added since morning
  • Low-Priority Tasks - Visible in dashboard only, included in weekly summary

This follows SRE principles of alert fatigue reduction while ensuring urgent issues reach decision-makers immediately. Sergio can filter by criticality in the maintenance.queenofsandiego.com dashboard to see new tasks at any time.

Staging vs. Production Separation

Currently, the maintenance tool uses a single HTML file deployed to S3. To establish a staging/production separation, we:

  • Keep the live version at s3://queenofsandiego-maintenance/tools/maintenance/index.html
  • Maintain staging version at the same S3 path with `-staging` suffix in the HTML filename
  • Route staging notifications to jadasailing@gmail.com instead of production email addresses
  • Use GAS script properties to detect environment and route accordingly

Email notifications from staging are clearly labeled as test messages, allowing team members to verify the workflow without sending production alerts.

Calendar Integration

We created a "Jada Maintenance" calendar under the jadasailing@gmail.com account to serve as a historical record of all maintenance activities. When a critical task is logged, the Lambda function creates a calendar event capturing:

  • Task description and criticality level
  • Date/time added
  • Assigned personnel
  • Estimated duration

This provides a