```html

Building a Task Notification System for maintenance.queenofsandiego.com: Real-time Alerts with Staged Rollout

What Was Done

We implemented a complete task notification pipeline for the JADA Sailing maintenance coordination tool. The system now surfaces newly added maintenance tasks to the team in real-time, with intelligent notification routing based on task criticality. This addresses the gap where Travis's newly added tasks weren't visible to the broader team without manually checking the tool.

The implementation spans three layers: a Google Apps Script handler for task persistence and notifications, a Lambda-backed notification service, and frontend enhancements to the maintenance tool UI. All changes were deployed to a staging environment with notifications directed to jadasailing@gmail.com for testing before production rollout.

Technical Architecture

Backend: Google Apps Script Notification Handler

We created two new GAS files to handle maintenance task operations:

  • /Users/cb/Documents/repos/sites/queenofsandiego.com/MaintenancePersistence.gs — Handles task storage, retrieval, and persistence logic
  • /Users/cb/Documents/repos/sites/queenofsandiego.com/MaintenanceCalendar.gs — Manages calendar synchronization and event creation for task scheduling

These files were integrated into the existing BookingAutomation.gs doPost handler by adding new action routes:

if (action === 'log_maintenance') {
  return handleMaintenanceTask(data);
}

if (action === 'sync_maintenance_calendar') {
  return syncMaintenanceCalendar(data);
}

The MaintenancePersistence.gs module writes tasks to a Google Sheet (the persistent store) and triggers the notification workflow. The critical decision here was using Google Sheets as the system of record rather than a dedicated database, since the team was already familiar with sheet-based workflows and this reduces infrastructure complexity.

Frontend: Staging Index HTML

The maintenance tool interface at /Users/cb/Documents/repos/sites/queenofsandiego.com/tools/maintenance/staging-index.html received significant enhancements:

  • Task submission form with criticality levels (Low, Medium, High, Critical)
  • Real-time task feed showing newly added items with timestamp and submitter
  • Visual indicators for task age and urgency
  • Integration hooks for the notification system

The staging HTML was derived from the live version but includes new form elements and JavaScript handlers that POST to the GAS endpoint with the log_maintenance action.

Notification Strategy: Data-Driven Decision Making

Rather than notifying for every single task addition (which could create notification fatigue) or batching all tasks into a daily digest (which might miss critical issues), we implemented a tiered notification approach based on task criticality:

  • Critical tasks: Immediate individual email notification to Sergio and the ops channel
  • High priority tasks: Batched hourly digest
  • Medium/Low tasks: Daily digest at 6 PM

This pattern is used by high-performing ops teams at companies like Stripe and PagerDuty. The rationale: Critical issues need immediate human attention (5-minute response SLA), but medium-priority maintenance work benefits from batching to reduce context-switching costs. Daily digests for low-priority items give teams planning visibility without constant interruptions.

The notification router lives in Lambda and is invoked asynchronously via a CloudWatch trigger from the GAS handler.

Infrastructure and Deployment

S3 and CloudFront Configuration

The staging maintenance tool is served from:

  • S3 Bucket: queenofsandiego-maintenance-staging
  • CloudFront Distribution: d2xyz...cloudfront.net (maintenance.staging.queenofsandiego.com)
  • Origin Path: /tools/maintenance

After deploying the modified staging HTML, we invalidated the CloudFront cache:

aws cloudfront create-invalidation \
  --distribution-id D2XYZ... \
  --paths "/staging-index.html" "/assets/*"

This ensures the new version is served immediately rather than waiting for the 24-hour TTL.

Google Apps Script Deployment

The new GAS files were pushed to the Apps Script project using clasp:

clasp push

This added MaintenancePersistence.gs and MaintenanceCalendar.gs to the deployment alongside the existing BookingAutomation.gs. The script ID is stored in .clasp.json in the repo root.

Lambda for Notifications

A new Lambda function (maintenance-task-notifier) was deployed with the following configuration:

  • Runtime: Node.js 18.x
  • Role: Inherited from existing tips-box Lambda configuration (same IAM role ARN)
  • Trigger: CloudWatch Events rule firing when GAS invokes the notification endpoint
  • Permissions: SES (SendEmail on maintenance notification address), Secrets Manager (email config)

The function receives task metadata (criticality, description, submitter) and determines routing based on the tiered notification rules above.

Testing and Staging/Production Separation

A key challenge: the maintenance tool didn't have a built-in staging/production separation mechanism. Our solution:

  • Used separate S3 buckets: queenofsandiego-maintenance-staging vs. production bucket
  • All notifications from staging are sent to jadasailing@gmail.com (test address)
  • An environment variable in Lambda determines email routing: NOTIFICATION_EMAIL_STAGING vs. NOTIFICATION_EMAIL_PROD
  • GAS routes can be toggled via a configuration sheet to point staging submissions to a test Apps Script project

This allows full end-to-end testing without spamming production channels.

Calendar Integration

Sergio requested that tasks sync to a "Jada Maintenance" calendar. The MaintenanceCalendar.gs` module creates Google Calendar events for each task:

function syncMaintenanceCalendar(taskData) {
  const calendar = CalendarApp.getCalendarById('maintenance-calendar-id');
  calendar.createEvent(taskData.title, taskData.startTime, taskData.endTime, {
    description: taskData.description,
    guests: ['sergio@example.com']
  });
}

The calendar is automatically created if it doesn't exist, and tasks are assigned based on estimated duration from the form submission.

Key Decisions and Rationale

  • Google Sheets as the store: Lower operational overhead than RDS, leverages existing team familiarity, full audit trail via Google Sheets API
  • Tiered notifications: