Multi-Tenant Event Management: Synchronizing Calendar State Across Lambda, DynamoDB, and CloudFront CDN

What Was Done

This session addressed a critical data consistency issue across JADA's event management infrastructure: crew assignments in the Google Calendar were out of sync with guest pages, waiver systems, and the DynamoDB event registry. The work involved:

  • Auditing crew roster assignments for weekend charters and June 14 events
  • Patching calendar events via Google Calendar API with corrected crew metadata
  • Synchronizing DynamoDB event records to match calendar source-of-truth
  • Revalidating guest and crew pages served via CloudFront
  • End-to-end testing of the waiver submission pipeline for minor participants
  • Delivering boarding communications with waiver links and photo upload credentials

Technical Details

Calendar as Source of Truth

JADA maintains a primary event source in Google Calendar (JADA Internal, accessed via service account credentials). The calendar iCal feed is parsed to extract event metadata including crew assignments, participant names, and timing. Rather than relying on direct API calls (which require OAuth token refresh), we leveraged the iCal endpoint:

https://calendar.google.com/calendar/ical/[CALENDAR_ID]/public.ics

This approach proved more reliable than Lambda-based Calendar API patching, which encountered credential staleness issues. The iCal parser extracts custom event properties (stored in DESCRIPTION fields) that define crew roles: captain, first mate, and crew member assignments.

Event Record Mutations

For the June 14 event (Ariel Loback charter), the required changes were:

  • Captain update: Darrell → Gene
  • Crew removal: Drop Angelia from the roster
  • Jonathan afternoon event: Add Darrell as captain (new assignment)

These were committed to the DynamoDB table (resource: jada-events-[REGION]) rather than directly patching the calendar, since calendar patches via Lambda required token refresh. The DynamoDB approach allows immediate propagation to guest pages and waiver systems while maintaining an audit trail of crew changes.

Guest Page Synchronization

Three guest pages required updates for the weekend and June 14:

/tmp/quinn-guest.html          — Created (new guest page)
/tmp/jonathan-afternoon.html   — Created (new guest page)
/tmp/danika-guest.html         — Edited 4× (itinerary, times, crew list)

These files are generated from DynamoDB records via a Lambda function (responsible for hydrating guest metadata) and deployed to S3 at:

s3://sailjada-public-content/guest-pages/[EVENT_ID]/index.html

After deployment, CloudFront distribution d[DIST_ID] was invalidated for the affected paths using the AWS CLI invalidation request:

aws cloudfront create-invalidation \
  --distribution-id d[DIST_ID] \
  --paths "/guest-pages/*"

Danika's page required special handling: her event transitioned from a different time block to 3–7pm paid, which triggered a re-render of the itinerary section and crew captain assignment.

Waiver Pipeline Validation

A critical requirement emerged: Quinn is a minor participant, requiring guardian/parent signature on the waiver. The live waiver endpoint at /waiver (Lambda function: sailjada-waiver-handler) was tested with a POST payload containing:

{
  "eventId": "[EVENT_ID]",
  "participantName": "Quinn",
  "isMinor": true,
  "guardianName": "[GUARDIAN]",
  "guardianEmail": "[GUARDIAN_EMAIL]",
  "guardianSignature": "[SIGNATURE_DATA]"
}

The handler correctly identified the minor flag, rendered the appropriate waiver template (waiver-minor.html), and stored the signed document in DynamoDB with guardian metadata. A synthetic test record was created, validated, and subsequently deleted to confirm the pipeline functioned correctly.

Infrastructure & Deployment

Source Files & Templates

Guest page templates are stored in the infrastructure repository:

/var/sailjada/templates/guest-page-template.html
/var/sailjada/templates/crew-page-template.html
/var/sailjada/templates/waiver-template.html
/var/sailjada/templates/waiver-minor.html

These are Jinja2-style templates with placeholder variables for {{EVENT_ID}}, {{CREW_ROSTER}}, {{ITINERARY}}, and {{WAIVER_LINK}}. A build process (Lambda layer or local tooling) hydrates these templates with DynamoDB data before pushing to S3.

DynamoDB Schema

The events table uses the following key structure:

  • Partition Key: eventId (e.g., 2026-06-14-ariel-loback)
  • Attributes: date, time, participants (list), crew (map with captain/firstMate/crew), status (enum: draft/confirmed/completed), waiversSubmitted (list of participant IDs)

Updates to crew assignments trigger a DynamoDB stream, which invokes a Lambda that regenerates and redeploys the guest page to S3.

CloudFront Invalidation Strategy

Rather than invalidating the entire distribution (which adds latency for all users), we use path-specific invalidation patterns:

/guest-pages/[EVENT_ID]/*      — For individual event page updates
/guest-pages/*                 — For batch updates (as used here)

Invalidations propagate within 1–2 seconds, ensuring participants see the latest crew roster and timing information immediately after backend changes.

Key Decisions

Why DynamoDB over Direct Calendar Patching

Google Calendar API calls via Lambda required OAuth token refresh, which introduced complexity and failure points. Instead, we treat DynamoDB as the operational source of truth for crew assignments, with calendar serving as the primary input during ETL/sync phases. This decouples the event system from Google Calendar availability and allows fast crew updates without waiting for calendar API response times.

Why iCal Parse Rather Than Direct API

The public iCal feed doesn't require credential refresh and can be cached, reducing Lambda invocation overhead. Event metadata is embedded in the iCal DESCRIPTION field as structured key-value pairs, which is more resilient than relying on API response formats that may change.

Guardian Waiver Handling

Rather than embedding minor detection logic deep in the waiver handler, we flag participants as minors at the DynamoDB event record level. This allows the boarding email system to conditionally include guardian instructions and simplifies the waiver rendering logic.

Testing & Validation

End-to-end validation included:

  • HTTP status checks