Newer
Older
gn-synapse / docs / 04-database.md

04 — Схема БД (#34), v1

Реализация — app/models/ + миграция alembic/versions/20261003_0001_initial_schema.py (7 таблиц). Постгрес в докере (postgres:17-alpine, том pgdata), Redis 7 (том redisdata).

Два контура данных: конфигурация (человек заводит через админку, меняется редко) и поток событий (пишется автоматически, растёт всегда).

Конфигурация

sources ──< api_keys
   │
   └──< notification_types          (уникальность: source_id + subject + action)
   │
routing_rules ──< routing_rule_actions ──> channel_targets
Таблица Что хранит Ключевые поля
sources Источники событий (регистрирует админ) name (slug, unique: monitoring), label
api_keys Ключи syn_… к источникам token_hash (sha256, unique), token_hint (последние 4 для UI), revoked_at (ротация: новый ключ, старая строка маркируется). Ключ — удостоверение; правила матчают source, не токен
notification_types Реестр типов из контракта тройка (source_id, subject, action) уникальна, payload_schema JSONB (опц., валидирует воркер)
channel_targets Цели каналов: куда доставлять channel ∈ telegram/email/s2s/internal_log (CHECK), config JSONB (chat_id, адрес, s2s-endpoint). Креды каналов (токен бота, SMTP) — не здесь, а в .env
routing_rules Правила «условия → действия» conditions JSONB (source, subjects[], actions[], priority_min), template (Jinja2 {{ payload.x }}), weight (порядок; в MVP применяется первое подошедшее), enabled
routing_rule_actions Действия правила rule_id, channel (CHECK), target_id → channel_targets (SET NULL при удалении цели), template — переопределение шаблона правила

Поток событий

events 1 ──< deliveries
Таблица Что хранит Ключевые поля
events Конверт события (контракт docs/05) UUID pk, source_id (RESTRICT — события переживают удаление источника), subject/action/priority (CHECK по шкале), payload JSONB, dedup_key (+индекс с created_at — окно дедупликации), expires_at (= created+ttl_seconds), scheduled_at (резерв), status ∈ queued/processing/done/failed
deliveries Доставка в конкретную цель event_id (CASCADE), rule_id (SET NULL — правило удалим, историю оставим), channel, channel_target_id, status ∈ pending/delivered/failed, attempts, last_error, next_retry_at (+индекс status,next_retry_at — скан ретраев), rendered_message (аудит: что реально ушло в канал)

Что сознательно НЕ в таблицах

  • Пользователи — их делает gnexus-auth; Synapse пользователей не хранит.
  • Секреты каналов — .env/gnexus-creds, не БД (TELEGRAM_BOT_TOKEN, SMTP и т.д.).
  • tags события — убраны из v1 контракта (см. docs/05); вернутся, когда появится правило, требующее их.
  • История попыток отдельно от delivery — одна запись с attempts/next_retry_at; поэлементный лог попыток не нужен MVP.

Проверено

  • alembic upgrade head поднимает всё из пустой базы (docker: api применяет миграции на старте).
  • ORM roundtrip: Source → ApiKey → NotificationType → ChannelTarget → RoutingRule(+Action) → Event → Delivery — вставляется и читается; демо-данные удалены, схема оставлена пустой.