```html

Building a Task Notification System for maintenance.queenofsandiego.com: Architecture and Implementation

Overview

When Travis added new maintenance tasks to the Queen of San Diego's maintenance tracking tool, there was no mechanism to surface these additions to the operations team. This created a critical gap: Sergio couldn't see what had changed, and no notification was being sent. This post details the architecture and implementation of a task notification system that bridges this gap, using industry best practices for alert fatigue mitigation and data-driven notification cadence.

What Was Built

We implemented a three-tier notification system:

  • Persistence Layer: A new Google Apps Script file (MaintenanceCalendar.gs) that tracks task state changes
  • Calendar Integration: Automatic syncing of maintenance tasks to a Google Calendar named "Jada Maintenance" for visibility and scheduling
  • Smart Notifications: A handler that sends emails to jadasailing@gmail.com with task criticality-based notification logic
  • Staging/Production Separation: A staging HTML interface at /tools/maintenance/staging-index.html that routes notifications to test email addresses

Technical Architecture

Google Apps Script (GAS) Modifications

Two new files were created in the /queenofsandiego.com GAS project:

  • MaintenancePersistence.gs - Handles state management and task comparison
  • MaintenanceCalendar.gs - Manages Google Calendar synchronization

The BookingAutomation.gs doPost handler was extended to route maintenance-related requests:

// In BookingAutomation.gs doPost handler
if (action === 'log_maintenance') {
  const result = MaintenancePersistence.logTask(data);
  const notified = MaintenanceCalendar.syncAndNotify(result);
  return ContentService.createTextOutput(JSON.stringify({
    success: true,
    taskId: result.id,
    notified: notified
  })).setMimeType(ContentService.MimeType.JSON);
}

Persistence Strategy

Rather than querying the HTML form state each time, we implemented a persistent comparison mechanism. When new tasks arrive via POST from the maintenance interface, MaintenancePersistence.gs:

  • Retrieves the previous task state from Google Drive (stored as a JSON file in the JADA shared drive)
  • Compares the current task payload with the persisted state
  • Identifies newly added tasks by comparing task arrays
  • Updates the persisted state atomically to prevent race conditions

Notification Logic: Criticality-Based Cadence

Rather than sending an email for every single task change (which would create alert fatigue), the system implements a criticality-driven approach based on research from high-performing incident management teams:

  • Critical Tasks (electrical safety, structural issues, compliance): Immediate email notification
  • High Priority Tasks (safety features, guest experience blockers): Sent at 6 PM daily digest
  • Standard Tasks (cosmetic, maintenance backlog): Weekly digest on Fridays at 9 AM

This prevents notification burnout while ensuring urgent issues are surfaced immediately. The criticality metadata is assigned in the maintenance form itself and stored in the task object.

Infrastructure Changes

S3 and CloudFront

The maintenance tool is served from:

  • S3 Bucket: queenofsandiego.com (main bucket)
  • S3 Path: /tools/maintenance/staging-index.html (staging) and /tools/maintenance/index.html (production)
  • CloudFront Distribution: maintenance.queenofsandiego.com distribution

Cache invalidation was required after deploying staging changes:

aws cloudfront create-invalidation \
  --distribution-id [DIST_ID] \
  --paths "/tools/maintenance/*"

Production vs. Staging Separation

The staging HTML includes a configuration flag that routes all notifications to jadasailing@gmail.com for testing. The production version will route to both Sergio and the appropriate operations email alias once determined. This is configured in the staging HTML's initialization:

const ENVIRONMENT = 'staging';
const NOTIFICATION_EMAIL = 'jadasailing@gmail.com';
const SCRIPT_DEPLOYMENT_ID = '[STAGING_DEPLOYMENT_ID]';

Google Calendar Integration

The MaintenanceCalendar.gs module creates a calendar named "Jada Maintenance" in the jadasailing@gmail.com account if it doesn't exist, and synchronizes tasks as calendar events. This provides:

  • Visual timeline of when tasks need to be completed
  • Integration with existing Google Calendar workflows
  • Automatic reminders via Google Calendar notifications
  • A shared view for Sergio and other team members

New tasks are created with a description containing task details, due dates are extracted from the form, and the event is updated whenever the task state changes.

Key Technical Decisions and Rationale

Why Google Apps Script + Google Calendar?

The existing infrastructure already uses Google Apps Script for automation and Google Workspace for team collaboration. Leveraging these tools meant:

  • No additional authentication infrastructure needed
  • Existing permissions structure (shared drives, team calendars) applies automatically
  • Reduced operational overhead compared to Lambda/DynamoDB alternatives
  • Team is already familiar with GAS debugging and deployment

Why Criticality-Based Notifications?

Research from incident response teams (PagerDuty, Opsgenie case studies) shows that alert fatigue causes teams to ignore notifications, reducing response times to actual emergencies. By tiering notifications based on urgency:

  • Critical safety issues get immediate attention (minutes)
  • Important tasks get visibility without interruption (same-day digest)
  • Backlog items stay organized without generating noise (weekly digest)

Why Staging Before Production?

The maintenance tool didn't have a clear staging/production separation. By deploying to /tools/maintenance/staging-index.html first, we can:

  • Verify the notification system works end-to-end
  • Confirm email deliverability and formatting
  • Test calendar synchronization without affecting operations
  • Establish a pattern for future staging/production deployments

Deployment Process

The deployment involved multiple component updates:

# 1. Deploy modified staging HTML to S3
aws s3 cp tools/maintenance/staging-index.html \
  s3://queenofsandiego