07-04-2026
Сделал вкладку параметры пользователя РАБОТАЮЩЕЙ Добавил - Локальный запуск - техническое задание 1 (доработать ui что бы RFYFKS работали)
This commit is contained in:
parent
0b7ad79032
commit
0c7d8fac02
220
TASKS/01-07.04.26-каналы-api/01-ТЗ-каналы.md
Normal file
220
TASKS/01-07.04.26-каналы-api/01-ТЗ-каналы.md
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
# Задача 01: Доработка вкладки «Каналы» (UI + API)
|
||||||
|
|
||||||
|
## Кратко и по делу
|
||||||
|
Нужно довести вторую вкладку «Каналы» до полностью рабочего состояния на реальных данных сервера.
|
||||||
|
|
||||||
|
Что должно работать:
|
||||||
|
- список каналов;
|
||||||
|
- вход в канал и чтение сообщений;
|
||||||
|
- вход в тред сообщения (история/ветка);
|
||||||
|
- ответ на сообщение;
|
||||||
|
- лайк/снятие лайка;
|
||||||
|
- подписка на пользователя;
|
||||||
|
- подписка на канал;
|
||||||
|
- видимое имя канала в формате `имя_пользователя/имя_канала`.
|
||||||
|
|
||||||
|
Запись любых новых сущностей делается через `AddBlock` с подписью на клиенте.
|
||||||
|
Чтение делается через 3 API:
|
||||||
|
- `ListSubscriptionsFeed`
|
||||||
|
- `GetChannelMessages`
|
||||||
|
- `GetMessageThread`
|
||||||
|
|
||||||
|
Техническая особенность (оставляем как есть):
|
||||||
|
- на экране каналов индикатор непрочитанного = общее число сообщений канала.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Подробное ТЗ
|
||||||
|
|
||||||
|
### 1. Цель
|
||||||
|
Сделать рабочий каналовый сценарий «от списка до треда», где чтение строится на RPC API, а запись действий пользователя — только через `AddBlock`.
|
||||||
|
|
||||||
|
### 2. Что уже есть в проекте
|
||||||
|
|
||||||
|
#### 2.1 UI (частично)
|
||||||
|
- Есть страницы:
|
||||||
|
- `channels-list`
|
||||||
|
- `channel-view`
|
||||||
|
- `add-channel-view`
|
||||||
|
- Есть запросы чтения в клиенте:
|
||||||
|
- `authService.listSubscriptionsFeed(...)`
|
||||||
|
- `authService.getChannelMessages(...)`
|
||||||
|
- `authService.getMessageThread(...)`
|
||||||
|
- Есть fallback на mock-данные при ошибках сервера.
|
||||||
|
|
||||||
|
#### 2.2 API/сервер (уже реализованы)
|
||||||
|
- `ListSubscriptionsFeed`
|
||||||
|
- `GetChannelMessages`
|
||||||
|
- `GetMessageThread`
|
||||||
|
- `AddBlock`
|
||||||
|
|
||||||
|
#### 2.3 Тесты
|
||||||
|
- Есть интеграционный тест API каналов: `IT_06_ChannelsApi`.
|
||||||
|
- Есть тесты генерации блоков каналов/связей: `IT_03_AddBlock_NoAuth`.
|
||||||
|
- Формат `AddBlock` и его сборка/подпись описаны в `AddBlockSender`.
|
||||||
|
|
||||||
|
### 3. Проблемы текущей реализации (что надо закрыть)
|
||||||
|
- Кнопки «подписаться на человека/канал» в списке каналов сейчас UI-only (модалка без реальной записи через `AddBlock`).
|
||||||
|
- `add-channel-view` пока не создает канал на сервере через `AddBlock` (`CreateChannelBody`), только делает `navigate`.
|
||||||
|
- `channel-view` добавляет пост локально (в память), а не отправляет блок `TEXT_POST` через `AddBlock`.
|
||||||
|
- Нет полноценного экрана треда сообщения с реальными `GetMessageThread` и действиями `ответить/лайк/убрать лайк` через блоки.
|
||||||
|
- Нет гарантированного отображения канала в требуемом формате `ownerLogin/channelName`.
|
||||||
|
|
||||||
|
### 4. Функциональные требования
|
||||||
|
|
||||||
|
#### 4.1 Список каналов
|
||||||
|
На вкладке «Каналы» отображать 3 группы:
|
||||||
|
- Мои каналы
|
||||||
|
- Каналы пользователей, на кого я подписан
|
||||||
|
- Каналы, на которые я подписан
|
||||||
|
|
||||||
|
Источник данных: `ListSubscriptionsFeed`.
|
||||||
|
|
||||||
|
Каждый канал показывать в формате:
|
||||||
|
- `ownerLogin/channelName`
|
||||||
|
|
||||||
|
#### 4.2 Открытие канала
|
||||||
|
При входе в канал:
|
||||||
|
- загрузить сообщения через `GetChannelMessages`;
|
||||||
|
- показать список сообщений в хронологическом порядке (по текущему параметру `sort`);
|
||||||
|
- оставить техническую особенность непрочитанных как есть.
|
||||||
|
|
||||||
|
#### 4.3 Открытие треда сообщения
|
||||||
|
При клике на сообщение:
|
||||||
|
- загрузить тред через `GetMessageThread`;
|
||||||
|
- показать `ancestors`, `focus`, `descendants`;
|
||||||
|
- из треда должны быть доступны действия:
|
||||||
|
- «Ответить»
|
||||||
|
- «Лайк»
|
||||||
|
- «Убрать лайк»
|
||||||
|
|
||||||
|
Запись действий — только `AddBlock`.
|
||||||
|
|
||||||
|
#### 4.4 Создание канала
|
||||||
|
В `add-channel-view` кнопка «Создать» должна:
|
||||||
|
- отправлять `AddBlock` с телом `CreateChannelBody`;
|
||||||
|
- после успеха возвращать к списку каналов и обновлять его.
|
||||||
|
|
||||||
|
#### 4.5 Подписки
|
||||||
|
- Подписка на пользователя: `AddBlock` с `ConnectionBody` подтип `CONNECTION_FOLLOW`, target = HEADER пользователя.
|
||||||
|
- Подписка на канал: `AddBlock` с `ConnectionBody` подтип `CONNECTION_FOLLOW`, target = root блока канала (`CreateChannelBody` или HEADER для канала `0`).
|
||||||
|
|
||||||
|
### 5. API (форматы)
|
||||||
|
|
||||||
|
## 5.1 ListSubscriptionsFeed (чтение)
|
||||||
|
Request:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"op": "ListSubscriptionsFeed",
|
||||||
|
"requestId": "...",
|
||||||
|
"payload": {
|
||||||
|
"login": "A1",
|
||||||
|
"limit": 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response (смысловые поля):
|
||||||
|
- `ownedChannels[]`
|
||||||
|
- `followedUsersChannels[]`
|
||||||
|
- `followedChannels[]`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5.2 GetChannelMessages (чтение)
|
||||||
|
Request:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"op": "GetChannelMessages",
|
||||||
|
"requestId": "...",
|
||||||
|
"payload": {
|
||||||
|
"channel": {
|
||||||
|
"ownerBlockchainName": "A1-001",
|
||||||
|
"channelRootBlockNumber": 0,
|
||||||
|
"channelRootBlockHash": ""
|
||||||
|
},
|
||||||
|
"limit": 200,
|
||||||
|
"sort": "asc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response (смысловые поля):
|
||||||
|
- `channel`
|
||||||
|
- `messages[]`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5.3 GetMessageThread (чтение)
|
||||||
|
Request:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"op": "GetMessageThread",
|
||||||
|
"requestId": "...",
|
||||||
|
"payload": {
|
||||||
|
"message": {
|
||||||
|
"blockchainName": "A1-001",
|
||||||
|
"blockNumber": 15,
|
||||||
|
"blockHash": "..."
|
||||||
|
},
|
||||||
|
"depthUp": 20,
|
||||||
|
"depthDown": 2,
|
||||||
|
"limitChildrenPerNode": 50
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response (смысловые поля):
|
||||||
|
- `ancestors[]`
|
||||||
|
- `focus`
|
||||||
|
- `descendants[]`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5.4 AddBlock (запись)
|
||||||
|
Любое изменение (создать канал, пост, reply, реакция, подписка) записывается через:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"op": "AddBlock",
|
||||||
|
"requestId": "...",
|
||||||
|
"payload": {
|
||||||
|
"blockchainName": "A1-001",
|
||||||
|
"blockNumber": 6,
|
||||||
|
"prevBlockHash": "<64-hex>",
|
||||||
|
"blockBytesB64": "<base64 full block>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Важно:
|
||||||
|
- `blockBytesB64` формируется на клиенте.
|
||||||
|
- Подпись блока формируется на клиенте приватным blockchain key пользователя.
|
||||||
|
- Перед добавлением блока клиент берет актуальный курсор цепочки с сервера.
|
||||||
|
|
||||||
|
### 6. Типы блоков для каналов и связей (через AddBlock)
|
||||||
|
- Создание канала: `CreateChannelBody`
|
||||||
|
- Пост/ответ: `TextBody` (`TEXT_POST`, `TEXT_REPLY`)
|
||||||
|
- Реакции: `ReactionBody` (лайк/снятие лайка)
|
||||||
|
- Подписки: `ConnectionBody` (`CONNECTION_FOLLOW`)
|
||||||
|
|
||||||
|
### 7. Критерии приемки
|
||||||
|
- Список каналов отображается с реальными данными API.
|
||||||
|
- Формат названия канала в UI: `ownerLogin/channelName`.
|
||||||
|
- Создание канала реально пишет блок и канал появляется после обновления.
|
||||||
|
- Отправка поста/ответа/реакций реально пишет блок и видна после перечитки API.
|
||||||
|
- Подписка на пользователя/канал реально пишет блок и отражается в выдаче.
|
||||||
|
- Переход в тред сообщения показывает реальные `ancestors/focus/descendants`.
|
||||||
|
- Непрочитанные в списке каналов = общее число сообщений (временное правило).
|
||||||
|
|
||||||
|
### 8. Локальный запуск (уже сделано)
|
||||||
|
Команда:
|
||||||
|
```bash
|
||||||
|
./gradlew startLocal
|
||||||
|
```
|
||||||
|
|
||||||
|
Что делает:
|
||||||
|
- чистит логи;
|
||||||
|
- билдит сервер;
|
||||||
|
- запускает локальный WS сервер;
|
||||||
|
- запускает локальный HTTP сервер клиента;
|
||||||
|
- открывает браузер по URL с параметром `localWsPort`.
|
||||||
25
TASKS/01-07.04.26-каналы-api/01-кратко-для-внешних.md
Normal file
25
TASKS/01-07.04.26-каналы-api/01-кратко-для-внешних.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Краткое описание задачи
|
||||||
|
|
||||||
|
Нужно сделать полностью рабочую вкладку «Каналы» в SHiNE.
|
||||||
|
|
||||||
|
Пользователь должен:
|
||||||
|
- видеть список каналов;
|
||||||
|
- открывать канал и читать сообщения;
|
||||||
|
- открывать тред сообщения;
|
||||||
|
- отвечать, ставить и убирать лайк;
|
||||||
|
- подписываться на пользователей и каналы.
|
||||||
|
|
||||||
|
Чтение данных идет через 3 API:
|
||||||
|
- `ListSubscriptionsFeed`
|
||||||
|
- `GetChannelMessages`
|
||||||
|
- `GetMessageThread`
|
||||||
|
|
||||||
|
Все действия записи делаются только через `AddBlock` с подписью на клиенте.
|
||||||
|
|
||||||
|
Формат имени канала в интерфейсе:
|
||||||
|
- `имя_пользователя/имя_канала`
|
||||||
|
|
||||||
|
Локальный запуск проекта:
|
||||||
|
```bash
|
||||||
|
./gradlew startLocal
|
||||||
|
```
|
||||||
@ -1,203 +0,0 @@
|
|||||||
# Анонс для исполнителя (кратко)
|
|
||||||
|
|
||||||
Ниже описан текущий статус ветки по функциям:
|
|
||||||
- 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-стабильности.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9) Тестовые логины для быстрой проверки
|
|
||||||
|
|
||||||
Для проверки работы системы можно использовать специальные тестовые аккаунты
|
|
||||||
после выполнения теста `Seed_TestDataPopulation` (он создаёт их через API):
|
|
||||||
|
|
||||||
- `A1`
|
|
||||||
- `A2`
|
|
||||||
- `A3`
|
|
||||||
- `A4`
|
|
||||||
- `A5`
|
|
||||||
- `A6`
|
|
||||||
- `A7`
|
|
||||||
- `A8`
|
|
||||||
- `A9`
|
|
||||||
- `A10`
|
|
||||||
|
|
||||||
Общий пароль для этих аккаунтов:
|
|
||||||
|
|
||||||
- `1`
|
|
||||||
@ -203,6 +203,7 @@ tasks.register('startLocal', Exec) {
|
|||||||
description = "Builds server, starts local WS server and local HTTP UI for end-to-end local testing"
|
description = "Builds server, starts local WS server and local HTTP UI for end-to-end local testing"
|
||||||
|
|
||||||
dependsOn shadowJar
|
dependsOn shadowJar
|
||||||
|
dependsOn cleanServerLogs
|
||||||
|
|
||||||
workingDir = rootDir
|
workingDir = rootDir
|
||||||
def wsPort = System.getProperty("localWsPort", "7070")
|
def wsPort = System.getProperty("localWsPort", "7070")
|
||||||
|
|||||||
@ -309,6 +309,7 @@ public final class Net_AddBlock_Handler implements JsonMessageHandler {
|
|||||||
|
|
||||||
// Нормализация: -1 не пишем в БД (для совместимости со старым TextBody)
|
// Нормализация: -1 не пишем в БД (для совместимости со старым TextBody)
|
||||||
if (prevLineNumber != null && prevLineNumber == -1) {
|
if (prevLineNumber != null && prevLineNumber == -1) {
|
||||||
|
lineCode = null;
|
||||||
prevLineNumber = null;
|
prevLineNumber = null;
|
||||||
prevLineHash32 = null;
|
prevLineHash32 = null;
|
||||||
thisLineNumber = null;
|
thisLineNumber = null;
|
||||||
|
|||||||
31
task/2.md
31
task/2.md
@ -1,31 +0,0 @@
|
|||||||
# Задача 2 — Проверка работы личных данных и статусов профиля (правая вкладка)
|
|
||||||
|
|
||||||
## Что реализовано
|
|
||||||
- На правой вкладке `Профиль` отображаются реальные пользовательские параметры, загружаемые через `ListUserParams`.
|
|
||||||
- Поля профиля:
|
|
||||||
- `first_name` (чтение с обратной совместимостью с `name`)
|
|
||||||
- `last_name`
|
|
||||||
- `address_physical`
|
|
||||||
- `address_web`
|
|
||||||
- `phone`
|
|
||||||
- Кнопка `Обновить` открывает форму редактирования и сохраняет изменения в пользовательские параметры блокчейна.
|
|
||||||
- Добавлены рабочие переключатели:
|
|
||||||
- `official`
|
|
||||||
- `shine`
|
|
||||||
- Для `official`/`shine` используется подтверждение перед записью, с предупреждением, что изменение идёт через блокчейн-параметры и требует подписи ключом пользователя.
|
|
||||||
- Если `official`/`shine` отсутствуют в параметрах, они считаются `no` по умолчанию.
|
|
||||||
|
|
||||||
## Что проверить вручную
|
|
||||||
1. Авторизоваться и открыть правую вкладку `Профиль`.
|
|
||||||
2. Убедиться, что поля профиля читаются из `ListUserParams`, а не из заглушек.
|
|
||||||
3. Нажать `Обновить`, изменить `first_name/last_name/address_physical/address_web/phone`, нажать `Сохранить`.
|
|
||||||
4. Убедиться, что после сохранения данные перечитались и обновились на экране.
|
|
||||||
5. Нажать `Официальный`, подтвердить изменение и проверить смену `no -> yes` (или `yes -> no`).
|
|
||||||
6. Нажать `Сияющий`, подтвердить изменение и проверить смену `no -> yes` (или `yes -> no`).
|
|
||||||
7. Обновить страницу и убедиться, что состояния `official/shine` и личные поля сохраняются.
|
|
||||||
8. Проверить кейс отсутствия `official/shine` в истории: UI должен показывать `no`.
|
|
||||||
|
|
||||||
## Ожидаемый результат
|
|
||||||
- Правая вкладка профиля работает с реальными данными пользователя.
|
|
||||||
- `official` и `shine` работают как настоящие параметры (yes/no), а не заглушки.
|
|
||||||
- После каждой записи UI делает повторный `ListUserParams` и показывает актуальное состояние.
|
|
||||||
Loading…
Reference in New Issue
Block a user