Central-University-IT-prod/2026-final-individual-vadim.khristenko

0

stars

0

commits

Rust

primary language

Mar 26, 2026

updated

README

LOTTY A/B Platform

A/B-платформа для продуктовых экспериментов. Позволяет запускать эксперименты на feature flags, отслеживать метрики, автоматически останавливать деградирующие варианты и принимать решения на данных.

Автор: Вадим Христенко

Проект создан с любовью и небольшим юмором (Спасибо Астольфо за вдохновение и стиль!). ШаховПобеда и БалюкПобеда, молодцы - всё заработает, всё будет хорошо, на защиту приду уверенно. Код скомпилирован, тесты пройдены (72 E2E check ✓), Telegram работает, learnings протестирован. Ничего не сломалось (вроде).

Стек

КомпонентТехнологияЗачем
ЯзыкRust (edition 2024)Скорость, безопасность памяти, zero-cost abstractions
HTTPAxum 0.8Async-роутер с extractors, совместим с Tower
БДPostgreSQL 18Основное хранилище: флаги, эксперименты, события, решения
КэшValkey 9 (Redis-совместимый)Кэш флагов/экспериментов, дедупликация, rate limiting
SQLSQLx 0.8Async-драйвер, compile-time проверка запросов
ХешированиеxxHash3 (xxh3_64)Детерминированный бакетинг и выбор вариантов
ПаролиArgon2Безопасное хеширование
ТокеныjsonwebtokenJWT-аутентификация
OpenAPIutoipa 5.4Генерация OpenAPI 3.1 спецификации из derive-макросов
Swagger UIrust-embed 8.11Встраивание Swagger UI в бинарник (Astolfo Edition)
КонтейнерыDocker + Compose V2Один docker compose up -d поднимает всё

Как это работает

Платформа решает три задачи:

  1. Выдача решений (POST /decide). Продукт спрашивает: «что показать пользователю user-42 для флага button_color?». Платформа проверяет эксперименты, применяет таргетинг DSL, детерминированно выбирает вариант через xxHash3 и возвращает значение + decision_id.

  2. Сбор событий (POST /events, POST /events/batch). Продукт сообщает: «user-42 кликнул кнопку». События привязываются к decision_id, проходят валидацию по каталогу типов, дедупликацию и атрибуцию.

  3. Автоматическая реакция. Фоновый guardrail-чекер каждые N секунд пересчитывает метрики из каталога. Если порог превышен, эксперимент ставится на паузу или откатывается к контролю.

Ключевые идеи

Детерминизм через хеширование. Один и тот же пользователь всегда попадает в один вариант. Для бакетинга используется xxh3_64(user_id:experiment_id), для выбора варианта xxh3_64(user_id:experiment_id:variant). Никакого дополнительного хранилища для sticky-сессий не нужно.

Каталоги, а не хардкод. Типы событий и метрики задаются в каталогах через API. Guardrail-ы привязываются к метрикам из каталога. Новые типы событий и метрики добавляются без правки кода.

Fire-and-forget на hot path. Запись решений и участия в /decide выполняется через tokio::spawn без ожидания. Счётчик участия кэшируется в Valkey с TTL 60с. Цель: минимальная латенция на 100k RPS.

DSL-таргетинг. Собственный лексер и парсер: age >= 18 AND country IN ("RU", "KZ"). Поддерживает AND/OR/NOT, сравнения, множества IN/NOT IN, вложенные скобки. Если атрибут отсутствует, условие считается false.

Уведомления (C7). Telegram, Discord, Slack. Каждая команда заводит свой канал с bot_token. Правила уведомлений настраиваются через API: какие события куда слать.

Learnings Library (C9). После завершения эксперимента сохраняется structured learning: гипотеза, результат, impact, теги. Поиск по похожим экспериментам через tags, flag_key, free-text.

Insights (C8). Аналитика качества данных: доля отклонённых событий, traffic skew, полнота атрибуции, сводка платформы.

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

docker compose up -d
# Ждём готовности (~30 секунд)
curl http://localhost:80/ready

Подробная инструкция: docs/RUNBOOK.md

Swagger UI / OpenAPI

После запуска доступна интерактивная документация:

Документация генерируется автоматически из кода через utoipa 5.4. Все 62 API-эндпоинта аннотированы с описаниями на русском. Swagger UI встроен прямо в бинарник через rust-embed - никаких внешних файлов или CDN.

Примечание: НЕ используется utoipa-swagger-ui - этот крейт загружает ассеты по сети при сборке, что ломает Docker Buildx в сетевой изоляции. Вместо него Swagger UI dist-файлы лежат в swagger-ui/ и компилируются в бинарник.

API

Публичные (без токена)

МетодПутьНазначение
GET/healthЗдоровье сервиса
GET/readyГотовность к работе
POST/decideПолучить решение по флагам
POST/eventsОтправить событие
POST/events/batchОтправить пачку событий

Аутентификация (rate limited)

МетодПутьНазначение
POST/auth/registerРегистрация
POST/auth/loginПолучить JWT-токен

Защищённые (Bearer token)

МетодПутьНазначение
GET/POST/flagsСписок / создание флагов
GET/PUT/DELETE/flags/{key}Чтение / обновление / удаление флага
GET/POST/experimentsСписок / создание экспериментов
GET/PUT/experiments/{id}Чтение / обновление (только draft)
POST/experiments/{id}/transitionСмена статуса
POST/experiments/{id}/completeЗавершение с выводом
POST/experiments/{id}/archiveАрхивирование
GET/experiments/{id}/versionsИстория версий
GET/experiments/{id}/guardrail-triggersСрабатывания guardrail
GET/POST/experiments/{id}/reviewРевью
GET/experiments/{id}/reportОтчёт по вариантам
GET/experiments/{id}/learningsLearnings этого эксперимента
GET/POST/event-typesКаталог типов событий
PUT/event-types/{name}Обновление типа
GET/POST/metricsКаталог метрик
PUT/metrics/{name}Обновление метрики
GET/auditАудит-лог
POST/dsl/validateПроверка DSL-правила
GET/PUT/DELETE/users/{id}/approver-groupГруппы аппруверов
GET/POST/notifications/channelsКаналы уведомлений
PUT/DELETE/notifications/channels/{id}Управление каналом
GET/POST/notifications/rulesПравила уведомлений
DELETE/notifications/rules/{id}Удаление правила
GET/notifications/logЛог отправок
GET/POST/learningsБиблиотека выводов
GET/PUT/DELETE/learnings/{id}Конкретный learning
GET/insights/event-qualityКачество данных
GET/insights/traffic-skew/{id}Перекос трафика
GET/insights/attributionЗдоровье атрибуции
GET/insights/summaryСводка платформы

Роли

РольСоздаёт экспериментыРевьюитЧитаетАдминистрирует
Admin++++
Experimenter++
Approver++
Viewer+

Жизненный цикл эксперимента

draft -> review -> approved -> launched -> paused -> completed -> archived

На любом шаге возможен reject (возврат в draft для доработки). Guardrail может автоматически поставить на паузу или откатить к контролю.

Тесты

cargo test

81 тест (61 unit + 20 inline). Интеграционные: bash scripts/integration_tests.sh.

Документация

ФайлСодержание
docs/ARCHITECTURE.mdC4-диаграммы, компоненты, критический путь, OpenAPI
docs/RUNBOOK.mdПошаговый запуск и happy path
docs/COMPLIANCE.mdМатрица соответствия критериям
docs/TEST_REPORT.mdОтчёт о тестировании
docs/DEMO_SCENARIOS.mdСценарии демонстрации
/docs/Swagger UI - интерактивная документация API (Astolfo Edition)
/api-docs/openapi.jsonOpenAPI 3.1 спецификация (62 paths, 75 schemas)

Central-University-IT-prod/2026-final-individual-vadim.khristenko

0

stars

0

commits

Rust

primary language

Mar 26, 2026

updated

README

LOTTY A/B Platform

A/B-платформа для продуктовых экспериментов. Позволяет запускать эксперименты на feature flags, отслеживать метрики, автоматически останавливать деградирующие варианты и принимать решения на данных.

Автор: Вадим Христенко

Проект создан с любовью и небольшим юмором (Спасибо Астольфо за вдохновение и стиль!). ШаховПобеда и БалюкПобеда, молодцы - всё заработает, всё будет хорошо, на защиту приду уверенно. Код скомпилирован, тесты пройдены (72 E2E check ✓), Telegram работает, learnings протестирован. Ничего не сломалось (вроде).

Стек

КомпонентТехнологияЗачем
ЯзыкRust (edition 2024)Скорость, безопасность памяти, zero-cost abstractions
HTTPAxum 0.8Async-роутер с extractors, совместим с Tower
БДPostgreSQL 18Основное хранилище: флаги, эксперименты, события, решения
КэшValkey 9 (Redis-совместимый)Кэш флагов/экспериментов, дедупликация, rate limiting
SQLSQLx 0.8Async-драйвер, compile-time проверка запросов
ХешированиеxxHash3 (xxh3_64)Детерминированный бакетинг и выбор вариантов
ПаролиArgon2Безопасное хеширование
ТокеныjsonwebtokenJWT-аутентификация
OpenAPIutoipa 5.4Генерация OpenAPI 3.1 спецификации из derive-макросов
Swagger UIrust-embed 8.11Встраивание Swagger UI в бинарник (Astolfo Edition)
КонтейнерыDocker + Compose V2Один docker compose up -d поднимает всё

Как это работает

Платформа решает три задачи:

  1. Выдача решений (POST /decide). Продукт спрашивает: «что показать пользователю user-42 для флага button_color?». Платформа проверяет эксперименты, применяет таргетинг DSL, детерминированно выбирает вариант через xxHash3 и возвращает значение + decision_id.

  2. Сбор событий (POST /events, POST /events/batch). Продукт сообщает: «user-42 кликнул кнопку». События привязываются к decision_id, проходят валидацию по каталогу типов, дедупликацию и атрибуцию.

  3. Автоматическая реакция. Фоновый guardrail-чекер каждые N секунд пересчитывает метрики из каталога. Если порог превышен, эксперимент ставится на паузу или откатывается к контролю.

Ключевые идеи

Детерминизм через хеширование. Один и тот же пользователь всегда попадает в один вариант. Для бакетинга используется xxh3_64(user_id:experiment_id), для выбора варианта xxh3_64(user_id:experiment_id:variant). Никакого дополнительного хранилища для sticky-сессий не нужно.

Каталоги, а не хардкод. Типы событий и метрики задаются в каталогах через API. Guardrail-ы привязываются к метрикам из каталога. Новые типы событий и метрики добавляются без правки кода.

Fire-and-forget на hot path. Запись решений и участия в /decide выполняется через tokio::spawn без ожидания. Счётчик участия кэшируется в Valkey с TTL 60с. Цель: минимальная латенция на 100k RPS.

DSL-таргетинг. Собственный лексер и парсер: age >= 18 AND country IN ("RU", "KZ"). Поддерживает AND/OR/NOT, сравнения, множества IN/NOT IN, вложенные скобки. Если атрибут отсутствует, условие считается false.

Уведомления (C7). Telegram, Discord, Slack. Каждая команда заводит свой канал с bot_token. Правила уведомлений настраиваются через API: какие события куда слать.

Learnings Library (C9). После завершения эксперимента сохраняется structured learning: гипотеза, результат, impact, теги. Поиск по похожим экспериментам через tags, flag_key, free-text.

Insights (C8). Аналитика качества данных: доля отклонённых событий, traffic skew, полнота атрибуции, сводка платформы.

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

docker compose up -d
# Ждём готовности (~30 секунд)
curl http://localhost:80/ready

Подробная инструкция: docs/RUNBOOK.md

Swagger UI / OpenAPI

После запуска доступна интерактивная документация:

Документация генерируется автоматически из кода через utoipa 5.4. Все 62 API-эндпоинта аннотированы с описаниями на русском. Swagger UI встроен прямо в бинарник через rust-embed - никаких внешних файлов или CDN.

Примечание: НЕ используется utoipa-swagger-ui - этот крейт загружает ассеты по сети при сборке, что ломает Docker Buildx в сетевой изоляции. Вместо него Swagger UI dist-файлы лежат в swagger-ui/ и компилируются в бинарник.

API

Публичные (без токена)

МетодПутьНазначение
GET/healthЗдоровье сервиса
GET/readyГотовность к работе
POST/decideПолучить решение по флагам
POST/eventsОтправить событие
POST/events/batchОтправить пачку событий

Аутентификация (rate limited)

МетодПутьНазначение
POST/auth/registerРегистрация
POST/auth/loginПолучить JWT-токен

Защищённые (Bearer token)

МетодПутьНазначение
GET/POST/flagsСписок / создание флагов
GET/PUT/DELETE/flags/{key}Чтение / обновление / удаление флага
GET/POST/experimentsСписок / создание экспериментов
GET/PUT/experiments/{id}Чтение / обновление (только draft)
POST/experiments/{id}/transitionСмена статуса
POST/experiments/{id}/completeЗавершение с выводом
POST/experiments/{id}/archiveАрхивирование
GET/experiments/{id}/versionsИстория версий
GET/experiments/{id}/guardrail-triggersСрабатывания guardrail
GET/POST/experiments/{id}/reviewРевью
GET/experiments/{id}/reportОтчёт по вариантам
GET/experiments/{id}/learningsLearnings этого эксперимента
GET/POST/event-typesКаталог типов событий
PUT/event-types/{name}Обновление типа
GET/POST/metricsКаталог метрик
PUT/metrics/{name}Обновление метрики
GET/auditАудит-лог
POST/dsl/validateПроверка DSL-правила
GET/PUT/DELETE/users/{id}/approver-groupГруппы аппруверов
GET/POST/notifications/channelsКаналы уведомлений
PUT/DELETE/notifications/channels/{id}Управление каналом
GET/POST/notifications/rulesПравила уведомлений
DELETE/notifications/rules/{id}Удаление правила
GET/notifications/logЛог отправок
GET/POST/learningsБиблиотека выводов
GET/PUT/DELETE/learnings/{id}Конкретный learning
GET/insights/event-qualityКачество данных
GET/insights/traffic-skew/{id}Перекос трафика
GET/insights/attributionЗдоровье атрибуции
GET/insights/summaryСводка платформы

Роли

РольСоздаёт экспериментыРевьюитЧитаетАдминистрирует
Admin++++
Experimenter++
Approver++
Viewer+

Жизненный цикл эксперимента

draft -> review -> approved -> launched -> paused -> completed -> archived

На любом шаге возможен reject (возврат в draft для доработки). Guardrail может автоматически поставить на паузу или откатить к контролю.

Тесты

cargo test

81 тест (61 unit + 20 inline). Интеграционные: bash scripts/integration_tests.sh.

Документация

ФайлСодержание
docs/ARCHITECTURE.mdC4-диаграммы, компоненты, критический путь, OpenAPI
docs/RUNBOOK.mdПошаговый запуск и happy path
docs/COMPLIANCE.mdМатрица соответствия критериям
docs/TEST_REPORT.mdОтчёт о тестировании
docs/DEMO_SCENARIOS.mdСценарии демонстрации
/docs/Swagger UI - интерактивная документация API (Astolfo Edition)
/api-docs/openapi.jsonOpenAPI 3.1 спецификация (62 paths, 75 schemas)

Languages

Rust

80.9%

Shell

13.0%

Dockerfile

5.5%