```html

Building an Automated Operations Stack for Sailing Charter Fulfillment

Over the past development session, I built out a comprehensive automation layer for JADA's sailing charter operations—spanning email follow-ups, operational digests, trip sheet deployment, and real-time crew dispatch coordination. The system integrates disparate data sources (DynamoDB crew tables, CSV contact registries, S3-hosted guest pages) into a single operational workflow, reducing manual touchpoints and ensuring Coast Guard compliance.

What Was Built

The system consists of three core components:

  • Follow-up Email Builder — Auto-generates templated follow-ups to charter clients (guest list requests, waiver reminders, boarding details)
  • Morning Digest Service — Aggregates daily operations summary: crew assignments, pending deposits, guest manifests, weather, launch checklist
  • Trip Sheet Deployment Pipeline — Generates guest-facing HTML trip sheets with unique photo codes, uploads to S3, invalidates CloudFront cache, and notifies crews

All three are coordinated through a scheduled macOS LaunchAgent and triggered from a central orchestration file.

Technical Architecture

Follow-Up Email System

Located at /Users/cb/.claude/skills/jada-followup/, the system uses a template-based approach:

  • Templates: reference/followup_templates.json — JSON-driven templates for guest list requests, deposit reminders, and cancellation notices
  • Builder: scripts/build_followups.py — Reads from ledger.json and contacts.csv, matches charter bookings to template rules, and generates email payloads
  • Filtering: Excludes crew-only records and prospective bookings; validates email addresses; applies suppression rules

The builder operates in a dry-run mode by default, masking PII before output—critical for safe local testing. Template invariants (required subject line, sender identity, required fields) are asserted before queue generation.

Morning Digest Pipeline

The digest system is defined in /Users/cb/icloud-jada-ops/digest/build_digest.py and automatically scheduled via LaunchAgent.

Automation: Registered with macOS at /Users/cb/Library/LaunchAgents/com.jada.morning-digest.plist, set to run daily at a configured hour. The LaunchAgent wrapper provides automatic restart on failure and integrates with system logs (queryable via log stream --predicate 'process == "build_digest.py"').

Data Sources:

  • DynamoDB table jada-crew-dispatch — real-time crew assignments, roles, and availability
  • ledger.json — charter bookings, deposit status, payment terms
  • contacts.csv — guest contact info, special requests, dietary restrictions
  • Weather APIs and external status feeds

Output: Digest is written to a timestamped file and emailed to the operations team, aggregating all pending actions into a single morning briefing.

Trip Sheet Deployment with Photo Codes

The trip sheet generation and deployment workflow:

  1. Generation: HTML trip sheet is generated dynamically, embedded with a unique 6-character photo code (e.g., BYHMJG) for guest photo sharing
  2. S3 Upload: Trip sheet and waiver PDFs are uploaded to the live S3 bucket (specific bucket name varies by environment; refer to /Users/cb/icloud-repos/shared/references/environments.md for current)
  3. Cache Invalidation: CloudFront distribution is invalidated for the trip sheet path, ensuring guests see the latest version immediately
  4. Guest Notification: Guests receive SMS and email with direct links to the trip sheet and waiver

Deployment Tool: Uses jada-deploy CLI, which abstracts S3 bucket management and CloudFront distribution IDs. Command pattern:

jada-deploy upload-print \
  --charter-id=2026-07-04-dylan \
  --file=trip-sheet.html \
  --invalidate-cdn=true

DynamoDB Integration for Crew Dispatch

Real-time crew assignments are stored in DynamoDB table jada-crew-dispatch, queried via key-value lookups on event date and crew member ID. The schema supports:

  • Role assignments (captain, deckhand, bartender, etc.)
  • Availability status and last-minute substitutions
  • Contact info for notifications

Queries are paginated to handle large datasets (July 4th events, for example, span multiple crew assignments). Failed queries are retried with exponential backoff to tolerate transient DynamoDB throttling.

Contact Management and Validation

The system maintains two canonical contact sources:

  • contacts.csv — authoritative registry of guest and crew info (email, phone, role, special flags)
  • DynamoDB jada-crew-dispatch — real-time crew assignment state

Cross-referencing ensures that email sends target the correct contact and that phone numbers match between sources. Edge cases (missing email, crew-only rows, prospective bookings) are filtered during template matching.

Key Architectural Decisions

Why LaunchAgent for Scheduling?

Rather than relying on external cron services or Lambda, the morning digest uses macOS LaunchAgent. Rationale:

  • No external dependency for a single-user, daily task
  • Native integration with system logging and restart policies
  • Operates even if the cloud infrastructure is temporarily down
  • Centralized control in the user's home directory

Why S3 + CloudFront for Guest Docs?

Trip sheets and waivers are served via S3 + CloudFront (not generated on-demand):

  • Performance: CloudFront edge caching ensures guests get near-instant downloads, critical on event day
  • Audit trail: S3 versioning tracks all trip sheet revisions
  • Cost: Static hosting is cheaper than running a web server
  • Availability: CDN remains available even if the primary application is down

Why Template-Based Emails Over Custom Logic?

Email generation uses JSON templates rather than inline business logic:

  • Non-engineers can edit templates without code changes
  • Templates are versioned and auditable
  • New email types can be added without redeploying scripts
  • A/B testing variants is trivial

Infrastructure and Secrets Management

All infrastructure references (S3 bucket names, CloudFront distribution IDs, DynamoDB table names, Gmail API credentials) are kept in /Users/cb/icloud-repos/shared/references/environments.md and loaded at runtime, never hardcoded in scripts. This allows the same codebase to work across development and production environments without modification.

What's Next

The foundation is in place for further automation:

  • Guest list validation—automatically parse responses from clients and cross-check against Coast Guard manifest requirements
  • Payment status monitoring—automatically remind guests of outstanding balances as the charter date approaches
  • Crew coordination—trigger follow-ups to crew only when their role is confirmed in DynamoDB
  • Weather-driven rescheduling—if marine forecast deteriorates, auto-notify guests of potential reschedule windows

All of these can be built as additional rules in the template system and digest pipeline without architectural changes.

```