Staging a Dynamic Event Section: Additive Deployment Pattern for zunigashoals.com
This post documents the staged deployment of a new "Zuniga Days" event section to the zunigashoals.com marketing site—specifically, the infrastructure decisions, file management, and deployment strategy that kept production untouched while validating the new feature set in a staging environment.
What Was Done
We added a new promotional section for an unsanctioned anchorage event to the zunigashoals.com homepage. Rather than modifying production directly, we:
- Captured the current production
index.htmlas a timestamped snapshot - Injected new CSS, HTML markup, and email-capture JavaScript into a staging copy
- Deployed the modified file to a
/_staging/prefix in S3 - Verified the staging URL served the new content without touching the production file
This additive deployment pattern—adding a prefix rather than overwriting—is particularly useful for marketing sites where stakeholder feedback cycles are tight and production stability is non-negotiable.
Technical Details: File Structure and Content Additions
Source and Target:
- Working file:
/tmp/zuniga-staging.html(local development copy) - Production snapshot:
/tmp/zunigashoals.com__index.html__2026-05-26T17-31-10Z.prod-snapshot - Staging deployment target:
s3://zunigashoals.com/_staging/index.html - Production (unchanged):
s3://zunigashoals.com/index.html
Content Additions (~212 lines):
- Sticky ribbon: A top-of-page callout: "Zuniga Days · the last free open anchorage in San Diego" with supporting CSS classes (
.ribbon,.ribbon-text) - New section markup: A full
<section id="zd">positioned between the hero and shop sections, containing:- Pull quote: "Who's in charge here?" — NO ONE.
- Three-column pillar row: PERMIT (none required), COST (free to anchor), RULES (see above)
- Six activity tiles with grid layout: Unsanctioned Dinghy Races, Zuniga Shoals T-Shirt Contest, Boat-Diving Contest, Raftup & Rage, Anchor & Anthem, Flag Off Your Stern
- "What you get for free" callout highlighting nearby landmarks (Hotel Del, Coronado, Point Loma)
- "No boat? No problem" CTA to find a dinghy partner
- Email-capture form: Placeholder text "Tell me the day. I'll be there." with form submission wired to the existing Google Apps Script endpoint
- CSS classes: Scoped to
.zd*namespace (.zd-section,.zd-pillar,.zd-tile,.zd-email, etc.) to avoid style collision with existing site CSS
Infrastructure: S3 Bucket Layout and CloudFront Routing
S3 Bucket Structure:
s3://zunigashoals.com/
├── index.html (production — untouched)
├── _staging/
│ └── index.html (new staging deployment)
├── css/
├── js/
└── assets/
The /_staging/ prefix is intentionally non-standard to avoid accidental indexing or SEO crawling. It's a private validation environment, not a public pre-production URL.
CloudFront Distribution:
The CloudFront distribution serving zunigashoals.com has origin configured to the S3 bucket with default root object set to index.html. By deploying to /_staging/index.html, we stay within the same distribution but on a distinct object path, ensuring:
- No cache invalidation required (staging requests go directly to that specific object)
- Production objects remain unaffected; existing cache TTLs on
/index.htmlare undisturbed - A separate staging URL (
https://zunigashoals.com/_staging/index.html) is immediately accessible for review
Email Capture Integration
The new section includes an email-capture form that submits to the existing Google Apps Script endpoint (already handling other site interactions). The form posts a JSON payload with:
{
"action": "zuniga_days_signup",
"email": "[user-provided email]",
"timestamp": "[ISO 8601 timestamp]"
}
This action key allows the GAS handler to route Zuniga Days signups to a distinct sheet or webhook, keeping event data separate from other form submissions.
Key Decisions
Why Snapshot Before Deploy? The production snapshot (/tmp/zunigashoals.com__index.html__2026-05-26T17-31-10Z.prod-snapshot) serves as a quick rollback reference and audit trail. If staging feedback necessitates a revert, the snapshot provides a byte-identical baseline. This is especially valuable for marketing sites where rapid iteration is expected.
Why the /_staging/ Prefix Instead of a Separate Domain? A separate staging domain (e.g., staging.zunigashoals.com) would require additional Route53 records, a second CloudFront distribution, and separate SSL certificates. Using a path prefix keeps infrastructure simpler, avoids cookie/CORS complications, and allows stakeholders to review the feature in the context of the actual domain.
Why Additive CSS Namespacing? By scoping all new styles to a .zd-* prefix, we ensure zero style collision with existing site CSS. The staging file can coexist with production indefinitely without risk of cascade issues if both are served temporarily.
Why Not Invalidate CloudFront? Since we're writing to a new object path (/_staging/index.html) rather than overwriting the production object, there's no cache to invalidate. Stakeholder browsers fetch the staging file directly from origin or CloudFront's fresh cache for that path.
Open Questions and Next Steps
- Event Name: "Zuniga Days" is the working title. Once stakeholders confirm, the section heading and ribbon text need a single-word replacement throughout the markup.
- Event Dates: The email-capture CTA currently shows "lands soon." Dates should come from product/ops; the form will log interest for now.
- Subdomain Registration: Three candidates were noted:
zunigadays.com,zunigashoalsdays.com,lastfreeanchor.com. Registrar check and domain grab should happen once naming is locked. - Annual Event Tee Grid Slot: The section