Building a Real-Time Maintenance Task Notification System for maintenance.queenofsandiego.com
What We Built
We implemented a multi-layer notification system for the JADA maintenance tracking tool that surfaces newly-added tasks to team members in real-time, with intelligent notification pacing based on task criticality. The system pipes maintenance task submissions through Google Apps Script handlers into a Lambda-backed persistence layer, which then triggers email notifications to designated team members.
This solves a critical operational problem: when Travis or other crew members add tasks to maintenance.queenofsandiego.com, there was no mechanism for Sergio and the operations team to be alerted. Tasks could languish unnoticed because the web interface had no notification component.
Architecture Overview
The solution uses four integrated components:
- Frontend (Staging HTML):
/Users/cb/Documents/repos/sites/queenofsandiego.com/tools/maintenance/staging-index.html— modified to include a task submission handler that POSTs to our GAS endpoint - GAS Router:
BookingAutomation.gs— extended with a new route handler for thelog_maintenanceaction that validates incoming maintenance tasks - Persistence Layer:
MaintenancePersistence.gs(newly created) — handles logging and triggering of notification workflows - Notification Engine: Lambda function that consumes persistence events and dispatches emails based on task criticality and time-of-day heuristics
Technical Implementation Details
GAS Request Routing
The existing BookingAutomation.gs doPost handler already had action-based routing logic. We added a new condition that checks for action === 'log_maintenance':
if (params.action === 'log_maintenance') {
return MaintenancePersistence.logTask(params);
}
This follows the existing pattern used for booking and other transactional operations in the same GAS project. The request body includes task name, criticality level (LOW, MEDIUM, HIGH, CRITICAL), assigned_to, and description fields.
New MaintenancePersistence Module
We created MaintenancePersistence.gs as a dedicated module for maintenance-specific logic. This separates concerns and makes the codebase easier to maintain as notification logic evolves.
Key functions in this module:
logTask(params)— Validates task parameters, writes to a Google Sheet for audit trail, and invokes the notification handlernotifyTeam(taskData)— Determines notification recipients based on task criticality and calls the Lambda notification endpointgetNotificationRecipients(criticality)— Returns appropriate email list based on task severity
The module writes task records to Maintenance Task Log sheet within the same Google Sheet that powers other JADA operations. This provides audit trail and historical context for maintenance work.
Criticality-Based Notification Pacing
Rather than notifying on every task, we implemented a data-driven approach based on industry best practices from high-performing operations teams:
- CRITICAL tasks: Immediate SMS + email notification to on-call personnel
- HIGH tasks: Immediate email to Sergio and crew leads; consolidated in daily ops briefing
- MEDIUM tasks: Consolidated into end-of-day digest (17:00 UTC dispatch)
- LOW tasks: Weekly summary email, Monday 08:00 UTC
This prevents notification fatigue while ensuring urgent issues get immediate attention. The pacing logic lives in the Lambda function, not in GAS, allowing for rapid iteration without redeploying the Apps Script.
Infrastructure & Deployment
S3 & CloudFront Configuration
The staging maintenance tool is deployed to:
- S3 Bucket:
queenofsandiego-maintenance-staging - Object Key:
tools/maintenance/staging-index.html - CloudFront Distribution: Points to
maintenance.queenofsandiego.comwith origin bucket configuration
After deploying updated staging HTML, we invalidate the CloudFront cache using:
aws cloudfront create-invalidation \
--distribution-id [DIST_ID] \
--paths "/tools/maintenance/*"
This ensures the staging environment reflects changes immediately without TTL delays.
Google Apps Script Deployment
All GAS code (including new MaintenancePersistence.gs) is tracked and deployed via clasp:
clasp push
The GAS project ID is configured in .clasp.json` within the queenofsandiego.com repository root. New files must be explicitly tracked by clasp before they're included in deployments; we verified MaintenancePersistence.gs appeared in the clasp file manifest before pushing.
Lambda Integration
The Lambda function for email dispatch uses an existing IAM role from the JADA infrastructure (referenced in the tips-box Lambda configuration). This function:
- Receives events from the GAS notification handler via HTTPS POST
- Evaluates current time and task criticality to determine dispatch timing
- Sends emails via SES (Simple Email Service) to recipients
- Logs all notifications to CloudWatch for audit and debugging
For staging/testing, emails are sent to jadasailing@gmail.com rather than crew aliases, preventing accidental notifications to the full team during development.
Key Decisions & Rationale
Why Separate Persistence Module?
Rather than adding all logic to the existing BookingAutomation.gs`, creating `MaintenancePersistence.gs` provides:
- Clear separation of domain concerns (bookings vs. maintenance)
- Easier testing and iteration of maintenance-specific logic
- Better onboarding for new engineers who need to understand maintenance workflows
- Reduced risk when deploying maintenance changes (isolated from booking logic)
Why Google Sheet for Audit Trail?
Rather than relying solely on Lambda/CloudWatch logs, we write to a Google Sheet because:
- Non-technical crew members (like Travis) can view task history without database access
- Sheets provide built-in search, filtering, and export capabilities
- Existing JADA infrastructure already uses Google Sheets for operational records
- Data is persistent even if Lambda logs expire or get rotated
Why Lambda Over GAS Email?
GAS has native email capabilities, but we chose Lambda because:
- Lambda can schedule notifications (digest batching) more elegantly than GAS time-based triggers
- Decouples email dispatch from synchronous task logging, improving response time
- Centralizes notification logic used