# Contracts

A consumer declares intent in a **contract** — a small YAML file that
names infrastructure (one or more modules), selects an environment, and
supplies module-specific inputs. The platform validates, resolves, and
deploys it.

## The contract file

A consumer repo keeps its contract at `.acdl/contract.yml`. A minimal
example (the `static-assets` module):

```yaml
id: assets
name: static-assets
environment: dev
infrastructure:
  static-assets:
    version: "1.0.0"
    inputs:
      bucket_name: my-static-site-assets
      region: us-east-1
```

A `microservice` example:

```yaml
id: msvc
name: microservice
environment: dev
infrastructure:
  microservice:
    version: "1.0.0"
    inputs:
      image: my-registry/my-microservice:latest
      port: 8080
      env:
        LOG_LEVEL: info
```

## Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | string | yes | Short operational acronym (3-6 chars, `^[a-z][a-z0-9-]{2,5}$`). Becomes the stack name used for the Terraform state key, ECS service name, outbox event identity, and resource naming prefix. |
| `name` | string | yes | Full human-readable stack name (min 3 chars). Becomes the stack title used for display in PR comments, evidence records, and leadership dashboards. |
| `environment` | string | yes | The platform-managed environment to deploy to (`dev`/`qa`/`prod`/`dr`). See [Environments](../environments/). |
| `infrastructure` | object | yes | Map of modules to deploy, keyed by module registry name. Each entry has an optional `version` (defaults to latest published) and required `inputs`. One entry = single-module deploy; N entries = multi-module manifest deployed in one pipeline run. |

### Infrastructure entry fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `version` | string | no | Module version pin (semver `X.Y.Z`). Omitted = latest non-deprecated version from the registry. |
| `inputs` | object | yes | Module-specific inputs (see the module's README). |

## Validation

The contract is validated against
[`schemas/contract.schema.json`](https://github.com/acdl/acdl/blob/main/schemas/contract.schema.json).
An invalid contract (missing field, unknown module, wrong type) fails at the
validate-contract stage with a clear error.

## Sample contracts

Two reference examples exist in `contracts/`:

- [`contracts/static-assets.yml`](https://github.com/acdl/acdl/blob/main/contracts/static-assets.yml)
  — the `static-assets` module.
- [`contracts/microservice.yml`](https://github.com/acdl/acdl/blob/main/contracts/microservice.yml)
  — the `microservice` module.

Additionally, every module has a `modules/<name>/examples/` directory with
validated example contracts (`simple.yml` + `complex.yml` + variation
files). See the [module catalog](../modules/) for the full list.

## Multiple modules per contract

A contract may declare multiple modules under the `infrastructure` map.
All modules deploy to the same `environment` in one pipeline run. Resource
IDs are namespaced with the module name to avoid collisions (e.g.
`microservice-vpc`, `static-assets-s3`).

```yaml
id: app
name: pricing-service-api
environment: dev
infrastructure:
  microservice:
    version: "1.0.0"
    inputs: { ... }
  static-assets:
    version: "1.0.0"
    inputs: { ... }
```

## Multiple contracts

A consumer repo may also contain more than one contract file (e.g. one per
environment). Each contract is a separate deployment; each is referenced by a
CI definition in `.github/workflows/` that invokes the central reusable
workflow with the contract path. See the
[Consumer Guide](../consumer-guide/) for the multi-contract pattern.