diff --git a/Dev_Docs/00_INDEX.md b/Dev_Docs/00_INDEX.md new file mode 100644 index 0000000..342bfa6 --- /dev/null +++ b/Dev_Docs/00_INDEX.md @@ -0,0 +1,28 @@ +# Dev_Docs — оглавление + +Этот набор документов сделан по текущему состоянию кода сервера (`/workspace/SHiNE-server`) и разбит по темам. + +## Список документов + +1. **01_Connection_and_Sessions.md** + Процесс подключения к WebSocket, авторизация (двухшаговая), создание сессии, вход в существующую сессию, просмотр и закрытие сессий. + +2. **02_Blockchain_Structure_and_Block_Types.md** + Архитектура блокчейна, форматы и типы блоков, что уже можно делать каждым типом блока. + +3. **03_Addable_Blocks_Channels_Messages_Connections.md** + Какие блоки добавляются через `AddBlock`, как делать каналы/подписки/контакты/друзей/лайки/ответы, что уже есть и чего не хватает в API. + +4. **04_Query_Design_for_Subscriptions_Counters_and_Sync.md** + Проектирование новых API-запросов: список подписок с общим/новым числом сообщений, список сообщений канала, граф ответов для сообщения, поток синхронизации online/offline. + +5. **05_Open_Questions_and_TODO.md** + Список открытых вопросов, рисков и приоритетов для доработки сервера. + +## Почему так разбито + +- **Сначала протокол и сессии** — это входная точка клиента. +- **Потом блокчейн-слой** — какие данные вообще можно выразить блоками. +- **Потом прикладные функции (каналы/сообщения/связи)** — что реально можно сделать уже сейчас. +- **Потом проектирование отсутствующих запросов** — чтобы закрыть разрыв между текущим сервером и нужной функциональностью клиента. +- **В конце вопросы** — чтобы быстро согласовать спорные места. diff --git a/Dev_Docs/01_Connection_and_Sessions.md b/Dev_Docs/01_Connection_and_Sessions.md new file mode 100644 index 0000000..8621a60 --- /dev/null +++ b/Dev_Docs/01_Connection_and_Sessions.md @@ -0,0 +1,65 @@ +# Соединение с сервером и сессии + +## 1) Базовый транспорт + +- Сервер работает по WebSocket + JSON-протокол (`op`, `requestId`, `payload`). +- Для каждой операции есть handler в `JsonHandlerRegistry`. + +## 2) Схема авторизации (актуальная) + +В проекте реализованы **две двухшаговые схемы**: + +### A. Создание новой сессии (через device key) + +1. `AuthChallenge(login)` + - сервер проверяет, что пользователь существует; + - кладёт в контекст соединения `authNonce`. + +2. `CreateAuthSession(...)` + - клиент подписывает строку `AUTH_CREATE_SESSION:{login}:{timeMs}:{authNonce}` приватным **device key**; + - сервер валидирует подпись, создаёт запись в `active_sessions`, возвращает `sessionId`; + - в сессии хранится `session_key` (публичный ключ сессии), который клиент сгенерировал для дальнейших логинов. + +### B. Вход в существующую сессию (через session key) + +1. `SessionChallenge(sessionId)` + - сервер выдаёт одноразовый nonce с TTL. + +2. `SessionLogin(sessionId, timeMs, signature)` + - клиент подписывает `SESSION_LOGIN:{sessionId}:{timeMs}:{nonce}` приватным ключом сессии; + - сервер проверяет подпись по `active_sessions.session_key`; + - при успехе возвращает `storagePwd`. + +## 3) Работа со списком сессий + +### `ListSessions` + +- Доступно только в состоянии `AUTH_STATUS_USER`. +- Возвращает все активные сессии текущего пользователя: + - `sessionId` + - информация о клиенте + - `lastAuthirificatedAtMs` + - гео (по ip, через кэш/lookup). + +### `CloseActiveSession` + +- В реестре операций присутствует. +- Используется для закрытия указанной или текущей сессии. + +## 4) Важные детали безопасности + +- Есть проверка рассинхрона времени клиента (обычно ±30 секунд). +- Nonce одноразовые, хранятся в контексте конкретного ws-соединения. +- При ошибках подписи/контекста сервер может закрывать WebSocket. + +## 5) Что уже хорошо + +- Разделены key-и: `device key` (создание сессии) и `session key` (повторные входы). +- Не передаётся приватный ключ — только подписи. +- Авторизация привязана к challenge/nonce. + +## 6) Что стоит дополнительно улучшить + +1. Добавить централизованный лимит попыток на `SessionLogin`/`CreateAuthSession`. +2. Логировать причины отказов в метриках (без утечки чувствительных данных). +3. Явно документировать формат Base64 (URL-safe/standard) для каждого поля, чтобы клиенты не путались. diff --git a/Dev_Docs/02_Blockchain_Structure_and_Block_Types.md b/Dev_Docs/02_Blockchain_Structure_and_Block_Types.md new file mode 100644 index 0000000..3b4b399 --- /dev/null +++ b/Dev_Docs/02_Blockchain_Structure_and_Block_Types.md @@ -0,0 +1,103 @@ +# Структура блокчейна и типы блоков + +## 1) Общая модель + +Каждый блок содержит: + +- заголовок (тип, subtype, version, blockNumber и пр.); +- `bodyBytes` (полезная нагрузка конкретного типа); +- хэш и подпись. + +На сервере при `AddBlock` выполняется: + +1. Проверка формата блока. +2. `body.check()`. +3. Проверка непрерывности цепочки (`blockNumber == last + 1`, `prevHash`). +4. Проверка подписи блока ключом блокчейна. +5. Сохранение в БД + файл блокчейна. + +## 2) Типы блоков (msg_type) + +## type=0 (TECH / HEADER) + +- `HEADER_COMPAT (subType=0)` — стартовый служебный блок. +- `TECH_CREATE_CHANNEL (subType=1)` — создание канала (линии) с именем канала. + +Что можно делать: +- инициализировать blockchain; +- заводить новые каналы внутри blockchain. + +## type=1 (TEXT) + +- `TEXT_POST (10)` — публикация в линии канала. +- `TEXT_EDIT_POST (11)` — редактирование поста (target на оригинал). +- `TEXT_REPLY (20)` — reply на любой target (может быть чужой блокчейн). +- `TEXT_EDIT_REPLY (21)` — редактирование reply. + +Что можно делать: +- публиковать посты в каналы; +- делать древовидные ответы; +- редактировать ранее отправленные тексты. + +## type=2 (REACTION) + +- `REACTION_LIKE (1)` — лайк на target-блок. + +Что можно делать: +- ставить лайки на сообщение. + +## type=3 (CONNECTION) + +- `FRIEND / UNFRIEND` +- `CONTACT / UNCONTACT` +- `FOLLOW / UNFOLLOW` + +Что можно делать: +- дружба, контакты, подписки. + +## type=4 (USER_PARAM) + +- `USER_PARAM_TEXT_TEXT (1)` — произвольный `key/value` параметр пользователя. + +Что можно делать: +- хранить пользовательские технические настройки и состояние синхронизации. + +## 3) Линии (line model) + +Для части блоков есть line-поля: +- `line_code` +- `prev_line_number` +- `prev_line_hash` +- `this_line_number` + +Смысл: +- отдельные последовательности для каналов/связей/параметров; +- БД-триггеры проверяют целостность ссылок line->prev. + +## 4) Target model + +Для reply/like/connection/edit используются target-поля: +- `to_bch_name` +- `to_block_number` +- `to_block_hash` +- `to_login` (сервер может вычислять из blockchainName). + +Это позволяет строить граф: +- кто на кого подписался; +- кто кому ответил; +- кто какой блок лайкнул; +- какой блок является edit какого. + +## 5) Сильные стороны текущей структуры + +- Достаточно выразительная модель для соц-сценариев (каналы/ответы/лайки/связи). +- Есть счетчики `message_stats` (likes/replies/edits) на уровне БД. +- Есть `connections_state` как «текущее состояние», собранное триггерами. + +## 6) Важный текущий риск + +В проекте есть **несовпадение констант subType между модулями** (`shine-server-blockchain` и `shine-server-db`): +- в blockchain-модуле `TEXT_POST=10, REPLY=20...` +- в db-модуле местами используются старые `TEXT_NEW=1, REPLY=2...` + +Это нужно унифицировать, иначе часть триггеров/DAO будет работать некорректно. diff --git a/Dev_Docs/03_Addable_Blocks_Channels_Messages_Connections.md b/Dev_Docs/03_Addable_Blocks_Channels_Messages_Connections.md new file mode 100644 index 0000000..b49d6db --- /dev/null +++ b/Dev_Docs/03_Addable_Blocks_Channels_Messages_Connections.md @@ -0,0 +1,75 @@ +# Какие блоки можно добавлять и что уже есть по API + +## 1) Что реально доступно по сети сейчас + +В `JsonHandlerRegistry` сейчас есть: +- `AddBlock` +- `GetFriendsLists` +- `UpsertUserParam`, `GetUserParam`, `ListUserParams` +- auth/system и тестовые операции. + +Отдельных read-API для каналов/сообщений пока нет (только запись блока + частично списки друзей + user params). + +## 2) Как добавляются блоки + +Через `AddBlock` клиент отправляет: +- blockchainName +- blockNumber +- prevBlockHash +- blockBytesB64 + +Сервер: +- парсит block; +- проверяет подпись блокчейна; +- извлекает `line`/`target` из body; +- сохраняет в `blocks`; +- обновляет `blockchain_state`; +- триггеры автоматически обновляют производные таблицы (`connections_state`, `message_stats`). + +## 3) Конкретные сценарии + +### 3.1 Создать канал + +Добавить TECH-блок `CreateChannelBody` (type=0/subType=TECH_CREATE_CHANNEL). + +### 3.2 Опубликовать сообщение в своём канале + +Добавить `TEXT_POST` в нужную линию канала (`lineCode` указывает на root канала). + +### 3.3 Ответ на сообщение + +Добавить `TEXT_REPLY` с target (`toBlockchainName`, `toBlockGlobalNumber`, `toBlockHash32`). + +### 3.4 Лайк + +Добавить `REACTION_LIKE` с target сообщения. + +### 3.5 Подписаться / отписаться от канала + +Добавить `CONNECTION_FOLLOW` / `CONNECTION_UNFOLLOW` с target root канала. + +### 3.6 Добавить в контакты/друзья + +- Контакты: `CONNECTION_CONTACT` / `CONNECTION_UNCONTACT`. +- Друзья: `CONNECTION_FRIEND` / `CONNECTION_UNFRIEND`. + +## 4) Есть ли метод «подписаться на канал» кроме публикации? + +Да: подписка — это **не отдельный RPC**, а блок `CONNECTION_FOLLOW`, отправляемый через `AddBlock`. + +## 5) Есть ли методы для сохранения технического состояния (например, сколько прочитано) + +Да, есть `UpsertUserParam`. + +Практично хранить: +- `channel_last_read:: -> ` +- `channel_last_sync_at -> ` + +Ограничение: `users_params` сейчас хранит строки `param/value`, то есть сложные структуры лучше класть в JSON-строку с версией схемы. + +## 6) Чего не хватает прямо сейчас + +1. Нет RPC, который вернёт **список подписанных каналов** и счётчики сообщений. +2. Нет RPC, который вернёт **сообщения конкретного канала** (с пагинацией). +3. Нет RPC, который вернёт **подробный тред сообщения** (предки + все ответы) одним JSON. +4. Нет RPC «ленты событий» (кто лайкнул/ответил/подписался) как отдельного серверного канала. diff --git a/Dev_Docs/04_Query_Design_for_Subscriptions_Counters_and_Sync.md b/Dev_Docs/04_Query_Design_for_Subscriptions_Counters_and_Sync.md new file mode 100644 index 0000000..619e3c2 --- /dev/null +++ b/Dev_Docs/04_Query_Design_for_Subscriptions_Counters_and_Sync.md @@ -0,0 +1,137 @@ +# Проектирование запросов: подписки, счетчики, синхронизация, сообщения + +## 1) Цель + +Сделать один запрос, который отдаёт: +- все каналы пользователя (подписки + опционально self-каналы); +- сколько сообщений всего в каждом канале; +- сколько новых (с учётом last_read). + +И отдельно: +- запрос сообщений канала; +- запрос треда конкретного сообщения (предки + все потомки + stats). + +## 2) Предлагаемые API + +## A. `ListMyChannelsWithCounters` + +### Request +```json +{ + "op": "ListMyChannelsWithCounters", + "requestId": "...", + "includeSelf": true, + "includePrivate": true +} +``` + +### Response +```json +{ + "op": "ListMyChannelsWithCounters", + "requestId": "...", + "status": 200, + "channels": [ + { + "channelId": "targetBch:targetRootBlock", + "channelType": "personal|public|system_notifications|dm", + "ownerLogin": "Alice", + "bchName": "Alice-001", + "lineCode": 0, + "title": "Alice main", + "totalMessages": 1234, + "lastReadSeq": 1200, + "newMessages": 34, + "lastMessage": { + "blockNumber": 3500, + "timeMs": 1760000000000, + "preview": "..." + } + } + ] +} +``` + +## B. `GetChannelMessages` + +- Возвращает сообщения канала по `channelId` или `(bchName,lineCode)`. +- Нужны `limit`, `before/after`, сортировка и флаг `includeStats`. + +## C. `GetMessageThreadGraph` + +Один JSON для: +- целевого сообщения; +- всей цепочки родителей до корня; +- всех ответов (даже 100+); +- stats по каждому узлу (`likes/replies/edits`). + +## 3) Как считать total/new + +## Источник truth по подпискам + +Использовать `connections_state` где `rel_type=FOLLOW`. + +## Источник сообщений канала + +`blocks` где `msg_type=TEXT` и блок принадлежит линии канала (`line_code`). + +## Источник last_read + +`users_params` ключ вида `read.` = число (last seen seq или blockNumber). + +`newMessages = max(0, totalMessages - lastReadSeq)` (или по blockNumber/seq в выбранной модели). + +## 4) Offline/online синхронизация + +Рекомендуемый поток: + +1. Клиент локально хранит last_read/last_sync. +2. При подключении делает: + - `ListMyChannelsWithCounters` + - затем по каналам с `newMessages > 0` делает `GetChannelMessages`. +3. После отображения сообщений обновляет сервер через `UpsertUserParam` (или новый bulk-метод). +4. Сервер всегда остаётся source of truth для chain/подписок; клиент — кэш. + +## 5) Подписи и device key + +- Операции изменения данных пользователя (`UpsertUserParam`) уже подписываются device key. +- Для нового bulk-обновления read-состояния лучше сохранить тот же принцип: подписанный payload от device key. + +## 6) Разделение каналов: личные / обычные / системные + +Предложение: + +- `personal_main`: root = HEADER (`lineCode=0`) пользователя. +- `public_channel`: root = CREATE_CHANNEL (lineCode = blockNumber root). +- `dm_channel`: отдельный тип канала (пока не реализован; либо как специальный connection+line policy). +- `system_notifications`: виртуальный/материализованный канал событий (ответы, лайки, follow/unfollow/friend/contact). + +## 7) Канал уведомлений (ответили/лайкнули/подписались) + +Сейчас это не готово как отдельная сущность API. + +Два варианта: + +1. **Виртуальный канал (рекомендуется сначала)** + - не писать новые блоки; + - собирать события SQL-запросом из `blocks` + `message_stats` + `connections_state`. + +2. **Материализованный канал** + - триггеры/воркер пишут отдельные event-записи в таблицу уведомлений; + - быстрее чтение, но сложнее консистентность. + +## 8) Что уже частично готово + +- База уже считает `likes/replies/edits` через `message_stats` триггеры. +- База уже держит текущее состояние связей через `connections_state`. + +## 9) Что нужно дописать в сервере + +1. Новые handlers в `JsonHandlerRegistry`: + - `ListMyChannelsWithCounters` + - `GetChannelMessages` + - `GetMessageThreadGraph` + - `ListNotificationFeed`. +2. Новые DAO + SQL-представления/CTE. +3. Унификация subType-констант (иначе статистика и выборки будут «плыть»). +4. Пагинация и лимиты ответа (для больших тредов). diff --git a/Dev_Docs/05_Open_Questions_and_TODO.md b/Dev_Docs/05_Open_Questions_and_TODO.md new file mode 100644 index 0000000..b1ca603 --- /dev/null +++ b/Dev_Docs/05_Open_Questions_and_TODO.md @@ -0,0 +1,40 @@ +# Открытые вопросы и TODO для согласования + +## Критичные вопросы + +1. **Единая нумерация subType** + - Подтверждаем ли окончательно новую схему (`POST=10, REPLY=20...`) во всех модулях (`db`, `triggers`, `dao`)? + +2. **Что считаем “сообщением канала” для counters** + - Только `TEXT_POST`? + - Или ещё `TEXT_EDIT_POST` и/или `REPLY` в этом же line? + +3. **Что такое “прочитано”** + - По `this_line_number`? + - По `block_number`? + - По времени? + +4. **Личные и публичные каналы** + - Явно вводим `channelType` в API? + - Нужны ли отдельные private/dm каналы в MVP? + +5. **Уведомления (лайк/reply/follow/friend)** + - Делаем сначала виртуальный канал (query-time), потом материализацию? + +## Технический TODO (рекомендуемый порядок) + +1. Унифицировать `MsgSubType` между модулями. +2. Добавить DAO для выборки каналов с counters. +3. Добавить read-api handlers (3-4 операции, описанные в 04 документе). +4. Добавить integration tests: + - подписка -> counters; + - read progress -> newMessages; + - thread graph на 100+ ответов. +5. Добавить индекс(ы) под новые query-паттерны (по `line_code`, `to_*`, `msg_type/subtype`). + +## Дополнительные идеи + +- Для `GetMessageThreadGraph` можно вводить режимы: + - `full` (все ответы) + - `compact` (первые N + hasMore) +- Для клиентской синхронизации можно добавить `syncToken` (версия снимка данных), чтобы отличать повторный ответ от изменений после запроса.