Automating Charter Document Generation and S3 Publishing for JADA Weekend Operations
This session focused on building infrastructure to automate the generation and publication of charter documents for weekend sailing operations at JADA. The goal was to reduce manual work for crew coordination while maintaining consistency across manifest documents, trip sheets, and passenger manifests that live both on crew pages and in S3 for captain access.
What Was Done
We built a complete document pipeline that:
- Extracts charter data from JADA's internal calendar via OAuth-authenticated API calls
- Generates HTML manifests and trip sheets with formatted passenger lists and payment details
- Publishes documents to two separate S3 locations: crew-page docs and captain-accessible manifests
- Invalidates CloudFront caches to ensure live content updates immediately
- Maintains durability by storing source documents in version-controlled
/jada-opsdirectories
The pipeline was tested against live weekend charters (Quinn Male, Jonathan) and verified end-to-end through live S3 URLs.
Technical Details
Charter Data Extraction
The process begins by querying JADA's Google Calendar API for weekend events. We use OAuth token refresh to maintain authenticated access without hardcoding credentials:
GET /calendar/v3/calendars/{JADA_CALENDAR_ID}/events
Query params: timeMin={friday}, timeMax={sunday}, showDeleted=false
Response: Event objects with title, description, attendees, custom properties
Custom calendar fields store payment amounts, captain names, and crew assignments. The calendar serves as the single source of truth, avoiding duplication across multiple systems.
Document Generation
Two Python scripts handle document creation:
charter_provisioner.py— Main orchestrator that fetches calendar events and coordinates document generationsend_charter_emails.py— Generates HTML documents and manages publishing workflows
Each charter gets two output formats:
- Manifest HTML (
quinn-male-manifest.html) — Passenger list with names, contact info, payment status. Format includes styled tables and captain notes section. - Trip Sheet HTML (
quinn-male-trip-sheet.html) — Operational details: departure times, weather notes, crew assignments, provisioning checklist.
Both documents are generated with semantic HTML and inline CSS for reliability across different viewing contexts (email, web, print).
S3 Publishing Strategy
Documents are published to two locations, each serving different purposes:
- Crew Page Docs Prefix:
s3://shipcaptaincrew/docs/{event_id}/{manifest,trip-sheet}.html- Renders within the crew page SPA via
handle_get_docLambda route - Accessible through crew portal with authentication
- CloudFront distribution:
d111111abcdef8.cloudfront.net
- Renders within the crew page SPA via
- Captain Manifest Prefix:
s3://shipcaptaincrew/manifests/{charter_id}/{manifest,trip-sheet}.html- Direct S3 URLs for captain offline access
- Published independently for durability
- Cached via same CloudFront distribution
S3 object metadata is set explicitly: Content-Type: text/html; charset=utf-8 to ensure proper rendering in browsers without requiring MIME type guessing.
Cache Invalidation
After publishing, we invalidate CloudFront to clear cached versions:
aws cloudfront create-invalidation \
--distribution-id d111111abcdef8 \
--paths "/docs/{event_id}/*" "/manifests/{charter_id}/*"
This ensures captains and crew see updated documents immediately, not stale cached versions. Invalidations are idempotent—safe to run multiple times without side effects.
Infrastructure Architecture
The system uses a tiered approach:
- Data Layer: Google Calendar API (OAuth-authenticated) provides charter metadata
- Processing Layer: Local Python scripts generate HTML documents from calendar data
- Storage Layer: S3 buckets store finalized HTML documents
- Distribution Layer: CloudFront delivers documents with caching and HTTPS
- Access Layer: Lambda functions (
handle_get_doc) retrieve documents from S3 for crew portal
Version control at /Users/cb/Documents/repos/jada-ops/ maintains source manifests for auditing and recovery, with per-charter subdirectories (quinn-male/, jonathan/) storing both HTML and metadata.
Key Decisions
Why Two S3 Prefixes?
Separating crew-page docs from captain manifests provides flexibility: crew portal can evolve its document rendering independently from captain offline access. It also allows different access controls or expiration policies per use case without affecting the other.
Why CloudFront Invalidation?
S3 alone doesn't guarantee immediate updates—CloudFront's default TTL could serve stale content for hours. Invalidation is the only way to guarantee captains see the latest manifest before departure.
Why Version-Controlled Source Documents?
Keeping HTML source in git enables audit trails, rollback capability, and diff visibility. If a manifest is published incorrectly, we can review what changed and revert.
Why Calendar as Single Source of Truth?
Rather than maintaining passenger lists in multiple systems (database, spreadsheets, documents), we treat Google Calendar as authoritative. Payment amounts, crew assignments, and passenger details live there—scripts just read and format for different outputs.
Verification and Testing
The pipeline was validated through:
- Fetching real weekend charters from calendar and confirming data extraction
- Generating manifests with actual passenger names and payment details
- Publishing to S3 and verifying HTTP 200 responses from live URLs
- Spot-checking CloudFront-served content matched source HTML
- Confirming passenger names appeared correctly in published manifests
All verification was done against production URLs to ensure the live system works as expected.
What's Next
Future improvements could include:
- Automated Scheduling: Trigger document generation on a cron schedule (e.g., Friday morning) rather than manual invocation
- SMS Notifications: Send captains text alerts when new manifests are published, integrating with existing SMS utilities
- Email Distribution: Extend
send_charter_emails.pyto email documents to crew on a schedule - Manifest Signing: Add digital signatures or water