```html

Building a Comprehensive Infrastructure Snapshot: Lessons from Multi-Site AWS Architecture Complexity

When working with interconnected web properties spanning multiple domains, S3 buckets, Lambda functions, and Google Apps Script projects, a single misconfiguration or reversion can cascade across your entire system. This post documents the technical approach to creating a complete v1.0 snapshot of the JADA ecosystem—three production sites (queenofsandiego.com, sailjada.com, salejada.com) plus their supporting infrastructure—and the architectural decisions that made it possible.

The Problem: Distributed State Across Multiple Services

The JADA infrastructure spans:

  • 46 S3 buckets containing static assets, backups, and site content
  • 66 CloudFront distributions serving these buckets with caching and origin configuration
  • 21 Lambda functions handling booking automation, data processing, and request routing
  • 16 Route53 hosted zones managing DNS across domains
  • 14 DynamoDB tables for persistent state
  • 4 Google Apps Script projects tied to Google Sheets for booking systems
  • 1 Lightsail instance running application logic and cron jobs
  • Local repositories containing deployment tools, site code, and configuration

The challenge: no single point of truth. Snapshots required coordinating across AWS APIs, Google Cloud APIs, local file systems, and S3 object metadata.

Technical Approach: Parallel Agents with Structured Inventory

1. AWS Resource Discovery

Before snapshots, we needed a complete inventory. We used AWS CLI to list all resources:

aws s3api list-buckets --query 'Buckets[*].Name' --output text
aws cloudfront list-distributions --query 'DistributionList.Items[*].[Id,DomainName]' --output text
aws lambda list-functions --query 'Functions[*].[FunctionName,Runtime,LastModified]' --output json
aws route53 list-hosted-zones --query 'HostedZones[*].[Id,Name]' --output text
aws dynamodb list-tables --output json

This produced the baseline inventory: 45 S3 buckets directly tied to JADA, 41 CloudFront distributions (the remaining 25 were unrelated), 21 Lambda functions, 11 Route53 zones, and 14 DynamoDB tables.

2. Parallel Download Strategy

Instead of sequential operations (which would take hours), we split work across four background agents running in parallel:

  • Agent 1: S3 Syncaws s3 sync s3://<bucket-name> /snapshot/v1.0/s3/<bucket-name>/ for all 45 buckets in batches
  • Agent 2: Lambda Export — For each function, pull code via aws lambda get-function, extract environment variables via aws lambda get-function-configuration, and store as JSON manifests
  • Agent 3: AWS Configurations — Export CloudFront distributions via aws cloudfront get-distribution-config, Route53 records via aws route53 list-resource-record-sets, DynamoDB schemas via aws dynamodb describe-table
  • Agent 4: Local Files — Copy repositories from /Users/cb/Documents/repos/sites/ and /Users/cb/Documents/repos/tools/ with full git history

Progress tracking showed steady completion: S3 at 30/45 synced (68MB), Lambda at 10/21 exported, CloudFront at 41/41 complete, Route53 at 11/11 complete.

3. Google Apps Script Extraction

GAS projects don't have direct AWS export. Instead, we used Clasp (the Apps Script CLI):

clasp login
clasp clone <SCRIPT_ID>
clasp pull

This pulled four projects:

  • Main JADA booking system (queenofsandiego.com)
  • Rady Shell replacement GAS project
  • Rady Shell legacy GAS project
  • EYD GAS project

Each was copied to /snapshot/v1.0/gas/ with its full source tree, including Code.gs, BookingAutomation.gs, and associated configuration.

4. Lightsail Instance Snapshot

The Lightsail instance running application code and scheduled tasks was snapshotted via AWS console (also available via CLI):

aws lightsail create-instance-snapshot \
  --instance-name <instance-name> \
  --snapshot-name jada-agent-v1.0-20260509

This captures the full filesystem, environment variables (stored in /home/ubuntu/.env on the instance), cron jobs, and installed dependencies.

Snapshot Structure and Organization

The v1.0 snapshot was organized as follows:

/snapshot/v1.0/
├── MANIFEST.md                    # Inventory of all resources
├── s3/
│   ├── queenofsandiego-com/
│   ├── sailjada-com/
│   ├── salejada-com/
│   ├── (42 more buckets)
├── lambda/
│   ├── BookingHandler.json        # Code + config + env vars
│   ├── EventProcessor.json
│   ├── (19 more functions)
├── gas/
│   ├── main-jada/                 # Clasp-pulled GAS projects
│   ├── rady-replacement/
│   ├── rady-old/
│   ├── eyd/
├── aws-configs/
│   ├── cloudfront-distributions.json
│   ├── route53-records.json
│   ├── dynamodb-schemas.json
│   ├── api-gateway-stages.json
├── lightsail/
│   ├── jada-agent-v1.0-20260509  # Snapshot ID (full filesystem)
├── local-repos/
│   ├── queenofsandiego.com/       # Full git history
│   ├── sailjada.com/
│   ├── tools/                     # Deployment scripts
├── env-vars/
│   ├── lambda-environment-manifest.json
│   ├── lightsail-env-vars.json
└── metadata/
    ├── snapshot-timestamp.txt
    ├── resource-counts.txt
    ├── file-integrity-hashes.txt

Key Architectural Decisions

Why Parallel Agents?

Sequential download of 45 S3 buckets + 21 Lambda functions + configurations would take 2-3 hours. Four parallel agents reduced this to ~30 minutes. Trade-off: more complex error tracking, but acceptable given the scope.

Why Store GAS Separately?

Google Apps Script code isn't AWS-native. By using Cla