diff --git a/TASKS/CHAT_PWA_HANDOFF.md b/TASKS/CHAT_PWA_HANDOFF.md new file mode 100644 index 0000000..a732835 --- /dev/null +++ b/TASKS/CHAT_PWA_HANDOFF.md @@ -0,0 +1,181 @@ +# Анонс для исполнителя (кратко) + +Ниже описан текущий статус ветки по функциям: +- PWA + FCM уведомления +- личные сообщения (вторая слева вкладка, "Личные сообщения") +- связи / близкие друзья (центральная вкладка) +- server-push события (в том числе закрытие сессии) + +## Что нужно проверить и довести до рабочего состояния +1. **PWA/FCM**: регистрация service worker, получение FCM token, отправка token на сервер, получение foreground/background уведомлений. +2. **Личные сообщения**: отправка первого сообщения любому пользователю, входящие по WS, ACK, fallback в FCM, дедупликация на клиенте. +3. **Связи / близкие друзья**: поиск пользователя, добавление в близкие, обновление графа связей сразу после добавления. +4. **SessionRevoked**: если сессию закрыли с другого устройства, клиент должен корректно завершить локальную сессию и показать понятное состояние. + +## Главная цель handoff +Сделать так, чтобы все описанные сценарии стабильно работали end-to-end без ручных "подпинок". + +--- + +# Подробное ТЗ и технические детали + +## 1) Архитектура протокола и общие принципы + +### 1.1 Формат обмена +Используется JSON-over-WebSocket. +- Для запрос-ответ: `op + requestId + payload` +- Для server-push событий: те же поля, но `event=true`, `requestId` используется как eventId. + +### 1.2 ID сообщений/событий +ID генерируются в формате: +- `prefix-yyyyMMdd-HHmmss-SSS-random10` + +Реализация: `NetIdGenerator`. + +### 1.3 Роли каналов доставки +- **WS** — приоритетная доставка в активные сессии. +- **FCM** — fallback, если ACK по WS не получен или WS-сессия отсутствует. + +--- + +## 2) PWA + FCM + +## 2.1 Что уже добавлено +### Клиент +- `shine-UI/manifest.webmanifest` +- `shine-UI/firebase-messaging-sw.js` +- `shine-UI/js/services/pwa-push-service.js` +- `shine-UI/index.html` содержит placeholders: + - `window.__SHINE_FIREBASE_CONFIG__` + - `window.__SHINE_FIREBASE_VAPID_KEY__` + +### Сервер +- API `UpsertPushToken` +- Таблица `user_push_tokens` +- Серверный FCM sender (legacy HTTP): `FcmPushSender` +- Конфиг: `fcm.server.key` в `application.properties` + +## 2.2 Как должно работать (целевое поведение) +1. Клиент после авторизации регистрирует SW. +2. Просит permission на notifications. +3. Получает FCM token. +4. Если token новый/изменился — отправляет `UpsertPushToken`. +5. Сервер сохраняет token за конкретной сессией. + +## 2.3 Что проверить/доделать +- Синхронизация Firebase config между `index.html` и `firebase-messaging-sw.js`. +- Работа iOS Safari (PWA через Home Screen). +- Поведение при смене token. +- Надёжность `FcmPushSender` (таймауты, логирование ошибок ответа). + +--- + +## 3) Вторая слева вкладка: Личные сообщения / Чаты + +## 3.1 Продуктовая логика (как должно быть) +1. Открытие списка диалогов на вкладке "Личные сообщения". +2. Кнопка `+` открывает поиск пользователя по префиксу логина (`SearchUsers`). +3. **Первое сообщение можно отправить любому пользователю**, даже если он не контакт. +4. Если пользователь не в контактах — в чате показывается действие "Добавить в контакты". +5. Входящее сообщение может прийти: + - напрямую по WS (`IncomingDirectMessage`) + - через FCM (fallback) +6. На клиенте дедупликация должна быть по `messageId`. + +## 3.2 Что уже сделано технически +### Сервер +- `SendDirectMessage` +- `AckIncomingMessage` +- `direct_messages` таблица + DAO +- доставка по активным WS-сессиям + ожидание ACK + fallback в FCM + +### Клиент +- `authService.sendDirectMessage(...)` +- `authService.ackIncomingMessage(...)` +- WS client поддерживает server events (`onEvent`) +- В `app.js` обработка `IncomingDirectMessage` +- В `state.js` добавлены `incomingDedup`, `addIncomingMessage` + +## 3.3 Что глючит/что проверить +- Стабильность отображения новых чатов, если сообщение пришло от неизвестного пользователя. +- Согласованность списка диалогов и фактических сообщений. +- Поведение при быстрых дубликатах WS + FCM. +- Поведение при сетевых обрывах/повторном коннекте. + +--- + +## 4) Центральная вкладка: Связи / Близкие друзья + +## 4.1 Целевое поведение +1. Экран "Связи" загружает граф друзей (`GetUserConnectionsGraph`). +2. Кнопка "Добавить близкого друга" открывает модалку: + - поле логина/префикса + - кнопка "Поиск" + - кнопка "Назад" +3. Поиск идёт через `SearchUsers`. +4. По клику на найденного — подтверждение "Добавить? Да/Нет". +5. При "Да" вызывается `AddCloseFriend`, после успеха: + - закрыть модалку + - вернуться на экран связей + - обновить граф. + +## 4.2 Что уже сделано +- UI-flow модалки реализован на `network-view.js`. +- API `AddCloseFriend` добавлен на сервере. +- `ConnectionsStateDAO.upsertRelation(...)` добавлен для upsert связи FRIEND. + +## 4.3 Что проверить/доделать +- Валидация edge-cases (добавление самого себя, несуществующий логин). +- Корректность отрисовки графа после добавления. +- Согласованность данных с будущей "настоящей" записью в blockchain (сейчас MVP upsert в `connections_state`). + +--- + +## 5) SessionRevoked и мультисессии + +## 5.1 Целевое поведение +Если с другой сессии закрыли текущую сессию: +1. сервер шлёт событие `SessionRevoked` +2. клиент чистит локальную авторизацию +3. клиент возвращается в состояние неавторизованного входа. + +## 5.2 Что проверить +- Что событие приходит до закрытия socket. +- Что UX не "зависает" на промежуточном экране. + +--- + +## 6) API-операции (быстрый список) + +### Уже используемые/добавленные в ветке +- `SearchUsers` +- `ListContacts` +- `GetUserConnectionsGraph` +- `AddCloseFriend` +- `UpsertPushToken` +- `SendDirectMessage` +- `AckIncomingMessage` +- `CloseActiveSession` (с server event `SessionRevoked`) + +--- + +## 7) Минимальный чек-лист тестирования для нового исполнителя + +1. Авторизация пользователя A и B в разных браузерах/устройствах. +2. A отправляет первое сообщение B (без контактов) — должно уйти. +3. B получает по WS, отправляется ACK, fallback FCM не должен дублировать. +4. Выключить WS у B и проверить fallback FCM. +5. Вкладка "Связи": добавить близкого друга через поиск, проверить обновление графа. +6. Закрыть сессию B с другого устройства и проверить `SessionRevoked` UX. +7. Перезапуск клиента: проверка повторной регистрации push-токена только при изменении. + +--- + +## 8) Важное ограничение текущей реализации + +Некоторые части реализованы как MVP и требуют стабилизации: +- местами UI/состояние могут рассинхронизироваться; +- fallback WS->FCM может требовать донастройки таймингов и ретраев; +- `AddCloseFriend` сейчас пишет прямое состояние связи (upsert), а не полный blockchain-поток создания блоков. + +Это ожидаемо для handoff: задача следующего исполнителя — довести до production-стабильности.