SHA256
Встроить синхронизацию Solana users в сервер
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
# PostgreSQL для серверов SHiNE
|
||||
|
||||
Этот документ фиксирует целевой стандарт PostgreSQL, который должен использоваться на всех серверных контурах SHiNE после ухода от SQLite.
|
||||
|
||||
Пока это не текущий production-state, а согласованная целевая схема, под которую можно писать миграции, deploy-скрипты и server-конфиги.
|
||||
|
||||
## Цель
|
||||
|
||||
На каждом сервере SHiNE должна быть отдельная локальная PostgreSQL-база:
|
||||
|
||||
- запускается в Docker;
|
||||
- использует `postgres:18`;
|
||||
- хранит данные не внутри контейнера, а в примонтированной папке хоста;
|
||||
- доступна только локально на сервере и из Docker-сети;
|
||||
- не публикуется в интернет;
|
||||
- автоматически перезапускается после reboot/crash;
|
||||
- имеет healthcheck;
|
||||
- использует отдельную БД приложения и отдельного пользователя приложения;
|
||||
- пароли и секреты хранятся только в локальном `.env`/override-конфиге на сервере и не коммитятся в git.
|
||||
|
||||
## Базовый стандарт
|
||||
|
||||
- Версия PostgreSQL: `18.x`
|
||||
- Docker image: `postgres:18`
|
||||
- Имена по умолчанию:
|
||||
- контейнер/сервис: `shine-postgres`
|
||||
- база приложения: `shine_server_db`
|
||||
- пользователь приложения: `shine_server`
|
||||
- Политика перезапуска: `unless-stopped`
|
||||
- Проверка готовности: `pg_isready`
|
||||
|
||||
## Сетевой доступ
|
||||
|
||||
PostgreSQL не должна быть доступна из интернета.
|
||||
|
||||
Разрешённые варианты:
|
||||
|
||||
- публиковать порт только на loopback:
|
||||
- `127.0.0.1:5432:5432`
|
||||
- либо не публиковать порт вообще, если клиент тоже живёт в Docker и ходит только по внутренней сети
|
||||
|
||||
Запрещено:
|
||||
|
||||
- `0.0.0.0:5432:5432`
|
||||
- открытие `5432/tcp` через внешний firewall/NAT/public ingress
|
||||
|
||||
Рекомендация по умолчанию для SHiNE:
|
||||
|
||||
- использовать `127.0.0.1:5432:5432`
|
||||
|
||||
Это даёт:
|
||||
|
||||
- локальную диагностику через `psql` на самом сервере;
|
||||
- отсутствие внешнего доступа из интернета;
|
||||
- совместимость с приложением, если оно работает не в Docker.
|
||||
|
||||
## Хранение данных
|
||||
|
||||
Данные PostgreSQL должны храниться в локальной папке хоста, а не во внутреннем Docker volume контейнера.
|
||||
|
||||
Причины:
|
||||
|
||||
- проще бэкапить;
|
||||
- проще переносить между серверами;
|
||||
- проще контролировать место хранения;
|
||||
- одинаковая схема для dev/test/production;
|
||||
- ниже риск потерять данные при пересоздании контейнера.
|
||||
|
||||
Рекомендуемая схема каталогов на сервере:
|
||||
|
||||
Production:
|
||||
|
||||
```text
|
||||
/home/player/SHiNE/postgres/shine_server_db
|
||||
```
|
||||
|
||||
Test/devnet:
|
||||
|
||||
```text
|
||||
/home/player/tX/postgres/shine_server_db
|
||||
```
|
||||
|
||||
Если на одном сервере появится несколько баз SHiNE-сервисов, раскладывать их по отдельным каталогам:
|
||||
|
||||
```text
|
||||
/home/player/SHiNE/postgres/shine_server_db
|
||||
/home/player/SHiNE/postgres/analytics_db
|
||||
/home/player/SHiNE/postgres/other_service_db
|
||||
```
|
||||
|
||||
## Пользователи и права
|
||||
|
||||
Нужны два уровня доступа:
|
||||
|
||||
- системный `postgres` superuser для администрирования;
|
||||
- рабочий пользователь приложения `shine_server` для подключения самого SHiNE server.
|
||||
|
||||
Требования:
|
||||
|
||||
- приложение не должно работать под `postgres`;
|
||||
- `shine_server` не должен быть `superuser`;
|
||||
- `shine_server` должен владеть своей БД `shine_server_db`;
|
||||
- для миграций по умолчанию использовать пользователя приложения, если ему хватает прав;
|
||||
- административные операции выполнять отдельно под `postgres`.
|
||||
|
||||
## Секреты
|
||||
|
||||
В git нельзя хранить:
|
||||
|
||||
- `.env` с реальными паролями;
|
||||
- connection strings с паролями;
|
||||
- SQL-файлы с зашитыми production/test паролями.
|
||||
|
||||
Хранить на сервере локально, например:
|
||||
|
||||
```text
|
||||
/home/player/SHiNE/postgres/.env
|
||||
```
|
||||
|
||||
или в другом root-only каталоге секретов хоста.
|
||||
|
||||
Минимально нужны:
|
||||
|
||||
- пароль `postgres`
|
||||
- пароль `shine_server`
|
||||
|
||||
Допустимо, но не рекомендуется, временно использовать одинаковый пароль для локального dev. Для production и постоянных test-серверов лучше разные пароли.
|
||||
|
||||
## Пример целевого compose
|
||||
|
||||
Ниже пример целевой схемы, которую можно брать за основу для серверов:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
shine-postgres:
|
||||
image: postgres:18
|
||||
container_name: shine-postgres
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_SUPERUSER_DB}
|
||||
POSTGRES_USER: ${POSTGRES_SUPERUSER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_SUPERUSER_PASSWORD}
|
||||
PGDATA: /var/lib/postgresql/data/pgdata
|
||||
ports:
|
||||
- "127.0.0.1:5432:5432"
|
||||
volumes:
|
||||
- ${SHINE_POSTGRES_DATA_DIR}:/var/lib/postgresql/data
|
||||
- ./initdb:/docker-entrypoint-initdb.d:ro
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- pg_isready -U "$${POSTGRES_SUPERUSER}" -d "$${POSTGRES_SUPERUSER_DB}"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 20s
|
||||
```
|
||||
|
||||
## Рекомендуемые переменные окружения
|
||||
|
||||
```dotenv
|
||||
POSTGRES_SUPERUSER_DB=postgres
|
||||
POSTGRES_SUPERUSER=postgres
|
||||
POSTGRES_SUPERUSER_PASSWORD=change_me
|
||||
SHINE_APP_DB=shine_server_db
|
||||
SHINE_APP_USER=shine_server
|
||||
SHINE_APP_PASSWORD=change_me_too
|
||||
SHINE_POSTGRES_DATA_DIR=/home/player/SHiNE/postgres/shine_server_db
|
||||
```
|
||||
|
||||
Для test/devnet путь адаптировать под конкретный контур:
|
||||
|
||||
```dotenv
|
||||
SHINE_POSTGRES_DATA_DIR=/home/player/t2/postgres/shine_server_db
|
||||
```
|
||||
|
||||
## Подключение приложения
|
||||
|
||||
SHiNE server должен подключаться именно к:
|
||||
|
||||
- host: `127.0.0.1`
|
||||
- port: `5432`
|
||||
- db: `shine_server_db`
|
||||
- user: `shine_server`
|
||||
|
||||
Не подключать серверное приложение под `postgres`, кроме одноразовых административных операций вручную.
|
||||
|
||||
## Бэкапы
|
||||
|
||||
Так как данные лежат в bind-mount каталоге хоста, сама папка с данными должна попадать в серверную backup-стратегию.
|
||||
|
||||
Но для PostgreSQL предпочтителен не только файловый backup, а как минимум один из вариантов:
|
||||
|
||||
- регулярный `pg_dump`
|
||||
- либо полноценный backup-скрипт с остановкой приложения/согласованным snapshot
|
||||
|
||||
Минимальное требование:
|
||||
|
||||
- перед серьёзными миграциями иметь свежий backup БД;
|
||||
- перед production rollout новой серверной версии иметь проверяемый backup.
|
||||
|
||||
## Для будущей миграции SHiNE
|
||||
|
||||
При переводе SHiNE server с SQLite на PostgreSQL считать обязательным:
|
||||
|
||||
- сначала поднять PostgreSQL по этому стандарту;
|
||||
- затем добавить серверные конфиги подключения;
|
||||
- затем прогнать миграции схемы;
|
||||
- только потом переключать runtime приложения на PostgreSQL.
|
||||
|
||||
До фактического rollout на конкретный сервер эта БД может ещё отсутствовать. Этот документ описывает не текущее наличие БД, а обязательный целевой стандарт для всех серверов SHiNE.
|
||||
@@ -20,6 +20,8 @@
|
||||
- `PRODUCTION_SERVERS.md` — production-контуры.
|
||||
- `TEST_SERVERS.md` — test/devnet-контуры.
|
||||
- `TURN_SERVERS.md` — TURN-серверы.
|
||||
- `POSTGRESQL_SERVERS_STANDARD.md` — целевой стандарт PostgreSQL для всех серверов SHiNE.
|
||||
- `SOLANA_USERS_SYNC_SERVER_SETUP.md` — интеграция синхронизации пользовательских Solana PDA в основной сервер.
|
||||
- `CONFIGURE_TURN_IN_SHINE.md` — как подключить TURN к SHiNE backend.
|
||||
- `SETUP_SERVER_FROM_ZERO.md` — настройка SHiNE-сервера и UI с нуля.
|
||||
- `SETUP_TURN_SERVER.md` — настройка TURN через Caddy/DNS/TLS.
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
# Интеграция синхронизации `shine_users` в основной сервер
|
||||
|
||||
Этот документ описывает, что нужно для встраивания Solana sync-модуля пользовательских PDA в основной SHiNE-server.
|
||||
|
||||
Основной архитектурный документ:
|
||||
|
||||
- [docs/Solana/SOLANA_USERS_SYNC_MODULE_DESIGN.md](/home/ai/work/SHiNE/SHiNE-server-sha256/SHiNE-product/docs/Solana/SOLANA_USERS_SYNC_MODULE_DESIGN.md)
|
||||
|
||||
## Что уже готово
|
||||
|
||||
Отдельный модуль `sync-solana` уже умеет:
|
||||
|
||||
- подключаться к Solana RPC и WebSocket;
|
||||
- вычислять `users_economy_config_pda`;
|
||||
- хранить checkpoint синхронизации в PostgreSQL;
|
||||
- читать историю через `getSignaturesForAddress(users_economy_config_pda)`;
|
||||
- поддерживать realtime через websocket;
|
||||
- выполнять страховочный periodic poll раз в 5 минут;
|
||||
- хранить:
|
||||
- `solana_sync_state`
|
||||
- `solana_sync_tx_history`
|
||||
- `solana_user_pda_current`
|
||||
- `solana_user_pda_history`
|
||||
- блокировать дальнейший startup до входа в `READY`.
|
||||
|
||||
## Что нужно перенести в основной сервер
|
||||
|
||||
Из `sync-solana` в сервер нужно перенести рабочие классы:
|
||||
|
||||
- `sync-solana/src/main/java/sync-solana/config/`
|
||||
- `sync-solana/src/main/java/sync-solana/service/`
|
||||
- `sync-solana/src/main/java/sync-solana/source/`
|
||||
- `sync-solana/src/main/java/sync-solana/source/rpc/`
|
||||
- `sync-solana/src/main/java/sync-solana/storage/postgres/`
|
||||
- `sync-solana/src/main/java/sync-solana/codec/`
|
||||
- `sync-solana/src/main/java/sync-solana/model/`
|
||||
- `sync-solana/src/main/java/sync-solana/util/`
|
||||
|
||||
`Main.java` нужен только как reference для bootstrap и как отдельный `main` в сервере уже не понадобится.
|
||||
|
||||
Рекомендуемый вариант:
|
||||
|
||||
- оформить это как отдельный Gradle submodule внутри `SHiNE-server`;
|
||||
- запускать его из server startup как lifecycle-сервис.
|
||||
|
||||
## Порядок запуска в сервере
|
||||
|
||||
При старте основного сервера последовательность должна быть такой:
|
||||
|
||||
1. прочитать общий server config;
|
||||
2. создать Solana users sync service;
|
||||
3. вызвать `start()`;
|
||||
4. вызвать `awaitReady()`;
|
||||
5. только после этого продолжать остальной startup сервера:
|
||||
- синхронизацию с другими нодами;
|
||||
- запуск WS/HTTP;
|
||||
- остальную серверную инициализацию.
|
||||
|
||||
Если Solana initial sync не дошёл до `READY`, startup сервера должен считаться неуспешным.
|
||||
|
||||
## Переменные окружения сервера
|
||||
|
||||
На сервере должны быть доступны:
|
||||
|
||||
```text
|
||||
SOLANA_RPC_URL=
|
||||
SOLANA_WS_URL=
|
||||
SOLANA_PROGRAM_ID=SHiNEPr1APdAgNBteUyBXcNovaHctpSjUu8oH2ZJdN6
|
||||
SYNC_POLL_INTERVAL_SECONDS=300
|
||||
```
|
||||
|
||||
Для PostgreSQL sync-модуль может использовать уже существующую server PostgreSQL-конфигурацию, если сервер уже предоставляет:
|
||||
|
||||
```text
|
||||
DATABASE_URL=
|
||||
PGUSER=
|
||||
PGPASSWORD=
|
||||
```
|
||||
|
||||
Если в сервере используется другая схема конфигов, нужно сделать адаптер на уровне server config, а не менять саму логику sync.
|
||||
|
||||
## Логи
|
||||
|
||||
Sync-модуль должен писать в общие server logs через тот же `slf4j/logback`, что и основной сервер.
|
||||
|
||||
Минимум, который должен быть виден в логах:
|
||||
|
||||
- старт sync-модуля;
|
||||
- вход в `READY`;
|
||||
- realtime sync;
|
||||
- periodic poll;
|
||||
- reconnect websocket;
|
||||
- fallback на full snapshot;
|
||||
- ошибки RPC/WS/DB.
|
||||
|
||||
## Что потребуется по deploy
|
||||
|
||||
Отдельных deploy-скриптов для sync-модуля не требуется, если он встроен в основной server jar.
|
||||
|
||||
По deploy нужно:
|
||||
|
||||
- обновить server env/override-конфиг новыми переменными `SOLANA_*` и `SYNC_POLL_INTERVAL_SECONDS`;
|
||||
- убедиться, что на сервере доступен PostgreSQL, в который модуль будет писать свои таблицы;
|
||||
- при необходимости описать новые env в документации конкретного server-контура.
|
||||
|
||||
## Что ещё проверить после интеграции
|
||||
|
||||
После встраивания в основной сервер нужно отдельно проверить:
|
||||
|
||||
- startup сервера с ожиданием `awaitReady()`;
|
||||
- создание таблиц в server PostgreSQL;
|
||||
- initial sync после пустой БД;
|
||||
- restart recovery после уже существующего checkpoint;
|
||||
- realtime update через websocket;
|
||||
- periodic poll без новых транзакций;
|
||||
- fallback на full snapshot при потере history anchor.
|
||||
Reference in New Issue
Block a user