# Production diagnostics

Lumi includes an optional, disabled-by-default diagnostics endpoint for investigating problems that only occur on a production installation. It is intended for trusted maintainers who need runtime evidence without being given shell, database, file, or administrative access.

## Security model

- Only an administrator can enable access, replace the key, or revoke it.
- The generated bearer key is shown once. Lumi stores its SHA-256 hash, a short display prefix, and its creation time—not the usable key.
- Remote requests require HTTPS. Requests over plain HTTP are accepted only from loopback. Lumi trusts forwarded HTTPS headers only from a reverse proxy on the same machine.
- Disabled endpoints and invalid keys return `404`, and valid keys are limited to 20 requests per minute.
- The request can select only one fixed, allowlisted check. It cannot provide commands, SQL, paths, URLs, module names, or code.
- Results recursively redact credential-like fields, authorization values, secret query parameters, local paths, and email addresses. Output size and nesting are bounded.
- Successful and failed authorized requests are recorded in Lumi's normal audit logs. The endpoint does not change application or plugin data; the audit record is its only routine write.

This is intentionally visible to Lumi administrators under **Admin → Diagnostics**. It is not a hidden support account or backdoor.

## Enable and connect

1. Open **Admin → Diagnostics**.
2. Choose **Create access key** and complete the timed confirmation.
3. Copy the one-time key to the trusted diagnostic computer. Store it outside the repository or in Lumi's ignored `.secrets` directory.
4. Send a JSON `POST` to `/api/diagnostics/v1/run` using the production HTTPS address:

```sh
curl -X POST "https://your-lumi-host/api/diagnostics/v1/run" \
  -H "Authorization: Bearer $LUMI_DIAGNOSTICS_KEY" \
  -H "Content-Type: application/json" \
  --data '{"check":"update_state"}'
```

For repository maintainers, save the key and address in the ignored `.secrets/production-diagnostics.json` file:

```json
{
  "base_url": "https://your-lumi-host",
  "key": "lumi_diag_replace-with-the-one-time-key"
}
```

The bundled client then runs an allowlisted check and prints its redacted JSON result:

```sh
npm run diagnostics:production -- update_state
```

`LUMI_DIAGNOSTICS_CONFIG` can point to a key file outside the repository. The client also reads an env-style `.secrets` file and accepts the shorter `LUMI_PROD_URL` / `LUMI_DIAG_KEY` names in addition to `LUMI_DIAGNOSTICS_URL` / `LUMI_DIAGNOSTICS_KEY`.

The supported checks are:

- `system_health`: runtime, database, dependency, disk-space, and recovery status.
- `update_state`: the last update status and stage, recovery state, and snapshot summary.
- `plugins`: plugin manifest and registry versions without plugin data.
- `recent_errors`: recent warnings and errors after redaction.
- `benchmark`: a bounded read-only database, plugin scan, and JSON timing workload.

Replace or revoke the key from the same page. Replacement immediately invalidates the previous key.

## Scope and limitations

The endpoint deliberately does not expose arbitrary benchmarks or generic diagnostic commands. New checks must be implemented and reviewed in core before they can run. For incident response, start with `update_state`, `system_health`, and `recent_errors`; their request IDs can be correlated with the audit list on the admin page.
