```html

Creating a Proposal-to-Deployment Pipeline: Building a Dynamic Charter Proposal Page with S3 + CloudFront

What Was Done

We created a missing static proposal page for a sailing charter service by building out the complete file structure, content, and deployment pipeline. The page `/proposals/jada-charter-proposal-sue.html` didn't exist in the repository despite being referenced in navigation—only a template existed. This required creating the HTML artifact, deploying it through S3/CloudFront, and invalidating the CDN cache to make it live.

Technical Details

File Structure & Repository Layout

The site structure follows a static site generator pattern:

/Users/cb/Documents/repos/sites/queenofsandiego.com/
├── proposals/
│   ├── jada-charter-proposal-sue.html  (newly created)
│   └── [other proposal files]
├── assets/
│   └── images/
│       ├── interior/
│       └── [image assets]
├── publish_static_site.sh
└── [other site files]

The decision to place the proposal in `/proposals/` rather than at the root level follows a logical content hierarchy: charter-related documents live in their own namespace, making the information architecture clear for both the filesystem and end users navigating the site.

HTML Content Structure

The proposal page was built with semantic HTML structure targeting three distinct content sections:

  • Pricing Options: Two clear options (Option A: 2-hour Captain-only at $750; Option B: 3-hour full crew at $1,575) to reduce decision fatigue
  • Legal Compliance Notes: USCG licensing, bareboat charter disclaimers, and EPA/MPRSA ash scattering regulation language
  • Brand Content: Hollywood history narrative (Bogart, Bacall, Flynn, Wayne era context)
  • Lead Capture: Q&A form at page footer routing to `bookings@queenofsandiego.com`

The use of a structured, option-focused layout (rather than open-ended pricing) was intentional: research on decision fatigue shows that 2–3 clear options with one marked "recommended" increases conversion over complex pricing matrices.

Deployment & Infrastructure

S3 Bucket Configuration

The site is hosted on S3 with the following deployment pattern:

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

# S3 upload command (credentials loaded from environment)
aws s3 cp proposals/jada-charter-proposal-sue.html \
  s3://[BUCKET_NAME]/proposals/jada-charter-proposal-sue.html \
  --region us-west-2

The S3 bucket is configured as a static website endpoint with public read permissions on HTML files. The `publish_static_site.sh` script automates this upload process and is sourced with environment variables from `/Users/cb/Documents/repos/.secrets/repos.env` (secrets management pattern).

CloudFront Distribution & Cache Invalidation

The site uses CloudFront as a CDN layer for performance and edge caching. After uploading to S3, the distribution cache must be invalidated so new content propagates immediately:

# Environment setup
set -a
source /Users/cb/Documents/repos/.secrets/repos.env
set +a

# CloudFront invalidation
aws cloudfront create-invalidation \
  --distribution-id [DISTRIBUTION_ID] \
  --paths "/proposals/jada-charter-proposal-sue.html" \
  --region us-west-2

Why this matters: CloudFront caches objects with a default TTL (time-to-live). Without explicit invalidation, users would see the old (missing) page for up to 24 hours. The invalidation API call creates a cache-busting operation that forces edge nodes to fetch fresh content from the origin on the next request.

DNS & Route Configuration

The domain `queenofsandiego.com` is managed through Route53 with a CNAME record pointing to the CloudFront distribution endpoint. The proposal page is accessible at:

https://queenofsandiego.com/proposals/jada-charter-proposal-sue.html

No Route53 changes were required for this deployment—the `/proposals/` path is handled entirely by the CloudFront → S3 origin chain.

Key Decisions & Rationale

Static Site vs. Dynamic Backend

This proposal is a static HTML artifact, not a dynamically generated page. This decision was made because:

  • Content is stable (pricing, legal text, history don't change frequently)
  • No server-side logic required (no database queries, no personalization)
  • Reduces attack surface (no application server vulnerabilities)
  • Improves page load speed (S3 + CloudFront edge distribution)
  • Simplifies deployment (single file commit → S3 copy → CloudFront invalidate)

Content Strategy: Limiting Options

Rather than presenting four pricing tiers or open-ended customization, we surface exactly two options with one labeled "recommended." This follows conversion rate optimization principles: more choices paradoxically decrease decision velocity. By pre-filtering to the two most common booking patterns, we reduce friction in the sales funnel.

Legal Compliance Integration

Ash scattering charters operate under EPA MPRSA (Marine Protection, Research, and Sanctuaries Act) regulations and USCG licensing requirements. Rather than burying compliance language, it's placed prominently alongside pricing to signal that this is a licensed, regulated service—not a bareboat rental.

Memory & Feedback Integration

A feedback log was created at:

/Users/cb/.claude/projects/-Users-cb-Documents-repos/memory/feedback_no_meta_copy_in_proposals.md

This captures a constraint discovered during development: proposal pages should not include metadata tags or boilerplate copy from the site template. The proposal is a standalone sales document, not a standard web page. This decision was logged to prevent template-based generation from adding navigation cruft in future proposal pages.

Image Asset Handling

The page references interior and vessel imagery stored in:

/Users/cb/Documents/repos/sites/queenofsandiego.com/assets/images/interior/

Image paths in the HTML use relative URLs to the assets directory, allowing the same HTML file to work whether served from S3, a local development server, or through CloudFront. Image optimization (compression, format conversion) happens at commit time or through a separate build step, not dynamically.

What's Next

  • Photo Integration: Confirm final image file paths and wire hero/interior shots into the proposal
  • A/B Testing: Monitor click-through rate on the two pricing options to validate the 2-option hypothesis
  • Form Integration: Verify the Q&A form backend is wired to `bookings@queenofsandiego.com`
  • Performance Audit: Check CloudFront cache hit ratio and S3 object metadata (gzip encoding for HTML)
  • Personalization