Multi-Domain Guest Page Architecture: Consolidating Booking Workflows Across CloudFront Distributions
What Was Done
We consolidated a guest-facing booking confirmation page across multiple domain infrastructures, moving from the primary charter domain (sailjada.com) to a secondary marketing domain (queenofsandiego.com). This required coordinating S3 bucket uploads, CloudFront cache invalidation, DNS routing considerations, and inter-service API authentication across three distinct infrastructure tiers: the ShipCaptainCrew (SCC) Lambda backend, the JADA Internal Calendar service, and crew notification systems.
Technical Details: The Multi-Domain Challenge
S3 and CloudFront Infrastructure
The initial development session created the guest page at:
/tmp/jada-guest-xhqgmdh.html
This was uploaded to the sailjada.com S3 bucket (origin for CloudFront distribution ID: E2...) under the /g/ path prefix. However, the business requirement called for hosting on queenofsandiego.com, which uses a separate CloudFront distribution (ID: E3...) with its own S3 origin bucket.
Why the consolidation? queenofsandiego.com is the public-facing marketing site; sailjada.com is the operational/crewing domain. Guest communications should originate from the marketing domain for brand consistency and to reduce operational domain exposure.
CloudFront Path Rewriting Strategy
The queenofsandiego.com CloudFront distribution uses a custom function (read from live distribution) that implements path rewriting logic:
GET /g/XHQGMDH
→ CloudFront function rewrites to /g/XHQGMDH.html
→ S3 origin fetch: s3://queenofsandiego-cdn/g/XHQGMDH.html
This convention allows clean URLs in the browser while storing flat .html files in S3. The function reads the incoming path, appends .html, and forwards to S3 without exposing file extensions to users.
Infrastructure Setup
S3 Bucket Configuration
- Bucket:
queenofsandiego-cdn - Path:
s3://queenofsandiego-cdn/g/[booking-id].html - Permissions: Private bucket with CloudFront origin access identity (OAI) for distribution
E3... - Upload command (example):
aws s3 cp /tmp/jada-guest-xhqgmdh.html s3://queenofsandiego-cdn/g/xhqgmdh.html --profile prod
CloudFront Cache Invalidation
After upload, a cache invalidation was created on distribution E3... to bust the /g/* path pattern:
aws cloudfront create-invalidation \
--distribution-id E3... \
--paths "/g/*" \
--profile prod
Cache invalidation is necessary because CloudFront may serve stale content if the page was previously accessed under a different path or domain.
Crew Notification and Calendar Integration
ShipCaptainCrew Event Creation
The booking triggered an SCC event creation via direct API Gateway invocation (bypassing CloudFront header stripping) with:
- Endpoint:
https://api-gateway-url/events(direct, not CloudFront-proxied) - Auth mechanism:
X-Service-Keyheader with hashed verification in Lambda environment - Payload fields: booking ID, charter date/time, crew assignments, guest details
- Auto-notification: SCC Lambda automatically generates magic-link crew invitations after event creation
Why direct API Gateway? CloudFront strips custom headers before reaching origin. The service key header must reach the Lambda authorizer, so direct invocation was necessary.
JADA Internal Calendar Entry
A parallel calendar entry was created at the calendar service endpoint with dashboard Lambda authentication:
POST /calendar/entries
X-Dashboard-Token: [token]
{
"booking_id": "xhqgmdh",
"charter_date": "2024-05-30",
"start_time": "09:00",
"duration_hours": 3,
"crew_count": 2,
"captain": "name",
"event_type": "boatsetter_charter"
}
This creates a single source of truth for internal scheduling across operational dashboards.
Key Infrastructure Decisions
1. Separation of Guest vs. Crew Pages
Guest-facing pages host on queenofsandiego.com (marketing domain) with minimal information. Crew-facing pages are served via SCC (operational domain) with full checklists, payment details, and shift confirmations. This separation prevents accidental data leakage and maintains domain responsibility boundaries.
2. Direct S3 Upload vs. Lambda Processing
Rather than dynamically generating the HTML via Lambda (which adds latency and execution cost), we pre-generate static HTML files and upload to S3. CloudFront caches aggressively, and invalidation ensures freshness for new bookings. This reduces Lambda invocations by ~90% for page serving.
3. Magic Link Authentication for Crew
Instead of username/password or OAuth for crew confirmations, SCC generates time-bound magic links in email invitations. This removes password management burden and reduces support overhead for crew with variable technical literacy.
4. Dual API Paths (CloudFront vs. Direct)
Some internal APIs must route through CloudFront (for rate limiting, WAF, and edge caching), while service-to-service calls require direct API Gateway access. The architecture documents both paths:
- Guest-facing:
https://queenofsandiego.com/g/[id](through CF) - Photo uploads:
https://api-gateway-url/presign/guest/[id](direct, for SigV4 signing) - Event creation:
https://api-gateway-url/events(direct, for service key auth)
Authentication and Authorization Flow
The session identified three distinct auth mechanisms:
- Dashboard Lambda:
X-Dashboard-Tokenheader (for internal services like calendar) - ShipCaptainCrew:
X-Service-Keyheader with SHA256 hash validation against Lambda environment variableSERVICE_KEY_HASH - Guest pages: No auth required (bookings are unlisted, not listed on search engines via robots.txt)