This document describes the automated backup system for Workload Wizard, including scheduling, contents, storage, and monitoring.
- Frequency: Daily
- Time: 02:00 Europe/London (01:00 UTC)
- Trigger: GitHub Actions scheduled workflow
- Duration: Typically 5-15 minutes
- Trigger: GitHub Actions workflow dispatch
- Access: Repository administrators only
- Options: Force upload (bypass deduplication)
- Source: Production Convex deployment
- Format: ZIP archive containing JSON data
- Size: Variable (typically 1-50 MB)
- Contents:
- All tables and documents
- System metadata
- Audit logs and timestamps
- Source: Vercel API (
/v10/projects/{project}/env) - Format: Minified JSON
- Size: Typically < 10 KB
- Contents:
- Application configuration
- API keys and secrets
- Feature flags
- Environment-specific settings
- Source: WorkOS API with pagination
- Format: Minified JSON array
- Size: Variable (typically 10-100 KB)
- Contents:
id: User identifierexternal_id: External system identifiercreated_at: Account creation timestamplast_active_at: Last activity timestampbanned: Account ban statuslocked: Account lock statusemail_addresses: Array of email addresses
- Primary: zstd (Zstandard) - faster and better compression
- Fallback: gzip - if zstd not available
- Archive Format: TAR with compression
- File Extension:
.tar.zstor.tar.gz
- Provider: Cloudflare R2
- Bucket: Configured via
R2_BUCKETsecret - Endpoint: Configured via
R2_ENDPOINTsecret - Path Structure:
s3://ww-backups/ ├── backup_20250127T020001Z.tar.zst ├── backup_20250128T020001Z.tar.zst └── latest.json
- Method: Content-based hashing (SHA256)
- Check: Compare with previous backup's content hash
- Behavior: Skip upload if content unchanged
- Manifest: Upload small
run.jsonwith status
# Export Convex data
convex export --prod --output backup/convex_snapshot.zip
# Fetch Vercel environment variables
curl -H "Authorization: Bearer $VERCEL_TOKEN" \
"https://api.vercel.com/v10/projects/$VERCEL_PROJECT/env" \
| jq -c '.' > backup/vercel/env.json
# Fetch WorkOS users with minimal fields
# (Paginated API calls with field filtering){
"timestamp": "2025-01-27T02:00:00Z",
"source": "prod",
"sizes": {
"convex_zip": 1234567,
"vercel_env": 2048,
"workos_users": 51200
}
}# Try zstd first, fallback to gzip
if command -v zstd >/dev/null 2>&1; then
tar --zstd -cf "backup_${timestamp}.tar.zst" -C backup .
else
tar -czf "backup_${timestamp}.tar.gz" -C backup .
fi# Download latest.json from R2
aws s3 cp "s3://$R2_BUCKET/latest.json" latest.json --endpoint-url "$R2_ENDPOINT"
# Compare content hashes
if [ "$existing_hash" = "$new_hash" ]; then
echo "Content unchanged, skipping upload"
# Upload only run.json manifest
else
echo "Content changed, proceeding with upload"
# Upload archive and update latest.json
fi- Status: Uploaded/Skipped/Failed
- Compression: Algorithm used
- Content Hash: SHA256 checksum
- File Sizes: Individual component sizes
- R2 Key: Archive location in R2
- Manifest:
backup/manifest.json(7-14 day retention) - Run Log:
run.jsonwith execution details - Archive: Stored in R2 only (not GitHub)
- Slack Notifications: On backup failures
- GitHub Notifications: Workflow status updates
- Email Alerts: Repository administrators
- Navigate to Actions tab in repository
- Select "Nightly DR Backup to R2" workflow
- Click "Run workflow"
- Optionally check "Force upload" to bypass deduplication
- Monitor execution in real-time
# Install dependencies
npm ci
npm install -g convex
# Set environment variables
export CONVEX_DEPLOY_KEY_PROD="your-prod-key"
export VERCEL_TOKEN="your-vercel-token"
export VERCEL_PROJECT="workload-wizard"
export WORKOS_API_KEY="your-workos-key"
export R2_ACCESS_KEY_ID_BACKUP="your-r2-key"
export R2_SECRET_ACCESS_KEY_BACKUP="your-r2-secret"
export R2_BUCKET="ww-backups"
export R2_ENDPOINT="https://your-account.r2.cloudflarestorage.com"
# Run backup script (if available)
npm run backup:manual- Symptom:
convex exportcommand fails - Causes: Invalid deploy key, network issues, Convex service down
- Resolution: Verify
CONVEX_DEPLOY_KEY_PRODsecret, check Convex status
- Symptom: Vercel environment fetch fails
- Causes: Invalid token, project not found, API rate limits
- Resolution: Verify
VERCEL_TOKENandVERCEL_PROJECTsecrets
- Symptom: WorkOS user fetch fails
- Causes: Invalid secret key, API rate limits, pagination issues
- Resolution: Verify
WORKOS_API_KEYsecret, check API limits
- Symptom: Archive upload to R2 fails
- Causes: Invalid credentials, bucket not found, network issues
- Resolution: Verify R2 credentials and bucket configuration
- Symptom: Content hash mismatch causing unnecessary uploads
- Causes: Data corruption, hash calculation errors
- Resolution: Check hash calculation logic, verify data integrity
-
Check Workflow Logs
- Navigate to Actions tab
- Click on failed workflow run
- Review step-by-step execution logs
-
Verify Secrets
- Ensure all required secrets are set
- Check secret values are correct and not expired
-
Test Individual Components
- Test Convex export manually
- Test Vercel API access
- Test WorkOS API access
- Test R2 connectivity
-
Check Resource Limits
- Verify GitHub Actions runner resources
- Check API rate limits
- Monitor R2 storage quotas
- Full Archives: 30 days in R2
- Manifests: 90 days in R2
- GitHub Artifacts: 7-14 days
- Logs: 90 days in GitHub Actions
- Deduplication: Reduces storage and transfer costs
- Compression: Minimizes storage footprint
- Lifecycle Rules: Automatic cleanup of old archives
- Monitoring: Regular cost analysis and optimization
- Encryption: All data encrypted in transit and at rest
- Access Control: Least privilege for backup credentials
- Audit Trail: Complete activity logging
- Isolation: Separate credentials for backup/restore
Document Version: 1.0
Last Updated: 2025-01-27
Next Review: 2025-04-27
Owner: DevOps Team Lead