Building HELM: An Interactive Operations Dashboard for Multi-Platform Booking and Crew Management
Over the past development session, we built HELM—a single-page, self-contained operations visualization tool for Queen of San Diego's complex booking, payment, and crew dispatch ecosystem. HELM renders as a force-directed graph showing how customer acquisition flows through email campaigns, web search, and referral partners; how revenue enters via Boatsetter, Viator, and GetMyBoat; and how each booking cascades through ops, crew dispatch, and asset management.
What Problem Does HELM Solve?
Queen of San Diego operates across multiple platforms, payment processors, and operational subsystems. Without a unified visualization, it's difficult to see:
- Which acquisition channels drive bookings
- How money flows from external platforms into internal systems
- Where operational bottlenecks occur in the crew dispatch pipeline
- Which integrations are live vs. planned
- System health at a glance
HELM solves this by rendering the entire operational graph in a single, interactive, drill-down interface. Engineers can explore the system topology, see which Google Apps Script (GAS) functions back each operation, and verify system health via live probes.
Architecture: Why a Single HTML File?
We chose to build HELM as a single, self-contained HTML file rather than a multi-file SPA for several reasons:
- No build step: Zero dependencies on Node, webpack, or bundlers. The file is deployable immediately.
- Instant load: Single HTTP request; no waterfall of JS chunks or CSS imports.
- vis-network physics: We embedded vis-network via CDN (
https://unpkg.com/vis-network/standalone/umd/vis-network.min.js) to handle force-directed graph layout without reinventing physics simulation. - GAS integration: The graph nodes directly reference GAS function names and script IDs, making it easy to drill into
/Users/cb/Documents/repos/sites/helm/index.htmland correlate visual nodes with actual backend code. - Dark theme + gold accents: Navy background with gold node borders and text, matching the Queen of San Diego brand and making it "polished" enough for engineering presentations.
Node Data Structure and GAS Function Mapping
The core of HELM is a NODE_DATA object mapping logical system components to their GAS implementations:
// Example node structure
{
id: "gas_crewdispatch",
label: "Crew Dispatch",
type: "ops",
scriptId: "1A2B3C4D...", // GAS script ID
functions: [
"dispatchCrew(sailId, crewList)",
"notifyCrewViaEmail(crewId, sailDetails)",
"trackCrewAvailability(crewId, dateRange)"
],
status: "live",
platform: "gsheet_crew"
}
We extracted function signatures from key GAS files by reading:
gas_crewdispatch— crew notification and dispatch logicgas_booking— booking intake from Boatsetter/Viatorgas_payments— revenue reconciliation and accountinggas_emailcampaigns— customer acquisition funnelgas_opsdashboard— operational metrics and KPIs
Each node includes a functions array; when clicked, a detail panel pops up on the right side showing the exact GAS function signatures, allowing engineers to immediately understand what that node does and drill into Google Apps Script.
Infrastructure: S3 + CloudFront + Route53
HELM is deployed to a dedicated subdomain to keep it separate from the main website. Here's the exact infrastructure:
S3 Bucket Creation
aws s3api create-bucket \
--bucket helm.queenofsandiego.com \
--region us-west-2 \
--create-bucket-configuration LocationConstraint=us-west-2
The bucket name follows the subdomain pattern, making it easy to find and manage alongside other Queen of San Diego assets.
CloudFront Distribution
We created a CloudFront Origin Access Control (OAC) to allow CloudFront to read from S3 without public bucket ACLs:
aws cloudfront create-distribution \
--distribution-config file://helm-cf-config.json
Key settings:
- Origin:
helm.queenofsandiego.com.s3.us-west-2.amazonaws.com - Viewer protocol policy: redirect-to-https
- Cache behavior: 300 second TTL on index.html, 86400 seconds on assets
- Default root object: index.html
- Custom error response: 404 → index.html (SPA-style fallback, though HELM is single-page)
The distribution ID (e.g., E1A2B3C4D5E6F7) is used for cache invalidation when HELM is updated.
Route53 ALIAS Record
aws route53 change-resource-record-sets \
--hosted-zone-id Z1A2B3C4D5E6F7 \
--change-batch '{
"Changes": [{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "helm.queenofsandiego.com",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "Z1A2B3C4D5E6F7",
"DNSName": "d1a2b3c4d5e6f.cloudfront.net",
"EvaluateTargetHealth": false
}
}
}]
}'
This creates an ALIAS (not a CNAME) pointing helm.queenofsandiego.com to the CloudFront distribution, avoiding DNS CNAME flattening issues at the root.
Health Probes and Real-Time Status
HELM includes embedded health checks. Nodes glow green (status: live) or red (status: down) based on lightweight probes:
- GAS script probes: Call a tiny GAS endpoint that returns a timestamp; if it's recent, the node is live.
- External platform probes: Poll Boatsetter, Viator, GetMyBoat API health endpoints (if public) or use cached status.
- System health bar: A summary bar at the top shows percentage of nodes online.
Nodes marked as "planned" (e.g., future integrations) are greyed out and non-interactive.
Drill-Down Detail Panel
The right side of HELM shows a collapsible detail panel. Clicking a node reveals:
- Node name and type