project-favorite

ProjectFavorite

Collection project_favorites — спільний документ favorite для пари TU + RU. Schema, indexes і ProjectFavoriteRepository оголошені в @it-monkeys/backend-common, типи — у @it-monkeys/contracts (ProjectFavoriteBase).

Поля

  • project — проєкт, до якого належить favorite.
  • tuId — посилання на ProjectTU.
  • ruId — ID RU на партнері, збережений як string: Golden і Prime — числовий ID, Chathouse і Udate — ULID.
  • type — new, normal, naughty або aggressive; ручне поле оператора.
  • contacts.status — yes або no.
  • contacts.email — email RU у нижньому регістрі, якщо він зберігається для цього проєкту.
  • blockedByRU — RU заблокував TU; оновлюється з partner-даних.
  • blockedByTU — RU вручну заблокований для TU у наших робочих логіках.
  • firstPaidAt / lastPaidAt — перша й остання платна дія RU для TU; null, поки платної дії не було.
  • profit — profit пари TU + RU у форматі конкретного проєкту: сума витрат у Golden і Chathouse, кількість платних вхідних повідомлень у Prime і Udate.
  • gifts — кількість подарунків, якщо проєкт повертає їх у джерелі.
  • isWhite — RU входить у white-list цієї TU.
  • createdAt / updatedAt — час створення й останньої зміни документа.

У документі немає directorId: scope директора визначає TU.

Profit

Проєктprofitgifts
GoldenСума витрат✅
PrimeКількість платних вхідних повідомлень—
ChathouseСума витрат разом із free credits✅
UdateКількість платних вхідних повідомлень🟡

В Udate поле gifts зараз є, але джерело для його заповнення не реалізоване.

Поточні collections по проєктах

Реальні поля з production-дампу на 2026-09-03.

ПроєктCollectionДокументівКлюч париПлатна активністьБлокуванняРучні поля
Goldengolden_favorites163 090ladyId_api + manId_api, uniquestartDate, lastDate + time (рядки), profit, giftsblocked (1 doc), blockedByTU; фактичні блоки RU — у golden_block_liststype, contactDetails.{status,email}, name, note + updateNote, language
Primeprime_favorites365 749ladyId + manIdfirstManMessage, lastManMessage, lastMessage (ms), messageCounter; messages[] завжди порожнійblocked, isBlackListtype, contacts, note + updateNote
Chathousechathouse_favorites328 384ladyDbId + manUlid, uniquefirstProfitAt, lastProfitAt (Date), profit, gifts, isFreeblocked, isBlackListtype (NEW), contacts, name, note + updateNote
Udateudate_favorites78 253ladyUlid + manUlidтільки messages[] з timestamp і messageId (у середньому 24, максимум 4 161 на пару)blocked, isBlackListtype (NEW), contacts, name, note + updateNote, isCheckedNew

Окремі агрегати для dashboard (*_favorite_news, *_favorite_uniques, prime_favorite_actions) до цієї сутності не належать і розглядаються разом зі статистикою.

Legacy → canonical для Golden

CanonicalLegacy golden_favoritesПравило
_id_idзберігається
tuIdladyId_apiчерез project_tus.partnerIds.idApi у scope директора; пари без TU не переносяться
ruIdmanId_apiString(manId_api)
typetypeNew → new і далі за назвою
contacts.statuscontactDetails.statusYes → yes; legacy-поле contacts не читається: воно розходиться зі contactDetails.status у 363 документах, а код на читанні бере саме contactDetails
contacts.emailcontactDetails.emailу нижньому регістрі; порожній рядок не переноситься
blockedByRUblocked або пара в golden_block_lists.blockList4 022 пари беруться з блок-листів, поле blocked майже не заповнене
blockedByTUblockedByTUяк є
firstPaidAtstartDateпочаток доби Kyiv; у legacy new Date('YYYY-MM-DD') давав UTC-північ
lastPaidAtlastDate + timeлокальний час Kyiv: golden_global_mans.lastMessageAt побудований саме так
profitprofitяк є
giftsgiftsяк є
isWhite—false; white-list рахує Electron
—name (79 033 непорожніх)у canonical favorite не входить; використовується як резерв для profile.name у ProjectGlobalFavorite
—note, updateNote (65 222 непорожніх)переносяться окремим кроком у NotesService; до того лишаються в legacy
—language (943 непорожніх)не переноситься, потрібне рішення

334 пари не мають lastDate, 92 — startDate: це порожні пари, створені Electron до першої вигрузки статистики; у canonical вони отримують null. Точний firstPaidAt з часом доби можна отримати з golden_statistics під час імпорту статистики.

Міграція: POST /migrations/favorites/apply у project-application-api, idempotent, повторний запуск оновлює документи за _id.

Використання в legacy Golden

ХтоЩо робитьДжерело
Frontend /favorites/getFavoritByLadyfavorites TU + overlay golden_temp_statistics, блок-лист, профіль RUGoldenFavoritesService.getFavoritesByLady
Frontend /favorites/updateFavoritById, updateFavoriteByIdForGlobalручні поля: type, contactDetails, name, note, language, blockedByTUGoldenFavoritesService.updateFavoritById
Frontend /favorites/getFavoritesByMan*favorites RU для сторінки Global Favorites, фільтри contacts і giftsGoldenFavoritesService.getFavoritesByMan
Frontend /favorites/getCalendarByLadyкалендар New / Unique з golden_calendars + overlay tempGoldenFavoritesService.getCalendarByLady
Electron /getBaseFavorites, /getFavorites, /getFavoritesEmailInfoбазовий snapshot по TU оператора, overlay temp і email-статусиElectronApiService
Electron /createFavoritesForPairsupsert порожніх пар, які з’явились у tempGoldenFavoritesService.createFavoritesForPairs
Вигрузка статистикиupdateFavoritesV2: агрегат golden_statistics ∪ golden_other_bonuses → profit, gifts, startDate, lastDate, timeStatisticsDownloadingService
initFavoritesдокачує історію бонусів нових TU і створює париручний роут, раніше — після TU sync
Розширення mail і extensionчитають favorites TU для NAF/FANM-логікMailExtensionService, GoldenExtensionRepository
Global Favoritesперерахунок golden_global_mans з усіх favoritesGlobalManService.generateGlobalFavorites

Electron

ProjectFavorite є базовим server snapshot для Electron FavoriteService. Electron накладає на нього поточний statistics/message overlay.

  • isActive не зберігається — рахується з lastPaidAt за однією platform-настройкою; default 7 днів.
  • isFreeloader додається з глобальної RU-логіки.
  • chatLimit, mailLimit і follow-up state залишаються runtime-станом Electron та в collection не зберігаються.

Профіль, avatar і online RU для глобальних фаворитів зберігаються у ProjectGlobalFavorite. Нотатки зберігатимуться окремо від favorite.

Індекси

  • unique { project: 1, tuId: 1, ruId: 1 } — uniq_project_favorite_pair;
  • { tuId: 1, lastPaidAt: -1 } — project_favorite_tu_list, список favorites TU;
  • { project: 1, ruId: 1 } — project_favorite_ru_links, зв’язки RU з TU для Global Favorites.

Заповнити

  • Вирішити, чи потрібен legacy language favorite, і де він живе, якщо потрібен.
  • Затвердити джерело paid activity для календаря New / Unique без зберігання необмеженого масиву подій у ProjectFavorite.
  • Перенести note у NotesService до вимкнення legacy favorites.