AppStatePatch

App State Patch

src/shared/interfaces/supervisor-stream.interface.ts

Контракт payload-у, який Electron шле тімліду через канал UPDATE_APP_STATE. Самозаживляючий частковий апдейт — будь-яка секція опційна, будь-яке поле всередині секції опційне.


Структура

interface IAppStatePatch {
  ladies?:    SectionDelta<ILadyReact, number>;
  favorites?: SectionDelta<IFavorite, string>;
  tasks?:     SectionDelta<IRunnerTask, string>;
  dialogs?:   IDialogsPatch;
  streams?:   IStreamsPatch;
  sleepMode?: boolean;
}
 
interface SectionDelta<T, IdT> {
  updated?: T[];
  removed?: IdT[];
}

Семантика секцій

СекціяТипСемантикаid-поле
ladiesSectionDeltaupsert-дельти ТЮladyId_api (number)
favoritesSectionDeltaupsert-дельти favorite-ів (через diff vs snapshot)favoriteId (Mongo _id, string)
tasksSectionDeltaЗаміна повного списку через updated: [...все]id (string)
dialogsobjectPing події про активність у чаті / маїлі / email
streamsobjectЗнімок поточного стану камер (snapshot-replace)
sleepModebooleanПоточний стан Sleep Mode оператора (snapshot-replace)

dialogs — пінги активності

interface IDialogsPatch {
  chat?:  Array<{ ladyId_api: number; manId_api: number }>;  // вхідне або вихідне chat-повідомлення
  mail?:  Array<{ ladyId_api: number; manId_api: number }>;  // вихідний лист
  email?: Array<{ ladyId_api: number; manId_api: number }>;  // вихідний email
}

Без даних — тільки сигнал: «в цьому діалозі є зміни». Frontend якщо відображає той самий діалог — рефрешить його через існуючий механізм. Якщо ні — може показати індикатор/бейдж.

streams — стан камер

interface IStreamsPatch {
  manStream: number[];                                            // manId_api що зараз з власним стрімом
  manWatching: Array<{ ladyId_api: number; manId_api: number }>;  // хто дивиться нашу ТЮ
}

Snapshot-replace: коли приходить — frontend заміняє свій локальний стан стрімів повністю на те що в payload. Не дельти, а повний знімок.

sleepMode — стан паузи оператора

sleepMode?: boolean;   // true — оператор у Sleep Mode, false — активний

Snapshot-replace: якщо поле є в payload — frontend замінює свій стан на це значення. Якщо нема — не чіпає. Initial snapshot завжди містить поточне значення.


Frontend reducer

Для всіх трьох CRUD-секцій (ladies, favorites, tasks):

ОпераціяДія на стороні supervisor frontend
updatedUpsert by id — додати якщо нема, замінити якщо є
removedВидалити з store за id

Семантика updated — «ось стан цієї сутності зараз». Якщо id раніше не було — додаємо, якщо був — замінюємо.

Для dialogs — frontend дивиться чи відкритий той діалог; якщо так — рефрешить дані з backend-у через існуючий ендпоінт. Якщо ні — може просто підсвітити в списку.

Для streams і sleepMode — frontend заміняє локальний state повністю на те що в payload.


Обгортка на wire

IAppStatePatch стискається через compressData (gzip + base64) і кладеться в IClientCommand.data:

interface IClientCommand {
  messageId: string;
  event: ClientCommand;              // завжди 'updateAppState' для цього потоку
  data: string;                      // compressed IAppStatePatch
  favoritesHaveContacts?: boolean;
}

favoritesHaveContacts — флаг для оптимізації на голдені. Виставляється true якщо в favorites.updated є хоч один fav з contactDetails?.status === 'Yes'. Голден читає прапор:

  • false → проксі-ить compressed payload без розпаковки
  • true → розпаковує, прокачує favorites через email-enrichment, пакує назад

Деталі — у favoritesHaveContacts флаг.


Чому одне UPDATE_APP_STATE event для всього

Раніше було два events — APP_STATE (повний snapshot на старті спостереження) і UPDATE_APP_STATE (дельти). Об’єднали в один → frontend має один reducer, initial snapshot — це просто {section: {updated: [...все]}}.

Прибрали асиметрію між форматами і одне місце входу.


Зв’язки

  • Шле: SupervisorStreamService
  • Канал: StackSocket (event UPDATE_APP_STATE)
  • Споживає: supervisor frontend (через golden workspace-проксі)
  • Enrichment favorites з контактами — на голдені, активується через favoritesHaveContacts флаг