# Спека: health-эндпоинт gnexus-сервисов

Контракт, по которому hard-panel (и любой другой монитор gnexus) опрашивает
`/health` сервисов и интерпретирует отклик. Эндпоинты уже есть у всех сервисов,
но формата нет — эта спека фиксирует **минимальный** контракт, работающий «из
коробки» для любого уже существующего эндпоинта, и **рекомендуемое расширение**,
к которому можно двигаться постепенно.

## 1. Минимальный контракт

Монитор опрашивает эндпоинт методом **GET**. Достаточно:

| Отклик | Интерпретация монитором |
|---|---|
| HTTP 2xx | сервис **в порядке (up)** |
| HTTP 2xx с телом-JSON, где `status` — из набора ok (см. §2) | **в порядке (up)** |
| HTTP 2xx с телом-JSON, где `status` — из набора degraded (см. §2) | **деградация (degraded)** |
| HTTP 2xx с телом-JSON, где `status` — любая другая строка | **вниз (down)** |
| HTTP 3xx–5xx | **вниз (down)** |
| таймаут, DNS, отказ соединения | **вниз (down)**, причина — текст ошибки |

Тело **может вообще отсутствовать или быть любым** (текст, HTML, JSON без
поля `status`) — чистый 2xx в порядке. Монитор никогда не угадывает глубже:
неизвестный формат не превращается во «вниз» (кроме незнакомой строки `status`,
см. §2 — раз сервис явно ответил статусом, монитору его не угадать).

## 2. Поле `status`

Если тело — JSON-объект со строковым полем `status`, монитор опирается на него.
Значение сравнивается без учёта регистра.

| Значение `status` | Монитор показывает |
|---|---|
| `ok`, `healthy`, `pass`, `passing`, `up` | в порядке |
| `degraded`, `warn`, `warning`, `partial`, `busy` | деградация |
| `down`, `error`, `fail`, `critical`, незнакомая строка | вниз |

Незнакомая строка трактуется консервативно (**вниз**): сервис взялся ответить
статусом — монитор не может считать его здоровым. Если нужно только «в порядке /
не в порядке», используйте просто `ok`; остальное оставьте по минимуму.

## 3. Рекомендуемое расширение

То, к чему стоит прийти gnexus-сервисам со временем — одинаковая, машина-читаемая
детализация:

```json
{
  "status": "ok",
  "service": "gnexus-creds",
  "version": "1.4.2",
  "checks": {
    "db":    { "status": "ok", "ms": 3 },
    "redis": { "status": "degraded", "detail": "replica lag 15s" }
  },
  "timestamp": "2026-10-04T12:00:00Z"
}
```

- `status` — агрегат по всем подчинённым: **худший** из `checks.*.status`
  (порядок тяжести: down > degraded > ok → down).
- `checks.{name}.status` — те же значения, что в §2 (`ok`/`degraded`/`down`).
- `checks.{name}.ms` — необязательная длительность подчинённой проверки, ms.
- `checks.{name}.detail` — необязательная причина degraded/down (одной строкой).
- `service`, `version`, `timestamp` — необязательные, для журналов и
  самодиагностики.

Мониторы, написанные по §1–2, продолжают работать с таким телом без изменений:
агрегатный `status` уже говорит всё.

## 4. Требования к эндпоинту

- **Без авторизации.** `/health` не раскрывает данные; auth на нём превращает
  мониторинг в «всегда вниз».
- **Дёшево.** Монитор опрашивается каждые ~30 с постоянно. Никаких тяжёлых
  запросов на пинг: проверяйте только доступность (ping БД — `SELECT 1`,
  не миграции). Кэшируйте результат, если проверка дороже ~100 ms, максимум
  на 10 с.
- **Быстро.** Отвечайте за **< 500 ms**; таймаут монитора — 5 s.
- **Идемпотентно, без побочных эффектов.** Никаких счётчиков метрик, писем,
  записей в БД.
- **Не логируйте каждый пинг.** Сотни записей в минуту — шум, заслоняющий
  настоящие ошибки.
- **Ставить в /health или /healthz — на выбор сервиса**; монитор берёт
  полный URL из настроек, редиректы следуются.

## 5. Примеры

```bash
# минимум — текстовый 200
$ curl -i http://gnexus-creds.local/health
HTTP/1.1 200 OK
OK

# со статусом деградации (монитор покажет «деградация», HTTP 200)
$ curl -i http://gnexus-auth.local/health
HTTP/1.1 200 OK
{"status": "degraded"}

# рекомендуемое расширение
$ curl http://gnsynapse.local/health
{"status": "ok", "service": "gnsynapse", "version": "0.8.0",
 "checks": {"db": {"status": "ok", "ms": 2}, "queue": {"status": "ok", "ms": 1}}}
```

Смена ответа монитору — не breaking change: добавление полей в тело безопасно,
монитор игнорирует неизвестное; удаление `status` (возвращаясь к минимуму)
— тоже.

## Changelog

- 2026-10-04 — первая версия: минимум (2xx + строка `status`), рекомендуемое
  расширение `checks`, требования к эндпоинту.