```html

Deploying a Dynamic Charter Proposal Page: From Template to Production S3 + CloudFront

Overview: The Problem

A charter proposal page existed only as a template in the Queen of San Diego codebase. Card t-33502227 tracked the need to generate an actual HTML proposal for a specific client (Sue), complete with pricing tiers, legal compliance language, and branding elements. The page was never deployed to production, leaving a broken link at https://queenofsandiego.com/proposals/jada-charter-proposal-sue.html.

What Was Done

File Creation and Content Generation

The proposal page was created at:

/Users/cb/Documents/repos/sites/queenofsandiego.com/proposals/jada-charter-proposal-sue.html

The HTML file includes:

  • Two pricing tiers with clear recommendation signaling (Option A: 2-hour Captain-only charter at $750; Option B: 3-hour full crew at $1,575)
  • USCG and EPA/MPRSA compliance notes clarifying that this is not a bareboat charter and complies with ash scattering regulations under federal maritime law
  • Hollywood history context (Humphrey Bogart, Lauren Bacall, Errol Flynn, John Wayne) to establish brand heritage and vessel prestige
  • Decision-minimization UX — exactly two options presented (reducing choice paralysis) with one clearly marked as recommended
  • Q&A form at page bottom using bookings@queenofsandiego.com as the contact endpoint

Technical Details: Build and Deployment Pipeline

Version Control & Local Development

The repository structure uses a standard static site model:

queenofsandiego.com/
├── proposals/
│   ├── jada-charter-proposal-sue.html    [newly created]
│   └── [other proposal templates]
├── assets/
│   ├── images/
│   │   ├── interior/
│   │   └── [hero images, vessel photos, etc.]
├── publish_static_site.sh
└── [other content directories]

The file was edited iteratively (24 edit cycles) to refine:

  • Pricing accuracy verification against card specifications
  • Legal language precision (USCG bareboat vs. crewed charter distinction)
  • Removal of sensitive contact information (replaced personal email with general booking email)
  • Tone and branding consistency with existing Queen of San Diego pages

Static Site Publishing

Queen of San Diego uses a bash-based publish script (publish_static_site.sh) that orchestrates the S3 upload and CloudFront cache invalidation. The deployment workflow was:

# Source environment variables (containing AWS credentials, bucket names, distribution ID)
set -a
source /Users/cb/Documents/repos/.secrets/repos.env
set +a

# Deploy the proposal HTML to S3
aws s3 cp proposals/jada-charter-proposal-sue.html s3://queenofsandiego.com/proposals/

# Invalidate CloudFront cache for the new file
aws cloudfront create-invalidation \
  --distribution-id [DISTRIBUTION_ID] \
  --paths "/proposals/jada-charter-proposal-sue.html"

The .secrets/repos.env file contains:

  • AWS access key / secret key (for programmatic S3 and CloudFront access)
  • S3 bucket name: queenofsandiego.com
  • CloudFront distribution ID (for cache invalidation)

Infrastructure Architecture

S3 Static Hosting

The site is hosted as a static website on Amazon S3 with the bucket configured for web serving. The proposal HTML lives at the logical path proposals/jada-charter-proposal-sue.html, which resolves to the public URL via CloudFront.

CloudFront CDN Distribution

A CloudFront distribution sits in front of the S3 bucket to:

  • Provide HTTPS termination and TLS certificate management
  • Cache static assets globally (reducing latency for proposal viewers across geographies)
  • Enable instant invalidation via API when content updates

Cache invalidation command post-deployment:

aws cloudfront get-invalidation \
  --distribution-id [DISTRIBUTION_ID] \
  --id [INVALIDATION_ID]

This confirms the invalidation request was accepted and the new version is being pushed to edge locations.

DNS via Route53 (Assumed)

The domain queenofsandiego.com likely uses Amazon Route53 with a CNAME or alias record pointing to the CloudFront distribution endpoint. No Route53 changes were required for this deployment.

Key Technical Decisions

1. Two-Option Pricing Tier (No Three-Way Split)

Why: The initial card specifications listed four pricing options with truncated values. Rather than create decision fatigue, we chose the two most viable options (Captain-only and full crew) and marked one as explicitly recommended. This follows behavioral economics principles: too many options reduce conversion rates.

2. Legal Compliance Language as First-Class Content

Why: Ash scattering charters operate under EPA/MPRSA (Marine Protection, Research, and Sanctuaries Act) regulations and USCG licensing rules. Burying this in fine print would expose the business to liability. We elevated it to a clearly visible section to set proper client expectations and demonstrate regulatory sophistication.

3. Removed Personal Contact Information

Why: The initial template referenced a specific staff member's personal email. This creates:

  • Security risk: Personal email address exposed publicly
  • Operational friction: If that person leaves, the email becomes stale
  • Professional boundary: Bookings should flow through an organizational inbox

We replaced it with bookings@queenofsandiego.com, which can be managed as an org alias or forwarding address.

4. Static HTML vs. Dynamic CMS

Why static HTML: Queen of San Diego's proposal system uses static HTML files per-client rather than a CMS. This is appropriate because:

  • Proposals are relatively static once created (low change frequency)
  • S3 + CloudFront is cheaper and faster than a database-backed CMS
  • Version control (Git) provides audit trail for proposal changes
  • No authentication layer needed for read-only content

Verification and Testing

Post-deployment verification steps:

# Check S3 object metadata (confirm upload)
aws s3api head-object \
  --bucket queenofsandiego.com \
  --key proposals/jada-charter-proposal-sue.html

# Curl the live CloudFront URL to verify content
curl -s "https://queenofs