Building a Comprehensive Infrastructure Snapshot: The JADA v1.0 Backup Strategy
When you're managing three interconnected production sites with distributed cloud infrastructure, a single misconfiguration or unintended reversion can cascade across multiple systems. This post details how we built a complete v1.0 snapshot of the entire JADA ecosystem—covering 45 S3 buckets, 66 CloudFront distributions, 21 Lambda functions, and 16 Route53 hosted zones—ensuring we never lose critical infrastructure state again.
The Problem: Distributed State with No Single Source of Truth
The JADA infrastructure spans three production domains:
- queenofsandiego.com — event management and commerce
- sailjada.com — primary brand site
- salejada.com — sales/affiliate properties
This infrastructure includes:
- 45 S3 buckets (production, staging, backups, archives)
- 66 CloudFront distributions (CDN, API caching, origin failover)
- 21 Lambda functions (event handlers, transformations, webhooks)
- 16 Route53 hosted zones (DNS, traffic routing, health checks)
- Google Apps Script (GAS) projects (4 main automation engines)
- Lightsail instances (development, staging, production environments)
- DynamoDB tables (14 tables for state management)
- SES, API Gateway, ACM certificates, and IAM policies
Without a comprehensive snapshot, infrastructure changes become difficult to audit, rollback, or replicate in disaster recovery scenarios.
Snapshot Architecture: Four Parallel Agents
Rather than sequential downloads that would take hours, we deployed four parallel background agents, each handling a different component class:
Agent 1: S3 Bucket Synchronization
# Sync all JADA-related S3 buckets to local snapshot
aws s3 ls | grep -E "(jada|qos|sailjada|salejada)" | awk '{print $3}' > /tmp/jada_buckets.txt
for bucket in $(cat /tmp/jada_buckets.txt); do
aws s3 sync s3://$bucket /snapshot/v1.0/s3/$bucket \
--region us-west-2 \
--exclude ".git/*" \
--exclude "node_modules/*" \
--exclude "venv/*"
done
Result: 45 buckets synced (68MB+ total), organized by bucket name. This preserves bucket structure exactly as it exists in production.
Agent 2: Lambda Code & Configuration Export
Lambda functions were pulled using the AWS CLI and aws lambda get-function for code, plus describe-function for configuration:
# Export all Lambda functions with their code and metadata
aws lambda list-functions --region us-west-2 --query 'Functions[*].FunctionName' \
--output text | tr '\t' '\n' | while read func; do
# Create function directory
mkdir -p /snapshot/v1.0/lambda/$func
# Export function code and configuration
aws lambda get-function --function-name $func --region us-west-2 \
--query 'Code.Location' --output text | xargs -I {} curl -o /snapshot/v1.0/lambda/$func/code.zip {}
# Export function configuration
aws lambda get-function-configuration --function-name $func --region us-west-2 \
> /snapshot/v1.0/lambda/$func/config.json
done
Key detail: We exported both compiled code (as .zip files) and full function metadata (timeout, memory, environment variables structure, VPC configuration, IAM execution role ARN). This ensures we can rebuild identical Lambda functions from snapshot.
Agent 3: AWS Infrastructure Configuration
CloudFront, Route53, DynamoDB, SES, API Gateway, and ACM were exported using describe-* and list-* operations:
# CloudFront distributions
aws cloudfront list-distributions > /snapshot/v1.0/aws/cloudfront-distributions.json
# Route53 hosted zones and records
aws route53 list-hosted-zones > /snapshot/v1.0/aws/route53-zones.json
aws route53 list-resource-record-sets --hosted-zone-id Z1234ABCD > /snapshot/v1.0/aws/route53-records.json
# DynamoDB table schemas
aws dynamodb list-tables > /snapshot/v1.0/aws/dynamodb-tables.json
for table in $(aws dynamodb list-tables --query 'TableNames' --output text); do
aws dynamodb describe-table --table-name $table \
> /snapshot/v1.0/aws/dynamodb/${table}-schema.json
done
All credentials and sensitive values were stripped from these exports before storage.
Agent 4: Google Apps Script & Local Code
GAS projects were pulled using Clasp (the Google Apps Script CLI), then all local repositories and configuration were copied:
# Pull main JADA GAS project
clasp pull --projectId abc123def456 -r main
cp -R ~/.clasp/* /snapshot/v1.0/gas/main-jada/
# Pull Rady Shell GAS (replacement version)
clasp pull --projectId xyz789uvw456 -r main
cp -R ~/.clasp/* /snapshot/v1.0/gas/rady-shell-replacement/
This captured four distinct GAS automation engines used for event management, data syncing, and webhook processing.
Special Handling: Lightsail Instance Snapshot
For stateful instances running development and staging environments, we triggered AWS Lightsail snapshots that capture disk state, application code, and database dumps at the instance level. The Lightsail snapshot ID jada-agent-v1.0-20260509 was generated and tracked separately, with AWS handling the ~15 minute creation process asynchronously.
Staging Workflow Integration
During snapshot creation, we also synchronized production assets to staging CloudFront distributions:
- QOS production bucket → staging bucket (full sync)
- Sailjada production bucket → staging bucket (full sync)
- CloudFront cache invalidation on staging distributions (ensuring fresh content)
This allowed parallel verification that staging mirrors production exactly, detected via file count comparison:
# Verify file count parity
prod_count=$(aws s3 ls s3://sailjada-prod --recursive | wc -l)
staging_count=$(aws s3 ls s3://sailjada-staging --recursive | wc -l)
if [ "$prod_count" -eq "$staging_count" ]; then
echo "✓ Staging matches production ($prod_count files)"
else
echo "✗ Mismatch: prod=$prod_count, staging=$staging_count"
fi
Snapshot Structure & Manifest
The complete v1.0 snapshot is organized as:
/snapshot/v1.0/
├── MANIFEST.md # Complete inventory with file counts
├── s3/ # 45 buckets, organized by name
│ ├── sailjada-prod/
│