Multi-Event Calendar Synchronization and Guest/Crew Page Deployment for Sailjada Charter Operations
Overview
This session focused on synchronizing charter event metadata across three independent systems—Google Calendar (JADA Internal), DynamoDB crew dispatch records, and S3-hosted guest/crew boarding pages—to ensure consistent information propagation for this weekend's sailing operations and June 14 events. The core challenge: multiple authoritative sources creating drift, requiring a coordinated update strategy that respects rate limits and eventual consistency.
What Was Done
- Patched Google Calendar events via the Calendar API to correct crew assignments and event timing
- Updated DynamoDB event records in the crew dispatch table to reflect accurate crew rosters and participant status
- Deployed three S3-hosted guest boarding pages with refreshed HTML and CloudFront cache invalidation
- Validated waiver submission flow for both adult and minor participants
- Sent boarding confirmation emails with waiver links and photo upload codes
- Verified end-to-end guest experience across calendar, waiver, and email touchpoints
Technical Architecture and Execution
Google Calendar API Synchronization
The JADA Internal calendar (fetched via iCal feed and Google Calendar API) serves as the single source of truth for event metadata. Two primary updates were required:
- June 14 Ariel Loback event: Crew assignment correction (replace Darrell with Gene, remove Angelia from roster)
- Quinn Male / Jonathan afternoon events: Time window and captain assignment updates
Rather than relying on stale Lambda environment credentials, the session leveraged direct Google Calendar API calls with refreshed OAuth tokens. The workflow:
1. Parse JADA Internal iCal feed → extract event UIDs and current metadata
2. Identify event ID collisions and correct UID format
3. Call PATCH /calendar/v3/calendars/{calendarId}/events/{eventId}
4. Include only delta fields (crew array, time fields) to minimize payload
5. Validate response HTTP 200 with updated metadata
The key decision to use API PATCH over event recreation avoided losing organizer info and participant notification history. Event descriptions remain in the 4000-character limit, stored as structured JSON within the description field for programmatic parsing.
DynamoDB Crew Dispatch Records
The DynamoDB crew dispatch table (in us-west-2) maintains event state for the waiver system and boarding logistics. Three operations were executed:
1. Create Quinn Male event record
- Partition key: eventId (EID from calendar)
- Attributes: eventDate, startTime, endTime, captains[], crew[], waiverStatus
- TTL: 30 days post-event
2. Create Jonathan afternoon event record
- Similar schema with captain assignment from calendar
3. Update Danika guest event
- Correct time window: 3:00 PM – 7:00 PM (was 2:00–7:00)
- Update status to reflect paid participation
- Trigger waiver email to existing email on file
DynamoDB write throughput was provisioned at on-demand capacity to avoid throttling during bulk updates. Each write included a conditional check to prevent overwrites of in-flight waiver submissions.
S3 Guest Page Deployment
Three HTML guest boarding pages were deployed to S3 bucket s3://sailjada-guests/ with CloudFront distribution d8f...` in front:
quinn-guest.html— New page, containing event details, waiver link, and photo upload codejonathan-afternoon.html— New page with captain roster and event contactdanika-guest.html— Updated four times during the session to correct arrive-by time and captain assignments
Each page follows a consistent template structure:
<h1>[Guest Name] Boarding Information</h1>
<section id="event-details">
<p>Date: {eventDate}</p>
<p>Time: {startTime} – {endTime}</p>
<p>Arrive By: {arriveByTime}</p>
<p>Captain: {captainName}</p>
</section>
<section id="waiver-prompt">
<a href="/waiver?eid={eventId}&minor={isMinor}">
Complete Waiver
</a>
</section>
After S3 upload, CloudFront cache was invalidated via the CreateInvalidation API call with path pattern /* to ensure guests receive fresh content within seconds rather than the 24-hour TTL.
Waiver System Validation
The waiver endpoint at /waiver (Lambda-backed) required testing for minor participant support. Two test submissions were executed:
POST /waiver
Content-Type: application/json
{
"eventId": "quinn-may-30",
"participantName": "Quinn",
"isMinor": true,
"guardianName": "Guardian Name",
"guardianSignature": "...",
"guardianEmail": "guardian@example.com"
}
The Lambda handler in /functions/shipcaptaincrew/waiver.js correctly:
- Validated guardian information before inserting into DynamoDB
- Persisted a synthetic test record (later deleted)
- Generated a waiver completion token for photo upload authorization
Live waiver page JavaScript correctly displayed the 3:00–7:00 PM event time after deployment, confirming that S3 content updates propagated through CloudFront.
Email Notifications
Boarding confirmation emails were sent via SES to guest email addresses on file:
From: crew@sailjada.com
To: [guest-email-from-calendar]
Subject: Sailing Charter Boarding Information – [eventDate]
Body includes:
- Event date/time and arrive-by window
- Direct waiver completion link
- Photo upload code (one-time use)
- Captain contact information
- Emergency contact procedures
For minor participants (Danika), the email included additional guidance on guardian waiver signature requirements and proof-of-guardianship documentation.
Infrastructure and Data Flow Decisions
Why Multi-System Sync?
Three systems exist by design:
- Google Calendar (JADA Internal): Human-editable, source of truth for crew rosters and timing
- DynamoDB: Optimized for waiver lookups (event ID → crew roster) and boarding state transitions
- S3 Guest Pages: Public-facing, cacheable, decoupled from authentication systems
Synchronizing all three ensures that: (a) the crew manager updates Calendar once, (b) Lambda functions automatically propagate to DynamoDB, and (c) guest pages reflect