Ahmed Hassan·
Claude Code reads our Terraform and emits a Mermaid diagram grouped by VPC, with data flows annotated. First time in months the architecture doc matched what is actually deployed.
Generates a reviewable Mermaid architecture diagram from Terraform configuration — grouped by network boundary, annotated with protocols, and honest about what it cannot infer.
Terraform-to-Mermaid Architecture Diagram
You are working in a repository containing Terraform configuration. Produce an architecture diagram that reflects what is ACTUALLY declared — not a generic cloud reference diagram.
Scope: {{tf_directory}}
Audience for the diagram: {{audience}}
Process:
1. **Inventory.** Read the Terraform in scope and list the deployed resources that matter architecturally: compute (instances, containers, functions), data stores, queues/topics, load balancers, gateways, DNS entries, and network boundaries (VPCs, subnets, peering, security groups). Skip IAM plumbing, log groups, and tagging modules unless they change the architecture story.
2. **Establish boundaries first.** The diagram's subgraphs are network boundaries: one subgraph per VPC, nested subgraphs for public/private subnet tiers. Anything external (SaaS endpoints, third-party APIs referenced in config) sits outside all subgraphs.
3. **Draw only declared edges.** An arrow requires evidence in the config: a security group rule, a listener/target mapping, an environment variable containing another resource's endpoint, a queue subscription. Annotate each edge with protocol and port where the config states it. If you infer an edge from an environment variable rather than a network rule, style it as a dashed line.
4. **Mark the unknowns.** Anything the Terraform references but does not define (data sources, hardcoded ARNs, that one mystery CIDR in a security group) goes in a clearly labeled 'external/unmanaged' group. Do not silently omit them — unmanaged dependencies are what bite during incidents.
5. **Output.** A single Mermaid `flowchart TB` block that renders without errors, followed by a legend and a short 'diagram debt' list: things declared in ways you could not confidently place, each with the file and line to check.
Keep node labels short (resource role, not full Terraform address) but include a mapping table from node label to Terraform address below the diagram.
Ergebnisse
## Architecture: `infra/prod` (14 architectural resources, 2 VPCs)
```mermaid
flowchart TB
subgraph vpc_app["VPC app-prod 10.20.0.0/16"]
subgraph pub["public subnets"]
alb["ALB api"]
nat["NAT gw"]
end
subgraph priv["private subnets"]
ecs["ECS api service"]
worker["ECS worker"]
redis[("ElastiCache redis")]
end
end
subgraph vpc_data["VPC data-prod 10.30.0.0/16"]
rds[("RDS postgres")]
end
ext_dns["Route53 api.example.com"] --> alb
alb -->|HTTP 8080| ecs
ecs -->|TCP 6379| redis
ecs -->|TCP 5432 via peering| rds
worker -->|TCP 5432 via peering| rds
worker -.->|HTTPS| ses["SES (external)"]
ecs -.->|HTTPS| stripe["Stripe API (external)"]
sqs[["SQS jobs queue"]] --> worker
ecs -->|SendMessage| sqs
subgraph unmanaged["external / unmanaged"]
legacy["CIDR 172.16.4.0/24 → RDS:5432"]
certarn["ACM cert (hardcoded ARN)"]
end
legacy -.-> rds
certarn -.- alb
```
**Legend:** solid = network-rule-backed edge · dashed = inferred from env var or hardcoded reference · cylinder = data store · double bracket = queue.
**Node → Terraform address:** alb → `aws_lb.api` · ecs → `aws_ecs_service.api` · worker → `aws_ecs_service.worker` · redis → `aws_elasticache_cluster.main` · rds → `aws_db_instance.primary` · sqs → `aws_sqs_queue.jobs` · nat → `aws_nat_gateway.main` (`network.tf:41`).
**Diagram debt:**
1. `security_groups.tf:88` — ingress from `172.16.4.0/24` to Postgres, no comment, not any VPC in this repo. Labeled unmanaged; someone should know what this is (VPN range? old office?).
2. `alb.tf:23` — certificate ARN hardcoded rather than via data source; if it is rotated outside Terraform, the listener breaks silently.
3. `worker.tf:31` — SES region env var differs from provider region (`eu-west-1` vs `eu-central-1`). Possibly intentional (SES availability), worth a comment.
4. Stripe edge inferred from `STRIPE_API_URL` env var only — no egress restriction exists, so the real egress surface is wider than the diagram shows.
Modell: Claude Code
30 Likes20 SavesScore: 23
2 Kommentare
Marco Rossi·
The unmanaged-CIDR callout is the whole value right there. Every prod environment has one mystery security group rule and it is always load-bearing.
Priya Nair·
Dashed-line convention for env-var-inferred edges is smart — same idea works for data lineage diagrams where half the edges come from dbt refs and half from airflow config.
