engineering-handbook/terraform-project-layout.md
Adam Moussa 85de977098
docs(cd): separate terraform infra from github app deploys
Make HCP Terraform plus GitHub Actions content CD the default for new
workloads, and keep SAM/CDK documented as the remaining path.
2026-09-15 17:58:09 -04:00

2.8 KiB

Terraform Project Layout

Default layout for new deployable repos. HCP Terraform applies this tree. GitHub Actions publishes application content. See hcp-terraform.md and cicd.md.

Standard Directory Structure

project-name/
├── terraform/
│   ├── bootstrap/                 # Committed stubs Terraform can create
│   │   └── handler-stub.zip
│   ├── iam_github_deploy.tf       # githubdeploy-<repo> only
│   ├── lambda.tf
│   ├── s3.tf
│   ├── ssm.tf                     # /<repo>/deploy/* contract
│   ├── variables.tf
│   ├── outputs.tf
│   └── versions.tf
├── src/                           # Application code (GHA owns the zip)
├── scripts/                       # Live-state verify scripts
├── .github/
│   └── workflows/
│       ├── ci.yaml
│       └── deploy-<name>.yaml     # One workflow per deployable
└── README.md

Working directory in both HCP workspaces is terraform. Do not flatten per-env roots (terraform/live/dev) unless a remaining stack already has them. New repos use one tree; workspaces select the account via variables.

File Purposes

terraform/bootstrap/

A tiny committed zip (or equivalent) so Terraform can create the Lambda. GitHub Actions overwrites the live code on the first deploy. Check the stub in. Do not generate it at plan time with data.external or archive_file from application source.

lambda.tf (or equivalent)

Create the skeleton. Point it at the stub. Set lifecycle.ignore_changes on filename, s3_bucket, s3_key, s3_object_version, and source_code_hash. Do not set GIT_SHA or a release label as a Terraform env var.

ssm.tf

Write /<repo>/deploy/* (see hcp-terraform.md). Workflows read these. YAML does not hardcode resource names.

iam_github_deploy.tf

The githubdeploy-<repo> role only. Trust and permissions are in cicd.md. Adding a deploy workflow means adding its job_workflow_ref here. That is a cross-family IAM change.

Do not add hcp_iam.tf. hcptf-<repo> and hcptf-<repo>-plan live in seahaven-org-baseline.

Application trees (src/, bff/, web/, functions/)

Owned by GitHub Actions. HCP trigger prefixes do not include these paths.

CI for Terraform

Repo CI runs terraform fmt -check -recursive, terraform init -backend=false, and terraform validate. Plans stay in HCP speculative runs. Do not have GitHub Actions call the HCP API to create or apply a run.

Remaining path

Stacks that still package Lambda code inside Terraform (mgmt migrations that have not been cut over) keep their source paths in HCP file triggers until they adopt this layout. New repos start here.