Для разработчика (или ИИ-агента), подключающего сервис экосистемы (bugtrail, gntodo, smart-home, gnexus-auth, Navi…) к хабу уведомлений. Контракт приёма — docs/05-ingestion-api.md; этот документ — порядок внедрения и паттерны. Клиентские библиотеки: gn-synapse-client-py / gn-synapse-client-php (README последних — полный справочник API).
source,subject,action), цели и правила.Админка — единственный способ конфигурировать Synapse: тип не зарегистрирован → 422 на каждое событие. Подключение сервиса начинается не с кода, а с регистрации: сначала в Synapse, потом код.
^[a-z0-9]([a-z0-9._-]*[a-z0-9])?$, 1..64, латиница строчными) — обычно имя репо/сервиса (bugtrail, gntodo, navi-rei);(subject, action) — что сервис будет сообщать (см. §4), с приоритетом по умолчанию каждой тройки;internal_log, push, telegram, s2s в Navi) и «о ком» — нужен ли payload.user_id.source_create (или §админка → источники) → key_issue → plaintext-ключ в .env сервиса и gnexus-creds, нигде больше; type_register для каждой тройки; rule_create/rule_set.SYNAPSE_URL=https://synapse.gnexus.space # или :8013 в LAN SYNAPSE_API_KEY=syn_... SYNAPSE_DEFAULT_SOURCE=<имя источника>
emit/send. Быстрая проверка после первого отправа — админка → поток (лог доставок), или send_test_event (MCP).Python:
pip install "git+https://git.gnexus.space/git/root/gn-synapse-client-py.git@v0.1.2"
from gnexus_synapse import SynapseClient sync = SynapseClient() # конфиг из SYNAPSE_* async_client = AsyncSynapseClient() # для FastAPI-контекста
PHP (composer, repositories vcs — см. README либы):
$client = new \GNexus\Synapse\SynapseClient(
\GNexus\Synapse\Config\SynapseConfig::fromGlobals(),
new \GuzzleHttp\Client(['timeout' => 10.0]),
new \GuzzleHttp\Psr7\HttpFactory(),
new \GuzzleHttp\Psr7\HttpFactory(),
);
Правило: один клиент-инстанс на процесс (переиспользует http-соединения); при ручном создании — таймаут обязательно (SYNAPSE_TIMEOUT и timeoutSeconds у Guzzle-транспорта), иначе вечный вис при лежащем Synapse.
| Паттерн | Когда | Возврат/падение | |
|---|---|---|---|
emit(source?, subject, action, …) |
событие «потери не страшно», основной путь большинства сервисов | `Event\ | None;SynapseError`/транспорт → warning в лог, не бросаются |
send(...) |
событие, чья потеря = инцидент (уведомление о падении монитора, инцидент безопасности) | бросает типизированные исключения (см. README) — у caller'а есть ретри- или эскалационная политика | |
send_batch([...]) |
прогон «сотни мелких» (импорт, массовая рассылка) | BatchResult.accepted/rejected; локально битые и серверные отклонения — по индексам, 202 и 422 парсятся одинаково |
|
status(event_id) |
отладка/приёмочный тест нового источника; в бизнес-коде обычно не нужен | EventStatus со списком доставок |
|
health() / ready() |
readiness-probe сервиса, старт-самоtest | без ключа |
Конвенции полей:
priority — low|normal|high|critical; critical — только действительно инциденты (обходит throttle правил).user_id= — конвенция «о ком событие» сразу параметром SDK (uuid gnexus-auth, перебивает payload["user_id"]); личный лог и push адресуются по нему.dedup_key — на «повторяющиеся в окне» события (ping-<день>, issue-<id>) чтобы не спамить; best-effort (24ч-окно, повтор вернёт id первого события с deduplicated=true) — не строить бизнес-логику на нём.ttl_seconds — забыть событие старше N сек (актуальность), по умолчанию окно от настроек Synapse.scheduled_at — резерв контракта, сервер пока не обрабатывает.Для приёмки нового источника есть ещё wait_for_status(event_id, statuses=("done","failed")) — поллинг статуса тестового события до терминального или таймаут (§6).
Тройки регистрируются админом один раз каждая — расширение списка это правка реестра, а не кода; берите предсказуемую схему:
task, issue, container, user, auth);created, completed, down, password_changed, login_failed); глаголы в прошедшем времени или существительные — не повелительное.Шаблон события держите в репо сервиса (или в описании сервиса gnexus-book), чтобы при регистрации нового типа не догадываться о смысле payload'а.
emit; критичные — send + try/catch с политикой
(лог + ручной ретри/эскалация — не автомедицина, Synapse сам ретраит доставки по каналам).
dedup_key не в ролях бизнес-идемпотентности.payload.user_id — uuid gnexus-auth (если адресные доставки нужны).`422` на проде = забыли тип — добавить `type_register`, не «обходить» в коде).
«что в payload»).
Быстрая приёмка после первого деплоя интеграции:
examples/plain/smoke.py, php: examples/plain-php/smoke.php (требуют источник libtest и тип; для реального сервиса подставьте своё имя). Дождаться доставки тестового события — wait_for_status(id, statuses=("done", "failed")) (waitForStatus в php), не ручным циклом.source_list → key_issue → type_register → send_test_event (прогон правила без кода сервиса) → deliveries_list.status).Большинство сервисов-приёмников и шлют события (§3) — поэтому приёмная половина живёт в том же SDK, без второй зависимости. Одна точка входа verify_webhook() проверяет подпись (одна схема на всю экосистему — зеркало WebhookSignature.php gnexus-auth и app/signature.py) и распарсивает конверт:
Python:
from gnexus_synapse import verify_webhook
@router.post("/webhooks/synapse")
async def synapse_webhook(request: Request):
env = verify_webhook(await request.body(), request.headers, S2S_SECRET)
# env["event_id"], env["subject"], env["action"], env["payload"], ...
PHP:
use GNexus\Synapse\Webhook\WebhookVerifier; $envelope = WebhookVerifier::verify($r->getContent(), $r->headers->all(), $secret);
Всё, что не прошло (нет подписи, чужой секрет, replay — тело старше 300 с, не-JSON), ловится одним SynapseWebhookError / InvalidWebhookException. Endpoint обязан возвращать 2xx быстро (первая попытка — сразу при маршрутизации; провал → ретраи Synapse 30 с → 2 м → 10 м → 30 м) и быть идемпотентным или не бояться повторов. Секрет per-target — S2S_SECRET_<token_ref> в env приёмника (+ gnexus-creds); в Synapse цель создаётся с token_ref (админка/MCP target_create). Заголовки-контекст: X-Gnexus-Event-Type = <source>.<subject>.<action>, X-Synapse-Source. Полная спецификация подписи — docs/05 → «Доставка s2s».
status() «до delivered» в бизнес-коде — события fire-and-forget; нужен мониторинг — это дежурные метрики Synapse и админка, не поллинг.statusCode = null) — ошибка кода, тесты; 422 сервера — вопрос регистрации, админ.