SHiNE — структура БД (актуальная версия)

Перечень таблиц и назначение

solana_users
Справочник пользователей: логин + ключ устройства + (опционально) Solana-ключ.
Базовая таблица, используется как FK почти везде.

active_sessions
Активные сессии авторизации/работы клиента: секреты, тайминги, WebPush-данные, IP и информация о клиенте.

users_params
Хранилище актуальных параметров пользователя.
Для каждой пары (login, param) хранится только самая новая версия по time_ms.

ip_geo_cache
Кеш геолокации по IP для снижения нагрузки на внешние сервисы.

blockchain_state
Агрегированное состояние блокчейна по blockchain_name:
лимиты, текущий размер, последний глобальный блок и состояние линий 0..7.

blocks
Журнал всех блоков и сообщений.
Содержит историю событий: тексты, реакции, ответы, связи.
PRIMARY KEY намеренно отсутствует.

connections_state ⭐
Актуальное состояние связей между пользователями
(друг / контакт / подписка).
Обновляется автоматически на основе событий из blocks.

message_stats ⭐
Агрегированные счётчики лайков и ответов на конкретные сообщения.
Поддерживается триггерами из blocks.

Таблицы подробно

solana_users
login — TEXT PK — уникальный логин пользователя
device_key — TEXT NOT NULL — публичный ключ устройства (Base64(32) / HEX(64))
solana_key — TEXT NULL — публичный ключ Solana-аккаунта

active_sessions
session_id — TEXT PK — идентификатор сессии
login — TEXT NOT NULL, FK → solana_users(login)
session_pwd — TEXT NOT NULL — секрет сессии
storage_pwd — TEXT NOT NULL — секрет storage
session_created_at_ms — INTEGER NOT NULL
last_authirificated_at_ms — INTEGER NOT NULL
push_endpoint — TEXT NULL
push_p256dh_key — TEXT NULL
push_auth_key — TEXT NULL
client_ip — TEXT NULL
client_info_from_client — TEXT NULL
client_info_from_request — TEXT NULL
user_language — TEXT NULL

users_params
login — TEXT NOT NULL, FK → solana_users(login)
param — TEXT NOT NULL
time_ms — INTEGER NOT NULL
value — TEXT NOT NULL
device_key — TEXT NULL
signature — TEXT NULL

Ограничение:
UNIQUE(login, param)

Логика:
обновление принимается только если excluded.time_ms > users_params.time_ms

ip_geo_cache
ip — TEXT PK
geo — TEXT NULL
updated_at_ms — INTEGER NOT NULL

blockchain_state
blockchain_name — TEXT PK
login — TEXT NOT NULL, FK → solana_users(login)
blockchain_key — TEXT NOT NULL
size_limit — INTEGER NOT NULL
file_size_bytes — INTEGER NOT NULL
last_global_number — INTEGER NOT NULL (-1 = genesis)
last_global_hash — TEXT NOT NULL
updated_at_ms — INTEGER NOT NULL

Линии 0..7:
для каждой линии:
lineX_last_number
lineX_last_hash

blocks
login — TEXT NOT NULL
bch_name — TEXT NOT NULL
block_global_number — INTEGER NOT NULL
block_global_pre_hash — TEXT NOT NULL
block_line_index — INTEGER NOT NULL
block_line_number — INTEGER NOT NULL
block_line_pre_hash — TEXT NOT NULL
msg_type — INTEGER NOT NULL
msg_sub_type — INTEGER NOT NULL
block_bytes — BLOB NULL

Ссылка на другой блок (nullable):
to_login
to_bch_name
to_block_global_number
to_block_hash

connections_state ⭐
Текущее агрегированное состояние связей.

login — TEXT NOT NULL
rel_type — INTEGER NOT NULL
10 = FRIEND
20 = CONTACT
30 = FOLLOW
to_login — TEXT NOT NULL
to_bch_name — TEXT NOT NULL
to_block_global_number — INTEGER NULL
to_block_hash — TEXT NULL

Ограничение:
UNIQUE(login, rel_type, to_login)

message_stats ⭐
Счётчики активности по целевому сообщению.

to_login — TEXT NOT NULL
to_bch_name — TEXT NOT NULL
to_block_global_number — INTEGER NOT NULL
to_block_hash — TEXT NOT NULL
likes_count — INTEGER NOT NULL DEFAULT 0
replies_count — INTEGER NOT NULL DEFAULT 0

UNIQUE:
(to_login, to_bch_name, to_block_global_number, to_block_hash)

Триггеры БД (полная логика)

3.1 Связи пользователей
trg_blocks_connection_state_ai
AFTER INSERT ON blocks

Условие:
msg_type = 3 (connection)

Добавление / обновление связи
msg_sub_type IN (10,20,30)
выполняется UPSERT в connections_state

Удаление связи
msg_sub_type IN (11,21,31)
удаляется соответствующая связь:
11 → 10
21 → 20
31 → 30

Итог:
blocks — журнал событий
connections_state — всегда актуальное состояние

3.2 Подсчёт лайков ⭐
trg_blocks_message_stats_like_ai
AFTER INSERT ON blocks

Условие:
msg_type = 2 (reaction)
msg_sub_type = 1 (like)

Действие:
определяется цель по to_bch_name, to_block_global_number, to_block_hash
to_login вычисляется как
substr(to_bch_name, 1, length(to_bch_name) - 3)
выполняется UPSERT в message_stats
likes_count += 1

3.3 Подсчёт ответов ⭐
trg_blocks_message_stats_reply_ai
AFTER INSERT ON blocks

Условие:
msg_type = 1 (text)
msg_sub_type = 2 (reply)

Действие:
цель определяется аналогично лайкам
выполняется UPSERT в message_stats
replies_count += 1

Индексы (смысл)

idx_solana_users_login — поиск пользователя
idx_active_sessions_login — сессии пользователя
idx_users_params_login — параметры пользователя
idx_ip_geo_cache_updated_at — чистка кеша
idx_blockchain_state_login — блокчейны пользователя
idx_blockchain_state_updated_at — обслуживание
idx_blocks_chain_global — чтение цепочки
idx_blocks_to_target — реакции / ответы
idx_message_stats_target — быстрый доступ к счётчикам

Итоговая модель мышления

blocks — неизменяемый журнал событий
connections_state — проекция связей
message_stats — проекция активности
всё вычисляется детерминированно через триггеры