| 2026-10-03 |
docs: рантбук под зафиксированные решения деплоя
...
docs/08: §0 — решения владельца (хост = целевая машина агента, домен
synapse.gnexus.space, телеграм отложен до #29); OAuth-клиент выделен в §5
(владелец регистрирует после подъёма, стек живёт и без него); эндпоинт
вебхука поправлен на POST /auth/webhooks. CLAUDE.md: закрытые вопросы
убраны, остался список открытых (#1 телеграм, #2 привязки каналов).
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
3 hours ago
|
docs: клиентские библиотеки gn-synapse-client-{py,php}
...
docs/05 — раздел «Клиентские библиотеки», README — либы в quickstart,
CLAUDE.md — принятые решения: тонкие клиенты, env SYNAPSE_*,
установка через git.gnexus.space по тегу v0.1.0.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
4 hours ago
|

feat: MCP-сервер встроенным FastMCP (/mcp) + архив вместо удаления
...
MCP (docs/07-mcp.md):
- embedded FastMCP streamable-http на /mcp того же контейнера api;
гейт — чистый ASGI McpTokenGuard по Bearer MCP_TOKEN из .env (пусто —
/mcp выключен). Route, не Mount: Mount('/mcp') не матчит точный /mcp.
- 31 тул в app/mcp/tools.py: выдача ключей клиенту (key_issue — plaintext
один раз), полный CRUD источников/типов/целей/правил, поток (events/
deliveries), push-подписки, настройки, send_test_event.
- тула переиспользуют функции admin-routes напрямую (синхронные def без
срабатывания Depends); HTTPException/ValidationError — как данные.
Архив вместо удаления (миграция 0007 b7d3e8f04a92):
- deleted_at на sources/notification_types/channel_targets/routing_rules +
частичные live-индексы; DELETE = 204 → архив, POST .../restore → 200.
- созд поверх архива → 409 с подсказкой id; ключ архивного источника →
401; тройка архивного типа → 422; целевые правки → 422; архивная цель в
правиле — Delivery skipped с аудитом; история имена архива показывает.
- push-подписки — исключение: жёсткое удаление.
- fix list_settings: оверрайды DB-only ключей (push/smtp, без .env-дефолта)
снова возвращаются в value.
Проверено: mcparch ALL OK (41), mcpcheck ALL OK (28, MCP SDK-клиент),
mecheck/retcheck ALL OK, UI-регрессия (SPA, источники+delete 204) ALL OK.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
7 hours ago
|

feat: раздел Настройки (.env-оверрайды UI) и PWA с web-push каналом
...
Настройки: реестр app/settings_registry.py + хранение оверрайдов в
app_settings (settings_store, без кэша). Дефолт из .env, перебивается из
админки без перезапуска. Секреты (VAPID private, тг-токен, SMTP-пароль)
— write-only: записываются через UI, никогда не возвращаются API.
Эндпоинты GET/PUT /api/v1/admin/settings.
Web-push: канал push (целенаправлен как user — адресат из payload.user_id),
таблица push_subscriptions, самопользовательская подписка браузера через
/me/push* (upsert по endpoint, чужой 404). Воркер send_push: pywebpush
(DER base64url ключи), 404/410 — подписка удаляется, ретраи как у s2s.
PWA: manifest + sw.js (pass-through, push/notificationclick), иконки из
gnexus-mark.svg, /settings с личным пуш-блоком и админ-конфигами.
Миграция 0006 (ck_channel ×3 +push, app_settings, push_subscriptions).
Верификация: 47 бэкенд-проверок + mecheck/retcheck + 17 puppeteer — ALL OK.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
9 hours ago
|
docs: фиксация отложенного вопроса привязки user_id к каналам (tg chat_id, push-подписка)
...
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
10 hours ago
|

feat: многопользовательский режим — личный лог по каналу user
...
- Конвенция payload.user_id (sub gnexus-auth): контракт v1 цел, получателей
в конверте нет — дописка в docs/05-ingestion-api.md.
- Канал user в CHANNELS: правило с действием user направляет событие в личный
лог пользователя; без payload.user_id — skipped-delivery с причиной (аудит).
- deliveries.recipient_user_id + ix_deliveries_recipient; миграция 0004
пересоздаёт ck_channel на всех трёх таблицах (deliveries, routing_rule_actions,
channel_targets).
- Routing: _throttled по recipient для user-канала; s2s без цели — прежний
ретрай-цикл.
- Правила: действие user валидно без цели, user + target_id — 422; TargetIn
по-прежнему отвергает user.
- GET /api/v1/me (любой аутентифицированный) и GET /api/v1/me/events (личный
лог строго по своему sub, дедуп по событию).
- OAuth-колбэк: токен выдаётся любому аутентифицированному, роль решает только
раздел; adмин-API остаётся под 403.
- SPA: роль-гейт в router (user -> /my-events, прямой заход в админ-маршруты
редиректит), нав от роли, MyEventsView («Мои события»), getSession-кэш.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
10 hours ago
|
| 2026-10-02 |
docs/05: контракт Ingestion API v1 — принят
...
- инвариант: источник не знает получателей/каналов; routing целиком в правилах
- source — явное поле, ключ — удостоверение; правила матчают имя, не токен
- subject/action отдельными полями; priority — шкала; payload валидируется мягко
- dedup_key/ttl_seconds в v1, scheduled_at — резерв; tags убраны; topics/recipients
в клиентском контракте не существуют
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
Правки каркаса по макету: профиль в дровере, подсветка навигации, ширина 1440
...
- футер дровера: GnUserCard (compact) с аватаром-initials, email и кнопкой
«Выйти» вместо текстовых footerLeft/footerRight
- активный пункт навигации подсвечивается: обход не-реактивного $route в
GnNavList (:key="route.path" на шеле + router.isReady() перед монтированием)
- контентный контейнер — максимум 1440px
- из страницы убраны кнопка «Выйти» и метрика «Вы вошли как»: профиль теперь
в карточке дровера; heartbeat сессии перенесён в App.vue (один на приложение)
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
Single sign-out: logout gnexus-auth отзывает токены Synapse через вебхуки
...
- logout в gnexus-auth НЕ отзывает OAuth-токены (проверено в его коде:
isUsable = только expiry/revoked) — значит SSO-выход доедает вебхук
- store_login: выданные при callback токены лежат в Redis по user_id (TTL 30d)
- webhook auth.logout / auth.global_logout / session.revoked ->
revoke access+refresh всех логинов пользователя на gnexus-auth + очистка
- POST /auth/logout: выход из Synapse отзывает все входы пользователя
- SPA: heartbeat adminMe каждые 45 c — 401 после logout в auth убивает
сессию SPA автоматически; 403 ведёт на denied
- порт 8001 -> 8012 (на локальной машине занят другим проектом)
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
SSO через gnexus-auth-client-py: OAuth-поток на сервере, без ввода токенов в UI
...
- /auth/login: state+PKCE в Redis (переживает рестарты), redirect на authorize
- /auth/callback: обмен кода, проверка system_role до выдачи токена,
не-админу access-токен сразу revoke; токены в URL-фрагменте
- /auth/refresh и /auth/revoke; SPA: кнопка входа, /oauth/callback,
тихий refresh по 401, логаут
- креды только из env (GAUTH_*), GAUTH_VERIFY_TLS для self-signed в LAN
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
Каркас #33: FastAPI + Celery + Postgres в докере, Vue 3 SPA на gnexus-ui-kit
...
- FastAPI: healthz/readyz, Swagger на /api/docs, раздача SPA-статики из того же контейнера
- Гейт админки по ролям gnexus-auth (opaque-токены, userinfo, admin/superadmin, 401/403)
- Celery-воркер (redis broker) с каркасной задачей synapse.ping
- Alembic настроен на DATABASE_URL из .env, миграций пока нет (#34)
- docker-compose: api, worker, postgres, redis — одна команда, миграции при старте
- frontend: Vue 3 + Vite + gnexus-ui-kit (git-зависимость), вход-заглушка dev, дашборд, denied-экран
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|