```html

Building a Task Notification Pipeline for maintenance.queenofsandiego.com: Real-Time Crew Alerts via Email and Calendar Integration

What Was Done

We implemented an end-to-end notification system for the maintenance tool that alerts crew members (specifically Sergio) when new maintenance tasks are added. The system combines Google Apps Script (GAS) handlers, Lambda persistence, email notifications, and Google Calendar integration to ensure critical maintenance work doesn't slip through the cracks. This work was completed in the staging environment at maintenance.queenofsandiego.com with testing directed to jadasailing@gmail.com.

The Problem We Solved

Travis was adding new tasks to the maintenance tool, but there was no mechanism to notify the team. Visibility into new work items was poor, and there was no audit trail. We needed a solution that:

  • Surfaces new tasks in real-time
  • Notifies Sergio and other crew leads immediately
  • Supports variable notification cadence based on task criticality
  • Integrates with existing calendar systems (JADA Maintenance calendar)
  • Maintains separation between staging and production environments

Technical Architecture

Component 1: GAS Maintenance Route Handler

We added a new route handler in /Users/cb/Documents/repos/sites/queenofsandiego.com/BookingAutomation.gs that intercepts maintenance-related POST requests:

if (action === 'log_maintenance') {
  const result = LogMaintenance.handleLogMaintenance(requestData);
  return ContentService
    .createTextOutput(JSON.stringify(result))
    .setMimeType(ContentService.MimeType.JSON);
}

This routing pattern follows our existing booking automation conventions, making it maintainable and consistent with the codebase.

Component 2: MaintenancePersistence.gs – The Persistence Layer

Created a new file at /Users/cb/Documents/repos/sites/queenofsandiego.com/MaintenancePersistence.gs that handles:

  • Task validation and storage: Receives task data from the maintenance UI, validates required fields (title, category, priority level)
  • Duplicate detection: Checks against recent task history to prevent duplicate notifications
  • Lambda invocation: Triggers the notification Lambda asynchronously so the UI doesn't wait for email/calendar operations
  • Audit logging: Writes to a Google Sheet for historical tracking (accessible at the JADA Internal drive)

The key function signature:

function handleLogMaintenance(taskData) {
  // Validate: title, category, priority (HIGH, MEDIUM, LOW)
  // Store in Sheet
  // Invoke Lambda for notifications
  // Return confirmation with task ID
}

Component 3: MaintenanceCalendar.gs – Calendar Integration

Created /Users/cb/Documents/repos/sites/queenofsandiego.com/MaintenanceCalendar.gs to manage calendar events. This file:

  • Integrates with the JADA Maintenance calendar (created under jadasailing@gmail.com)
  • Creates calendar events for all tasks, with event details including criticality
  • Uses recurring event patterns for recurring maintenance (e.g., weekly electrical checks)
  • Tags events with the task ID for bidirectional linking with the maintenance tool

We created the calendar via the Google Calendar UI and confirmed it exists in the JADA account. All subsequent events are created via GAS CalendarApp.

Component 4: Staging HTML Modifications

Modified /Users/cb/Documents/repos/sites/queenofsandiego.com/tools/maintenance/staging-index.html to add:

  • Task submission handler: When users add a task, the form POSTs to the GAS endpoint with action log_maintenance
  • Real-time UI feedback: Toast notifications showing "Task added - notifications sent"
  • Task history sidebar: Shows recently added tasks with timestamps and who added them
  • Criticality badges: Visual indicators (color-coded) for HIGH/MEDIUM/LOW priority

The key form submission:

document.getElementById('addTaskForm').addEventListener('submit', async (e) => {
  e.preventDefault();
  const taskData = {
    action: 'log_maintenance',
    title: document.getElementById('taskTitle').value,
    category: document.getElementById('taskCategory').value,
    priority: document.getElementById('taskPriority').value,
    assignedTo: document.getElementById('taskAssigned').value,
    notes: document.getElementById('taskNotes').value,
    timestamp: new Date().toISOString()
  };
  const response = await fetch(GAS_ENDPOINT_URL, {
    method: 'POST',
    payload: JSON.stringify(taskData)
  });
  // Handle response
});

Infrastructure: Lambda and Email Pipeline

Lambda Function Deployment

We deployed a Lambda function (exact name: maintenance-task-notifier) that receives events from the GAS persistence layer. The function:

  • Determines notification cadence: HIGH priority tasks trigger immediate email; MEDIUM tasks are collected for hourly digest; LOW tasks go to daily digest
  • Sends email via SES: Using the noreply@queenofsandiego.com alias (or appropriate alias for task notifications)
  • Calls Calendar API: Creates corresponding events in the JADA Maintenance calendar
  • Writes to DynamoDB: Stores task metadata for dashboards and reporting

The Lambda IAM role uses the existing pattern from tips-box Lambda deployments with added permissions for:

  • ses:SendEmail and ses:SendRawEmail
  • dynamodb:PutItem and dynamodb:Query
  • Google Calendar API credentials (via Secrets Manager)

Email Template Strategy

HIGH priority emails go immediately with subject line: 🚨 [URGENT] New Maintenance Task: {title}

MEDIUM priority tasks are digested hourly: 📋 Maintenance Update - Hourly Digest

LOW priority tasks are in daily digest: 📅 Daily Maintenance Summary

Staging vs. Production Separation

Since both staging and production use the same CloudFront distribution pointing to the S3 maintenance bucket, we implemented separation at the application layer:

  • Environment detection: The staging HTML checks hostname; if staging- is in the path, it sets ENVIRONMENT='staging'
  • Email routing in Lambda: When environment is staging, all emails go to jadasailing@gmail.com (test address) instead of Sergio's production address