Favorites
src/chathouse/components/favorites/ · Swagger → Favorites
HTTP-контракт — у Swagger. Тут тільки бізнес-логіка і нюанси.
Поняття
Favorite — RU, по якому є bonuses в статистиці у діалозі з конкретною TU. Зв’язок TU↔RU, один запис у chathouse_favorite.
Active favorite — RU, у якого lastProfitAt не старіший за 7 днів. Обчислюється динамічно, не зберігається як окреме поле. Використовується в FavoriteWorker і SenderRunner для визначення чи треба обробляти діалог.
Freeloader — тип RU на рівні відображення: якщо GlobalMan.isFreeProfit вказує на безкоштовну активність, type підміняється на Freeloader при конвертації для UI. У БД не зберігається.
При запитах на відображення фаворитів - підгружається глобальна інформація з GlobalMan.isFreeProfit. Також підгружається інформація з тимчасової статистики. Якщо всюди isFree - Freeloader.
Сховища
| Колекція | Що зберігає |
|---|---|
chathouse_favorite | Основний запис TU↔RU: тип, прибуток, дати, нотатки, чорний список, контакти |
chathouse_favorite_new | Dashboard записи “новий favorite”: прив’язана до ролей (lady, operator, supervisor, topManager) + дата |
chathouse_favorite_unique | Dashboard записи унікальних favorites для дашборду, по тижнях/днях і зрізах ролей |
Типи favorites (FavoriteType)
| Тип | Опис |
|---|---|
NEW | Щойно з’явився, ще не оброблений оператором |
Normal | Звичайний RU |
Naughty | Схильний до неприйнятної поведінки |
Aggressive | Агресивний RU |
Freeloader | Лише при відображенні — RU без реального прибутку (підміна з GlobalFavoriteType) |
Поля chathouse_favorite
| Поле | Опис |
|---|---|
ladyDbId | ID TU в БД |
manUlid | Ulid RU |
type | Тип (за замовчуванням NEW) |
contacts | Чи TU має контакти з RU поза платформою (Yes/No, за замовч. No) |
blocked | Чи TU заблокована від спілкування з RU |
isBlackList | Чи RU в чорному списку TU — впливає на SenderRunner (пропускає діалог) |
note | Нотатка оператора |
firstProfitAt | Дата першого прибутку |
lastProfitAt | Дата останнього прибутку — визначає flagActiveFavorite |
profit | Загальний прибуток (сума з БД; актуальна сума = profit + tempStatCache) |
gifts | Кількість подарунків |
isFree | Чи прибуток безкоштовний |
Поля chathouse_favorite_new
Лог-подія: фіксує момент появи нового favorite з прив’язкою до всіх рівнів ієрархії. Використовується для підрахунку нових favorites на дашборді.
| Поле | Опис |
|---|---|
manUlid | RU |
ladyDbId | TU (опц.) |
operatorFamilyId | Family оператора (опц.) |
supervisorFamilyId | Family supervisor-а (опц.) |
stackTopManagerId | ID top manager-а (опц.) |
timestamp | Час події |
yearWeek | Рядок YYYY-WW для групування |
yearMonthDay | Рядок YYYY-MM-DD для групування |
isFree | Безкоштовний прибуток |
Групи агрегації (chathouse_favorite_unique)
Зберігає кількість унікальних і платних favorites за різними зрізами:
type | Зріз |
|---|---|
global | Всі по тижню |
dailyLady | TU за день |
weeklyLady | TU за тиждень |
supervisor | Supervisor за тиждень |
operatorAndSupervisor | Оператор + supervisor за тиждень |
topManager | Top manager за тиждень |
topManagerAndSupervisor | Top manager + supervisor за тиждень |
topManagerAndSupervisorAndOperator | Top manager + supervisor + operator за тиждень |
Як favorites з’являються в системі
Є два тригери — щохвилинний (тимчасова статистика) і нічний (основна статистика).
Щохвилинний крон — cronDownloadStatistics
Запускається воркером downloadingStatistics.queue кожні 2 хв.
- Завантажує бонуси поточного дня з партнерського API (для кожного активного адміна).
- Повністю перезаписує
chathouse_temp_statistics(deleteMany + create). - Знімає
isFreeProfitзGlobalManдля RU з реальними платежами (removeFreeProfitMen). - Оновлює in-memory кеш
CachesTempStatisticsStore(initCaches). createFavoritesByTempStatistics— для кожної нової пари TU↔RU з кешу, якої ще немає вchathouse_favorite, створює новий запис.profitу новоствореного запису порожній — реальна сума живе лише в кеші до нічного крону. Після цього регенеруєGlobalManдля нових manUlid-ів.
Новий favorite з’являється в
chathouse_favoriteщохвилини, щойно RU вперше витратив кредити за поточний день у діалозі з TU.
Нічний крон — launchDownloadLogic о 00:20 UTC
downloadMainStatistics— завантажує всі дні від останнього запису вchathouse_statisticsдо вчора і зберігає в основну колекцію.statisticsGenerateService.updateCollection()— генеруєStatisticsRelations-зріз.updateMainFavoritesProfit— для кожної пари TU↔RU отримує підсумковий прибуток з основної статистики і записує вchathouse_favoriteполяprofit,lastProfitAt,firstProfitAt,gifts(upsert).generateGlobalFavorites({})— регенеруєGlobalManдля всіх favorites.metricsGenerateService.generateGeneralMetricsData()— оновлює метрики.
Поле
profitуchathouse_favoriteактуальне лише після нічного крону — тобто завжди “вчорашнє”.
Прибуток: БД vs відображення
Поле profit у chathouse_favorite оновлюється воркером раз на день після оновлення глобальної статистики. Щоб отримати актуальний profit при підгрузках фаворитів - до збереженого profit додається CachesTempStatisticsStore — тимчасова статистика. Те саме для lastProfitAt, firstProfitAt і gifts.
Тому flagActiveFavorite на UI може відрізнятися від значення яке дасть прямий запит у MongoDB.
Flow 1 — Сторінка favorites (Favorite Page)
Повертаються всі favorites по TU, відсортовані за lastProfitAt (найновіші першими). Для кожного додається ім’я і lastOnlineAt з GlobalMan, актуальний прибуток з temp-кешу, flagActiveFavorite.
Редагування: можна змінювати type, contacts, note, isBlackList через updateFavoriteById. Повертається оновлений запис у форматі Favorite Page.
Top manager - отримує фаворитів які закріплені за його тімлідами Supervisor - отримує фаворитів, які закріплені за його операторами (звязок operator-TU-favorite)
Flow 2 — Глобальна favorites (Global Page)
Supervisor або top manager дивиться всіх TU, які мають конкретного RU в favorites.
getFavoritesByManForSupervisor → фільтрує по TU з family supervisor-а (через SupervisorService). Повертає список у форматі Global Page — з назвою і аватаром TU, прибутком, flagActiveFavorite.
getFavoritesByMan — те саме без фільтру по family (для більш широкого доступу).
Редагування: через updateFavoriteByIdForGlobal — ті самі поля, але відповідь у форматі Global Page.
Flow 3 — Відображення в діалозі
Хто тригерить: оператор, supervisor відкриває діалог з RU
getFavoriteForDialog → повертає { profit, isFreeloader } для конкретної пари TU↔RU. Отримує актуальний Profit (БД + temp-кеш). Якщо запис favorite відсутній або у RU немає загального прибутку в GlobalMan — повертає null.
Flow 4 — Календар favorites TU
При відкриті favorites сторінку з календарем TU.
getCalendarByLady → повертає map { день → { new, unique } } за вказаний місяць (yearMonth). Дати розраховуються в таймзоні Europe/Kyiv.
new— кількість подій зchathouse_favorite_newза цей день для TU.unique— значенняuniqueFavoritesзchathouse_favorite_unique(типdailyLady) за цей день.