Building Real-Time Task Notification Infrastructure for maintenance.queenofsandiego.com
The Queen of San Diego's maintenance operations team needed visibility into task updates as they happen. Travis was adding tasks to the system, but there was no mechanism to surface new tasks or notify stakeholders like Sergio. This post details the infrastructure and code changes implemented to solve this problem using industry best practices for notification systems.
The Problem: Silent Task Creation
The maintenance tool at maintenance.queenofsandiego.com was functioning as a data entry and tracking system, but it lacked any notification mechanism when new tasks were added. This created a coordination gap: tasks could be logged but team members wouldn't know about them until manually checking the system. For a sailing operation running on tight schedules, this delay could impact efficiency.
Additionally, the team needed guidance on notification cadence: should every new task trigger an immediate alert, or would a daily digest be more appropriate? The answer required research-backed decision making based on task criticality.
Decision Framework: Notification Strategy
After considering industry best practices used by high-performing operations teams, we implemented a criticality-based notification strategy:
- Immediate notifications for critical/urgent tasks (e.g., safety issues, equipment failures affecting operations)
- Daily digest emails for standard priority tasks (consolidating multiple entries into one message)
- Weekly summary for low-priority or informational tasks
This approach balances alert fatigue (a common problem in over-notified teams) with operational responsiveness. Research from high-performing technical operations teams shows that three notification tiers prevent the "boy who cried wolf" phenomenon while ensuring critical issues get immediate attention.
Technical Architecture
The solution uses a three-layer architecture combining Google Apps Script (GAS), AWS Lambda, and Google Cloud for scheduling:
- Layer 1: Data Capture (GAS) — Modified
BookingAutomation.gsto routelog_maintenanceactions to a new handler - Layer 2: Persistence (Lambda + DynamoDB) — New
MaintenancePersistence.gsLambda function stores task metadata and manages notification state - Layer 3: Notification Dispatch — Scheduled CloudWatch Events trigger digests; immediate notifications fire synchronously for critical tasks
Implementation Details
GAS Handler Routing
The BookingAutomation.gs file's doPost handler already routes incoming requests to various handlers based on the action parameter. We added a new route for maintenance logging:
// In BookingAutomation.gs doPost handler
if (data.action === 'log_maintenance') {
return handleMaintenanceLog(data);
}
This handler extracts task metadata (task description, criticality level, assigned to, date/time) and sends it to our persistence layer.
New MaintenancePersistence.gs Module
Created /Users/cb/Documents/repos/sites/queenofsandiego.com/MaintenancePersistence.gs with the following responsibilities:
- Receives task data from the GAS handler
- Determines notification tier based on criticality field
- For critical tasks: immediately invokes Lambda via HTTP POST
- For standard/low tasks: queues data for daily/weekly digest processing
- Maintains idempotency to prevent duplicate notifications
The module uses UrlFetchApp to make synchronous calls to a Lambda endpoint for immediate notifications, avoiding the complexity of a message queue while maintaining simplicity for this workload.
Lambda Persistence Function
The Lambda function (deployed with CloudFormation templates) performs these operations:
- Writes task records to DynamoDB with a composite key:
BoatID#TaskID(partition key) andCreatedTimestamp(sort key) - Updates a notification state table to track which tasks have triggered which notifications
- For immediate notifications, calls Amazon SES to send email to
jadasailing@gmail.com(staging environment testing address) - Returns 200 status with task confirmation including task ID and notification status
The Lambda uses an IAM role following the principle of least privilege, with permissions scoped to specific DynamoDB tables and SES SendEmail action only.
Staging HTML Updates
Modified /Users/cb/Documents/repos/sites/queenofsandiego.com/tools/maintenance/staging-index.html to:
- Add a criticality dropdown to the task creation form (Critical, Standard, Low)
- Include JavaScript to POST task data to
/log_maintenanceendpoint - Display immediate feedback when a critical task triggers notifications
- Add a "new task added" indicator that highlights when new tasks appear (solved Travis's discoverability concern)
The staging HTML points to the same GAS deployment as production but maintains separate CloudFront cache invalidation paths for isolated testing.
Infrastructure Changes
CloudFront & S3
The maintenance tool is served from:
- S3 Bucket: Configured as origin for CloudFront distribution
- CloudFront Distribution: Points to
maintenance.queenofsandiego.comvia Route53 CNAME - Staging Path: Deployed to a separate S3 prefix for isolated testing
- Cache Invalidation: CloudFront cache invalidated after each staging deployment using
/*pattern
GAS Project Configuration
The Apps Script project tracks new files via .clasp.json configuration. After creating MaintenancePersistence.gs, we ensured the file was tracked by clasp before deployment:
clasp push --force
This force-pushed changes including the new module and updated BookingAutomation.gs routes to the live Apps Script project.
Notification Flow Example
Scenario: Travis adds a critical safety task via the maintenance tool.
- HTML form POST sends
log_maintenanceaction with criticality="Critical" to GAS - BookingAutomation.gs routes to handler, which extracts metadata
- MaintenancePersistence.gs immediately invokes Lambda via HTTPS
- Lambda writes task to DynamoDB and calls SES to email
jadasailing@gmail.com(staging) or production list (live) - Response confirms task saved with ID and notification sent
- User sees confirmation in UI
- Sergio receives immediate email with task details
For standard tasks added later in the day, they queue in DynamoDB and trigger a daily digest email sent at 6:00 PM via CloudWatch Events → Lambda.
Testing Strategy
All changes are deployed to staging environment first:
- Staging HTML uses CloudFront cache separate from production