- Go 98.7%
- Makefile 1.1%
- Dockerfile 0.2%
| .zed | ||
| app | ||
| cmd/prod_back | ||
| e2e | ||
| ent | ||
| internal | ||
| migrations | ||
| schema | ||
| tests | ||
| .env.example | ||
| .gitignore | ||
| .gitlab-ci.yml | ||
| dev-compose.yml | ||
| Dockerfile | ||
| embed.go | ||
| go.mod | ||
| go.sum | ||
| Makefile | ||
| openapi.yaml | ||
| policy.yml | ||
| README.md | ||
| swagger-analytics.yaml | ||
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 |
Фоновый воркер: проверяет правила и создаёт алерты |
Основные поля
Organization — id, name, description, image_url, created_at, updated_at, deleted_at
Project — id, organization_id, name, description, image_url
Integration — id (uuid), project_id, type → ссылка на IntegrationType (src: тип источника)
Mention — id (uuid), project_id, integration_id, post_id, brand, sentiment (positive/neutral/negative), keyword, match_level, explanation, created_at
AlertRule — id, project_id, integration_id, threshold (кол-во упоминаний/мин), severity (Info/Warn/Critical/Disaster), created_at, updated_at
Alert — id, 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 (секунды).
Основной сценарий
- Пользователь регистрируется (
POST /auth/register) и получает JWT. - Создаёт организацию и проект.
- Добавляет интеграцию нужного типа (соцсеть / RSS / веб) и привязывает к ней источники (URL, @handle).
- Настраивает ключевые слова и стоп-слова для проекта.
- Настраивает правила алертов: порог упоминаний и уровень серьёзности.
- Краулер периодически запрашивает
GET /crawler/integrations— получает список источников для обхода. - Краулер пушит найденные упоминания через
POST /crawler/pushс тональностью и метаданными. - Воркер алертинга каждую минуту проверяет правила и открывает/закрывает алерты.
- Пользователь смотрит дашборд (
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.