Новая документация-as-code на платформе Diplodoc (Yandex open-source) с YFM (Yandex Flavored Markdown). Build → static HTML, deployable куда угодно. Что добавлено: - package.json + .yfm + toc.yaml — Diplodoc setup, навигация для sidebar - index.md — главная страница с tabs для разных audiences - README.md — инструкция для contributors Раздел integration/api/ — 11 страниц про интеграцию consumers: - index — обзор + глоссарий - auth — Keycloak service accounts, scope mapping - read-endpoints — GET /dictionaries, list/by-key, spatial filters - events — Kafka outbox топики, partition keys, idempotency, DLQ - webhooks — HMAC, SSRF guard, retry policy, test ping endpoint - bitemporal — validFrom/validTo + history, future-dated entries, bulk close/export - x-references — FK syntax, validation errors, scope hiding, orphan scanner, v2 cascade preview - caching — TTL / push / snapshot strategies, hybrid pattern - errors — full error code reference (validation/auth/conflict/server), retry strategy - best-practices — 33 numbered rules для consumers - bundle-cuod — все 40 справочников с FK графом и сценариями Обновлены: - ops/README.md — link на новую integration/api/, убран inline <br> - ops/slo.md — broken cross-repo links заменены на text references Build: cd docs && pnpm install && pnpm build → ./_dist (20 HTML files, 7.1M) pnpm serve # → http://localhost:8088 CI deploy job для GitLab Pages — в roadmap (см. docs/README.md). Существующий tech/api-integration.md оставлен в toc как legacy (содержимое мигрировано + расширено в integration/api/).
6.9 KiB
Webhooks
Альтернатива Kafka events для consumer'ов которые не хотят / не могут поддерживать Kafka client. Ordinis отправляет HTTP POST на зарегистрированный URL при изменениях справочников.
{% note info %}
Если у тебя есть Kafka access — используй события. Webhooks проще в развёртывании, но менее надёжны (HTTP retry vs Kafka durable log) и медленнее (HTTP overhead vs Kafka batch).
{% endnote %}
Регистрация подписки
curl -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
https://ordinis.k8s.264.nstart.cloud/api/v1/admin/webhooks/subscriptions \
-d '{
"name": "altum-cache-invalidation",
"url": "https://altum-backend.altum.local/webhooks/ordinis",
"secret": "<HMAC_SECRET_GENERATED_BY_YOU>",
"scopes": ["PUBLIC", "INTERNAL"],
"dictionaries": ["spacecraft", "satellite_type", "instrument"],
"actions": ["created", "updated", "closed"],
"active": true
}'
Поля
| Поле | Тип | Назначение |
|---|---|---|
name |
string | Человекочитаемое имя для admin UI. |
url |
string | HTTPS endpoint. HTTP блокируется SSRF guard'ом. |
secret |
string | HMAC-SHA256 секрет для подписи payload (см. ниже). |
scopes |
array | Фильтр по scope (subset из доступных consumer'у). |
dictionaries |
array | Фильтр по dictionary names. null/[] = все доступные. |
actions |
array | created / updated / closed. null = все. |
active |
bool | Можно временно отключить без удаления. |
SSRF guard
Webhook URLs валидируются перед отправкой:
- Запрещено: private CIDR (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), localhost, link-local (169.254/16), metadata IPs.
- Запрещено: non-HTTPS scheme. Только
https://. - Запрещено: URL > 2048 chars.
Метрика nsi_webhook_ssrf_rejected_total increments при попытках. См.
prometheus rule OrdinisWebhookSsrfRejected.
Payload
POST на зарегистрированный URL с body:
{
"deliveryId": "wd-abc123-xyz789",
"subscriptionName": "altum-cache-invalidation",
"occurredAt": "2026-05-07T15:23:45.123+03:00",
"events": [
{
"schemaVersion": "1.0.0",
"eventType": "dictionary.changed",
"dictionary": "spacecraft",
"businessKey": "RESURS-P-3",
"action": "updated",
"version": 3,
"validFrom": "2026-05-07T00:00:00+03:00",
"data": { ... }
}
]
}
{% note tip %}
Payload может содержать несколько events (events array) если они
произошли в одной transaction (bulk close, bundle import). Не предполагай
single-event payload.
{% endnote %}
HMAC подпись
Каждый POST имеет header:
X-Ordinis-Signature: sha256=<HEX>
X-Ordinis-Delivery: wd-abc123-xyz789
X-Ordinis-Subscription: altum-cache-invalidation
Где <HEX> = HMAC-SHA256 от raw body bytes с secret который ты задал
при регистрации.
Verify (Python)
import hmac, hashlib
def verify(body: bytes, signature_header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature_header)
Verify (Node.js)
import crypto from 'crypto'
function verify(body, signatureHeader, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
)
}
{% note warning %}
Verify подпись до парсинга JSON. Если invalid — 403 Forbidden,
не трогай payload. Без verify ты уязвим к подделке events от любого, кто
знает твой URL.
{% endnote %}
Response contract
Consumer должен ответить 2xx в течение 10 секунд:
| Status | Семантика |
|---|---|
200 / 201 / 202 / 204 |
Принято. Ordinis помечает delivered. |
4xx |
Permanent failure (твой bug). Ordinis НЕ retry. |
5xx / timeout |
Transient. Ordinis retry с exponential backoff. |
Retry policy
| Попытка | Интервал |
|---|---|
| 1 | сразу |
| 2 | через 30s |
| 3 | через 2 мин |
| 4 | через 10 мин |
| 5 | через 1ч |
| 6-10 | каждые 6ч |
| 1000+ | DLQ → ручной разбор |
После 1000 неудач delivery попадает в DLQ (/api/v1/admin/webhooks/deliveries/dlq).
Alert: OrdinisWebhookDLQNonEmpty.
Test ping
Endpoint для проверки доступности URL до регистрации:
curl -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
https://ordinis.k8s.264.nstart.cloud/api/v1/admin/webhooks/test-ping \
-d '{
"url": "https://altum-backend.altum.local/webhooks/ordinis",
"secret": "<TEST_SECRET>"
}'
Response:
{
"success": true,
"statusCode": 200,
"responseBody": "OK",
"elapsedMs": 142
}
Либо details про failure (DNS issue, timeout, SSRF reject и т.д.).
Best practices
- Idempotency — webhook может прийти дважды (network retry, partial
failure). Используй
deliveryIdкак dedup key. - Async обработка — отвечай
202 Acceptedсразу, обрабатывай в background. 10s timeout жёсткий — если БД медленная, лучше принять и сложить в очередь. - HMAC verify первым — до парсинга JSON.
- Metrics — track received / processed / errors для своего side. Сравнивай с Ordinis metrics при расследовании.
- Whitelist Ordinis IP на firewall если строгие правила. IP cluster.142
=
192.168.100.142, но в production будет ingress IP. Спросить у Ordinis team при registration.
Alerting (Ordinis side)
| Alert | Trigger |
|---|---|
OrdinisWebhookHighFailureRate |
failure rate > 50% за 5 мин |
OrdinisWebhookDLQNonEmpty |
events в DLQ > 0 |
OrdinisWebhookDispatcherIdle |
0 deliveries при > 0 active subscriptions |
OrdinisWebhookSsrfRejected |
SSRF guard сработал > 0 раз за 15 мин |
Дальше
- События (Kafka) — primary delivery channel
- Caching — webhook invalidation pattern