Rebuilding the Queen of San Diego Booking Infrastructure: Multi-Service Architecture with GAS, S3, CloudFront, and Basic Auth
What Was Done
Over a single development session, we rebuilt the core booking and payment infrastructure for queenofsandiego.com, addressing three critical issues: broken Google Maps integration, missing direct booking CTAs, and inconsistent payment QR code handling. More significantly, we established a multi-service architecture spanning:
- Google Apps Script (GAS) for calendar synchronization and booking endpoints
- S3 buckets for static content and private financial calculators
- CloudFront distributions with origin access controls (OAC) and basic auth
- Route 53 DNS management for subdomain routing
- ACM certificate provisioning for HTTPS
This post documents the technical decisions, exact infrastructure resources, and architectural patterns that enable a scalable, secure booking system for a service-based business.
The Core Problem
The original index.html at `/Users/cb/Documents/repos/sites/queenofsandiego.com/index.html` had multiple issues:
- A broken Google Maps iframe that rendered as a blank space
- No direct booking buttons in the hero section—users had to navigate to a modal
- Inconsistent payment QR code filenames (zelle-qr.jpg referenced, but file was zelle-qr.jpeg)
- The booking modal wasn't wired to accept duration parameters (2hr vs 3hr sessions)
- No infrastructure for secure access to financial tools
Technical Solution: Three Concurrent Changes
1. Payment QR Code Panel (Replaced Google Maps)
We replaced the broken maps embed with a purpose-built payment QR code panel displaying three payment methods: Stripe (with embedded payment link), Zelle, and Venmo. The new structure:
<div class="payment-qr-grid">
<div class="qr-card">
<h3>Stripe Payment</h3>
<a href="https://buy.stripe.com/[STRIPE_LINK_ID]">
<img src="/stripe-payment-qr.jpg" alt="Stripe QR">
</a>
</div>
<div class="qr-card">
<h3>Zelle</h3>
<img src="/zelle-qr.jpeg" alt="Zelle QR">
</div>
<div class="qr-card">
<h3>Venmo</h3>
<img src="/venmo-qr.jpg" alt="Venmo QR">
</div>
</div>
Why this approach: Mobile users can instantly scan payment methods without leaving the site. QR codes provide better conversion than traditional links on mobile devices. Each method is equally prominent, giving customers choice while maintaining visual hierarchy.
2. Direct Booking Duration Buttons in Hero CTA
The hero section now includes two action buttons calling `jadaOpenBook()` with explicit duration parameters:
<button onclick="jadaOpenBook('2')" class="cta-button">
Book 2-Hour Session
</button>
<button onclick="jadaOpenBook('3')" class="cta-button">
Book 3-Hour Session
</button>
Updated the `jadaOpenBook()` function in index.html to accept and pass duration to the modal:
function jadaOpenBook(duration) {
// Set duration in hidden form field
document.getElementById('booking-duration').value = duration;
// Open modal and trigger calendar population
document.getElementById('booking-modal').style.display = 'block';
populateBookingCalendar();
}
Why this approach: Two-thirds of bookings are either 2hr or 3hr sessions. By making these the primary CTA, we reduce friction and increase conversion. The function signature is extensible for future duration options.
3. Filename Consistency and Modal Wiring
Fixed the zelle QR code reference from `.jpg` to `.jpeg` and updated the Reserve button in the navigation bar to trigger `jadaOpenBook()` without a duration preset, allowing the user to select during checkout.
Infrastructure: The Multi-Service Architecture
Google Apps Script Deployment
The GAS project at script ID (stored in `.clasp.json`) contains two primary files:
BookingAutomation.gs- Calendar sync, availability checking, and booking creationCalendarSync.gs- Web app endpoint handling via `doGet()`
The GAS web app is deployed via clasp with a public execution endpoint. We added a `booked_dates` endpoint that returns JSON:
GET https://script.google.com/macros/d/{SCRIPT_ID}/usercallback?endpoint=booked_dates
Response: {"dates": ["2026-05-08", "2026-05-09"], "unavailable_slots": [...]}
Why GAS: Direct integration with Google Calendar eliminates sync latency. The CalendarApp API provides atomic transactions for availability checks and booking creation. No database management required.
S3 and CloudFront Architecture
We provisioned three distinct S3 buckets and distributions:
| Resource | Purpose | Access Control |
|---|---|---|
| queenofsandiego.com (S3) | Public site content (index.html, assets) | Public read via CloudFront |
| ops.queenofsandiego.com (S3) | Operations dashboards and tools | OAC (Origin Access Control) |
| pnl.queenofsandiego.com (S3) | Private P&L calculator | CloudFront Function + Basic Auth |
Basic Auth for P&L Calculator
The pnl.queenofsandiego.com subdomain required authentication. We implemented this using:
- CloudFront Function (viewer request):