Skip to main content

Infrastructure as One Stack

Every Azure resource behind ALERTCalifornia — the web apps and function apps, the storage accounts, Cosmos and SQL, App Configuration and Key Vault, SignalR, Event Hubs, Front Door, and all the monitoring — is defined as code in this repository, and stamped out identically to five environments. Nothing is clicked into existence in the portal. This section is the guide to that code: how it's organized, how it deploys, and how to change it safely.

If you've worked in application repos, the mental shift is this: there are no "requests" here, only desired state. You describe what Azure should look like; Terraform computes the diff against reality and makes it so. Everything below serves that one idea.

The three pieces​

The infrastructure is not one big file — it's three cooperating layers:

  • The root stack (alertca/) is the composition — it decides which resources exist, wired together with identities, roles, and configuration. It's organized by domain, not by resource type (more on that next).
  • The reusable modules (Terraform.Module.Azure.*) are separate, version-pinned repositories that each know how to build one kind of Azure resource well. The root stack consumes them; it rarely writes raw azurerm_* resources itself.
  • The pipelines (devops/) run Terraform against the stack for a chosen environment — init, plan, and apply — with approvals between environments.

Organized by domain, not by resource type​

Open alertca/ and you won't find storage.tf, network.tf, compute.tf. You'll find domain pairs — a locals.<domain>.tf that holds a domain's configuration as data, and a main.<domain>.tf that turns that data into resources:

Domain pairOwns
locals.backend.tf · main.backend.tfThe backend/admin APIs (web apps)
locals.functions.tf · main.functions.tfThe Azure Function apps
locals.storage.tf · main.storage.tfStorage accounts, containers, queues, tables
locals.databases.tf · main.database.tfCosmos DB and SQL
locals.appconfig.tf · main.appconfig.tfApp Configuration keys and Key Vault references
locals.identities.tf · main.roles.tfManaged identities and RBAC
… and appinsights, eventhub, frontdoor, keyvault, monitor, mock, scheduler, signalr

Cross-cutting files sit alongside them: locals.tf (naming and tags), variables.tf (the typed input contract), data.*.tf (data sources), outputs.tf (values downstream systems read), provider.tf, and terraform.tf (versions and the remote state backend).

The stack, deployed five ways​

The same code produces five environments — hub, sbx, dev, uat, prd — using Terraform workspaces over a single remote state backend, with per-environment envs/*.tfvars overrides and one Azure subscription each. How that works, and how a change is promoted from dev to production, is a lesson of its own.

The reading path​

This section builds from "how it's shaped" to "how to change it safely":

  1. The Domain Pattern — how one domain wires config → resources → identity → RBAC → config.
  2. Reusable Modules — the module catalog, the contract, and how to add one.
  3. Environments & Deployment — workspaces, state, tfvars, and the pipeline.
  4. Adding a Component — the end-to-end workflow, step by step.
  5. Naming, Identity & RBAC — the conventions that keep 200+ resources coherent.
  6. State, Pinning & Gotchas — remote state, version pinning, and the sharp edges.

Wrapping up​

The ALERTCalifornia infrastructure is one domain-organized Terraform stack that composes version-pinned reusable modules and deploys to five workspace-backed environments through Azure DevOps pipelines. The whole thing is desired state: you edit the description, Terraform reconciles Azure to match. Start with the pattern every domain follows: The Domain Pattern.