global-favorite-service

GlobalFavoriteService

Спільний модуль project-application-api для глобальних фаворитів RU.

Задача

  1. Збирати всі ProjectFavorite одного RU у ProjectGlobalFavorite.
  2. Віддавати нашому frontend один список Global Favorites для всіх проєктів.
  3. Віддавати TU, на яких вибраний RU є фаворитом.
  4. Зберігати цільовий для Electron прапорець senderIgnore.
  5. Віддавати Global Favorites і короткі профілі RU у стартових даних Electron.

Агрегація

Після ProjectFavoriteChanged сервіс читає зв’язки RU прямо з collection і перераховує один ProjectGlobalFavorite. Через RMQ передаються тільки project і ruId, а не список favorites.

ПолеРозрахунок
firstPaidAtмінімальний firstPaidAt
lastPaidAtмаксимальний lastPaidAt
tuCountкількість зв’язків TU + RU
contactsкількість зв’язків із contacts.status = Yes
profitсума profit
giftsсума gifts
isFreeloaderправило проєкту від profit та ознак проєкту, див. нижче

Перерахунок є idempotent: агрегат щоразу будується з поточних ProjectFavorite, а senderIgnore і профіль RU не перезаписуються.

Freeloader

Окремого поля для платної частини profit немає: isFreeloader рахується з profit і ознак проєкту, які приходять із джерела платної активності.

Як зараз

ПроєктДе живеПравилоХто читає
Goldenніде: у моделях є лише enum Freeloader як тип для frontendне реалізовано; Electron-док очікує «бонусний фаворит із сумою 0»—
Primeprime_global_mans.profitfreeloader, якщо profit (кількість платних повідомлень) < 11 або відсутній; константа QUANTITY_MESSAGES_MAN_SPEND_MONEYсторінки favorites і global page (type = Freeloader), картка діалогу, workspace bookmark-діалоги (freeloader: true)
Chathousechathouse_favorites.isFree і chathouse_global_mans.isFreeProfitfreeloader, якщо всі платні дії RU з 2025-03-21 були за free credits (is_free_credits зі statistics API); перша реальна витрата знімає прапорець через removeFreeProfitMenсторінки favorites і global page, картка діалогу, workspace, tasks NeedToWriteMail і Online (freeloader пропускається), New Year
Udateudate_global_mans.profit та in-memory store globalFavoritesWithoutFreeloadersfreeloader, якщо profit < 11; store наповнюється при profit >= 11 у runner-і та > 11 у socket-taskсторінки favorites і global page, картка діалогу, FavoriteTaskRunner бере кандидатів для нових діалогів лише зі store

Ознака скрізь глобальна для RU, а не для пари TU + RU. У Prime і Udate profit — це лічильник повідомлень, тому поріг 11 вбудований у сенс поля. У Chathouse profit включає free credits, тому потрібна окрема ознака з джерела.

Як змінимо

  • isFreeloader зберігається лише у ProjectGlobalFavorite і рахується при перерахунку агрегату; favorites не мають власного прапорця.
  • Одне правило на проєкт у GlobalFavoriteService, поріг Prime і Udate — platform-настройка (11), без дубля > 11 у socket-логіках.
  • Chathouse: ProjectFavoriteService передає з платної дії ознаку free credits; агрегат тримає, чи була хоч одна реальна витрата. Формат цієї ознаки у ProjectFavorite (булеве hasPaidProfit чи окремий лічильник) вирішується під час імпорту статистики Chathouse.
  • Golden: profit <= 0 до появи окремого правила; міграція виставляє саме так.
  • Frontend отримує isFreeloader як окреме поле, а не через підміну type.

Frontend API

№ОпераціяEndpoint
1Список Global FavoritesGET /projects/{project}/global-favorites
2TU вибраного RUGET /projects/{project}/global-favorites/{ruId}/favorites
3Увімкнути або вимкнути цільове поле senderIgnorePATCH /projects/{project}/global-favorites/{ruId}

Список підтримує pagination, пошук за externalId або ім’ям і сортування за датами, online, кількістю TU, contacts, gifts та profit. Другий endpoint може фільтрувати зв’язки за contacts або gifts.

Director бачить усі RU проєкту. Тімлід і Top Manager бачать RU, пов’язаних хоча б з однією доступною їм TU; у вкладеному списку повертаються лише доступні TU. Сам агрегат RU завжди рахується по всьому проєкту.

Нотатка, яку зараз редагують на сторінці Global Favorites, буде читатися й змінюватися через NotesService.

Внутрішні операції

№ОпераціяХто використовує
1Перерахувати Global Favorite за project + ruIdProjectFavoriteService
2Отримати Global Favorites за списком доступних TUElectron StartupDataService

Окремий worker не потрібен: звичайне оновлення запускається разом зі зміною ProjectFavorite. Для первинної міграції або ремонту даних потрібен idempotent rebuild усієї проєкції.

Межі

  • Короткий профіль RU оновлюється з уже отриманих partner-відповідей та Electron data sync.
  • lastOnlineAt оновлює логіка RU online.
  • Поточний Prime Agency blacklist переноситься у senderIgnore; frontend та Electron SenderService змінюють одне поле.
  • GlobalFavoriteService не виконує partner-запитів і не містить адаптерів проєктів.

Agency

  • Prime Agency blacklist — це ручне виключення RU із сендерів, тому окремий AgencyService для нього не потрібен.
  • AgencyService — окрема логіка актуальних, нових і втрачених платних RU в межах усього проєкту для Golden і Chathouse. Це не календар New / Unique RU конкретної TU у FavoriteService.