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_newDashboard записи “новий favorite”: прив’язана до ролей (lady, operator, supervisor, topManager) + дата
chathouse_favorite_uniqueDashboard записи унікальних favorites для дашборду, по тижнях/днях і зрізах ролей

Типи favorites (FavoriteType)

ТипОпис
NEWЩойно з’явився, ще не оброблений оператором
NormalЗвичайний RU
NaughtyСхильний до неприйнятної поведінки
AggressiveАгресивний RU
FreeloaderЛише при відображенні — RU без реального прибутку (підміна з GlobalFavoriteType)

Поля chathouse_favorite

ПолеОпис
ladyDbIdID TU в БД
manUlidUlid 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 на дашборді.

ПолеОпис
manUlidRU
ladyDbIdTU (опц.)
operatorFamilyIdFamily оператора (опц.)
supervisorFamilyIdFamily supervisor-а (опц.)
stackTopManagerIdID top manager-а (опц.)
timestampЧас події
yearWeekРядок YYYY-WW для групування
yearMonthDayРядок YYYY-MM-DD для групування
isFreeБезкоштовний прибуток

Групи агрегації (chathouse_favorite_unique)

Зберігає кількість унікальних і платних favorites за різними зрізами:

typeЗріз
globalВсі по тижню
dailyLadyTU за день
weeklyLadyTU за тиждень
supervisorSupervisor за тиждень
operatorAndSupervisorОператор + supervisor за тиждень
topManagerTop manager за тиждень
topManagerAndSupervisorTop manager + supervisor за тиждень
topManagerAndSupervisorAndOperatorTop manager + supervisor + operator за тиждень

Як favorites з’являються в системі

Є два тригери — щохвилинний (тимчасова статистика) і нічний (основна статистика).

Щохвилинний крон — cronDownloadStatistics

Запускається воркером downloadingStatistics.queue кожні 2 хв.

  1. Завантажує бонуси поточного дня з партнерського API (для кожного активного адміна).
  2. Повністю перезаписує chathouse_temp_statistics (deleteMany + create).
  3. Знімає isFreeProfit з GlobalMan для RU з реальними платежами (removeFreeProfitMen).
  4. Оновлює in-memory кеш CachesTempStatisticsStore (initCaches).
  5. createFavoritesByTempStatistics — для кожної нової пари TU↔RU з кешу, якої ще немає в chathouse_favorite, створює новий запис. profit у новоствореного запису порожній — реальна сума живе лише в кеші до нічного крону. Після цього регенерує GlobalMan для нових manUlid-ів.

Новий favorite з’являється в chathouse_favorite щохвилини, щойно RU вперше витратив кредити за поточний день у діалозі з TU.

Нічний крон — launchDownloadLogic о 00:20 UTC

  1. downloadMainStatistics — завантажує всі дні від останнього запису в chathouse_statistics до вчора і зберігає в основну колекцію.
  2. statisticsGenerateService.updateCollection() — генерує StatisticsRelations-зріз.
  3. updateMainFavoritesProfit — для кожної пари TU↔RU отримує підсумковий прибуток з основної статистики і записує в chathouse_favorite поля profit, lastProfitAt, firstProfitAt, gifts (upsert).
  4. generateGlobalFavorites({}) — регенерує GlobalMan для всіх favorites.
  5. 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) за цей день.