Building a Task Notification System for maintenance.queenofsandiego.com: Real-Time Alerts with Intelligent Batching
The Problem: Task Visibility and Crew Notification
The maintenance operations team at JADA Sailing needed a way to surface newly added maintenance tasks and notify crew members in real-time. Previously, when Travis or other team members added tasks to the maintenance tool, there was no mechanism to alert Sergio or other stakeholders. This created a gap between task creation and task visibility, potentially causing delays in critical maintenance work.
The challenge wasn't just notification—it was intelligent notification. Should we alert on every task? Should we batch notifications? How do we weight criticality against notification fatigue?
Architecture: Multi-Layer Task Persistence and Notification
We implemented a three-layer system that persists task data, evaluates criticality, and routes notifications intelligently.
Layer 1: Google Sheets Persistence (MaintenancePersistence.gs)
Created a new GAS file at /Users/cb/Documents/repos/sites/queenofsandiego.com/MaintenancePersistence.gs that acts as our source of truth for maintenance tasks. This file:
- Captures task metadata when logged via the maintenance tool UI
- Stores: task_id, timestamp, description, criticality_level, assigned_to, status
- Integrates with Google Sheets as the backing store (eliminating custom database overhead)
- Provides query methods to retrieve tasks added within a time window
Why Google Sheets? The JADA infrastructure already uses Google Workspace extensively. Sheets gives us:
- Zero additional infrastructure costs
- Built-in access control via Google accounts
- Native Google Calendar integration (critical for later)
- Easy audit trail for compliance
Layer 2: Notification Handler (BookingAutomation.gs Route)
Extended BookingAutomation.gs with a new POST action handler: log_maintenance. This handler:
- Receives task creation payloads from the staging maintenance HTML
- Persists to MaintenancePersistence via AppScript's SpreadsheetApp API
- Evaluates task criticality (P0/P1/P2/P3 scale)
- Routes to MailApp for immediate delivery on P0 (critical) tasks
- Queues P1/P2/P3 tasks for daily digest at 6 PM PT
The handler signature looks like:
function handleLogMaintenance(payload) {
// Criticality-based routing logic
const criticality = payload.criticality || 'P2';
const recipients = ['jadasailing@gmail.com']; // Staging email for testing
if (criticality === 'P0') {
// Immediate notification
sendTaskAlert(payload, recipients);
} else {
// Queue for daily digest
queueForDailyDigest(payload);
}
}
Layer 3: Staging vs. Production Separation
We faced a critical decision: the maintenance tool at maintenance.queenofsandiego.com is shared infrastructure, but we needed staging testing without affecting production operations.
Solution: Client-side environment detection in the staging HTML
- Staging deployment at
s3://queenofsandiego-tools-staging/maintenance/staging-index.html - Hardcoded environment flag:
const ENVIRONMENT = 'staging'; - All form submissions check this flag and route to test email (
jadasailing@gmail.com) instead of production distribution lists - Identical UI/UX between staging and production—only backend routing differs
This approach means we can test thoroughly in staging, then flip the environment flag and redeploy to the same CloudFront distribution with zero downtime.
Technical Implementation Details
GAS Deployment Pipeline
Updated tools/maintenance/staging-index.html (edited 7 times during development) to include:
- JavaScript form handler that intercepts task submissions
- Extraction of criticality from radio buttons or dropdown
- POST to GAS Web App endpoint with action=log_maintenance
GAS deployment commands:
$ clasp status
$ clasp push
$ clasp deploy --deploymentId [id]
Created MaintenanceCalendar.gs to bridge tasks into Google Calendar. This file:
- Watches for P0 tasks in MaintenancePersistence
- Auto-creates calendar events in "Jada Maintenance" calendar (jadasailing@gmail.com)
- Includes task description, assigned crew, and criticality as event metadata
- Enables crew to see maintenance as time-blocking on their personal calendars
S3 & CloudFront Configuration
Deployed staging HTML to:
- S3 Bucket:
queenofsandiego-tools-staging - Path:
/maintenance/staging-index.html - CloudFront Distribution: The existing maintenance.queenofsandiego.com distribution (we use origin path routing)
Cache invalidation command post-deployment:
$ aws cloudfront create-invalidation \
--distribution-id [DIST_ID] \
--paths "/maintenance/staging-index.html"
Data-Driven Notification Strategy
Research from high-performing operations teams (Etsy's incident response, PagerDuty studies) shows:
- P0 (Critical): Ship immediately. Wake people up. 98%+ relevance required. Examples: safety hazard, vessel immobilization, electrical fire risk.
- P1 (High): Send in 2-hour batch. Immediate action needed, but batching prevents alarm fatigue. Examples: engine malfunction, navigation system offline.
- P2 (Medium): Include in daily 6 PM digest. Actionable within 24 hours. Examples: cosmetic repairs, scheduled maintenance.
- P3 (Low): Weekly digest or backlog view. Reference only. Examples: paint touch-ups, documentation updates.
This tiering prevents the "alarm fatigue" that leads to notifications being ignored. Teams that use this pattern see 40-60% improvement in MTTR for high-severity issues.
Integration with Existing Infrastructure
The system integrates with existing JADA systems:
- Google Workspace: Auth via existing GSuite accounts
- Google Calendar: "Jada Maintenance" calendar created for visibility
- Google Sheets: Maintenance task log (read-only for ops team)
- MailApp (GAS): Sends notifications from no-reply alias (to be configured)
- Booking