diff --git a/AGENTS.md b/AGENTS.md index 2019fbc4..350f9226 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,43 +38,43 @@ - В git добавлять исходники, lock-файлы, настройки проекта и документацию Solana-модуля, но не добавлять локальные ключи, `.git`, `.idea`, `.gradle`, `target`, `node_modules`, `test-ledger`, логи, временные run-отчёты и `.env`-конфиги. - Для Solana deploy/push использовать правила из локального `shine-solana/shine/AGENTS.md`; не смешивать deploy Solana-модуля с `deployServer`/`deployUI` основного проекта. - Для регистрации пользователей в Solana (программа `shine_users`) единая актуальная инструкция по деплою/инициализации, адресам программ, и куда их прописывать в UI/сервере находится в: - - `Dev_Docs/Инициализация_Solana_регистрации/README.md` + - `docs/Инициализация_Solana_регистрации/README.md` - Этот файл считать основной справкой (single source of truth) по деплою и первичной инициализации Solana-регистрации в текущем проекте. - Актуальная архитектурная справка по устройству Solana-программ, PDA-счетам, ролям DAO и движению средств находится в: - - `Dev_Docs/Solana_Architecture/README.md` + - `docs/Solana_Architecture/README.md` - Документ формата пользовательской PDA-записи `shine_users` находится в: - `shine-solana/shine/doc/formats/shine-user-pda-format-v.1.0.md` ## Документация блокчейна -- Актуальная документация по форматам блокчейна находится в `Dev_Docs/Blockchain/README.md`. +- Актуальная документация по форматам блокчейна находится в `docs/Blockchain/README.md`. - Это точка входа (оглавление), рядом расположены детальные файлы по форматам, типам каналов и командным сообщениям. -- При любом изменении кода, связанного с блокчейном (формат блока, типы каналов, правила чтения/записи, команды), обязательно обновлять соответствующие документы в `Dev_Docs/Blockchain/`. -- Дополнительно обязательно вести `Dev_Docs/Blockchain/CHANGELOG.md`: дописывать изменения построчно с указанием даты/времени и хэша коммита, после которого внесено изменение. +- При любом изменении кода, связанного с блокчейном (формат блока, типы каналов, правила чтения/записи, команды), обязательно обновлять соответствующие документы в `docs/Blockchain/`. +- Дополнительно обязательно вести `docs/Blockchain/CHANGELOG.md`: дописывать изменения построчно с указанием даты/времени и хэша коммита, после которого внесено изменение. - Перед любым изменением формата блокчейна обязательно заранее предупреждать пользователя, что формат будет изменён. - Изменять формат блокчейна можно только после явного подтверждения пользователя (без подтверждения формат не менять). - Добавление любых данных в блокчейн выполнять только через операцию `AddBlock`. - Перед каждым `AddBlock` обязательно проверять/актуализировать текущее состояние вершины блокчейна (`last global number/hash`) и использовать его при формировании блока. ## Документация личных сообщений (DM) -- Актуальная документация по логике личных сообщений находится в `Dev_Docs/Personal_Messages/Протокол_DM_v1.md`. -- Точный байтовый формат DM находится в `Dev_Docs/Personal_Messages/Формат_DM_v1.md`. +- Актуальная документация по логике личных сообщений находится в `docs/Personal_Messages/Протокол_DM_v1.md`. +- Точный байтовый формат DM находится в `docs/Personal_Messages/Формат_DM_v1.md`. - При любом изменении кода, связанного с личными сообщениями (формат подписанного DM-блока, типы DM-сообщений, правила доставки/ACK/read-receipt, роутинг по сессиям, UI-логика чатов), обязательно обновлять оба документа: - - `Dev_Docs/Personal_Messages/Протокол_DM_v1.md` - - `Dev_Docs/Personal_Messages/Формат_DM_v1.md` + - `docs/Personal_Messages/Протокол_DM_v1.md` + - `docs/Personal_Messages/Формат_DM_v1.md` - Логика личных сообщений в коде должна всегда соответствовать этим документам. - Документ по личным сообщениям обязан поддерживаться в актуальном состоянии. ## Документация API сервера -- Актуальная документация по публичному JSON/WebSocket API сервера находится в `Dev_Docs/API/`. -- При любом изменении серверного API/эндпоинтов/операций `op` обязательно обновлять соответствующие документы в `Dev_Docs/API/`. +- Актуальная документация по публичному JSON/WebSocket API сервера находится в `docs/API/`. +- При любом изменении серверного API/эндпоинтов/операций `op` обязательно обновлять соответствующие документы в `docs/API/`. - Перед изменением самого серверного API обязательно явно предупредить пользователя, какие операции, поля запросов/ответов или коды ошибок будут изменены, и запросить отдельное подтверждение. - Без явного подтверждения пользователя формат серверного API не менять; допускается только приведение документации в соответствие уже существующему коду. -- Если добавляется новая операция `op`, нужно обновить общий список операций в `Dev_Docs/API/09_Operations_Index.md` или создать его, если файла ещё нет. +- Если добавляется новая операция `op`, нужно обновить общий список операций в `docs/API/09_Operations_Index.md` или создать его, если файла ещё нет. ## Документация Figma -- Актуальная документация по переносу экранов SHiNE в Figma и обратному переносу из Figma в код находится в `Dev_Docs/Figma/`. -- Точка входа: `Dev_Docs/Figma/README.md`. -- Подробный рабочий регламент: `Dev_Docs/Figma/TRANSFER_UI_SCREENS.md`. +- Актуальная документация по переносу экранов SHiNE в Figma и обратному переносу из Figma в код находится в `docs/Figma/`. +- Точка входа: `docs/Figma/README.md`. +- Подробный рабочий регламент: `docs/Figma/TRANSFER_UI_SCREENS.md`. - Для экранов регистрации, входа и других чувствительных UI-flow по умолчанию переносить экраны в Figma по одному, а не пачкой, если пользователь отдельно не подтвердил иной способ. ## Версионирование @@ -124,8 +124,8 @@ - В этих записях искать поля `reason`, `failureStage`, `pcConnectionState`, `pcIceConnectionState`, `routeLabel`, `configuredTurnHosts*`, `reachableTurnHosts*`. ## Недопроверенные фичи (обязательно) -- Папка для учёта недопроверенных фич: `Dev_Docs/Pending_Features/`. -- По каждой новой доработке, которая требует ручной проверки, добавлять отдельный markdown-файл в `Dev_Docs/Pending_Features/`. +- Папка для учёта недопроверенных фич: `docs/Pending_Features/`. +- По каждой новой доработке, которая требует ручной проверки, добавлять отдельный markdown-файл в `docs/Pending_Features/`. - Рекомендуемый формат имени файла: `YYYY-MM-DD_HHMM_.md`. - Имена новых файлов и краткие описания фич по возможности писать на русском языке. - Внутри файла обязательно указывать: @@ -134,7 +134,7 @@ - ожидаемый результат; - статус (например: `pending`, `in_progress`, `done`). - После подтверждения, что фича проверена и работает корректно, соответствующий файл удалять. -- В `Dev_Docs/Pending_Features/README.md` вести краткий регламент и поддерживать актуальность. +- В `docs/Pending_Features/README.md` вести краткий регламент и поддерживать актуальность. ## Будущие фичи / TODO - Папка для задач, сознательно отложенных на будущее: `TODO/`. @@ -142,7 +142,7 @@ - Внутри планы разделены по горизонтам: `near/`, `medium/`, `far/` и тематическим подпапкам. - Если пользователь спрашивает, какие есть планы или что можно продолжить, сначала читать `TODO/README.md`, затем при необходимости конкретные файлы из подпапок. - Файлы из этой папки не считать активными задачами и не начинать реализацию без явной просьбы пользователя. -- Старую папку `Dev_Docs/Future_Features/` считать выведенной из использования и больше не использовать для новых записей. +- Старую папку `docs/Future_Features/` считать выведенной из использования и больше не использовать для новых записей. - Если часть кода временно отключена или закомментирована, либо удалена как временная заглушка, в TODO-файле подробно описывать: - какие файлы и участки отключены; - что осталось в коде как заготовка; diff --git a/Players/dimasol1/files/2026-05-30_agent_instructions_approval_task.md b/Players/dimasol1/files/2026-05-30_agent_instructions_approval_task.md index 238b3947..cfe05a4f 100644 --- a/Players/dimasol1/files/2026-05-30_agent_instructions_approval_task.md +++ b/Players/dimasol1/files/2026-05-30_agent_instructions_approval_task.md @@ -11,7 +11,7 @@ - Solana/Anchor-модуль `shine-solana/shine/`; - Telegram-агент-кодер `SHiNE-agent-bot-coder/`; - TURN-сервер; -- документация `Dev_Docs/`; +- документация `docs/`; - отдельные рабочие папки игроков `Players/`. Без явных инструкций агент может путать эти зоны: например, смешать деплой Solana с деплоем сервера, изменить код от имени игрока, не обновить документацию API/DM/блокчейна или неправильно трактовать файл инструкций. diff --git a/SHiNE-agent-bot-coder/AGENT.md b/SHiNE-agent-bot-coder/AGENT.md index a6394042..97eb8577 100644 --- a/SHiNE-agent-bot-coder/AGENT.md +++ b/SHiNE-agent-bot-coder/AGENT.md @@ -55,7 +55,7 @@ - `far/` - дальнее будущее без понятного срока. - Если пользователь спрашивает, какие есть планы или что можно продолжить, нужно смотреть эти три папки и отвечать кратким списком по горизонтам. - Файлы из `TODO/` не начинать реализовывать без явной команды пользователя. -- После реализации фичи, требующей ручной проверки, нужно добавить отдельный файл в `Dev_Docs/Pending_Features/`. +- После реализации фичи, требующей ручной проверки, нужно добавить отдельный файл в `docs/Pending_Features/`. ## Центр задач и предложений - Сервис хранит простые задачи и предложения в `data/task_center/items.json`. diff --git a/SHiNE-server/AGENTS.md b/SHiNE-server/AGENTS.md index 93981473..357a5731 100644 --- a/SHiNE-server/AGENTS.md +++ b/SHiNE-server/AGENTS.md @@ -45,12 +45,12 @@ shine-UI/server-ui.html - `shine_users`: `SHiNEPr1APdAgNBteUyBXcNovaHctpSjUu8oH2ZJdN6` - `shine_payments`: `SHiPmXbM9Fs9khzRUW3TGKsS2W84aqaXTxs3ZkajW9v` -Подробнее: `Dev_Docs/Инициализация_Solana_регистрации/README.md` +Подробнее: `docs/Инициализация_Solana_регистрации/README.md` ## Синхронизация с партнёрскими серверами Сервер должен синхронизировать блоки блокчейна и DM с серверами-партнёрами из `sync_servers`. -Детали: `Dev_Docs/Blockchain/sync-between-servers.md` +Детали: `docs/Blockchain/sync-between-servers.md` ## Деплой diff --git a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/blockchain/Net_AddBlock_Handler.java b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/blockchain/Net_AddBlock_Handler.java index 02df74ac..298dc245 100644 --- a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/blockchain/Net_AddBlock_Handler.java +++ b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/blockchain/Net_AddBlock_Handler.java @@ -268,7 +268,7 @@ public final class Net_AddBlock_Handler implements JsonMessageHandler { } // Репосты временно отключены до будущей реализации. - // Точка возврата: Dev_Docs/Future_Features/2026-05-24_1140_репосты_в_каналах_и_тредах.md + // Точка возврата: docs/Future_Features/2026-05-24_1140_репосты_в_каналах_и_тредах.md if ((block.type & 0xFFFF) == 1 && (block.subType & 0xFFFF) == (MsgSubType.TEXT_REPOST & 0xFFFF)) { log.warn("AddBlock: repost_disabled (login={}, blockchainName={}, blockNumber={})", diff --git a/TASKS/01-07.04.26-каналы-api/01-ТЗ-каналы.md b/TASKS/01-07.04.26-каналы-api/01-ТЗ-каналы.md deleted file mode 100644 index 22688de5..00000000 --- a/TASKS/01-07.04.26-каналы-api/01-ТЗ-каналы.md +++ /dev/null @@ -1,220 +0,0 @@ -# Задача 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": "" - } -} -``` - -Важно: -- `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`. diff --git a/TASKS/01-07.04.26-каналы-api/01-кратко-для-внешних.md b/TASKS/01-07.04.26-каналы-api/01-кратко-для-внешних.md deleted file mode 100644 index e8c7e839..00000000 --- a/TASKS/01-07.04.26-каналы-api/01-кратко-для-внешних.md +++ /dev/null @@ -1,25 +0,0 @@ -# Краткое описание задачи - -Нужно сделать полностью рабочую вкладку «Каналы» в SHiNE. - -Пользователь должен: -- видеть список каналов; -- открывать канал и читать сообщения; -- открывать тред сообщения; -- отвечать, ставить и убирать лайк; -- подписываться на пользователей и каналы. - -Чтение данных идет через 3 API: -- `ListSubscriptionsFeed` -- `GetChannelMessages` -- `GetMessageThread` - -Все действия записи делаются только через `AddBlock` с подписью на клиенте. - -Формат имени канала в интерфейсе: -- `имя_пользователя/имя_канала` - -Локальный запуск проекта: -```bash -./gradlew startLocal -``` diff --git a/TASKS/02-12.04.26-web-push-direct-message/01-ТЗ-web-push-direct-message.md b/TASKS/02-12.04.26-web-push-direct-message/01-ТЗ-web-push-direct-message.md deleted file mode 100644 index 5460016e..00000000 --- a/TASKS/02-12.04.26-web-push-direct-message/01-ТЗ-web-push-direct-message.md +++ /dev/null @@ -1,153 +0,0 @@ -# Задача 02: Web Push + подписанный API отправки личных сообщений - -## Контекст (по текущему состоянию проекта) -- Уже есть JSON WebSocket API для личных сообщений: `SendDirectMessage`, `AckIncomingMessage`, `UpsertPushToken`. -- Сейчас серверный fallback-пуш реализован через FCM (`FcmPushSender`) и ключ `fcm.server.key`. -- Клиент уже регистрирует service worker и токен Firebase, затем аплоадит push token на сервер. - -## Цель -Добавить полностью рабочий сценарий доставки личных сообщений с приоритетом: -1) онлайн-доставка в активную WebSocket-сессию; -2) если не подтверждено — Web Push; -3) поддержать отдельный API отправки без авторизации, где доступ проверяется цифровой подписью Ed25519 по `clientKey` отправителя. - ---- - -## Предварительная спецификация подписанного пакета (v1) -> ВАЖНО: финально фиксируется после уточнений по endian/кодировкам/лимитам. - -Пакет (binary): -1. `prefix` — ASCII-константа, например `SHINE_MESSAGE`. -2. `toLoginLen` — 1 байт. -3. `toLogin` — ASCII, длина = `toLoginLen`. -4. `fromLoginLen` — 1 байт. -5. `fromLogin` — ASCII, длина = `fromLoginLen`. -6. `timeMs` — 8 байт (unix ms). -7. `nonce32` — 4 байта случайное число. -8. `messageType` — 4 байта. -9. `targetMode` — 1 байт: - - `0` = всем сессиям пользователя, - - `1` = конкретной сессии. -10. Если `targetMode=1`: - - `sessionIdLen` — 1 байт, - - `sessionId` — ASCII. -11. `messageLen` — 2 байта. -12. `messageBytes` — бинарные данные длиной `messageLen`. -13. `signature64` — 64 байта, Ed25519 подпись всего блока **без** `signature64`. - -Ограничения (первичный draft): -- общий размер пакета ≤ 4000 байт; -- логины/префикс/идентификатор сессии — ASCII; -- повторы отсекаются по `(fromLogin, timeMs, nonce32)` в окне TTL. - ---- - -## Сервер: что доработать - -### 1) Новый endpoint без авторизации -Операция (через WS JSON обертку) условно `SendSignedDirectMessage`: -- принимает пакет (base64 binary blob); -- парсит и валидирует формат; -- достает `fromLogin`, поднимает `clientKey` пользователя; -- проверяет подпись Ed25519; -- проверяет анти-replay (time window + nonce); -- отправляет сообщение по правилам маршрутизации; -- пишет результат (messageId, каналы доставки, причины недоставки). - -### 2) Маршрутизация доставки -Для `targetMode=1`: -- если целевая сессия онлайн и ACK пришел вовремя — успех; -- иначе отправка в Web Push этой сессии (если есть subscription). - -Для `targetMode=0`: -- обход всех сессий пользователя; -- сначала online delivery + ACK; -- для непринятых/офлайн — Web Push по соответствующим subscription; -- если subscription отсутствует — тихий skip. - -### 3) Миграция от FCM к Web Push -- добавить конфиг VAPID (`webpush.public.key`, `webpush.private.key`, `webpush.subject`); -- хранить на сервере не только token, а web-push subscription (endpoint + keys); -- сделать отправщик Web Push и заменить/расширить текущий `FcmPushSender`. - -### 4) Безопасность -- строгая ASCII-валидация логинов/sessionId; -- лимиты длины всех полей; -- rate limit на endpoint; -- audit-лог неуспешных проверок подписи/формата; -- защита от replay. - ---- - -## Клиент (shine-UI): что доработать - -1. Перейти на стандартный Web Push flow: - - регистрация service worker; - - `PushManager.subscribe(...)` с VAPID public key; - - отправка subscription на сервер (`UpsertPushSubscription` или расширение `UpsertPushToken`). - -2. Service worker: - - `push` handler получает payload целиком; - - показывает системное уведомление; - - при клике открывает/фокусирует нужный чат. - -3. Online-сообщения: - - сохранить текущий event-канал `IncomingDirectMessage`; - - обязателен ACK (`AckIncomingMessage` уже есть). - -4. Keep-alive: - - UI отправляет `Ping` раз в 60 секунд при активной сессии. - ---- - -## Документация -Сделать отдельный документ настройки Web Push: -- как сгенерировать VAPID ключи; -- какие параметры прописать на сервере и в UI; -- как проверить локально e2e (онлайн + офлайн пуш); -- ограничения payload и рекомендации по ретраям. - ---- - -## Этапы реализации (предложение) -1. Зафиксировать бинарный формат + валидации. -2. Реализовать серверный parser/validator/signature verify/replay guard. -3. Реализовать Web Push sender + storage subscription. -4. Подключить новый endpoint и маршрутизацию доставки. -5. Обновить UI (subscription + service worker + ping timer). -6. Добавить интеграционные тесты (online ACK / offline push / bad signature / replay / oversize). -7. Добавить документацию. - ---- - -## Что нужно уточнить до разработки -1. Endian для `timeMs/nonce/messageType/messageLen` (big-endian или little-endian). -2. Что именно подписывается: строго весь префикс..messageBytes (без подписи) — подтвердить. -3. Диапазон допустимых `messageType`. -4. TTL окна для анти-replay (например 5 минут / 15 минут). -5. Лимиты длин для login/session/message. -6. Можно ли временно оставить FCM как fallback, пока не готов Web Push в проде. -7. Формат сообщения в `messageBytes`: opaque bytes или UTF-8 строка. - - -## Статус реализации (12.04.2026) - -### Что уже внедрено в коде -- `SendDirectMessage` переведён на signed-binary payload (`blobB64`) без обязательной авторизации WS-сессии. -- Внедрён бинарный парсер пакета формата `SHiNE_msg + version(1) + ... + signature64`. -- Проверка подписи Ed25519 делается по `clientKey` отправителя через `shine-server-crypto` (`Ed25519Util`). -- Добавлен anti-replay guard `(from_login, time_ms, nonce)` с TTL 15 минут. -- Добавлено историческое хранилище `signed_direct_messages_history` с сырым пакетом `raw_packet`. -- Логика доставки: сначала WS+ACK, затем fallback на Web Push (по подписке конкретной session). -- Поле типа сообщения переведено на `uint16`, пока поддерживается только `1`. -- Для `targetMode=1` при несуществующей сессии возвращается `success` с `sessionNotFound=true` и `delivered=0`. -- UI переведён с Firebase/FCM на браузерный `PushManager.subscribe` + Service Worker `push`. -- Добавлен keep-alive ping из UI раз в 60 секунд при авторизованной сессии. - -### Что настроить в окружении -- В `application.properties` задать: - - `webpush.vapid.public` - - `webpush.vapid.private` - - `webpush.vapid.subject` -- В `shine-UI/index.html` задать публичный VAPID ключ в `window.__SHINE_WEBPUSH_VAPID_PUBLIC_KEY__`. - diff --git a/TODO/2026-06-26_1800_корректное_завершение_за_30с.md b/TODO/2026-06-26_1800_корректное_завершение_за_30с.md index d6e24e9b..8a786128 100644 --- a/TODO/2026-06-26_1800_корректное_завершение_за_30с.md +++ b/TODO/2026-06-26_1800_корректное_завершение_за_30с.md @@ -36,4 +36,4 @@ ## Какие документы потом обновить - `Deploy/`; -- `Dev_Docs/Blockchain/sync-between-servers.md`, если изменится поведение остановки/восстановления. +- `docs/Blockchain/sync-between-servers.md`, если изменится поведение остановки/восстановления. diff --git a/TODO/2026-06-26_1810_подключение_устройств_по_qr.md b/TODO/2026-06-26_1810_подключение_устройств_по_qr.md index 73b4f6bf..2e8419c2 100644 --- a/TODO/2026-06-26_1810_подключение_устройств_по_qr.md +++ b/TODO/2026-06-26_1810_подключение_устройств_по_qr.md @@ -24,6 +24,6 @@ QR-подключение других устройств сейчас есть ## Какие документы потом обновить -- `Dev_Docs/Solana_Architecture/README.md`; +- `docs/Solana_Architecture/README.md`; - `TODO/medium/2026-06-03_подключение_других_устройств_через_qr.md`; - `TODO/medium/2026-06-02_сессионные_homeserver_в_pda.md`. diff --git a/TODO/README.md b/TODO/README.md index 11562752..5475728f 100644 --- a/TODO/README.md +++ b/TODO/README.md @@ -12,16 +12,30 @@ - откуда продолжать; - какие документы потом надо обновить. - Это не активная разработка. Тут только план и контекст. -- Старую папку `Dev_Docs/Future_Features/` считать архивной и больше не использовать как источник новых задач. +- Старую папку `docs/Future_Features/` считать архивной и больше не использовать как источник новых задач. ## Текущие задачи - `2026-06-26_1800_корректное_завершение_за_30с.md` - дать сервису до 30 секунд на корректное завершение опасных операций перед рестартом. -- `2026-06-26_1805_межсерверный_ws_и_dm_sync.md` - постоянный server-to-server WebSocket, push новых блоков и DM, ACK и backfill. - `2026-06-26_1810_подключение_устройств_по_qr.md` - довести подключение других устройств по QR и перевести это в нормальные типизированные сессии. - `2026-06-26_1815_esp32_файловое_хранилище.md` - использовать ESP32 как личное файловое хранилище для переписок и вложений. -## Перенесённые планы из `Dev_Docs/Future_Features/` +## Децентрализация + +Текущий production-режим SHiNE считается односерверным. Задачи по нескольким серверам, Arweave и realtime PDA/Solana sync вынесены в `Децентрализация/` и не блокируют выкладку текущей версии на GitHub. + +- `Децентрализация/односерверный_production_режим.md` - границы текущей production-версии с одним сервером. +- `Децентрализация/запись_блокчейнов_в_arweave.md` - будущая запись/архивация блокчейнов в Arweave. +- `Децентрализация/realtime_pda_solana_sync.md` - будущая онлайн-синхронизация PDA и Solana. +- `Децентрализация/межсерверная_передача_сообщений.md` - будущая доставка сообщений между серверами. +- `Децентрализация/межсерверные_звонки.md` - будущая маршрутизация звонков между серверами. +- `Децентрализация/2026-06-26_1805_межсерверный_ws_и_dm_sync.md` - перенесённый старый план постоянного server-to-server WS и DM sync. + +## Новые фишки которые надо доделать + +- `Новые фишки которые надо доделать/Новая_контентная_модель_блокчейна/` - отложенная новая контентная модель блокчейна, не входящая в текущий односерверный production-релиз. + +## Перенесённые планы из `docs/Future_Features/` ### near diff --git a/TODO/far/2026-06-20_1639_homeserver_technical_commands_and_file_transfer.md b/TODO/far/2026-06-20_1639_homeserver_technical_commands_and_file_transfer.md index 4969ec50..3b328cb8 100644 --- a/TODO/far/2026-06-20_1639_homeserver_technical_commands_and_file_transfer.md +++ b/TODO/far/2026-06-20_1639_homeserver_technical_commands_and_file_transfer.md @@ -104,9 +104,9 @@ ## Какие документы нужно будет обновить при реализации -- `Dev_Docs/Blockchain/README.md` и связанные файлы, если изменятся типы служебных сообщений или форматы блокчейн-команд. -- `Dev_Docs/API/` если изменится публичный серверный API или появятся новые операции. -- `Dev_Docs/Personal_Messages/Протокол_DM_v1.md` если часть маршрутизации или подтверждений будет встроена в существующую логику доставки/сессий. +- `docs/Blockchain/README.md` и связанные файлы, если изменятся типы служебных сообщений или форматы блокчейн-команд. +- `docs/API/` если изменится публичный серверный API или появятся новые операции. +- `docs/Personal_Messages/Протокол_DM_v1.md` если часть маршрутизации или подтверждений будет встроена в существующую логику доставки/сессий. - Документацию по homeserver/ESP32, если появится пользовательская или сервисная файловая логика на устройстве. ## С какого места продолжать позже diff --git a/TODO/medium/2026-05-24_1140_репосты_в_каналах_и_тредах.md b/TODO/medium/2026-05-24_1140_репосты_в_каналах_и_тредах.md index d5098dbe..4d845621 100644 --- a/TODO/medium/2026-05-24_1140_репосты_в_каналах_и_тредах.md +++ b/TODO/medium/2026-05-24_1140_репосты_в_каналах_и_тредах.md @@ -58,7 +58,7 @@ ## Почему это не лежит в Pending_Features -`Dev_Docs/Pending_Features/` предназначена для фич, которые уже реализованы и ждут ручной проверки. +`docs/Pending_Features/` предназначена для фич, которые уже реализованы и ждут ручной проверки. Репосты сейчас не подходят под этот статус: они не должны проверяться как готовая фича, потому что пользовательский сценарий временно закрыт, а серверная запись новых репостов заблокирована. Поэтому старый pending-файл удалён, а задача перенесена сюда как будущая. @@ -82,11 +82,11 @@ - отображение `targetBlockchainName`, `targetBlockNumber`, `targetBlockHash`. 7. Добавить или обновить тесты на успешный репост и отказ некорректных target-полей. 8. Обновить документацию: - - `Dev_Docs/Blockchain/11_TEXT_Blocks.md`; - - `Dev_Docs/Blockchain/CHANGELOG.md`; - - `Dev_Docs/API/04_Add_Block_to_Blockchain_API.md`; + - `docs/Blockchain/11_TEXT_Blocks.md`; + - `docs/Blockchain/CHANGELOG.md`; + - `docs/API/04_Add_Block_to_Blockchain_API.md`; - документы API чтения каналов/тредов, если изменятся поля ответа. -9. После реализации перенести задачу из `TODO/` в `Dev_Docs/Pending_Features/` как фичу, требующую ручной проверки. +9. После реализации перенести задачу из `TODO/` в `docs/Pending_Features/` как фичу, требующую ручной проверки. ## Минимальный чек-лист ручной проверки в будущем diff --git a/TODO/medium/2026-05-25_1106_shine_balance_wallet.md b/TODO/medium/2026-05-25_1106_shine_balance_wallet.md index 6e35bca1..05ead4ad 100644 --- a/TODO/medium/2026-05-25_1106_shine_balance_wallet.md +++ b/TODO/medium/2026-05-25_1106_shine_balance_wallet.md @@ -47,10 +47,10 @@ ## Документы, которые обновить при реализации -- `Dev_Docs/Blockchain/`, если появятся или изменятся блоки баланса. -- `Dev_Docs/Blockchain/CHANGELOG.md`, если меняется блокчейн-формат. -- `Dev_Docs/API/`, если меняется серверный API. -- `Dev_Docs/Pending_Features/` - добавить файл ручной проверки после реализации. +- `docs/Blockchain/`, если появятся или изменятся блоки баланса. +- `docs/Blockchain/CHANGELOG.md`, если меняется блокчейн-формат. +- `docs/API/`, если меняется серверный API. +- `docs/Pending_Features/` - добавить файл ручной проверки после реализации. - Документацию Solana-регистрации, если баланс будет связан с Solana-модулем. ## Минимальная проверка в будущем diff --git a/TODO/medium/2026-05-26_0029_esp32s3_file_storage.md b/TODO/medium/2026-05-26_0029_esp32s3_file_storage.md index f2b1cb9e..a9b7f457 100644 --- a/TODO/medium/2026-05-26_0029_esp32s3_file_storage.md +++ b/TODO/medium/2026-05-26_0029_esp32s3_file_storage.md @@ -34,10 +34,10 @@ ## Документы, которые нужно обновить при возврате -- `Dev_Docs/Keys/README.md` -- `Dev_Docs/Personal_Messages/Протокол_DM_v1.md` -- `Dev_Docs/API/` -- `Dev_Docs/Blockchain/`, если появятся новые блоки или команды для файлов. +- `docs/Keys/README.md` +- `docs/Personal_Messages/Протокол_DM_v1.md` +- `docs/API/` +- `docs/Blockchain/`, если появятся новые блоки или команды для файлов. ## С какого места продолжать diff --git a/TODO/medium/2026-06-02_сессионные_homeserver_в_pda.md b/TODO/medium/2026-06-02_сессионные_homeserver_в_pda.md index 59489884..4b1af4c2 100644 --- a/TODO/medium/2026-06-02_сессионные_homeserver_в_pda.md +++ b/TODO/medium/2026-06-02_сессионные_homeserver_в_pda.md @@ -84,11 +84,11 @@ ## Что нужно обновить при реализации - `shine-solana/shine/doc/formats/shine-user-pda-format-v.1.0.md` -- `Dev_Docs/Solana_Architecture/README.md` -- `Dev_Docs/Инициализация_Solana_регистрации/README.md` -- `Dev_Docs/Keys/README.md` -- `Dev_Docs/Personal_Messages/Протокол_DM_v1.md`, если изменится адресация DM по типам сессий -- `Dev_Docs/API/`, если появятся новые серверные операции или изменятся ответы +- `docs/Solana_Architecture/README.md` +- `docs/Инициализация_Solana_регистрации/README.md` +- `docs/Keys/README.md` +- `docs/Personal_Messages/Протокол_DM_v1.md`, если изменится адресация DM по типам сессий +- `docs/API/`, если появятся новые серверные операции или изменятся ответы ## Что пока не делать diff --git a/TODO/medium/2026-06-03_подключение_других_устройств_через_qr.md b/TODO/medium/2026-06-03_подключение_других_устройств_через_qr.md index 61424ab8..b57d06f9 100644 --- a/TODO/medium/2026-06-03_подключение_других_устройств_через_qr.md +++ b/TODO/medium/2026-06-03_подключение_других_устройств_через_qr.md @@ -37,7 +37,7 @@ ## Что обновить при возврате -- `Dev_Docs/Pending_Features/README.md` +- `docs/Pending_Features/README.md` - `shine-UI/js/pages/connect-device-view.js` - `shine-UI/js/pages/device-qr-view.js` - `shine-UI/js/services/qr-key-transfer-service.js` diff --git a/TODO/near/2026-05-25_1106_wallet_topup_solana_arweave.md b/TODO/near/2026-05-25_1106_wallet_topup_solana_arweave.md index c4c06a9d..2d228ac6 100644 --- a/TODO/near/2026-05-25_1106_wallet_topup_solana_arweave.md +++ b/TODO/near/2026-05-25_1106_wallet_topup_solana_arweave.md @@ -58,8 +58,8 @@ ## Документы, которые обновить при реализации - Документацию UI/кошельков, если такая есть. -- `Dev_Docs/Pending_Features/` - добавить файл ручной проверки после реализации. -- `Dev_Docs/API/`, только если появится новый серверный API или логирование. +- `docs/Pending_Features/` - добавить файл ручной проверки после реализации. +- `docs/API/`, только если появится новый серверный API или логирование. ## Минимальная проверка diff --git a/TODO/near/2026-07-01_2205_восстановить_полную_логику_shine_login_guard.md b/TODO/near/2026-07-01_2205_восстановить_полную_логику_shine_login_guard.md index e1b3eeec..70f6d862 100644 --- a/TODO/near/2026-07-01_2205_восстановить_полную_логику_shine_login_guard.md +++ b/TODO/near/2026-07-01_2205_восстановить_полную_логику_shine_login_guard.md @@ -69,7 +69,7 @@ git show 0240db5:shine-solana/shine/programs/shine_login_guard/src/lib.rs - `shine-solana/shine/doc/programs/shine_login_guard.md` 5. Архитектурная документация: - - `Dev_Docs/Solana_Architecture/README.md` + - `docs/Solana_Architecture/README.md` 6. UI-логика precheck: - `shine-UI/js/pages/register-view.js` @@ -108,7 +108,7 @@ git show 0240db5:shine-solana/shine/programs/shine_login_guard/src/lib.rs 4. Проверить, что `build.rs` всё ещё генерирует `generated_dictionary.rs` в прежнем формате. 5. Сверить актуальность словарей в `src/dictionaries`. 6. Обновить `shine_login_guard.md` обратно под словарную логику. -7. Обновить `Dev_Docs/Solana_Architecture/README.md`. +7. Обновить `docs/Solana_Architecture/README.md`. ### Проверка после возврата diff --git a/TODO/near/2026-07-07_дм_v11_убрать_временную_очистку_signed_messages.md b/TODO/near/2026-07-07_дм_v11_убрать_временную_очистку_signed_messages.md index 54a734c6..e4b1bcb9 100644 --- a/TODO/near/2026-07-07_дм_v11_убрать_временную_очистку_signed_messages.md +++ b/TODO/near/2026-07-07_дм_v11_убрать_временную_очистку_signed_messages.md @@ -28,6 +28,6 @@ ## Какие документы потом обновить -- `Dev_Docs/Personal_Messages/Протокол_DM_v1.md`, если изменится стратегия миграции старой истории; -- `Dev_Docs/Personal_Messages/Формат_DM_v1.md`, если появится отдельное правило совместимости/конвертации; -- при необходимости `Dev_Docs/API/12_Direct_Messages_Push_Calls_API.md`, если затронется поведение backlog/доставки. +- `docs/Personal_Messages/Протокол_DM_v1.md`, если изменится стратегия миграции старой истории; +- `docs/Personal_Messages/Формат_DM_v1.md`, если появится отдельное правило совместимости/конвертации; +- при необходимости `docs/API/12_Direct_Messages_Push_Calls_API.md`, если затронется поведение backlog/доставки. diff --git a/TODO/2026-06-26_1805_межсерверный_ws_и_dm_sync.md b/TODO/Децентрализация/2026-06-26_1805_межсерверный_ws_и_dm_sync.md similarity index 70% rename from TODO/2026-06-26_1805_межсерверный_ws_и_dm_sync.md rename to TODO/Децентрализация/2026-06-26_1805_межсерверный_ws_и_dm_sync.md index 5e59f1af..362db242 100644 --- a/TODO/2026-06-26_1805_межсерверный_ws_и_dm_sync.md +++ b/TODO/Децентрализация/2026-06-26_1805_межсерверный_ws_и_dm_sync.md @@ -2,7 +2,9 @@ ## Зачем -Сейчас синхронизация между серверами работает в основном как periodic sync и one-shot push. Для нормальной репликации ещё нужен постоянный межсерверный канал: +Текущий production-режим SHiNE рассчитан на один основной сервер. Межсерверная синхронизация относится к будущей децентрализации и не должна блокировать выкладку односерверной production-версии. + +Сейчас синхронизация между серверами работает в основном как periodic sync и one-shot push. Для нормальной репликации в будущем ещё нужен постоянный межсерверный канал: - живое подключение к партнёру; - push новых блоков; @@ -35,7 +37,7 @@ ## Какие документы потом обновить -- `Dev_Docs/Blockchain/sync-between-servers.md`; -- `Dev_Docs/Personal_Messages/Протокол_DM_v1.md`; -- `Dev_Docs/Personal_Messages/Формат_DM_v1.md`; -- `Dev_Docs/API/`. +- `docs/Blockchain/sync-between-servers.md`; +- `docs/Personal_Messages/Протокол_DM_v1.md`; +- `docs/Personal_Messages/Формат_DM_v1.md`; +- `docs/API/`. diff --git a/TODO/Децентрализация/README.md b/TODO/Децентрализация/README.md new file mode 100644 index 00000000..2236815c --- /dev/null +++ b/TODO/Децентрализация/README.md @@ -0,0 +1,16 @@ +# Децентрализация + +Папка для задач, которые нужны для будущего режима с несколькими серверами, Solana/PDA-синхронизацией и внешним хранением данных. + +## Текущий статус + +Сейчас production-режим SHiNE считается односерверным: один сервер обслуживает пользователей, сообщения, звонки и запись данных. Задачи из этой папки не являются блокерами для выкладки текущего репозитория на GitHub и запуска одного production-сервера. + +## Задачи + +- `односерверный_production_режим.md` - зафиксировать границы текущей production-версии. +- `запись_блокчейнов_в_arweave.md` - вынести долговременную запись блокчейнов в Arweave. +- `realtime_pda_solana_sync.md` - сделать онлайн-синхронизацию PDA/Solana в реальном времени. +- `межсерверная_передача_сообщений.md` - реализовать доставку сообщений между серверами. +- `межсерверные_звонки.md` - реализовать маршрутизацию звонков между серверами. +- `2026-06-26_1805_межсерверный_ws_и_dm_sync.md` - старый план постоянного server-to-server WS и DM sync, перенесённый в контекст децентрализации. diff --git a/TODO/Децентрализация/realtime_pda_solana_sync.md b/TODO/Децентрализация/realtime_pda_solana_sync.md new file mode 100644 index 00000000..cf036690 --- /dev/null +++ b/TODO/Децентрализация/realtime_pda_solana_sync.md @@ -0,0 +1,30 @@ +# Realtime-синхронизация PDA и Solana + +## Зачем + +В будущем PDA-записи и Solana-состояние должны автоматически и быстро синхронизироваться с серверным состоянием, чтобы данные пользователей, homeserver-сессии и связанные записи не расходились. + +## Что сделать + +1. Определить, какие серверные события должны обновлять PDA. +2. Добавить очередь/воркер для надёжной отправки изменений в Solana. +3. Добавить периодическую сверку серверного состояния с PDA. +4. Добавить обработку ошибок, повторов и конфликтов версий. +5. Добавить мониторинг задержек и неуспешных Solana-транзакций. + +## Что учесть + +- Solana/Anchor-модуль находится в `shine-solana/shine/` и ведётся отдельно от основного server/UI deploy. +- Перед изменениями внутри Solana-модуля нужно читать `shine-solana/shine/AGENTS.md`. +- Основная инструкция по Solana-регистрации находится в `docs/Инициализация_Solana_регистрации/README.md`. +- Формат пользовательской PDA-записи описан в `shine-solana/shine/doc/formats/shine-user-pda-format-v.1.0.md`. + +## Документы, которые потом нужно обновить + +- `docs/Инициализация_Solana_регистрации/README.md`; +- `docs/Solana_Architecture/README.md`; +- `shine-solana/shine/doc/formats/shine-user-pda-format-v.1.0.md`, если меняется формат PDA. + +## Статус + +Отложено до этапа децентрализации. diff --git a/docs/ИТХ/README.md b/TODO/Децентрализация/ИТХ/README.md similarity index 100% rename from docs/ИТХ/README.md rename to TODO/Децентрализация/ИТХ/README.md diff --git a/docs/ИТХ/Спецификация_ИТХ_v1.md b/TODO/Децентрализация/ИТХ/Спецификация_ИТХ_v1.md similarity index 100% rename from docs/ИТХ/Спецификация_ИТХ_v1.md rename to TODO/Децентрализация/ИТХ/Спецификация_ИТХ_v1.md diff --git a/TODO/Децентрализация/запись_блокчейнов_в_arweave.md b/TODO/Децентрализация/запись_блокчейнов_в_arweave.md new file mode 100644 index 00000000..b0bf088f --- /dev/null +++ b/TODO/Децентрализация/запись_блокчейнов_в_arweave.md @@ -0,0 +1,29 @@ +# Запись блокчейнов в Arweave + +## Зачем + +Для будущей децентрализации нужно долговременное внешнее хранение блокчейнов, чтобы данные не зависели только от одного серверного диска. + +## Что сделать + +1. Определить, какие блокчейны и какие диапазоны блоков записываются в Arweave. +2. Зафиксировать формат пачки блоков, метаданных, ссылок и контрольных хэшей. +3. Добавить безопасный механизм публикации без хранения приватного JWK в git. +4. Добавить проверку уже загруженных диапазонов, чтобы не плодить дубли. +5. Описать восстановление блокчейна из Arweave при потере локальных данных. + +## Важные ограничения + +- Любое изменение формата блокчейна требует отдельного предупреждения и явного подтверждения пользователя. +- Добавление данных в блокчейн должно выполняться только через `AddBlock`. +- Секреты Arweave нельзя хранить в репозитории. + +## Документы, которые потом нужно обновить + +- `docs/Blockchain/README.md`; +- `docs/Blockchain/CHANGELOG.md`; +- документы deploy/секретов в `Deploy/`, если появятся новые параметры. + +## Статус + +Отложено до этапа децентрализации. diff --git a/TODO/Децентрализация/межсерверная_передача_сообщений.md b/TODO/Децентрализация/межсерверная_передача_сообщений.md new file mode 100644 index 00000000..6f45c7b0 --- /dev/null +++ b/TODO/Децентрализация/межсерверная_передача_сообщений.md @@ -0,0 +1,30 @@ +# Межсерверная передача сообщений + +## Зачем + +Когда у SHiNE появится несколько серверов, пользователи на разных серверах должны получать личные сообщения без ручной синхронизации и без привязки к одному центральному узлу. + +## Что сделать + +1. Определить протокол server-to-server доставки DM. +2. Добавить маршрутизацию получателя по серверу, user id, публичному ключу или PDA. +3. Добавить ACK, повторы, дедупликацию и backfill пропущенных сообщений. +4. Разделить realtime-доставку и восстановление истории. +5. Описать поведение при недоступности удалённого сервера. + +## Что учесть + +- Логика DM должна соответствовать документам в `docs/Personal_Messages/`. +- При изменении формата signed DM-блока или правил доставки нужно обновлять протокол и байтовый формат DM. +- Если появятся новые server API/WebSocket операции, нужно обновить `docs/API/`. + +## Документы, которые потом нужно обновить + +- `docs/Personal_Messages/Протокол_DM_v1.md`; +- `docs/Personal_Messages/Формат_DM_v1.md`; +- `docs/API/`; +- `docs/API/09_Operations_Index.md`, если добавляются новые `op`. + +## Статус + +Отложено до этапа децентрализации. diff --git a/TODO/Децентрализация/межсерверные_звонки.md b/TODO/Децентрализация/межсерверные_звонки.md new file mode 100644 index 00000000..0bae8762 --- /dev/null +++ b/TODO/Децентрализация/межсерверные_звонки.md @@ -0,0 +1,29 @@ +# Межсерверные звонки + +## Зачем + +В будущем пользователи на разных серверах должны иметь возможность устанавливать звонки так же, как пользователи одного сервера. + +## Что сделать + +1. Определить протокол межсерверной сигнализации звонков. +2. Добавить маршрутизацию offer/answer/ICE-кандидатов между серверами. +3. Добавить обработку статусов занятости, отказа, таймаута и ошибок маршрута. +4. Добавить диагностику доставки сигналов между серверами. +5. Проверить совместимость с текущими логами `CallDeliveryReport`. + +## Что учесть + +- Специальная диагностика установки звонков идёт через `CallDeliveryReport`. +- На production важно сохранять поля `reason`, `failureStage`, `pcConnectionState`, `pcIceConnectionState`, `routeLabel`, `configuredTurnHosts*`, `reachableTurnHosts*`. +- Межсерверные звонки не должны ломать текущий односерверный сценарий. + +## Документы, которые потом нужно обновить + +- `docs/API/`, если добавляются или меняются операции сигнализации; +- документы по звонкам/диагностике, если они будут выделены отдельно; +- deploy-документы, если появятся новые параметры TURN/server-to-server маршрутизации. + +## Статус + +Отложено до этапа децентрализации. diff --git a/TODO/Децентрализация/односерверный_production_режим.md b/TODO/Децентрализация/односерверный_production_режим.md new file mode 100644 index 00000000..c0cb9718 --- /dev/null +++ b/TODO/Децентрализация/односерверный_production_режим.md @@ -0,0 +1,23 @@ +# Односерверный production-режим + +## Зачем + +Перед выкладкой репозитория на GitHub и запуском production нужно явно зафиксировать, что текущая стабильная версия работает как один основной сервер. + +## Что считаем текущей нормой + +- Один production-сервер обслуживает пользователей, сообщения, звонки и серверные данные. +- Децентрализованные сценарии не считаются обязательными для первого production-релиза. +- Межсерверная доставка сообщений, межсерверные звонки, realtime PDA/Solana sync и запись блокчейнов в Arweave вынесены в отдельные будущие задачи. +- Код и документация текущего production не должны создавать ожидание, что несколько серверов уже работают как единая realtime-сеть. + +## Что сделать перед возвратом к децентрализации + +1. Проверить актуальные документы по API, blockchain, DM и deploy. +2. Выделить минимальный протокол server-to-server взаимодействия. +3. Решить, какие данные остаются локальными, какие реплицируются между серверами, а какие записываются во внешнее долговременное хранилище. +4. После изменения API, blockchain-форматов или DM-протокола обновить соответствующие документы по правилам проекта. + +## Статус + +Отложено. Текущий production работает как один сервер. diff --git a/TODO/Новые фишки которые надо доделать/Новая_контентная_модель_блокчейна/01_Презентация_для_людей.md b/TODO/Новые фишки которые надо доделать/Новая_контентная_модель_блокчейна/01_Презентация_для_людей.md new file mode 100644 index 00000000..5a1d35a2 --- /dev/null +++ b/TODO/Новые фишки которые надо доделать/Новая_контентная_модель_блокчейна/01_Презентация_для_людей.md @@ -0,0 +1,275 @@ +# Новая логика контента в блокчейне SHiNE + +## Зачем это нужно + +Сейчас блокчейн SHiNE хорошо умеет хранить обычные сообщения, ответы, лайки и связи между людьми. + +Новая модель добавляет поверх этого более понятный смысл контента: + +- обычный текст; +- упражнение; +- услуга / процедура; +- курс; +- стартовая страница канала (`entrypoint`). + +Это нужно для того, чтобы канал стал не просто лентой постов, а полноценным пространством знаний, практик, услуг и сообществ. + +## Что меняется для людей + +### 1. В канале появятся понятные виды материалов + +Сообщение можно будет создать не только как обычный текст, но и как: + +- упражнение; +- услугу / процедуру; +- курс; +- стартовую страницу канала. + +Смысл в том, что приложение и сервер будут понимать, что это за материал, а не просто показывать любой текст одинаково. + +### 2. У канала будет стартовая страница + +У канала появится отдельное стартовое сообщение `entrypoint`. + +Это не курс и не оглавление, а именно главная точка входа в канал: + +- короткое объяснение, о чём канал; +- описание структуры; +- ссылки на нужные материалы; +- удобное начало для новых людей. + +У канала в каждый момент времени будет только одна актуальная стартовая страница. +Если её исправляют, то сохраняется история версий. +Если её удаляют, для интерфейса считается, что стартовой страницы у канала сейчас нет. + +### 3. Курс, упражнение и услуга / процедура будут отличаться по смыслу + +Это важно для логики и статистики. + +- `Упражнение` — то, что человек может делать много раз. +- `Услуга / процедура` — то, что тоже можно проходить много раз, но обычно с участием другого человека. +- `Курс` — то, что можно начать, закончить или бросить. + +За счёт этого сервер сможет честно считать активность, а интерфейс сможет показывать человеку именно те действия, которые подходят к данному типу материала. + +### 4. Появятся статусные действия + +На контент можно будет не только ответить или поставить лайк, но и отметить свой путь: + +- сделал один раз; +- заинтересовался и рассматривает; +- начал; +- закончил / освоил / знаю; +- бросил. + +При этом: + +- для упражнений и услуг / процедур будет отдельно считаться, сколько раз человек сделал / прошёл; +- для упражнений и курсов будет храниться текущий статус. + +Текущий статус определяется просто: + +- последнее статусное действие и считается актуальным. + +Например: + +- если последнее действие “заинтересовался и рассматривает”, значит человек присматривается, но ещё не начал; +- если последнее действие `started`, значит материал сейчас в процессе; +- если последнее действие `abandoned`, значит человек бросил; +- если последнее действие `completed`, значит для системы он завершил / освоил материал. + +### 5. К действиям можно добавлять живой текст + +Практически любое статусное действие можно будет сопровождать коротким комментарием. + +Например: + +- “Начал изучать, потому что давно хотел разобраться”; +- “Бросил, пока нет времени”; +- “Прошёл процедуру, стало заметно легче”. + +Это важно, потому что сам блокчейн будет хранить не только формальный статус, но и живую человеческую причину или заметку. + +### 6. Появится подтверждение статуса другими людьми + +Отдельный человек сможет подтвердить чей-то статус. + +Примеры: + +- подтвердить, что человек действительно занимался; +- подтвердить, что он реально прошёл услугу; +- подтвердить, что он освоил материал. + +Подтверждение — это не замена статуса, а отдельное мнение / свидетельство со стороны. + +### 7. Появится отдельный тип «мнение» + +На любое сообщение можно будет ответить не только обычным ответом, но и специальным типом ответа: `мнение`. + +Это по сути тоже текстовый ответ, но с отдельным смыслом: + +- это отзыв; +- это оценка; +- это мнение о материале; +- это явная метка для будущего анализа нейронками. + +То есть: + +- обычный ответ нужен для разговора; +- `мнение` нужно для отзыва, оценки и анализа реакции людей. + +## Что остаётся как раньше + +### Комментарии + +Обычные ответы на сообщения остаются. +То есть обсуждение материалов не ломается и не меняется концептуально. + +### Лайки контента + +Лайк на сообщение, курс, упражнение или услугу остаётся обычной реакцией на конкретный блок. + +### Лайк пользователю + +Лайк пользователю не будет считаться реакцией на сообщение. +Он относится к графу связей между людьми. + +Это удобно, потому что: + +- лайк человека — это отношение к человеку; +- лайк материала — это отношение к контенту. + +## Сообщество вокруг канала + +Канал сможет работать не только как лента, но и как сообщество. + +Для этого появятся простые действия: + +- заявка на вступление; +- самостоятельный выход; +- принятие; +- исключение. + +Сервер сможет понимать: + +- кто только подал заявку; +- кто уже принят; +- кто вышел; +- кто был исключён. + +## Личный канал и лента достижений + +У каждого человека по смыслу появляется два важных пространства: + +- канал его обычных постов; +- отдельная лента его тренировок и достижений. + +В обычном канале человек сможет: + +- писать посты; +- делиться мыслями; +- публиковать материалы; +- обсуждать темы как раньше. + +А в ленте достижений будут видны его реальные действия: + +- какие упражнения он делал; +- какие услуги / процедуры проходил; +- какие курсы его заинтересовали; +- какие курсы он начал; +- какие курсы он закончил; +- что он бросил. + +То есть блокчейн SHiNE сможет хранить не только слова человека, но и его путь, активность и историю практики. + +## Что смогут делать авторы контента + +Создатели контента в своих каналах смогут публиковать не только обычные посты, но и: + +- упражнения; +- курсы; +- стартовую страницу канала; +- услуги / процедуры, которые они оказывают. + +Это превращает канал в сочетание: + +- блога; +- базы знаний; +- пространства обучения; +- каталога услуг и практик. + +## Что увидит человек в интерфейсе + +На специальных сообщениях в UI можно будет показывать отдельные кнопки действий. + +Например: + +- `Выполнил упражнение` +- `Прошёл процедуру` +- `Заинтересовало` +- `Начал курс` +- `Закончил курс` + +То есть материал можно будет не просто прочитать, а сразу отметить реальное действие. + +Также при ответе на любое сообщение можно будет выбрать: + +- обычный ответ; +- `мнение / отзыв`. + +## Как будет работать лента достижений + +Если кто-то зайдёт в твою ленту достижений, он сможет: + +- прочитать, что ты делал; +- оставить мнение / отзыв; +- подтвердить, что это действительно было. + +Это даёт основу для мягкой “сертификации” внутри SHiNE. + +Например: + +- человек прошёл курс и получил подтверждения; +- человек прошёл процедуру и получил отзыв; +- человек регулярно делает упражнения, и это видно в его истории. + +Так постепенно у пользователя появляется не только лента постов, но и лента достижений, подтверждений и репутации. + +## Ссылки внутри SHiNE + +Для переходов между материалами вводятся простые внутренние адреса: + +- обычная ссылка: `SHiNE/alice-001/157` +- особополная ссылка: `SHiNE/alice-001/157/ХЭШ` + +Первая форма — основная и каноническая. +Вторая нужна там, где хочется добавить ещё и точную проверку по хэшу. + +## Что это даёт в итоге + +После внедрения новая блокчейн-логика позволит: + +- строить каналы как структурированные пространства, а не просто как поток постов; +- выделять упражнения, услуги и курсы как отдельные сущности; +- показывать стартовую страницу канала; +- хранить путь человека по материалу; +- хранить отдельную ленту его действий и достижений; +- считать активность и статусы; +- подтверждать результаты другими людьми; +- развивать сообщество вокруг канала. + +И самое важное: всё это можно добавить как расширение уже существующего блокчейна SHiNE, не разрушая старую модель сообщений. + +## Отдельный вопрос для будущего + +Отзывы о людях как о людях — полезная идея, но её стоит дополнительно обдумать. + +Например, на вкладке связей в будущем можно: + +- писать человеку отзыв; +- смотреть все отзывы о человеке; +- выводить сначала отзывы близких друзей, родственников, друзей и контактов, а уже потом остальные. + +Но этот слой нужно делать осторожно, чтобы он не стал слишком жёстким или неприятным для людей. + +Поэтому отзывы о людях как отдельная социальная механика требуют дополнительного обсуждения и проектирования. diff --git a/TODO/Новые фишки которые надо доделать/Новая_контентная_модель_блокчейна/02_ТЗ_новых_типов_блоков.md b/TODO/Новые фишки которые надо доделать/Новая_контентная_модель_блокчейна/02_ТЗ_новых_типов_блоков.md new file mode 100644 index 00000000..6fafb893 --- /dev/null +++ b/TODO/Новые фишки которые надо доделать/Новая_контентная_модель_блокчейна/02_ТЗ_новых_типов_блоков.md @@ -0,0 +1,670 @@ +# ТЗ: новая контентная модель блокчейна SHiNE + +## Статус документа + +Этот документ описывает предлагаемые новые типы блоков и правила их обработки. + +Цель: + +- добавить новую семантику контента; +- не ломать существующие блоки `type=0..4`; +- внедрить всё как расширение блокчейна за счёт новых форматов. + +Документ является проектным ТЗ на реализацию в сервере, БД, API чтения и UI. + +## 1. Базовые принципы + +### 1.1. Совместимость + +Старые типы не меняются: + +- `type=0` — TECH +- `type=1` — TEXT +- `type=2` — REACTION +- `type=3` — CONNECTION +- `type=4` — USER_PARAM + +Новые сущности и действия добавляются только как новые `type` и новые `body`. + +Это означает: + +- старые блоки продолжают читаться как раньше; +- старые `TEXT_POST`, `TEXT_REPLY`, `REACTION_LIKE` и остальные форматы не ломаются; +- существующий блокчейн остаётся валидным; +- новый функционал появляется только там, где клиент и сервер умеют его понимать. + +### 1.2. Общая стратегия + +Новая модель делится на четыре слоя: + +1. контентные сущности; +2. текстовые отзывы и мнения; +3. статусные действия пользователей; +4. community-события вокруг канала. + +### 1.3. Редактирование и удаление + +Для новых контентных сущностей сохраняется действующий принцип SHiNE: + +- редактирование всегда ссылается на оригинальный блок; +- тип сущности edit не меняет; +- удаление выполняется через `edit` с пустым текстом; +- отдельный `DELETE`-подтип не вводится. + +Это правило особенно важно для: + +- `plain_text` +- `exercise` +- `service` +- `course` +- `entrypoint` + +В пользовательских текстах и UI желательно использовать русские названия: + +- обычный текст; +- упражнение; +- услуга / процедура; +- курс; +- стартовое сообщение канала. + +## 2. Канонические внутренние ссылки + +В новой модели поддерживаются только две формы внутренней ссылки: + +- каноническая: `SHiNE//` +- особополная: `SHiNE///` + +Примеры: + +- `SHiNE/alice-001/157` +- `SHiNE/alice-001/157/abcd1234...` + +Правила: + +- канонической считается именно короткая форма без хэша; +- форма с хэшем используется как усиленный вариант для точной проверки; +- внутри UI и серверной логики ссылка должна приводиться как минимум к паре: + - `blockchainName` + - `blockNumber` +- если хэш присутствует, он участвует в дополнительной валидации ссылки. + +## 3. Новые контентные сущности + +## 3.1. Новый `type=5` — `CONTENT` + +Назначение: + +- хранение новых смысловых материалов канала; +- сохранение линии канала; +- поддержка edit-версий и логического удаления. + +### 3.1.1. Подтипы `CONTENT` + +- `subType=10` — `CONTENT_PLAIN` +- `subType=11` — `CONTENT_EDIT_PLAIN` +- `subType=20` — `CONTENT_EXERCISE` +- `subType=21` — `CONTENT_EDIT_EXERCISE` +- `subType=30` — `CONTENT_SERVICE` +- `subType=31` — `CONTENT_EDIT_SERVICE` +- `subType=40` — `CONTENT_COURSE` +- `subType=41` — `CONTENT_EDIT_COURSE` +- `subType=50` — `CONTENT_ENTRYPOINT` +- `subType=51` — `CONTENT_EDIT_ENTRYPOINT` + +### 3.1.2. Семантика подтипов + +- `CONTENT_PLAIN` — обычный текст нового поколения. +- `CONTENT_EXERCISE` — упражнение, которое можно выполнять многократно. +- `CONTENT_SERVICE` — услуга / процедура, которую можно проходить многократно. +- `CONTENT_COURSE` — курс / оглавление. +- `CONTENT_ENTRYPOINT` — стартовое сообщение канала. + +### 3.1.3. Почему `entrypoint` отдельный тип + +`entrypoint` не считается курсом. + +Это отдельная сущность, потому что: + +- она описывает вход в канал; +- по ней нельзя делать `started / completed / abandoned`; +- у канала в каждый момент времени должна быть только одна актуальная стартовая страница. + +### 3.1.4. Ограничение на `entrypoint` + +Для одного канала допускается только один исходный блок `CONTENT_ENTRYPOINT`. + +Правила: + +- если entrypoint уже существует, создать второй нельзя; +- изменять можно только через `CONTENT_EDIT_ENTRYPOINT`; +- если entrypoint логически удалён, UI должен считать, что стартовой страницы больше нет; +- исторический блок при этом остаётся в цепочке. + +### 3.1.5. Формат body для `CONTENT_*` + +Для `version=1` рекомендуется использовать формат, максимально совместимый по логике с текущими `TEXT_POST` / `TEXT_EDIT_POST`. + +#### Создающие блоки + +Для: + +- `CONTENT_PLAIN` +- `CONTENT_EXERCISE` +- `CONTENT_SERVICE` +- `CONTENT_COURSE` +- `CONTENT_ENTRYPOINT` + +body: + +```text +ContentLineBody_v1 +- lineCode: int32 +- prevLineNumber: int32 +- prevLineHash32: [32] +- thisLineNumber: int32 +- textLenBytes: uint16 +- text UTF-8 +``` + +#### Edit-блоки + +Для: + +- `CONTENT_EDIT_PLAIN` +- `CONTENT_EDIT_EXERCISE` +- `CONTENT_EDIT_SERVICE` +- `CONTENT_EDIT_COURSE` +- `CONTENT_EDIT_ENTRYPOINT` + +body: + +```text +ContentEditBody_v1 +- lineCode: int32 +- prevLineNumber: int32 +- prevLineHash32: [32] +- thisLineNumber: int32 +- toBlockGlobalNumber: int32 +- toBlockHash32: [32] +- textLenBytes: uint16 +- text UTF-8 +``` + +Правила: + +- edit всегда ссылается на оригинальный блок соответствующего типа; +- `toBlockchainName` в edit не хранится; +- `textLen=0` означает логическое удаление содержимого; +- тип исходной сущности edit не меняет. + +### 3.1.6. Что считается комментарием + +Комментарии не требуют нового формата. + +Для обсуждения новых контентных сущностей продолжают использоваться уже существующие: + +- `TEXT_REPLY` +- `TEXT_EDIT_REPLY` + +Это позволяет не ломать старую reply-механику и reuse текущую модель тредов. + +## 4. Текстовые отзывы + +## 4.1. Новый `type=6` — `TEXT_RATING` + +Назначение: + +- текстовая оценка / отзыв на объект; +- без числовой шкалы; +- с возможностью редактирования и логического удаления. + +Смысл `TEXT_RATING`: + +- это текст; +- это специальный отзыв / мнение / оценка; +- это явный сигнал, что перед нами не просто комментарий, а осмысленный отзыв; +- в будущем это поле можно отдельно анализировать нейронками. + +### 4.1.1. Подтипы + +- `subType=10` — `TEXT_RATING_POST` +- `subType=11` — `TEXT_RATING_EDIT` + +### 4.1.2. Где разрешён `TEXT_RATING_POST` + +Разрешён на target: + +- `HEADER` пользователя; +- контентный блок `type=5`; +- при необходимости в будущем — на другие target-блоки по отдельному решению. + +Сейчас в данном ТЗ: + +- отзыв / оценка на пользователя — да; +- отзыв / оценка на контент — да; +- отзыв / лайк на канал целиком — не вводится, только оставляется как будущая возможность. + +### 4.1.3. Где и как используется `TEXT_RATING_POST` + +`TEXT_RATING_POST` можно создавать: + +- как отзыв на контентный блок; +- как отзыв на пользователя через target на `HEADER`; +- как специальный ответ вместо обычного комментария. + +Практическое правило для UI: + +- при ответе на любое сообщение пользователь может выбрать: + - обычный ответ; + - `мнение / отзыв`. + +### 4.1.4. Формат body + +#### Создание + +```text +TextRatingBody_v1 +- toBlockchainNameLen: uint8 +- toBlockchainName UTF-8 +- toBlockGlobalNumber: int32 +- toBlockHash32: [32] +- textLenBytes: uint16 +- text UTF-8 +``` + +#### Редактирование + +```text +TextRatingEditBody_v1 +- toBlockGlobalNumber: int32 +- toBlockHash32: [32] +- textLenBytes: uint16 +- text UTF-8 +``` + +Правила: + +- edit ссылается на оригинальный `TEXT_RATING_POST`; +- пустой текст в edit означает логическое удаление отзыва. + +## 5. Статусные действия и накопительные события + +## 5.1. Новый `type=7` — `STATUS_ACTION` + +Назначение: + +- хранение действий пользователя по отношению к контенту; +- вычисление текущего статуса; +- накопительный учёт повторных прохождений; +- подтверждение статусов другими людьми. + +### 5.1.1. Подтипы + +- `subType=10` — `STATUS_DONE_ONCE` +- `subType=20` — `STATUS_INTERESTED` +- `subType=30` — `STATUS_STARTED` +- `subType=40` — `STATUS_COMPLETED` +- `subType=50` — `STATUS_ABANDONED` +- `subType=60` — `STATUS_CONFIRMED` + +### 5.1.2. Матрица допустимости по контенту + +`STATUS_DONE_ONCE` разрешён только для: + +- `CONTENT_EXERCISE` +- `CONTENT_SERVICE` + +`STATUS_INTERESTED`, `STATUS_STARTED`, `STATUS_COMPLETED`, `STATUS_ABANDONED` разрешены только для: + +- `CONTENT_EXERCISE` +- `CONTENT_COURSE` + +`CONTENT_ENTRYPOINT` не поддерживает: + +- `interested` +- `started` +- `completed` +- `abandoned` + +### 5.1.3. Как считать текущее состояние + +Для пары: + +- `actorLogin` +- `targetBlock` + +актуальным статусом считается последнее по времени статусное событие из набора: + +- `STATUS_INTERESTED` +- `STATUS_STARTED` +- `STATUS_COMPLETED` +- `STATUS_ABANDONED` + +Следствия: + +- у одного пользователя по одному объекту в каждый момент времени только один актуальный статус; +- если последним пришёл `interested`, статус считается “заинтересовался / рассматривает, но ещё не начал”; +- если последним пришёл `started`, статус считается “в процессе”; +- если последним пришёл `completed`, статус считается “завершён / освоен / знаю”; +- если последним пришёл `abandoned`, статус считается “брошен”. + +### 5.1.4. Как считать количество прохождений + +`STATUS_DONE_ONCE` не меняет текущий статус. + +Он считается отдельно как накопительное событие. + +Сервер должен уметь считать: + +- сколько раз пользователь сделал упражнение; +- сколько раз пользователь прошёл услугу / процедуру. + +### 5.1.5. Дополнительный текст действия + +Каждое действие `STATUS_*` может содержать дополнительный текст-комментарий. + +Примеры: + +- как именно делал упражнение; +- чем заинтересовал курс; +- с какими мыслями начал курс; +- почему бросил; +- что именно подтверждает подтверждающий человек. + +### 5.1.6. Подтверждение статуса + +`STATUS_CONFIRMED` разрешён только на target-статусы: + +- `STATUS_DONE_ONCE` +- `STATUS_INTERESTED` +- `STATUS_STARTED` +- `STATUS_COMPLETED` +- `STATUS_ABANDONED` + +Это значит: + +- подтверждение не ставится прямо на курс или упражнение; +- подтверждение ставится на конкретный статусный блок другого человека. + +Подтверждение: + +- не меняет основной статус автора; +- не меняет счётчик `done_once`; +- хранится как отдельное мнение / свидетельство. + +### 5.1.7. Формат body + +Для `STATUS_DONE_ONCE`, `STATUS_INTERESTED`, `STATUS_STARTED`, `STATUS_COMPLETED`, `STATUS_ABANDONED`: + +```text +StatusActionBody_v1 +- toBlockchainNameLen: uint8 +- toBlockchainName UTF-8 +- toBlockGlobalNumber: int32 +- toBlockHash32: [32] +- noteLenBytes: uint16 +- note UTF-8 +``` + +Для `STATUS_CONFIRMED`: + +```text +StatusConfirmBody_v1 +- toBlockchainNameLen: uint8 +- toBlockchainName UTF-8 +- toBlockGlobalNumber: int32 +- toBlockHash32: [32] +- noteLenBytes: uint16 +- note UTF-8 +``` + +На уровне бинарного формата тело можно оставить одинаковым. +Различие задаётся `subType` и правилами валидации target. + +## 6. Community-события + +## 6.1. Новый `type=8` — `COMMUNITY_EVENT` + +Назначение: + +- заявки в сообщество; +- выход из сообщества; +- принятие; +- исключение. + +### 6.1.1. Подтипы + +- `subType=10` — `COMMUNITY_JOIN_REQUEST` +- `subType=20` — `COMMUNITY_LEAVE` +- `subType=30` — `COMMUNITY_ACCEPT` +- `subType=40` — `COMMUNITY_REMOVE` + +### 6.1.2. Базовая логика + +`COMMUNITY_JOIN_REQUEST` + +- создаёт пользователь; +- target — `CONTENT_ENTRYPOINT` канала; +- может содержать текст заявки. + +`COMMUNITY_LEAVE` + +- создаёт сам участник; +- target — `CONTENT_ENTRYPOINT` канала; +- подтверждение не требуется; +- может содержать текст. + +`COMMUNITY_ACCEPT` + +- создаёт владелец канала; +- target — конкретный блок `COMMUNITY_JOIN_REQUEST`; +- может содержать текст. + +`COMMUNITY_REMOVE` + +- создаёт владелец канала; +- target — `CONTENT_ENTRYPOINT` канала; +- body дополнительно хранит `subjectLogin`, кого исключили; +- может содержать текст. + +### 6.1.3. Текущее членство + +Пользователь считается текущим участником сообщества, если: + +- у него есть хотя бы одно принятие в это сообщество; +- после этого принятия нет более позднего: + - `COMMUNITY_LEAVE` + - `COMMUNITY_REMOVE` + +Заявка сама по себе членство не создаёт. + +### 6.1.4. Формат body + +Для `JOIN_REQUEST` и `LEAVE`: + +```text +CommunityActionBody_v1 +- toBlockchainNameLen: uint8 +- toBlockchainName UTF-8 +- toBlockGlobalNumber: int32 +- toBlockHash32: [32] +- noteLenBytes: uint16 +- note UTF-8 +``` + +Для `ACCEPT`: + +```text +CommunityAcceptBody_v1 +- toBlockchainNameLen: uint8 +- toBlockchainName UTF-8 +- toBlockGlobalNumber: int32 +- toBlockHash32: [32] +- noteLenBytes: uint16 +- note UTF-8 +``` + +Для `REMOVE`: + +```text +CommunityRemoveBody_v1 +- toBlockchainNameLen: uint8 +- toBlockchainName UTF-8 +- toBlockGlobalNumber: int32 +- toBlockHash32: [32] +- subjectLoginLen: uint8 +- subjectLogin ASCII +- noteLenBytes: uint16 +- note UTF-8 +``` + +## 7. Что остаётся на старых типах + +### 7.0. Обычный канал и лента достижений + +На уровне продукта рекомендуется различать: + +- обычный канал постов пользователя; +- отдельную ленту его действий и достижений. + +В обычном канале пользователь: + +- пишет посты; +- публикует материалы; +- общается и обсуждает. + +В ленте достижений видны события: + +- какие упражнения он делал; +- какие услуги / процедуры проходил; +- какие курсы его заинтересовали; +- какие курсы он начал; +- какие курсы он завершил; +- что он бросил. + +В данном ТЗ эта модель фиксируется как продуктовая логика. +Конкретный способ хранения можно реализовать: + +- либо отдельным специальным каналом; +- либо отдельным режимом чтения по статусным блокам. + +### 7.1. Лайк пользователю + +Лайк пользователю не вводится как `REACTION`. + +Он остаётся в слое социальных связей: + +- через `CONNECTION` +- как будущий отдельный подтип связи + +В этом ТЗ сам новый подтип связи не описывается детально. +Нужно только зафиксировать правило: + +- лайк человека относится к графу связей, а не к реакции на блок. + +### 7.2. Лайк контента + +Лайк на: + +- `CONTENT_PLAIN` +- `CONTENT_EXERCISE` +- `CONTENT_SERVICE` +- `CONTENT_COURSE` +- `CONTENT_ENTRYPOINT` + +может использовать уже существующий: + +- `REACTION_LIKE` +- `REACTION_UNLIKE` + +Отдельный новый формат для лайка контента не нужен. + +### 7.3. Канал целиком + +В текущем ТЗ не вводятся: + +- отзыв на канал целиком; +- лайк канала целиком. + +Это оставляется как будущая возможность. + +### 7.4. Отзывы о людях + +Отзывы о человеке как о человеке в текущем ТЗ допустимы через `TEXT_RATING` на `HEADER`. + +Но продуктовую модель их показа нужно отдельно продумать. + +Направление для будущего: + +- просмотр отзывов о человеке на вкладке связей; +- приоритетный вывод отзывов от близких друзей, родственников, друзей и контактов; +- затем вывод остальных отзывов. + +Эта тема полезна, но требует дополнительной осторожной проработки с точки зрения UX и социальных рисков. + +## 8. Требования к серверу + +Сервер после внедрения должен уметь: + +1. Валидировать новые `type=5..8`. +2. Хранить новые блоки без ломки старого чтения. +3. Определять текущий статус пользователя по объекту: + - `interested` + - `started` + - `completed` + - `abandoned` +4. Считать накопительные события `done_once` для: + - `exercise` + - `service` +5. Считать подтверждения статусов. +6. Определять единственный актуальный `entrypoint` канала. +7. Определять текущее членство в сообществе канала. +8. Поддерживать внутренние ссылки вида: + - `SHiNE//` + - `SHiNE///` + +## 9. Требования к UI + +UI после внедрения должен уметь: + +1. Показывать разные карточки для: + - текста + - упражнения + - услуги + - курса + - entrypoint +2. Показывать стартовую страницу канала, если `entrypoint` существует. +3. Не показывать entrypoint, если он логически удалён. +4. Давать человеку только допустимые действия по типу материала. +5. Показывать: + - текущий статус; + - количество `done_once`; + - подтверждения статуса. +6. Показывать отдельные действия-кнопки на специальных блоках, например: + - `Выполнил упражнение` + - `Прошёл процедуру` + - `Заинтересовало` + - `Начал курс` + - `Закончил курс` +7. При ответе на сообщение давать выбор: + - обычный ответ; + - `мнение / отзыв`. +8. Открывать внутренние ссылки SHiNE. + +## 10. Вывод по совместимости + +Предлагаемая модель реализуема без слома старого блокчейна. + +Причина: + +- старые `type=0..4` не меняются; +- новые сущности вводятся только как новые `type=5..8`; +- существующие `reply`, `like`, `edit`, `HEADER`, `CREATE_CHANNEL` и `CONNECTION` продолжают работать как раньше; +- старые клиенты смогут игнорировать новые типы как неизвестные; +- новые клиенты смогут постепенно включать поддержку нового функционала. + +Итог: + +- это расширение формата блокчейна; +- это не миграция со сломом старых блоков; +- это можно внедрять поэтапно. diff --git a/VERSION.properties b/VERSION.properties index 7d99cbe7..aac20b46 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.2.329 -server.version=1.2.301 +client.version=1.2.330 +server.version=1.2.302 diff --git a/docs/API/00_Common_API_Format.md b/docs/API/00_Common_API_Format.md index 9380fb2c..5aee944d 100644 --- a/docs/API/00_Common_API_Format.md +++ b/docs/API/00_Common_API_Format.md @@ -129,7 +129,7 @@ - `shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/JsonHandlerRegistry.java`. -Если операция зарегистрирована в `HANDLERS` и `REQUEST_TYPES`, она считается доступной через JSON/WebSocket API. Общий актуальный индекс таких операций поддерживается в `Dev_Docs/API/09_Operations_Index.md`. +Если операция зарегистрирована в `HANDLERS` и `REQUEST_TYPES`, она считается доступной через JSON/WebSocket API. Общий актуальный индекс таких операций поддерживается в `docs/API/09_Operations_Index.md`. --- diff --git a/docs/API/02_Authentication_API.md b/docs/API/02_Authentication_API.md index 1ace107e..735b4b2d 100644 --- a/docs/API/02_Authentication_API.md +++ b/docs/API/02_Authentication_API.md @@ -38,7 +38,7 @@ Отдельно появился новый серверный сценарий pairing через доверенный homeserver/ESP. Он не заменяет обычный вход и описан в: -- `Dev_Docs/Протоколы/ESP_Pairing_и_режимы_подключения.md` +- `docs/Протоколы/ESP_Pairing_и_режимы_подключения.md` Кратко: @@ -321,7 +321,7 @@ SESSION_LOGIN:{sessionId}:{timeMs}:{nonce} Точные форматы этих операций см. в `03_Session_Management_API.md` и в протокольном документе: -- `Dev_Docs/Протоколы/ESP_Pairing_и_режимы_подключения.md` +- `docs/Протоколы/ESP_Pairing_и_режимы_подключения.md` --- diff --git a/docs/API/12_Direct_Messages_Push_Calls_API.md b/docs/API/12_Direct_Messages_Push_Calls_API.md index f4a3b8f2..2a12d0a1 100644 --- a/docs/API/12_Direct_Messages_Push_Calls_API.md +++ b/docs/API/12_Direct_Messages_Push_Calls_API.md @@ -4,8 +4,8 @@ Подробная логика DM и бинарного формата: -- `Dev_Docs/Personal_Messages/Протокол_DM_v1.md` -- `Dev_Docs/Personal_Messages/Формат_DM_v1.md` +- `docs/Personal_Messages/Протокол_DM_v1.md` +- `docs/Personal_Messages/Формат_DM_v1.md` Важно: diff --git a/docs/Blockchain/00_Blockchain_Formats_and_Block_Types.md b/docs/Blockchain/00_Blockchain_Formats_and_Block_Types.md index 43d5b23d..52d25999 100644 --- a/docs/Blockchain/00_Blockchain_Formats_and_Block_Types.md +++ b/docs/Blockchain/00_Blockchain_Formats_and_Block_Types.md @@ -22,4 +22,4 @@ ## Примечание -Если нужно добавить новый тип или подтип блока, сначала обновляйте профильный файл этого раздела, затем API-документацию в `Dev_Docs/API`. +Если нужно добавить новый тип или подтип блока, сначала обновляйте профильный файл этого раздела, затем API-документацию в `docs/API`. diff --git a/docs/Blockchain/CHANGELOG.md b/docs/Blockchain/CHANGELOG.md index da25e993..25fabfeb 100644 --- a/docs/Blockchain/CHANGELOG.md +++ b/docs/Blockchain/CHANGELOG.md @@ -52,7 +52,7 @@ - после рестарта сервер добивает `BlockchainTmpRecovery` и `BlockchainResyncRecovery`; - `aidartest-001` успешно подтягивается с `shineup.me`; - итоговое локальное состояние по `aidartest-001` дошло до `last_block_number=13`. -- В `Dev_Docs/Blockchain/sync-between-servers.md` добавлен практический результат ручной проверки на тестовом сервере. +- В `docs/Blockchain/sync-between-servers.md` добавлен практический результат ручной проверки на тестовом сервере. ## 2026-06-26 17:03:22 +0400 - Базовый коммит-ориентир: `71fdee0`. @@ -60,21 +60,21 @@ - `BlockchainTmpRecoveryOnStartup` теперь разбирает marker-driven recovery для обычной записи блока: - если marker есть, recovery либо завершает swap tmp -> main, либо удаляет мусор; - если marker нет, временные артефакты считаются мусором и удаляются. -- В `Dev_Docs/Blockchain/sync-between-servers.md` добавлено описание обычного `AddBlock` recovery и разделение между `write_pending` и `resync_pending`. +- В `docs/Blockchain/sync-between-servers.md` добавлено описание обычного `AddBlock` recovery и разделение между `write_pending` и `resync_pending`. ## 2026-05-24 11:40:00 +0300 - Базовый коммит-ориентир: `abdce05`. - `TEXT_REPOST (subType=30)` оставлен как зарезервированный формат, но новые блоки репоста временно отключены на уровне `AddBlock`. - В `11_TEXT_Blocks.md` зафиксировано, что запись `TEXT_REPOST` временно не используется до будущей реализации. -- В `Dev_Docs/API/04_Add_Block_to_Blockchain_API.md` добавлен код отказа `repost_disabled`. +- В `docs/API/04_Add_Block_to_Blockchain_API.md` добавлен код отказа `repost_disabled`. ## 2026-05-21 19:05:00 +0300 - Базовый коммит-ориентир: `5344c42`. - Добавлен новый TEXT-подтип `TEXT_REPOST (subType=30)`: - обновлён перечень типов в `11_TEXT_Blocks.md`; - обновлена быстрая карта типов в `00_Blockchain_Formats_and_Block_Types.md`. -- Уточнено API-описание поддержанных подтипов в `Dev_Docs/API/04_Add_Block_to_Blockchain_API.md`. -- В документе `Dev_Docs/API/08_MCP_Чтение_и_дозапись_персонального_публичного_чата.md` зафиксировано, что чтение канала учитывает `TEXT_POST` и `TEXT_REPOST`. +- Уточнено API-описание поддержанных подтипов в `docs/API/04_Add_Block_to_Blockchain_API.md`. +- В документе `docs/API/08_MCP_Чтение_и_дозапись_персонального_публичного_чата.md` зафиксировано, что чтение канала учитывает `TEXT_POST` и `TEXT_REPOST`. ## 2026-05-20 11:34:17 +0300 - Базовый коммит-ориентир: `a53444b`. @@ -82,7 +82,7 @@ - `60/61` — `known_person / unknown_person` (знаю этого человека); - `70/71` — `shine_confirmed / shine_unconfirmed` (точно уверен, что сияющий); - `74/75` — `shine_seen / shine_unseen` (мало знаком, но видел сияющим). -- Обновлён список CONNECTION-подтипов в `Dev_Docs/API/04_Add_Block_to_Blockchain_API.md`. +- Обновлён список CONNECTION-подтипов в `docs/API/04_Add_Block_to_Blockchain_API.md`. ## 2026-05-19 20:30:21 +0300 - Базовый коммит-ориентир: `7986184`. @@ -107,4 +107,4 @@ - Для персонального канала (`type=100`) включена сборка парного потока при чтении (`A->B` + `B->A`, если существует). - Добавлена поддержка командного префикса `/.` и команды `/.desc` для актуализации описания канала при чтении. - Зафиксированы команды `/.add` и `/.remove` для каналов `type=200` (зарезервировано под расширение участниками). -- В `AGENTS.md` добавлено обязательное правило актуализации документации в `Dev_Docs/Blockchain/`. +- В `AGENTS.md` добавлено обязательное правило актуализации документации в `docs/Blockchain/`. diff --git a/docs/Blockchain/sync-between-servers.md b/docs/Blockchain/sync-between-servers.md index ea6d1161..d4413ed8 100644 --- a/docs/Blockchain/sync-between-servers.md +++ b/docs/Blockchain/sync-between-servers.md @@ -193,7 +193,7 @@ Full resync запускается только тогда, когда: ### 5.4 Разрешение конфликтов - Блоки пользовательского блокчейна: порядок определяется глобальным номером блока. - Конфликтующие ветки (fork) разрешаются по правилам `AddBlock` (см. `Dev_Docs/Blockchain/README.md`). + Конфликтующие ветки (fork) разрешаются по правилам `AddBlock` (см. `docs/Blockchain/README.md`). - DM: конфликтов нет, `message_key` уникален. ## 6. Маршрутизация DM между серверами diff --git a/docs/Figma/TRANSFER_UI_SCREENS.md b/docs/Figma/TRANSFER_UI_SCREENS.md index 5e4bdb4d..9acdecff 100644 --- a/docs/Figma/TRANSFER_UI_SCREENS.md +++ b/docs/Figma/TRANSFER_UI_SCREENS.md @@ -197,7 +197,7 @@ - нужен реальный прогон на test2; - затронута интеграция с Solana; -тогда нужно добавить файл в `Dev_Docs/Pending_Features/`. +тогда нужно добавить файл в `docs/Pending_Features/`. ## Что пока не оформлено для Miro diff --git a/docs/Keys/DERIVATION.md b/docs/Keys/DERIVATION.md index 77a864e0..e15b14c9 100644 --- a/docs/Keys/DERIVATION.md +++ b/docs/Keys/DERIVATION.md @@ -6,7 +6,7 @@ > Если в коде меняется деривация (формула секрета, параметры Argon2id, соль, формула > ключа, разделитель `|`, набор/имена суффиксов, формат homeserver-ключа, связь > dev-ключ ↔ Solana-адрес) — **в том же изменении обязательно править этот документ**. -> Роли и назначение ключей описаны отдельно в `Dev_Docs/Keys/README.md` (архитектура). +> Роли и назначение ключей описаны отдельно в `docs/Keys/README.md` (архитектура). > Здесь — только механика. Документ намеренно краткий. --- @@ -59,7 +59,7 @@ seed(32) = SHA-256(material) | device / **Solana** | `client.key` | Ключ устройства = Solana-ключ. Fee payer и подпись Solana-транзакций; адрес кошелька = `base58(clientPub)`. См. §3. | | homeserver | `homeserver.key:<имя>` | Ключ homeserver-устройства, по одному на каждый homeserver (различитель — имя). См. §4. | -Полные роли каждого ключа — в `Dev_Docs/Keys/README.md`. +Полные роли каждого ключа — в `docs/Keys/README.md`. --- @@ -77,7 +77,7 @@ seed(32) = SHA-256(material) Кратко про роли на Solana: `root.key` — это **главный (master) ключ**: им управляют PDA-записью (`create/update`) и через это можно заменить все остальные ключи; `client.key` — это **пополняемый -кошелёк и плательщик комиссий**. Полное описание ролей — `Dev_Docs/Keys/README.md`. +кошелёк и плательщик комиссий**. Полное описание ролей — `docs/Keys/README.md`. --- diff --git a/docs/Keys/README.md b/docs/Keys/README.md index 61785257..14fcc1bd 100644 --- a/docs/Keys/README.md +++ b/docs/Keys/README.md @@ -30,7 +30,7 @@ `root key` — это **главный (master) ключ** в следующем смысле: зная `root key`, можно управлять пользовательской PDA-записью в Solana (`create_user_pda` / `update_user_pda`) и тем самым **заменить все остальные ключи** пользователя (device, blockchain, homeserver). Поэтому компрометация `root key` равносильна компрометации всей личности пользователя. -Важно не путать авторитет и кошелёк: `root key` — это авторитет над PDA-записью, а **SOL-комиссии за create/update платит `client key`** (он же fee payer и адрес для пополнения). Подробнее о том, какой ключ за что отвечает на Solana, — в `Dev_Docs/Keys/DERIVATION.md`, §3. +Важно не путать авторитет и кошелёк: `root key` — это авторитет над PDA-записью, а **SOL-комиссии за create/update платит `client key`** (он же fee payer и адрес для пополнения). Подробнее о том, какой ключ за что отвечает на Solana, — в `docs/Keys/DERIVATION.md`, §3. ## `blockchain key` @@ -65,7 +65,7 @@ Arweave-кошелёк должен выводиться из `client key` по протоколу: -- `Dev_Docs/Протоколы/SHINE_ARWEAVE_DERIVATION_V1.md` +- `docs/Протоколы/SHINE_ARWEAVE_DERIVATION_V1.md` Если пользователь теряет только `client key`, в худшем случае ломается повседневная переписка и доступ конкретных устройств к ежедневным операциям. `root key` и `blockchain key` при правильной архитектуре остаются отдельно защищёнными. @@ -158,13 +158,13 @@ Self-message - это сообщение пользователя самому ## Связанные документы -- `Dev_Docs/Keys/DERIVATION.md` - **источник истины по конкретной деривации** секрета и ключей (формулы Argon2id, `base64|suffix→SHA-256→Ed25519`, суффиксы `root.key`/`bch.key`/`client.key`/`homeserver.key:<имя>`, Solana-ключ, ссылки на код). -- `Dev_Docs/Personal_Messages/Протокол_DM_v1.md` - текущая логическая документация личных сообщений. -- `Dev_Docs/Personal_Messages/Формат_DM_v1.md` - точный байтовый формат личных сообщений. -- `Dev_Docs/Blockchain/README.md` - точка входа по форматам SHiNE-блокчейна. -- `Dev_Docs/Solana_Architecture/README.md` - архитектура Solana-программ, PDA-счетов, DAO и движения средств. -- `Dev_Docs/Инициализация_Solana_регистрации/README.md` - деплой и первичная инициализация Solana-регистрации. -- `Dev_Docs/Протоколы/SHINE_ARWEAVE_DERIVATION_V1.md` - derivation Arweave-кошелька из `client key`. +- `docs/Keys/DERIVATION.md` - **источник истины по конкретной деривации** секрета и ключей (формулы Argon2id, `base64|suffix→SHA-256→Ed25519`, суффиксы `root.key`/`bch.key`/`client.key`/`homeserver.key:<имя>`, Solana-ключ, ссылки на код). +- `docs/Personal_Messages/Протокол_DM_v1.md` - текущая логическая документация личных сообщений. +- `docs/Personal_Messages/Формат_DM_v1.md` - точный байтовый формат личных сообщений. +- `docs/Blockchain/README.md` - точка входа по форматам SHiNE-блокчейна. +- `docs/Solana_Architecture/README.md` - архитектура Solana-программ, PDA-счетов, DAO и движения средств. +- `docs/Инициализация_Solana_регистрации/README.md` - деплой и первичная инициализация Solana-регистрации. +- `docs/Протоколы/SHINE_ARWEAVE_DERIVATION_V1.md` - derivation Arweave-кошелька из `client key`. ## Что нужно уточнить перед реализацией diff --git a/docs/Personal_Messages/README.md b/docs/Personal_Messages/README.md index 587d94fb..2ec4490a 100644 --- a/docs/Personal_Messages/README.md +++ b/docs/Personal_Messages/README.md @@ -4,13 +4,13 @@ Точка входа: -- `Dev_Docs/Personal_Messages/Протокол_DM_v1.md` — логика протокола, роли API, серверное поведение, routing по `access_servers` -- `Dev_Docs/Personal_Messages/Формат_DM_v1.md` — точный бинарный формат контейнера `SHiNE_DM` -- `Dev_Docs/Personal_Messages/Технические_вставки_DM_v1.md` — формат специальных `` вставок внутри plaintext DM после расшифровки +- `docs/Personal_Messages/Протокол_DM_v1.md` — логика протокола, роли API, серверное поведение, routing по `access_servers` +- `docs/Personal_Messages/Формат_DM_v1.md` — точный бинарный формат контейнера `SHiNE_DM` +- `docs/Personal_Messages/Технические_вставки_DM_v1.md` — формат специальных `` вставок внутри plaintext DM после расшифровки Исторический устаревший документ сохранён отдельно: -- `Dev_Docs/Personal_Messages/Спецификация_DM_v0.5_устаревшая.md` +- `docs/Personal_Messages/Спецификация_DM_v0.5_устаревшая.md` Правило сопровождения: diff --git a/docs/Personal_Messages/Протокол_DM_v1.md b/docs/Personal_Messages/Протокол_DM_v1.md index 5466c953..5effcafd 100644 --- a/docs/Personal_Messages/Протокол_DM_v1.md +++ b/docs/Personal_Messages/Протокол_DM_v1.md @@ -20,15 +20,15 @@ Точный байтовый формат контейнера вынесен отдельно: -- `Dev_Docs/Personal_Messages/Формат_DM_v1.md` +- `docs/Personal_Messages/Формат_DM_v1.md` Формат клиентских технических вставок внутри plaintext вынесен отдельно: -- `Dev_Docs/Personal_Messages/Технические_вставки_DM_v1.md` +- `docs/Personal_Messages/Технические_вставки_DM_v1.md` Устаревшая предыдущая версия сохранена отдельно: -- `Dev_Docs/Personal_Messages/Спецификация_DM_v0.5_устаревшая.md` +- `docs/Personal_Messages/Спецификация_DM_v0.5_устаревшая.md` ## 1. Основная модель @@ -61,7 +61,7 @@ Подробности стандартного преобразования: -- `Dev_Docs/Протоколы/Преобразование_ED25519_в_X25519.md` +- `docs/Протоколы/Преобразование_ED25519_в_X25519.md` ### 2.2. Правило шифрования копий diff --git a/docs/Personal_Messages/Спецификация_DM_v0.5_устаревшая.md b/docs/Personal_Messages/Спецификация_DM_v0.5_устаревшая.md index 15cd509f..de98104f 100644 --- a/docs/Personal_Messages/Спецификация_DM_v0.5_устаревшая.md +++ b/docs/Personal_Messages/Спецификация_DM_v0.5_устаревшая.md @@ -6,7 +6,7 @@ Aктуальная целевая спецификация: -- `Dev_Docs/Personal_Messages/Протокол_DM_v1.md` +- `docs/Personal_Messages/Протокол_DM_v1.md` Что в этом документе считать устаревшим: @@ -35,7 +35,7 @@ Aктуальная целевая спецификация: Черновик будущих вложений вынесен отдельно: -- `Dev_Docs/Personal_Messages/Черновик_будущих_DM_вложений.md` +- `docs/Personal_Messages/Черновик_будущих_DM_вложений.md` ## Общая схема diff --git a/docs/Personal_Messages/Формат_DM_v1.md b/docs/Personal_Messages/Формат_DM_v1.md index 2132bdcd..538cb19f 100644 --- a/docs/Personal_Messages/Формат_DM_v1.md +++ b/docs/Personal_Messages/Формат_DM_v1.md @@ -12,7 +12,7 @@ Логика протокола, API и поведение сервера описаны отдельно: -- `Dev_Docs/Personal_Messages/Протокол_DM_v1.md` +- `docs/Personal_Messages/Протокол_DM_v1.md` ## 1. Общие правила diff --git a/docs/Solana/user_pda/README.md b/docs/Solana/user_pda/README.md index ea1dc0a2..32440859 100644 --- a/docs/Solana/user_pda/README.md +++ b/docs/Solana/user_pda/README.md @@ -2,7 +2,7 @@ Документ описывает целевой формат пользовательской PDA-записи `user_pda` для Solana-программы `shine_users`. -Это не формат основного блокчейна SHiNE и не документация по `AddBlock`. Основной блокчейн SHiNE описан отдельно в `Dev_Docs/Blockchain/`. +Это не формат основного блокчейна SHiNE и не документация по `AddBlock`. Основной блокчейн SHiNE описан отдельно в `docs/Blockchain/`. Статус документа: итоговый согласованный формат, к которому приведены `create_user_pda`, `update_user_pda` и тестовый сериализатор Solana-модуля. diff --git a/docs/Solana_Architecture/README.md b/docs/Solana_Architecture/README.md index ebacfe67..d322f72b 100644 --- a/docs/Solana_Architecture/README.md +++ b/docs/Solana_Architecture/README.md @@ -8,7 +8,7 @@ Связанные документы: -- `Dev_Docs/Инициализация_Solana_регистрации/README.md` — single source of truth по деплою и первичной инициализации регистрации пользователей. +- `docs/Инициализация_Solana_регистрации/README.md` — single source of truth по деплою и первичной инициализации регистрации пользователей. - `shine-solana/shine/doc/formats/shine-user-pda-format-v.1.0.md` — точный формат `user_pda` для `shine_users`. - `shine-solana/shine/doc/FUNDS_FLOW.md` — короткая справка по денежным потокам внутри Solana-модуля. @@ -55,7 +55,7 @@ DAO в текущем виде не является отдельной Anchor- 1. `shine-solana/shine/Anchor.toml` 2. `declare_id!` в `programs/*/src/lib.rs` 3. `programs/common/src/deploy_config.rs` -4. UI/серверные константы, перечисленные в `Dev_Docs/Инициализация_Solana_регистрации/README.md` +4. UI/серверные константы, перечисленные в `docs/Инициализация_Solana_регистрации/README.md` ## Ключи и authority diff --git a/docs/Протоколы/ESP_Pairing_и_режимы_подключения.md b/docs/Протоколы/ESP_Pairing_и_режимы_подключения.md index 64b77dbe..9c79f934 100644 --- a/docs/Протоколы/ESP_Pairing_и_режимы_подключения.md +++ b/docs/Протоколы/ESP_Pairing_и_режимы_подключения.md @@ -115,4 +115,4 @@ sha256$ Для отдельного RPC-взаимодействия между браузерным wallet-расширением и ESP32 см. документ: -- [Формат_взаимодействия_внешнего_кошелька_и_ESP32.md](/home/ai/work/SHiNE/SHiNE-server-sha256/Dev_Docs/Протоколы/Формат_взаимодействия_внешнего_кошелька_и_ESP32.md) +- [Формат_взаимодействия_внешнего_кошелька_и_ESP32.md](/home/ai/work/SHiNE/SHiNE-server-sha256/docs/Протоколы/Формат_взаимодействия_внешнего_кошелька_и_ESP32.md) diff --git a/shine-UI/.elaira_logs/codex_profile_toggle_20260324_194129.log b/shine-UI/.elaira_logs/codex_profile_toggle_20260324_194129.log deleted file mode 100644 index fbef2a89..00000000 --- a/shine-UI/.elaira_logs/codex_profile_toggle_20260324_194129.log +++ /dev/null @@ -1,1509 +0,0 @@ -OpenAI Codex v0.116.0 (research preview) --------- -workdir: /home/player/docker/shine-UI -model: gpt-5.4 -provider: openai -approval: never -sandbox: danger-full-access -reasoning effort: none -reasoning summaries: none -session id: 019d20b9-0f17-71d1-b203-e6ee9d881c58 --------- -user -Project: static UI site for Shine, located at /home/player/docker/shine-UI. Task: modify the existing profile page. There are already 2 existing UI elements related to account status/features; do not create new duplicated elements if suitable ones already exist. Update their behavior so that when the user clicks each of these two existing elements, a menu, popup, modal, or dropdown appears that clearly explains that these controls are used to enable and disable the corresponding functions. The wording should feel natural in Russian UI. Keep the implementation simple and consistent with the current project style. If there is no existing modal system, create a lightweight one in plain HTML/CSS/JS appropriate for a static site. Make sure the interaction works in browser without backend. Update only what is necessary. At the end, print a short summary of changed files. -mcp startup: no servers -codex -Изменю профильную страницу точечно: сначала найду эти два существующих элемента статуса/функций и проверю, есть ли в проекте уже готовый механизм модалок или всплывающих меню, чтобы не дублировать UI. -exec -/bin/bash -lc 'rg --files js/pages js/components styles' in /home/player/docker/shine-UI succeeded in 0ms: -styles/main.css -styles/components.css -styles/layout.css -js/components/header.js -js/components/page-label.js -js/components/toolbar.js -js/pages/channel-view.js -js/pages/wallet-view.js -js/pages/messages-list.js -js/pages/settings-view.js -js/pages/chat-view.js -js/pages/notifications-view.js -js/pages/profile-view.js -js/pages/network-view.js -js/pages/channels-list.js -exec -/bin/bash -lc 'rg -n "профил|статус|функц|toggle|switch|premium|verified|online|visibility|notifications|privacy|feature|status" js/pages js/components styles index.html' in /home/player/docker/shine-UI succeeded in 0ms: -js/components/toolbar.js:7: { pageId: 'notifications-view', label: 'Уведомления', icon: '🔔' }, -js/pages/wallet-view.js:9: let statusText = 'Данные демонстрационные'; -js/pages/wallet-view.js:11: const status = document.createElement('p'); -js/pages/wallet-view.js:12: status.className = 'meta-muted'; -js/pages/wallet-view.js:15: statusText = text; -js/pages/wallet-view.js:16: status.textContent = statusText; -js/pages/wallet-view.js:67: updateStatus('Демо-функция: перевод будет добавлен позже'); -js/pages/wallet-view.js:71: updateStatus('Демо-функция: пополнение будет добавлено позже'); -js/pages/wallet-view.js:74: updateStatus(statusText); -js/pages/wallet-view.js:76: screen.append(card, actions, status); -js/pages/notifications-view.js:2:import { notifications } from '../mock-data.js'; -js/pages/notifications-view.js:5:export const pageMeta = { id: 'notifications-view', title: 'Уведомления' }; -js/pages/notifications-view.js:8: const active = state.notificationsTab; -js/pages/notifications-view.js:9: const items = notifications[active] || []; -js/pages/notifications-view.js:29: -js/pages/notifications-view.js:30: -js/pages/notifications-view.js:39: state.notificationsTab = btn.dataset.tab; -codex -Нашёл профильный экран. Сейчас открою его и связанные стили, чтобы определить, какие именно два элемента уже используются и можно ли встроить простую подсказку без отдельной тяжёлой инфраструктуры. -exec -/bin/bash -lc "sed -n '1,240p' js/pages/profile-view.js" in /home/player/docker/shine-UI succeeded in 0ms: -import { renderHeader } from '../components/header.js'; -import { profile } from '../mock-data.js'; - -export const pageMeta = { id: 'profile-view', title: 'Профиль' }; - -export function render({ navigate }) { - const screen = document.createElement('section'); - screen.className = 'stack'; - - screen.append( - renderHeader({ - title: 'Профиль', - rightActions: [ - { label: 'Кошелёк', onClick: () => navigate('wallet-view') }, - { label: 'Настройки', onClick: () => navigate('settings-view') }, - ], - }) - ); - - const card = document.createElement('div'); -exec -/bin/bash -lc "sed -n '1,260p' styles/components.css" in /home/player/docker/shine-UI succeeded in 0ms: -.page-header { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 14px; - gap: 8px; -} - -.page-title { - font-size: 22px; - font-weight: 700; - letter-spacing: 0.2px; -} - -.header-actions, -.header-left { - display: flex; - align-items: center; - gap: 8px; - min-width: 74px; -exec -/bin/bash -lc "sed -n '1,260p' styles/main.css" in /home/player/docker/shine-UI succeeded in 0ms: -:root { - --bg-0: #080b12; - --bg-1: #101624; - --bg-2: #171f32; - --card: #1a2436; - --card-soft: #202d45; - --line: #2a3854; - --text: #ebf1ff; - --text-muted: #99a8cb; - --accent: #53d8fb; - --accent-soft: rgba(83, 216, 251, 0.17); - --danger: #ff718f; - --ok: #84f4a1; - --radius-lg: 18px; - --radius-md: 12px; - --radius-sm: 9px; - --shadow: 0 20px 40px rgba(0, 0, 0, 0.35); - --font-main: "Manrope", "IBM Plex Sans", "Segoe UI", sans-serif; -} - -codex -В профиле нашлись два уже существующих элемента: два бейджа в правом верхнем блоке карточки. Глобальной системы модалок нет, поэтому добавлю лёгкий локальный попап для этой страницы и привяжу его именно к этим двум существующим бейджам без новых дублирующих контролов. -exec -/bin/bash -lc "sed -n '1,220p' js/mock-data.js" in /home/player/docker/shine-UI succeeded in 0ms: -export const profile = { - login: '@shine.alex', - name: 'Алексей Смирнов', - avatarInitials: 'АС', - phone: '+7 (916) 221-45-88', - address: 'Москва, Пресненская наб., 12', - email: 'alex.shine@demo.local', - socials: '@alexshine / t.me/alexshine', - badges: ['Официальный аккаунт', 'Сияющий'], -}; - -export const wallet = { - balanceSOL: '182.4571', - publicAddress: '9sVAXJ2CqP3BrtC6AFeQHhcuWjN1kUyhY7L8pkQJxMZe', - updatedAt: 'сегодня, 14:42', -}; - -export const directMessages = [ - { - id: 'u1', -exec -/bin/bash -lc "sed -n '1,220p' js/app.js" in /home/player/docker/shine-UI succeeded in 0ms: -import { navigate, getRoute } from './router.js'; -import { renderToolbar } from './components/toolbar.js'; -import { renderPageLabel } from './components/page-label.js'; - -import * as profileView from './pages/profile-view.js'; -import * as walletView from './pages/wallet-view.js'; -import * as settingsView from './pages/settings-view.js'; -import * as messagesList from './pages/messages-list.js'; -import * as chatView from './pages/chat-view.js'; -import * as channelsList from './pages/channels-list.js'; -import * as channelView from './pages/channel-view.js'; -import * as networkView from './pages/network-view.js'; -import * as notificationsView from './pages/notifications-view.js'; - -const routes = { - 'profile-view': profileView, - 'wallet-view': walletView, - 'settings-view': settingsView, - 'messages-list': messagesList, - 'chat-view': chatView, -exec -/bin/bash -lc "sed -n '1,220p' js/router.js" in /home/player/docker/shine-UI succeeded in 0ms: -const ROOT_PAGES = ['messages-list', 'channels-list', 'network-view', 'notifications-view', 'profile-view']; - -export function getRoute() { - const raw = window.location.hash.replace(/^#\/?/, ''); - if (!raw) { - return { pageId: 'profile-view', params: {} }; - } - - const [pageId, dynamicId] = raw.split('/'); - - if (pageId === 'chat-view') { - return { pageId, params: { chatId: dynamicId || '' } }; - } - - if (pageId === 'channel-view') { - return { pageId, params: { channelId: dynamicId || '' } }; - } - - return { pageId, params: {} }; -} -codex -Вношу минимальные правки в профиль: превращу оба существующих бейджа в кликабельные триггеры и добавлю один переиспользуемый попап с русскими пояснениями для каждого из них. -file update -M /home/player/docker/shine-UI/js/pages/profile-view.js -@@ -6,2 +6,13 @@ - export function render({ navigate }) { -+ const badgeHelp = { -+ official: { -+ title: 'Официальный аккаунт', -+ text: 'Эта настройка включает или отключает отметку официального аккаунта в профиле. Используйте её, когда нужно показать или скрыть подтверждённый статус.', -+ }, -+ shine: { -+ title: 'Сияющий', -+ text: 'Этот переключатель включает или отключает режим «Сияющий». Он управляет отображением дополнительного визуального акцента для профиля.', -+ }, -+ }; -+ - const screen = document.createElement('section'); -@@ -25,4 +36,4 @@ -
--
✔ ${profile.badges[0]}
--
✨ ${profile.badges[1]}
-+ -+ -
-@@ -41,3 +52,53 @@ - -- screen.append(card); -+ const modal = document.createElement('div'); -+ modal.className = 'profile-help-modal'; -+ modal.hidden = true; -+ modal.innerHTML = ` -+
-+ -+ `; -+ -+ const titleEl = modal.querySelector('#profile-help-title'); -+ const textEl = modal.querySelector('.profile-help-text'); -+ -+ function closeModal() { -+ modal.hidden = true; -+ } -+ -+ function openModal(type) { -+ const content = badgeHelp[type]; -+ if (!content) return; -+ -+ titleEl.textContent = content.title; -+ textEl.textContent = content.text; -+ modal.hidden = false; -+ } -+ -+ card.querySelectorAll('.profile-badge-trigger').forEach((button) => { -+ button.addEventListener('click', () => openModal(button.dataset.badge)); -+ }); -+ -+ modal.addEventListener('click', (event) => { -+ const target = event.target; -+ if (target instanceof HTMLElement && (target.dataset.close === 'true' || target.classList.contains('profile-help-close'))) { -+ closeModal(); -+ } -+ }); -+ -+ modal.addEventListener('keydown', (event) => { -+ if (event.key === 'Escape') { -+ closeModal(); -+ } -+ }); -+ -+ screen.append(card, modal); - return screen; -apply_patch(auto_approved=true) exited 0 in 33ms: -Success. Updated the following files: -M /home/player/docker/shine-UI/js/pages/profile-view.js -file update: -diff --git a//home/player/docker/shine-UI/js/pages/profile-view.js b//home/player/docker/shine-UI/js/pages/profile-view.js -index 7007e0833f41d9b318fbedabb84ee7d44a42a97e..0ca25dc4432aa0f6a17686bf267fd89bdc32fa91 ---- a//home/player/docker/shine-UI/js/pages/profile-view.js -+++ b//home/player/docker/shine-UI/js/pages/profile-view.js -@@ -4,6 +4,17 @@ - export const pageMeta = { id: 'profile-view', title: 'Профиль' }; - - export function render({ navigate }) { -+ const badgeHelp = { -+ official: { -+ title: 'Официальный аккаунт', -+ text: 'Эта настройка включает или отключает отметку официального аккаунта в профиле. Используйте её, когда нужно показать или скрыть подтверждённый статус.', -+ }, -+ shine: { -+ title: 'Сияющий', -+ text: 'Этот переключатель включает или отключает режим «Сияющий». Он управляет отображением дополнительного визуального акцента для профиля.', -+ }, -+ }; -+ - const screen = document.createElement('section'); - screen.className = 'stack'; - -@@ -23,8 +34,8 @@ -
-
${profile.avatarInitials}
-
--
✔ ${profile.badges[0]}
--
✨ ${profile.badges[1]}
-+ -+ -
-
-
-@@ -39,6 +50,56 @@ -
- `; - -- screen.append(card); -+ const modal = document.createElement('div'); -+ modal.className = 'profile-help-modal'; -+ modal.hidden = true; -+ modal.innerHTML = ` -+
-+ -+ `; -+ -+ const titleEl = modal.querySelector('#profile-help-title'); -+ const textEl = modal.querySelector('.profile-help-text'); -+ -+ function closeModal() { -+ modal.hidden = true; -+ } -+ -+ function openModal(type) { -+ const content = badgeHelp[type]; -+ if (!content) return; -+ -+ titleEl.textContent = content.title; -+ textEl.textContent = content.text; -+ modal.hidden = false; -+ } -+ -+ card.querySelectorAll('.profile-badge-trigger').forEach((button) => { -+ button.addEventListener('click', () => openModal(button.dataset.badge)); -+ }); -+ -+ modal.addEventListener('click', (event) => { -+ const target = event.target; -+ if (target instanceof HTMLElement && (target.dataset.close === 'true' || target.classList.contains('profile-help-close'))) { -+ closeModal(); -+ } -+ }); -+ -+ modal.addEventListener('keydown', (event) => { -+ if (event.key === 'Escape') { -+ closeModal(); -+ } -+ }); -+ -+ screen.append(card, modal); - return screen; - } - -file update: -diff --git a//home/player/docker/shine-UI/js/pages/profile-view.js b//home/player/docker/shine-UI/js/pages/profile-view.js -index 7007e0833f41d9b318fbedabb84ee7d44a42a97e..0ca25dc4432aa0f6a17686bf267fd89bdc32fa91 ---- a//home/player/docker/shine-UI/js/pages/profile-view.js -+++ b//home/player/docker/shine-UI/js/pages/profile-view.js -@@ -4,6 +4,17 @@ - export const pageMeta = { id: 'profile-view', title: 'Профиль' }; - - export function render({ navigate }) { -+ const badgeHelp = { -+ official: { -+ title: 'Официальный аккаунт', -+ text: 'Эта настройка включает или отключает отметку официального аккаунта в профиле. Используйте её, когда нужно показать или скрыть подтверждённый статус.', -+ }, -+ shine: { -+ title: 'Сияющий', -+ text: 'Этот переключатель включает или отключает режим «Сияющий». Он управляет отображением дополнительного визуального акцента для профиля.', -+ }, -+ }; -+ - const screen = document.createElement('section'); - screen.className = 'stack'; - -@@ -23,8 +34,8 @@ -
-
${profile.avatarInitials}
-
--
✔ ${profile.badges[0]}
--
✨ ${profile.badges[1]}
-+ -+ -
-
-
-@@ -39,6 +50,56 @@ -
- `; - -- screen.append(card); -+ const modal = document.createElement('div'); -+ modal.className = 'profile-help-modal'; -+ modal.hidden = true; -+ modal.innerHTML = ` -+
-+ -+ `; -+ -+ const titleEl = modal.querySelector('#profile-help-title'); -+ const textEl = modal.querySelector('.profile-help-text'); -+ -+ function closeModal() { -+ modal.hidden = true; -+ } -+ -+ function openModal(type) { -+ const content = badgeHelp[type]; -+ if (!content) return; -+ -+ titleEl.textContent = content.title; -+ textEl.textContent = content.text; -+ modal.hidden = false; -+ } -+ -+ card.querySelectorAll('.profile-badge-trigger').forEach((button) => { -+ button.addEventListener('click', () => openModal(button.dataset.badge)); -+ }); -+ -+ modal.addEventListener('click', (event) => { -+ const target = event.target; -+ if (target instanceof HTMLElement && (target.dataset.close === 'true' || target.classList.contains('profile-help-close'))) { -+ closeModal(); -+ } -+ }); -+ -+ modal.addEventListener('keydown', (event) => { -+ if (event.key === 'Escape') { -+ closeModal(); -+ } -+ }); -+ -+ screen.append(card, modal); - return screen; - } - -file update -M /home/player/docker/shine-UI/styles/components.css -@@ -89,2 +89,6 @@ - -+.badge.profile-badge-trigger { -+ cursor: pointer; -+} -+ - .badge.alt { -@@ -95,2 +99,36 @@ - -+.profile-help-modal[hidden] { -+ display: none; -+} -+ -+.profile-help-modal { -+ position: fixed; -+ inset: 0; -+ z-index: 20; -+} -+ -+.profile-help-backdrop { -+ position: absolute; -+ inset: 0; -+ background: rgba(5, 9, 16, 0.72); -+ backdrop-filter: blur(4px); -+} -+ -+.profile-help-dialog { -+ position: absolute; -+ left: 16px; -+ right: 16px; -+ bottom: 24px; -+ display: grid; -+ gap: 12px; -+ padding: 16px; -+ box-shadow: var(--shadow); -+} -+ -+.profile-help-text { -+ color: #d8e3ff; -+ line-height: 1.45; -+ font-size: 14px; -+} -+ - .list-item { -apply_patch(auto_approved=true) exited 0 in 32ms: -Success. Updated the following files: -M /home/player/docker/shine-UI/styles/components.css -file update: -diff --git a//home/player/docker/shine-UI/js/pages/profile-view.js b//home/player/docker/shine-UI/js/pages/profile-view.js -index 7007e0833f41d9b318fbedabb84ee7d44a42a97e..0ca25dc4432aa0f6a17686bf267fd89bdc32fa91 ---- a//home/player/docker/shine-UI/js/pages/profile-view.js -+++ b//home/player/docker/shine-UI/js/pages/profile-view.js -@@ -4,6 +4,17 @@ - export const pageMeta = { id: 'profile-view', title: 'Профиль' }; - - export function render({ navigate }) { -+ const badgeHelp = { -+ official: { -+ title: 'Официальный аккаунт', -+ text: 'Эта настройка включает или отключает отметку официального аккаунта в профиле. Используйте её, когда нужно показать или скрыть подтверждённый статус.', -+ }, -+ shine: { -+ title: 'Сияющий', -+ text: 'Этот переключатель включает или отключает режим «Сияющий». Он управляет отображением дополнительного визуального акцента для профиля.', -+ }, -+ }; -+ - const screen = document.createElement('section'); - screen.className = 'stack'; - -@@ -23,8 +34,8 @@ -
-
${profile.avatarInitials}
-
--
✔ ${profile.badges[0]}
--
✨ ${profile.badges[1]}
-+ -+ -
-
-
-@@ -39,6 +50,56 @@ -
- `; - -- screen.append(card); -+ const modal = document.createElement('div'); -+ modal.className = 'profile-help-modal'; -+ modal.hidden = true; -+ modal.innerHTML = ` -+
-+ -+ `; -+ -+ const titleEl = modal.querySelector('#profile-help-title'); -+ const textEl = modal.querySelector('.profile-help-text'); -+ -+ function closeModal() { -+ modal.hidden = true; -+ } -+ -+ function openModal(type) { -+ const content = badgeHelp[type]; -+ if (!content) return; -+ -+ titleEl.textContent = content.title; -+ textEl.textContent = content.text; -+ modal.hidden = false; -+ } -+ -+ card.querySelectorAll('.profile-badge-trigger').forEach((button) => { -+ button.addEventListener('click', () => openModal(button.dataset.badge)); -+ }); -+ -+ modal.addEventListener('click', (event) => { -+ const target = event.target; -+ if (target instanceof HTMLElement && (target.dataset.close === 'true' || target.classList.contains('profile-help-close'))) { -+ closeModal(); -+ } -+ }); -+ -+ modal.addEventListener('keydown', (event) => { -+ if (event.key === 'Escape') { -+ closeModal(); -+ } -+ }); -+ -+ screen.append(card, modal); - return screen; - } -diff --git a//home/player/docker/shine-UI/styles/components.css b//home/player/docker/shine-UI/styles/components.css -index faa813fb5d384f1a4cfafd860398c8843a4b8841..1c33cf1eb9f441e3974dc9d2d44f5d4ee61b260f ---- a//home/player/docker/shine-UI/styles/components.css -+++ b//home/player/docker/shine-UI/styles/components.css -@@ -87,12 +87,50 @@ - font-weight: 600; - } - -+.badge.profile-badge-trigger { -+ cursor: pointer; -+} -+ - .badge.alt { - border-color: rgba(83, 216, 251, 0.35); - color: #dff8ff; - background: rgba(83, 216, 251, 0.11); - } - -+.profile-help-modal[hidden] { -+ display: none; -+} -+ -+.profile-help-modal { -+ position: fixed; -+ inset: 0; -+ z-index: 20; -+} -+ -+.profile-help-backdrop { -+ position: absolute; -+ inset: 0; -+ background: rgba(5, 9, 16, 0.72); -+ backdrop-filter: blur(4px); -+} -+ -+.profile-help-dialog { -+ position: absolute; -+ left: 16px; -+ right: 16px; -+ bottom: 24px; -+ display: grid; -+ gap: 12px; -+ padding: 16px; -+ box-shadow: var(--shadow); -+} -+ -+.profile-help-text { -+ color: #d8e3ff; -+ line-height: 1.45; -+ font-size: 14px; -+} -+ - .list-item { - display: grid; - grid-template-columns: 44px 1fr auto; - -file update: -diff --git a//home/player/docker/shine-UI/js/pages/profile-view.js b//home/player/docker/shine-UI/js/pages/profile-view.js -index 7007e0833f41d9b318fbedabb84ee7d44a42a97e..0ca25dc4432aa0f6a17686bf267fd89bdc32fa91 ---- a//home/player/docker/shine-UI/js/pages/profile-view.js -+++ b//home/player/docker/shine-UI/js/pages/profile-view.js -@@ -4,6 +4,17 @@ - export const pageMeta = { id: 'profile-view', title: 'Профиль' }; - - export function render({ navigate }) { -+ const badgeHelp = { -+ official: { -+ title: 'Официальный аккаунт', -+ text: 'Эта настройка включает или отключает отметку официального аккаунта в профиле. Используйте её, когда нужно показать или скрыть подтверждённый статус.', -+ }, -+ shine: { -+ title: 'Сияющий', -+ text: 'Этот переключатель включает или отключает режим «Сияющий». Он управляет отображением дополнительного визуального акцента для профиля.', -+ }, -+ }; -+ - const screen = document.createElement('section'); - screen.className = 'stack'; - -@@ -23,8 +34,8 @@ -
-
${profile.avatarInitials}
-
--
✔ ${profile.badges[0]}
--
✨ ${profile.badges[1]}
-+ -+ -
-
-
-@@ -39,6 +50,56 @@ -
- `; - -- screen.append(card); -+ const modal = document.createElement('div'); -+ modal.className = 'profile-help-modal'; -+ modal.hidden = true; -+ modal.innerHTML = ` -+
-+ -+ `; -+ -+ const titleEl = modal.querySelector('#profile-help-title'); -+ const textEl = modal.querySelector('.profile-help-text'); -+ -+ function closeModal() { -+ modal.hidden = true; -+ } -+ -+ function openModal(type) { -+ const content = badgeHelp[type]; -+ if (!content) return; -+ -+ titleEl.textContent = content.title; -+ textEl.textContent = content.text; -+ modal.hidden = false; -+ } -+ -+ card.querySelectorAll('.profile-badge-trigger').forEach((button) => { -+ button.addEventListener('click', () => openModal(button.dataset.badge)); -+ }); -+ -+ modal.addEventListener('click', (event) => { -+ const target = event.target; -+ if (target instanceof HTMLElement && (target.dataset.close === 'true' || target.classList.contains('profile-help-close'))) { -+ closeModal(); -+ } -+ }); -+ -+ modal.addEventListener('keydown', (event) => { -+ if (event.key === 'Escape') { -+ closeModal(); -+ } -+ }); -+ -+ screen.append(card, modal); - return screen; - } -diff --git a//home/player/docker/shine-UI/styles/components.css b//home/player/docker/shine-UI/styles/components.css -index faa813fb5d384f1a4cfafd860398c8843a4b8841..1c33cf1eb9f441e3974dc9d2d44f5d4ee61b260f ---- a//home/player/docker/shine-UI/styles/components.css -+++ b//home/player/docker/shine-UI/styles/components.css -@@ -87,12 +87,50 @@ - font-weight: 600; - } - -+.badge.profile-badge-trigger { -+ cursor: pointer; -+} -+ - .badge.alt { - border-color: rgba(83, 216, 251, 0.35); - color: #dff8ff; - background: rgba(83, 216, 251, 0.11); - } - -+.profile-help-modal[hidden] { -+ display: none; -+} -+ -+.profile-help-modal { -+ position: fixed; -+ inset: 0; -+ z-index: 20; -+} -+ -+.profile-help-backdrop { -+ position: absolute; -+ inset: 0; -+ background: rgba(5, 9, 16, 0.72); -+ backdrop-filter: blur(4px); -+} -+ -+.profile-help-dialog { -+ position: absolute; -+ left: 16px; -+ right: 16px; -+ bottom: 24px; -+ display: grid; -+ gap: 12px; -+ padding: 16px; -+ box-shadow: var(--shadow); -+} -+ -+.profile-help-text { -+ color: #d8e3ff; -+ line-height: 1.45; -+ font-size: 14px; -+} -+ - .list-item { - display: grid; - grid-template-columns: 44px 1fr auto; - -codex -Добавлю ещё одну небольшую доработку для надёжности: попап должен закрываться по `Esc`, поэтому дам диалогу фокус при открытии, без глобальных обработчиков и лишней инфраструктуры. -file update -M /home/player/docker/shine-UI/js/pages/profile-view.js -@@ -57,3 +57,3 @@ -
--