# Naming Standards — General Approach

This document describes a general naming approach for Terraform-managed AWS resources, using the VPC module as a reference example.

## 1. Core Pattern

Every resource name follows a consistent structure:

```
${var.name}-<resource-type>[-<qualifier>]
```

- **`var.name`** — a caller-supplied prefix identifying the deployment (e.g. an environment, workload, or stack name). The module itself never hardcodes this; it's injected from outside.
- **`<resource-type>`** — a short, fixed token identifying what kind of resource this is (`vpc`, `subnet`, `rt`, `nat`, `igw`, `eip`, `flow-log`).
- **`<qualifier>`** — optional, used when multiple instances of the same resource type exist (a tier, an AZ key, a logical map key).

Examples pulled directly from the module:

```
${var.name}-vpc
${var.name}-igw
${var.name}-flow-log-role
${var.name}-subnet-public-${each.key}
${var.name}-subnet-private-${each.key}
${var.name}-subnet-isolated-${each.key}
${var.name}-rt-public
${var.name}-rt-private-${each.key}
${var.name}-rt-isolated-${each.key}
${var.name}-nat-eip-${each.key}
${var.name}-nat-${each.key}
```

## 2. Resource-Type Tokens Are Abbreviated and Fixed

The module uses a small, consistent vocabulary for resource types rather than spelling things out per-resource:

| Token           | Resource               |
| --------------- | ---------------------- |
| `vpc`           | VPC                    |
| `igw`           | Internet Gateway       |
| `nat`           | NAT Gateway            |
| `nat-eip`       | Elastic IP for NAT     |
| `subnet`        | Subnet                 |
| `rt`            | Route Table            |
| `flow-log`      | VPC Flow Log           |
| `flow-log-role` | IAM Role for flow logs |

Keeping these short and stable means names stay predictable and greppable across the whole estate, regardless of what `var.name` is set to.

## 3. Qualifiers Encode Tier and Key, Not Free Text

Where a resource type can have multiple instances, the name appends a **tier** (`public` / `private` / `isolated`) and/or the **map key** (`each.key`) that produced it — never a free-form description:

```
${var.name}-subnet-public-${each.key}
${var.name}-rt-isolated-${each.key}
```

This means the name is fully derivable from the Terraform state — anyone looking at `for_each` inputs can predict the resulting resource name without needing external documentation.

## 4. Tags Carry Structured Metadata; Names Carry Identity

The module separates two concerns:

- **Name** (`Name` tag / resource name attribute) — human-identifiable, follows the pattern above.
- **`resource-type` tag** — a machine-filterable, redundant encoding of what the resource is, independent of naming convention drift:

```hcl
tags = merge(var.tags, local.module_tags, {
  Name          = "${var.name}-subnet-public-${each.key}"
  resource-type = "subnet"
  reachability  = "public"
})
```

A third convention layer — `reachability` — captures a semantic property (public/private/isolated) that isn't strictly a "type" but is useful for querying or policy enforcement.

Additionally, `local.module_tags` injects two constants on every resource:

```hcl
module_tags = {
  managed-by  = "terraform"
  module-name = "networking:vpc"
}
```

`module-name` uses a `<domain>:<component>` convention (`networking:vpc`) — useful when many modules across many domains are tagging resources into the same account, so origin is traceable without inspecting state.

## 5. Conditional Resources Use Fixed Singleton Keys, Not Booleans in Names

For resources that may or may not exist (`aws_internet_gateway.this`, `aws_route_table.public`, `aws_flow_log.this`, IAM role/policy for flow logs), the module uses a `for_each` over a single-key map (`{ igw = true }`, `{ public = true }`, `{ flow_log = true }`, `{ role = true }`) rather than `count = 0/1`. This keeps:

- The **resource address** stable (`aws_internet_gateway.this["igw"]` rather than `aws_internet_gateway.this[0]`), so toggling the condition doesn't force a destroy/recreate.
- The **name string itself unaffected by the condition** — the qualifier is a fixed literal (`"igw"`, `"public"`, `"flow_log"`, `"role"`), not derived from a boolean.

## 6. Summary Rules

1. Prefix every name with the caller-supplied identity (`var.name`); never hardcode identity inside a module.
2. Use a short, fixed abbreviation per resource type; keep the vocabulary small and consistent module-wide.
3. Append tier/key qualifiers only when multiplicity requires disambiguation, and derive them from `for_each` keys — never free text.
4. Mirror the resource type as a tag (`resource-type`) so it's queryable independent of the name string.
5. Tag every resource with a constant module identity (`module-name`, `managed-by`) using a `domain:component` style for the module name.
6. For optional/conditional resources, use singleton-map `for_each` with a fixed key rather than `count`, so addresses and names stay stable across toggles.
