# Products and environments

Products are what you test, environments are where they run, and a deployment joins one product to one environment.

A workspace describes the software it tests and where that software runs with three objects.
Products and environments do not depend on each other; only a deployment joins them. Test runs
target a deployment, and the secrets vault keeps each deployment's values.

| Object      | Meaning                                                                                                                          |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Product     | A piece of software the workspace tests, such as the `storefront` website or a public API                                        |
| Environment | A place products run, such as `staging` or `production`, shared by every product                                                 |
| Deployment  | One product running in one environment: where it answers (`baseUrl`), its Fixture API (`fixtureUrl`) and which build (`version`) |

## Products

- `slug`: 2–48 lowercase letters, digits or hyphens, with no hyphen at the start or end and not a
  reserved Windows folder name such as `con`. Unique in the workspace.
- `name`: 1–100 characters, unique in the workspace ignoring case.
- `type`: `website`, `api`, `cli`, `mobile_app`, `desktop_app` or `agent`. A product becomes a
  website or API product only once each of its deployments has a base URL.
- `description`: optional, up to 200 characters.
- `repository`: optional, the source repository as `owner/name`, such as `acme/storefront`.
  Messages about a project's tickets go to agent sessions working in the repositories of the
  products the project changes.

## Environments

- `slug` and `name`: the same rules as a product, with names up to 80 characters.
- `class`: `production` or `non-production`, chosen at creation and never changed. Production means
  real customer data, or the live system customers use. To treat a place as the other class, create
  a new environment.
- `description`: optional, up to 200 characters. `emoji`: optional, shown beside the name.

The class decides the vault's rules: only admins and owners write production secrets, and only a
vault key reads them back. See [Secrets vault and CLI](https://docs.qa.clankership.net/get-started/concepts/secrets-vault.md).

## Deployments

- One per product and environment pair, addressed as `{product}/{environment}`, such as
  `storefront/staging`.
- `baseUrl`: an `http://` or `https://` URL without a username, password or `#fragment`. A trailing
  slash is dropped. Required for website and API products.
- `fixtureUrl`: optional, the deployment's Fixture API, which test runs call to create test data
  and delete it when they finish. It follows the same URL rules as `baseUrl`. See
  [Test runs](https://docs.qa.clankership.net/get-started/concepts/test-runs.md#test-data).
- `version`: optional free text up to 100 characters, such as a git SHA or a tag. The server sets
  `versionUpdatedAt` whenever it changes.
- `active`: false while its product or its environment is archived.

Responses carry IDs as well as slugs. IDs never change; renaming a slug keeps deployments, secrets
and vault key grants, and the old slug stops working.

## Archive, restore and remove

Products and environments are archived, never deleted. Archiving one:

- hides it from lists unless you ask for archived objects with `archived=include` or
  `archived=only`;
- makes it read-only: changing it, or creating, changing or removing one of its deployments, fails
  with `409` and says to restore it first;
- keeps its slug and name reserved, so it can always be restored;
- makes its deployments inactive, so vault pulls for them are refused.

Restoring reverses all of this. Repeating an archive or a restore returns the object unchanged.

Removing a deployment deletes it, but its secret values stay: deploying the same pair again brings
them back.

## Who can change them

| Action                                              | Viewer | Member | Admin, owner |
| --------------------------------------------------- | ------ | ------ | ------------ |
| List and get products, environments and deployments | yes    | yes    | yes          |
| Create, change, archive and restore                 | no     | yes    | yes          |
| Create, change and remove deployments               | no     | yes    | yes          |

## API

Paths are relative to `https://api.clankertest.com/v1/workspaces/{slug}`. Creating returns `201`,
removing a deployment returns `204`, and every other call returns `200` with the object. `PATCH`
changes only the fields you send, and `null` clears an optional field.

| Operation           | Request                                        | Reference                                      |
| ------------------- | ---------------------------------------------- | ---------------------------------------------- |
| List products       | `GET /products?archived=include`               | [List products](https://docs.qa.clankership.net/api/products/list.md)            |
| Create a product    | `POST /products`                               | [Create a product](https://docs.qa.clankership.net/api/products/create.md)       |
| Change a product    | `PATCH /products/{product}`                    | [Update a product](https://docs.qa.clankership.net/api/products/update.md)       |
| Archive, restore    | `POST /products/{product}/archive`, `/restore` | [Archive a product](https://docs.qa.clankership.net/api/products/archive.md)     |
| Environments        | The same under `/environments`                 | [Environments](https://docs.qa.clankership.net/api/environments.md)              |
| List deployments    | `GET /deployments?product=storefront`          | [List deployments](https://docs.qa.clankership.net/api/deployments/list.md)      |
| Create a deployment | `POST /deployments`                            | [Create a deployment](https://docs.qa.clankership.net/api/deployments/create.md) |
| Change a deployment | `PATCH /deployments/{product}/{environment}`   | [Update a deployment](https://docs.qa.clankership.net/api/deployments/update.md) |
| Remove a deployment | `DELETE /deployments/{product}/{environment}`  | [Delete a deployment](https://docs.qa.clankership.net/api/deployments/delete.md) |

```bash
curl https://api.clankertest.com/v1/workspaces/acme/deployments \
  -H "Authorization: Bearer $CLANKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "product": "storefront", "environment": "production", "baseUrl": "https://shop.acme.dev" }'
```

## CLI

Every command prints the API's JSON, uses the workspace `clanker link` recorded (or `--workspace`),
and exits 2 when it is used wrongly or the request is refused. An empty value clears a field.

```bash
clanker environment create production --name Production --class production
clanker product create storefront --name Storefront --type website --repository acme/storefront
clanker deployment create storefront production --base-url https://shop.acme.dev \
  --fixture-url https://shop.acme.dev/fixtures
clanker deployment update storefront production --deployed-version "$GIT_SHA"
clanker product list --archived only
clanker product archive storefront
clanker product restore storefront
```

The flag is `--deployed-version` because `--version` prints the CLI's own version.

## Agents

Agents use [list_products](https://docs.qa.clankership.net/mcp/tools/list_products.md),
[create_deployment](https://docs.qa.clankership.net/mcp/tools/create_deployment.md), [update_deployment](https://docs.qa.clankership.net/mcp/tools/update_deployment.md)
and the other catalog tools, or their `/agent/v1` twins. Archiving and removing are marked
destructive, so clients ask before they run them.

## Errors

| Rule                        | Status | Example message                                                                          |
| --------------------------- | ------ | ---------------------------------------------------------------------------------------- |
| Slug or name taken          | `409`  | A product named Storefront already exists.                                               |
| Taken by an archived object | `409`  | An archived product already uses the slug storefront. Restore it or choose another slug. |
| Pair already deployed       | `409`  | Storefront is already deployed to Staging.                                               |
| Archived object             | `409`  | Storefront is archived. Restore it before changing it or its deployments.                |
| Not found                   | `404`  | No product with the slug storefront.                                                     |
| Role too low                | `403`  | You do not have permission to manage products, environments or deployments.              |
| Bad slug, class or base URL | `400`  | The message names the rule, such as the slug format or a missing base URL.               |
