Diagnosing and Resolving a Multi-Site Deployment Pipeline: OAuth Token Expiry, Booking Widget Template Parsing, and GA4 Integration
This session involved debugging a complex, multi-tenant deployment infrastructure spanning three separate sites (86from.com, sailjada.com, and queenofsandiego.com), troubleshooting a broken Google OAuth token in a background sync daemon, fixing template syntax errors in a booking widget, and establishing proper GA4 API authentication for analytics reporting. Here's a detailed technical breakdown of what happened and why.
The Starting Point: Daemon Health Diagnosis
The investigation began with a health check on the jada-agent orchestrator daemon running on a Lightsail instance (34.239.233.28). This daemon is responsible for picking up async tasks from a progress dashboard and executing Claude agent runs with a 30-turn limit per session.
What we found:
jada-agent.servicewas active and running for 3 days without crashes- CPU utilization was 0.65% on average — healthy idle state between task pickups
- Memory usage was 144MB / 914MB — well within bounds
- Three agent sessions had run today; two hit the 30-turn limit (exit code 1), one completed successfully
- A critical recurring error:
port_sheet_syncGoogle OAuth token was expired/revoked, causing sync failures every 30 minutes
Why this matters: The daemon itself is stable, but the port sheet sync — which keeps a Google Sheet synchronized with task metadata — had been silently failing. This meant downstream consumers of that data (dashboards, reporting, task routing) were working with stale information.
OAuth Token Remediation: GA4 and Google Sheets Integration
Rather than patch the existing broken token, we took the opportunity to properly establish Google OAuth credentials for multiple services. The approach:
- Created
/Users/cb/Documents/repos/tools/auth_ga.py— a dedicated OAuth flow script for establishing GA4 credentials - Leveraged existing stored credentials for the
dangerouscentaur@gmail.comaccount to bootstrap new auth flows without re-entering passwords - Verified that
google-auth-oauthlibwas installed and the token structure included bothclient_idandclient_secretfields, allowing credential reuse across multiple Google APIs - Locked down the credentials file with restrictive permissions:
chmod 600on the secrets directory
Once authenticated, we queried the GA4 API to list all properties under the dangerouscentaur account and pulled a full 7-day analytics report for 86dfrom.com (later renamed to 86from.com). This established the baseline for monitoring traffic to the newly deployed site.
Why separate OAuth from the daemon code: The auth script is idempotent and reusable. By keeping it in tools/, it can be invoked manually or scheduled independently of the daemon, reducing the risk of token expiry causing cascading failures.
SEO Content Deployment: 86from.com Launch
During this session, a new site content project for 86from.com was created and deployed. The workflow:
- Renamed the staging directory from
86dfrom.comto86from.comto match the final domain - Created a new SEO-focused page at
/Users/cb/Documents/repos/sites/86from.com/site/what-does-86d-meanto capture long-tail search traffic - Modified the main index.html multiple times to refine on-page SEO elements
- Deployed the site to an S3 bucket and invalidated the CloudFront distribution cache to ensure immediate propagation
Pre-deployment validation: We performed DNS, HTTP status, and TLS certificate checks for the domain via command-line tools, verified HTTP redirect chains, and confirmed Wayback Machine snapshots to ensure no stale cached versions would cause confusion.
Fixing Template Syntax in the Booking Widget
A critical issue was discovered in the booking widget embedded across sailjada.com and queenofsandiego.com: double-brace template syntax ({{ }}) was leaking outside the intended booking widget section and breaking the page HTML structure.
Root cause: The booking widget JavaScript was using Handlebars-style templating with double braces. However, these braces appeared both inside the widget's <script> tag and in other parts of the page, causing templating engines (if any were running) to misinterpret the markup.
The fix:
- Audited all occurrences of
{{and}}across the index.html files - Confirmed that double braces outside the widget section were in plain HTML/text contexts where they should not be interpreted as template syntax
- Replaced vulnerable double-brace patterns with single braces (
{and}) or alternative notation where outside the widget - Extracted the booking widget JavaScript block, syntax-checked it with Node.js, and confirmed it parsed without errors
- Embedded a version tag with model ID into a comment within the widget for future reference
Why this approach: Rather than strip the widget entirely, we preserved its functionality while sandboxing the templating syntax. This maintains the user-facing booking flow while reducing injection attack surface.
Multi-Site Staging and Production Deployment
Changes were deployed across three separate site repositories:
- 86from.com: New SEO content + index.html refinements → S3 bucket → CloudFront invalidation
- sailjada.com: Booking widget syntax fixes (14+ edits to index.html) → staging bucket first, then production
- queenofsandiego.com: Updates to
BookingAutomation.gs(Google Apps Script) for booking workflow automation
All S3 deployments included CloudFront cache invalidation to ensure CDN freshness. Staging deployments were validated before production push.
Infrastructure: Lightsail, S3, CloudFront, and Route53
- Lightsail Instance: 34.239.233.28 running jada-agent.service with systemd management
- SSH Access: Temporary credentials obtained via AWS Lightsail API (key pair: jada-key) for session management
- S3 Buckets: Separate buckets for each site domain; versioning enabled for rollback capability
- CloudFront Distributions: One per site for CDN acceleration and TLS termination
- Route53: DNS zones for domain routing and health checks (WHOIS and DNS validation confirmed active)
Why distributed S3 buckets: Each site is independently scalable, has separate access controls, and can be managed by different teams without cross-contamination.
Key Decisions and Rationale
- OAuth token rotation: Leveraged existing credentials to bootstrap new auth flows rather than forcing manual re-authentication, reducing friction while improving security posture
- Booking