Architecture specification

Environments

Thin, canonical deployable roots under env/ that compose reusable modules for a concrete deployment target and run without ad hoc parameters.

Applies at
env/
Status
Stable
Source · managed
env/README.md

01 Defines

The directory of canonical deployment targets: one readable root per logical deployed unit and tier, wiring reusable modules to the configuration that a specific continuous-deployment target needs.

02 Applies when

  • A repository deploys something — a website, a service, a secrets system — through continuous deployment.
  • The same deployed unit exists in more than one tier or variant, such as production, non-production, or a pull request deployment.
  • A generic deployment system needs to find and run a root using only repository conventions.

03 Boundaries

  • Reusable infrastructure lives in modules, not in environment roots.
  • Developer-oriented and user-derived deployments live in workspaces/.
  • Shared infrastructure such as VPCs and DNS zones may be referenced but is owned here only if this repository deploys it.

Expected behaviour

  1. 01
    Each root is a thin entry point that composes modules and supplies target-specific configuration.
  2. 02
    Roots are organised by logical deployed unit and then by environment tier or variant.
  3. 03
    Every root can be executed by a generic deployer without deployment-specific parameters passed by hand.
  4. 04
    Provider lock files are committed for deployable Terraform roots.
  5. 05
    State files, local variable files, provider plugin directories, and local cache output are never committed.

Behaviour#

env/ answers the question “what can be deployed?”. Each directory beneath it is a root that a deployment system can point at and run, and each one stands for a real target — production, a non-production tier, a variant. Reading the tree tells you the full set of canonical deployments without opening any file.

A root is wiring, not implementation. It names a module, supplies a domain, a backend, and credentials, and exposes the outputs a deployer needs. The infrastructure pattern itself lives in a module, local or published, so the same pattern can back every tier. See Pinned Module Composition .

Terraform is the primary format, but the directory is not limited to it. Any deployment definition that the repository’s orchestration can execute as a root belongs here.

Layout#

  • env/
  • prod/ Environment tier
  • release/ Logical deployed unit: the website Pinned Module Composition
  • .terraform.lock.hcl Committed provider lock file
  • backend.tf Committed S3 backend; the root owns its state
  • main.tf Locals and one module block Modules
  • outputs.tf Values the deployer reads after apply
  • providers.tf Named AWS profiles and regions
  • versions.tf Terraform and provider constraints

Environments and workspaces#

env/

  • Canonical continuous-deployment targets
  • Fully parameterless under the deployer
  • One root per deployed unit and tier
  • State owned directly by the root

workspaces/

  • Development, testing, and validation copies
  • Identity may come from developer context
  • One root per system, many instances
  • One state object per Terraform workspace

The split keeps env/ strict without making developer systems awkward: anything that needs the current user or branch to decide its identity moves to Workspaces , and env/ stays Parameterless Deployment .

Examples#

The production root is a handful of locals and a single module block:

env/prod/release/main.tf
locals {
  site_domain = "sampletest.dev.prosyon.ca"

  tags = {
    Environment = "production"
    Project     = "static-website"
    ManagedBy   = "terraform"
  }
}

module "this" {
  source = "registry.forge.prosyon.ca/patterned-designs/hcl-aws-cloudfront-s3-static-website-xam--variant-shared/aws"

  providers = {
    aws           = aws
    aws.us_east_1 = aws.us_east_1
    aws.dns       = aws.dns
  }

  domain = local.site_domain
}

Its outputs are exactly what the deployer needs to finish the job:

env/prod/release/outputs.tf
# The three values scripts/deploy.sh needs to upload the site and refresh the CDN.

output "bucket_name" {
  value = module.this.bucket_name
}

output "cloudfront_distribution_id" {
  value = module.this.cloudfront_distribution_id
}

output "site_url" {
  value = "https://${local.site_domain}"
}