Vertex — AWS architecture
Status: Proposed · Region: eu-west-1 (Ireland)

Network (common ttg-* layer, per environment)
The network, NAT instance and RDS instance form the common platform layer (ttg-<env>-*). Vertex owns only its
application resources (vertex-<env>-*).
| prod | stage | |
|---|---|---|
| VPC | ttg-prod-vpc · 10.30.0.0/16 | ttg-stage-vpc · 10.20.0.0/16 |
| Public subnets (AZ a/b/c) | 10.30.0-2.0/24 | 10.20.0-2.0/24 |
| Private application subnets | 10.30.10-12.0/24 | 10.20.10-12.0/24 |
| Private data subnets | 10.30.20-22.0/24 | 10.20.20-22.0/24 |
All nine subnets are created per VPC (subnets are free). Only AZ a runs resources today; AZ b/c are reserved for a future ALB, NAT gateway, additional tasks and RDS Multi-AZ. Stage and prod VPCs are not peered.
Route tables
| Route table | Subnets | Destination | Target |
|---|---|---|---|
ttg-<env>-rt-public | public-a/b/c | 0.0.0.0/0 | Internet gateway |
ttg-<env>-rt-app | private-app-a/b/c | 0.0.0.0/0 | NAT instance ENI |
ttg-<env>-rt-data | private-data-a/b/c | VPC CIDR | local only (no internet) |
Components
| Component | Specification |
|---|---|
NAT instance ttg-<env>-nat | t4g.nano, Amazon Linux 2023 + iptables (no community AMI), Elastic IP (fixed egress IP), source/destination check disabled. Swap to NAT gateway by one variable. |
ECS cluster / service vertex-<env> | Fargate, x86_64, task 0.5 vCPU / 2 GB. prod desired 1; stage 0–1. Deployment circuit breaker with rollback; ECS Exec enabled. |
| Task containers | core :8020 (runs Alembic migrations on start, dependsOn identity healthy, IDENTITY_BASE_URL=http://localhost:8030) · identity :8030 (health /health) · cloudflared (official image, tunnel token only). All essential. |
RDS ttg-<env>-postgres | PostgreSQL 16, db.t4g.micro, 20 GB gp3, Single-AZ, encrypted, not public, rds.force_ssl=1, master password managed by RDS. DB subnet group = data-a + data-b (RDS requires two AZs). |
| RDS prod settings | Deletion protection on, final snapshot on delete, 7-day backups (requires the AWS paid plan). |
| RDS stage settings | 1-day backups, stoppable when idle. |
| Logs | CloudWatch Logs /vertex/<env>/{core,identity,cloudflared}, 30-day retention. |
Terraform layout (ttg-infra)
ttg-infra/
terraform/
modules/ network, nat, database, secrets, ecs, access
shared/prod ttg-prod-vpc, ttg-prod-nat, ttg-prod-postgres (state key shared/prod)
shared/stage ttg-stage-vpc, ttg-stage-nat, ttg-stage-postgres (state key shared/stage)
vertex/prod ECS service, roles, secrets — reads shared/prod outputs
vertex/stage same for stage
apps/vertex/cloudflare/wrangler.toml
.github/workflows/vertex-deploy.yml, stage-power.yml
App stacks read the shared layer's outputs (VPC id, subnets, RDS endpoint and security group), so an app change
can never modify the common network or database. terraform plan / apply run locally by the TTG operator.
Kept open for later
- NAT instance → NAT gateway per AZ (one variable)
- Single AZ → multi-AZ tasks; RDS Single-AZ → Multi-AZ (one flag)
- Tunnel → ALB + ACM certificate on
thetaxgraph.com(public subnets already exist) - Single account → one AWS account per environment (modules take the account as input)
- x86_64 → ARM64 after an arm64 build is proven on stage