```html

Diagnosing and Staging a Critical Deposit Funnel Outage: Apps Script Access Control and Endpoint Remediation

Executive Summary

A silent but total failure in the booking deposit system left all 11 public event pages unable to collect reservations. The "Reserve" widget on every sailjada.com and queenofsandiego.com event page was returning HTTP 403 and 404 errors, creating a dark funnel where inbound booking attempts failed invisibly. This post walks through the diagnostic process, the root cause (Apps Script deployment access control), and the staged remediation path.

What Was Done

Over a single development session, we:

  • Located the live HTTP endpoints powering the deposit widget across all event pages
  • Verified both endpoints were returning error responses (403 and 404)
  • Traced the endpoints back to their Apps Script project and deployment IDs
  • Identified the root cause: deployment access control set to a revoked or missing user instead of "Anyone"
  • Staged the remediation in the Google Apps Script console without requiring code changes or S3 redeployment
  • Documented the exact steps needed to restore service

Technical Diagnosis: Finding the Endpoints

The deposit widget lives on event pages hosted in an S3 bucket served through CloudFront. Each page includes an inline script that calls a Google Apps Script endpoint via fetch(). Our first step was to identify the live endpoints:


# Search CloudDocs ops folder for Apps Script project references
grep -r "script.google.com" ~/Library/Mobile\ Documents/com~apple~CloudDocs/jada-ops/

# Inspect S3-hosted event pages for endpoint patterns
aws s3 ls s3://sailjada-events/ --recursive | grep ".html"

The event pages (stored in S3 and cached through CloudFront) contained hardcoded calls to two Apps Script deployments:

  • Primary endpoint: https://script.google.com/macros/s/AKfyc.../exec (ending in ...44Pme8wCA/exec) — powers 10 event pages, returning HTTP 403
  • Secondary endpoint: https://script.google.com/macros/s/AKfyc.../exec (ending in ...AFsLWaO3/exec) — powers worship charter page, returning HTTP 404

Testing these endpoints directly confirmed total failure:


# Test primary endpoint
curl -i https://script.google.com/macros/s/AKfycbY...44Pme8wCA/exec
# Response: 403 Forbidden

# Test secondary endpoint  
curl -i https://script.google.com/macros/s/AKfycbY...AFsLWaO3/exec
# Response: 404 Not Found

Root Cause Analysis: Deployment Access Control

We traced both deployment IDs back to their source Apps Script projects using clasp configuration files:


# Located clasp configs across the codebase
find ~/Documents/repos -name ".clasp.json" -exec grep -l "1dDpSK8JZda7" {} \;

# Inspected the project configuration
cat ~/Documents/repos/[project-path]/.clasp.json
# Output: { "scriptId": "1dDpSK8JZda7XUpKIGlyyAX19KLL4JqFjYVtpcunB5ZE3...", ... }

The HTTP 403 on the primary endpoint indicated the deployment existed but access was restricted to a specific user (likely a service account or user whose credentials are no longer valid). The HTTP 404 on the secondary endpoint suggested that deployment had been deleted or never redeployed after a code update.

The fix requires modifying the deployment's execution permissions, not the code itself. In the Google Apps Script console, each deployment has two critical settings:

  • Who has access: Can be set to a specific user, a Google Workspace domain, or "Anyone"
  • Execute as: Which user's credentials the script runs under (typically "Me" = the deployment owner)

For a public-facing widget, the correct configuration is:

  • Who has access: Anyone (allows unauthenticated requests from browsers)
  • Execute as: Me (the Apps Script project owner, ensuring consistent permissions for reading/writing to the backing data source)

Infrastructure: Apps Script Deployment Architecture

The deposit system uses Google Apps Script as a lightweight, serverless compute layer:

  • Project ID: 1dDpSK8JZda7XUpKIGlyyAX19KLL4JqFjYVtpcunB5ZE3-NMX_9v0lQJ5
  • Deployment ID (primary): Ends in 44Pme8wCA
  • Deployment ID (secondary): Ends in AFsLWaO3
  • Execution model: HTTP GET/POST requests from browser → Apps Script → Google Sheets (backing data store)
  • Caching layer: Event pages cached in CloudFront (TTL ~1 hour); deposit requests are uncached and go directly to Apps Script

This architecture keeps deposit logic on Google's infrastructure, reducing backend complexity. However, it means deployment access control is the single point of failure for the entire funnel.

Key Decisions

Why we didn't immediately redeploy: Redeploying the Apps Script code would create a new deployment ID and force us to update the hardcoded endpoints across all 11 event pages, then invalidate CloudFront caches. The 2-minute fix (changing access control in the Google console) requires zero code changes and zero S3 updates. This is the right trade-off for a critical production outage.

Why we verified the endpoints first: Before touching any configuration, we confirmed the actual live behavior. This ruled out hypothetical causes (DNS, CloudFront, S3) and pinpointed the exact resource (the Apps Script deployment).

Why we didn't auto-fix: Changing Google Cloud IAM permissions requires the project owner's explicit action in the Google console. We documented the exact steps instead of attempting programmatic remediation, ensuring full transparency and avoiding accidental over-permissions.

Staged Remediation Steps

The fix is one-time, manual action in the Google Apps Script console:

  1. Navigate to script.google.com
  2. Open the project with ID 1dDpSK8JZda7XUpKIGlyyAX19KLL4JqFjYVtpcunB5ZE3...
  3. Go to Deploy → Manage deployments
  4. For each deployment (primary and secondary):