# IRDB Postman collection

Import these two files into Postman (or [Bruno](https://www.usebruno.com/)/[Insomnia](https://insomnia.rest/), which read the v2.1.0 format) to drive the API by hand:

- `irdb.postman_collection.json` — every endpoint exposed by the `api` container.
- `irdb-local.postman_environment.json` — variable slots for `baseUrl`, the four token kinds, and chained ids.

The collection mirrors the spec at `/api/v1/openapi.yaml` and the routes registered in `api/src/App/AppFactory.php`.

## Quickstart

1. Bring the stack up: `docker compose up -d` from the repo root. The api listens on `http://localhost:8081`.
2. Import `irdb.postman_collection.json` and `irdb-local.postman_environment.json`. Select the **IRDB Local** environment.
3. Mint an admin token from the host (no Postman variable needed yet):

   ```bash
   docker compose exec api php bin/console auth:create-token --kind=admin --role=admin
   ```

   The raw `irdb_adm_…` token is printed to stdout and shown only once. Paste it into the environment's `adminToken` variable. Available roles are `viewer`, `operator`, `admin`. Run `docker compose exec api php bin/console --help` to see the full set of console commands (`db:migrate`, `auth:bootstrap-service-token`, `jobs:run`, `jobs:status`, `scores:rebuild`).
4. Run **Health & Docs → GET /healthz**. You should see `{ "status": "ok", … }`.
5. Run **Admin — Identity → GET /api/v1/admin/me**. You should get back your token's role.

The collection's default auth is `Bearer {{adminToken}}`. Per-folder overrides apply for the public, auth and internal-job endpoints.

## Token kinds at a glance

| Folder                  | Auth used                                   | Variable          |
| ----------------------- | ------------------------------------------- | ----------------- |
| Health & Docs           | none                                        | —                 |
| Public — Reporter       | `Bearer {{reporterToken}}`                  | `reporterToken`   |
| Public — Consumer       | `Bearer {{consumerToken}}`                  | `consumerToken`   |
| Auth API (UI BFF)       | `Bearer {{serviceToken}}`                   | `serviceToken`    |
| Admin — *               | `Bearer {{adminToken}}` (collection-level)  | `adminToken`      |
| Internal Jobs           | `Bearer {{internalJobToken}}`               | `internalJobToken`|

### Service-token impersonation against the Admin API

Admin endpoints also accept a service token plus an `X-Acting-User-Id` header. To use that flow with the collection:

1. Set the `serviceToken` variable to the value of the `UI_SERVICE_TOKEN` env var.
2. Set `actingUserId` to the user id you want to act as (`POST /api/v1/auth/users/upsert-local` returns one).
3. On a request, override **Authorization** to `Bearer {{serviceToken}}` and tick the disabled `X-Acting-User-Id: {{actingUserId}}` header (it is included on every Admin request, just disabled by default).

The audit log will attribute these calls to `actor_kind=user` with `actor_id=<userId>`, exactly as the UI does in production.

## Suggested run order on a fresh database

Tests in the collection capture useful ids back to environment variables, so this sequence works without manual copy/paste:

1. **Admin — Categories → GET /api/v1/admin/categories** (sanity check; defaults are seeded).
2. **Admin — Policies → GET /api/v1/admin/policies** — populates `policyId` (prefers `moderate`).
3. **Admin — Reporters → POST /api/v1/admin/reporters** — populates `reporterId`.
4. **Admin — Consumers → POST /api/v1/admin/consumers** — uses `policyId`, populates `consumerId`.
5. **Admin — Tokens → POST /api/v1/admin/tokens (reporter)** — populates `reporterToken` directly.
6. **Admin — Tokens → POST /api/v1/admin/tokens (consumer)** — populates `consumerToken` directly.
7. **Public — Reporter → POST /api/v1/report** — submits a report with the freshly-minted reporter token.
8. **Internal Jobs → POST /internal/jobs/recompute-scores** (or **Admin — Jobs → trigger/recompute-scores**) to fold the report into `ip_scores`.
9. **Public — Consumer → GET /api/v1/blocklist** — pulls the resulting blocklist.

Run that loop end-to-end and you have exercised the report-and-distribute golden path.

## Raw-token capture

Token creation responses include `raw_token` once and only once. The collection's test scripts mirror it into:

- `lastRawToken` (always)
- `reporterToken` (on `kind=reporter`)
- `consumerToken` (on `kind=consumer`)

If you create an admin-kind token via the UI / collection, copy `lastRawToken` into `adminToken` to swap auth.

## Internal jobs caveat

`/internal/*` endpoints are bound to loopback and RFC1918 by the api's Caddyfile and return `404` from any other source. Run Postman on the same host as the api container (or inside the Docker network), not from a workstation calling a public hostname.
