Статистика
src/statistics/ · project-golden/src/statistics/ — операції партнера по TU, прив’язка сум до команди по днях і місячна статистика операторів і TU для всіх ролей.
Дані: project_statistics, project_statistics_temp, project_statistics_relations · Swagger: тег Statistics · План: StatisticsService
Що робить модуль
- Зберігає операції партнера по TU: завершені дні —
project_statistics, незавершені —project_statistics_temp. - Щодня прив’язує суми TU до власників дня — оператора, тімліда, client manager — у relations.
- Віддає місячну статистику операторів і TU для director, тімліда, топа, client manager і оператора; незавершені дні накладаються на читанні.
Спільні кроки — у StatisticsService; правила, що поки свої в кожного проєкту (запис relations, незавершені дні), — в адаптерах src/statistics/adapters/ (реалізовано Golden). Дані Stack читаються напряму з колекцій, без RMQ.
Потік даних
| Крок | Хто | Коли |
|---|---|---|
Оперативна вигрузка: незавершені дні (сьогодні, до 13:06 — ще й вчора) по кожній активній адмін панелі → project_statistics_temp; далі платформа створює порожні favorites для нових пар (06-favorites) | project-golden | щохвилини |
Денна вигрузка: завершені дні з дня після останнього записаного → project_statistics; невідома TU запускає refresh TU | project-golden | 13:06 за Києвом, 3 спроби з паузою 30 хв |
| Relations нових днів (нижче), потім у фоні копія статистики в ClickHouse (10-metrics) | платформа, internal update | після денної вигрузки |
| Перерахунок favorites | платформа (06-favorites) | після relations |
Видалення завершених днів з project_statistics_temp | project-golden | після перерахунку |
Історія TU до появи в агенції пишеться в project_statistics як зовнішня під час init TU.
Логіка
Relations дня
Для кожного дня після останнього в relations адаптер будує записи дня (Golden — перенесений legacy updateCollection):
- TU продовжує фінальний запис попереднього дня або починається з події створення.
- Події доби з
tu_logsділять TU на відрізки; операції відрізка дістаються його власникам. Власника змінюють лише логін оператора, зняття оператора, що працює, зняття його тімліда і зміна client manager; призначення лише фіксує поточний запис. - Після TU — записи операторів без TU з журналу Stack
log_operators: заблоковані за добу, нові, з яких зняли всі TU, і порожні активні. - Службові типи операцій і подарунки в relations не входять.
- День без статистики пропускається.
Порожні relations (без міграції) — помилка: перший день рахується від уже записаного.
Relations місяця на читанні
Записані дні місяця плюс незавершені дні з project_statistics_temp: від останнього записаного дня адаптер будує кожен день знімка тим самим алгоритмом, що й запис; фільтр роуту застосовується й до них. Якщо останній записаний день — у попередньому місяці, оператори, заблоковані чи видалені до початку місяця, в незавершені дні не потрапляють.
Рядок оператора
- Сума дня — сума relations оператора;
null, коли суми немає, а деньredчиgray. - Стан дня: до першої події місяця з журналу оператора (
log_operators) — зворотний до неї; день без подій після блокування —red, після видалення чи зняття тімліда —gray; інакше — день оператора Stack (stack_operator_days). - Статус місяця — за останньою подією журналу. Кількість TU — TU з фінальним активним записом в останній день; у поточному місяці — TU, закріплені зараз у
project_tus. - Сторінка оператора: рядок оператора і рядки TU з relations, у поточному місяці — ще й TU, закріплені за ним зараз. Для TU без оператора сума дня — сума його TU; TU без суми не показуються.
Рядок TU
Стан дня — зі стану TU в першому записі дня, рольових і lifecycle-подій tu_logs; стан переходить на наступний день. Сума — relations TU. TU, видалена весь місяць, не показується, якщо зараз не закріплена за оператором. Ім’я, вік, фото — project_tus; рівень та історія рівня — картка TU у Stack; оператор бачить ім’я без прізвища. У списках — TU, активні в місяці або з сумою.
Топ
Тімліди топа за місяць — з журналу тімлідів і stack_log_top_managers. Дні, коли тімліда не було в топа, сірі й без суми; у списку операторів — дні поза відрізками оператора в топа.
Online
Джерело — відрізки online платформи.
- День online — доба проєкту або з
onlinePeriod: shiftзміна: від години початку робочих годин тімліда до тієї ж години наступного дня. Тімлід зміни: у командах тімліда — він сам; у director, топа і на сторінці оператора — поточний тімлід оператора; без тімліда чи годин — доба. - Online дня — сума перетинів відрізків із днем; відрізок без тривалості — 1 с.
online—Hч Mм(хвилини вниз, менше хвилини —0ч 1м),onlineSec— секунди,nullпри нулі. Не показується в день без суми зі станомredчиgray; у топа поза відрізками оператора —online: null,onlineSec: 0. - У команді тімліда і топа online рахується лише за час оператора в цьому тімліді (тімлідах топа).
- Online рахується оператору з relations, журналом або днями оператора в місяці; рядок TU без оператора —
null. - TU — лише на сторінці оператора: час відкриття TU в Electron цього оператора; TU без relations і подій у місяці —
null, на сторінці TU без оператора —0ч 0м. isOnline— програма оператора підключена зараз (Electron Gateway, покиstack-golden); лише для оператора в станіnone, інакшеfalse. Без Gateway — усіfalse, запит не падає.sleepModeне переноситься: у legacy він вимкнений.
API для frontend
Усі роути приймають project, month (YYYY-MM) і поля нижче. operatorProjectId: null — TU без оператора, clientManagerProjectId: null — TU без client manager. Роути операторів приймають onlinePeriod: day | shift.
| Роут | Ролі | Поля |
|---|---|---|
POST /v2/statistics/operators | director | — |
POST /v2/statistics/team-lead-operators | director, тімлід | teamLeadProjectId |
POST /v2/statistics/top-manager-operators | top manager, director | teamLeadProjectId?, topManagerUserId? |
POST /v2/statistics/operator | operator, director | operatorProjectId |
POST /v2/statistics/team-lead-operator | director, тімлід | teamLeadProjectId, operatorProjectId |
POST /v2/statistics/top-manager-operator | top manager, director | operatorProjectId, teamLeadProjectId?, topManagerUserId? |
POST /v2/statistics/tus | director | — |
POST /v2/statistics/client-manager-tus | director, client manager | clientManagerProjectId |
POST /v2/statistics/team-lead-tus | director, тімлід | teamLeadProjectId |
POST /v2/statistics/top-manager-tus | top manager, director | teamLeadProjectId?, clientManagerProjectId?, topManagerUserId? |
POST /v2/statistics/client-manager-team-lead-tus | client manager, director | teamLeadProjectIds, clientManagerProjectId? |
Топ без teamLeadProjectId — усі його тімліди за місяць; без topManagerUserId — топ з токена.
Internal API
| Роут | Хто викликає | Навіщо |
|---|---|---|
POST /v2/internal/statistics-relations/update | project-golden | relations нових днів після денної вигрузки |
POST /v2/internal/statistics-relations/users-sum | — (замінює RMQ GoldenUsersStatisticsSum Stack) | суми операторів і тімлідів за весь час |
POST /v2/internal/statistics-relations/hr-operators | — (замінює RMQ getStatisticsFromFamily) | статистика операторів для HR |
Звірка з legacy
- Запис relations на дампі від legacy-записів попереднього дня: 01.12.2025–12.09.2026 — 402 231 запис проти 402 222 legacy, розбіжності в 10 днях по 1–4 записи. До грудня 2025 legacy рахував без логінів операторів — ця історія переноситься міграцією.
- HTTP-звірка з
stack-golden(той самий токен директора, 23 випадки кожного роуту, зокрема TU без оператора, client manager, топ з усіма тімлідами): липень і серпень 2026 — 0 розбіжностей по сумах і станах днів, підсумку, статусу, кількості TU, імені, фото і рівню TU; вересень до 27.09 — 0, решта — рядки з temp-даних legacy за 28–29.09, яких локально немає. - Online: по добі — 0 розбіжностей у липні–вересні, крім 1 с на legacy-дублі відрізка. По змінах дві відмінності від legacy: директорський список legacy обрізає останню зміну місяця опівночі; сторінка оператора в топа з усіма тімлідами в legacy online не обрізає. Тут обидва випадки рахуються повністю й однаково.
- Незавершені дні 28–29.09 проти legacy
createAdditionalRelationsна тих самих temp-даних — 2237 і 1256 записів, 0 розбіжностей.
Нюанси
- Оновлення relations — одне на проєкт одночасно (лок 1 година); повторний запуск під час роботи — 409.
- Legacy-копія алгоритму незавершених днів не перевіряла блокування оператора; тут обидва шляхи використовують один алгоритм.
- Legacy падає на тімліді, якого немає в топа; тут такі дні сірі.
Борг
- Ролі не обмежують
teamLeadProjectId,operatorProjectIdіclientManagerProjectIdсвоїм scope — як у legacy: тімлід може запросити чужу команду. users-sumіhr-operatorsреалізовані, але Stack досі ходить у legacy через RMQ.