Сервер: дочистить PostgreSQL runtime и документацию

This commit is contained in:
AidarKC
2026-07-27 18:01:15 +04:00
parent b5116474c7
commit 618a30c2ab
20 changed files with 47 additions and 46 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ SHiNE-server — серверная часть мессенджера SHiNE: Web
- `shine-server-net-server/` — точка входа, запуск HTTP/WS сервера - `shine-server-net-server/` — точка входа, запуск HTTP/WS сервера
- `shine-server-net-protocol/` — обработчики операций (RPC и события WS) - `shine-server-net-protocol/` — обработчики операций (RPC и события WS)
- `shine-server-db/` — DAO, SQL-схема, SQLite - `shine-server-db/` — DAO, SQL-схема, PostgreSQL runtime
- `shine-server-blockchain/` — логика хранения и проверки блоков блокчейна - `shine-server-blockchain/` — логика хранения и проверки блоков блокчейна
- `shine-server-crypto/` — криптографические утилиты - `shine-server-crypto/` — криптографические утилиты
- `shine-server-config/` — конфигурация сервера - `shine-server-config/` — конфигурация сервера
@@ -36,10 +36,6 @@ public final class DbController implements DbProvider {
return delegate.getConnection(); return delegate.getConnection();
} }
public boolean isPostgres() {
return true;
}
@Override @Override
public void close() { public void close() {
delegate.close(); delegate.close();
@@ -7,7 +7,7 @@ import java.sql.SQLException;
/** /**
* Базовый JDBC provider поверх DriverManager. * Базовый JDBC provider поверх DriverManager.
* *
* Не знает ничего про SQLite/PostgreSQL как про доменные режимы: * Не знает ничего про конкретный доменный режим БД:
* конкретные параметры и post-connect инициализация задаются снаружи. * конкретные параметры и post-connect инициализация задаются снаружи.
*/ */
public final class DriverManagerDbProvider implements DbProvider { public final class DriverManagerDbProvider implements DbProvider {
@@ -24,7 +24,7 @@ import java.sql.SQLException;
* - эта схема проще и прозрачнее, чем много обратных триггеров по разным таблицам; * - эта схема проще и прозрачнее, чем много обратных триггеров по разным таблицам;
* - если любой шаг не удался, делаем rollback и БД остаётся в исходном состоянии; * - если любой шаг не удался, делаем rollback и БД остаётся в исходном состоянии;
* - файловые действия (.bch / .tmp_bch) сознательно НЕ входят в эту транзакцию: * - файловые действия (.bch / .tmp_bch) сознательно НЕ входят в эту транзакцию:
* SQLite не может атомарно закоммитить и SQL, и файловую систему сразу; * SQL-транзакция и файловая система не коммитятся атомарно вместе;
* поэтому БД-чистка делается здесь, а файловая чистка будет следующим шагом * поэтому БД-чистка делается здесь, а файловая чистка будет следующим шагом
* отдельным recovery/resync-слоем после успешного commit. * отдельным recovery/resync-слоем после успешного commit.
* *
@@ -14,7 +14,7 @@ import java.util.List;
* Таблица: solana_users * Таблица: solana_users
* *
* Колонки: * Колонки:
* - login TEXT PRIMARY KEY (COLLATE NOCASE) * - login TEXT PRIMARY KEY
* - blockchain_name TEXT NOT NULL * - blockchain_name TEXT NOT NULL
* - solana_key TEXT NOT NULL * - solana_key TEXT NOT NULL
* - blockchain_key TEXT NOT NULL * - blockchain_key TEXT NOT NULL
@@ -8,7 +8,7 @@ import java.util.Base64;
* Таблица: solana_users * Таблица: solana_users
* *
* Поля: * Поля:
* - login — PRIMARY KEY (TEXT) (case-insensitive на уровне COLLATE NOCASE) * - login — PRIMARY KEY (TEXT)
* - blockchain_name — TEXT NOT NULL * - blockchain_name — TEXT NOT NULL
* - solana_key — TEXT NOT NULL * - solana_key — TEXT NOT NULL
* - blockchain_key — TEXT NOT NULL * - blockchain_key — TEXT NOT NULL
@@ -4,7 +4,7 @@
-- Назначение: -- Назначение:
-- - поднять пустую PostgreSQL БД сервера SHiNE с нуля; -- - поднять пустую PostgreSQL БД сервера SHiNE с нуля;
-- - включить таблицы модуля синхронизации Solana users; -- - включить таблицы модуля синхронизации Solana users;
-- - включить runtime-таблицы сервера без legacy SQLite таблиц: -- - включить runtime-таблицы сервера без legacy-таблиц старого runtime:
-- * НЕ создаём solana_users -- * НЕ создаём solana_users
-- * НЕ создаём direct_messages -- * НЕ создаём direct_messages
-- * основной runtime DM storage = signed_messages -- * основной runtime DM storage = signed_messages
@@ -12,7 +12,7 @@
-- Важно: -- Важно:
-- - источник истины по пользователям: solana_user_pda_current; -- - источник истины по пользователям: solana_user_pda_current;
-- - runtime table blockchain_state остаётся как локальное серверное состояние chain, -- - runtime table blockchain_state остаётся как локальное серверное состояние chain,
-- но не мигрируется из старой SQLite и не считается identity-слоем; -- но не мигрируется из старого локального runtime и не считается identity-слоем;
-- - триггеры переписаны под PostgreSQL и сохраняют текущую серверную логику. -- - триггеры переписаны под PostgreSQL и сохраняют текущую серверную логику.
BEGIN; BEGIN;
@@ -42,8 +42,7 @@ public class Net_AddCloseFriend_Handler implements JsonMessageHandler {
} }
// Idempotent insert for close-friend relation. // Idempotent insert for close-friend relation.
// Using INSERT OR IGNORE avoids ON CONFLICT(column list) mismatches // Rely on PostgreSQL ON CONFLICT DO NOTHING.
// across DB instances with different UNIQUE schemas.
insertCloseFriendIgnoreDuplicate(c, from, canonicalTo, targetBch); insertCloseFriendIgnoreDuplicate(c, from, canonicalTo, targetBch);
Net_AddCloseFriend_Response resp = new Net_AddCloseFriend_Response(); Net_AddCloseFriend_Response resp = new Net_AddCloseFriend_Response();
+1 -1
View File
@@ -67,7 +67,7 @@ The SHiNE Java server uses third-party dependencies from Maven Central, includin
- Jackson (`com.fasterxml.jackson.core:jackson-databind`) - Apache-2.0 - Jackson (`com.fasterxml.jackson.core:jackson-databind`) - Apache-2.0
- Logback (`ch.qos.logback:logback-classic`) - EPL-1.0 / LGPL-2.1 - Logback (`ch.qos.logback:logback-classic`) - EPL-1.0 / LGPL-2.1
- SLF4J (`org.slf4j:slf4j-api`) - MIT - SLF4J (`org.slf4j:slf4j-api`) - MIT
- SQLite JDBC (`org.xerial:sqlite-jdbc`) - Apache-2.0 - PostgreSQL JDBC (`org.postgresql:postgresql`) - BSD-2-Clause
- Web Push Java library (`nl.martijndwars:web-push`) - Apache-2.0 - Web Push Java library (`nl.martijndwars:web-push`) - Apache-2.0
- JUnit (`org.junit:*`) - EPL-2.0 - JUnit (`org.junit:*`) - EPL-2.0
+1 -1
View File
@@ -49,7 +49,7 @@
- `medium/2026-05-26_0029_esp32s3_file_storage.md` - ESP32S3 как личное файловое хранилище SHiNE для файлов переписок и вложений. - `medium/2026-05-26_0029_esp32s3_file_storage.md` - ESP32S3 как личное файловое хранилище SHiNE для файлов переписок и вложений.
- `medium/2026-06-02_сессионные_homeserver_в_pda.md` - несколько homeserver-ов пользователя как типизированные сессии в PDA с версией записи. - `medium/2026-06-02_сессионные_homeserver_в_pda.md` - несколько homeserver-ов пользователя как типизированные сессии в PDA с версией записи.
- `medium/2026-06-03_подключение_других_устройств_через_qr.md` - довести подключение других устройств через QR: сейчас заготовка есть, но сценарий работает нестабильно и его нужно будет отдельно доделать. - `medium/2026-06-03_подключение_других_устройств_через_qr.md` - довести подключение других устройств через QR: сейчас заготовка есть, но сценарий работает нестабильно и его нужно будет отдельно доделать.
- `medium/2026-07-22_переход_с_sqlite_на_postgresql.md` - подготовить перевод серверной БД с `SQLite` на `PostgreSQL` для более серьёзной конкурентной нагрузки и дальнейшего масштабирования. - `medium/2026-07-22_переход_с_sqlite_на_postgresql.md` - завершить зачистку хвостов после перевода серверной БД с `SQLite` на `PostgreSQL`.
### dao_запуск ### dao_запуск
@@ -2,32 +2,30 @@
## Зачем ## Зачем
Текущая серверная база на `SQLite` удобна для простого односерверного режима, но она хуже подходит для большого числа параллельных записей, роста нагрузки и дальнейшего масштабирования сервера. Переход runtime-сервера на `PostgreSQL` уже выполнен, но после него остались хвосты в документации, именах, комментариях и части прямых SQL-запросов.
`PostgreSQL` нужен как следующий уровень серверной БД для более надёжной конкурентной записи, более предсказуемой работы под нагрузкой и дальнейшего роста проекта. Этот TODO теперь нужен не для самого перехода, а для доведения проекта до полностью консистентного состояния после ухода от `SQLite`.
## Что сделать ## Что сделать
- Подготовить план переноса серверной БД с `SQLite` на `PostgreSQL`. - Дочистить документацию, где ещё описан `SQLite` как текущий runtime.
- Найти все места, где код завязан на особенности `SQLite`. - Убрать или переименовать legacy-названия и комментарии, которые уже не соответствуют PostgreSQL runtime.
- Проверить все DAO и SQL-запросы на совместимость с `PostgreSQL`. - Постепенно перенести оставшиеся прямые SQL-запросы из хэндлеров в DAO/service.
- Продумать схему миграции существующей production/test базы без потери данных. - Проверить case-insensitive сравнения, уникальные ограничения и индексы уже в чисто PostgreSQL модели.
- Отдельно проверить транзакции, `UPSERT`, индексы, case-insensitive сравнения и миграции схемы. - Отдельно пройтись по TODO/служебным документам и убрать ссылки на удалённые SQLite-классы как на актуальный код.
- После этого подготовить отдельный этап внедрения и переключения сервера.
## Что уже есть в коде ## Что уже есть в коде
- Доступ к БД в основном проходит через DAO-слой, а не полностью размазан по проекту. - Доступ к БД в основном проходит через DAO-слой, а не полностью размазан по проекту.
- Основная серверная логика уже разделена по модулям. - Основная серверная логика уже разделена по модулям.
- Но SQL и миграции сейчас написаны под `SQLite` и потребуют отдельного прохода. - Runtime-сервер уже работает только с `PostgreSQL`.
- Пустая БД инициализируется автоматически через `schema_v1`.
## Откуда продолжать ## Откуда продолжать
- Начать с инвентаризации всех DAO и схемы БД. - Продолжать с зачистки legacy-документации и комментариев.
- После этого сделать отдельный документ с оценкой объёма работ по переносу. - Затем добрать оставшиеся прямые SQL-запросы вне DAO.
- Затем решить, будет ли это: - После этого можно отдельно решать вопрос косметического переименования `*V2`, `DbController` и других переходных сущностей.
- полный перевод сервера на `PostgreSQL`;
- или поддержка двух драйверов на переходный период.
## Что потом обновить ## Что потом обновить
@@ -11,7 +11,7 @@
## Что именно потом сделать ## Что именно потом сделать
- удалить временную миграцию `migrateToV11()` из [SqliteDbController.java](/home/ai/work/SHiNE/SHiNE-server-sha256/SHiNE-server/shine-server-db/src/main/java/shine/db/SqliteDbController.java); - найти историческое место, где была добавлена временная миграция `migrateToV11()`, и убрать её остатки из runtime-логики/документации;
- удалить helper `clearLegacySignedMessagesForDmV11(...)`; - удалить helper `clearLegacySignedMessagesForDmV11(...)`;
- поднять версию схемы дальше обычным образом уже без destructive-cleanup; - поднять версию схемы дальше обычным образом уже без destructive-cleanup;
- при необходимости заменить это на нормальную точечную миграцию старых DM-записей или совсем убрать поддержку старой истории. - при необходимости заменить это на нормальную точечную миграцию старых DM-записей или совсем убрать поддержку старой истории.
+1 -1
View File
@@ -1,2 +1,2 @@
client.version=1.2.354 client.version=1.2.354
server.version=1.2.331 server.version=1.2.332
+9 -2
View File
@@ -46,7 +46,9 @@ Production пример:
```properties ```properties
server.port=7070 server.port=7070
server.SHiNE.login=shineupme server.SHiNE.login=shineupme
db.path=data/shine.sqlite db.url=jdbc:postgresql://127.0.0.1:5432/shine_server_db
db.user=shine_server
db.password=CHANGE_ME
server.ui.indexPath=/home/player/SHiNE/shine-ui/index.html server.ui.indexPath=/home/player/SHiNE/shine-ui/index.html
server.info.url=https://shineup.me server.info.url=https://shineup.me
server.info.origin=production server.info.origin=production
@@ -58,7 +60,9 @@ Test/devnet пример:
```properties ```properties
server.port=7102 server.port=7102
server.SHiNE.login=server_t2 server.SHiNE.login=server_t2
db.path=data/shine.sqlite db.url=jdbc:postgresql://127.0.0.1:5432/shine_t2_db
db.user=shine_t2
db.password=CHANGE_ME
server.ui.indexPath=/home/player/t2/UI/index.html server.ui.indexPath=/home/player/t2/UI/index.html
server.info.url=https://t2.shineup.me server.info.url=https://t2.shineup.me
server.info.origin=devnet server.info.origin=devnet
@@ -66,6 +70,9 @@ solana.cluster=devnet
solana.rpcUrl=https://api.devnet.solana.com solana.rpcUrl=https://api.devnet.solana.com
``` ```
Если указан `db.url` и в выбранной БД ещё нет таблицы `db_schema_version`,
сервер сам создаст runtime-схему PostgreSQL при первом старте.
## 5. Caddy ## 5. Caddy
Минимальный site block: Минимальный site block:
+2 -2
View File
@@ -92,5 +92,5 @@ cp /path/to/SHiNE-product/application.properties ./application.properties
## Что пока остаётся как есть ## Что пока остаётся как есть
- `sync_servers` сервер по-прежнему загружает из server PDA в Solana; - `sync_servers` сервер по-прежнему загружает из server PDA в Solana;
- старый SQLite runtime код ещё может лежать в репозитории, но новая runtime-схема на него не должна опираться; - runtime-сервер уже работает только с PostgreSQL;
- механический перенос DAO и runtime SQL на PostgreSQL делается отдельным шагом после утверждения схемы `v1`. - дальнейшим отдельным шагом остаются зачистка legacy-документации, переименования и перенос оставшихся прямых SQL-запросов в DAO/service.
+1 -1
View File
@@ -9,7 +9,7 @@
- загрузка идёт через **серверный Arweave-кошелёк**; - загрузка идёт через **серверный Arweave-кошелёк**;
- лимит на пользователя: по умолчанию `3` загрузки за всё время; - лимит на пользователя: по умолчанию `3` загрузки за всё время;
- лимит хранится в SQLite-таблице `test_free_avatar_uploads`; - лимит хранится в PostgreSQL-таблице `test_free_avatar_uploads`;
- если лимит исчерпан, сервер возвращает понятную ошибку; - если лимит исчерпан, сервер возвращает понятную ошибку;
- загружать можно только маленький итоговый файл аватара, по умолчанию до `128 KB`. - загружать можно только маленький итоговый файл аватара, по умолчанию до `128 KB`.
@@ -550,7 +550,7 @@ SYNC_POLL_INTERVAL_SECONDS=300
3. выделить lifecycle-сервис с `awaitReady()`; 3. выделить lifecycle-сервис с `awaitReady()`;
4. реализовать вычисление `users_economy_config_pda`; 4. реализовать вычисление `users_economy_config_pda`;
5. реализовать polling истории по сигнатурам; 5. реализовать polling истории по сигнатурам;
6. добавить новые SQLite-таблицы; 6. добавить runtime-таблицы PostgreSQL;
7. добавить запись в `current` и `history`; 7. добавить запись в `current` и `history`;
8. добавить periodic guard раз в 5 минут; 8. добавить periodic guard раз в 5 минут;
9. сохранить отдельный `main` для запуска как процесса. 9. сохранить отдельный `main` для запуска как процесса.
+5 -6
View File
@@ -1,17 +1,16 @@
shine-server-bd — это библиотека реалезующая всю работу с БД: shine-server-bd — это библиотека реалезующая всю работу с БД:
хранит пользователей/сессии/параметры/кэш IP→гео и данные блокчейна (состояние + блоки), предоставляя единый SqliteDbController для соединений, набор DAO под каждую таблицу (Singleton, методы с Connection для транзакций и без Connection — сами открывают/закрывают), и простые entity-модели как контейнеры данных для маппинга ResultSet↔Java. хранит пользователей/сессии/параметры/кэш IP→гео и данные блокчейна (состояние + блоки), предоставляя единый PostgreSQL runtime-контроллер соединений, набор DAO под каждую таблицу (Singleton, методы с Connection для транзакций и без Connection — сами открывают/закрывают), и простые entity-модели как контейнеры данных для маппинга ResultSet↔Java.
Логика структуры классов (в двух словах): Логика структуры классов (в двух словах):
shine.db.SqliteDbController — один вход в БД: читает db.path, при отсутствии файла создаёт БД, выдаёт новые Connection и настраивает PRAGMA. shine.db.DbController / shine.db.PostgresDbController — вход в runtime БД: читает `db.url/db.user/db.password`, подключается только к PostgreSQL и выдаёт новые `Connection`.
shine.db.DatabaseInitializer — разовая сборка схемы (таблицы + индексы). shine.db.DatabaseInitializer — проверяет наличие `db_schema_version` и при пустой БД автоматически накатывает `postgres/schema_v1.sql`.
shine.db.entities.* — POJO-модели строк таблиц (без логики, только поля/геттеры/сеттеры + иногда удобные методы вроде getClientKeyByte()). shine.db.entities.* — POJO-модели строк таблиц (без логики, только поля/геттеры/сеттеры + иногда удобные методы вроде getClientKeyByte()).
shine.db.dao.* — DAO по таблицам: ActiveSessionsDAO, SolanaUsersDAO, UserParamsDAO, IpGeoCacheDAO, BlockchainStateDAO, BlocksDAO; плюс “сервисные” DAO: shine.db.dao.* — DAO по таблицам: ActiveSessionsDAO, SolanaUsersDAO, UserParamsDAO, IpGeoCacheDAO, BlockchainStateDAO, BlocksDAO; плюс “сервисные” DAO:
UserCreateDAO — атомарная регистрация пользователя в транзакции (BEGIN IMMEDIATE + rollback/commit). UserCreateDAO — атомарная регистрация пользователя в транзакции (BEGIN IMMEDIATE + rollback/commit).
// Временное решение позволяющее регистрировать новых пользователей // Временное runtime-решение, позволяющее регистрировать новых пользователей
// атомарно и добавляет запись и в solana_users и в BlockchainState // атомарно и добавляющее запись в runtime-таблицы сервера.
@@ -62,7 +62,7 @@
## Что не входит в v1 ## Что не входит в v1
- удаление legacy SQLite-классов; - полная зачистка legacy-документации, старых названий и TODO-хвостов;
- переименование Java DAO/классов `*V2` в runtime-коде; - переименование Java DAO/классов `*V2` в runtime-коде;
- перенос прямых SQL-запросов из хэндлеров в DAO/service; - перенос прямых SQL-запросов из хэндлеров в DAO/service;
- переключение всего runtime-кода на новый `DbProvider`. - переключение всего runtime-кода на новый `DbProvider`.
+3 -1
View File
@@ -4,4 +4,6 @@ shine-server-config
Настройки: Настройки:
server.port=7070 — порт запуска сервера server.port=7070 — порт запуска сервера
db.path=data/shine.sqlite — путь к SQLite базе данных db.url=jdbc:postgresql://127.0.0.1:5432/shine_server_db — JDBC URL PostgreSQL
db.user=shine_server — пользователь PostgreSQL
db.password=... — пароль пользователя PostgreSQL