Add Dev_Docs with protocol, blockchain, and API design analysis
This commit is contained in:
parent
18bf5d65d7
commit
b23ecdfdf2
28
Dev_Docs/00_INDEX.md
Normal file
28
Dev_Docs/00_INDEX.md
Normal 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**
|
||||
Список открытых вопросов, рисков и приоритетов для доработки сервера.
|
||||
|
||||
## Почему так разбито
|
||||
|
||||
- **Сначала протокол и сессии** — это входная точка клиента.
|
||||
- **Потом блокчейн-слой** — какие данные вообще можно выразить блоками.
|
||||
- **Потом прикладные функции (каналы/сообщения/связи)** — что реально можно сделать уже сейчас.
|
||||
- **Потом проектирование отсутствующих запросов** — чтобы закрыть разрыв между текущим сервером и нужной функциональностью клиента.
|
||||
- **В конце вопросы** — чтобы быстро согласовать спорные места.
|
||||
65
Dev_Docs/01_Connection_and_Sessions.md
Normal file
65
Dev_Docs/01_Connection_and_Sessions.md
Normal 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) для каждого поля, чтобы клиенты не путались.
|
||||
103
Dev_Docs/02_Blockchain_Structure_and_Block_Types.md
Normal file
103
Dev_Docs/02_Blockchain_Structure_and_Block_Types.md
Normal 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 будет работать некорректно.
|
||||
75
Dev_Docs/03_Addable_Blocks_Channels_Messages_Connections.md
Normal file
75
Dev_Docs/03_Addable_Blocks_Channels_Messages_Connections.md
Normal 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 «ленты событий» (кто лайкнул/ответил/подписался) как отдельного серверного канала.
|
||||
137
Dev_Docs/04_Query_Design_for_Subscriptions_Counters_and_Sync.md
Normal file
137
Dev_Docs/04_Query_Design_for_Subscriptions_Counters_and_Sync.md
Normal 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. Пагинация и лимиты ответа (для больших тредов).
|
||||
40
Dev_Docs/05_Open_Questions_and_TODO.md
Normal file
40
Dev_Docs/05_Open_Questions_and_TODO.md
Normal 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` (версия снимка данных), чтобы отличать повторный ответ от изменений после запроса.
|
||||
Loading…
Reference in New Issue
Block a user