Таски — цільовий дизайн
Цільовий набір тасків єдиного воркспейсу: що це за таски, яке апі є в кожного проекту і як цим апі зробити кожен таск. Рішення і відкриті питання — Plan; as-is деталі проходів — Unification і Current State.
Цільовий набір (з обговорення)
Follow-up = колишній NeedToWrite. Таски сортуються по пріоритету (правила — питання 1 у Plan).
- 120 с · Unanswered message — вхідні повідомлення в чаті.
- 600 с · Unanswered mail — вхідні листи.
- 43200 с · Unanswered e-mail — вхідні імейли (з моменту отримання листа).
- 300 с · Follow-up message — нагадати про себе, щоб продовжити чат:
- після відповіді на unanswered — створюється рандомно через 60–180 с, лімітована кількість із шансом (1-й — 100%, 2-й — 75%, 3-й — 50%);
- логіку вести не в рамках сесії, а відносно діалогу;
- якщо RU офлайн — тримати логіку, поки не спрацює умова 2;
- останнє повідомлення від TU понад 3600 с тому;
- нотифікація від Chathouse.
- після відповіді на unanswered — створюється рандомно через 60–180 с, лімітована кількість із шансом (1-й — 100%, 2-й — 75%, 3-й — 50%);
- 900 с · Follow-up mail — нагадати про себе листом; по фрілоадерах не створюється:
- останній лист від TU понад 6 год тому;
- лист від TU прочитано RU;
- (післячатовий - можна писати офлайн РЮ) створюється через 600–1200 с після останньої відповіді на unanswered message, якщо після неї не було відправлених листів;
- якщо за 10 хв від RU прийшло понад 5 повідомлень — при закритті кожного unanswered message створюється з шансом 50%;
- нотифікація від Chathouse, якщо нема лімітів у чаті.
- 300 с · Open Limits:
- повністю порожній діалог з відкритими лімітами;
- останнє повідомлення — айсбрейкер;
- системне повідомлення про відкриття лімітів.
- 300 с · Open Limits (Captcha) — чат-реквести.
- 300 с · Like — будь-які безкоштовні дії типу лайка, вінка, розочки.
Приставка VIP — по всіх клієнтах, колір залежить від глобальних витрат RU за останні 30 днів: червоний — 300 · зелений — 900 $.
План реалізації
Unanswered message · 120 с
Вхідні повідомлення в чаті.
| Логіка | Golden (в Electron) | Chathouse | Prime |
|---|---|---|---|
| Сокет | receivePrivateMessage | Send | MessageSent |
| Колонка Unanswered з API | ❌ | check chat | check chat |
| При перегляді активних фаворитів онлайн | генерація Follow-up підстрахує | ❌ | ❌ |
check chat — перевірка колонки з апі при логіні, при реконекті сокета і, можливо, раз на 30 хв. Колонки різні: Chathouse — вкладка new, одна на чат і листи; Prime — окрема чат-вибірка unanswered.
Unanswered mail · 600 с
Вхідні листи.
| Логіка | Golden (в Electron) | Chathouse | Prime |
|---|---|---|---|
| Сокет | ❌ | Send (тип inmail_message) | email |
| Статистика | бонуси по типах EmailSend* | бонуси по типах inmail_send* | ❌ — статистики нема |
| Апі пошти | ❌ | ❌ | check mail |
EmailSend* — типи EmailSend / EmailSendSatellite / EmailSendBonusCoins: RU надіслав лист → перевіряємо цей діалог.
inmail_send* — типи inmail_send / inmail_photo_send / inmail_video_send: бонус за лист від RU → перевіряємо цей діалог. Зараз ці типи ніде не читаються — логіка буде нова. TODO: уточнити, на які типи точно реагуємо.
check mail — у Prime апі пошти окреме, не як у чаті; сокет є → перевірка тільки при логіні, а не постійна, як зараз на проді.
Follow-up message · 300 с
Нагадати про себе, щоб продовжити чат. За замовчуванням створюється тільки активним фаворитам онлайн, яких не заблокували ми чи вони нас.
| Логіка | Golden (в Electron) | Chathouse | Prime |
|---|---|---|---|
| Ланцюжок після unanswered | наша логіка | наша логіка | наша логіка |
| Останнє від TU понад 3600 с | наші фаворити; онлайн — апі онлайн-RU | наші фаворити; онлайн — зі скролу колонок | наші фаворити; онлайн — зі скролу колонок |
| Нотифікація сокетом | ❌ | new_notification | ❌ |
Фаворити й онлайн — фаворитів обчислюємо і тримаємо на своїй стороні (рішення — Plan); з апі оновлюємо тільки онлайн і хто кого заблокував. Golden має апі онлайн-RU; колонки Chathouse/Prime і так скролитимуться, щоб тримати онлайн RU, — з цих даних фільтруємо активних фаворитів онлайн, окремо для цього таска нічого не скролимо. Умову «останнє від TU понад 3600 с» перевіряємо прямо в цих проходах онлайну — окремого проходу для неї нема.
Ланцюжок — повністю наша логіка, стан ведемо по діалогу, не в рамках сесії. Список тасків і список повідомлень скоріш за все не збігатимуться 1 в 1 — важливі два часи: коли написав RU і коли TU його закрила (це і є жовтий Unanswered таск з часом закриття). Точка відліку ланцюжка — час закриття Unanswered message (теоретично він може бути через скільки завгодно від моменту, як написав RU). Від нього таск через рандомні 60–180 с; 2-й і 3-й кроки — ті самі 60–180 с від попередньої спроби; кроки лімітовані з шансом (1-й — 100%, 2-й — 75%, 3-й — 50%). Це три спроби створити таск, а не три гарантовані таски — шанс може не випасти, тасків може бути й один. Ланцюжок працює по тасках: якщо оператор пише сам, без таска, — не важливо, не враховуємо. У стані ланцюжка фіксуємо номер спроби та її час, і оновлюємо їх не при створенні таска, а при його фактичному закритті; якщо спроба без таска (шанс не випав) — у момент перевірки. Бо таск можна створити, не закрити і вийти; оператор може його ігнорувати; або RU вийде в офлайн і таск закриється як прострочений. Ланцюжок обмежений у часі: стосується фаворитів, які писали нам недавно, — до ~1 год; далі діалог переходить у логіку «понад 3600 с». Варіанти життя ланцюжка:
- новий Unanswered message стирає інфо про спробу й час — нова відповідь TU запустить новий ланцюжок (може повторюватись знову і знову);
- ланцюжок закрили повністю — всі кроки відпрацювали;
- RU офлайн у момент, коли таймер дійшов до таска — таск не створюємо, спробу й час не оновлюємо, таймер по колу не крутимо: щойно RU зайде в онлайн — таск одразу; так тримаємо, поки не спрацює умова «понад 3600 с»;
- у момент створення таска — знову перевірити онлайн RU і ліміти.
Нотифікація (Chathouse) — сокет пінгує (ONLINE_NOW / RECENT_PURCHASE) → пробуємо створити таск: якщо тасків по діалогу нема — створюємо; якщо діалог уже ведеться — нічого.
Відновлення після перезапуску — ланцюжки треба не лише вести в реальному часі, а й відновлювати після перезапуску програми. Джерело — історія тасків + інформація про спроби у фавориті. Приклад: в історії Unanswered message о 13:00 і закритий Follow-up о 13:30 → RU онлайн → рандомимо 60–180 с на наступний крок. Кроки при цьому розтягуються відносно повідомлення RU (від нього може пройти ~3 год, а від TU піде лише 3 повідомлення) — по ідеї це ок. Це має працювати і між операторами: перезайшов змінщик — ланцюжки підтягуються.
Пропозиції:
- Найпростіше — писати стан ланцюжка у фаворита (коли остання спроба і скільки їх було); але не хочеться оновлювати купу даних — подумати.
Сценарії (чернетка; за основу — історія тасків + стан ланцюжка у фаворита: «спроба N, час T»):
stateDiagram-v2 state "Очікування таймера" as wait state "Перевірка" as check state "Follow-up таск" as task [*] --> wait: TU закрила Unanswered — фіксуємо час закриття wait --> check: рандом 60–180 с минув check --> wait: RU офлайн — чекаємо заходу в онлайн, тоді таск одразу check --> wait: шанс не випав — спроба +1, час = перевірки check --> task: шанс випав (100/75/50%) — створюємо таск task --> wait: таск закрито — спроба +1, час = закриття wait --> [*]: 3 спроби або ~1 год — діалог далі веде «понад 3600 с» note right of wait Новий Unanswered у будь-який момент: стан стирається, ланцюжок піде заново end note
- Написав RU (новий Unanswered).
- Чистимо стан ланцюжка у фаворита: спроба й час → null.
- Це автоматично рве поточний таймер і логіку спроб.
- TU закрила Unanswered.
- Оновлюємо у фаворита час = закриття таска.
- Запускаємо таймер рандом 60–180 с.
- Перезайшли в програму до 1-го Follow-up.
- В історії — закритий Unanswered, у фаворита — час без спроб.
- Минуло < 180 с від часу закриття → рандомимо таймер і продовжуємо.
- Минуло від 180 с до ~1 год → таск одразу.
- Минуло понад ~1 год → ланцюжок не відновлюємо, діалог уже в логіці «понад 3600 с».
- 1-й Follow-up створено й закрито.
- При закритті: спроба 1, час = закриття; таймер на 2-у спробу.
- Таймер спрацював → шанс 75%: випав → створюємо таск; не випав → спроба 2, час = перевірки, таймер на 3-ю (50%).
- Таймер спрацював, RU офлайн.
- Таск не створюємо, стан не чіпаємо, таймер по колу не крутимо.
- Щойно RU зайде в онлайн — таск одразу.
- Невдала спроба → перезайшли.
- У фаворита вже зафіксовано спробу N і час перевірки.
- Відновлення як у сценарії 3 (якщо спроб < 3): < 180 с → таймер, до ~1 год → таск одразу.
- RU офлайн уже 15 хв на 1-й спробі.
- Чекаємо за сценарієм 5 — без повторних таймерів.
- Повернувся онлайн → таск одразу.
- Не повернувся до ~1 год → ланцюжок завершився, діалог підхопить «понад 3600 с» (їй теж потрібен онлайн).
- 1-й закрито, 2-а і 3-я — невдача.
- У фаворита послідовно: спроба 1 (час закриття) → спроба 2 (час перевірки) → спроба 3 (час перевірки).
- Ланцюжок завершено; стан лежить, поки RU не напише знову (сценарій 1).
- Посеред ланцюжка написав RU.
- Сценарій 1: стан чиститься, таймер рветься.
- TU закрила новий Unanswered → ланцюжок заново (сценарій 2).
- Блок посеред ланцюжка (ми RU чи RU нас).
- Логіка перевірки блоків видаляє відкритий таск і чистить таймер зі станом ланцюжка.
Рішення — з чого будується Follow-up message
Тип побудований тільки на історії тасків та оновленні онлайну — без додаткових запитів на апі:
- Історія тасків — знаходимо останній Unanswered message, бачимо, коли він закритий → фільтруємо діалог у пул для логіки ланцюжків.
- Фаворити — тут зберігаємо порядок ланцюжка і останній час його генерації (на випадок негативного рандому).
- Стан RU онлайн — окрема логіка тримає актуальний онлайн: Golden — окреме апі (15 с), Chathouse і Prime — сервіс скролу онлайн-діалогів (60 с).
З цього фільтруємо діалоги під умови ланцюжків: є час початку ланцюжка, час закриття останнього Follow-up, час, коли може створитись наступний, і розуміння, коли діалог перевалює за годину в іншу логіку. Умова «останнє повідомлення понад 60 хв» перевіряється там само — при скролі онлайну.
Follow-up mail · 900 с
Нагадати про себе листом. За замовчуванням створюється тільки активним фаворитам онлайн, яких не заблокували ми чи вони нас, і які не фрілоадери. Єдиний виняток з онлайну — післячатовий мейл-таймер: він може створити таск і для офлайн RU.
| Логіка | Golden (в Electron) | Chathouse | Prime |
|---|---|---|---|
| Лист від TU понад 6 год | скрол листів по активних фаворитах онлайн — getMail | скрол листів по активних фаворитах онлайн — getInmailsChain | скрол листів по активних фаворитах онлайн — апі пошти |
| Лист від TU прочитано RU | статистика: EmailRead / OpenAttachFileSatellite | статистика: inmail_read* | ❌ — статистики нема (питання 1) |
| Мейл-таймер після відповіді на unanswered | наша логіка | наша логіка | наша логіка |
| Понад 5 unanswered за 10 хв | наша логіка | наша логіка | наша логіка |
| Нотифікація сокетом (нема чат-лімітів) | ❌ | new_notification | ❌ |
inmail_read* — типи inmail_read / inmail_photo_read / inmail_video_read; сьогодні вже використовуються для мейл-тасків.
Фрілоадери — критерії з рішення у Plan: Chathouse — платить лише бонусами; Prime — менше 11 платних дій; Golden — «бонусні» фаворити (сума 0).
Мейл-таймер після відповіді — через 600–1200 с після останньої відповіді на unanswered message, якщо після неї не було відправлених листів. Логіка схожа на ланцюжки Follow-up message: і в реальному часі, і при перелогіні у нас є інфо про закритий unanswered message і про Follow-up mail після нього — додатково треба дивитись переписку листів, як в умові «понад 6 год». Наявність листа перевіряємо перед самим створенням таска, а не в момент створення таймера. Важливо: рахуємо саме відправку листа, а не мейл-таск — лист могли відправити й без таска. Працює і для офлайн RU — єдиний виняток із дефолту онлайн.
Понад 5 unanswered за 10 хв — рахуємо закриті unanswered-таски за 10 хв: перевалило за 5 → логіка вмикається, ні — вимкнена (спілкування по черзі і тригерить її; RU написав 3 підряд — це один таск). Коли ввімкнена — при закритті кожного unanswered просто намагаємось зробити Follow-up mail з шансом 50%, якщо це можливо. Ця умова і мейл-таймер постійно взаємодіють: закриття unanswered-таска тригерить і таймер, і пряме створення.
Нотифікація (Chathouse) — та сама new_notification, що в чатовому: якщо чат-лімітів нема → пробуємо мейл-таск.
Рішення — з чого будується Follow-up mail
- Історія тасків — закритий unanswered message і Follow-up mail після нього (мейл-таймер) + лічильник unanswered за 10 хв (вмикає «понад 5»).
- Активні фаворити онлайн — пул, по якому скролимо переписку листів (умова «понад 6 год»).
- Переписка листів — скрол по пулу + точкова перевірка наявності листа перед самим створенням таска.
- Статистика прочитання — Golden і Chathouse; Prime — питання 1.
- Стан RU онлайн — той самий сервіс, що в Follow-up message; виняток — мейл-таймер працює і для офлайн RU.
- Нотифікація Chathouse — сокет, коли нема чат-лімітів.
Питання 1 — прочитання листа на Prime
Статистики прочитання на Prime нема. Або цієї умови там не буде, або треба регулярно перевіряти всі листи і фіксувати прочитання в БД — складнувато. Вирішити.
Питання 2 — межі мейл-таймера після unanswered
Чи чистить новий unanswered message таймер і цю логіку (як у чатовому ланцюжку)?
Open Limits · 300 с
Порожній діалог з відкритими лімітами — написати першими. Golden концепту лімітів не має — тип не застосовується.
| Логіка | Golden (в Electron) | Chathouse | Prime |
|---|---|---|---|
| Порожній діалог / взаємний лайк | — | вкладка new — ще не створений діалог (id=null, без повідомлень) або взаємний лайк | — |
Останнє system + є ліміти | — | — | сокет створення діалогу + скрол active |
| Останнє — айсбрейкер | — | закоментована логіка LimitsAreOpenedAfterIcebreakerMessage — реанімувати й тестити | — |
Скрол Prime (as-is) — це не онлайн-колонка, а окремий прохід criteria active зі stateful-курсором: 1 сторінка (15 діалогів) за тік ~120 с, крок за кроком назад до 7 днів, потім курсор скидається. Сокет і скрол ведуть в одну умову: останнє повідомлення system + є ліміти + не заблокований, з VIP-дедупом; ліміти перевіряються живим запитом обмежень (значення в списку діалогів може бути кешоване). Сокет-подія «system opened limits» в коді є, але її обробка закоментована.
Chathouse — та сама вкладка new, що вже крутиться для Unanswered/Like, — окремого проходу не треба.
Айсбрейкер на Prime — логіки не буде. У списку діалогів айс — звичайне message без жодної мітки.
Питання 3 — як крутити Open Limits
По ідеї це теж перевіряємо, коли крутимо онлайн-колонку. Але на Prime порожні діалоги з типом
systemживуть у вибірціactive(не online) — лишаємо окремий скрол зі stateful-курсором, як зараз, чи чіпляємо до спільних проходів?
Like · 300 с
Будь-які безкоштовні дії типу лайка, вінка, розочки. Логіка 1 в 1 як в Unanswered message — тільки тип дії в сокеті чи в останньому повідомленні не смс, а лайк і подібні.
| Логіка | Golden (в Electron) | Chathouse | Prime |
|---|---|---|---|
| Сокет | receivePrivateMessage — 🌹 | Send — лайк по тілу повідомлення | MessageSent — лайк-типи |
| Колонка Unanswered з API | ❌ | check chat | лайки тільки в [] (all) |
Лайк-типи — Prime: likephoto / wink / like_newsfeed_post; Chathouse — лайк визначається по тілу повідомлення; Golden — текст 🌹.
Prime — лайки у вибірках. У вибірці active (скрол діалогів) лайків не буде — вони в [] (all): схоже, criteria [] доведеться крутити по-любому, а active тоді лишається тільки для Open Limits (system-діалоги). Що і як краще крутити — подумати (питання 5). TODO: as-is код ловить like-типи у вибірці unanswered — звірити, чи лайки справді туди не потрапляють.
Питання 4 — доля LikeMail (Prime)
У новому наборі LikeMail нема. Prime сьогодні має окремий таск: фаворит лайкнув, чат-ліміти вичерпані, лист ще є → таск написати листом. Зливаємо це в Like чи прибираємо? TODO: вирішити (мабуть так). Важливо: ця крутілка ще й перебирала дії фаворитів і оновлювала їх — поки це потрібно (див. питання 5).
Зведення проходів — що крутимо
Ціль — крутити якомога менше, щоб менше запитів на апі, але щоб логіки працювали правильно.
| Прохід | Крутимо | Для чого |
|---|---|---|
| Chathouse | ||
вкладка all + is_online | постійно | онлайн RU, фаворити, Follow-up «понад 3600 с» |
вкладка new | check chat | Unanswered чат/мейл, Like, Open Limits |
вкладка saved | не крутимо | — |
| Prime | ||
criteria [active, online] | постійно | онлайн RU, фаворити, Follow-up «понад 3600 с» |
criteria unanswered | check chat | Unanswered чат (Like — TODO, див. Like) |
пошта inbox_unanswered | check mail | Unanswered мейл |
criteria active | питання 3 | Open Limits |
criteria bookmarked | не крутимо — фаворити тепер у нас | — |
criteria [] (всі діалоги) | схоже, крутимо — лайки видно тільки тут (питання 5) | as-is годував LikeMail і бутстрап фаворитів |
Golden колонок не має — крутиться апі онлайн-RU і точкові запити по пулу фаворитів (chatHistory, getMail).
Питання 5 — criteria
[](всі діалоги) на PrimeЧи знадобиться прохід усіх діалогів для іншої логіки? As-is він робив три речі: одноразовий бутстрап фаворитів при першому логіні TU (повна історія), сендер-автолист нефаворитам і LikeMail (питання 4). Якщо фаворитів рахуємо у себе — бутстрап першого запуску TU все одно звідкись треба брати.
Питання 6 — таймери чи тіки
Відчуття, що проект треба будувати не на таймерах, як зараз (усе на setTimeout), а на тіках: робити тіки і по порядку звіряти логіки — але якось правильно. Проговорити.
Зв’язки
- Plan — рішення і відкриті питання воркспейсу.
- Unification — as-is механіка проходів і сокет-тригерів.
- Current State — as-is по проектах (таймери, закриття).