No description
  • Go 98.7%
  • Makefile 1.1%
  • Dockerfile 0.2%
Find a file
2026-03-17 06:37:37 +00:00
.zed fix: http error handling, clickhouse DSN 2026-03-15 23:13:08 +03:00
app feat: add analytics 2026-03-17 02:14:04 +03:00
cmd/prod_back Initial 2026-03-15 12:09:16 +03:00
e2e merge: linting fixes 2026-03-16 16:46:00 +03:00
ent fix: crawler push 2026-03-17 05:35:06 +03:00
internal fix lint 2026-03-17 05:35:06 +03:00
migrations fix: crawler push 2026-03-17 05:35:06 +03:00
schema fix: crawler push 2026-03-17 05:35:06 +03:00
tests Dev 2026-03-17 05:02:16 +00:00
.env.example fix: http error handling, clickhouse DSN 2026-03-15 23:13:08 +03:00
.gitignore add analytics 2026-03-16 21:24:12 +03:00
.gitlab-ci.yml Revert "feat: unlock ci docker build" 2026-03-16 23:44:47 +00:00
dev-compose.yml feat: add migrations with dev compose 2026-03-17 02:14:02 +03:00
Dockerfile Dev 2026-03-17 05:02:16 +00:00
embed.go feat: add openapi docs 2026-03-17 02:10:26 +03:00
go.mod feat: add observability tools 2026-03-17 02:10:26 +03:00
go.sum feat: add observability tools 2026-03-17 02:10:26 +03:00
Makefile Dev 2026-03-17 05:02:16 +00:00
openapi.yaml crawler/push 2026-03-17 02:04:29 +03:00
policy.yml [skip ci] Initial commit 2026-03-13 13:22:17 +00:00
README.md Edit README.md 2026-03-17 06:37:37 +00:00
swagger-analytics.yaml swagger 2026-03-17 00:12:45 +03:00

backend

Бэкенд сервис платформы Sauron — мониторинг упоминаний бренда в интернете. Сервис собирает упоминания из внешних источников через краулер, анализирует тональность (позитив / нейтраль / негатив), отслеживает ключевые слова и стоп-слова, считает аналитические метрики и автоматически поднимает алерты при аномальном росте упоминаний.

В основе лежит библиотека runway — самописная библиотека одного из участников команды.

Быстрый старт

Поднять инфраструктуру (PostgreSQL, ClickHouse, Redis) и применить миграции:

docker compose -f dev-compose.yml up

Скопировать конфиг и при необходимости подправить:

cp .env.example .env

Запустить сервис:

go run ./cmd/prod_back

Сервер стартует на :8080.

Архитектура

Сервис построен на uber/fx (dependency injection) и разбит на независимые модули. HTTP-слой — Echo.

┌─────────────────────────────────────────────────────────────┐
│                        HTTP :8080                           │
│  Echo + JWT middleware + error middleware + Prometheus      │
└────────────────────────┬────────────────────────────────────┘
                         │
          ┌──────────────▼──────────────┐
          │       Business modules      │
          │  auth · organizations       │
          │  projects · integrations    │
          │  keywords · mentions        │
          │  alerts · analytics         │
          │  crawler · alerting worker  │
          └──────┬──────────┬───────────┘
                 │          │
    ┌────────────▼──┐  ┌────▼──────────────┐
    │  PostgreSQL   │  │    ClickHouse      │
    │  (ent ORM)    │  │  (аналитика,       │
    │  основные     │  │   упоминания)      │
    │  сущности     │  └────────────────────┘
    └───────────────┘

Модули

Модуль Ответственность
auth Регистрация, логин, выдача JWT
organizations CRUD организаций
projects CRUD проектов внутри организации
integrations Управление интеграциями и источниками (соцсети, RSS, веб)
keywords Управление ключевыми словами и стоп-словами проекта
mentions Хранение и просмотр упоминаний
crawler API для краулера: список источников + приём упоминаний
analytics Дашборд, тональность, серии алертов, метрики активности
alerts CRUD правил алертов
alerting Фоновый воркер: проверяет правила и создаёт алерты

Основные поля

Organizationid, name, description, image_url, created_at, updated_at, deleted_at

Projectid, organization_id, name, description, image_url

Integrationid (uuid), project_id, type → ссылка на IntegrationType (src: тип источника)

Mentionid (uuid), project_id, integration_id, post_id, brand, sentiment (positive/neutral/negative), keyword, match_level, explanation, created_at

AlertRuleid, project_id, integration_id, threshold (кол-во упоминаний/мин), severity (Info/Warn/Critical/Disaster), created_at, updated_at

Alertid, alert_rule_id, started_at, ended_at (null = активен)

Схема БД управляется через ent — сгенерированный код находится в ent/.

Переходы состояний

Alert (алерт)

[нет алерта]
     │
     │  воркер: count > threshold И нет активного алерта
     ▼
  [ACTIVE]  started_at = now, ended_at = NULL
     │
     │  воркер: count <= threshold И есть активный алерт
     ▼
  [CLOSED]  ended_at = now

Воркер запускается каждую минуту (настраивается через ALERTING_WORKER_INTERVAL). На каждом тике он считает количество упоминаний за последнюю минуту по каждому правилу и открывает или закрывает алерт.

API

Swagger UI доступен по адресу: GET /docs

Спецификация OpenAPI (YAML): GET /openapi.yaml

Группы эндпоинтов

Тег Эндпоинты
auth POST /auth/register, POST /auth/login, GET /auth/me
organizations CRUD /organizations, /organizations/:id/projects
projects CRUD /projects/:id
integrations CRUD /projects/:id/integrations, /integrations/:id/sources, GET /integration-types
mentions GET /projects/:id/mentions, GET /mentions/:id
alerts POST/GET /projects/:id/alert-rules, PATCH/DELETE /alert-rules/:id
analytics GET /projects/:id/analytics/dashboard, /sentiment-distribution, /alerts-series, /negative-mentions-series, /banword-whitelist-ratio
crawler GET /crawler/integrations, POST /crawler/push

Все эндпоинты, кроме /auth/register, /auth/login, /health, /ready, /metrics, /docs, /openapi.yaml, требуют JWT.

Авторизация

JWT HS256. Токен передаётся в заголовке:

Authorization: Bearer <token>

Токен содержит sub (user_id), role, org_id. Middleware проверяет подпись и кладёт claims в контекст запроса. Параметры токена: JWT_SECRET, JWT_TTL (секунды).

Основной сценарий

  1. Пользователь регистрируется (POST /auth/register) и получает JWT.
  2. Создаёт организацию и проект.
  3. Добавляет интеграцию нужного типа (соцсеть / RSS / веб) и привязывает к ней источники (URL, @handle).
  4. Настраивает ключевые слова и стоп-слова для проекта.
  5. Настраивает правила алертов: порог упоминаний и уровень серьёзности.
  6. Краулер периодически запрашивает GET /crawler/integrations — получает список источников для обхода.
  7. Краулер пушит найденные упоминания через POST /crawler/push с тональностью и метаданными.
  8. Воркер алертинга каждую минуту проверяет правила и открывает/закрывает алерты.
  9. Пользователь смотрит дашборд (GET /projects/:id/analytics/dashboard) — видит взвешенный score, тональность, серии алертов и стоп-слов.

Взвешенный score дашборда

sentiment_score  = positive_count * w_positive + negative_count * (-1) * w_negative
activity_index   = alerts_total * w_alerts + banword_total * w_banword + activity_raw * w_activity
weighted_score   = sentiment_score + banword_whitelist_ratio * w_ratio + activity_index

Веса настраиваются на уровне проекта и хранятся в PostgreSQL.

Тестирование

Что покрыто

Уровень Файлы Что проверяется
Unit internal/modules/alerting/service_test.go Логика воркера: открытие алерта при превышении порога, закрытие при нормализации, идемпотентность при уже активном алерте
Unit internal/modules/analytics/service_test.go Расчёт weighted score, корректность формулы при разных весах и данных
Unit internal/modules/analytics/controller_test.go Маппинг запрос → сервис → ответ
Integration app/http/health_test.go, app/http/metrics_test.go HTTP health и metrics эндпоинты
E2E e2e/import_sources_test.go Полный сценарий: создание org → project → integration → source

Запуск тестов

# unit + integration
go test ./...

# e2e (требует запущенного сервиса)
E2E_BASE_URL=http://localhost:8080 go test ./e2e/...

Подход к бизнес-правилам

Бизнес-логика алертинга и аналитики тестируется через фейковые репозитории (fake/stub), без реальной БД. Это позволяет проверять граничные случаи (порог = 0, нет данных, ошибки репозитория) быстро и изолированно. E2E тесты проверяют интеграцию всех слоёв на живом сервисе.

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

Все параметры задаются через переменные окружения (или .env файл). Основные:

Переменная Описание Пример
APP_ENV Окружение (development, staging, production) development
HTTP_PUBLIC_BIND_ADDR Адрес HTTP сервера :8080
POSTGRES_DSN Строка подключения к PostgreSQL postgres://user:pass@localhost:5432/db
CLICKHOUSE_DSN Строка подключения к ClickHouse clickhouse://default:@localhost:9000/default
REDIS_ADDR Адрес Redis localhost:6379
JWT_SECRET Секрет для подписи JWT supersecret
JWT_TTL Время жизни токена в секундах 86400
ALERTING_WORKER_INTERVAL Интервал воркера алертинга 60s
LOG_LEVEL Уровень логов (debug, info, warn, error) info
LOG_JSON JSON-формат логов true

Полный список с описаниями — в .env.example.

Внешние интеграции

Краулер — отдельный сервис, который взаимодействует с бэкендом через два эндпоинта:

  • GET /crawler/integrations — получает список источников (тип + external_id) для обхода
  • POST /crawler/push — пушит найденные упоминания с тональностью, вероятностью и метаданными

Бэкенд при получении упоминания сохраняет его в PostgreSQL (основная запись) и в ClickHouse (для аналитических запросов). Синхронизация между хранилищами происходит лениво при запросе дашборда через MentionIngestor.