Newer
Older
gn-synapse / CLAUDE.md

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Что это

Gnexus Synapse — централизованный хаб уведомлений экосистемы Gnexus. Любой сервис шлёт событие «что случилось» в Synapse, Synapse решает, кому, куда и каким каналом доставить: Telegram, Email, Push, внутренний лог, plus system-to-system доставка в Navi и другие сервисы. Цель — убрать из каждого сервиса (bugtrail, gntodo, smart-home, Navi-инстансы, gnexus-auth) собственные реализации уведомлений.

Архитектура (слои)

  • Ingestion Layer — HTTP API приёма событий (тип, payload, приоритет, получатели/топик). Аутентификация источников по API-ключам.
  • Queue — Celery + Redis: приём мгновенно возвращает 202, обработка асинхронная.
  • Routing Engine — по типу уведомления и настройкам маршрутизации решает: какие каналы, кому, какие шаблоны.
  • Provider Adapters — Telegram (бот), Email (SMTP), Push (web-push), Internal Log (БД — деградация и аудит).
  • System-to-System Delivery — доставка в Navi (swarm-инстансы) и другие сервисы через их API/webhook.
  • Persistence — PostgreSQL: пользователи, типы уведомлений, настройки маршрутизации, логи доставки со статусами и ретраями. SQLite допустим только для локальных быстрых тестов, основной путь — Postgres.
  • Web UI / Админ-панель — SPA на Vue 3 (PWA на Gnexus UI Kit), раздаётся как статика из того же контейнера FastAPI (отдельного фронтенд-контейнера нет). Это не только просмотр, но и основной способ конфигурирования Synapse: пользователи, типы уведомлений, маршрутизация, API-ключи, шаблоны — всё управляется из админки. Обзор — события, статусы, логи доставки.

Стек: Python + FastAPI, SQLAlchemy + Alembic, Celery + Redis, PostgreSQL, Docker + docker-compose. Frontend админки — SPA на Vue 3 + Gnexus UI Kit.

Инфраструктурное решение: база берём с собой в докер — Postgres поднимается контейнером из docker-compose, отдельного продового сервера БД нет (на 100%). Тоже касается Redis. Скорость ответа приёма (202) — ключевой контракт Ingestion: тяжёлая работа только в воркерах.

Решения, которые пока не приняты (не выбирать молча)

Открытые вопросы — фиксировать выбранный вариант здесь и в описании задачи gntodo, после решения убрать из списка:

  1. Хост и домен деплоя (synapse.gnexus.space?) — VM на libvirt или существующий VPS.
  2. Telegram-бот — новый или существующий токен.
  3. Единый JSON-контракт событий — черновик в задаче #32.

Интеграция с gnexus-auth (SSO)

gnexus-auth — Laravel (PHP), токены opaque, не JWT: валидация только «call home» через GET /oauth/userinfo с Authorization: Bearer <token> (локальной проверки/JWKS нет; зато отзыв токена и блокировка пользователя видны сразу).

  • Python SDK: gnexus-gauth (репо gnexus-auth-client-py, зависимость только httpx): полный OAuth2 Authorization Code + PKCE, exchange/refresh/revoke, fetch_user() → AuthenticatedUser. Для SPA у gnexus-auth есть свой JS-клиент (packages/auth-client/, доки 18–20).
  • Роли: системные — superadmin > admin > user (глобальные), плюс клиентские (per-сервис slug'и, пока не используем). Доступ к админке = system_role in ("admin", "superadmin") — аналог SystemRole::canAccessAdminArea() на сервере auth.
  • userinfo-ответ: sub, email, system_role, profile, client.roles/permissions (scopes: openid email profile roles permissions). Access-токен живёт ~30 мин, есть refresh-ротация с детекцией переиспользования.
  • OAuth-поток на сервере (app/api/auth_routes.py, клиент gnexus-gauth): GET /auth/login (state+PKCE в Redis, redirect на authorize) → GET /auth/callback (обмен кода, проверка роли до выдачи токена: не-админу access-токен сразу revoke) → SPA получает токены в URL-фрагменте #. Тихое обновление — POST /auth/refresh, логаут — POST /auth/revoke (revoke access-токена).
  • Токены — opaque; каждый запрос API валидируется через userinfo. Креды клиента (GAUTH_CLIENT_ID/SECRET) — только в .env, в UI авторизация никак не конфигурируется.
  • TLS gnexus-auth в LAN self-signed: GAUTH_VERIFY_TLS=false по умолчанию; в проде с нормальным сертификатом — true.
  • Single sign-out (правило владельца): выход из gnexus-auth обязан завершать сессию в Synapse. Прямой logout в gnexus-auth НЕ отзывает OAuth-токены (access до 30 мин, refresh 30 дней переживают logout) — поэтому callback сохраняет выданные токены в Redis по user_id (store_login), а вебхук auth.logout/auth.global_logout/session.revoked отзывает их все. SPA-poll /api/v1/admin/me каждые 45 c: 401 → уход на /login. Выход из Synapse (POST /auth/logout) тоже отзывает входы пользователя; завершение самой SSO-сессии (RP-initiated logout) — TODO в gnexus-auth, зафиксировано в #32.
  • Локальная разработка: gnexus-auth = http://gnexus-auth.local (в контейнерах — extra_hosts: host-gateway в compose), API на localhost:8012.
  • Токен передаётся Authorization: Bearer — cookie не годятся (сессия gnexus-auth не выходит за пределы auth-сервера); SPA-клиент хранит access/refresh сам (docs 18–20 описывают клиентскую сторону).

GNexus UI Kit

Фронтенд-зависимость: npm install git+https://git.gnexus.space/git/root/gnexus-ui-kit.git — не в npm-registry, но dist/ и Vue-адаптер (src/vue/, экспорт gnexus-ui-kit/vue, peer-dep Vue ^3.4) закоммичены в репо кита, установка из git работает. Принцип: минимум своего, максимум из кита.

Правила (полный гайд — node_modules/gnexus-ui-kit/docs/ai-guide.md; в репо кита — docs/ai-guide.md и docs/catalog.json):

  • Перед написанием любого UI-маркапа проверять каталог node_modules/gnexus-ui-kit/docs/catalog.json (need → component → props → useWhen). Если компонент для нужды есть — использовать его (GnButton, GnModal, GnStatusCard, GnMetricCard, GnNavigationShell для каркаса приложения, ...). В vanilla HTML — классы кита, не самодельные аналоги.
  • Иконки — только Phosphor: icon="ph-house" в Vue, <i class="ph ph-house"></i> в HTML.
  • Варианты — только primary, secondary, accent, success, warning, danger, error, info; не выдумывать свои.
  • Цвета — токены кита (SCSS $color-*/$surface-* или CSS custom properties var(--gn-color-secondary), var(--gn-space-4), ...), никогда сырые hex. Отступы — шкала $space-1…$space-12, никакого произвольного пиксельного padding.
  • Фокус — focus_ring на :focus-visible у интерактивных элементов; hover — через hover_touch.
  • Если в каталоге нет нужного компонента — сначала убедиться, что нет, потом делать свой строго по рецепту из docs/ai-guide.md → «Building a custom component in the GNexus style» (hard_panel, uppercase-заголовки, IBM Plex Mono — не переопределять font-family).

Принятые решения

  • FastAPI для API (не Django) — обоснование описать в задаче #32 при проектировании API.
  • Админ-панель — SPA на Vue 3 с Gnexus UI Kit; раздаётся как статика контейнером FastAPI. Всё конфигурирование проекта — через админку, UI первичен для настроек. Минимум своего, максимум из кита.
  • Доступ к админке — роли gnexus-auth (SSO): только admin и выше. Пользователя с ролью ниже — отсекать явной ошибкой (403 «недостаточно прав»), как на уровне API, так и в UI (гейт после логина). Своих паролей Synapse не хранит.

Инфраструктура

  • gnexus-auth (SSO, 192.168.1.167) — единая аутентификация экосистемы.
  • Navi swarm — инстансы: rei, ayame, tsukiko, pilar, melody, zoe, Kael. Доставка system-to-system через их API/webhook.
  • Публичный доступ — через gnexus.space (nginx), внутренняя сеть 192.168.1.0/24.

Рабочие правила

  • Задачи в gntodo (проект id 9): #33 скелет → #34 схема БД → #32 проектирование API → #31 Ingestion → #30 Routing Engine → #29 Provider Adapters → #28 System-to-System → #27 тестирование и деплой. Статусы обновлять в gntodo по ходу работы.
  • Спорные архитектурные решения — фиксировать в описаниях задач, не молча.
  • Документация: документировать всё (README, схема БД, примеры curl). После деплоя — задокументировать сервис в gnexus-book через MCP-инструменты.
  • Секреты — в .env + репозиторий gnexus-creds, никогда не в этом репозитории.

Принципы владельца

Self-hosted, open-source, бюджет-first, без платных SaaS. Простые прямые решения без оверинжиниринга. Веб-интерфейс при необходимости — PWA на Gnexus UI Kit.

Definition of Done (MVP)

API принимает событие → очередь → маршрутизация → доставка минимум в 2 канала (Telegram + внутренний лог) → лог доставки в БД; Navi получает уведомление system-to-system; docker-compose поднимает всё одной командой; README с quickstart.