# Gnexus Synapse

Централизованный хаб уведомлений экосистемы Gnexus: сервисы присылают событие «что случилось», Synapse решает — кому, куда и каким каналом доставить (Telegram, Email, Push, внутренний лог, system-to-system в Navi).

## Стек

- **API**: Python, FastAPI, SQLAlchemy 2 + Alembic
- **Очередь**: Celery + Redis
- **БД**: PostgreSQL (в докере, вместе с приложением)
- **Админка**: SPA на Vue 3 + [Gnexus UI Kit](https://git.gnexus.space/git/root/gnexus-ui-kit), раздаётся статикой из контейнера FastAPI
- **Аутентификация**: gnexus-auth (SSO), доступ к админке — роли `admin` и выше

## Что уже в каркасе

- FastAPI-приложение: `/api/healthz` (liveness), `/api/readyz` (зависимости), `/api/docs` (Swagger)
- Гейт админки по ролям gnexus-auth: `app/auth/deps.py` (`get_current_user` → `require_admin`, 401/403)
- Celery-воркер с каркасной задачей `synapse.ping`
- Alembic-миграции: схема v1 (#34) — `docs/04-database.md`
- Vue 3 SPA: вход (dev-заглушка), дашборд, экран «доступ запрещён» для роли ниже admin
- docker-compose: api + worker + postgres + redis, миграции применяются при старте

## Quickstart

```bash
cp .env.example .env   # заполнить пароль БД, gnexus-auth-креды появятся после регистрации клиента
docker compose up -d --build
curl http://localhost:8000/api/healthz
```

После сборки админка доступна на `http://localhost:8000/` (SPA раздаёт контейнер api).

### Локальная разработка без docker

```bash
# терминал 1 — API (нужны работающие Postgres/Redis, DATABASE_URL хост = localhost)
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload

# терминал 2 — воркер
celery -A app.worker.celery_app worker --loglevel=info

# терминал 3 — SPA dev-сервер (проксирует /api на :8013)
cd frontend && npm install && npm run dev   # http://localhost:5174
```

### Проверка Ingestion (#31)

```bash
# Сидинг конфигурации (в проде — через админку):
docker compose exec api python -m app.cli create-source monitoring
docker compose exec api python -m app.cli add-type monitoring container down
docker compose exec api python -m app.cli add-target telegram infra-alerts --config '{"chat_id":"@infra-alerts"}'
docker compose exec api python -m app.cli add-rule "контейнеры вниз" --source monitoring \
  --subjects container --actions down --priority high \
  --template "Контейнер {{ payload.container }} упал" \
  --action telegram:infra-alerts --action internal_log
docker compose exec api python -m app.cli create-key monitoring   # токен печатается один раз

# Событие (202 мгновенно) и его статус:
curl -X POST http://localhost:8013/api/v1/events \
  -H "Authorization: Bearer syn_..." -H "Content-Type: application/json" \
  -d '{"source":"monitoring","subject":"container","action":"down","priority":"critical","payload":{"container":"api","host":"melody"},"dedup_key":"demo-1"}'
curl http://localhost:8013/api/v1/events/<id> -H "Authorization: Bearer syn_..."

# Коды защиты: 401 — ключа нет/битый, 403 — source не совпадает с ключом,
# 422 — тройка (source, subject, action) не зарегистрирована.
# Пачка: POST /api/v1/events/batch — список конвертов, честные ошибки по индексам.
# Дедуп: тот же dedup_key в окне (DEDUP_WINDOW_SECONDS, дефолт 24ч) → id первого.
```

### Проверка воркера

```bash
docker compose exec api celery -A app.worker.celery_app call synapse.ping   # возвращает task id
```

Ретраи (#30): провал доставки → пауза 30 с → 2 м → 10 м → 30 м, 5 попыток → `failed`; скан due-доставок — beat воркера раз в минуту (`synapse.retry_due`). Шумодав — `--throttle N` у правила (не чаще одной доставки в цель за N с, critical проходит всегда); все подошедшие правила применяются (режим `all`, `ROUTING_MATCH_MODE=first` — только первое). Подробности — docs/05, раздел «Типы и правила».

## MCP: управление ИИ-агентом

Synapse встраивает MCP-сервер (`/mcp`, streamable-http) — ИИ-агент (Claude Code) управляет всем: регистрирует источники и **выдаёт API-ключи клиентам** (plaintext токен показывается один раз), ведёт типы/цели/правила, смотрит поток событий и доставок, меняет настройки. Включается токеном:

```bash
# .env: MCP_TOKEN=$(openssl rand -hex 32) и перезапуск api
claude mcp add --transport http synapse http://localhost:8013/mcp \
  --header "Authorization: Bearer <MCP_TOKEN>"
```

Удаление = архив: DELETE ставит метку (`deleted_at`), `restore` возвращает; архивный источник перестаёт принимать события, цель — «сюда больше не ходим» (доставки skipped с аудитом). Каталог тулов и семантика — docs/07.

## Вход в админку

SSO-поток целиком на сервере (gnexus-auth-client-py, OAuth2 Authorization Code + PKCE):

1. Зарегистрировать OAuth-клиент `synapse` в gnexus-auth, redirect URI — `<публичный URL synapse>/auth/callback`; креды в `.env` (`GAUTH_*`).
2. `GET /auth/login` кладёт state+PKCE в Redis и уводит браузер на форму логина gnexus-auth.
3. `GET /auth/callback` обменивает код, проверяет `system_role`: **админ получает токен** (access+refresh в URL-фрагменте), пользователю ниже admin токен не выдаётся — access-токен сразу revoke, браузер уходит на экран «Доступ запрещён».
4. SPA делает тихое обновление токена через `POST /auth/refresh`, логаут — `POST /auth/revoke`. API продолжает проверять каждый запрос через `GET /oauth/userinfo`.

### Проверка без живого gnexus-auth

```bash
curl -i http://localhost:8013/auth/login   # 302 на authorize endpoint с client_id/code_challenge/state
```

## Структура

```text
app/
  main.py            FastAPI: роуты API + статики SPA
  config.py          настройки из .env
  database.py        SQLAlchemy engine/session
  models/            схема БД (#34): источники, ключи, типы, правила, события, доставки
  auth/              SSO-валидация + гейт ролей admin/superadmin
  api/routes.py      healthz, readyz, admin/me
  signature.py       HMAC подпись/проверка вебхуков (s2s + входящие gnexus-auth)
  worker/            Celery: celery_app, tasks, senders (s2s)
alembic/             миграции (env.py читает DATABASE_URL из .env)
docs/                docs/04 — схема БД, docs/05 — контракт Ingestion API, docs/06 — настройки+PWA, docs/07 — MCP, docs/08 — рантбук развёртывания (для ИИ-агента)
frontend/            Vue 3 SPA админки (сборка кладётся в spa_static/ образа)
docker/entrypoint.sh режимы api (миграции+uvicorn) / worker (celery)
docker-compose.yml   api, worker, postgres, redis
```

## Roadmap (задачи gntodo, проект 9)

#33 скелет → #34 схема БД → #32 контракты API → #31 Ingestion → #30 Routing Engine → #29 Provider Adapters → #28 System-to-System (Navi) → #27 тесты и деплой.