# Health-эндпоинт сервисов

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

Референсная реализация интерпретации: hard-panel (`panel/backend/app/services_probe.py`).

## 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. Поле `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).
- `checks.{name}.status` — те же значения, что в §2.
- `checks.{name}.ms` — необязательная длительность подчинённой проверки, ms.
- `checks.{name}.detail` — необязательная причина degraded/down, одной строкой.
- `service`, `version`, `timestamp` — необязательные, для журналов.

Мониторы, написанные по §1–2, работают с таким телом без изменений.

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

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

## Ссылки

- Референс-потребитель: hard-panel — https://git.gnexus.space/root/hard-panel
  (спека и раздел «Сервисы» в его README).