# ADR 0009 — Postman collection and Newman smoke

- Status: Accepted
- Date: 2026-08-19

## Context

The final deliverable is a Postman collection + environments that stays in sync
with the API and can drive an end-to-end smoke run, including tokens that only
arrive by email.

## Decisions

- **Generated base, enriched by hand.** `scripts/gen-postman.sh` exports
  `/v3/api-docs` and runs `openapi-to-postmanv2`, so the endpoint list is derived
  from the OpenAPI spec and cannot drift. The committed
  `demo-api.postman_collection.json` is that base enriched with collection-level
  bearer auth (`{{accessToken}}`), token-capture scripts, the Smoke folder, and
  `pm.test` assertions (status, body shape, and `ProblemDetail` `code` on errors).
- **Environment variables only; no committed secrets.** `baseUrl`, `mailhogUrl`,
  `email`, `password`, `accessToken`, `refreshToken`, `itemId`,
  `activationToken`, `resetToken`, etc. Committed `local`/`staging`/`prod`
  environments hold placeholders; real values go in a gitignored
  `*.local.postman_environment.json`.
- **Email tokens via the MailHog HTTP API.** Of the two supported ways, the
  collection implements option 1: a pre-request script reads
  `{{mailhogUrl}}/api/v2/messages`, matches the message to the run's unique
  `smoke+<ts>@example.com`, and extracts the token. The test-profile-only endpoint
  (option 2) was deliberately not built — nothing token-revealing should exist in
  a prod-reachable path.
- **Newman extends (not replaces) the bash smoke on staging.** `deploy.yml` runs
  the bash `smoke-test.sh` first (fast, dependency-free), then — on staging only —
  the Newman **Smoke** folder for the full ordered journey, publishing an HTML
  report artifact. Prod keeps the lighter bash smoke to avoid registering throwaway
  accounts in production.
- **TLS**: docs tell users to import the dev CA into Postman, reserving
  `--insecure` for throwaway local runs and never staging/prod.

## Consequences

- Validated locally with Newman against a live container: **Smoke** (12 requests /
  14 assertions) and **Negative paths** (4 / 6) both pass, including MailHog token
  retrieval and refresh reuse detection.
- Regenerating the base after an API change is one command; the enrichment is
  re-applied on top.
