Воркспейс — каркас логік
Повний перелік логік воркспейсу — що мусить бути, щоб нічого не пропустити. Тут — що це і від чого залежить.
- Current State: фактичні розбіжності по проектах.
- Server Coupling: проблеми які буду пов’язані з переносом.
- Family Blueprint: повний набір логіки одного проєкту.
Запуск
1. Логін оператора → підключення сокету до нашого серверу.
- аутентифікація оператора
- перевірка версії програми
- перевірка часу з світовим
2. Підключення сокету до нашого серверу - отримання списку TU.
- підключення чи перепідключення завжди повертає актуальний список ТЮ з статусами.
- час (зміна) роботи оператора перевіряється на цьому етапі
- обробка індивідуальних логік проектів по логіну ТЮ буде на цьому етапі теж
3. Отримання даних з серверу для запуску та робити логік.
- мабуть варто це реалізувати одним запитом
- відповідно до проекту набори даних будуть і однакові і різні TO DO
4. Логін TU на сайт + сокет по ТЮ.
Логін і носій сесії для запитів різні на кожному сайті; Golden ще й має два логіни (вкладка + окреме оф-апі).
| Golden | Chathouse | Prime | |
|---|---|---|---|
| Логін | in-page rlogin у вкладці (id_api+pass) + окремий логін оф-апі agencyhelper (login+pass) | POST /tru/login (email+pass+auth_code) | POST /platform/auth/login (email+pass+referral_code) · |
| Що юзаємо для запитів | 2× JSESSIONID: вкладки (Chromium шле сам) + оф-апі (вручну в Cookie: axios) | Bearer JWT access_token → Authorization: Bearer | кукі (Set-Cookie) у → Cookie: axios |
| Сокет — ключі конекту | Red5 wss://…/Red5Chat: param1=id_api + param5=loginTokenChat (+2 хардкод-конст, subproto chat) | Centrifuge wss://ws.chatshouse.com: окремий broadcasting-токен; канал api#<ulid> | Centrifuge wss://talkytimes.com/rtm: tld-token (JWT з кукі) у хендшейку + X-Requested-With; канали broadcast/online/personal:#<id> |
Golden — виняток: логін і сокет крутяться всередині реальної браузер-вкладки (Electron BrowserWindow) → кукі возяться автоматично + працює WebRTC-камера. Chathouse/Prime — headless (axios + Centrifuge), сторінка не потрібна.
- комбінацію логінів та запусків ініціалізуючих логік треба ще переглянути, десь можна паралельно, десь тільки послідовно (зараз: Golden — TU послідовно, Prime — паралельно
Promise.all, Chathouse — послідовно)
5. Запуск pre логік.
Перед основними логіками Chathouse і Prime ганяють на старті кілька підготовчих логік і показують оператору вікно з їх прогресом. У Golden цього немає.
| Pre-логіка | Golden | Chathouse | Prime |
|---|---|---|---|
| Фаворити на сайті (поставити/зняти) | — | FavoriteWorker (save/unsave) | PrimeBookmarkWorker (bookmark/unbookmark) |
| Айсбрейкери | — | IceWorker (чат + лист) | PrimeIcesWorker (чат-групи + лист) |
Фаворити на сайті. Обидва тримають на сайті позначку «фаворит» синхронізованою: кому треба — ставлять, хто вже ні — знімають. Різниця — звідки беруть «хто фаворит»:
- Chathouse — зі статистики (RU з платним профітом за останні 7 днів). Ставить: проходить вкладку
all, і кому з активних фаворитів позначки ще нема →saveDialog(save:true). Знімає: проходить вкладкуsaved, і хто вже не активний фаворит →saveDialog(save:false). Заодно позначає заблокованих (RU заблокував анкету). - Prime — статистики нема, тому все по історії листування. Ставить: де RU надіслав платне повід./лист за останні 7 днів →
changeBookmark(true). Знімає (changeBookmark(false)): якщо чат-ліміти вичерпані — одразу (навіть при свіжому спілкуванні); або якщо останнє платне від RU старше 7 днів. Лічильник дій RU (за ним і визначається фаворит) оновлюється реалтайм по сокету (+1 на кожне платне повід./лист); повний скрол історії — раз на TU (перша ініціалізація), а при логіні для вже відомого фаворита скрол іде лише до останньої зафіксованої дати й доливає нові.
Реворк: сумнівно скролити діалоги й проставляти фаворитів на сайті при кожному логіні — цю логіку треба переробити.
Айсбрейкери. Раз на день на кожну TU активують випадковий айсбрейкер по кожному типу (чат + лист); що вже активовано сьогодні — не повторюють (перевірка по БД надісланих за добу).
- Chathouse — на кожен тип бере випадковий approved і ще не активний ice → активує.
- Prime — лист: випадковий готовий mail-ice. Чат складніше: треба ≥2 ice на кожен настрій (
friendship/hot_talks/real_love), тоді зупиняє поточні й шле групу з трьох настроїв (по випадковому в кожному).
Під питанням: айсбрейкери не мусять блокувати старт — їх можна робити у фоні; тримати їх у стартовому прогресі сенсу мало.
6. Старт основних логік.
- Сервіс підтримки ТЮ в онлайні, перевірки ТЮ з апі що вона онлайн та реконект, фіксування часу онлайн
- Обробка дій оператора для перевірки активності та фіксування онлайну і дій оператора
- Пошук тасків
- Сендера
- Оновлення фаворитів чи чатхісторі
Важливі логіки
Постійні алгоритми, що тримають роботу. Кожна мусить бути в кожному проекті. Згруповані за залежністю від партнерського API — саме вона визначає, наскільки логіку можна звести до спільної реалізації.
Тір 1 — незалежні від API
1. Обробка дій оператора
- обчислення дій оператора по типах
- обчислення онлайну оператора
- кік-закриття програми при неактивності (10хв)
- оновлення останнього онлайну в редіс
2. Синхронізація стану на бек (data-sync)
Збереження даних з локальної бази msql lite на наш сервер. Дані будуть відповідно до логік, те що уже існує:
- результати сендерів
- дії оператора
- онлайн оператора
- періоди стрімів
- перегляди профілів
- критичні логи
3. Інвайти для сендерів
- створення інвайтів
- вибір інвайтів для сендерів
4. Тімлід live-view
Реалтайм-дзеркало стану воркспейсу оператора (список TU, фаворити, таски, діалоги, стрім) → тімліду через наш сокет. Стан у нас → не залежить від сайтів, однаково всюди — просте, спільна реалізація. Залежить від: наш сокет, агрегований стан воркспейсу.
Тір 2 — слабо залежні від API
1. Тримання TU онлайн
Кожен сайт має механізм підтримки ТЮ в онлайні, треба щоб він був в кожної ТЮ імплементований незалежно
- Golden активно пінгує +
setAuthUserOnline(60с) - Chathouse реєструє TU у батч-пінг адмін-API
- Prime тримає онлайн просто WS-конектом + регулярні запити
2. Перевірка онлайну TU та реконект
- потрібне апі для перевірки чи ТЮ онлайн, зазвичай це апі з адмінки
- якщо ТЮ онлайн - рахувати його
- якщо ТЮ офлайн - механізм реконекту (індивідуально по проекту)
Зведення що ми маємо:
| Логіка | Golden (в Electron) | Chathouse | Prime |
|---|---|---|---|
| Тримання онлайну | API ✅ · Логіка ✅ | API ✅ · Логіка ✅ | API — · Логіка ❓ |
| Перевірка онлайну TU | API ✅ · Логіка ✅ | API ✅ · Логіка ❌ | API ✅ · Логіка ❌ |
| Реконект | ✅ детект офлайн → перезапуск TU + Red5-сокет окремо | ⚠️ перезапуск init, але від фейлу старту, не від перевірки | ⚠️ лише сокет (авто-реконект Centrifuge), без перезапуску логік |
Висновок. Цільова петля — «раз на ~60с перевірити з апі онлайн кожної TU → якщо офлайн, перезапустити/переконектити». Тримання є всюди. Треба протестувати стабільність Chathouse і Prime.
Яке апі є і як працює:
- Golden — тримання:
setAuthUserOnline— на сесії самої TU (усередині її вкладки, POST на chat-сервіс), по одній. Перевірка:getOnlineLadies— апі з адмінки (agencyhelper):userId=0= весь список онлайн-TU одним запитом; зараз Golden смикає по одній TU в циклі щохвилини. - Chathouse — тримання:
ping-list— один батч-POST з масивомtrusted_user_ids(групується по адміну). Перевірка:getLadies(GET .../trusted-user) — весь список TU одним запитом, у кожної є полеis_online(зараз код його не читає). - Prime — перевірка:
trusted-user/collection(POSTdatame.cloud) — курсорна пагінація (limit+id_last), у кожної TU єis_online(зараз читається лише для синку каталогу).
3. Медіа (галерея TU)
Отримання / завантаження / видалення медіа з галереї TU. Задача на фронті однакова (вибрати й надіслати), різняться набір типів і форма апі. У Chathouse/Prime чат і лист беруть з однієї галереї (фільтр по контексту); у Golden — окремі пули. У чат зазвичай 1 файл, у лист — кілька. Chathouse ще має поле що фото було відправлене.
Чат:
| Golden | Chathouse | Prime | |
|---|---|---|---|
| Типи | фото, відео | фото, відео | фото, відео, аудіо, стікери, пости |
| Список | все одразу (getMediaLibraries) | все одразу (GET /media) | курсор (фото/відео); аудіо — все одразу |
| Upload / Delete | ✅ / ✅ | ✅ / ❌ (лок. «сховати») | ✅ / ✅ (аудіо-delete ❌) |
| Paid | ✅ isPaid | фото✅, відео❌ | ✅ sent/accessed |
| Модерація | ✅ moderate (поле) | ✅ окремі списки /media/moderation·/decline | ✅ статуси approved/on_moderation/declined |
Лист:
| Golden | Chathouse | Prime | |
|---|---|---|---|
| Типи | тільки фото (до 2) | фото + відео | фото + відео |
| Список | все одразу (attach) | все одразу (GET /media) | курсор (фото/відео) |
| Upload / Delete | ✅ / ✅ | ✅ / ❌ (лок. «сховати») | ✅ / ✅ |
| Paid | ✅ isPaid | фото✅, відео❌ (лише режим листа paid_all) | ✅ sent/accessed |
| Модерація | ✅ isModerate | ✅ /media/moderation·/decline | ✅ статуси |
⭐ Головна різниця — форма списку: Prime віддає фото/відео курсором (cursor+limit 40), Golden і Chathouse — все одразу. Спільний інтерфейс має вміти обидва.
Chathouse-нюанс — медіа-квота на листах: при відправці листа бек рахує частку листів із медіа за день і блокує лист без медіа, якщо оператор нижче порога (~35%), а RU з кредитами. Тобто на Chathouse відправка листа може вимагати медіа.
Тір 3 — сильно залежні від API
API диктує формування, умови й саму можливість → тут головна робота: спільний скелет, реалізація під контракт кожного сайту.
1. Таски
Три осі:
- Механізм:
сокет(реалтайм-подія) ·скрол(інтервальний обхід/пагінація діалогів) ·статистика(колонки подій). - Типи: Unanswered чат/мейл, NeedToWrite чат/мейл, OpenLimits, OpenLimits VIP, Like, Typing.
- Скрол-логіки: що крутимо → що знаходимо → як часто → як глибоко.
Шляхи створення по типах:
| Тип | Golden | Chathouse | Prime |
|---|---|---|---|
| Unanswered чат | сокет + скрол | сокет + скрол | сокет + скрол |
| Unanswered мейл | статистика | сокет + скрол | сокет + скрол |
| NeedToWrite чат | скрол | сокет + скрол | скрол (×2) |
| NeedToWrite мейл | статистика | сокет + скрол + статистика | — (зводиться) |
| OpenLimits | — | скрол | сокет + скрол |
| OpenLimits VIP | — | — | планувальник (наш DB) |
| Like | сокет | сокет + скрол | сокет + скрол |
| LikeMail | — | — | скрол |
| Typing | — | сокет | — |
ActiveChat (Golden) — не окремий тип: платний чат перемикає титули-стани (ActiveChat/Finished) поверх Unanswered чат; той самий таск, інші тайтли.
Сокет-тригери (подія → логіка):
- Golden —
receivePrivateMessage: текст 🌹 → Like, інакше → Unanswered чат.paidChatStarted/paidChatStopped→ титули-стани Unanswered чат (ActiveChat/Finished). - Chathouse —
Send: платне вхідне → Unanswered чат,inmail_message→ Unanswered мейл, лайк → Like.NewNotification(NEW/REPEAT;ONLINE_NOW/RECENT_PURCHASE) → тягне діалог RU: chat-ліміти → NeedToWrite чат, інакше mail-ліміти → NeedToWrite мейл, нема лімітів → скіп.Typing→ Typing (не в БД, гард 60с). - Prime —
MessageSent→getDialogs[unanswered]+checkChatRestrictions: платний тип → Unanswered чат, like-тип → Like.chat_DialogCreated→getDialogs[active]: останнєsystem+messagesLeft→ OpenLimits (VIP-дедуп).email→ Unanswered мейл.Blocked→ видалення всіх тасків пари.
Скрол — групи та архітектура (як буде):
Ціль: один код в Electron, різні проекти — різне апі під тими самими логіками. Архітектура: скрол-сервіс обходить діалоги певної «поверхні» (онлайн / unanswered / фаворити) → віддає потрібні діалоги в таск-сервіс, який робить таск. Поверхні групуються так:
0. Golden — списку діалогів немає. У Golden апі є лише на конкретний діалог (chatHistory / getMail по manID), а списку всіх діалогів немає взагалі. Тому скролити нема що — Golden бере свій список фаворитів (зі статистики) і по кожному окремо тягне його чат/листи. Список фаворитів заміняє Golden’у список діалогів.
1. Онлайн-діалоги (Chathouse all+is_online, Prime [active, online]). Обходимо діалоги RU, які онлайн, і шукаємо ті, де останнє повідомлення від TU (кілька хв/год тому), пара не блокована і є ліміти.
- Chathouse: один запит віддає список онлайн-діалогів. У кожному діалозі — одне останнє повідомлення (з типом: чат це чи лист) і окремі лічильники лімітів на чат і на лист. Тобто чат і лист — не різні діалоги, це один діалог, де видно обидва ліміти; саме тіло листа, якщо треба, тягнеться окремим запитом.
- Prime: чати і листи — різні запити (онлайн-діалоги дають чат; листи — окремо).
2. Unanswered — RU нам написав (Chathouse new, Prime unanswered + пошта inbox_unanswered). Те саме, але не онлайн, а хто нам написав — чат чи лист.
- Chathouse: 1 запит (чат і лист в одному діалозі, як вище). Prime: 2 запити — окремо чат (
unanswered) і окремо пошта (inbox_unanswered).
3. Фаворити. Як зараз — окремий прохід сайтом по збережених/закладених фаворитах (сайтова позначка «збережено»/зірочка). Є тільки в Chathouse і Prime; у Golden такого немає (група 0 вище). Що кожен робить:
- Chathouse — вкладка
saved. Щохвилини прокручує до кінця список збережених діалогів і тримає його по кожній TU. Сам таск звідси не робить — по цьому списку працює окрема логіка PostChatMail: коли RU щойно заплатив за дію в чаті по такому діалогу і минуло ≥10хв без відповіді (і немає відкритого Unanswered) — створює NeedToWrite мейл. - Prime — criteria
bookmarked. Щохвилини прокручує закладених фаворитів, пропускає заблокованих і складає список по кожній TU (bookmarkDialogs) — це і є список фаворитів оператора; сам таск звідси не робиться. По цьому списку крутиться окремий сканерNoOnlineActiveFavorite: бере фаворита, який офлайн, останньою в діалозі писала TU (>12–16 год тому), його давно не чіпали листом і ще лишились ліміти (чат або лист) — і робить таск NeedToWrite. Це доповнення до онлайн-проходу: онлайн-фаворитів ловить[active, online](група 1), аNoOnlineActiveFavorite— тих, хто офлайн і замовк.
Як це переробити (обговоримо).
Список активних фаворитів потрібен, по суті, лише щоб знаходити й робити таски NeedToWrite. Ідея — тримати цей список у себе і по ньому робити таски. Випадки, коли фаворит дає NeedToWrite (усі треба покрити):
- Є куди писати (чат + ліміти). Дивимось діалог фаворита й ліміти → пишемо: онлайн з лімітами → NeedToWrite чат; офлайн, що замовк, з лімітами → NeedToWrite лист. Є всюди (Golden
chatHistory, Chathouseall+is_online, Prime[active, online]+NoOnlineActiveFavorite). - Післячатове. Після платного чату (≥10хв, без відповіді) → NeedToWrite лист. Лише Chathouse (
PostChatMail). - Після оплати листа. RU оплатив/прочитав наш лист → NeedToWrite лист. Golden (
EmailRead/OpenAttach) і Chathouse (inmail_read), обидва зі статистики; у Prime детальної статистики нема → цього шляху нема.
Питання:
- Список фаворитів — статистика (Golden/Chathouse: платив за 7 днів) та Prime: ≥11 платних дій
- Перевірка онлайну — Golden одним запитом (список онлайн-RU), Prime батч
checkMenOnline, Chathouse окремого апі нема (онлайн видно лише в списку діалогів). - Дістати діалог (чат+лист) по парі TU+RU — по суті скрізь два запити (чат окремо, листи окремо): Golden
chatHistory+getMail; ChathousegetDialogMessages(чат) +getInmailsChain(листи); Prime — чат і листи різними запитами. Chathouse-специфіка лише в тому, що список діалогів одразу показує обидва ліміти в одному пункті.
4. Ще два Prime-специфічні проходи:
criteria [active](→ OpenLimits) — потроху (по 15 за раз, крок за кроком назад до 7 днів) проходить активні діалоги і шукає ті, де останнє повідомлення системне (знак, що ліміти щойно відкрились) і ліміти справді є → таск «відкрились ліміти».criteria [](усі діалоги) →mailTaskPrime. Це не один механізм, а три, зшиті в один скан усіх діалогів:- Бутстрап фаворитів (лише перший логін TU) — глибоко читає чат-історію (не листи!) кожного діалогу, рахує платні повідомлення від RU. Єдиний спосіб Prime визначити фаворитів (статистики нема). Поріг ≥11 рахується по сумі по всіх TU (глобальний профіт RU), і саме він пускає RU в глобальний кеш «якісних», який годує автостворення чатів (
CreatingChatService). - Сендер — автолист нефаворитам. Спрацьовує, коли по чату ліміти вже вичерпані, а на лист ще є. Якщо RU не фаворит — лист шле автомат, без оператора: RU лайкнув → шле безумовно; RU мовчить, а TU писала останньою ≥12год → шле лише якщо RU онлайн зараз (
checkMenOnline). - Таск LikeMail — фаворитам. Та сама ситуація (чат вичерпаний, лист є), але RU фаворит і щойно лайкнув → замість автолиста таск оператору написати самому (
unanswered2= LikeMail). Мовчазний фаворит сюди не потрапляє — його добирають онлайн-/офлайн-проходи фаворитів.
- Бутстрап фаворитів (лише перший логін TU) — глибоко читає чат-історію (не листи!) кожного діалогу, рахує платні повідомлення від RU. Єдиний спосіб Prime визначити фаворитів (статистики нема). Поріг ≥11 рахується по сумі по всіх TU (глобальний профіт RU), і саме він пускає RU в глобальний кеш «якісних», який годує автостворення чатів (
Висновок: архітектурно — один скрол-сервіс (проходить поверхню, віддає потрібні діалоги) + таск-сервіс (з діалогу робить таск). Різниця лише в тому, як діставати діалоги: Golden — бере свій список фаворитів і питає кожного окремо; Chathouse — проходить вкладку (чат і лист в одному діалозі); Prime — проходить по criteria (чат і листи окремо). Головний невирішений вузол — фаворити + перевірка онлайну: статистика (Golden/Chathouse) проти скрол-підрахунку (Prime), і зручного апі «хто з фаворитів онлайн» немає в Chathouse.
Скрол-логіки — що крутимо і що знаходимо:
| Проєкт | Що крутимо (запит) | Знаходить | Каданс | Глибина |
|---|---|---|---|---|
| Golden | список онлайн-фаворитів + chatHistory по кожному | Unanswered / NeedToWrite чат | 60с | снапшот останнього повід. (без пагінації) |
| Golden | список фаворитів (статистика) + getMail по кожному | Unanswered / NeedToWrite мейл | 60с | снапшот останнього листа |
| Chathouse | вкладка all + is_online | NeedToWrite чат/мейл | 60с | до кінця (курсор next, поки стор. ≥50) |
| Chathouse | вкладка new | Unanswered чат/мейл, Like, OpenLimits | 60с | до кінця |
| Chathouse | вкладка saved (фідер) | — (годує PostChatMail) | 60с | до кінця |
| Prime | criteria [active, online] | NeedToWrite чат (online) | 120с | до кінця (limit 40) |
| Prime | criteria unanswered | Unanswered чат, Like | 60с | до кінця (40) |
| Prime | пошта inbox_unanswered | Unanswered мейл | 60с | 1 сторінка (15) |
| Prime | criteria active | OpenLimits | 120с | 1 стор./тік, stateful-курсор назад до 7 днів |
| Prime | criteria bookmarked (снапшот воркспейсу) | NeedToWrite лист (офлайн-фаворит) | 60с | до 7 днів (limit 50) |
| Prime | criteria [] (всі діалоги) | LikeMail | 600с | до кінця (20) + повна історія на 1-му проході |
Три патерни глибини: снапшот (Golden — не пагінує, тільки останнє повід.) · до кінця (Chathouse + більшість Prime — щотіка вся вкладка) · обмежене вікно (Prime openLimit і bookmarked — назад до 7 днів; openLimit ще й тягне курсор між тіками).
Запити по апі — скільки і як часто (те саме as-is, згруповано по запитах):
Chathouse — цикли на кожну TU:
| Апі-запит | Як часто | Глибина | Звідки |
|---|---|---|---|
getDialogs вкладка all + is_online | щохвилини | до кінця (стор. ~50) | OnlineTask |
getDialogs вкладка all повна | щохвилини | до кінця; з неї беруть вікно 2 год | WorkspaceRunner (чат-історія) |
getDialogs вкладка new | щохвилини | до кінця | UnansweredTask |
getDialogs вкладка saved | щохвилини | до кінця | WorkspaceRunner |
getInmailsChain по діалогу | щохвилини, тільки по кандидатах на мейл-таск; повтор по тому ж діалогу — не раніше TTL Redis-кешу (до 12 год) | один діалог | OnlineTask |
getDialogMessages по діалогу | рідко, точково («післячатовий» перший лист) | один діалог | OnlineTask |
вкладки all / saved | разово на логіні | до кінця | FavoriteWorker |
Разом: 4 пагіновані серії getDialogs щохвилини на кожну TU + точкові листи/чат-історія по кандидатах. Вкладка all ходить двічі на хвилину (повна містить у собі онлайн-фільтровану) — перший кандидат на об’єднання.
Prime — один цикл на оператора, всередині запити по кожній TU:
| Апі-запит | Як часто | Глибина | Звідки |
|---|---|---|---|
getDialogs criteria [unanswered] | щохвилини | до кінця, по 40 | unansweredMessageTaskPrime |
getMails inbox/unanswered | щохвилини (той самий тік) | 1 сторінка, 15 | unansweredMailTaskPrime |
getDialogs criteria [bookmarked] | щохвилини | по 50, до 7 днів | PrimeWorkspaceRunner |
getDialogs criteria [] | щохвилини | по 50, поки у вікні 4 год | PrimeWorkspaceRunner (чат-історія) |
getMails outbox | щохвилини | по 50, до 7 днів | PrimeWorkspaceRunner (мейл-історія) |
getDialogs criteria [active, online] | кожні 2 хв | до кінця, по 40 | onlineTaskPrime |
getDialogs criteria [active] | кожні 2 хв | 1 сторінка, 15; курсор живе між тіками, назад до 7 днів | openLimitTaskPrime |
getDialogs criteria [] (глибокий) | кожні 10 хв | до кінця, по 20; на першому проході + чат-історія по 100 до кінця | mailTaskPrime |
точкові: checkChatRestrictions, checkRelations, профілі, getDialogs limit 1 | по кандидатах усередині проходів | одиничні | скрізь |
Разом: 5 серій щохвилини на TU (unanswered + inbox_unanswered + bookmarked + [] 4 год + outbox), кожні 2 хв — ще дві ([active, online], [active]), кожні 10 хв — глибокий [].
Скрол — що саме крутимо (+ умови попадання в таск):
Unanswered чат.
- Golden — список онлайн-фаворитів, по кожному
chatHistory(снапшот останнього, без пагінації). Умова: останнє — від RU + чатready-to-send. - Chathouse — пагінує вкладку
new(курсорnext, до <50). Умова: останнє — платне вхідне. - Prime — criteria
unanswered(курсор, limit 40). Умова: останнє — платний тип +messagesLeft.
Unanswered мейл.
- Golden — скролу нема (від статистики);
getMailзвіряє: останній лист від RU, <1 рік, не заблокований. - Chathouse — та сама вкладка
new, якщо останнє = платний inmail. - Prime — пошта
inbox_unanswered(1 стор., limit 15). Умова:lettersLeft+ діалог не заблокований.
NeedToWrite чат.
- Golden — список активних онлайн-фаворитів,
chatHistoryпо кожному. Умова: останнє — від TU >10хв, не white-list, чатready-to-send. - Chathouse — вкладка
all+is_online. Умова: TU-останнє, є chat-ліміти, збережений/онлайн або >1год. - Prime — criteria
[active,online]: TU-останнє ≥2год +messagesLeft+ bookmarked. + сканерbookmarked(NoOnlineActiveFavorite): RU офлайн, останнє 12–16год, є ліміти.
NeedToWrite мейл.
- Golden — від статистики: активний фаворит онлайн, останній лист >12год або прийшов бонус, mail
ready-to-send. - Chathouse — вкладка all+online при mail-лімітах (решта шляхів — статистика/сокет).
- Prime — окремого типу нема (зводиться в NeedToWrite / обробляє мейл-сендер).
OpenLimits.
- Chathouse — вкладка
new: порожній/непроявлений діалог (id=null) або «liked each other» з відкритими лімітами. - Prime — criteria
active, stateful-курсор (1 стор./тік, limit 15, reset на 7 днях). Умова: останнє =system, єmessagesLeft, не заблокований, ≤7 днів.
OpenLimits VIP.
- Prime — не скрол: планувальник по нашому DB. Умова: леді активна +
canCreateChat, є ліміти, не частіше ніж 1 VIP / 2год на TU; + ручне.
Like.
- Chathouse — fallback у вкладці
new: вхідне = лайк + ліміти. - Prime — criteria
unanswered: останнє = like-тип +messagesLeft. LikeMail — усі діалоги ([], limit 20): like + bookmarked +lettersLeft, чат-ліміти вичерпані.
Typing — тільки сокет, скролу нема.
Статистика (є лише там, де є детальна статистика подій):
- Golden — temp-statistics:
EMAIL_SEND→ Unanswered мейл;EmailRead/OpenAttach→ NeedToWrite мейл (жене весь mail-блок). - Chathouse — Mongo-статистика:
inmail_read→ NeedToWrite мейл; spend-події → PostChatMail (2 з 4 mail-шляхів). - Prime — детальної статистики нема → статистичні шляхи неможливі. Тому mail Prime тягне сканом пошти/лімітів, а окремого NeedToWrite мейл узагалі нема.
Client-email таски (Golden UnansweredEmail) — окрема логіка, поза цим пунктом: зав’язана на зовнішні поштові акаунти леді (email-інбокс), а не на воркспейс-API сайтів. Описується окремо.
Залежить від: сесія TU, сокет, ліміти з API, фаворити, статистика (де є).
2. Сендери
Авто-надсилання інвайтів (чат/мейл) онлайн-RU, які замовкли — TU писала останньою, а RU не відповідає.
Golden — окрема, унікальна логіка (свої рушії, затримки й правила). Тут не зводимо — описується окремо.
Prime і Chathouse — по суті однакові. Спільна механіка:
- Рушій не самостійний — його годує скан онлайн-діалогів (Prime:
onlineTaskPrime~2хв чат +mailTaskPrime~10хв мейл; Chathouse:OnlineTask, самоперепланований). Кого слати — вирішує скан. - Кого бере: діалог, де останнє від TU (не збережений), старше порогу, RU онлайн і з лімітами, не заблокований і не в блек-листі.
- Один рушій, чат-перший → мейл-фолбек: чат-інвайт, якщо минула затримка + є невідправлений чат-шаблон + чат-ліміт; інакше мейл, якщо чат-шаблонів/лімітів нема, минула мейл-затримка, є мейл-шаблон + лист-ліміт.
- Тротлінг на пару TU+RU: історія відправок у БД (остання дата) + Redis-ключ; затримки різні (нижче).
- Інвайти: ланцюжок шаблонів на TU (чат[]/мейл[]); бере перший, якого ще не слали цьому RU (по черзі, без рандому).
- Первинний інвайт — без перевірки доставки: ланцюг рухається далі, лише поки RU не відповів (інакше діалог випадає зі скану) і поки попередня відправка успішна.
- Блек-лист: пара TU+RU з
isBlackList— перевірка перед самою відправкою (далі 10хв пропуск). Prime ще фільтрує глобальний блек-лист чоловіків у скані. - Побічне: запис в історію відправок, лічильник шаблону, лічильник автодій оператора, помітка «шаблони закінчились».
Різниці Prime vs Chathouse:
| Аспект | Prime | Chathouse |
|---|---|---|
| Затримка чат / мейл | 2год / 12год | 1год / 6год |
| Дод. дослання | нема | ≤2 таймовані (текст/стікер/фото) з перевіркою, що попереднє дійшло |
| Крос-TU кап на одного RU | нема | ≤5 TU за хвилину |
| Low-credit | — | окремий мейл-шаблон для RU зі spend 0–20; фото лише при spend 20+ |
| Мова інвайтів | — | лише латиниця |
| Медіа в мейлі | ≤10 фото + ≤10 відео | фото (крім low-credit) |
Тобто уніфікований сендер = цей спільний рушій + пер-сайт параметри (затримки, медіа-ліміти, low-credit, дод. дослання).
Залежить від: інвайти (контент), API відправки, ліміти, блек-лист.
3. Фаворити + чат/мейл-історія
Дві речі разом: хто для TU постійний RU (реальний фаворит) і чим наповнити колонку фаворитів — останнє повідомлення / історія чату й листів, щоб оператор бачив свіже.
Що дає сайт (ключова різниця):
- Prime, Chathouse — є апі фаворитів, профілів і останнього повідомлення в діалозі → простий рендер колонки фаворитів + готова чат/мейл-історія.
- Golden — сайт не дає нічого з цього: нема апі фаворитів, профілів, останнього повідомлення, чат-історії. Тож усе тримаємо й оновлюємо в нас (фаворити — зі статистики, профілі — зберігаємо самі).
Ідеї, як звести (чернетка — обговорити):
- Список фаворитів тримати в нас. Формуємо/оновлюємо його у себе; на логіні лише проставляємо актуальний список на апі сайту (де воно є), щоб потім зручно тягти з апі — але в самих логіках апі-версію не використовувати.
- Останнє повідомлення в колонці рендерити в нас. Спочатку його нема; щойно прийшов лист або ми відкрили чат/лист — підставляємо в систему найсвіжіше. Так тримаємо псевдоісторію колонки без окремого апі.
- Чат-історія Golden — зібрати штучно з історії тасків і сендера (апі чат-історії нема).
Залежить від: партнерське API фаворитів / діалогів (де є), власне сховище (де нема — Golden).
4. Створення діалогів
Проактивно завести новий платний чат з онлайн-RU, поки є вільні ліміти.
- Prime — підсистема
CreatingChat: планувальник (2хв) для кожної TU зcanCreateChatі вільними лімітами бере свіжого онлайн-RU з пулу «якісних» (глобальний ≥11-пул + зовнішня агенція), звіряє онлайн (checkMenOnline) і підкидає оператору таскopenLimitVip«написати першому»; сам чат відкривається, коли оператор відповість. Обмеження: ≤1 VIP / 2год на TU, дедуп, ліміти з апі (оновлення раз на добу).readyCreateChat— сигнал показати кнопку «створити чат», коли тасків нема. - Golden — сенсу нема;
- Chathouse — проактивного нема; діалог виникає неявно (вгорі) при першій відправці; у списку є порожні заготовки (
id=null) → таск-нагадування написати першим.
Залежить від: API створення/лімітів, список онлайн-RU, пул кандидатів.
5. Профіль RU (id, ім’я, аватар, вік)
Профіль чоловіка (id, ім’я, аватар, вік) для картки таска/діалогу й колонки фаворитів. Питання: де взяти весь профіль за раз, а де апі нема — тримати свій стор і оновлювати. Плюс критичний випадок: RU написав TU вперше, у фаворитах/на фронті профілю ще нема, а рендерити треба.
Звідки взяти весь профіль (і коли його ще нема):
- Chathouse — у списку діалогів АБО в самій сокет-події.
getDialogsнесеcontact(id/ім’я/аватар/вік); а коли RU пише по сокету — подія (Send→contact,NewNotification→sender) уже містить повний профіль, тож доганяти нічого не треба (навіть новий RU рендериться з події). На вимогу —getProfile(ulid). Стор не потрібен. - Prime — окремий батч
getManProfiles([ids]). ІgetDialogs, і сокет-подія дають лише id → профіль тягнеться живцем (пачкою по 50 у скані або по одному id при сокет-таску). Стор не потрібен. - Golden — картку наповнює зі свого стору. Стор годується харвестом онлайн-списку чоловіків із сайту (у вкладці TU, ~5хв). Профіль по id теж є — запит
getMan(оф-апі) віддає повний профіль, але зараз його смикають лише для попапа профілю й бекфілу аватара при відкритті діалогу, а не для картки таска. Вузьке місце — перший контакт: нового RU може ще не бути в сторі (харвест бачить лише онлайн), аgetManдля картки не викликають → профіль порожній, поки діалог не відкриють (фікс дешевий: смикнутиgetMan(id)при наповненні картки).
Як зараз профіль потрапляє в чат-історію / фаворитів / таски:
- Prime — бек збагачує кожен прохід (
getManProfiles→interlocutor{ім'я, аватар}); таск — черезgetTaskUsers→getManProfiles. - Chathouse — їде прямо з діалогу (
contactу списку) в історію й фаворитів; таск — із того ж діалогу. - Golden — накладається з локального стору при рендері (
manId_api→ профіль зі стору); стор годується харвестом + бекфіломgetMan.
Орієнтир для проектування: де можна за раз — беремо звідти (Chathouse — з діалогу, Prime — батч по id); де апі нема — тримаємо стор і оновлюємо (Golden). Уніфікація = провайдер профілю з трьома реалізаціями: (1) inline з діалогу, (2) батч по id, (3) свій стор + добір по id для промахів. Головний ризик — Golden на першому контакті (порожня картка, поки не добрали getMan).
Залежить від: API профілю RU (де є), власний стор + добір по id (Golden).
6. Ньюзфід постів (Prime)
Тільки Prime (/newsfeed). Оператор вручну створює й публікує пости від імені TU (свій текст 100–1500 + фото), пости проходять модерацію; є трекер «яка TU сьогодні ще не постила». Автопостингу нема. Зворотний бік: коли RU лайкнув/відповів на пост, це вертається таском — like_newsfeed_post → Like, reply_newsfeed_post → Unanswered (звичайний таск-пайплайн). API: platform/news-feed/post/{create,send,list,delete}. Залежить від: API ньюзфіду.
7. RU заблокував / видалив профіль
Треба знати, що RU заблокував TU (щоб зняти таски/фаворитів і не гнати сендери в порожнечу) і що RU видалив профіль.
Блокування — сигнал у кожного свій:
- Golden — найпростіше: команда
blackList(оф-апі) віддає по TU плоский список id заблокувальників; полінг ~5хв. - Prime:
checkRelations(platform/connection/get) →blockedByInterlocutor— батчем по діалогах проходу (не по одному RU; точкові виклики лише на відкритті чату / сокеті / помилці відправки). Плюс міткаisBlockedу списку діалогів (не надійна на 100% → щопрохід досвіпують таски заблокованих) і RTM-сокетBlocked(реалтайм). - Chathouse: поле
blocked_by_ruна діалозі (getDialogs, полінг, без сокета).
Реакція скрізь схожа: помітити фаворита blocked, видалити/закрити таски цієї пари, виключити з нових тасків і з сендера (Golden і Chathouse ще логують історію блоків у ClickHouse).
Видалення профілю — сигналу нема ніде. У всіх трьох немає ні окремого апі, ні прапорця is_deleted на профілі чоловіка, ні сокет-події, ні окремого коду помилки. Видалення можна лише здогадатись: чоловік зникає зі списків / профіль повертається порожнім / відправка падає (Prime трактує це так само, як блок).
Орієнтир для проектування: блок = свій сигнал на сайт (Golden — список id, Prime — relations + сокет, Chathouse — прапорець у діалозі) → спільна реакція (зняти таски, виключити з сендера, помітити фаворита). Видалення доведеться виводити непрямо (падіння запиту / зникнення зі списків) — окремого сигналу не буде.
TODO (обговорити): як правильно вести обидва списки — «RU заблокував TU» і зворотний «TU заблокував RU» — і як їх оновлювати (де істина: сайт чи наш стор, як синхронізувати).
Залежить від: API статусів RU (блок), непряме виведення (видалення).
Побічні логіки
Дрібні / усталені логіки, що мають просто бути. Частина — тривіальні (повністю наше апі), частина — три «душні» списки, які треба розписати детально.
Прості — повністю наше апі, дизайну майже не треба:
- Перекладач — Electron → наше апі → наш сервер → DeepL (або AI); однаковий усюди.
- Нотатки оператора (+ AI-нотатки) — повністю наше апі, до сайтів не прив’язані → спільний сервіс.
- Імейли (клієнт-email канал) — зовнішні поштові акаунти TU (інбокс) → таск; повністю через наше апі/сервер. Поки лише Golden.
Тільки Golden:
- Стрім камер TU — трансляція анкети + трекінг інтервалів трансляцій.
- Збереження переглядів профіля — хто дивився анкету (→ ClickHouse).
Три «душні» — по порядку:
1. White-list — тільки Golden, список чат-сендера (per TU, manId_api).
- Робить: чат-сендер (FAV-трек) авто-пише тільки тим, хто в списку; поки RU у списку — оператор вручну писати не може (бот ним володіє).
- Наповнення: щологіну автозаповнюється неактивними фаворитами (останній контакт >7 днів), крім тих, хто вже дав дохід сьогодні; при
profit ≥ 10RU авто-виходить. - Керування зараз майже вимкнене: прибрати можна лише активного фаворита з малим балансом — неактивного (а список саме з них) вже не прибрати; додати — лише активного з малим балансом (
profit ≥ 10— ні). Тому сенс списку майже зник.
2. Black-lists — семантично 3 типи (Golden розмазав на 3 сховища, Chathouse/Prime — компактні поля):
- (a) RU заблокував TU — детект блокування (див. Тір 3 #7); по такому RU не працюють сендери/таски.
- (b) TU/оператор заблокував RU — ручний «не чіпати цього RU».
- (c) сендер-виключення — службовий список самого сендера (авто при помилках відправки).
Назви одного концепту різні: (b) = blockedByTU (Golden) = isBlackList (Chathouse/Prime).
- Chathouse: (b)
isBlackListна фаворита (оператор) → сендер не шле; (a) авто-blocked(окреме поле, для UI/детекту). Глобального нема. - Prime: (b)
isBlackList→ гейтить сендер; (a) авто-blocked— пишеться, але для гейту не читається (блок при таску бере живийcheckRelations); + глобальнийprime_men_black_list(по RU, наповнюється руками) — його юзають усі таск-ранери (скіпають цих RU). - Golden — 3 окремі сховища: (b)
blockedByTU— гейтить майже все (створення тасків, чат-сендер FAV, мейл-сендер FAV, інтервали); (a)golden_block_list(синк 5хв) — гейтить сендер + закриває мейл/чат-таски; (c) мейл-сендер має власні 2 списки (FAV/NEW, авто при помилці). Чат-сендер персистентного (c) не має (лише тимчасові стопи); глобального нема.
Орієнтир для проектування: звести все до 3 типів на пару TU+RU (a/b/c) + опційно глобальний по RU (як Prime, адмін-інструмент) — не плодити окремий список на кожен сендер. Назви уніфікувати.
3. Фрілоадери — «безкоштовний» RU, на якого шкода зусиль. Тільки Chathouse і Prime; у Golden концепту нема. Назва одна, а критерій і вплив різні:
- Chathouse — «платить лише бонусами». Ставиться: усі платежі RU — тільки безкоштовні кредити, реальних грошей не було (з 2025-03-21); глобально по RU (
isFreeProfit), перерахунок щотижня/щодня. Знімається: щойно заплатив реальні гроші — одразу. Впливає: виключає з мейл-тасків (NeedToWriteMail, PostChatMail) + UI-бейдж; сендер не чіпає. Суть: не писати листи тому, хто платить лише бонусами. - Prime — «мало платив» (
profit < 11). Ставиться: похідне відGlobalMan.profit(сумарна к-сть платних повід./листів по всіх TU); фрілоадер ⇔profit < 11(той самий поріг, що й «фаворит»); не зберігається — рахується на льоту. Знімається: автоматично приprofit ≥ 11. Впливає: лише UI-бейдж, тасків/сендера не гейтить. (Відсів по грошах у Prime робить інверсія:profit ≥ 11= «якісний» → лише таких бере авто-створення чатів.) Суть: мітка «чатиться, але не платить».
Головна різниця: Chathouse дивиться на вид оплати (бонуси vs гроші) і ріже мейл-таски; Prime — на кількість платних (< 11) і це лише мітка. Одна назва — різний критерій і різний вплив; при уніфікації визначити єдино: що таке «фрілоадер» і що він гейтить.
Уже описані окремо, тут не дублюємо: айсбрейкери й перевірка версії/часу — у «Запуску»; стартовий чек-ліст статусів.
Відкриті рішення
- Перенос усього у Electron — Server Coupling (реле сесії → повністю клієнт).
- Тримання TU онлайн — єдина стратегія чи per-API.
- Data-sync — мінімальний спільний контракт на всі проекти.
- Панель заробітку оператора (денна сума на фронт) — чи тримаємо в уніфікованому воркспейсі, чи це аналітика збоку.