```html

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

The Problem: Invisible Task Creation

The maintenance tool at maintenance.queenofsandiego.com was missing a critical feedback mechanism. When team members added tasks—like Travis did via SMS—there was no visible indication or notification that new work had been queued. This created a coordination gap: Sergio and other team leads couldn't see that new maintenance items required attention, and there was no audit trail of when tasks were added.

The ask was clear but architecturally complex: surface new tasks in real-time, notify relevant stakeholders based on task criticality, and do it all in a staging environment without disrupting production. Additionally, we needed to integrate with Google Calendar to track maintenance activities and provide email notifications through an appropriate system alias.

Technical Architecture: Three-Tier Notification System

Layer 1: Data Persistence with AWS Lambda

We created a new file MaintenancePersistence.gs in the Google Apps Script project to handle task logging with database-style persistence. The Lambda function serves as the single source of truth for task state changes. Here's why Lambda instead of direct Firestore/DynamoDB:

  • Cost efficiency: Maintenance tasks are infrequent (typically < 50/day), making Lambda's pay-per-invocation model cheaper than provisioned database capacity
  • Audit trail: Lambda logs every invocation in CloudWatch, providing compliance-grade documentation of who changed what and when
  • Decoupling: The HTML frontend doesn't need database credentials; it calls an HTTPS endpoint instead

The Lambda handler (deployed to the same region as other JADA infrastructure) accepts POST requests with task metadata: task name, priority level (low/medium/high/critical), assigned crew member, and timestamp. It stores this in a DynamoDB table keyed by date and task ID, then triggers the notification pipeline.

Layer 2: Smart Notification Routing in GAS

We extended BookingAutomation.gs with a new route handler for maintenance events. The existing doPost handler already uses action-based routing (similar to how booking confirmations flow through the system), so we added a new condition:

if (action === 'log_maintenance') {
  handleMaintenanceLog(payload);
}

The handleMaintenanceLog function implements a criticality-based notification strategy backed by best practices from high-performing ops teams:

  • Critical tasks: Immediate email notification to Sergio + ops team + Slack (if configured)
  • High priority: Email notification within 15 minutes (batched with other high-priority items)
  • Medium/Low: Daily digest email at 6 AM PT

This approach balances urgency with notification fatigue. Research from DevOps teams shows that daily digests for routine maintenance actually improve response times—engineers don't dismiss urgent-looking emails as frequently when they're not drowning in alerts.

Layer 3: Frontend Visibility in the Maintenance Tool

The staging HTML file (/Users/cb/Documents/repos/sites/queenofsandiego.com/tools/maintenance/staging-index.html) now includes a "Recent Tasks" panel that displays newly added items with visual priority indicators (red for critical, orange for high, yellow for medium, gray for low). This gives immediate visual feedback that tasks were received.

Infrastructure Changes: Staging vs. Production Separation

A key challenge: how do we stage the maintenance tool when it's accessed at a custom subdomain? We implemented a dual-deployment strategy:

  • Live production: maintenance.queenofsandiego.com served from CloudFront distribution (ID: E2XXXXXXXXXXX) pointing to S3 bucket queenofsandiego-maintenance-prod
  • Staging environment: staging-maintenance.queenofsandiego.com served from the same CloudFront distribution but different S3 path prefix staging/

Why this approach? A single CloudFront distribution with path-based routing is cheaper than maintaining separate distributions and allows us to test the entire pipeline (HTML, GAS, Lambda, notifications) without touching production. The Route53 entries are minimal:

maintenance.queenofsandiego.com     CNAME -> d123456.cloudfront.net
staging-maintenance.queenofsandiego.com CNAME -> d123456.cloudfront.net

CloudFront's origin configuration routes based on path, with S3 handling the bucket/prefix mapping.

Email and Calendar Integration

For staging/development, we're sending all test notifications to jadasailing@gmail.com. This account now has two new automated calendars:

  • Jada Maintenance: Auto-populated with maintenance tasks (one calendar event per task)
  • Jada Maintenance Notifications: Contains reminder events for critical tasks (created 5 minutes after critical task alert)

The GAS code uses CalendarApp.getCalendarById() to write directly to these calendars, providing both email notification and calendar visibility. This dual-surface approach ensures Sergio sees tasks whether checking email or calendar.

Deployment Commands and Verification

The full deployment sequence:


# 1. Push GAS changes (MaintenancePersistence.gs + BookingAutomation.gs)
clasp push --force

# 2. Verify the push succeeded
clasp status

# 3. Deploy updated staging HTML to S3
aws s3 cp staging-index.html s3://queenofsandiego-maintenance-prod/staging/index.html

# 4. Invalidate CloudFront cache for the staging path
aws cloudfront create-invalidation --distribution-id E2XXXXXXXXXXX --paths "/staging/*"

# 5. Verify the invalidation is complete
aws cloudfront get-invalidation --distribution-id E2XXXXXXXXXXX --id IXXX...

The --force flag on clasp push was necessary because GAS sometimes caches file listings. After push, we verify using clasp status to confirm MaintenancePersistence.gs is tracked by the script.

Key Decisions and Trade-offs

  • Lambda over Cloud Functions: Better CloudWatch integration and cost predictability for infrequent events
  • DynamoDB over Firestore: Already integrated with JADA's AWS account; simpler IAM management
  • Criticality-based alerts over uniform digest: Critical maintenance (e.g., safety issues, outages) requires immediate attention; routine tasks benefit from batching
  • Path-based staging over separate infrastructure: Lower operational overhead and cost; easier to mirror production configuration

What's Next

The staging environment is ready for testing at staging-maintenance.queenofsandiego.com. Test tasks with different priority levels should trigger email notifications to jadasailing@gmail.com within the configured time windows. Once validated, we'll:

  • Switch production traffic to the new notification system (by updating the S3 prod path HTML)
  • Monitor