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-stagingvs. production bucket - All notifications from staging are sent to
jadasailing@gmail.com(test address) - An environment variable in Lambda determines email routing:
NOTIFICATION_EMAIL_STAGINGvs.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: