Region scope: This template covers us-east-2 only. CloudFormation stacks are region-scoped, and a handful of resources are forced into us-east-1 by AWS service availability — SES inbound email receiving, the CloudFront WAF, and CloudFront's own metrics all only exist there. See Section 8 for the full list and the companion template name.
The short version: This is your insurance policy. If every single piece of the us-east-2 footprint of The Trinity Beast Infrastructure were deleted tomorrow — every server, every database, every network — this one YAML file recreates all of it with a single command.
This is a disaster-recovery reference, not the live stack. The account's actual running infrastructure is hand-built — it was never deployed from this template, and it was never adopted into it. Only one CloudFormation stack genuinely exists in the account today (trinity-beast-ultimate-v3), and it owns only the base VPC/security-group layer, not the application layer. Running create-stack from this template builds a fresh, equivalent environment in parallel — it does not touch, adopt, or modify anything already running. Corrected 2026-08-13 after this file and its underlying template were found to describe infrastructure that no longer matches reality in several places (wrong cache engine, missing Lambdas, two deleted Lambdas still present, an entire feature's infrastructure missing) — see the correction notes throughout this document.
Think of CloudFormation as a blueprint for a building. When a contractor builds a house, they don't wing it — they follow a blueprint that describes every wall, every pipe, every electrical outlet. CloudFormation is the same idea, but for cloud infrastructure.
You write a YAML file that describes what you want: "I need a network, a database, three servers, a load balancer..." and AWS reads that file and builds everything for you. Every time. Exactly the same way. No clicking through consoles, no forgetting a step, no "it worked on my machine."
aws cloudformation create-stackThe Trinity Beast template is 182 resources defined in a single file, covering everything in us-east-2 — networking, databases, servers, load balancers, DNS, CDN, monitoring, AI operations, and document translation. One file. One command. Everything except the us-east-1 footprint (Section 9), which lives in its own template because CloudFormation stacks are region-scoped.
Why this matters: Without this template, recreating The Trinity Beast would mean manually clicking through dozens of AWS console screens, remembering exact settings, and hoping you don't miss anything. With this template, it's one command and a 30-minute wait. That's the difference between a weekend of panic and a coffee break.
The template defines 182 AWS resources organized into 11 layers. Each layer builds on the ones before it — you can't have servers without a network, and you can't have a load balancer without servers. CloudFormation handles the ordering automatically.
The foundation. Think of the VPC as the building itself — it defines the walls and rooms. Subnets are the rooms. The Internet Gateway is the front door. Security groups are the locks on each room's door.
| Resource | Details | Purpose |
|---|---|---|
| VPC | 10.0.0.0/16 (65,536 IPs) | The private network — your building |
| Public Subnets | 3 subnets across 3 AZs | Rooms with windows — internet-facing (load balancers live here) |
| Private Subnets | 3 subnets across 3 AZs | Interior rooms — no direct internet access (databases, servers live here) |
| Internet Gateway | 1 IGW attached to VPC | The front door to the internet |
| Route Tables | 4 route tables | Hallway signs — tell traffic where to go |
| Security Groups | 7 security groups | Door locks — control who can talk to what |
| VPC Endpoints | 10 endpoints | Private back doors to AWS services (no internet needed) |
| Flow Logs | VPC Flow Logs → CloudWatch | Security cameras — record all network traffic |
IAM roles are like employee badges — they define what each service is allowed to do. A server can read from the database but can't delete the network. Each role follows the principle of least privilege: only the permissions needed, nothing more.
| Role | Purpose |
|---|---|
| ECS Task Execution Role | Lets ECS pull Docker images from ECR and write logs to CloudWatch |
| ECS Task Role | Lets the running containers access Secrets Manager, S3, SES, SQS, and AWS Translate |
| EventBridge Role | Lets the scheduler (EventBridge) launch ECS tasks for the nightly sync job |
| Flow Logs Role | Lets VPC Flow Logs write to CloudWatch Logs |
| Receipt Lambda Role | Lets the receipt Lambda read trinity-beast-receipt-secrets (Stripe keys only — isolated from the shared DB secret), send SES, and enqueue to the email queue |
trinity-beast-email-sender-role | Dedicated role for the "brainless" email-sender Lambda — SQS consume + SES send only, no DB, no shared secret |
tbi-autonomous-ops-role | Shared execution role for all 8 AutoOps Lambdas (ECS, WAF, CloudWatch, Bedrock, SES, SNS, SQS, Secrets Manager) |
tbi-translate-role | Translation worker ECS task role only (Bedrock, S3, CloudFront, SQS, SNS) — no Lambdas share it since the deploy/finalize Lambdas were removed 2026-06-27 |
Corrected 2026-08-13. tbi-translate-pipe-role and tbi-translate-orchestrator-role no longer exist — both were deleted along with the EventBridge Pipe and Step Function they served when the translation architecture was simplified to direct SQS fan-out (2026-06-27). Added the email-sender role, which was missing entirely.
Where your data lives. Aurora is the main database (think: filing cabinets). ElastiCache is the speed cache (think: sticky notes on your desk for things you need instantly). ECR stores your Docker images. S3 stores your website files.
| Resource | Details | Purpose |
|---|---|---|
| Aurora Serverless v2 | PostgreSQL 17.7, 1.5–18 ACU, Optimized I/O | Main database — writer + reader instances |
| ElastiCache Serverless for Valkey | Valkey 9.0, auto-scaling storage (0–30 GB) and compute (0–10,000 ECPU/s), multi-AZ, TLS always-on | In-memory cache — sub-millisecond reads, no node to size or manage |
| ECR Repositories | 5 repositories | Docker image storage — trinity-beast-lpo-server, trinity-beast-sync-job, tbi-translate-worker, plus 2 legacy repos (trinity-beast, trinity-beast-lpo) kept for template parity with the account's actual inventory |
| S3 Bucket | trinity-beast-website-east2 | Website files, daily/cost reports, translated docs |
| Secrets Manager | trinity-beast-secrets + trinity-beast-receipt-secrets | DB creds/Stripe/API keys, and an isolated Stripe-keys-only secret for the receipt Lambda (no DB access, isolated 2026-07-24) |
Corrected 2026-08-13. The bucket name was wrong throughout this document — it's trinity-beast-website-east2, not trinity-beast-website-east2 (which does not exist). The tier_catalog table row was removed from this list — it's real and important, but it's created by application migrations against Aurora, not by this CloudFormation template, which only provisions the empty database engine.
The workers. ECS Fargate runs your containers without you managing servers. Think of it as hiring workers and only paying for the hours they work — no building maintenance. Lambda runs small, one-off tasks (like processing a receipt after a purchase).
| Resource | Details | Purpose |
|---|---|---|
| ECS Cluster | trinity-beast-fargate-cluster | The factory floor — organizes all services |
| Main Service | trinity-beast-main-service — 2 vCPU / 6 GB | LPO + LRS (SERVER_TYPE: APP_REPORT_SERVER) |
| Mirror Service | trinity-beast-mirror-service — 2 vCPU / 6 GB | LPO + LRS (SERVER_TYPE: APP_REPORT_SERVER) |
| LRS Service | trinity-beast-lrs-service — 2 vCPU / 6 GB | LPO + LRS (SERVER_TYPE: APP_REPORT_SERVER) |
| Webhook Service | trinity-beast-webhook-service — 2 vCPU / 6 GB | Webhook Push delivery engine + Webhook Push Test Receiver (SERVER_TYPE: WEBHOOK_SERVER) — see Layer 5 for the test-receiver's inbound ports |
| Translate Worker Service | tbi-translate-worker-service — 2 vCPU / 6 GB, persistent | Bedrock translation worker — polls SQS directly, no orchestrator |
| Sync Job Task Def | trinity-beast-sync-job — 0.5 vCPU / 1 GB | Nightly database sync task definition (BeastReconciler) |
| Lambda Function | trinity-beast-receipt — Go, 1770 MB, 180s | Post-checkout receipt processing; enqueues to the email queue (falls back to direct SES if enqueue fails) |
| SQS Queue | trinity-beast-queued-usage-logs — Standard | Decoupled usage log write pipeline |
| Lambda Function | trinity-beast-queued-writer — Go, 256 MB, in VPC | SQS consumer — batch-inserts usage logs into Aurora |
| SQS Queue | trinity-beast-email-queue | Decouples email delivery from the receipt Lambda's response path |
| Lambda Function | trinity-beast-email-sender — Go, 1770 MB, 60s | "Brainless" SQS consumer — receives pre-built emails, sends via SES. No DB, no Valkey, no Bedrock. |
Corrected 2026-08-13. The Webhook service was sized 1 vCPU / 2 GB in this document — it's actually 2 vCPU / 6 GB, standardized to match every other ECS service on 2026-08-03. The translate worker's persistent ECS service and the email queue/sender pair were entirely missing.
Load balancers are traffic cops. They stand at the front door and direct incoming requests to the right server. The ALB handles web traffic (HTTP/HTTPS). The NLB handles UDP traffic (real-time price feeds).
| Resource | Listeners | Purpose |
|---|---|---|
ALB (Trinity-Beast-TCP-ALB) | Port 80, 443, 8080, 9090 + host-header rules on 443 for lrs. and webhook. | Web traffic — API, LRS reports, HTTPS redirect, webhook test receiver |
NLB (Trinity-Beast-UDP-NLB) | UDP 2679, 2680, 2681 | Real-time UDP price/report feeds + webhook test receiver |
| Target Groups | 6 target groups | Route traffic to the right ECS service |
Listener breakdown: Port 80 redirects to 443 (HTTPS). Port 443 serves the API (default action) and carries two additional host-header rules — priority 10 for lrs.cpmp-site.org, priority 20 for webhook.cpmp-site.org. Port 8080 routes to the main service. Port 9090 routes to LRS services. Ports 8081, 9091, and 8092 serve dedicated health checks (isolated from production traffic). UDP 2679 and 2680 deliver real-time price/report data.
The Webhook service (BeastWebhook) is not purely outbound anymore. Alongside its outbound delivery engine (UDP datagrams + signed HTTPS POSTs to subscribers), it also runs a permanent, health-checked, in-process test receiver — built specifically to test the outbound engine end-to-end against a real network endpoint, both transports, without standing up a throwaway receiver each time. It was briefly a standalone Lambda for a few hours the same day it was built, then migrated in-process specifically to gain a persistent UDP socket, which a Lambda Function URL cannot provide.
| Transport | Reachable at | Path |
|---|---|---|
| HTTPS | https://webhook.cpmp-site.org/ | ALB host-header rule (priority 20) → trinity-beast-webhook-test-tg (container port 8090) |
| UDP | udp.cpmp-site.org:2681 | New NLB listener → Trinity-Beast-UDP-2681-TG (container port 2681) |
| Health | — | Dedicated health server, container port 8092 — gates both target groups above |
Gated behind WEBHOOK_TEST_RECEIVER_ENABLED=true — off by default, structurally. The HTTPS side uses an additional SNI certificate on the existing 443 listener (ACMCertificateArnWebhook) — the default certificate serving api/lrs/www is never touched.
Corrected 2026-08-13. The webhook test receiver's entire infrastructure — 2 target groups, 1 ALB listener rule, 1 NLB listener, 1 additive ACM cert, the DNS record for webhook.cpmp-site.org, and 3 new security-group rules — was missing from the template entirely. It has been live since 2026-08-07.
DNS is the phone book of the internet. When someone types cpmp-site.org, DNS tells their browser which server to talk to. Route 53 manages all of this.
| Record | Points To | Purpose |
|---|---|---|
cpmp-site.org | CloudFront | Main website |
www.cpmp-site.org | CloudFront | WWW alias for website |
api.cpmp-site.org | ALB | REST API endpoint |
lrs.cpmp-site.org | ALB | LRS report server |
udp.cpmp-site.org | NLB | UDP price/report feed + webhook test receiver (port 2681) |
webhook.cpmp-site.org | ALB | Webhook Push test receiver (HTTPS) — added 2026-08-13, was missing |
| MX record | SES inbound | Email receiving |
| SPF record | TXT record | Email authentication — "yes, we're allowed to send email" |
| DMARC record | TXT record | Email policy — tells receivers how to handle our email |
| SES verification | TXT/CNAME records | Proves we own the domain for sending email |
CloudFront is like having copies of your website in cities around the world. Instead of everyone connecting to Ohio, visitors get served from the nearest location. Faster for them, less load on your servers.
| Setting | Value |
|---|---|
| Origin | S3 bucket (trinity-beast-website-east2) |
| HTTP → HTTPS | Automatic redirect |
| TLS Version | TLS 1.2 minimum |
| Certificate | ACM certificate in us-east-1 (CloudFront requirement) |
Monitoring is your early warning system. CloudWatch watches metrics (CPU usage, error rates, database health) and SNS sends you a text or email when something goes wrong. You find out about problems before your users do.
| Category | Alarms | What They Watch |
|---|---|---|
| ECS CPU | CPU alarms per service | Container CPU usage — alerts if consistently high |
| ECS Service Count | Running task count (main/mirror/lrs/webhook/translate-worker) | Alerts if a service has zero running tasks (it's down) |
| Aurora | CPU, connections (threshold 250) | Database health — CPU spikes, connection exhaustion |
| ElastiCache Serverless | ECPU (>6,000 of 10,000, 3 consecutive periods), storage (>24 of 30 GB), throttled commands (>0) | Cache health — processing-unit consumption, capacity pressure |
| ALB/NLB target-group health | 6 target-group alarms — one per target group across both load balancers | Unhealthy hosts on any of the 6 target groups, including the webhook test receiver |
| S3 | Bucket size on the real website bucket | Unusual growth on trinity-beast-website-east2 |
| Translation DLQ | Messages visible > 0 | Failed, already-paid customer translation work sitting undelivered |
Corrected 2026-08-13, several changes: (1) The 3 ElastiCache alarms previously watched AWS/MemoryDB metrics that don't exist for this cluster — rewritten against the real AWS/ElastiCache Serverless metrics. The ECPU alarm requires 3 consecutive breaching periods (not 2), added after two consecutive nights of a harmless nightly-sync bulk-write burst tripping it on a bucket-boundary coincidence. (2) ALB/NLB health alarms now use TreatMissingData: missing instead of notBreaching — a healthy load balancer always publishes a zero, so absence of data can only mean the alarm itself is blind (this exact setting hid the real ALB alarm for 3.5 months in 2026, per go-live.md). (3) Added the S3 size and Translation-DLQ alarms, which were both entirely absent. (4) All alarms route to the AutoOps notification pipeline (Section 10 in autonomous-ops.md), not the legacy critical-alerts SNS topic this document previously described — see Layer 10 below.
EventBridge is your cron job in the cloud. It runs tasks on a schedule without you lifting a finger. The AutoOps rules (bedrock-analyze schedule, GuardDuty finding, digests) live in the AutoOps section of the template and are listed together with this one for completeness.
| Rule | Schedule | What It Does |
|---|---|---|
trinity-beast-nightly-sync | cron(0 5 * * ? *) = 1:00 AM EDT | Launches the sync job ECS task (BeastReconciler) to synchronize database data nightly |
tbi-ops-alarm-trigger | Event pattern — any CloudWatch alarm state change | Triggers the self-heal Step Function |
tbi-ops-honeypot-queue-processor | rate(5 minutes) | Drains the honeypot auto-block queue |
tbi-ops-bedrock-analyze-schedule | rate(30 minutes) | AI threat correlation via Bedrock |
tbi-ops-guardduty-high-finding | Event pattern — GuardDuty severity ≥ 7 | Immediate AI threat analysis on a real finding |
tbi-ops-daily-digest | cron(0 11 * * ? *) = 6:00 AM EST | Concise daily operational summary |
tbi-ops-weekly-digest | cron(0 12 ? * MON *) = 7:00 AM EST Mondays | "Week in Review" + subscriber newsletter |
tbi-cpmp-monthly-newsletter | cron(0 15 ? * 1#1 *) = 10:00 AM EST, 1st Sunday | CPMP ministry newsletter |
Corrected 2026-08-13. 7 of these 8 rules were missing from the template entirely. The nightly-sync schedule was also off by an hour — cron(0 6 * * ? *) is 1 AM EST, but the live rule runs cron(0 5 * * ? *) (1 AM EDT, daylight time, in effect most of the year). Adjust by one hour each November when clocks fall back, same as the live rule.
The AutoOps layer adds intelligent, self-healing automation across 5 layers. It monitors the infrastructure, detects problems, fixes them automatically, generates AI-powered reports, and handles support tickets — notifying you after the fact.
| Resource | Type | Purpose |
|---|---|---|
tbi-ops-notify | Lambda (Go, 1770 MB, 180s) | Send severity-tagged SNS notifications |
tbi-ops-self-heal | Lambda (Go, 1770 MB, 180s) | ECS task restart, force-deploy, health checks |
tbi-ops-waf-action | Lambda (Go, 1770 MB, 180s) | Block/unblock IPs in WAF IP set |
tbi-ops-honeypot-processor | Lambda (Go, 1770 MB, 180s) | Drain honeypot queue → WAF block → notify |
tbi-ops-bedrock-analyze | Lambda (Go, 1770 MB, 180s) | AI threat analysis via Bedrock (Qwen 3 235B) |
tbi-rhema-support | Lambda (Go, 1770 MB, 180s) | AI ticket categorization + draft responses (Qwen 3 235B) |
tbi-ops-digest | Lambda (Go, 1770 MB, 540s) | Daily/weekly/monthly operational digests via Bedrock |
tbi-ops-health-check-heal | Step Function | Multi-step heal workflow: check → wait → recheck → deploy → verify → notify |
tbi-autoops-blocked-ips | WAF IP Set | Auto-blocked IPs from honeypot + AI analysis |
tbi-ops-notifications | SNS Topic | Single funnel for every operational alert with severity levels |
tbi-autonomous-ops-role | IAM Role | Shared execution role for the 5 core AutoOps Lambdas + Rhema + digest |
trinity-beast-queued-writer | Lambda (Go, 256 MB, VPC) | SQS → Aurora batch usage log writer |
trinity-beast-queued-usage-logs | SQS Queue | Decoupled usage log pipeline |
trinity-beast-email-queue | SQS Queue | Decoupled email delivery pipeline |
trinity-beast-email-sender | Lambda (Go, 1770 MB, 60s) | "Brainless" SQS consumer — pre-built email → SES, own dedicated role |
Corrected 2026-08-13, several changes. (1) tbi-rhema-support, tbi-ops-digest, and trinity-beast-email-sender were entirely missing from this template — 3 of the account's 10 live Lambdas were never declared. (2) The Bedrock model reference was wrong throughout — the standing model for every AutoOps/Rhema call is Qwen 3 235B (qwen.qwen3-235b-a22b-2507-v1:0), not Claude Haiku. (3) The 4 anomaly detectors row has been removed — 2 of the original 4 (CacheHitRate, Latency) were deleted 2026-07-30 after being diagnosed as structurally unmeasurable at pre-launch volume (see go-live.md); the remaining 2 (RequestRate, ErrorRate) exist live but anomaly detectors are not currently declarable via this CloudFormation template resource type in a way that matches the live configuration, so they are intentionally not represented here — recreate them via the AWS CLI per the procedure in go-live.md if rebuilding from scratch. (4) The agent_profiles/agent_profile_events table row was removed — like tier_catalog above, these are Aurora application tables created by migrations, not by this template.
The WAF Web ACL protecting the ALB (trinity-beast-api-waf) and the CloudFront-managed ACL are not declared in this template — this is a known, documented gap, not a regression (it was never here). Building all 8 live rule groups correctly (IP Reputation, Common Rules, Known Bad Inputs, SQL Injection, two rate-limit rules, the AutoOps IP-set rule, and the honeypot auto-block rule) in CloudFormation is substantial, and shipping it half-verified would be worse than being explicit about the gap. The WAF IP Set that AutoOps writes to (tbi-autoops-blocked-ips) is declared and correct — only the ACL that references it via a rule is not. Recreating the WAF ACLs is the current manual step in a full disaster-recovery scenario; see security.py in the KCC helper scripts for the live rule inventory to replicate.
A custom translation pipeline that uses Amazon Bedrock (Qwen 3 235B) with sentinel preprocessing to translate documents while preserving code blocks, Mermaid diagrams, and brand terms. AWS Translate is NOT used — it corrupts technical content.
| Resource | Type | Purpose |
|---|---|---|
tbi-translate-worker | ECR Repository | Python 3.11 container image for the translation worker |
tbi-translate-role | IAM Role | Worker task role only — Bedrock, S3, CloudFront, SQS, SNS |
trinity-beast-translation-queue | SQS Queue | One message per language — the worker polls this directly |
trinity-beast-translation-queue-dlq | SQS Queue (DLQ) | Failed translation messages after 3 receive attempts |
trinity-beast-translation-cost-queue | SQS Queue | Translation cost events |
tbi-translate-worker-task | ECS Task Definition | Fargate task def (2 vCPU / 6 GB, no timeout ceiling) |
tbi-translate-worker-service | ECS Service (persistent) | Always-on worker polls SQS directly — one container per language message |
Architecture, simplified 2026-06-27: POST /admin/translate → N SQS messages (1 per language) → N persistent worker containers, auto-scaled to match → each worker handles sentinel preprocessing, Bedrock translation, validation, S3 write, and CloudFront invalidation directly (boto3 — no Lambda) → the last worker to finish calls POST /admin/translate/complete/{job_id} on the LPO server, which handles state update, search rebuild, cost computation, and notification in-process. Zero Lambdas, zero Step Functions, zero EventBridge Pipes.
Corrected 2026-08-13 — this section was describing a dead architecture. tbi-translation-orchestrator (Step Function), tbi-translate-deploy and tbi-translate-finalize (both Lambdas), and the EventBridge Pipe that fed the orchestrator were all deleted from AWS on 2026-06-27 when the pipeline was simplified to direct SQS fan-out — but this template and this document both still declared/described all four as if they were live. None of them exist. The worker's task sizing was also wrong (1 vCPU / 3 GB instead of the real 2 vCPU / 6 GB), and the translation DLQ and cost queue were both missing entirely.
Parameters are the blanks you fill in when deploying. Think of them as the customization options on an order form. Most have sensible defaults — you only must provide two values.
Only 2 required: DBPassword and SecretValue are the only parameters you absolutely must provide. Everything else has a default that matches the current production setup.
| Parameter | Purpose | Default | Secret? | Required? |
|---|---|---|---|---|
DBPassword |
PostgreSQL master password for Aurora cluster | None — you must provide this | Yes (NoEcho) | YES |
SecretValue |
JSON string for trinity-beast-secrets (DB creds, Stripe keys, API keys) | None — you must provide this | Yes (NoEcho) | YES |
DBUsername |
PostgreSQL master username | postgres |
No | No |
DBName |
Aurora database name | CPMP_Backend_Aurora |
No | No |
DomainName |
Primary domain name | cpmp-site.org |
No | No |
ACMCertificateArnEast2 |
ACM certificate ARN in us-east-2 (for ALB HTTPS) | Current production cert ARN | No | No |
ACMCertificateArnEast1 |
ACM certificate ARN in us-east-1 (for CloudFront) | Current production cert ARN | No | No |
ACMCertificateArnWebhook |
Single-SAN ACM cert ARN for webhook.cpmp-site.org — added 2026-08-13, was missing |
Current production cert ARN | No | No |
AlertEmail |
Email address for critical alerts | [email] |
No | No |
AlertSMS |
Phone number for SMS alerts | [phone] |
No | No |
SESFromAddress |
SES sender address for receipt emails | CPMP Mission <No-Reply@CPMP-Site.org> |
No | No |
LPOImageTag |
Docker image tag for LPO server | latest |
No | No |
SyncImageTag |
Docker image tag for sync job | latest |
No | No |
About SecretValue: This is a JSON string containing all the secrets your application needs. Format: {"DB_PASSWORD":"...","STRIPE_SECRET_KEY":"...","STRIPE_WEBHOOK_SECRET":"...",...}. Keep this stored securely outside of AWS — in a password manager, encrypted file, or similar. If you lose this, you'll need to regenerate all the API keys and passwords it contains.
CloudFormation doesn't just create resources in isolation — it wires them together using two key mechanisms: !Ref (reference another resource's ID) and !GetAtt (get a specific attribute like an endpoint URL). Here's what that looks like in plain English.
graph TB
Internet["Internet"]
subgraph DNS_CDN["DNS & CDN"]
Route53["Route 53
cpmp-site.org"]
CloudFront["CloudFront
Static Website"]
S3["S3 Bucket
trinity-beast-website-east2"]
end
subgraph LoadBalancers["Load Balancers"]
ALB["ALB
Trinity-Beast-TCP-ALB
TCP: 80, 443 → 8080, 9090"]
NLB["NLB
Trinity-Beast-UDP-NLB
UDP: 2679, 2680"]
end
subgraph ECS["ECS Fargate Cluster — 4 of 5 Services Shown (BeastTranslate omitted, no ALB/NLB path)"]
Main["BeastMain · AZ 2a
APP_REPORT_SERVER
2 vCPU / 6 GB"]
Mirror["BeastMirror · AZ 2b
APP_REPORT_SERVER
2 vCPU / 6 GB"]
LRS["BeastLRS · AZ 2c
APP_REPORT_SERVER
2 vCPU / 6 GB"]
Webhook["BeastWebhook
WEBHOOK_SERVER
2 vCPU / 6 GB"]
end
subgraph Data["Data Layer"]
Aurora["Aurora PostgreSQL
Serverless v2
1.5–18 ACU"]
MemDB["ElastiCache Serverless
Valkey 9.0
Auto-scaling · Multi-AZ"]
Secrets["Secrets Manager
trinity-beast-secrets"]
end
Lambda["Lambda
trinity-beast-receipt
Go / provided.al2023"]
EventBridge["EventBridge
Nightly Sync
1 AM EDT"]
SyncJob["Sync Job
0.5 vCPU / 1 GB"]
SNS["SNS
AutoOps Notifications
tbi-ops-notify → SES"]
CW["CloudWatch
~25 Alarms in Template"]
Internet --> Route53
Route53 -->|"cpmp-site.org"| CloudFront
Route53 -->|"api / lrs"| ALB
Route53 -->|"udp"| NLB
CloudFront --> S3
Internet -->|"Stripe Webhook"| Lambda
ALB -->|"TCP 8080"| Main
ALB -->|"TCP 8080"| Mirror
ALB -->|"TCP 9090"| LRS
NLB -->|"UDP 2679"| Main
NLB -->|"UDP 2679"| Mirror
NLB -->|"UDP 2680"| LRS
Main --> Aurora
Main --> MemDB
Mirror --> Aurora
Mirror --> MemDB
LRS --> Aurora
LRS --> MemDB
Webhook --> Aurora
Webhook --> MemDB
Main -.->|"!GetAtt Endpoint"| Aurora
Main -.->|"!GetAtt Endpoint"| MemDB
Main -.->|"Reads"| Secrets
Lambda --> Aurora
Lambda --> MemDB
Lambda -.->|"Reads"| Secrets
EventBridge -->|"cron 0 6 * * ?"| SyncJob
SyncJob --> Aurora
SyncJob --> MemDB
CW -.->|"ALARM"| SNS
%% Internet → DNS — white
linkStyle 0 stroke:#e2e8f0,stroke-width:2px
%% DNS → CDN — pink (website path)
linkStyle 1 stroke:#f472b6,stroke-width:2px
%% DNS → ALB — blue (TCP)
linkStyle 2 stroke:#60a5fa,stroke-width:2px
%% DNS → NLB — orange (UDP)
linkStyle 3 stroke:#FF9900,stroke-width:2px
%% CloudFront → S3 — pink
linkStyle 4 stroke:#f472b6,stroke-width:2px
%% Internet → Lambda — violet (Stripe)
linkStyle 5 stroke:#a78bfa,stroke-width:2px
%% ALB → ECS — blue (TCP)
linkStyle 6 stroke:#60a5fa,stroke-width:2px
linkStyle 7 stroke:#60a5fa,stroke-width:2px
linkStyle 8 stroke:#60a5fa,stroke-width:2px
%% NLB → ECS — orange (UDP)
linkStyle 9 stroke:#FF9900,stroke-width:2px
linkStyle 10 stroke:#FF9900,stroke-width:2px
linkStyle 11 stroke:#FF9900,stroke-width:2px
%% ECS → Aurora — red (database)
linkStyle 12 stroke:#f87171,stroke-width:2px
linkStyle 14 stroke:#f87171,stroke-width:2px
linkStyle 16 stroke:#f87171,stroke-width:2px
linkStyle 18 stroke:#f87171,stroke-width:2px
%% ECS → ElastiCache — green (cache)
linkStyle 13 stroke:#10b981,stroke-width:2px
linkStyle 15 stroke:#10b981,stroke-width:2px
linkStyle 17 stroke:#10b981,stroke-width:2px
linkStyle 19 stroke:#10b981,stroke-width:2px
%% !GetAtt / !Ref wiring — cyan (dashed)
linkStyle 20 stroke:#22d3ee,stroke-width:1.5px
linkStyle 21 stroke:#22d3ee,stroke-width:1.5px
%% Secrets reads — rose
linkStyle 22 stroke:#fca5a5,stroke-width:1.5px
%% Lambda → Aurora — red
linkStyle 23 stroke:#f87171,stroke-width:2px
%% Lambda → ElastiCache — green
linkStyle 24 stroke:#10b981,stroke-width:2px
%% Lambda → Secrets — rose
linkStyle 25 stroke:#fca5a5,stroke-width:1.5px
%% EventBridge → SyncJob — yellow
linkStyle 26 stroke:#facc15,stroke-width:2px
%% SyncJob → Aurora — red
linkStyle 27 stroke:#f87171,stroke-width:2px
%% SyncJob → ElastiCache — green
linkStyle 28 stroke:#10b981,stroke-width:2px
%% CloudWatch → SNS — rose (alerts)
linkStyle 29 stroke:#fca5a5,stroke-width:1.5px
style Internet fill:#FF9900,color:#0f172a,stroke:#FF9900
style ALB fill:#1e293b,stroke:#60a5fa,color:#e2e8f0
style NLB fill:#1e293b,stroke:#FF9900,color:#e2e8f0
style Main fill:#064e3b,stroke:#10b981,color:#e2e8f0
style Mirror fill:#064e3b,stroke:#10b981,color:#e2e8f0
style LRS fill:#064e3b,stroke:#10b981,color:#e2e8f0
style Webhook fill:#064e3b,stroke:#10b981,color:#e2e8f0
style Aurora fill:#1e293b,stroke:#f87171,color:#e2e8f0
style MemDB fill:#1e293b,stroke:#10b981,color:#e2e8f0
style Lambda fill:#1e293b,stroke:#a78bfa,color:#e2e8f0
style CloudFront fill:#1e293b,stroke:#f472b6,color:#e2e8f0
style S3 fill:#1e293b,stroke:#f472b6,color:#e2e8f0
style Route53 fill:#1e293b,stroke:#e2e8f0,color:#e2e8f0
style Secrets fill:#7f1d1d,stroke:#fca5a5,color:#e2e8f0
style SNS fill:#7f1d1d,stroke:#fca5a5,color:#e2e8f0
style CW fill:#1e293b,stroke:#60a5fa,color:#e2e8f0
style SyncJob fill:#1e293b,stroke:#facc15,color:#e2e8f0
style EventBridge fill:#1e293b,stroke:#facc15,color:#e2e8f0
The Aurora cluster endpoint is automatically passed to all 4 ECS task definitions as the DB_HOST environment variable. When CloudFormation creates the Aurora cluster, it gets an endpoint like trinity-beast-aurora.cluster-xxxxx.us-east-2.rds.amazonaws.com. That endpoint is injected into every container so they know where the database is — no hardcoding needed.
The ElastiCache Serverless endpoint is passed to all 4 ECS task definitions as the CACHE_URL environment variable. Same idea — CloudFormation creates the cache, gets the endpoint, and passes it to the containers automatically. With Serverless, there is no node to size or manage — it scales transparently behind that single endpoint.
Security groups reference each other to create a chain of trust:
This is defense in depth. Even if someone bypasses the load balancer, they can't reach the database directly because the security group only trusts traffic from the ECS containers.
Route 53 records use !GetAtt to point at the load balancers:
api.cpmp-site.org → ALB's DNS name (automatically resolved)udp.cpmp-site.org → NLB's DNS namecpmp-site.org → CloudFront distribution domainIf the load balancer's address changes (e.g., after a rebuild), the DNS records update automatically because they reference the resource, not a hardcoded IP.
The Secrets Manager secret ARN is passed to ECS task definitions. At runtime, ECS pulls the secret values and injects them as environment variables. Your application code never sees the raw secret — it just reads environment variables like DB_PASSWORD and STRIPE_SECRET_KEY.
Deploying the stack means telling CloudFormation: "Build everything described in this template." Here's how, step by step.
aws sts get-caller-identity to verify you're authenticated to account 211998422884us-east-2 (for the ALB)us-east-1 (for CloudFront — this is an AWS requirement, CloudFront only uses us-east-1 certs)Important: Replace the placeholder values below with your actual secrets. Never commit real secrets to version control.
aws cloudformation create-stack \
--stack-name trinity-beast-stack \
--template-body file://trinity-beast-stack.yaml \
--capabilities CAPABILITY_NAMED_IAM \
--region us-east-2 \
--parameters \
ParameterKey=DBPassword,ParameterValue='YOUR_DB_PASSWORD_HERE' \
ParameterKey=SecretValue,ParameterValue='{"DB_PASSWORD":"...","STRIPE_SECRET_KEY":"...","STRIPE_WEBHOOK_SECRET":"..."}' \
ParameterKey=DBUsername,ParameterValue=postgres \
ParameterKey=DBName,ParameterValue=CPMP_Backend_Aurora \
ParameterKey=DomainName,ParameterValue=cpmp-site.org \
ParameterKey=AlertEmail,ParameterValue='[email]' \
ParameterKey=AlertSMS,ParameterValue='[phone]' \
ParameterKey=LPOImageTag,ParameterValue=latest \
ParameterKey=SyncImageTag,ParameterValue=latest
What's CAPABILITY_NAMED_IAM? This flag tells CloudFormation: "Yes, I know this template creates IAM roles, and I'm okay with that." It's a safety check — AWS wants you to explicitly acknowledge that you're granting permissions.
CloudFormation reads the template, figures out the dependency order, and starts creating resources. Here's the rough timeline:
| Time | What's Happening |
|---|---|
| 0–2 min | VPC, subnets, internet gateway, route tables created |
| 2–5 min | Security groups, VPC endpoints, IAM roles created |
| 5–15 min | Aurora cluster spinning up (this is the slowest part) |
| 5–15 min | ElastiCache Serverless cache creating (runs in parallel with Aurora) |
| 10–20 min | ECR repos, S3 bucket, Secrets Manager created |
| 15–25 min | ECS cluster, task definitions, ALB, NLB created |
| 20–30 min | ECS services start (4 services — they'll fail health checks until images are pushed) |
| 25–35 min | Route 53 records, CloudFront distribution, CloudWatch alarms |
| 30–45 min | Stack complete — all 182 resources created |
The stack creates the infrastructure, but some things need to be done manually after:
# Authenticate Docker to ECR
aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin 211998422884.dkr.ecr.us-east-2.amazonaws.com
# Tag and push the LPO server image
docker tag trinity-beast-lpo-server:latest 211998422884.dkr.ecr.us-east-2.amazonaws.com/trinity-beast-lpo-server:latest
docker push 211998422884.dkr.ecr.us-east-2.amazonaws.com/trinity-beast-lpo-server:latest
# Tag and push the sync job image
docker tag trinity-beast-sync-job:latest 211998422884.dkr.ecr.us-east-2.amazonaws.com/trinity-beast-sync-job:latest
docker push 211998422884.dkr.ecr.us-east-2.amazonaws.com/trinity-beast-sync-job:latest
aws lambda update-function-code \
--function-name trinity-beast-receipt \
--zip-file fileb://bootstrap.zip \
--region us-east-2
aws s3 sync ./website/ s3://trinity-beast-website-east2/ --delete
aws cloudfront create-invalidation \
--distribution-id E110PRKEIYQVLL \
--paths "/*"
dig api.cpmp-site.org
dig udp.cpmp-site.org
dig cpmp-site.org
curl -I https://api.cpmp-site.org/health
# Check overall stack status
aws cloudformation describe-stacks --stack-name trinity-beast-stack --region us-east-2
# Watch events in real-time (useful during creation)
aws cloudformation describe-stack-events \
--stack-name trinity-beast-stack \
--region us-east-2 \
--query 'StackEvents[0:10].[Timestamp,ResourceType,LogicalResourceId,ResourceStatus]' \
--output table
# List all resources in the stack
aws cloudformation list-stack-resources \
--stack-name trinity-beast-stack \
--region us-east-2
Success looks like: "StackStatus": "CREATE_COMPLETE". If you see CREATE_FAILED or ROLLBACK_COMPLETE, check the events for the specific resource that failed — CloudFormation will tell you exactly what went wrong.
Need to change something? Edit the YAML file and tell CloudFormation to update. It's smart enough to figure out what changed and only touch those resources.
aws cloudformation update-stack \
--stack-name trinity-beast-stack \
--template-body file://trinity-beast-stack.yaml \
--capabilities CAPABILITY_NAMED_IAM \
--region us-east-2 \
--parameters \
ParameterKey=DBPassword,UsePreviousValue=true \
ParameterKey=SecretValue,UsePreviousValue=true
Notice UsePreviousValue=true — for secret parameters, you don't need to re-enter them on every update. CloudFormation remembers the values from the last deployment.
CloudFormation compares your new template against the current state and categorizes each change:
| Change Type | What Happens | Example |
|---|---|---|
| No Interruption | Resource is updated in place — no downtime | Changing a CloudWatch alarm threshold |
| Some Interruption | Resource is briefly interrupted during update | Changing an ECS task definition (rolling deploy) |
| Replacement | Old resource is deleted and a new one is created | Changing VPC CIDR block, Aurora engine version |
⚠️ Replacement Warning: Some changes force CloudFormation to delete and recreate a resource. This can cause data loss. Before updating, always preview changes with a Change Set:
aws cloudformation create-change-set \
--stack-name trinity-beast-stack \
--template-body file://trinity-beast-stack.yaml \
--change-set-name my-changes \
--capabilities CAPABILITY_NAMED_IAM \
--region us-east-2
# Review what will change
aws cloudformation describe-change-set \
--stack-name trinity-beast-stack \
--change-set-name my-changes \
--region us-east-2
This shows you exactly what will be modified, added, or replaced — before anything happens. Always use Change Sets for production updates.
The scenario: everything is gone. The AWS account was compromised, someone deleted the stack, or you need to rebuild from scratch in a new account. Here's the step-by-step playbook.
Estimated recovery time: 1–2 hours from "everything is gone" to "everything is running." The stack itself takes 30–45 minutes. The rest is pushing code and verifying.
This is the big one. One command creates all 182 resources (the us-east-2 footprint — see Section 9 for the us-east-1 pieces):
aws cloudformation create-stack \
--stack-name trinity-beast-stack \
--template-body file://trinity-beast-stack.yaml \
--capabilities CAPABILITY_NAMED_IAM \
--region us-east-2 \
--parameters \
ParameterKey=DBPassword,ParameterValue='YOUR_DB_PASSWORD' \
ParameterKey=SecretValue,ParameterValue='YOUR_SECRETS_JSON'
Then wait. Monitor progress:
aws cloudformation describe-stacks --stack-name trinity-beast-stack --region us-east-2 \
--query 'Stacks[0].StackStatus' --output text
Watch for CREATE_COMPLETE. This takes 30–45 minutes. Aurora and ElastiCache are the slowest. Go get coffee.
The ECR repos are empty — they're just containers waiting for images. Build and push:
# Authenticate
aws ecr get-login-password --region us-east-2 | \
docker login --username AWS --password-stdin \
211998422884.dkr.ecr.us-east-2.amazonaws.com
# Build and push LPO server
docker build -t trinity-beast-lpo-server:latest .
docker tag trinity-beast-lpo-server:latest \
211998422884.dkr.ecr.us-east-2.amazonaws.com/trinity-beast-lpo-server:latest
docker push 211998422884.dkr.ecr.us-east-2.amazonaws.com/trinity-beast-lpo-server:latest
# Build and push sync job
docker build -t trinity-beast-sync-job:latest -f Dockerfile.sync .
docker tag trinity-beast-sync-job:latest \
211998422884.dkr.ecr.us-east-2.amazonaws.com/trinity-beast-sync-job:latest
docker push 211998422884.dkr.ecr.us-east-2.amazonaws.com/trinity-beast-sync-job:latest
ECS will automatically pick up the new images and start the services.
Repeat this build-and-deploy pattern for every Lambda in the template: trinity-beast-receipt, trinity-beast-queued-writer, trinity-beast-email-sender, and the 5 AutoOps functions (tbi-ops-notify, tbi-ops-self-heal, tbi-ops-waf-action, tbi-ops-honeypot-processor, tbi-ops-bedrock-analyze) plus tbi-rhema-support and tbi-ops-digest. See deployment.md for the exact source directory of each.
# Build the Go binary for Lambda — GOARCH must be amd64, matching the
# template's x86_64 Architectures setting (NOT arm64)
GOOS=linux GOARCH=amd64 go build -o bootstrap ./cmd/handler/
zip -j function.zip bootstrap
# Deploy to Lambda
aws lambda update-function-code \
--function-name trinity-beast-receipt \
--zip-file fileb://function.zip \
--region us-east-2
aws s3 sync ./cpmp-redesign/ s3://trinity-beast-website-east2/ --delete
aws cloudfront create-invalidation \
--distribution-id E110PRKEIYQVLL \
--paths "/*"
If the hosted zone was recreated, it gets new nameservers. You must update them at your domain registrar (wherever you bought cpmp-site.org).
# Get the new nameservers
aws route53 get-hosted-zone --id YOUR_HOSTED_ZONE_ID \
--query 'DelegationSet.NameServers' --output text
Copy those 4 nameserver values and update them at your registrar. DNS propagation can take up to 48 hours, but usually completes within 1–2 hours.
# Check ECS services
aws ecs describe-services \
--cluster trinity-beast-fargate-cluster \
--services trinity-beast-main-service trinity-beast-mirror-service trinity-beast-lrs-service trinity-beast-webhook-service tbi-translate-worker-service \
--region us-east-2 \
--query 'services[].{name:serviceName,running:runningCount,desired:desiredCount,status:status}'
# Check API health
curl -s https://api.cpmp-site.org/health | jq .
# Check ALB target health
aws elbv2 describe-target-health \
--target-group-arn YOUR_TARGET_GROUP_ARN \
--region us-east-2
# Check Aurora
aws rds describe-db-clusters \
--db-cluster-identifier trinity-beast-aurora-cluster \
--region us-east-2 \
--query 'DBClusters[0].Status'
# Check ElastiCache Serverless
aws elasticache describe-serverless-caches \
--serverless-cache-name trinity-beast-cache-serverless \
--region us-east-2 \
--query 'ServerlessCaches[0].Status'
Database note: The stack creates an empty Aurora database. You'll need to run your database migrations to recreate the schema and seed data. If you have a database backup (RDS snapshot), you can restore from that instead — but that's a manual step outside the CloudFormation template.
Honesty time. The CloudFormation template is powerful, but it doesn't cover everything. Some things require manual steps, either because AWS doesn't support them in CloudFormation or because they involve external services.
These items require manual action after the stack is deployed. The template creates the infrastructure, but these pieces must be configured separately.
| Item | Why It's Not in the Template | What You Need to Do |
|---|---|---|
| ACM Certificates | Certificates require DNS validation — a chicken-and-egg problem (you need DNS to validate, but DNS is in the template) | Request certificates in ACM for us-east-2 (ALB) and us-east-1 (CloudFront). Validate via DNS. Pass the ARNs as parameters. |
| SES Domain Verification & DKIM | SES verification involves external DNS records and waiting for AWS to verify | Verify cpmp-site.org in SES. Set up DKIM signing. Move out of SES sandbox if needed. |
| Stripe Webhook Configuration | Stripe is an external service — CloudFormation can't configure it | Log into Stripe Dashboard. Create webhook endpoint pointing to https://api.cpmp-site.org/webhook/stripe. Copy the webhook secret into your SecretValue parameter. |
| Database Schema & Seed Data | CloudFormation creates the database engine, not the tables inside it | After Aurora is up, connect and run your migrations: go run cmd/migrate/main.go. Seed any required reference data. |
| Docker Images | The template creates ECR repos (the shelves) but not the images (the books) | Build your Docker images locally or in CI/CD, then push to ECR. See Section 7, Step 3. |
| Website Content | The template creates the S3 bucket (the filing cabinet) but not the files inside it | Upload your website files: aws s3 sync ./cpmp-redesign/ s3://trinity-beast-website-east2/ |
| Compute Savings Plan | Savings Plans are billing commitments, not infrastructure — they can't be defined in CloudFormation | Purchase a Compute Savings Plan through the AWS Cost Explorer console after your infrastructure is stable. |
| WAF Web ACLs | Building all 8 live rule groups correctly is substantial and was deliberately deferred rather than shipped half-verified — see the callout in Layer 10 above | Recreate trinity-beast-api-waf via console or CLI, replicating the live rule inventory (IP Reputation, Common Rules, Known Bad Inputs, SQL Injection, 2 rate-limit rules, the AutoOps IP-set rule, honeypot auto-block). The IP Set itself IS in the template. |
| Actual Secret Values | Secrets should never be stored in a template file — that would be a security risk | You provide secrets as parameters at deploy time. Store them securely in a password manager or encrypted vault. |
Corrected 2026-08-13 — ElastiCache Serverless row removed from this list. AWS::ElastiCache::ServerlessCache is a real, well-supported CloudFormation resource type and IS declared in the template now (Section 2, Layer 3) — this document previously claimed otherwise and had the template quietly using the wrong service (MemoryDB, not ElastiCache) as a workaround. That workaround is gone; the template creates the real cache.
Think of it this way: The template builds the house — walls, plumbing, electrical, locks on the doors. But you still need to move in your furniture (Docker images), hang your pictures (website content), set up your mail forwarding (SES), and give the locksmith your key preferences (secrets). The house is ready, but it needs to be lived in.
Added 2026-08-13. CloudFormation stacks deploy to a single region — you cannot mix resources from two regions in one create-stack call. This template targets us-east-2. A handful of real, necessary resources are forced into us-east-1 by AWS service availability, not by choice, and they live in a companion template (trinity-beast-stack-us-east-1.yaml) rather than being squeezed into this one.
Why these specific resources have to be in us-east-1: SES inbound email receiving is not available in us-east-2 at all — it's a hard region restriction, not a preference. The CloudFront WAF and all AWS/CloudFront metrics are global-service resources that AWS only exposes through us-east-1.
| Resource | Type | Why us-east-1 |
|---|---|---|
tbi-support-inbound | Lambda (Go, 1770 MB, 60s) | Threads inbound customer email replies back into support tickets. Triggered by S3, not SES directly. |
tbi-support-inbound-role | IAM Role | S3 read + Aurora-facing Lambda invoke for the above |
tbi-support-inbound | S3 Bucket (prefix emails/) | SES receipt-rule destination — must be co-located with the receipt rule |
support-reply-inbound | SES Receipt Rule | Routes inbound mail on reply.cpmp-site.org to the S3 bucket above |
reply.cpmp-site.org, cpmp-site.org | SES Identities | Verified sender/receiver domains for the inbound path |
CreatedByCloudFront-449feaa5 | WAF Web ACL (global scope) | CloudFront WAF is global/us-east-1 by definition |
aws-waf-logs-trinity-beast-use1 | S3 Bucket | us-east-1 unified logs bucket — home for CloudFront WAF logs (region-locked) and any future us-east-1 vended logs |
tbi-ops-notifications | SNS Topic (us-east-1, same name as the us-east-2 one — a distinct resource) | The notification entry point for us-east-1 alarms (e.g. CloudFront 5xx). A CloudWatch alarm can only publish to a same-region SNS topic. |
Trinity-Beast-CloudFront-5XX-High | CloudWatch Alarm | CloudFront metrics are us-east-1-only, so the alarm publishing on them must live there too |
The bridge back to the normal notification pipeline: the us-east-1 tbi-ops-notifications topic has the us-east-2 tbi-ops-notify Lambda as a confirmed cross-region subscriber — SNS permits a Lambda subscription across regions. So a us-east-1 alarm still ends up as one formatted SES email, same as every other alert, with no forwarder Lambda needed.
Do not add regions to this list casually. Every other cross-region reach in this system is transient (the translation engine's Bedrock failover chain tries us-east-1 and then us-west-2 only if us-east-2 Bedrock is unavailable — it creates no resources in those regions, it only invokes Bedrock there). The resources above are the only resident us-east-1 infrastructure in the account, and they exist because AWS requires it, not because anyone chose it.
The CloudFormation template and supporting files are stored in multiple locations for redundancy.
trinity-beast-lpo-server/deployments/cloudformation/trinity-beast-stack.yaml
This is the canonical version. All edits should be made here and then synced to S3.
s3://trinity-beast-website-east2/cloudformation/trinity-beast-stack.yaml
A copy in S3 for redundancy. You can deploy directly from S3 using --template-url instead of --template-body:
aws cloudformation create-stack \
--stack-name trinity-beast-stack \
--template-url https://trinity-beast-website-east2.s3.us-east-2.amazonaws.com/cloudformation/trinity-beast-stack.yaml \
--capabilities CAPABILITY_NAMED_IAM \
--region us-east-2 \
--parameters ...
trinity-beast-lpo-server/deployments/cloudformation/inventory/
This directory contains 75 JSON files — one for every resource's current configuration as captured from the live AWS environment at the time of capture. These serve as a reference if you need to verify that the CloudFormation template matches what's actually deployed. They're snapshots, not live data — some predate the 2026-08-13 correction pass and may themselves be stale; treat them as a starting point for comparison, not as ground truth.
Keep these in sync: When you update the template locally, remember to upload the new version to S3: aws s3 cp trinity-beast-stack.yaml s3://trinity-beast-website-east2/cloudformation/