# ТЗ: единая аналитическая платформа. Версия 0.1 (короткая)

Черновик от 20.09.2026. Собран из решений 17.09 (`plan.md`), разбора halleg и discovery-созвонов
18.09 (`calls-2026-09-18.md`). Пометки: **[Р]** решение принято, **[И]** пришло из интервью,
**[?]** открыто. Пункты без пометки выведены из известного и требуют подтверждения.

## 1. Зачем

Отчёты компании разбросаны по отделам: halleg (16 отчётов аналитики), самописные борды саппорта
(4 интерфейса), кабинет аффилиатов, Google-таблицы. Одни и те же метрики считаются по-разному,
проверить число негде, доступы выдаются вручную и бессистемно. **[И]**

Платформа даёт одну точку входа, одну модель доступа и один реестр метрик. UX существующих
отчётов не меняем, переносим как есть. **[Р]**

## 2. Пользователи

- 106 зарегистрированных, 96 активных в неделю, все внутренние сотрудники. **[Р]**
- Отделы на старте: аналитика, трейдеры, саппорт. Аффилиаты и остальные позже. **[Р]**
- Рабочее место: десктоп. Мобильную версию не делаем. **[Р]** Подтверждено саппортом. **[И]**
- Языки EN / RU / UA, все три реально используются. **[Р]**

## 3. Что должна уметь

### 3.1 Оболочка
- Вход по логину, шапка с пользователем и ролью, боковая навигация. Один shell для всех отчётов.
- Каталог отчётов с поиском, сгруппированный по отделам. Отчёты, недоступные роли, не показываются.

### 3.2 Отчёты
- Существующие отчёты halleg переносятся без изменения UX. Правки только двух видов: приведение
  к единой палитре и починка того, что тормозит. **[Р]**
- Приоритет переноса по посещаемости: Trader Operational, Trader Shifts, Weekly KPI, Scoreboard,
  Detailed закрывают 95% трафика.
- Отчёты интерактивные, не PDF-выгрузки. **[Р]**
- Экспорт есть у каждого отчёта и не выдаёт того, что скрыто от роли на экране. **[Р]**

### 3.3 Доступ
- Модель: отдел -> роль -> набор отчётов. Права на уровне отчёта целиком, без прав на строки и
  колонки в этой итерации. **[Р]**
- Сущности: пользователь, отдел, роль, отчёт. Пользователь в одном отделе, ролей может быть
  несколько, права = объединение отчётов всех ролей. Персональных исключений нет: нестандартный
  набор доступов = отдельная роль, видна в админке как аномалия. Иначе через полгода снова
  плоский список, как сейчас в `/api/me` halleg.
- Права проверяет бэкенд на каждом вызове данных. Фронт скрывает недоступные отчёты из каталога
  и навигации, но это удобство, а не защита.
- Экспорт формируется на сервере с теми же правами и фильтрами, что данные. Пока прав внутри
  отчёта нет, правило одно: нет доступа к отчёту, нет выгрузки. **[Р]**
- Админка: матрица «роль x отчёт», список пользователей с ролями, ручная блокировка «сейчас».
  Журнал выдачи прав (кто, кому, что, когда) пишется с первого дня.
- Блокировка уволенных по данным CRM, подключает CTO. **[Р]** Два события: увольнение блокирует
  вход; перевод между отделами снимает роли старого отдела и ставит роль по умолчанию нового.
  Ручной рычаг обязателен, задержка CRM неизвестна.
- Два увиденных паттерна **[И]** ложатся так:
  - саппорт: роли «менеджер» и «тимлид» в одном отделе. «Менеджер видит только себя» - это
    параметризованный отчёт: бэкенд подставляет текущего пользователя, отчёт знает, кто его
    открыл. Это ещё права на уровне отчёта, а не фильтр во фронте;
  - аффилиаты: разделение по принадлежности данных = права на строки. В первую итерацию не
    входит, кабинет аффилиатов остаётся отдельным. В дорожную карту как первый кандидат на
    row-level. **[?]**
- Сценарии, которые демка должна показать: вход под разными ролями (каталог меняется),
  попытка открыть недоступный отчёт по прямой ссылке (403 от бэкенда, а не пустой экран),
  выдача роли в админке, блокировка уволенного, экспорт доступен ровно там, где доступен отчёт.
- Роли до выгрузки «пользователь -> роль -> отчёты» с halleg - заглушки по наблюдённым
  паттернам (`local/platform/data/roles.json`). Схема в `local/platform/schema.md`.

### 3.4 Реестр метрик
- Один реестр, три представления: справочник целиком, легенда у каждого отчёта, подсказка у
  каждого числа с переходом к формуле. **[Р]** Прямой запрос аффилиатов: «увидел число,
  сразу понял, как оно посчитано». **[И]** Легенда отчёта не хранится отдельно: это выборка из
  реестра по списку метрик отчёта, поэтому расхождений между тремя видами быть не может.
- Запись реестра: идентификатор, имя на трёх языках, группа, статус, определение, формула,
  единицы, синонимы, где используется и как там описана, отклонения от канона по отчётам,
  примечания, автор, верификатор, дата. Полная структура в `local/platform/schema.md`.
- Идентификаторы метрик наши, читаемый snake_case (`payin_volume`, `cr`). Совпадение с
  параметрами halleg не обязательство: API у платформы свой. **[Р, 21.09.2026]**
- Статусы: `canonical` (есть в `metrics-legend`), `conflict` (несовместимые определения без
  канона, нужен арбитр), `needs_review` (в каноне нет, определение взято из кода как есть).
- Наполнение: импорт канонической `metrics-legend` с halleg (15 метрик с формулами и
  синонимами) плюс описания, извлечённые из кода 11 отчётов. Стартовый реестр собран:
  `local/platform/data/metrics.json`, 74 метрики, 15 канонических. Состав и определения будут
  перебираться аналитиками, это стартовая точка, а не истина. **[Р]**
- Отклонение от канона фиксируется в записи, а не скрывается: у числа пользователь видит, что
  здесь считается иначе и почему. Цель канона «иначе исправляется отчёт» остаётся, но до
  исправления расхождение показано. Найдено и выписано 17 отклонений по 10 метрикам.
- `Score` заведён двумя метриками (`score_scoreboard`, `score_tier`): формулы несовместимы,
  канона нет. Объединять нельзя до решения арбитра и получения `TIER_CALCULATION.md`.
- Поиск по синонимам: «Налив», «vol», «Amount IN» ведут к PayIn Volume.
- Описание пишет автор метрики, верифицирует аналитик. Метрика без описания в реестр не
  принимается, метрика вне реестра не попадает в отчёт. **[Р]**
- Версии: каждое изменение определения или формулы = новая версия с датой и автором, старая не
  удаляется. Отчёт за прошлый период ссылается на формулу, по которой считался. Реестр живёт и
  обновляется, а не выгружается разово: у саппорта формулы меняются ежедневно. **[И]**

### 3.5 Статистика использования
- Платформа сама логирует посещения отчётов и показывает дашборд использования. **[Р]**
- Условие: весь трафик к отчётам идёт через платформу, иначе статистика слепая.

## 4. Ограничения

- Свой сервер, внутренний домен, не halleg. **[Р]**
- Одна тема, тёмная. **[Р]**
- Фронтенд и проверяемая ролевая модель делаем мы. Бэкенд и реальные данные другая команда. **[Р]**
- Стек демки: статический HTML + общий shell без сборки, данные отдельно от разметки.
  Предложено, не подтверждено.

## 5. Не входит в первую итерацию

- Новые метрики и новые экраны. **[Р]**
- Права на уровне строк и колонок. **[Р]**
- Личные борды руководителей (саппорт) и кабинет аффилиатов как внешний продукт. **[И]**
- Агент-проверяльщик метрик, автопроверка отчёта при публикации. **[Р]**
- Ручные источники вроде Google-таблицы «Регистр» аффилиатов. **[?]**

## 6. Открытые вопросы, без которых ТЗ не закрыть

1. Отчёты переезжают к нам целиком или остаются на halleg и открываются через платформу.
   Во втором случае нужен SSO между доменами и нагрузка halleg не лечится.
2. Реальный список ролей: нет выгрузки «пользователь -> роль -> отчёты».
3. Контракт API halleg: нет ни одного примера ответа, репозиторий недоступен.
4. Один человек-арбитр по спорным определениям метрик. Отдел не подходит.
5. Как платформа отвечает на «сравнить два источника»: аффилиатам мало одной формулы, им
   нужно видеть, почему два экрана дают 1520 и 1607.

## 7. Дальше

Следующие версии: добавить требования к производительности из `report-weight.md` и данные саппорта, когда
пришлют ссылки и список метрик.
