diff --git a/10-platform/auth.md b/10-platform/auth.md index 7f0d505..03c7c23 100644 --- a/10-platform/auth.md +++ b/10-platform/auth.md @@ -26,6 +26,24 @@ - Личная настройка пользователя (`PATCH /me`) — **только по cookie-сессии**: у Bearer-токенов нет личности (Bearer-админ → 401). - При auth-off (client_id пуст) панель/сервис открыты без логина, личные настройки — в localStorage браузера. +## Вариант Synapse (SPA держит Bearer, без cookie-сессии) +Допустимый вариант каркаса для SPA без серверной cookie-сессии (референс +gnexus-synapse): access/refresh-токены хранит сам SPA (localStorage), +каждый API-запрос — `Authorization: Bearer `, и личность на сервере +устанавливается **call-home в `/oauth/userinfo` на каждый запрос** (токены +opaque; локальной проверки нет). Отличия от cookie-паттерна: +- Никакой локальной записи пользователя и httpOnly-cookie; сессий на сервере нет — + отзыв видит call-home сразу. Личная настройка пользователя (`PATCH /me`) работает + по Bearer: личность у Bearer-токена есть, пока проходит userinfo. +- Per-user override локали хранится в минимальной таблице `user_prefs` (ПК `sub`, + locale + служебные флаги) — не полноценная зеркальная запись, а микрорекомендация. +- `401` из API тот же сигнал гейта: SPA делает один тихий refresh, после + повторного `401` — гейт, poll `/me` держит сессию живой. +- Single sign-out по-прежнему нужен: выданные tokens кэшируются на стороне + сервиса (`store_login` по user_id) и отзываюся вебхуком `auth.logout`/ + `global_logout`/`session.revoked`, т.к. SSO-сервер не отзывает access-токены + по прямому logout. + ## Вебхуки gnexus-auth (обязательно для клиента) Роут `/webhooks/gnexus-auth`, подпись HMAC в заголовках (`t=,v1=`), секрет — `*AUTH_WEBHOOK_SECRET`: - **profile.update** — обновить в локальной зеркальной записи имя, аватарку и профиль (`profile` хранится verbatim JSON). Не должен затирать локальные override-ы пользователя (например override языка). diff --git a/10-platform/mcp.md b/10-platform/mcp.md index b9d73b4..cf06af8 100644 --- a/10-platform/mcp.md +++ b/10-platform/mcp.md @@ -47,4 +47,14 @@ - Референс: gnexus-creds (`gnexus_creds/mcp*.py`, страница Tokens в UI) - hard-panel пока на едином Bearer GHARD_ADMIN_TOKEN — при переходе на мультиюзер: токены по этой конвенции, страница «Токены» в UI (см. - [auth.md](auth.md) про матрицу доступа). \ No newline at end of file + [auth.md](auth.md) про матрицу доступа). +- **Gnexus Synapse** — второй референс с допустимым вариантом: те же принципы + (страница `/mcp-keys` в UI, plaintext один раз, sha256 в `mcp_tokens`, + лимит ≤10 активных, admin-обзор и отзыв чужих), отличия: вместо scopes — + **снейпшот роли владельца** на момент выпуска токена (role `user` видит + только личные тулы, `admin`+ — весь каталог); исторический + маршрут `/mcp` остаётся alias'ом к `/mcp-protocol/`, заблокированный в + gnexus-auth пользователь гасит свои MCP-токены одним флагом из вебхука + `user.blocked` (`user_prefs.blocked`; гард отвечает тем же 401, что и при + неверном токене — не раскрывать статус блокировки), а самопривязка + SSO-логаут MCP-токены не трогает. \ No newline at end of file diff --git a/10-platform/notifications.md b/10-platform/notifications.md index 26bc807..baf2246 100644 --- a/10-platform/notifications.md +++ b/10-platform/notifications.md @@ -1,11 +1,34 @@ # Уведомления: Gnexus Synapse -Исходящие уведомления сервисов (email, Telegram, webhooks) идут через хаб Gnexus Synapse. +Исходящие уведомления сервисов (email, Telegram, web-push, system-to-system +доставка) идут через хаб Gnexus Synapse. Каждый сервис, который шлёт уведомления, +интегрируется с Synapse и не держит собственных каналов доставки. Как Synapse +доставляет и кому — решает маршрутизация Synapse, не отправитель. ## Правила -- Сервис регистрируется в Synapse как источник и шлёт события в хаб. -- Каналы доставки (email, Telegram) настраиваются в Synapse, а не в каждом сервисе. -- Секреты интеграции — в `.env` и gnexus-creds. +- Каналы доставки (email, Telegram, push) и их секреты живут в Synapse, а не в каждом сервисе. Секреты интеграции — в `.env` и gnexus-creds. +- Что шлёт сервис — это его знание («что случилось у меня»): конверт события. Кому и куда доставить — решают правила маршрутизации в Synapse. В конверте **нет получателей, каналов и топиков**. +- Свой очередь/механизм ретраев для уведомлений не строить — это забота Synapse. + +## Интеграция отправителя + +1. **Регистрация источника**: админка Synapse → Источники → создать (или MCP-инструментом). На выходе — API-ключ `syn_*`, показывается ровно один раз: в `.env` сервиса и в gnexus-creds. Ключ — только удостоверение источника; имя `source` в конверте должно совпадать с источником ключа (анти-спуфинг). +2. **Отправка**: `POST https://synapse.gnexus.space/api/v1/events`, заголовок `Authorization: Bearer syn_*`. Приём мгновенно возвращает `202` — обработка асинхронная. Статус доставки — `GET /api/v1/events/{id}`. +3. **Конверт v1**: поля `source`, `subject`, `action`, `priority` (`low|normal|high|critical`), `payload` (объект), `dedup_key`, `ttl_seconds`, `scheduled_at`. Полный контракт — `docs/05-ingestion-api.md` в репо Synapse. +4. **Адресное уведомление пользователю** — конвенция `payload.user_id` = `sub` gnexus-auth (это часть payload-конвенции, не получатель). +5. **Client-libs**: тонкие клиенты без очередей — `gn-synapse-client-py` (PyPI `gnexus-synapse`), `gn-synapse-client-php` (Composer `gnexus/synapse-client`), установка по тегу `v0.1.0`. Конфиг только env: + + | env | что | + |---|---| + | `SYNAPSE_URL` | базовый URL хаба | + | `SYNAPSE_API_KEY` | ключ `syn_*` источника | + | `SYNAPSE_TIMEOUT` | таймаут HTTP, сек | + | `SYNAPSE_DEFAULT_SOURCE` | умолчание `source` (смягчает 403 анти-спуфинга) | + +## Интеграция получателя (system-to-system) + +Сервис, который *хочет получать* события (Navi-инстансы и др.), отдаёт webhook-эндпоинт, и он регистрируется в Synapse как **цель** (Target). Дальше Synapse сам шлёт deliveries с ретраями; статусы видны в логе доставок админки. ## Ссылки -- Факты: gnexus-book → `10-systems/services/gnexus-synapse.md` +- Репозиторий: https://git.gnexus.space/root/gnexus-synapse (контракт v1 — `docs/05-ingestion-api.md`) +- Факты: gnexus-book → `10-systems/services/gnexus-synapse.md` \ No newline at end of file diff --git a/90-templates/new-service-checklist.md b/90-templates/new-service-checklist.md index f2c88c5..f4706bd 100644 --- a/90-templates/new-service-checklist.md +++ b/90-templates/new-service-checklist.md @@ -4,7 +4,7 @@ - [ ] SSO: OAuth-клиент в gnexus-auth (если есть пользователи) - [ ] UI: подключён gnexus-ui-kit (если есть веб-интерфейс) - [ ] Секреты: `.env` (chmod 600) + gnexus-creds, `.gitignore` -- [ ] Уведомления: интеграция с Synapse (если сервис шлёт уведомления) +- [ ] Уведомления: интеграция с Synapse — источник с ключом `syn_*` и/или webhook-цель ([notifications.md](../10-platform/notifications.md)) - [ ] Хост: выбран по [hosting.md](../20-deployment/hosting.md), systemd-юнит, автостарт - [ ] Домен: поддомен `*.gnexus.space` + nginx vhost (если публичный) - [ ] Бэкап: что / куда / как часто / восстановление diff --git a/README.md b/README.md index 1cc22fc..dcfe052 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ - [mcp.md](10-platform/mcp.md) — MCP и API-токены для ИИ-агентов - [ui.md](10-platform/ui.md) — UI и визуальный стиль - [health.md](10-platform/health.md) — health-эндпоинт сервисов - - [notifications.md](10-platform/notifications.md) — уведомления через Gnexus Synapse + - [notifications.md](10-platform/notifications.md) — уведомления через Gnexus Synapse: конвенция интеграции (источник с `syn_*`, конверт v1, webhook-цель) - [secrets.md](10-platform/secrets.md) — секреты - [git.md](10-platform/git.md) — Git и GitBucket - `20-deployment/` — справка о размещении, доменах и бэкапах (информация, не предписания)