# Анонс для исполнителя (кратко) Ниже описан текущий статус ветки по функциям: - 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-стабильности.