GlobalFavoriteService
Спільний модуль project-application-api для глобальних фаворитів RU.
Задача
- Збирати всі ProjectFavorite одного RU у ProjectGlobalFavorite.
- Віддавати нашому frontend один список Global Favorites для всіх проєктів.
- Віддавати TU, на яких вибраний RU є фаворитом.
- Зберігати цільовий для Electron прапорець
senderIgnore. - Віддавати 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» | — |
| Prime | prime_global_mans.profit | freeloader, якщо profit (кількість платних повідомлень) < 11 або відсутній; константа QUANTITY_MESSAGES_MAN_SPEND_MONEY | сторінки favorites і global page (type = Freeloader), картка діалогу, workspace bookmark-діалоги (freeloader: true) |
| Chathouse | chathouse_favorites.isFree і chathouse_global_mans.isFreeProfit | freeloader, якщо всі платні дії RU з 2025-03-21 були за free credits (is_free_credits зі statistics API); перша реальна витрата знімає прапорець через removeFreeProfitMen | сторінки favorites і global page, картка діалогу, workspace, tasks NeedToWriteMail і Online (freeloader пропускається), New Year |
| Udate | udate_global_mans.profit та in-memory store globalFavoritesWithoutFreeloaders | freeloader, якщо 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 Favorites | GET /projects/{project}/global-favorites |
| 2 | TU вибраного RU | GET /projects/{project}/global-favorites/{ruId}/favorites |
| 3 | Увімкнути або вимкнути цільове поле senderIgnore | PATCH /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 + ruId | ProjectFavoriteService |
| 2 | Отримати Global Favorites за списком доступних TU | Electron 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.