SHA256
Навести порядок в deploy и документации проекта
This commit is contained in:
@@ -189,7 +189,7 @@
|
||||
3. Переносить эти изменения назад в код минимально необходимыми правками.
|
||||
4. Если из Figma следует уже не только визуальная, но и UX-логическая правка, отдельно проверить, что она согласована пользователем.
|
||||
|
||||
## Когда нужно добавить заметку в Pending_Features
|
||||
## Когда нужно отдельно согласовать ручную проверку
|
||||
|
||||
Если после изменения по Figma:
|
||||
- поменялась логика flow;
|
||||
@@ -197,7 +197,7 @@
|
||||
- нужен реальный прогон на test2;
|
||||
- затронута интеграция с Solana;
|
||||
|
||||
тогда нужно добавить файл в `docs/Pending_Features/`.
|
||||
тогда нужно отдельно согласовать ручную проверку с пользователем.
|
||||
|
||||
## Что пока не оформлено для Miro
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
# Поддержать проект Сияние
|
||||
|
||||
Статус: `pending`
|
||||
|
||||
## Кратко
|
||||
|
||||
В `shine-UI/js/pages/wallet-view.js` добавлен новый раздел `Поддержать проект Сияние` с тремя входами:
|
||||
|
||||
1. купить билет;
|
||||
2. посмотреть билет по номеру;
|
||||
3. сгенерировать новую пару ключей.
|
||||
|
||||
## Что проверить
|
||||
|
||||
1. Открыть `Кошелёк`.
|
||||
2. Перейти в `Поддержать проект Сияние`.
|
||||
3. Проверить экран покупки:
|
||||
- виден коэффициент;
|
||||
- виден остаток лимита очереди 1;
|
||||
- виден расчет в SOL;
|
||||
- кнопка `Справка` открывает отдельный экран;
|
||||
- покупка блокируется, если сумма больше остатка лимита.
|
||||
4. Проверить экран просмотра:
|
||||
- `12` ищется как билет очереди 1;
|
||||
- `2-5` и `3 8` ищутся как билеты очередей 2 и 3;
|
||||
- показываются статус, количество билетов до него и уже выплаченные значения.
|
||||
5. Проверить генератор ключей:
|
||||
- генерируется новая пара ключей;
|
||||
- публичный и секретный ключи показываются;
|
||||
- можно скопировать и скачать результат;
|
||||
- дополнительный текст в поле необязателен.
|
||||
|
||||
## Ожидаемый результат
|
||||
|
||||
- Экран раздела поддержки открывается из `wallet-view`.
|
||||
- Покупка билета выполняется по текущему курсу и с допуском 3%.
|
||||
- По номеру билета показывается понятная сводка по очереди.
|
||||
- Генерация ключей использует безопасный браузерный рандом и не требует сохранения секретного ключа.
|
||||
@@ -1,20 +0,0 @@
|
||||
# Promo-логины через продавцов в Solana
|
||||
|
||||
- краткое описание:
|
||||
- в `shine_users` добавлена поддержка PDA продавцов красивых логинов, promo-подписи `shine_promo_v1:<login>` и отдельная автономная страница `shine-UI/promo-code-generator.html` для генерации promo-кода через браузерный кошелёк или через ручной ввод Base58 seed 32 bytes;
|
||||
- что проверять:
|
||||
- admin-транзакцией создать или обновить `promo_seller_pda`;
|
||||
- сгенерировать promo-код на странице `promo-code-generator.html` в режиме wallet extension;
|
||||
- сгенерировать promo-код на той же странице в режиме ручного Base58 seed;
|
||||
- открыть HTML локально как отдельный файл без сервера и убедиться, что генерация в режиме Base58 seed продолжает работать;
|
||||
- зарегистрировать короткий/premium логин по promo-коду;
|
||||
- убедиться, что без promo-кода тот же логин не проходит `shine_login_guard`;
|
||||
- убедиться, что после успешной регистрации `remaining_sales` уменьшается на 1;
|
||||
- проверить отказ при исчерпанной квоте, неверной подписи и логине короче `min_login_length`;
|
||||
- ожидаемый результат:
|
||||
- promo-регистрация проходит только при валидной подписи продавца и соблюдении лимитов;
|
||||
- обычная регистрация без promo-кода продолжает работать как раньше;
|
||||
- страница генерации выдаёт строку формата `1seller-signatureBase58` в обоих режимах;
|
||||
- single-file HTML работает локально оффлайн минимум в режиме ручного Base58 seed;
|
||||
- статус:
|
||||
- `pending`
|
||||
@@ -1,51 +0,0 @@
|
||||
# Синхронизация mainnet-адресов Solana по UI/серверу/ESP32
|
||||
|
||||
- статус: `pending`
|
||||
|
||||
## Кратко
|
||||
|
||||
Во все основные клиентские и серверные точки проекта протянуты актуальные mainnet-адреса программ:
|
||||
|
||||
- `shine_login_guard`: `SHiGxGsXGioQYCYhchQ5R7KWoxN5UjFAFsucPf6sfnh`
|
||||
- `shine_users`: `SHiNEPr1APdAgNBteUyBXcNovaHctpSjUu8oH2ZJdN6`
|
||||
- `shine_payments`: `SHiPmXbM9Fs9khzRUW3TGKsS2W84aqaXTxs3ZkajW9v`
|
||||
|
||||
Также по умолчанию переключены основные RPC defaults на `https://api.mainnet-beta.solana.com` там, где это нужно для рабочего mainnet-сценария.
|
||||
|
||||
## Что проверять
|
||||
|
||||
1. Основной UI:
|
||||
- отображение и использование новых program id;
|
||||
- регистрация/чтение Solana PDA в mainnet;
|
||||
- экран кошелька и покупка лимита.
|
||||
|
||||
2. Server UI:
|
||||
- создание server PDA в mainnet;
|
||||
- чтение PDA;
|
||||
- обновление PDA;
|
||||
- корректная блокировка devnet-автопополнения при mainnet endpoint.
|
||||
|
||||
3. Browser plugin wallet:
|
||||
- резолв `user_pda` и `server PDA` через mainnet RPC.
|
||||
|
||||
4. Web UI `shine_payments`:
|
||||
- чтение очередей;
|
||||
- покупка билета;
|
||||
- admin/manager/dao tools открываются с новыми program id и mainnet RPC.
|
||||
|
||||
5. ESP32 homeserver UI:
|
||||
- отображаются новые program id;
|
||||
- дефолтный Solana RPC теперь mainnet.
|
||||
|
||||
6. Временный режим регистрации:
|
||||
- в основном UI логины длиной 5-7 символов без временного кода не проходят;
|
||||
- в основном UI логины длиной 5-7 символов с временным кодом проходят локальную проверку;
|
||||
- в основном UI любой другой временный код отклоняется сразу;
|
||||
- ESP32 и прямой on-chain вызов `shine_users` полагаются на текущий временный `shine_login_guard`, то есть валидные логины длиной от 5 символов допускаются без словарной классификации.
|
||||
|
||||
## Ожидаемый результат
|
||||
|
||||
- Во всех перечисленных поверхностях используются новые mainnet program id.
|
||||
- Запросы по умолчанию идут в mainnet, кроме явно devnet-утилит.
|
||||
- Нет обращений к старым devnet program id.
|
||||
- Временный UI-барьер для коротких логинов работает так, как задумано, и не ломает обычную регистрацию для логинов от 8 символов.
|
||||
@@ -1,42 +0,0 @@
|
||||
# Временный режим коротких логинов
|
||||
|
||||
- статус: `pending`
|
||||
|
||||
## Кратко
|
||||
|
||||
Временно упрощён `shine_login_guard`:
|
||||
|
||||
- on-chain допускаются любые валидные логины длиной от `5` символов;
|
||||
- словарная premium/trademark-классификация временно отключена.
|
||||
|
||||
Поверх этого основной UI вводит временное ограничение:
|
||||
|
||||
- логины длиной `8+` проходят обычную проверку;
|
||||
- логины длиной `5..7` допускаются только при вводе временного кода;
|
||||
- любой другой код отклоняется сразу.
|
||||
|
||||
ESP32 в этом временном режиме не ограничивается UI-кодом и использует только on-chain правила.
|
||||
|
||||
## Что проверять
|
||||
|
||||
1. Основной UI:
|
||||
- логин длиной `4` символа отклоняется;
|
||||
- логин длиной `5..7` без временного кода отклоняется;
|
||||
- логин длиной `5..7` с корректным временным кодом проходит локальную проверку;
|
||||
- логин длиной `5..7` с любым другим кодом отклоняется;
|
||||
- логин длиной `8+` проходит без временного кода.
|
||||
|
||||
2. Solana on-chain:
|
||||
- `shine_login_guard` возвращает `CLASS_FREE` для валидных логинов длиной от `5`;
|
||||
- `shine_login_guard` возвращает `CLASS_PREMIUM` для логинов короче `5` или с невалидными символами.
|
||||
|
||||
3. ESP32 / прямой вызов:
|
||||
- валидный логин длиной `5+` регистрируется без временного кода;
|
||||
- логин короче `5` не регистрируется.
|
||||
|
||||
## Ожидаемый результат
|
||||
|
||||
- Основной UI удерживает обычных пользователей от коротких логинов без временного кода.
|
||||
- Свои пользователи могут временно регистрировать короткие логины через UI-код.
|
||||
- ESP32 продолжает работать без отдельной промо-логики.
|
||||
- On-chain логика остаётся простой и компактной.
|
||||
@@ -1,39 +0,0 @@
|
||||
# 4 тестовых SHiNE-сервера на одном VPS (`178.208.90.249`)
|
||||
|
||||
- статус: `pending`
|
||||
|
||||
## Кратко
|
||||
|
||||
Поднят отдельный тестовый стенд:
|
||||
- `t1.shineup.me`
|
||||
- `t2.shineup.me`
|
||||
- `t3.shineup.me`
|
||||
- `t4.shineup.me`
|
||||
|
||||
Каждый домен ведёт на свой SHiNE-инстанс под пользователем `player`, все инстансы работают через Solana `devnet`.
|
||||
|
||||
## Что проверять
|
||||
|
||||
- UI каждого домена открывается без ошибок:
|
||||
- `https://t1.shineup.me`
|
||||
- `https://t2.shineup.me`
|
||||
- `https://t3.shineup.me`
|
||||
- `https://t4.shineup.me`
|
||||
- регистрация/логин клиента может работать через каждый из этих серверов
|
||||
- WebSocket-подключение реально идёт на свой инстанс, а не в соседний
|
||||
- чтение PDA и server-ui формы по умолчанию используют `devnet`
|
||||
- межсерверный sync после ручных тестов действительно использует `access_servers/sync_servers`
|
||||
- не происходит путаницы данных между `t1/t2/t3/t4`
|
||||
|
||||
## Ожидаемый результат
|
||||
|
||||
- каждый домен работает независимо
|
||||
- у каждого инстанса своя БД и свои локальные данные
|
||||
- `Caddy` корректно проксирует `/ws` на `7101..7104`
|
||||
- серверы не падают после старта
|
||||
- если devnet RPC временно даёт `429`, последовательный рестарт по одному инстансу позволяет подтянуть `sync_servers`
|
||||
|
||||
## Примечание
|
||||
|
||||
Подробная схема размещения описана в:
|
||||
- [docs/deploy/test-server/178.208.90.249_quad_devnet.md](/home/ai/work/SHiNE/SHiNE-server-sha256/docs/deploy/test-server/178.208.90.249_quad_devnet.md)
|
||||
@@ -1,17 +0,0 @@
|
||||
# Итог звонка как DM от инициатора
|
||||
|
||||
- краткое описание фичи:
|
||||
Вместо локальных `call-tech` записей итог звонка теперь отправляется как обычное DM-сообщение только от стороны, которая инициировала звонок.
|
||||
|
||||
- что именно проверять:
|
||||
1. Успешный звонок: после завершения инициатор отправляет в чат DM вида `Звонок: 37с` или `Звонок: 2м 14с`.
|
||||
2. Неуспешный звонок без ответа: инициатор отправляет `Звонил, но недозвонился: нет ответа`.
|
||||
3. Неуспешный звонок, когда у адресата нет доставленных сессий: инициатор отправляет `Звонил, но недозвонился: абонент не в сети`.
|
||||
4. Неуспешный звонок при проблеме соединения: инициатор отправляет `Звонил, но недозвонился: не удалось установить соединение`.
|
||||
5. Старые локальные `call-tech` bubble про итог звонка больше не появляются ни у инициатора, ни у принимающей стороны.
|
||||
|
||||
- ожидаемый результат:
|
||||
Итог звонка виден обеим сторонам как обычное DM-сообщение от инициатора, а локальные служебные записи про итог звонка больше не используются.
|
||||
|
||||
- статус:
|
||||
pending
|
||||
@@ -1,23 +0,0 @@
|
||||
## Краткое описание
|
||||
|
||||
Сервер перестал валидировать внутреннюю crypto-структуру `body` у контентных DM `type=1/2`.
|
||||
UI теперь не отбрасывает такие сообщения: если сообщение не удалось расшифровать, вместо текста показывается заглушка `Неудалось расшифровать сообщение`.
|
||||
|
||||
## Что проверять
|
||||
|
||||
- Отправка и приём обычных DM между штатными клиентами продолжают работать как раньше.
|
||||
- Сообщение с незнакомым форматом `body` у `type=1/2` принимается сервером и доходит до клиента.
|
||||
- В UI такое сообщение отображается в чате одной из ожидаемых заглушек:
|
||||
- `Формат сообщения не поддерживается`
|
||||
- `Не удалось расшифровать сообщение`
|
||||
- `Сообщение повреждено`
|
||||
- После выхода из аккаунта и повторного входа backlog с такими сообщениями тоже отображается с той же заглушкой.
|
||||
- ACK доставки по сессии для такого сообщения не зацикливается и сообщение не приходит бесконечно повторно.
|
||||
|
||||
## Ожидаемый результат
|
||||
|
||||
Сервер выступает транспортом для opaque DM-body, а клиент при неудачной расшифровке показывает безопасный fallback вместо полного пропуска сообщения с различением основных причин.
|
||||
|
||||
## Статус
|
||||
|
||||
pending
|
||||
@@ -1,28 +0,0 @@
|
||||
## Краткое описание
|
||||
|
||||
В DM добавлен клиентский формат технических вставок в начале plaintext:
|
||||
|
||||
- `<SHiNE:reply;v=1;id=...>`
|
||||
- `<SHiNE:call;v=1;status=...;...>`
|
||||
|
||||
UI скрывает такие вставки из текста сообщения, а call-вставки отображает специальным человекочитаемым видом.
|
||||
Также добавлена защита от пользовательского текста, начинающегося с `<SHiNE:`, и исправлен безопасный рендер превью последнего сообщения в списке личных диалогов.
|
||||
|
||||
## Что проверять
|
||||
|
||||
- Если пользователь отправляет обычный текст, начинающийся с `<SHiNE:`, он уходит как `< SHiNE:` и отображается как обычный текст.
|
||||
- DM с `<SHiNE:call...>` показывается в чате как специальное call-сообщение, а не как сырой техтекст.
|
||||
- При исходящем звонке короче `5` секунд call-summary не отправляется вообще.
|
||||
- В списке личных сообщений превью такого сообщения показывает человекочитаемый итог звонка.
|
||||
- DM с `<SHiNE:reply...>Текст ответа` скрывает техблок и показывает только `Текст ответа`.
|
||||
- В меню любого DM первым пунктом есть `Ответить`, и отправка из этого режима реально добавляет `<SHiNE:reply...>` в начало plaintext.
|
||||
- Если reply-цель отсутствует, сообщение всё равно показывается как обычный текст ответа.
|
||||
- Текст вида `<script>alert(1)</script>` или похожие HTML-теги не исполняются ни в чате, ни в списке личных сообщений, ни в списке каналов.
|
||||
|
||||
## Ожидаемый результат
|
||||
|
||||
Технические SHiNE-вставки работают только как управляющие метаданные UI, а отображаемый пользователю текст и превью остаются безопасными и не рендерят HTML.
|
||||
|
||||
## Статус
|
||||
|
||||
pending
|
||||
@@ -1,30 +0,0 @@
|
||||
# Исправление завершения звонка и таймаутов ACK
|
||||
|
||||
## Краткое описание
|
||||
|
||||
Исправлена клиентская логика звонков:
|
||||
- входящий экран теперь должен закрываться сразу при `remote_hangup`;
|
||||
- после нажатия `Ответить` добавлен таймаут ожидания стадии `connecting`, чтобы окно не висело бесконечно;
|
||||
- исходящий таймаут ожидания ACK больше не обрывает звонок слишком рано, если invite уже был доставлен.
|
||||
- в локальный app log клиента добавлен точный timeline по этапам звонка: invite, выбор remoteSessionId, accept/offer/answer, ICE, смены `RTCPeerConnection` и финализация.
|
||||
- добавлена явная диагностика `SESSION_NOT_FOUND` для звонковых сигналов: отдельный timeline-этап в клиенте и отдельный серверный warn-лог.
|
||||
|
||||
## Что проверять
|
||||
|
||||
- Если исходящая сторона завершила звонок, входящее окно у второй стороны закрывается сразу.
|
||||
- Если принять входящий звонок, а соединение/offer не приходит, экран не висит бесконечно и сам завершается по таймауту.
|
||||
- Если invite был доставлен, исходящий звонок не падает через 10 секунд раньше времени только из-за медленного ACK.
|
||||
- В app log по звонку видна последовательность этапов с локальными `+N ms`, по которой можно понять, где именно образуется задержка или гонка.
|
||||
- Если сигнал звонка не дошёл до целевой сессии, это явно видно и в клиенте, и в серверном логе.
|
||||
|
||||
## Ожидаемый результат
|
||||
|
||||
- Нет бесконечно висящего окна `Соединяем…` на принимающей стороне.
|
||||
- В логах вместо преждевременного `no_ack_10s` для уже доставленного invite появляется более поздний таймаут.
|
||||
- При `remote_hangup` звонок визуально завершается сразу.
|
||||
- По каждому проблемному звонку есть локальный timeline и тот же краткий timeline попадает в `CallDeliveryReport`.
|
||||
- В серверных логах есть строка `CALL_SIGNAL_SESSION_NOT_FOUND ...` с `callId`, `targetSessionId` и количеством активных сессий адресата.
|
||||
|
||||
## Статус
|
||||
|
||||
`pending`
|
||||
@@ -1,16 +0,0 @@
|
||||
# Адаптация верхней панели экрана «Связи»
|
||||
|
||||
## Краткое описание
|
||||
- Экран графа связей больше не расширяется за границы контейнера. Верхняя панель ограничена границами экрана, чтобы кнопки возврата, поиска и справки не обрезались на узких устройствах.
|
||||
|
||||
## Что проверить
|
||||
- Открыть экран «Связи» на ширине около 320, 390 и 794 px.
|
||||
- Убедиться, что кнопки возврата, «Найти» и «?» полностью видны и нажимаются.
|
||||
- Убедиться, что фильтры и граф связей остаются доступными.
|
||||
|
||||
## Ожидаемый результат
|
||||
- Верхние действия не выходят за левую или правую границу приложения.
|
||||
- Заголовок при нехватке места сокращается, а не сдвигает кнопки за край.
|
||||
|
||||
## Статус
|
||||
- `pending` — локальная проверка на ширине 320 и 794 px пройдена; нужна ручная проверка после публикации на тестовом или production-стенде.
|
||||
@@ -1,16 +0,0 @@
|
||||
# Кнопка поиска каналов
|
||||
|
||||
## Краткое описание
|
||||
- Emoji-иконка поиска в верхней панели «Каналов» заменена на контурную кнопку-лупу в стиле интерфейса.
|
||||
|
||||
## Что проверить
|
||||
- Открыть список каналов.
|
||||
- Убедиться, что кнопка поиска видна рядом с кнопкой создания канала и имеет подсказку «Найти канал».
|
||||
- Нажать кнопку и убедиться, что открывается прежнее окно поиска каналов.
|
||||
|
||||
## Ожидаемый результат
|
||||
- Кнопка выглядит как часть общей тёмной панели и не использует emoji.
|
||||
- Поиск каналов работает без изменений.
|
||||
|
||||
## Статус
|
||||
- `pending` — локальная визуальная проверка и открытие окна поиска пройдены; нужна ручная проверка после публикации на тестовом или production-стенде.
|
||||
@@ -1,20 +0,0 @@
|
||||
# Локальный тестовый вход
|
||||
|
||||
## Краткое описание
|
||||
- На `localhost`, `127.0.0.1` и `::1` доступна кнопка «Локальный тестовый вход».
|
||||
- Она создаёт только локальный демо-сеанс `local-tester`; пароль, серверная сессия и production не используются.
|
||||
- Экран личных сообщений и список каналов открывают автономные локальные состояния без запроса к серверу.
|
||||
- Профиль заполняется демонстрационными данными, чтобы интерфейс можно было проверить без серверного пользователя.
|
||||
|
||||
## Что проверить
|
||||
- Открыть локальный UI и нажать «Локальный тестовый вход».
|
||||
- Проверить переход к списку сообщений и доступ к экранам профиля, каналов, связей и настроек.
|
||||
- Обновить страницу и убедиться, что локальный сеанс сохраняется.
|
||||
- Выйти из сеанса и убедиться, что снова открывается экран старта.
|
||||
|
||||
## Ожидаемый результат
|
||||
- Локальный режим даёт возможность изучить интерфейс без реальной авторизации.
|
||||
- На `shineup.me` и тестовых доменах кнопка отсутствует.
|
||||
|
||||
## Статус
|
||||
- `pending` — локальный вход, переход к профилю и демонстрационные каналы проверены; нужна ручная проверка выхода из сеанса после публикации на тестовом или production-стенде.
|
||||
@@ -1,23 +0,0 @@
|
||||
# Экран проверки public Solana RPC в UI
|
||||
|
||||
- статус: `pending`
|
||||
|
||||
## Кратко
|
||||
|
||||
Добавлен отдельный экран разработчика для проверки публичных mainnet Solana RPC прямо из браузера.
|
||||
Экран отправляет реальный JSON-RPC `getVersion` запрос к списку public endpoint-ов и показывает,
|
||||
какие ноды реально подходят для browser use.
|
||||
|
||||
## Что проверять
|
||||
|
||||
- в `Настройки разработчика` появилась кнопка `Solana: проверить public RPC`;
|
||||
- экран открывается без ошибок;
|
||||
- по каждой mainnet ноде показывается итоговый статус;
|
||||
- для доступных нод видно HTTP-статус, время ответа и версию `solana-core`;
|
||||
- длинные URL и ошибки не распирают экран по ширине на телефоне.
|
||||
|
||||
## Ожидаемый результат
|
||||
|
||||
- можно визуально увидеть, какие public Solana RPC доступны именно из браузера;
|
||||
- проверка работает без промежуточного сервера;
|
||||
- экран остаётся mobile-first и не требует горизонтального скролла.
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
## Кратко
|
||||
- Переделан финальный flow регистрации: сначала экран ожидания подтверждения Solana с прогрессом и повторными проверками, потом отдельный экран успешной регистрации с кнопкой входа в стандартный экран сохранения ключей.
|
||||
|
||||
## Что проверять
|
||||
- После отправки регистрации открывается экран ожидания с текстом про подтверждение Solana и кликабельным `Tx ID`.
|
||||
- Прогресс-бар сначала идёт быстрее, потом заметно замедляется.
|
||||
- Первая проверка регистрации начинается примерно через 4 секунды, далее повторяется раз в 2 секунды.
|
||||
- Пока подтверждения нет, снизу показываются понятные статусы ожидания.
|
||||
- После подтверждения открывается экран «Поздравляем с регистрацией» с одной кнопкой `Войти в аккаунт`.
|
||||
- Кнопка `Войти в аккаунт` открывает штатный экран сохранения ключей с тремя галочками.
|
||||
- Стрелка назад в левом верхнем углу на обоих экранах возвращает в главное меню.
|
||||
- После успешного сохранения ключей регистрационный черновик и адрес кошелька очищаются.
|
||||
|
||||
## Ожидаемый результат
|
||||
- Пользователь не видит преждевременное поздравление до подтверждения регистрации в Solana.
|
||||
- Финальный успех показывается только после появления подтверждения регистрации.
|
||||
- Вход после регистрации идёт через тот же стандартный сценарий сохранения ключей, что и в обычном login-flow.
|
||||
|
||||
## Статус
|
||||
- pending
|
||||
@@ -1,20 +0,0 @@
|
||||
# Недопроверенные фичи
|
||||
|
||||
Эта папка хранит список доработок, которые уже реализованы, но ещё не подтверждены ручной проверкой.
|
||||
|
||||
## Как использовать
|
||||
|
||||
1. При каждом коммите с новыми пользовательскими фичами (если нужна ручная проверка) добавить новый файл:
|
||||
- формат: `YYYY-MM-DD_HHMM_<short-feature-name>.md`
|
||||
- название `<short-feature-name>` и текст файла по возможности писать на русском языке
|
||||
2. В файле указать:
|
||||
- что сделано;
|
||||
- как проверять;
|
||||
- ожидаемый результат;
|
||||
- текущий статус (`pending` / `in_progress` / `done`).
|
||||
3. После подтверждения работоспособности — удалить файл фичи из этой папки.
|
||||
|
||||
## Важно
|
||||
|
||||
- `README.md` не удаляется.
|
||||
- Количество недопроверенных фич = число файлов `*.md` в этой папке, кроме `README.md`.
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
# Регистрация: FAQ и режим пароля из 12 слов
|
||||
|
||||
- краткое описание:
|
||||
- на экране регистрации добавлен блок частых вопросов с переходом на отдельный экран справки;
|
||||
- добавлен альтернативный режим ввода пароля через 12 полей-слов в кошелёчном формате, которые склеиваются в одну строку без изменения API;
|
||||
- такой же режим добавлен и на экран входа по логину и паролю.
|
||||
|
||||
- что проверять:
|
||||
- на стартовом экране открыть `Зарегистрироваться`;
|
||||
- убедиться, что внизу экрана есть кнопки FAQ;
|
||||
- открыть несколько вопросов и проверить возврат обратно на регистрацию;
|
||||
- включить галочку `Представить пароль в виде 12 слов`;
|
||||
- убедиться, что появляется сетка с нумерованными полями в 3 колонки;
|
||||
- ввести часть слов, перейти дальше и проверить, что шаг подтверждения и генерация ключей работают;
|
||||
- выключить галочку и проверить, что пароль остаётся собранным в одном поле;
|
||||
- открыть экран входа по паролю и повторить те же проверки для режима `12 слов`;
|
||||
- пройти регистрацию до шага оплаты без ошибок интерфейса.
|
||||
|
||||
- ожидаемый результат:
|
||||
- FAQ открывается отдельным экраном и содержит понятные ответы;
|
||||
- режим `12 слов` не ломает регистрацию и вход и даёт тот же поток, что и обычный пароль;
|
||||
- пароль не отправляется в новом формате, а продолжает использоваться как одна строка.
|
||||
|
||||
- статус:
|
||||
- pending
|
||||
@@ -1,25 +0,0 @@
|
||||
# Временная бесплатная загрузка аватара в Arweave
|
||||
|
||||
- краткое описание фичи:
|
||||
Добавлены два временных `Test...` API для бесплатной загрузки маленьких аватаров в Arweave через серверный кошелёк с лимитом `3` загрузки на пользователя. В UI мастера смены аватара добавлен пункт `Залить аватар бесплатно`.
|
||||
|
||||
- что именно проверять:
|
||||
1. Пользователь с активной сессией открывает редактирование профиля.
|
||||
2. По нажатию на аватар открывается мастер `Сменить аватар`.
|
||||
3. В мастере есть пункт `Залить аватар бесплатно`.
|
||||
4. До первой загрузки UI показывает остаток `3 из 3`.
|
||||
5. Маленький JPEG/PNG/WebP после уменьшения до файла <= `128 KB` успешно уходит через `TestUploadFreeAvatar`.
|
||||
6. После загрузки приходит `txId`, и аватар сохраняется в профиль как `avatar.ar`.
|
||||
7. Остаток уменьшается: `2`, `1`, `0`.
|
||||
8. На четвёртой попытке сервер отвечает понятной ошибкой про исчерпанный бесплатный лимит.
|
||||
9. Если итоговый уменьшенный файл всё ещё > `128 KB`, UI не отправляет его и показывает понятную ошибку.
|
||||
10. Если серверный Arweave JWK/path не настроен, UI получает понятную ошибку временной функции.
|
||||
|
||||
- ожидаемый результат:
|
||||
- первые 3 маленькие аватарки загружаются через серверный Arweave-кошелёк;
|
||||
- после каждой успешной загрузки `ava` в профиле указывает на новый `txId`;
|
||||
- после исчерпания лимита дальнейшая бесплатная загрузка блокируется без записи в профиль;
|
||||
- обычная загрузка через свой Arweave-кошелёк продолжает работать отдельно.
|
||||
|
||||
- статус:
|
||||
pending
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
# Общий список каналов без stories
|
||||
|
||||
- Краткое описание:
|
||||
вкладка `Каналы` переведена на единый список без разделения на "мои" и "подписки".
|
||||
Название канала в списке теперь показывается как `login_владельца/название_канала`.
|
||||
Служебный канал `stories` скрыт из списка каналов, поиска, подписки и связанных UI-сценариев.
|
||||
|
||||
- Что проверять:
|
||||
1. Открыть вкладку `Каналы`.
|
||||
2. Убедиться, что сразу показывается один общий список.
|
||||
3. Проверить, что свои и чужие каналы отображаются вместе.
|
||||
4. Проверить формат названий: `ownerLogin/channelName`.
|
||||
5. Открыть свой канал и убедиться, что внутри сохраняется UI владельца.
|
||||
6. Открыть чужой канал и убедиться, что внутри сохраняется UI подписчика.
|
||||
7. Проверить, что `stories` не отображается:
|
||||
- в общем списке;
|
||||
- в поиске каналов;
|
||||
- в подписке на канал;
|
||||
- в списках выбора канала для репоста.
|
||||
|
||||
- Ожидаемый результат:
|
||||
- вкладка `Каналы` больше не делится на два режима;
|
||||
- все видимые каналы идут единым списком;
|
||||
- `stories` нигде не виден и не предлагается пользователю;
|
||||
- переход в канал сохраняет корректный UI в зависимости от владельца.
|
||||
|
||||
- Статус:
|
||||
`pending`
|
||||
@@ -1,47 +0,0 @@
|
||||
# Crash-safe запись обычного `AddBlock` через `tmp_bch`
|
||||
|
||||
## Кратко
|
||||
|
||||
Обычный `AddBlock` переведён на схему:
|
||||
|
||||
1. сборка `<blockchainName>.tmp_bch`;
|
||||
2. запись sidecar `<blockchainName>.write_check` с `blockNumber` и `blockHash`;
|
||||
3. создание пустого marker `<blockchainName>.write_pending`;
|
||||
4. SQL-транзакция;
|
||||
5. атомарная подмена `tmp -> main`;
|
||||
6. удаление временных файлов.
|
||||
|
||||
## Что проверить
|
||||
|
||||
1. Обычный `AddBlock` на свежей цепочке.
|
||||
2. Падение до SQL-commit:
|
||||
- должны остаться только временные файлы;
|
||||
- на старте они должны быть удалены.
|
||||
3. Падение после SQL-commit, но до `atomicReplaceBlockchainFile(...)`:
|
||||
- на старте recovery должен довести swap до конца.
|
||||
4. Падение после `atomicReplaceBlockchainFile(...)`, но до удаления marker/sidecar:
|
||||
- на старте recovery должен просто подчистить хвост.
|
||||
5. Сценарий без marker:
|
||||
- `tmp_bch` / `write_check` считаются мусором и удаляются.
|
||||
|
||||
## Ожидаемый результат
|
||||
|
||||
- БД и файловая версия цепочки остаются согласованными.
|
||||
- Повторный старт сервера не ломает chain и не требует ручной правки файлов.
|
||||
- `BlockchainTmpRecoveryOnStartup` корректно обрабатывает и живые остатки, и мусор.
|
||||
|
||||
## Статус
|
||||
|
||||
`pending`
|
||||
|
||||
## Что уже сделано
|
||||
|
||||
- В коде есть `tmp_bch`, `write_check` и `write_pending`.
|
||||
- `BlockchainWriter` пишет обычный `AddBlock` через временные артефакты.
|
||||
- `BlockchainTmpRecoveryOnStartup` умеет добивать или чистить незавершённую запись.
|
||||
|
||||
## Что ещё перепроверить
|
||||
|
||||
- ручной crash-test на тестовом сервере;
|
||||
- совместимость с уже существующими `resync_pending` marker-файлами;
|
||||
- отсутствие ложных срабатываний на старых временных файлах.
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
# Проверка аварийных остановок на разных этапах
|
||||
|
||||
## Кратко
|
||||
|
||||
Нужно отдельно проверить, как сервер восстанавливается после внезапной остановки:
|
||||
|
||||
1. во время обычного `AddBlock` / `tmp_bch`-pipeline;
|
||||
2. во время `full resync` цепочки;
|
||||
3. во время startup recovery, если остановка произошла на предыдущем запуске;
|
||||
4. при обычном апгрейде сервиса без явного crash-сценария.
|
||||
|
||||
## Что проверять
|
||||
|
||||
1. Остановка сервиса до `commit` БД.
|
||||
2. Остановка сервиса после `commit`, но до замены `main.bch`.
|
||||
3. Остановка сервиса во время `BlockchainResyncCleanupDAO`.
|
||||
4. Остановка сервиса во время повторной загрузки цепочки по `GetBlockchainBlock`.
|
||||
5. Поведение при обычном `systemctl restart`, когда сервер сам должен добить recovery.
|
||||
|
||||
## Ожидаемый результат
|
||||
|
||||
- после старта сервер либо дочищает временные артефакты, либо завершает незаконченный `resync`;
|
||||
- не остаётся битых `.tmp_bch`, `.write_check`, `.write_pending`, `.resync_pending`;
|
||||
- БД и файлы цепочки остаются согласованными;
|
||||
- обычная работа сервера не стартует поверх незавершённого recovery.
|
||||
|
||||
## Статус
|
||||
|
||||
`pending`
|
||||
@@ -105,7 +105,7 @@ DAO в текущем виде не является отдельной Anchor-
|
||||
|
||||
## Правило разделения с основным сервером
|
||||
|
||||
Solana-модуль лежит в основном репозитории как отдельная папка `shine-solana/shine/`, но не подключается автоматически к сборке или деплою основного сервера SHiNE. Команды `deployServer` и `deployUI` не должны деплоить Anchor-программы. Solana build/deploy выполняется отдельно из папки `shine-solana/shine/` по локальным правилам модуля.
|
||||
Solana-модуль лежит в основном репозитории как отдельная папка `shine-solana/shine/`, но не подключается автоматически к сборке или деплою основного сервера SHiNE. Скрипты основного server/UI deploy из `deploy/scripts/` не должны деплоить Anchor-программы. Solana build/deploy выполняется отдельно из папки `shine-solana/shine/` по локальным правилам модуля.
|
||||
|
||||
## Движение денег
|
||||
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
# Деплой SHiNE (шаблон)
|
||||
|
||||
Этот раздел хранит актуальные инструкции по деплою.
|
||||
|
||||
## Базовый сервер
|
||||
|
||||
- SSH: `player@shineup.me`
|
||||
- Домен: `shineup.me`
|
||||
- Базовый путь: `/home/player`
|
||||
|
||||
Для всех рабочих инструкций и скриптов использовать доменное имя `shineup.me`, а не фиксированный IP:
|
||||
|
||||
- актуальный IP должен браться через DNS-резолв на момент подключения;
|
||||
- ручное дублирование IP в документации и deploy-скриптах не поддерживать.
|
||||
|
||||
## Контуры деплоя
|
||||
|
||||
- Production:
|
||||
- SSH: `player@shineup.me`
|
||||
- Домен: `shineup.me`
|
||||
- IP: `178.208.64.62`
|
||||
- Second production:
|
||||
- SSH: `player@193.8.215.70`
|
||||
- Домен: `server2.shineup.me`
|
||||
- IP: `193.8.215.70`
|
||||
## Локальные команды
|
||||
|
||||
- Default server deploy: `./gradlew deployServer` или `./gradlew deployServerTest2`
|
||||
- Default UI deploy: `./gradlew deployUI` или `./gradlew deployUITest2`
|
||||
- Production server deploy: `./gradlew deployServerProduction`
|
||||
- Production UI deploy: `./gradlew deployUIProduction`
|
||||
- Локальный запуск: `./gradlew startLocal`
|
||||
|
||||
## Отдельные тестовые VPS
|
||||
|
||||
- Отдельный стенд с 4 devnet-серверами на одном VPS описан в:
|
||||
- `docs/deploy/test-server/README.md`
|
||||
|
||||
## Политика подтверждений
|
||||
|
||||
- `shineup.me` и `server2.shineup.me` считать production-контурами.
|
||||
- Любые изменения на production-контурах, включая deploy сервера, deploy UI, конфиги, перезапуски и миграции, делать только после отдельного явного подтверждения пользователя.
|
||||
## Second production deploy (`server2.shineup.me`)
|
||||
|
||||
- Это второй production-сервер SHiNE.
|
||||
- Исторические задачи `deployServer`, `deployUI`, `deployServerTest2`, `deployUITest2` по-прежнему могут указывать сюда.
|
||||
- Серверный deploy не запускает JUnit/IT-тесты на удалённом сервере.
|
||||
- `deployServer` / `deployServerTest2` делают:
|
||||
- сборку fat-jar локально;
|
||||
- синхронизацию `data/` и `shine.sqlite` с production `shineup.me`;
|
||||
- перенос `application.properties` с production с поправкой `server.ui.indexPath` на `/home/player/SHiNE/shine-ui/index.html`;
|
||||
- установку `systemd` unit на `193.8.215.70`;
|
||||
- перезапуск `shine-server.service`;
|
||||
- установку/проверку Caddy для `server2.shineup.me`.
|
||||
- `deployUI` / `deployUITest2` публикуют UI в `/home/player/SHiNE/shine-ui` на `193.8.215.70`.
|
||||
- Важно: историческое имя `deployUITest2` вводит в заблуждение. По умолчанию эта задача деплоит на `server2.shineup.me`, а не на `t2.shineup.me`.
|
||||
|
||||
## UI-деплой и Caddy (обязательно)
|
||||
|
||||
- Целевая директория UI-деплоя: `/home/player/SHiNE/shine-ui`.
|
||||
- `Caddyfile` на сервере должен смотреть в ту же директорию через `root * /home/player/SHiNE/shine-ui`.
|
||||
- В `deploy_shine-PWA.sh` добавлена проверка: скрипт ищет блок `shineup.me { ... }` (или значение `EXPECTED_CADDY_SITE`) и проверяет `root` внутри этого блока.
|
||||
- Если `root` внутри целевого блока не совпадает, деплой прерывается с ошибкой.
|
||||
- Для ручного обхода проверки (только осознанно): `ALLOW_CADDY_MISMATCH=1 ./gradlew deployUI`.
|
||||
- При необходимости можно явно переопределить путь деплоя:
|
||||
- `REMOTE_UI_DIR=/нужный/путь ./gradlew deployUI`
|
||||
- `EXPECTED_CADDY_UI_ROOT=/нужный/путь ./gradlew deployUI`
|
||||
- `EXPECTED_CADDY_SITE=example.com ./gradlew deployUI`
|
||||
|
||||
## Временные тестовые сайты Solana tickets
|
||||
|
||||
- Для HTML UI программы `shine_payments` используется отдельный временный тестовый сайт.
|
||||
- Основной каталог публикации:
|
||||
- `/home/player/sites/test-solana-tickets.shineup.me`
|
||||
- Рабочие домены:
|
||||
- `https://test-solana-tickets.shineup.me`
|
||||
- `https://test-solana-tickets.shiningpeople.ru`
|
||||
- Назначение:
|
||||
- ручная проверка сценариев покупки билетов;
|
||||
- проверка DAO-инструментов и лимитов менеджеров;
|
||||
- проверка ручного добавления билетов и `step_payout`.
|
||||
- Эти сайты не считать основным UI SHiNE; это отдельная тестовая публикация под Solana-часть.
|
||||
|
||||
### Важно для локального UI (history-router / Ctrl+F5)
|
||||
|
||||
- Локальный UI **обязательно** поднимать только через `./gradlew startLocal`.
|
||||
- Эта задача запускает `scripts/local_spa_server.py`, который делает SPA fallback: любой неизвестный путь (`/m/...`, `/channel/...`) возвращает `index.html`.
|
||||
- Это обязательно для корректной работы `Ctrl+F5` на внутренних роутов без `404`.
|
||||
- Рабочий URL выводится задачей в консоль в формате: `http://localhost:<WEB_PORT>/?localWsPort=<WS_PORT>`.
|
||||
|
||||
## Обязательные правила
|
||||
|
||||
1. Перед серверным деплоем проверить локально.
|
||||
2. При нестандартном деплое (другой хост, другая структура, ручные шаги) обязательно уточнить у пользователя, нужно ли обновить этот шаблон.
|
||||
3. Если деплой-процесс изменился, этот файл и файлы в `servers/` обновлять в том же коммите.
|
||||
@@ -1,36 +0,0 @@
|
||||
# Локальный деплой SHiNE-agent-bot-coder (systemd, пользователь ai)
|
||||
|
||||
## Где находится сервис
|
||||
- Папка сервиса: `SHiNE-agent-bot-coder/`
|
||||
- Systemd unit: `SHiNE-agent-bot-coder/scripts/systemd/shine-agent-bot-coder.service`
|
||||
- Скрипт установки: `SHiNE-agent-bot-coder/scripts/systemd/install-local-systemd.sh`
|
||||
|
||||
## Предусловия
|
||||
1. Заполнен `.env` на основе `.env.example`.
|
||||
2. Доступен рабочий Codex CLI:
|
||||
- `/home/ai/.cache/JetBrains/IntelliJIdea2026.1/aia/codex/bin/codex-x86_64-unknown-linux-musl`
|
||||
3. На машине установлен `systemd --user`.
|
||||
|
||||
## Установка
|
||||
Из корня репозитория:
|
||||
|
||||
```bash
|
||||
bash SHiNE-agent-bot-coder/scripts/systemd/install-local-systemd.sh
|
||||
```
|
||||
|
||||
Скрипт:
|
||||
1. проверяет наличие `python3`;
|
||||
2. копирует unit в `~/.config/systemd/user/`;
|
||||
3. делает `systemctl --user daemon-reload`;
|
||||
4. включает автозапуск и стартует сервис.
|
||||
|
||||
## Проверка
|
||||
```bash
|
||||
systemctl --user status shine-agent-bot-coder --no-pager
|
||||
journalctl --user -u shine-agent-bot-coder -f
|
||||
```
|
||||
|
||||
## Перезапуск после изменений
|
||||
```bash
|
||||
systemctl --user restart shine-agent-bot-coder
|
||||
```
|
||||
@@ -1,43 +0,0 @@
|
||||
# Сервер `193.8.215.70` — второй production (`server2.shineup.me`)
|
||||
|
||||
- Пользователь: `player`
|
||||
- Домен: `server2.shineup.me`
|
||||
- Логин сервера: `server2shineupme`
|
||||
- Каталог SHiNE: `/home/player/SHiNE`
|
||||
- UI публикация для Caddy: `/home/player/SHiNE/shine-ui`
|
||||
- Сервер: `/home/player/SHiNE/shine-server/shine-server.jar`
|
||||
- Данные: `/home/player/SHiNE/shine-server/data/`
|
||||
- `shine.sqlite`
|
||||
- `*.bch`
|
||||
- Логи сервера: `/home/player/SHiNE/shine-server/logs/app.log`
|
||||
|
||||
## Сервисы
|
||||
|
||||
- `shine-server.service` (systemd)
|
||||
- `caddy.service` (systemd)
|
||||
|
||||
## Статус
|
||||
|
||||
- Это второй production-сервер SHiNE.
|
||||
- Исторические имена deploy-задач могут по-прежнему ссылаться на него как на `test2`.
|
||||
- В документации и в списке окружений считать его production-контуром.
|
||||
|
||||
## Caddy
|
||||
|
||||
- Конфиг: `/etc/caddy/Caddyfile`
|
||||
- Сайты:
|
||||
- `server2.shineup.me`
|
||||
- `agent.shiningpeople.ru`
|
||||
- Для `server2.shineup.me`:
|
||||
- `root * /home/player/SHiNE/shine-ui`
|
||||
- `try_files {path} /index.html`
|
||||
- `reverse_proxy /ws* -> 127.0.0.1:7070`
|
||||
|
||||
## Deploy
|
||||
|
||||
- Default server deploy:
|
||||
- `./gradlew deployServer`
|
||||
- `./gradlew deployServerTest2`
|
||||
- Default UI deploy:
|
||||
- `./gradlew deployUI`
|
||||
- `./gradlew deployUITest2`
|
||||
@@ -1,48 +0,0 @@
|
||||
# Сервер `shineup.me` — основной
|
||||
|
||||
- SSH: `player@shineup.me`
|
||||
- Определение IP: через DNS-резолв домена `shineup.me` на момент подключения
|
||||
- Текущий IP на момент последнего обновления документа: `178.208.64.62`
|
||||
- Пользователь: `player`
|
||||
- Базовый путь: `/home/player`
|
||||
- Каталог SHiNE: `/home/player/SHiNE`
|
||||
- UI публикация: `/home/player/SHiNE/shine-ui`
|
||||
- Сервер: `/home/player/SHiNE/shine-server/shine-server.jar`
|
||||
- Данные: `/home/player/SHiNE/shine-server/data/`
|
||||
- Логи сервера: `/home/player/SHiNE/shine-server/logs/app.log`
|
||||
|
||||
## Сервисы
|
||||
|
||||
- `shine-server.service` (systemd)
|
||||
- `caddy.service` (systemd)
|
||||
|
||||
## Caddy
|
||||
|
||||
- Активный конфиг (через systemd `ExecStart`): `/etc/caddy/Caddyfile`
|
||||
- Для UI:
|
||||
- `root * /home/player/SHiNE/shine-ui`
|
||||
- `try_files {path} /index.html` (SPA fallback)
|
||||
- no-cache заголовки
|
||||
- `reverse_proxy /ws* -> 127.0.0.1:7070`
|
||||
|
||||
## Дополнительно
|
||||
|
||||
- Для отдельной админки `shine_payments` используется каталог:
|
||||
- `/home/player/sites/test-solana-tickets.shineup.me`
|
||||
- Эта публикация используется как временный тестовый сайт для сценариев покупки билетов и выплат `shine_payments`.
|
||||
- Домены этой публикации:
|
||||
- `https://test-solana-tickets.shineup.me`
|
||||
- `https://test-solana-tickets.shiningpeople.ru`
|
||||
- Для всех deploy-скриптов и инструкций использовать именно `player@shineup.me`, без жёсткой фиксации IP.
|
||||
|
||||
## Правило изменений
|
||||
|
||||
- `shineup.me` — production.
|
||||
- Любые изменения на этом сервере делать только после отдельного явного подтверждения пользователя.
|
||||
|
||||
## Deploy
|
||||
|
||||
- Production deploy-задачи:
|
||||
- `./gradlew deployServerProduction`
|
||||
- `./gradlew deployUIProduction`
|
||||
- Default deploy-задачи `./gradlew deployServer` и `./gradlew deployUI` сюда больше не относятся.
|
||||
@@ -1,173 +0,0 @@
|
||||
# VPS `178.208.90.249` (`player`) — 4 тестовых SHiNE-сервера на devnet
|
||||
|
||||
## Назначение
|
||||
|
||||
Этот VPS используется как отдельный тестовый стенд для одновременного запуска 4 SHiNE-серверов:
|
||||
- `server_t1` → `https://t1.shineup.me`
|
||||
- `server_t2` → `https://t2.shineup.me`
|
||||
- `server_t3` → `https://t3.shineup.me`
|
||||
- `server_t4` → `https://t4.shineup.me`
|
||||
|
||||
Все 4 инстанса работают через Solana `devnet`.
|
||||
|
||||
## Каталоги
|
||||
|
||||
Структура в домашней папке пользователя `player`:
|
||||
- `/home/player/t1/server`
|
||||
- `/home/player/t1/UI`
|
||||
- `/home/player/t2/server`
|
||||
- `/home/player/t2/UI`
|
||||
- `/home/player/t3/server`
|
||||
- `/home/player/t3/UI`
|
||||
- `/home/player/t4/server`
|
||||
- `/home/player/t4/UI`
|
||||
|
||||
Дополнительно:
|
||||
- подробная памятка на самом сервере: `/home/player/Agents.md`
|
||||
|
||||
## Порты и systemd
|
||||
|
||||
Соответствие инстансов:
|
||||
- `t1` → localhost `7101` → `shine-t1.service`
|
||||
- `t2` → localhost `7102` → `shine-t2.service`
|
||||
- `t3` → localhost `7103` → `shine-t3.service`
|
||||
- `t4` → localhost `7104` → `shine-t4.service`
|
||||
|
||||
Каждый unit запускает один и тот же jar:
|
||||
- `/home/player/tX/server/shine-server.jar`
|
||||
|
||||
Рабочая директория каждого unit:
|
||||
- `/home/player/tX/server`
|
||||
|
||||
Это важно, потому что сервер читает внешний `application.properties` именно из текущей рабочей директории.
|
||||
|
||||
## Конфиги сервера
|
||||
|
||||
У каждого инстанса свой файл:
|
||||
- `/home/player/tX/server/application.properties`
|
||||
|
||||
Ключевые параметры в нём:
|
||||
- `server.port=710X`
|
||||
- `server.SHiNE.login=server_tX`
|
||||
- `db.path=data/shine.sqlite`
|
||||
- `solana.cluster=devnet`
|
||||
- `solana.rpcUrl=https://api.devnet.solana.com`
|
||||
- `server.ui.indexPath=/home/player/tX/UI/index.html`
|
||||
- `server.info.url=https://tX.shineup.me`
|
||||
- `server.info.origin=devnet`
|
||||
|
||||
Важно:
|
||||
- Program ID SHiNE одинаковые для mainnet и devnet.
|
||||
- Поэтому для перевода инстанса на devnet достаточно правильных `solana.cluster` и `solana.rpcUrl`.
|
||||
|
||||
## Конфиги UI
|
||||
|
||||
У каждого домена лежит отдельная копия `shine-UI`.
|
||||
|
||||
В каждой копии меняется `js/deploy-config.js`:
|
||||
- `defaultServerLogin=server_tX`
|
||||
- `defaultServerAddress=tX.shineup.me`
|
||||
- `defaultSolanaCluster=devnet`
|
||||
- `defaultSolanaEndpoint=https://api.devnet.solana.com`
|
||||
|
||||
За счёт этого:
|
||||
- UI по умолчанию открывает именно свой сервер
|
||||
- `server-ui` формы по умолчанию используют именно `devnet`
|
||||
|
||||
## Caddy
|
||||
|
||||
Конфиг:
|
||||
- `/etc/caddy/Caddyfile`
|
||||
|
||||
Логика по каждому сайту одинаковая:
|
||||
- статические файлы берутся из `/home/player/tX/UI`
|
||||
- путь `/ws` проксируется на `127.0.0.1:710X`
|
||||
|
||||
Права доступа:
|
||||
- каталог `/home/player` и `/home/player/tX` должен быть доступен на `+x` для чтения через Caddy
|
||||
- все каталоги и файлы в `/home/player/tX/UI` должны быть читаемы пользователем `caddy`
|
||||
|
||||
## Что уже проверено
|
||||
|
||||
После настройки было подтверждено:
|
||||
- `https://t1.shineup.me` отвечает `HTTP 200`
|
||||
- `https://t2.shineup.me` отвечает `HTTP 200`
|
||||
- `https://t3.shineup.me` отвечает `HTTP 200`
|
||||
- `https://t4.shineup.me` отвечает `HTTP 200`
|
||||
- `Caddy` успешно выпустил сертификаты Let's Encrypt на все 4 домена
|
||||
- все 4 процесса Java слушают свои порты `7101..7104`
|
||||
- в логах есть строка `WS сервер запущен на ws://localhost:710X/ws`
|
||||
|
||||
## Важный operational-нюанс
|
||||
|
||||
Официальный `https://api.devnet.solana.com` может отдавать `HTTP 429`, если несколько инстансов одновременно делают bootstrap PDA/sync-серверов на старте.
|
||||
|
||||
На практике это уже проявилось:
|
||||
- `t3` и `t4` подтянули `sync_servers` сразу
|
||||
- `t1` и `t2` на первом одновременном старте словили `429`
|
||||
- после последовательного рестарта `shine-t1` и `shine-t2` они тоже успешно сохранили `sync_servers`
|
||||
|
||||
Если после очередного деплоя какой-то инстанс не подтянул `sync_servers`, сначала делать не массовый рестарт, а по одному:
|
||||
|
||||
```bash
|
||||
sudo systemctl restart shine-t1
|
||||
sleep 8
|
||||
sudo systemctl restart shine-t2
|
||||
sleep 8
|
||||
sudo systemctl restart shine-t3
|
||||
sleep 8
|
||||
sudo systemctl restart shine-t4
|
||||
```
|
||||
|
||||
## Как обновлять сервер
|
||||
|
||||
1. Локально собрать jar:
|
||||
|
||||
```bash
|
||||
./gradlew shadowJar
|
||||
```
|
||||
|
||||
2. Залить `SHiNE-server/build/libs/shine-server.jar` в каждый нужный каталог:
|
||||
- `/home/player/t1/server/shine-server.jar`
|
||||
- `/home/player/t2/server/shine-server.jar`
|
||||
- `/home/player/t3/server/shine-server.jar`
|
||||
- `/home/player/t4/server/shine-server.jar`
|
||||
|
||||
3. Если менялся runtime-конфиг, обновить соответствующий `application.properties`.
|
||||
|
||||
4. Перезапускать сервисы лучше по одному, с паузой, чтобы снизить шанс `429` от devnet RPC.
|
||||
|
||||
## Как обновлять UI
|
||||
|
||||
1. Взять свежую локальную папку `shine-UI/`.
|
||||
2. Для каждой копии подставить свой `deploy-config.js`.
|
||||
3. Скопировать файлы в `/home/player/tX/UI/`.
|
||||
4. Проверить права чтения для Caddy.
|
||||
|
||||
## Полезные команды на VPS
|
||||
|
||||
Проверка сервисов:
|
||||
|
||||
```bash
|
||||
sudo systemctl --no-pager --full status caddy shine-t1 shine-t2 shine-t3 shine-t4
|
||||
```
|
||||
|
||||
Перезапуск одного инстанса:
|
||||
|
||||
```bash
|
||||
sudo systemctl restart shine-t1
|
||||
```
|
||||
|
||||
Логи одного инстанса:
|
||||
|
||||
```bash
|
||||
tail -n 200 /home/player/t1/server/logs/app.log
|
||||
sudo journalctl -u shine-t1 -n 200 --no-pager
|
||||
```
|
||||
|
||||
Проверка Caddy:
|
||||
|
||||
```bash
|
||||
sudo caddy validate --config /etc/caddy/Caddyfile
|
||||
curl -I https://t1.shineup.me
|
||||
```
|
||||
@@ -1,12 +0,0 @@
|
||||
# Тестовый VPS с 4 SHiNE-серверами
|
||||
|
||||
В этой папке описан отдельный тестовый VPS `178.208.90.249`, на котором подняты 4 независимых SHiNE-инстанса под доменами `t1.shineup.me` ... `t4.shineup.me`.
|
||||
|
||||
Текущая основная схема:
|
||||
- пользователь на VPS: `player`
|
||||
- все 4 инстанса работают через `devnet`
|
||||
- каждый инстанс имеет свой каталог `server`, свой каталог `UI`, свой `systemd` unit и свой localhost-порт
|
||||
- внешний HTTPS и маршрутизацию `/ws` обслуживает один общий `Caddy`
|
||||
|
||||
Детальное описание:
|
||||
- [178.208.90.249_quad_devnet.md](/home/ai/work/SHiNE/SHiNE-server-sha256/docs/deploy/test-server/178.208.90.249_quad_devnet.md)
|
||||
@@ -1,75 +0,0 @@
|
||||
# Установка TURN сервера (coturn)
|
||||
|
||||
## 1. Что нужно
|
||||
- Сервер с публичным IP (в примере: `37.214.58.208`).
|
||||
- Доступ `root` по SSH.
|
||||
- Открытые порты в firewall:
|
||||
- `3478/tcp`
|
||||
- `3478/udp`
|
||||
- диапазон relay-портов, например `49160-49200/udp`
|
||||
|
||||
## 2. Быстрая установка (рекомендуется)
|
||||
В проекте уже есть готовый скрипт:
|
||||
|
||||
```bash
|
||||
sudo bash scripts/setup_turn_coturn.sh \
|
||||
--secret "CHANGE_ME_LONG_RANDOM_SECRET" \
|
||||
--realm "shineup.me"
|
||||
```
|
||||
|
||||
Что делает скрипт:
|
||||
- ставит `coturn`;
|
||||
- включает режим `use-auth-secret` (временные логин/пароль);
|
||||
- пишет `/etc/turnserver.conf`;
|
||||
- включает и перезапускает сервис `coturn`.
|
||||
|
||||
## 3. Проверка
|
||||
Проверить статус:
|
||||
|
||||
```bash
|
||||
sudo systemctl status coturn --no-pager
|
||||
```
|
||||
|
||||
Проверить, что порт слушается:
|
||||
|
||||
```bash
|
||||
sudo ss -lntup | grep 3478
|
||||
```
|
||||
|
||||
## 4. Ручная установка (если без скрипта)
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y coturn
|
||||
```
|
||||
|
||||
Пример `/etc/turnserver.conf`:
|
||||
|
||||
```conf
|
||||
listening-port=3478
|
||||
fingerprint
|
||||
lt-cred-mech
|
||||
use-auth-secret
|
||||
static-auth-secret=CHANGE_ME_LONG_RANDOM_SECRET
|
||||
realm=shineup.me
|
||||
external-ip=37.214.58.208
|
||||
listening-ip=0.0.0.0
|
||||
relay-ip=37.214.58.208
|
||||
min-port=49160
|
||||
max-port=49200
|
||||
no-cli
|
||||
simple-log
|
||||
```
|
||||
|
||||
В `/etc/default/coturn`:
|
||||
|
||||
```conf
|
||||
TURNSERVER_ENABLED=1
|
||||
```
|
||||
|
||||
Запуск:
|
||||
|
||||
```bash
|
||||
sudo systemctl enable coturn
|
||||
sudo systemctl restart coturn
|
||||
```
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
# Подключение TURN к SHiNE-серверу
|
||||
|
||||
Начиная с текущей версии, клиент звонков запрашивает ICE-конфиг у backend через WS-операцию `GetCallIceConfig` и использует её для `RTCPeerConnection`.
|
||||
|
||||
## 1. Настройки backend
|
||||
Файл: `src/main/resources/application.properties`
|
||||
|
||||
Ключи:
|
||||
|
||||
```properties
|
||||
call.ice.stun.urls=stun:stun.l.google.com:19302
|
||||
call.ice.turn.urls=turn:37.214.58.208:3478?transport=udp,turn:37.214.58.208:3478?transport=tcp
|
||||
call.ice.turn.ttlSec=600
|
||||
call.ice.turn.userPrefix=shine
|
||||
call.ice.turn.sharedSecret=CHANGE_ME_LONG_RANDOM_SECRET
|
||||
|
||||
# fallback (если не используете shared-secret)
|
||||
call.ice.turn.username=
|
||||
call.ice.turn.password=
|
||||
```
|
||||
|
||||
## 2. Рекомендуемый режим (временные credentials)
|
||||
- На coturn и на SHiNE-сервере должен быть **одинаковый** secret:
|
||||
- coturn: `static-auth-secret=...`
|
||||
- SHiNE: `call.ice.turn.sharedSecret=...`
|
||||
- Тогда SHiNE выдаёт короткоживущие `turnUsername/turnPassword` (TTL).
|
||||
|
||||
## 3. Fallback режим (статический логин/пароль)
|
||||
Если временные credentials не используются:
|
||||
|
||||
```properties
|
||||
call.ice.turn.sharedSecret=
|
||||
call.ice.turn.username=turn_user
|
||||
call.ice.turn.password=turn_password
|
||||
```
|
||||
|
||||
## 4. Деплой после изменения
|
||||
```bash
|
||||
./gradlew deployServerNoCleanNoTests
|
||||
./gradlew deployWEB
|
||||
```
|
||||
|
||||
## 5. Проверка
|
||||
1. Авторизоваться двумя клиентами.
|
||||
2. Запустить звонок.
|
||||
3. Проверить, что звонок устанавливается даже в сети, где прямой P2P затруднён.
|
||||
4. Если TURN недоступен, клиент автоматически откатится к STUN-конфигу по умолчанию.
|
||||
|
||||
Reference in New Issue
Block a user