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 — проекция активности всё вычисляется детерминированно через триггеры