Add Dev_Docs with protocol, blockchain, and API design analysis

This commit is contained in:
ai5590 2026-03-26 15:27:59 +03:00
parent 18bf5d65d7
commit b23ecdfdf2
6 changed files with 448 additions and 0 deletions

28
Dev_Docs/00_INDEX.md Normal file
View File

@ -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**
Список открытых вопросов, рисков и приоритетов для доработки сервера.
## Почему так разбито
- **Сначала протокол и сессии** — это входная точка клиента.
- **Потом блокчейн-слой** — какие данные вообще можно выразить блоками.
- **Потом прикладные функции (каналы/сообщения/связи)** — что реально можно сделать уже сейчас.
- **Потом проектирование отсутствующих запросов** — чтобы закрыть разрыв между текущим сервером и нужной функциональностью клиента.
- **В конце вопросы** — чтобы быстро согласовать спорные места.

View File

@ -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) для каждого поля, чтобы клиенты не путались.

View File

@ -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 будет работать некорректно.

View File

@ -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:<bchName>:<lineCode> -> <lastSeenMessageSeq или blockNumber>`
- `channel_last_sync_at -> <time_ms>`
Ограничение: `users_params` сейчас хранит строки `param/value`, то есть сложные структуры лучше класть в JSON-строку с версией схемы.
## 6) Чего не хватает прямо сейчас
1. Нет RPC, который вернёт **список подписанных каналов** и счётчики сообщений.
2. Нет RPC, который вернёт **сообщения конкретного канала** (с пагинацией).
3. Нет RPC, который вернёт **подробный тред сообщения** (предки + все ответы) одним JSON.
4. Нет RPC «ленты событий» (кто лайкнул/ответил/подписался) как отдельного серверного канала.

View File

@ -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.<channelId>` = число (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. Пагинация и лимиты ответа (для больших тредов).

View File

@ -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` (версия снимка данных), чтобы отличать повторный ответ от изменений после запроса.