Multi-Service Guest & Crew Portal Synchronization: Calendar, Database, and Static Site Coordination
This session focused on synchronizing guest boarding pages, crew assignments, and calendar events across multiple systems for weekend charters. The core challenge: ensuring that calendar changes, crew roster updates, and deployed static HTML pages stayed in perfect alignment—and that minors could complete waivers with guardian data.
What Was Done
- Updated three guest boarding pages (Quinn, Jonathan, Danika) with corrected times, captain assignments, and deployment to S3
- Fixed Google Calendar events for Quinn and Jonathan via the Calendar API
- Patched DynamoDB event records with corrected crew assignments and event times
- Verified waiver endpoint supports minor/guardian workflows
- Sent boarding emails and SMS with waiver links and photo upload codes
- Identified missing crew data on JADA Internal Calendar and flagged for correction
Technical Details: Guest Page Workflow
Guest pages live in two places: S3 bucket and CloudFront distribution. The workflow was:
# List existing guest pages
aws s3 ls s3://sailjada-guest-pages/boarding/
# Download current versions
aws s3 cp s3://sailjada-guest-pages/boarding/quinn-guest.html /tmp/
aws s3 cp s3://sailjada-guest-pages/boarding/jonathan-afternoon.html /tmp/
aws s3 cp s3://sailjada-guest-pages/boarding/danika-guest.html /tmp/
# Deploy updated pages after local edits
aws s3 cp /tmp/quinn-guest.html s3://sailjada-guest-pages/boarding/
aws s3 cp /tmp/jonathan-afternoon.html s3://sailjada-guest-pages/boarding/
aws s3 cp /tmp/danika-guest.html s3://sailjada-guest-pages/boarding/
# Invalidate CloudFront cache
aws cloudfront create-invalidation \
--distribution-id E2X1Y2Z3A4B5C6 \
--paths "/boarding/quinn-guest.html" "/boarding/jonathan-afternoon.html" "/boarding/danika-guest.html"
Why S3 + CloudFront? S3 provides durability and versioning; CloudFront edge locations reduce latency for guests downloading from mobile devices. The invalidation ensures browsers and edge caches fetch fresh HTML within seconds, not hours.
Calendar & DynamoDB Synchronization
Three systems track events; they must stay consistent:
- Google Calendar (iCal feed): Source of truth for dates, times, descriptions
- DynamoDB `events` table: Crew roster, guest counts, waiver status
- Static guest pages: Human-readable event details (time, captain, location)
Updates flowed like this:
# 1. Fetch iCal from JADA Internal calendar
curl -H "Authorization: Bearer $JADA_TOKEN" \
"https://calendar.jada-internal/ical/v1/calendars/events.ics"
# 2. Parse event for Quinn (May 30, 10am–2pm)
# - Original captain: Darrell → Changed to Gene
# - Guest waivers: Create DynamoDB records
# 3. Update DynamoDB event record
aws dynamodb update-item \
--table-name events \
--key '{"eventId": {"S": "QUINN_MAY30_10AM"}}' \
--update-expression "SET captain = :c, crew = :crew, #status = :st" \
--expression-attribute-names '{"#status": "status"}' \
--expression-attribute-values '{
":c": {"S": "Gene"},
":crew": {"SS": ["Gene", "Sarah", "Marcus"]},
":st": {"S": "confirmed"}
}'
# 4. Update Google Calendar event
aws lambda invoke \
--function-name patchCalendarEvent \
--payload '{"eventId": "QUINN_MAY30_10AM", "captain": "Gene"}' \
/dev/stdout
Why this order? Google Calendar is the slowest to update (external API, potential OAuth token refresh). DynamoDB is the operational record for crew dispatch and waiver processing. Guest pages must be regenerated last, after both upstream systems are correct, to avoid serving stale crew names.
Waiver Endpoint & Minor Support
The waiver endpoint at https://sailjada.com/waiver invokes a Lambda function that checks the incoming POST payload. Key discovery: the existing handler already supported a guardian_email and guardian_name fields. Danika's case (minor guest) required:
{
"guestName": "Danika",
"eventId": "DANIKA_MAY31_3PM",
"isMinor": true,
"guardianName": "Maria",
"guardianEmail": "maria@example.com",
"guardianPhone": "+1-619-555-0123"
}
The Lambda function (in src/handlers/waiver.ts) inserts this record into DynamoDB with a flag requiresGuardianSignature: true. A separate email workflow then sends the guardian a separate waiver link with pre-filled child data.
Communication & Contact Reconciliation
One operational challenge: finding Jonathan's phone number for the SMS notification. The process involved:
- Checking the guest page and DynamoDB (incomplete)
- Searching Gmail for the original Boatsetter booking confirmation
- Extracting phone from the forwarded email body
- Sending SMS via SNS to confirm receipt
Lesson: Contact data should be normalized at booking time and stored in DynamoDB with the event. Fallback searches are fragile and slow.
Infrastructure & Services Involved
| Service | Resource | Purpose |
|---|---|---|
| S3 | sailjada-guest-pages |
Static HTML boarding pages |
| CloudFront | E2X1Y2Z3A4B5C6 |
Edge caching & TLS termination |
| DynamoDB | events table (primary key: eventId) |
Crew, guest count, waiver state |
| Lambda | patchCalendarEvent, waiverHandler |
Calendar sync, waiver processing |
| Google Calendar API | JADA Internal calendar |