Architecture specification

Modules

Small, focused infrastructure building blocks with explicit inputs and outputs, consumed by deployable roots in env/ and workspaces/.

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

01 Defines

The directory of reusable infrastructure local to a repository: composable implementation details that deployable roots wire to concrete targets, with every environment-specific value exposed as an input.

02 Applies when

  • The same infrastructure shape is needed by more than one root, such as a canonical environment and a developer workspace.
  • Implementation detail would otherwise be copied between roots.
  • A repository needs infrastructure behaviour that no external module provides.

03 Boundaries

  • A module does not represent a concrete deployment unless it is deliberately designed to double as a standalone root.
  • Deployment-specific names, tiers, and account details stay in the roots.
  • Modules published outside the repository are consumed by roots directly and need not be mirrored here.

Expected behaviour

  1. 01
    Modules are reusable across environments and workspaces in the same repository.
  2. 02
    Provider requirements are explicit.
  3. 03
    Behaviour is driven by clear inputs and outputs rather than implicit environment assumptions.
  4. 04
    Module-local state, provider plugin directories, and cache output are never committed.
  5. 05
    Modules carry no lock file unless they are also standalone deployable roots.

Behaviour#

A module is the part of the infrastructure that does not care where it is deployed. It knows how to build a thing — a bucket and its distribution, a secrets store, a network — and it asks the caller for everything that differs between targets: the domain, the tags, which providers to use.

Roots supply those answers. Because a module makes no assumptions about tier or account, the same module can sit behind production and behind every developer’s own copy, and a fix made once reaches all of them.

FlowWhere each concern lives
  1. 01 Module How the infrastructure is built; inputs for everything that varies
  2. 02 Root Which target, which domain, which backend, which credentials Environments
  3. 03 Deployer Runs the root by convention, with no extra parameters Parameterless Deployment

Local and external modules#

Reusable infrastructure can come from two places. Modules specific to this repository live in modules/. Modules worth sharing more widely are published to a registry and referenced from roots by source address — exactly how this repository’s static-site stack is consumed.

  • modules/
  • .assets/ The README icon
  • .gitignore Managed; ignores state, plugins, caches, and lock files
  • README.md The managed standard for this directory Managed Standard Files
  • env/
  • prod/
  • release/ Composes the published site module Environments
  • workspaces/
  • site/ Composes the same published module Workspaces

modules/ here holds only the standard: the whole S3, CloudFront, ACM, and DNS pattern comes from a published module, so there is nothing local to keep.

Inputs, not assumptions#

Exposed as an input

  • The domain a site is served from
  • Provider configurations for each region or account
  • Optional behaviour, such as enable_monitoring

Kept out of the module

  • Names like production or a developer’s username
  • Account IDs and named AWS profiles
  • Backend and state configuration

Examples#

Both roots call the same module. The workspace root passes one extra input to switch off monitoring for disposable copies — the module exposes the choice rather than guessing it:

workspaces/site/main.tf
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
  enable_monitoring = false
}