docs: refactor docs structure
This commit is contained in:
+1
-1
@@ -16,7 +16,7 @@ frontend/node_modules/
|
|||||||
docs-site/node_modules/
|
docs-site/node_modules/
|
||||||
docs-site/.astro/
|
docs-site/.astro/
|
||||||
docs-site/dist/
|
docs-site/dist/
|
||||||
docs-site/src/content/docs/reference/
|
docs-site/src/content/docs/
|
||||||
deploy/compose/docker-compose-dev.yml
|
deploy/compose/docker-compose-dev.yml
|
||||||
data/*
|
data/*
|
||||||
!data/tariffs.example.json
|
!data/tariffs.example.json
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ node_modules/
|
|||||||
# Documentation site build artifacts
|
# Documentation site build artifacts
|
||||||
docs-site/.astro/
|
docs-site/.astro/
|
||||||
docs-site/dist/
|
docs-site/dist/
|
||||||
docs-site/src/content/docs/reference/
|
docs-site/src/content/docs/
|
||||||
|
|
||||||
# WebApp build artifacts (regenerated by `npm run build:webapp` / Docker build)
|
# WebApp build artifacts (regenerated by `npm run build:webapp` / Docker build)
|
||||||
bot/app/web/templates/subscription_webapp.css
|
bot/app/web/templates/subscription_webapp.css
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Remnawave Minishop - Telegram-бот и Web App (Mini App) для продажи и управления подписками панели [Remnawave](https://docs.rw/). Бот обрабатывает регистрацию, оплату, продление, пробный период, промокоды, рефералов и поддержку в чате. Web App показывает ссылку подключения, срок действия, трафик, оплату, устройства и вход по Telegram Mini Apps `initData`, Telegram OAuth / OpenID Connect и одноразовому email-коду.
|
Remnawave Minishop - Telegram-бот и Web App (Mini App) для продажи и управления подписками панели [Remnawave](https://docs.rw/). Бот обрабатывает регистрацию, оплату, продление, пробный период, промокоды, рефералов и поддержку в чате. Web App показывает ссылку подключения, срок действия, трафик, оплату, устройства и вход по Telegram Mini Apps `initData`, Telegram OAuth / OpenID Connect и одноразовому email-коду.
|
||||||
|
|
||||||
Проект является переработанным форком [kavore/remnawave-tg-shop](https://github.com/kavore/remnawave-tg-shop). Для переноса данных из прежнего стека используйте [инструкцию по миграции](docs/migration-to-minishop.md).
|
Проект является переработанным форком [kavore/remnawave-tg-shop](https://github.com/kavore/remnawave-tg-shop). Для переноса данных из прежнего стека и других ботов используйте [раздел миграций](docs/migrations/index.md).
|
||||||
|
|
||||||
## Возможности
|
## Возможности
|
||||||
|
|
||||||
@@ -32,15 +32,18 @@ Remnawave Minishop - Telegram-бот и Web App (Mini App) для продажи
|
|||||||
|
|
||||||
## Документация
|
## Документация
|
||||||
|
|
||||||
|
- [Входная страница документации](docs/index.md) - маршрут по установке, настройке, платежам, админке и диагностике.
|
||||||
|
- [Deploy examples](docs/deploy-examples/index.md) - готовые варианты запуска: Caddy, Nginx, Pangolin/Newt и no-proxy.
|
||||||
- [Настройка окружения](docs/configuration.md) - bootstrap `.env` и рекомендуемая настройка через Web App админку.
|
- [Настройка окружения](docs/configuration.md) - bootstrap `.env` и рекомендуемая настройка через Web App админку.
|
||||||
- [Переменные `.env`](docs/env-vars.md) - полный справочник всех env-ключей по разделам.
|
- [Переменные `.env`](docs/configuration/env-vars.md) - полный справочник всех env-ключей по разделам.
|
||||||
- [Тарифы](docs/tariffs.md) - каталог тарифов, period- и traffic-модели, обычные и premium-докупки, premium-сквады, смена тарифа, HWID-лимиты и обработка трафика.
|
- [Тарифы](docs/features/tariffs.md) - каталог тарифов, period- и traffic-модели, обычные и premium-докупки, premium-сквады, смена тарифа, HWID-лимиты и обработка трафика.
|
||||||
- [Админ-панель](docs/admin.md) - права доступа, настройки, редактор тарифов, premium-сквады и сохранение JSON-каталога.
|
- [Админ-панель](docs/features/admin-panel.md) - права доступа, настройки, редактор тарифов, premium-сквады и сохранение JSON-каталога.
|
||||||
- [Web App / Mini App](docs/webapp.md) - отдельный порт, домен, Telegram OAuth, email-вход, инструкции установки и реферальные ссылки.
|
- [Web App / Mini App](docs/features/web-app.md) - отдельный порт, домен, Telegram OAuth, email-вход, инструкции установки и реферальные ссылки.
|
||||||
- [Поддержка](docs/support.md) - тикеты в Mini App, входящий список админки, уведомления, лимиты и внешняя ссылка поддержки.
|
- [Поддержка](docs/features/support.md) - тикеты в Mini App, входящий список админки, уведомления, лимиты и внешняя ссылка поддержки.
|
||||||
- [Темы Web App](docs/webapp-themes.md) - кастомные темы, настройка внешнего вида, логотипы, CSS/ассеты и пайплайн создания новой темы.
|
- [Темы Web App](docs/features/webapp-themes.md) - кастомные темы, настройка внешнего вида, логотипы, CSS/ассеты и пайплайн создания новой темы.
|
||||||
- [Развертывание](docs/deployment.md) - Docker Compose, reverse proxy, Nginx, Caddy, вебхуки, запуск из образа и обновление версии (`IMAGE_TAG`).
|
- [Развертывание](docs/deployment.md) - Docker Compose, reverse proxy, Nginx, Caddy, вебхуки, запуск из образа и обновление версии (`IMAGE_TAG`).
|
||||||
- [Миграция с remnawave-tg-shop](docs/migration-to-minishop.md) - перенос данных из прежнего стека.
|
- [Миграции](docs/migrations/index.md) - готовые сценарии переноса с других ботов; сейчас описан `remnawave-tg-shop`.
|
||||||
|
- [Миграция с remnawave-tg-shop](docs/migrations/remnawave-tg-shop.md) - готовый сценарий для legacy-стека.
|
||||||
|
|
||||||
## Совместимость
|
## Совместимость
|
||||||
|
|
||||||
@@ -88,9 +91,9 @@ docker compose logs -f backend worker frontend
|
|||||||
- `PANEL_API_URL`, `PANEL_API_KEY`, `PANEL_WEBHOOK_SECRET` - доступ к Remnawave;
|
- `PANEL_API_URL`, `PANEL_API_KEY`, `PANEL_WEBHOOK_SECRET` - доступ к Remnawave;
|
||||||
- остальные настройки удобнее задать в Web App админке.
|
- остальные настройки удобнее задать в Web App админке.
|
||||||
|
|
||||||
После первого входа в админку настройте тарифы, платежные провайдеры, внешний вид, поддержку, уведомления и инструкции подключения через UI. Инструкции установки включены по умолчанию, читают Subscription Page config из Remnawave Panel и при проблемах с конфигом откатываются к обычной ссылке подключения. Полный справочник env-переменных: [docs/env-vars.md](docs/env-vars.md).
|
После первого входа в админку настройте тарифы, платежные провайдеры, внешний вид, поддержку, уведомления и инструкции подключения через UI. Инструкции установки включены по умолчанию, читают Subscription Page config из Remnawave Panel и при проблемах с конфигом откатываются к обычной ссылке подключения. Полный справочник env-переменных: [docs/configuration/env-vars.md](docs/configuration/env-vars.md).
|
||||||
|
|
||||||
Для каталога тарифов используется `TARIFFS_CONFIG_PATH` со значением по умолчанию `data/tariffs.json`. Пример формата лежит в [data/tariffs.example.json](data/tariffs.example.json), подробности - в [docs/tariffs.md](docs/tariffs.md).
|
Для каталога тарифов используется `TARIFFS_CONFIG_PATH` со значением по умолчанию `data/tariffs.json`. Пример формата лежит в [data/tariffs.example.json](data/tariffs.example.json), подробности - в [docs/features/tariffs.md](docs/features/tariffs.md).
|
||||||
|
|
||||||
Если в Docker Compose включаете bind mount `./data:/app/data`, заранее создайте каталог и отдайте его пользователю контейнера. Это нужно для сохранения `data/tariffs.json`, каталога тем `data/themes`, кеша логотипа Web App и animated emoji:
|
Если в Docker Compose включаете bind mount `./data:/app/data`, заранее создайте каталог и отдайте его пользователю контейнера. Это нужно для сохранения `data/tariffs.json`, каталога тем `data/themes`, кеша логотипа Web App и animated emoji:
|
||||||
|
|
||||||
@@ -120,7 +123,7 @@ docker compose up -d
|
|||||||
IMAGE_TAG=3.1.0 docker compose up -d
|
IMAGE_TAG=3.1.0 docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
Для production-запуска удобнее брать готовые папки из [`deploy/examples`](deploy/examples): там отдельно собраны варианты для Caddy, Nginx, Newt/Pangolin и прямой публикации портов без reverse proxy. В каждой папке рядом лежат `docker-compose.yml`, `.env.example`, README и нужный proxy-конфиг.
|
Для production-запуска удобнее брать готовые папки из [`deploy/examples`](deploy/examples), а читать каноничные инструкции в [docs/deploy-examples/index.md](docs/deploy-examples/index.md): там отдельно описаны варианты для Caddy, Nginx, Newt/Pangolin и прямой публикации портов без reverse proxy. В папках рядом с compose лежат только конфиги и короткие ссылки на документацию.
|
||||||
|
|
||||||
GHCR image names for releases:
|
GHCR image names for releases:
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,12 @@
|
|||||||
# Готовые варианты запуска
|
# Deploy examples
|
||||||
|
|
||||||
В этой папке лежат самодостаточные compose-примеры. Каждый вариант запускается из своей директории обычной командой:
|
Каноничная документация по вариантам запуска живет в [docs/deploy-examples/index.md](../../docs/deploy-examples/index.md).
|
||||||
|
|
||||||
```bash
|
Эта папка хранит только рабочие compose-примеры и конфиги. Подробное описание не дублируется здесь, чтобы сайт документации и навигация из README использовали один источник.
|
||||||
cp .env.example .env
|
|
||||||
nano .env
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
После старта полезно проверить:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose ps
|
|
||||||
docker compose logs -f backend worker frontend
|
|
||||||
```
|
|
||||||
|
|
||||||
## Какой вариант выбрать
|
|
||||||
|
|
||||||
| Папка | Когда использовать | Что править |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| [`caddy`](caddy) | Нужен самый простой публичный HTTPS с автоматическими сертификатами Let's Encrypt. | `.env`; при нестандартной схеме можно поправить `Caddyfile`. |
|
|
||||||
| [`nginx`](nginx) | Уже используете Nginx и готовы положить TLS-сертификаты рядом с примером. | `.env`, `nginx.conf.template`, файлы в `ssl/`. |
|
|
||||||
| [`newt`](newt) | Публикуете сервисы через Pangolin/Newt без входящих портов на сервере приложения. | `.env` и ресурсы в панели Pangolin. |
|
|
||||||
| [`no-proxy`](no-proxy) | Нужно напрямую открыть порты backend/frontend или проверить стек без reverse proxy. | `.env`. |
|
|
||||||
|
|
||||||
Для всех вариантов нужны два публичных URL:
|
|
||||||
|
|
||||||
- webhook/backend URL для Telegram, платежных систем и Remnawave webhooks;
|
|
||||||
- Mini App/frontend URL для Telegram Mini App и Web App.
|
|
||||||
|
|
||||||
Обычно это два домена, например `webhooks.example.com` и `app.example.com`.
|
|
||||||
|
|
||||||
|
| Папка | Документация |
|
||||||
|
| --- | --- |
|
||||||
|
| `caddy` | [Caddy](../../docs/deploy-examples/caddy.md) |
|
||||||
|
| `nginx` | [Nginx](../../docs/deploy-examples/nginx.md) |
|
||||||
|
| `newt` | [Pangolin / Newt](../../docs/deploy-examples/newt.md) |
|
||||||
|
| `no-proxy` | [No proxy](../../docs/deploy-examples/no-proxy.md) |
|
||||||
|
|||||||
@@ -1,31 +1,5 @@
|
|||||||
# Запуск с Caddy
|
# Caddy
|
||||||
|
|
||||||
Caddy сам выпускает и продлевает HTTPS-сертификаты. На сервере должны быть открыты входящие `80/tcp` и `443/tcp`, а DNS-записи `WEBHOOK_HOST` и `MINIAPP_HOST` должны смотреть на этот сервер.
|
Каноничная инструкция: [docs/deploy-examples/caddy.md](../../../docs/deploy-examples/caddy.md).
|
||||||
|
|
||||||
```bash
|
|
||||||
cp .env.example .env
|
|
||||||
nano .env
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
Минимально поменяйте в `.env`:
|
|
||||||
|
|
||||||
- `WEBHOOK_HOST` и `MINIAPP_HOST`;
|
|
||||||
- `BOT_TOKEN`, `ADMIN_IDS`;
|
|
||||||
- `POSTGRES_PASSWORD`;
|
|
||||||
- `WEBAPP_SESSION_SECRET`, `WEBHOOK_SECRET_TOKEN`;
|
|
||||||
- `PANEL_API_URL`, `PANEL_API_KEY`, `PANEL_WEBHOOK_SECRET`.
|
|
||||||
|
|
||||||
`Caddyfile` лежит рядом и использует домены из `.env`. Если нужна нестандартная логика Caddy, правьте его и перезапускайте:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose up -d --force-recreate caddy
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверка:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose ps
|
|
||||||
docker compose logs -f caddy backend worker frontend
|
|
||||||
```
|
|
||||||
|
|
||||||
|
Файлы этого примера остаются рядом: `docker-compose.yml`, `.env.example` и `Caddyfile`.
|
||||||
|
|||||||
@@ -1,33 +1,5 @@
|
|||||||
# Запуск через Newt / Pangolin
|
# Pangolin / Newt
|
||||||
|
|
||||||
Этот вариант не открывает входящие порты на сервере приложения. Newt подключается к Pangolin, а публичные домены настраиваются ресурсами в панели Pangolin.
|
Каноничная инструкция: [docs/deploy-examples/newt.md](../../../docs/deploy-examples/newt.md).
|
||||||
|
|
||||||
```bash
|
Файлы этого примера остаются рядом: `docker-compose.yml` и `.env.example`.
|
||||||
cp .env.example .env
|
|
||||||
nano .env
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
В `.env` заполните:
|
|
||||||
|
|
||||||
- `WEBHOOK_HOST` и `MINIAPP_HOST` - публичные домены ресурсов в Pangolin;
|
|
||||||
- `PANGOLIN_ENDPOINT`, `NEWT_ID`, `NEWT_SECRET` - значения из настроек site/client в Pangolin;
|
|
||||||
- обычные переменные приложения: `BOT_TOKEN`, `ADMIN_IDS`, `POSTGRES_PASSWORD`, секреты и доступ к Remnawave.
|
|
||||||
|
|
||||||
Официальная инструкция Pangolin по установке Newt site: <https://docs.pangolin.net/manage/sites/install-site>.
|
|
||||||
|
|
||||||
В Pangolin создайте два HTTP-ресурса для этого Newt site:
|
|
||||||
|
|
||||||
| Публичный домен | Upstream |
|
|
||||||
| --- | --- |
|
|
||||||
| `https://webhooks.example.com` | `http://backend:8080` |
|
|
||||||
| `https://app.example.com` | `http://frontend:80` |
|
|
||||||
|
|
||||||
Домены в Pangolin должны совпадать с `WEBHOOK_HOST` и `MINIAPP_HOST`.
|
|
||||||
|
|
||||||
Проверка:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose ps
|
|
||||||
docker compose logs -f newt backend worker frontend
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -1,42 +1,5 @@
|
|||||||
# Запуск с Nginx
|
# Nginx
|
||||||
|
|
||||||
Этот пример поднимает Nginx в той же Docker-сети, что и приложение:
|
Каноничная инструкция: [docs/deploy-examples/nginx.md](../../../docs/deploy-examples/nginx.md).
|
||||||
|
|
||||||
- `WEBHOOK_HOST` проксируется в `backend:8080`;
|
|
||||||
- `MINIAPP_HOST` проксируется в `frontend:80`;
|
|
||||||
- `frontend` сам проксирует внутренние `/api`, `/auth` и ассеты тем в `backend:8081`.
|
|
||||||
|
|
||||||
## Подготовка
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cp .env.example .env
|
|
||||||
nano .env
|
|
||||||
```
|
|
||||||
|
|
||||||
Положите TLS-сертификаты в `ssl/`:
|
|
||||||
|
|
||||||
```text
|
|
||||||
ssl/
|
|
||||||
webhooks.example.com/
|
|
||||||
fullchain.pem
|
|
||||||
privkey.pem
|
|
||||||
app.example.com/
|
|
||||||
fullchain.pem
|
|
||||||
privkey.pem
|
|
||||||
```
|
|
||||||
|
|
||||||
Имена папок должны совпадать с `WEBHOOK_HOST` и `MINIAPP_HOST` в `.env`.
|
|
||||||
|
|
||||||
## Запуск
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose up -d
|
|
||||||
docker compose logs -f nginx backend worker frontend
|
|
||||||
```
|
|
||||||
|
|
||||||
Если нужно поменять заголовки, лимиты или TLS-настройки, правьте `nginx.conf.template` рядом с compose и перезапускайте Nginx:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose up -d --force-recreate nginx
|
|
||||||
```
|
|
||||||
|
|
||||||
|
Файлы этого примера остаются рядом: `docker-compose.yml`, `.env.example`, `nginx.conf.template` и папка `ssl/` для сертификатов.
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# TLS-сертификаты для Nginx
|
# TLS certificates
|
||||||
|
|
||||||
Положите сюда сертификаты для доменов из `.env`.
|
Каноничная инструкция по Nginx: [docs/deploy-examples/nginx.md](../../../../docs/deploy-examples/nginx.md).
|
||||||
|
|
||||||
Пример структуры:
|
Кладите сертификаты в подпапки, совпадающие с `WEBHOOK_HOST` и `MINIAPP_HOST`:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
ssl/
|
ssl/
|
||||||
@@ -13,6 +13,3 @@ ssl/
|
|||||||
fullchain.pem
|
fullchain.pem
|
||||||
privkey.pem
|
privkey.pem
|
||||||
```
|
```
|
||||||
|
|
||||||
Если используете wildcard-сертификат, можно положить одинаковые `fullchain.pem` и `privkey.pem` в обе папки.
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,5 @@
|
|||||||
# Запуск без reverse proxy
|
# No proxy
|
||||||
|
|
||||||
Этот вариант напрямую публикует два HTTP-порта:
|
Каноничная инструкция: [docs/deploy-examples/no-proxy.md](../../../docs/deploy-examples/no-proxy.md).
|
||||||
|
|
||||||
- backend/webhooks: `WEB_SERVER_BIND`, по умолчанию `0.0.0.0:8080`;
|
|
||||||
- frontend/Mini App: `FRONTEND_BIND`, по умолчанию `0.0.0.0:8082`.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cp .env.example .env
|
|
||||||
nano .env
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
Важно: контейнеры приложения сами не выпускают TLS-сертификаты. Для реального Telegram webhook и Mini App публичные URL должны быть HTTPS. Используйте этот вариант для локальной проверки, внутренней сети или когда HTTPS уже завершается внешней платформой и дальше трафик приходит на эти порты.
|
|
||||||
|
|
||||||
Проверка локально:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl http://127.0.0.1:8080/healthz
|
|
||||||
curl http://127.0.0.1:8082/health
|
|
||||||
docker compose logs -f backend worker frontend
|
|
||||||
```
|
|
||||||
|
|
||||||
|
Файлы этого примера остаются рядом: `docker-compose.yml` и `.env.example`.
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
# Cloudflare Pages deploy
|
|
||||||
|
|
||||||
This docs site is built with Astro Starlight and publishes to:
|
|
||||||
|
|
||||||
```text
|
|
||||||
https://minishop.minidoc.cc
|
|
||||||
```
|
|
||||||
|
|
||||||
## Cloudflare Pages settings
|
|
||||||
|
|
||||||
Create a Pages project connected to the GitLab repository and use:
|
|
||||||
|
|
||||||
| Setting | Value |
|
|
||||||
| --- | --- |
|
|
||||||
| Production branch | `main` |
|
|
||||||
| Framework preset | `Astro` |
|
|
||||||
| Root directory | `docs-site` |
|
|
||||||
| Build command | `npm ci && npm run build` |
|
|
||||||
| Build output directory | `dist` |
|
|
||||||
| Node version | `22` |
|
|
||||||
|
|
||||||
The build script runs `scripts/sync-docs.mjs` before Astro builds the site. Keep editing the canonical Markdown files in the repository-level `docs/` directory.
|
|
||||||
|
|
||||||
## Custom domain
|
|
||||||
|
|
||||||
After the first successful Pages deploy:
|
|
||||||
|
|
||||||
1. Open the Pages project in Cloudflare.
|
|
||||||
2. Go to **Custom domains**.
|
|
||||||
3. Add `minishop.minidoc.cc`.
|
|
||||||
4. If `minidoc.cc` is already on Cloudflare DNS, accept the suggested DNS record and wait for TLS activation.
|
|
||||||
|
|
||||||
## Optional API automation
|
|
||||||
|
|
||||||
Do not use a root token for automation. Create a scoped Cloudflare API token and expose it locally as an environment variable only for the setup command.
|
|
||||||
|
|
||||||
Minimum useful permissions:
|
|
||||||
|
|
||||||
| Scope | Permission |
|
|
||||||
| --- | --- |
|
|
||||||
| Account | Cloudflare Pages: Edit |
|
|
||||||
| Zone: `minidoc.cc` | Zone: Read |
|
|
||||||
| Zone: `minidoc.cc` | DNS: Edit |
|
|
||||||
|
|
||||||
Cloudflare's GitLab integration still requires the Cloudflare GitLab app/OAuth connection to be authorized for the repository. If that is not connected yet, complete the GitLab connection in the Cloudflare dashboard first, or use a direct-upload Pages workflow instead of Git-connected deployments.
|
|
||||||
+78
-22
@@ -6,23 +6,20 @@ export default defineConfig({
|
|||||||
site: 'https://minishop.minidoc.cc',
|
site: 'https://minishop.minidoc.cc',
|
||||||
integrations: [
|
integrations: [
|
||||||
starlight({
|
starlight({
|
||||||
title: 'Remnawave Minishop',
|
title: 'minishop',
|
||||||
|
favicon: '/favicon.png',
|
||||||
description:
|
description:
|
||||||
'Документация по настройке, развертыванию и эксплуатации Remnawave Minishop.',
|
'Документация по настройке, развертыванию и эксплуатации Remnawave Minishop.',
|
||||||
plugins: [
|
plugins: [
|
||||||
starlightThemeNova({
|
starlightThemeNova({
|
||||||
nav: [
|
nav: [
|
||||||
{ label: 'Запуск', href: '/reference/deployment/' },
|
{ label: 'Главная', href: '/' },
|
||||||
{ label: 'Настройка', href: '/reference/configuration/' },
|
{ label: 'Установка', href: '/getting-started/setup/' },
|
||||||
|
{ label: 'Платежи', href: '/features/payments/' },
|
||||||
{ label: 'GitLab', href: 'https://gitlab.com/3252a8/remnawave-minshop' },
|
{ label: 'GitLab', href: 'https://gitlab.com/3252a8/remnawave-minshop' },
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
favicon: '/favicon.svg',
|
|
||||||
logo: {
|
|
||||||
src: './src/assets/logo.svg',
|
|
||||||
alt: 'Remnawave Minishop',
|
|
||||||
},
|
|
||||||
customCss: ['./src/styles/custom.css'],
|
customCss: ['./src/styles/custom.css'],
|
||||||
lastUpdated: false,
|
lastUpdated: false,
|
||||||
locales: {
|
locales: {
|
||||||
@@ -32,11 +29,19 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
head: [
|
head: [
|
||||||
|
{
|
||||||
|
tag: 'link',
|
||||||
|
attrs: {
|
||||||
|
rel: 'icon',
|
||||||
|
href: '/favicon.webp',
|
||||||
|
type: 'image/webp',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
tag: 'meta',
|
tag: 'meta',
|
||||||
attrs: {
|
attrs: {
|
||||||
name: 'theme-color',
|
name: 'theme-color',
|
||||||
content: '#0f766e',
|
content: '#00fe7a',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -49,32 +54,83 @@ export default defineConfig({
|
|||||||
],
|
],
|
||||||
sidebar: [
|
sidebar: [
|
||||||
{
|
{
|
||||||
label: 'Обзор',
|
label: 'Начало',
|
||||||
link: '/',
|
items: [
|
||||||
|
{ label: 'Главная', link: '/' },
|
||||||
|
{ label: 'Обзор', slug: 'getting-started/overview' },
|
||||||
|
{ label: 'Установка', slug: 'getting-started/setup' },
|
||||||
|
{ label: 'Deploy examples', slug: 'deploy-examples' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Запуск',
|
label: 'Варианты деплоя',
|
||||||
items: [
|
items: [
|
||||||
|
{ label: 'Caddy', slug: 'deploy-examples/caddy' },
|
||||||
|
{ label: 'Nginx', slug: 'deploy-examples/nginx' },
|
||||||
|
{ label: 'Pangolin / Newt', slug: 'deploy-examples/newt' },
|
||||||
|
{ label: 'Без reverse proxy', slug: 'deploy-examples/no-proxy' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Конфигурация',
|
||||||
|
items: [
|
||||||
|
{ label: 'Переменные', slug: 'configuration/env-vars' },
|
||||||
{ label: 'Настройка окружения', slug: 'reference/configuration' },
|
{ label: 'Настройка окружения', slug: 'reference/configuration' },
|
||||||
{ label: 'Переменные .env', slug: 'reference/env-vars' },
|
{ label: 'Безопасность', slug: 'configuration/security' },
|
||||||
{ label: 'Развертывание', slug: 'reference/deployment' },
|
|
||||||
{ label: 'Миграция', slug: 'reference/migration-to-minishop' },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Web App',
|
label: 'Возможности',
|
||||||
items: [
|
items: [
|
||||||
{ label: 'Mini App', slug: 'reference/webapp' },
|
{ label: 'Основные', slug: 'features/core' },
|
||||||
{ label: 'Темы и внешний вид', slug: 'reference/webapp-themes' },
|
{ label: 'Платежи', slug: 'features/payments' },
|
||||||
{ label: 'Админ-панель', slug: 'reference/admin' },
|
{ label: 'Подписки', slug: 'features/subscriptions' },
|
||||||
{ label: 'Поддержка', slug: 'reference/support' },
|
{ label: 'Тарифы', slug: 'features/tariffs' },
|
||||||
|
{ label: 'Mini App', slug: 'features/web-app' },
|
||||||
|
{ label: 'Темы Web App', slug: 'features/webapp-themes' },
|
||||||
|
{ label: 'Админ-панель', slug: 'features/admin-panel' },
|
||||||
|
{ label: 'Поддержка', slug: 'features/support' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Продукт',
|
label: 'Платежные системы',
|
||||||
|
items: [
|
||||||
|
{ label: 'YooKassa', slug: 'payments/yookassa' },
|
||||||
|
{ label: 'FreeKassa', slug: 'payments/freekassa' },
|
||||||
|
{ label: 'Platega', slug: 'payments/platega' },
|
||||||
|
{ label: 'SeverPay', slug: 'payments/severpay' },
|
||||||
|
{ label: 'Wata', slug: 'payments/wata' },
|
||||||
|
{ label: 'CryptoPay', slug: 'payments/cryptopay' },
|
||||||
|
{ label: 'Heleket', slug: 'payments/heleket' },
|
||||||
|
{ label: 'Telegram Stars', slug: 'payments/telegram-stars' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Администрирование',
|
||||||
|
items: [
|
||||||
|
{ label: 'Пользователи', slug: 'administration/users' },
|
||||||
|
{ label: 'Обслуживание', slug: 'administration/maintenance' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Миграции',
|
||||||
|
items: [
|
||||||
|
{ label: 'Обзор миграций', slug: 'migrations' },
|
||||||
|
{ label: 'remnawave-tg-shop', slug: 'migrations/remnawave-tg-shop' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Устранение неполадок',
|
||||||
|
items: [
|
||||||
|
{ label: 'Проблемы', slug: 'troubleshooting/issues' },
|
||||||
|
{ label: 'Логи', slug: 'troubleshooting/logs' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Справочник',
|
||||||
items: [
|
items: [
|
||||||
{ label: 'Тарифы', slug: 'reference/tariffs' },
|
|
||||||
{ label: 'Архитектура', slug: 'reference/architecture' },
|
{ label: 'Архитектура', slug: 'reference/architecture' },
|
||||||
|
{ label: 'Развертывание', slug: 'reference/deployment' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
@@ -1,5 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96">
|
|
||||||
<rect width="96" height="96" rx="22" fill="#0f172a"/>
|
|
||||||
<path d="M19 59c11 0 14-20 28-20 11 0 14 11 24 11 4 0 7-1 10-3v13c-3 2-7 3-11 3-13 0-16-11-25-11-10 0-14 20-26 20V59Z" fill="#2dd4bf"/>
|
|
||||||
<path d="M18 39c12 0 15-18 29-18 10 0 13 9 23 9 4 0 8-1 11-4v13c-3 2-7 3-12 3-13 0-16-9-24-9-10 0-14 18-27 18V39Z" fill="#f59e0b"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 396 B |
Binary file not shown.
|
After Width: | Height: | Size: 7.3 KiB |
+138
-31
@@ -5,19 +5,44 @@ import { fileURLToPath } from 'node:url';
|
|||||||
const siteRoot = path.resolve(fileURLToPath(new URL('..', import.meta.url)));
|
const siteRoot = path.resolve(fileURLToPath(new URL('..', import.meta.url)));
|
||||||
const repoRoot = path.resolve(siteRoot, '..');
|
const repoRoot = path.resolve(siteRoot, '..');
|
||||||
const sourceDir = path.join(repoRoot, 'docs');
|
const sourceDir = path.join(repoRoot, 'docs');
|
||||||
const outputDir = path.join(siteRoot, 'src', 'content', 'docs', 'reference');
|
const outputDir = path.join(siteRoot, 'src', 'content', 'docs');
|
||||||
|
|
||||||
const descriptions = {
|
const descriptions = {
|
||||||
'admin.md': 'Возможности админ-панели, управление пользователями, настройками, тарифами и поддержкой.',
|
'index.md': 'Документация по запуску, настройке и сопровождению Telegram Mini App для Remnawave.',
|
||||||
|
'getting-started/overview.md': 'Что входит в Remnawave Minishop и как связаны бот, Mini App, backend, worker и Remnawave Panel.',
|
||||||
|
'getting-started/setup.md': 'Минимальный путь запуска Remnawave Minishop через Docker Compose.',
|
||||||
|
'configuration/security.md': 'Секреты, публичные URL, доступ администраторов и базовые меры защиты Minishop.',
|
||||||
|
'configuration/env-vars.md': 'Полный справочник переменных окружения Remnawave Minishop.',
|
||||||
|
'features/core.md': 'Пользовательские и админские сценарии Remnawave Minishop.',
|
||||||
|
'features/payments.md': 'Платежные провайдеры, кнопки оплаты и webhook-обработка.',
|
||||||
|
'features/subscriptions.md': 'Period- и traffic-тарифы, premium-сквады, HWID-устройства и жизненный цикл подписки.',
|
||||||
|
'features/tariffs.md': 'Каталог тарифов, period/traffic-модели, premium-сквады и HWID-устройства.',
|
||||||
|
'features/web-app.md': 'Telegram Mini App, авторизация, публичные инструкции и проксирование.',
|
||||||
|
'features/webapp-themes.md': 'Кастомные темы, CSS-токены, ассеты и пайплайн создания темы.',
|
||||||
|
'features/admin-panel.md': 'Возможности админ-панели, управление пользователями, настройками, тарифами и поддержкой.',
|
||||||
|
'features/support.md': 'Пользовательские тикеты, админский inbox, уведомления и лимиты поддержки.',
|
||||||
|
'deploy-examples/index.md': 'Как выбрать готовый deploy example для production или проверки.',
|
||||||
|
'deploy-examples/caddy.md': 'Запуск Remnawave Minishop с Caddy и автоматическим HTTPS.',
|
||||||
|
'deploy-examples/nginx.md': 'Запуск Remnawave Minishop с Nginx и внешними TLS-сертификатами.',
|
||||||
|
'deploy-examples/newt.md': 'Запуск через Pangolin/Newt без входящих портов на сервере приложения.',
|
||||||
|
'deploy-examples/no-proxy.md': 'Прямой запуск backend и frontend портов без reverse proxy.',
|
||||||
|
'migrations/index.md': 'Готовые сценарии миграции в Remnawave Minishop с других ботов.',
|
||||||
|
'migrations/remnawave-tg-shop.md': 'Перенос данных со старого remnawave-tg-shop на split-архитектуру Minishop.',
|
||||||
|
'payments/yookassa.md': 'Быстрый вход в настройку YooKassa для Remnawave Minishop.',
|
||||||
|
'payments/freekassa.md': 'Быстрый вход в настройку FreeKassa для Remnawave Minishop.',
|
||||||
|
'payments/platega.md': 'Настройка Platega, отдельных СБП/карта и crypto-кнопок.',
|
||||||
|
'payments/severpay.md': 'Настройка SeverPay, MID, token, return URL и срока жизни ссылки.',
|
||||||
|
'payments/wata.md': 'Настройка Wata, API token, TTL ссылки, подписи webhook и trusted IP.',
|
||||||
|
'payments/cryptopay.md': 'Настройка CryptoPay, токена, сети, currency type и asset.',
|
||||||
|
'payments/heleket.md': 'Настройка Heleket, merchant ID, payment API key, invoice currency и webhook-проверок.',
|
||||||
|
'payments/telegram-stars.md': 'Оплата подписок и докупок через Telegram Stars.',
|
||||||
|
'administration/users.md': 'Где управлять пользователями, подписками, блокировками и поддержкой.',
|
||||||
|
'administration/maintenance.md': 'Обновления, миграции, резервные копии и проверки production-стека.',
|
||||||
|
'troubleshooting/issues.md': 'Короткие чеклисты для частых проблем запуска, вебхуков, Mini App и платежей.',
|
||||||
|
'troubleshooting/logs.md': 'Какие логи смотреть при диагностике backend, worker, frontend, миграций и вебхуков.',
|
||||||
'architecture.md': 'Краткая архитектура backend, frontend, worker и инфраструктурных сервисов.',
|
'architecture.md': 'Краткая архитектура backend, frontend, worker и инфраструктурных сервисов.',
|
||||||
'configuration.md': 'Минимальный .env, bootstrap-секреты и настройка через Web App админку.',
|
'configuration.md': 'Минимальный .env, bootstrap-секреты и настройка через Web App админку.',
|
||||||
'deployment.md': 'Docker Compose, reverse proxy, TLS, образы, обновления и резервные копии.',
|
'deployment.md': 'Docker Compose, reverse proxy, TLS, образы, обновления и резервные копии.',
|
||||||
'env-vars.md': 'Полный справочник переменных окружения Remnawave Minishop.',
|
|
||||||
'migration-to-minishop.md': 'Перенос данных со старого remnawave-tg-shop на split-архитектуру Minishop.',
|
|
||||||
'support.md': 'Пользовательские тикеты, админский inbox, уведомления и лимиты поддержки.',
|
|
||||||
'tariffs.md': 'Каталог тарифов, period/traffic-модели, premium-сквады и HWID-устройства.',
|
|
||||||
'webapp.md': 'Telegram Mini App, авторизация, публичные инструкции и проксирование.',
|
|
||||||
'webapp-themes.md': 'Кастомные темы, CSS-токены, ассеты и пайплайн создания темы.',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const imageExtensions = new Set(['.avif', '.gif', '.jpeg', '.jpg', '.png', '.svg', '.webp']);
|
const imageExtensions = new Set(['.avif', '.gif', '.jpeg', '.jpg', '.png', '.svg', '.webp']);
|
||||||
@@ -26,23 +51,45 @@ function yamlString(value) {
|
|||||||
return JSON.stringify(value);
|
return JSON.stringify(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function slugFor(fileName) {
|
function toPosix(relativePath) {
|
||||||
return fileName.replace(/\.md$/i, '');
|
return relativePath.split(path.sep).join('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractTitle(fileName, content) {
|
function outputRelativePath(sourceRelativePath) {
|
||||||
|
if (sourceRelativePath === 'index.md') {
|
||||||
|
return 'index.md';
|
||||||
|
}
|
||||||
|
if (!sourceRelativePath.includes('/')) {
|
||||||
|
return `reference/${sourceRelativePath}`;
|
||||||
|
}
|
||||||
|
return sourceRelativePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pagePathForSource(sourceRelativePath, hash = '') {
|
||||||
|
const output = outputRelativePath(sourceRelativePath).replace(/\.md$/i, '');
|
||||||
|
const route = output === 'index' ? '/' : `/${output.replace(/\/index$/u, '')}/`;
|
||||||
|
return `${route}${hash}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function titleForRelativePath(relativePath) {
|
||||||
|
const baseName = path.posix.basename(relativePath, '.md');
|
||||||
|
return baseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractTitle(relativePath, content) {
|
||||||
const match = content.match(/^#\s+(.+?)\s*$/m);
|
const match = content.match(/^#\s+(.+?)\s*$/m);
|
||||||
return match?.[1] ?? slugFor(fileName);
|
return match?.[1] ?? titleForRelativePath(relativePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
function stripFirstHeading(content) {
|
function stripFirstHeading(content) {
|
||||||
return content.replace(/^#\s+.+?\s*\r?\n+/, '');
|
return content.replace(/^#\s+.+?\s*\r?\n+/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
function rewriteMarkdownLinks(markdown) {
|
function rewriteMarkdownLinks(markdown, sourceRelativePath) {
|
||||||
|
const sourceDirectory = path.posix.dirname(sourceRelativePath);
|
||||||
return markdown.replace(/\]\((?!https?:\/\/|mailto:|tel:|\/|#)([^)\s]+\.md)(#[^)]+)?\)/g, (match, target, hash = '') => {
|
return markdown.replace(/\]\((?!https?:\/\/|mailto:|tel:|\/|#)([^)\s]+\.md)(#[^)]+)?\)/g, (match, target, hash = '') => {
|
||||||
const slug = slugFor(path.posix.basename(target));
|
const resolvedTarget = path.posix.normalize(path.posix.join(sourceDirectory, target));
|
||||||
return `](/reference/${slug}/${hash})`;
|
return `](${pagePathForSource(resolvedTarget, hash)})`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,45 +99,105 @@ function normalizeCodeFences(markdown) {
|
|||||||
.replace(/^```caddyfile\s*$/gim, '```txt');
|
.replace(/^```caddyfile\s*$/gim, '```txt');
|
||||||
}
|
}
|
||||||
|
|
||||||
function frontmatter({ title, description, fileName }) {
|
function extraFrontmatter(sourceRelativePath) {
|
||||||
const editUrl = `https://gitlab.com/3252a8/remnawave-minshop/-/edit/main/docs/${encodeURIComponent(fileName)}`;
|
if (sourceRelativePath !== 'index.md') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'template: splash',
|
||||||
|
'hero:',
|
||||||
|
' tagline: "Telegram-бот и Mini App для продажи подписок Remnawave: платежи, тарифы, админка, поддержка и инструкции подключения."',
|
||||||
|
' image:',
|
||||||
|
' html: \'<img class="minishop-hero-screenshot" src="/remnawave-minishop.webp" alt="Интерфейс Remnawave Minishop" width="1920" height="1080" loading="eager" decoding="async" />\'',
|
||||||
|
' actions:',
|
||||||
|
' - text: "Быстрый старт"',
|
||||||
|
' link: /getting-started/setup/',
|
||||||
|
' icon: right-arrow',
|
||||||
|
' - text: "Deploy examples"',
|
||||||
|
' link: /deploy-examples/',
|
||||||
|
' icon: setting',
|
||||||
|
' variant: minimal',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function frontmatter({ title, description, sourceRelativePath }) {
|
||||||
|
const editPath = sourceRelativePath
|
||||||
|
.split('/')
|
||||||
|
.map((segment) => encodeURIComponent(segment))
|
||||||
|
.join('/');
|
||||||
|
const editUrl = `https://gitlab.com/3252a8/remnawave-minshop/-/edit/main/docs/${editPath}`;
|
||||||
return [
|
return [
|
||||||
'---',
|
'---',
|
||||||
`title: ${yamlString(title)}`,
|
`title: ${yamlString(title)}`,
|
||||||
`description: ${yamlString(description)}`,
|
`description: ${yamlString(description)}`,
|
||||||
`editUrl: ${yamlString(editUrl)}`,
|
`editUrl: ${yamlString(editUrl)}`,
|
||||||
|
...extraFrontmatter(sourceRelativePath),
|
||||||
'---',
|
'---',
|
||||||
'',
|
'',
|
||||||
].join('\n');
|
].join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function syncMarkdown(entries) {
|
async function walk(directory) {
|
||||||
for (const entry of entries.filter((item) => item.name.endsWith('.md'))) {
|
const entries = await readdir(directory, { withFileTypes: true });
|
||||||
const sourcePath = path.join(sourceDir, entry.name);
|
const files = [];
|
||||||
|
for (const entry of entries) {
|
||||||
|
const absolutePath = path.join(directory, entry.name);
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
files.push(...(await walk(absolutePath)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (entry.isFile()) {
|
||||||
|
files.push(absolutePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function syncMarkdown(files) {
|
||||||
|
for (const sourcePath of files.filter((file) => file.endsWith('.md'))) {
|
||||||
|
const sourceRelativePath = toPosix(path.relative(sourceDir, sourcePath));
|
||||||
|
const outputRelative = outputRelativePath(sourceRelativePath);
|
||||||
|
const outputPath = path.join(outputDir, ...outputRelative.split('/'));
|
||||||
const content = await readFile(sourcePath, 'utf8');
|
const content = await readFile(sourcePath, 'utf8');
|
||||||
const title = extractTitle(entry.name, content);
|
const title = extractTitle(sourceRelativePath, content);
|
||||||
const body = normalizeCodeFences(rewriteMarkdownLinks(stripFirstHeading(content).trimStart()));
|
const body = normalizeCodeFences(
|
||||||
|
rewriteMarkdownLinks(stripFirstHeading(content).trimStart(), sourceRelativePath),
|
||||||
|
);
|
||||||
const output = frontmatter({
|
const output = frontmatter({
|
||||||
title,
|
title,
|
||||||
description: descriptions[entry.name] ?? title,
|
description: descriptions[sourceRelativePath] ?? title,
|
||||||
fileName: entry.name,
|
sourceRelativePath,
|
||||||
});
|
});
|
||||||
|
|
||||||
await writeFile(path.join(outputDir, entry.name), `${output}${body}\n`, 'utf8');
|
await mkdir(path.dirname(outputPath), { recursive: true });
|
||||||
|
await writeFile(outputPath, `${output}${body}\n`, 'utf8');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function syncImages(entries) {
|
async function syncAssets(files) {
|
||||||
for (const entry of entries.filter((item) => imageExtensions.has(path.extname(item.name).toLowerCase()))) {
|
for (const sourcePath of files.filter((file) => imageExtensions.has(path.extname(file).toLowerCase()))) {
|
||||||
await copyFile(path.join(sourceDir, entry.name), path.join(outputDir, entry.name));
|
const sourceRelativePath = toPosix(path.relative(sourceDir, sourcePath));
|
||||||
|
const outputRelative = !sourceRelativePath.includes('/')
|
||||||
|
? sourceRelativePath
|
||||||
|
: sourceRelativePath;
|
||||||
|
const outputPath = path.join(outputDir, ...outputRelative.split('/'));
|
||||||
|
await mkdir(path.dirname(outputPath), { recursive: true });
|
||||||
|
await copyFile(sourcePath, outputPath);
|
||||||
|
|
||||||
|
if (!sourceRelativePath.includes('/')) {
|
||||||
|
const referenceOutputPath = path.join(outputDir, 'reference', sourceRelativePath);
|
||||||
|
await mkdir(path.dirname(referenceOutputPath), { recursive: true });
|
||||||
|
await copyFile(sourcePath, referenceOutputPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await rm(outputDir, { recursive: true, force: true });
|
await rm(outputDir, { recursive: true, force: true });
|
||||||
await mkdir(outputDir, { recursive: true });
|
await mkdir(outputDir, { recursive: true });
|
||||||
|
|
||||||
const entries = await readdir(sourceDir, { withFileTypes: true });
|
const files = await walk(sourceDir);
|
||||||
await syncMarkdown(entries);
|
await syncMarkdown(files);
|
||||||
await syncImages(entries);
|
await syncAssets(files);
|
||||||
|
|
||||||
console.log(`Synced documentation from ${path.relative(repoRoot, sourceDir)} to ${path.relative(repoRoot, outputDir)}`);
|
console.log(`Synced documentation from ${path.relative(repoRoot, sourceDir)} to ${path.relative(repoRoot, outputDir)}`);
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96" role="img" aria-labelledby="title desc">
|
|
||||||
<title id="title">Remnawave Minishop</title>
|
|
||||||
<desc id="desc">Abstract layered wave mark.</desc>
|
|
||||||
<rect width="96" height="96" rx="22" fill="#0f172a"/>
|
|
||||||
<path d="M19 59c11 0 14-20 28-20 11 0 14 11 24 11 4 0 7-1 10-3v13c-3 2-7 3-11 3-13 0-16-11-25-11-10 0-14 20-26 20V59Z" fill="#2dd4bf"/>
|
|
||||||
<path d="M18 39c12 0 15-18 29-18 10 0 13 9 23 9 4 0 8-1 11-4v13c-3 2-7 3-12 3-13 0-16-9-24-9-10 0-14 18-27 18V39Z" fill="#f59e0b"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 536 B |
@@ -1,32 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Remnawave Minishop"
|
|
||||||
description: "Документация по запуску, настройке и сопровождению Telegram Mini App для Remnawave."
|
|
||||||
template: splash
|
|
||||||
hero:
|
|
||||||
tagline: "Telegram-бот и Mini App для продажи подписок Remnawave: платежи, тарифы, админка, поддержка и инструкции подключения."
|
|
||||||
image:
|
|
||||||
alt: Интерфейс Remnawave Minishop
|
|
||||||
html: '<img src="/remnawave-minishop.webp" alt="Интерфейс Remnawave Minishop" width="900" height="520" loading="eager" decoding="async" />'
|
|
||||||
actions:
|
|
||||||
- text: Быстрый старт
|
|
||||||
link: /reference/deployment/
|
|
||||||
icon: right-arrow
|
|
||||||
- text: Настройка
|
|
||||||
link: /reference/configuration/
|
|
||||||
icon: setting
|
|
||||||
variant: minimal
|
|
||||||
---
|
|
||||||
|
|
||||||
## Основные разделы
|
|
||||||
|
|
||||||
- **Запуск и окружение** - минимальный `.env`, Docker Compose, reverse proxy, обновления и резервные копии.
|
|
||||||
- **Web App / Mini App** - Telegram-авторизация, email-вход, инструкции установки и публичные ссылки.
|
|
||||||
- **Админка и тарифы** - управление пользователями, платежами, темами, каталогом тарифов и premium-сквадами.
|
|
||||||
- **Миграция** - перенос со старого `remnawave-tg-shop` на текущую split-архитектуру.
|
|
||||||
|
|
||||||
## Быстрые ссылки
|
|
||||||
|
|
||||||
- [Развертывание](/reference/deployment/)
|
|
||||||
- [Переменные окружения](/reference/env-vars/)
|
|
||||||
- [Тарифы](/reference/tariffs/)
|
|
||||||
- [Темы Web App](/reference/webapp-themes/)
|
|
||||||
@@ -1,25 +1,73 @@
|
|||||||
@layer starlight, nova, minishop;
|
@layer starlight, nova, minishop;
|
||||||
|
|
||||||
@layer minishop {
|
@layer minishop {
|
||||||
.site-title {
|
.site-title,
|
||||||
|
.site-title span {
|
||||||
|
color: #00fe7a;
|
||||||
font-weight: 760;
|
font-weight: 760;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.site-title:hover,
|
||||||
|
.site-title:hover span {
|
||||||
|
color: #00fe7a;
|
||||||
|
}
|
||||||
|
|
||||||
.hero {
|
.hero {
|
||||||
gap: clamp(2rem, 6vw, 5rem);
|
gap: clamp(2rem, 6vw, 5rem);
|
||||||
padding-block: clamp(3.5rem, 10vw, 6.5rem);
|
padding-block: clamp(3.5rem, 10vw, 6.5rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hero > .hero-html:has(.minishop-hero-screenshot) {
|
||||||
|
width: min(96vw, 72rem);
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
.hero img {
|
.hero img {
|
||||||
border: 1px solid var(--sl-color-gray-5);
|
border: 1px solid var(--sl-color-gray-5);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
box-shadow: 0 24px 70px rgb(15 23 42 / 18%);
|
box-shadow: 0 24px 70px rgb(15 23 42 / 18%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.minishop-hero-screenshot {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
max-width: none;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
:root[data-theme='dark'] .hero img {
|
:root[data-theme='dark'] .hero img {
|
||||||
box-shadow: 0 24px 70px rgb(0 0 0 / 36%);
|
box-shadow: 0 24px 70px rgb(0 0 0 / 36%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 50rem) {
|
||||||
|
.hero:has(.minishop-hero-screenshot) {
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
gap: clamp(2rem, 4vw, 4rem);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero > .hero-html:has(.minishop-hero-screenshot) {
|
||||||
|
order: 2;
|
||||||
|
width: min(100%, 90rem);
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero:has(.minishop-hero-screenshot) .stack {
|
||||||
|
align-items: center;
|
||||||
|
max-width: 64rem;
|
||||||
|
margin-inline: auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero:has(.minishop-hero-screenshot) .copy {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero:has(.minishop-hero-screenshot) .actions {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.sl-markdown-content :is(h2, h3) {
|
.sl-markdown-content :is(h2, h3) {
|
||||||
letter-spacing: 0;
|
letter-spacing: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Обслуживание
|
||||||
|
|
||||||
|
Плановое обслуживание обычно сводится к обновлению образов, проверке миграций, логов и резервных копий PostgreSQL.
|
||||||
|
|
||||||
|
## Обновление
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose pull
|
||||||
|
docker compose up -d
|
||||||
|
docker compose logs -f migrate backend worker
|
||||||
|
```
|
||||||
|
|
||||||
|
## Резервная копия PostgreSQL
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose exec -T postgres sh -c 'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB"' > backup.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
## Проверки после работ
|
||||||
|
|
||||||
|
- `docker compose ps`
|
||||||
|
- `docker compose logs -f backend worker frontend`
|
||||||
|
- `/healthz` на backend-домене
|
||||||
|
- вход в Mini App и админку
|
||||||
|
- тестовый платеж или тестовая активация
|
||||||
|
|
||||||
|
Подробности: [развертывание](../deployment.md) и [логи](../troubleshooting/logs.md).
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Пользователи
|
||||||
|
|
||||||
|
Пользовательские операции выполняются в Web App админке. Доступ получают только Telegram-пользователи из `ADMIN_IDS`.
|
||||||
|
|
||||||
|
## Что доступно администратору
|
||||||
|
|
||||||
|
- список пользователей с поиском и фильтрами;
|
||||||
|
- просмотр подписки, статуса, трафика и premium-лимитов;
|
||||||
|
- блокировка пользователя;
|
||||||
|
- ручная синхронизация с Remnawave Panel;
|
||||||
|
- тикеты поддержки и ответы пользователю;
|
||||||
|
- просмотр платежей и служебных событий.
|
||||||
|
|
||||||
|
## Связанные разделы
|
||||||
|
|
||||||
|
- [Админ-панель](../features/admin-panel.md)
|
||||||
|
- [Поддержка](../features/support.md)
|
||||||
|
- [Тарифы](../features/tariffs.md)
|
||||||
|
- [Mini App](../features/web-app.md)
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
Админка сохраняет overrides в базе данных и применяет их поверх `.env`. Это удобно для платежей, внешнего вида, поддержки, уведомлений, legacy-цен и большинства пользовательских параметров. Тарифы редактируются отдельно в разделе **Система -> Тарифы** и сохраняются в JSON-файл `TARIFFS_CONFIG_PATH`.
|
Админка сохраняет overrides в базе данных и применяет их поверх `.env`. Это удобно для платежей, внешнего вида, поддержки, уведомлений, legacy-цен и большинства пользовательских параметров. Тарифы редактируются отдельно в разделе **Система -> Тарифы** и сохраняются в JSON-файл `TARIFFS_CONFIG_PATH`.
|
||||||
|
|
||||||
Полный справочник всех переменных вынесен в [env-vars.md](env-vars.md).
|
Полный справочник всех переменных вынесен в [configuration/env-vars.md](configuration/env-vars.md).
|
||||||
|
|
||||||
## Минимальный `.env`
|
## Минимальный `.env`
|
||||||
|
|
||||||
@@ -102,9 +102,9 @@ docker compose exec backend sh -lc 'id; touch /app/data/themes/test && rm /app/d
|
|||||||
|
|
||||||
## Дополнительные разделы
|
## Дополнительные разделы
|
||||||
|
|
||||||
- [env-vars.md](env-vars.md) - полный справочник переменных `.env`.
|
- [configuration/env-vars.md](configuration/env-vars.md) - полный справочник переменных `.env`.
|
||||||
- [admin.md](admin.md) - как устроены overrides и allowlist настроек.
|
- [features/admin-panel.md](features/admin-panel.md) - как устроены overrides и allowlist настроек.
|
||||||
- [tariffs.md](tariffs.md) - JSON-каталог тарифов и редактор тарифов.
|
- [features/tariffs.md](features/tariffs.md) - JSON-каталог тарифов и редактор тарифов.
|
||||||
- [webapp.md](webapp.md) - домен Mini App, Telegram OAuth и email-вход.
|
- [features/web-app.md](features/web-app.md) - домен Mini App, Telegram OAuth и email-вход.
|
||||||
- [support.md](support.md) - тикеты поддержки и уведомления.
|
- [features/support.md](features/support.md) - тикеты поддержки и уведомления.
|
||||||
- [deployment.md](deployment.md) - Docker Compose, reverse proxy, Caddy/Nginx и обновления.
|
- [deployment.md](deployment.md) - Docker Compose, reverse proxy, Caddy/Nginx и обновления.
|
||||||
|
|||||||
@@ -368,7 +368,7 @@ PAYMENT_HELEKET_TELEGRAM_EMOJI
|
|||||||
|
|
||||||
## Поддержка
|
## Поддержка
|
||||||
|
|
||||||
Подробный сценарий описан в [support.md](support.md).
|
Подробный сценарий описан в [features/support.md](../features/support.md).
|
||||||
|
|
||||||
| Переменная | Назначение |
|
| Переменная | Назначение |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# Безопасность
|
||||||
|
|
||||||
|
Безопасность Minishop в первую очередь держится на стабильных секретах, корректном разделении публичных доменов и ограниченном доступе к админке.
|
||||||
|
|
||||||
|
## Секреты
|
||||||
|
|
||||||
|
- `WEBAPP_SESSION_SECRET` должен быть постоянным между рестартами, иначе Web App-сессии станут невалидными.
|
||||||
|
- `WEBHOOK_SECRET_TOKEN` защищает Telegram webhook.
|
||||||
|
- `PANEL_WEBHOOK_SECRET` проверяет входящие события Remnawave Panel.
|
||||||
|
- Платежные токены и webhook-секреты храните в `.env` или настройках админки с учетом доступа к серверу.
|
||||||
|
|
||||||
|
Сгенерировать секрет можно так:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openssl rand -hex 32
|
||||||
|
```
|
||||||
|
|
||||||
|
## Доступ администраторов
|
||||||
|
|
||||||
|
- `ADMIN_IDS` задает Telegram ID администраторов.
|
||||||
|
- Админка доступна только пользователям из `ADMIN_IDS` при входе через Telegram.
|
||||||
|
- Email-only аккаунты не получают админский доступ.
|
||||||
|
|
||||||
|
## Публичные URL
|
||||||
|
|
||||||
|
- `WEBHOOK_BASE_URL` должен вести на backend webhook server.
|
||||||
|
- `SUBSCRIPTION_MINI_APP_URL` должен вести на frontend/Mini App.
|
||||||
|
- Не добавляйте `/api`, `/auth` или webhook-пути в `SUBSCRIPTION_MINI_APP_URL`.
|
||||||
|
|
||||||
|
## Дополнительно
|
||||||
|
|
||||||
|
- Используйте HTTPS на всех публичных доменах.
|
||||||
|
- Ограничивайте доступ к серверу и `.env`.
|
||||||
|
- Следите за логами платежных вебхуков и panel webhooks.
|
||||||
|
- После ротации секретов перезапускайте соответствующие сервисы и проверяйте вебхуки.
|
||||||
|
|
||||||
|
См. также [переменные окружения](env-vars.md) и [развертывание](../deployment.md).
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# Caddy
|
||||||
|
|
||||||
|
Вариант `deploy/examples/caddy` подходит, если нужен самый простой публичный HTTPS. Caddy сам выпускает и продлевает сертификаты Let's Encrypt.
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
- На сервере открыты входящие `80/tcp` и `443/tcp`.
|
||||||
|
- DNS-записи `WEBHOOK_HOST` и `MINIAPP_HOST` смотрят на этот сервер.
|
||||||
|
- В `.env` заполнены домены, токены, секреты и доступы к Remnawave.
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd deploy/examples/caddy
|
||||||
|
cp .env.example .env
|
||||||
|
nano .env
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Минимально поменяйте:
|
||||||
|
|
||||||
|
- `WEBHOOK_HOST` и `MINIAPP_HOST`;
|
||||||
|
- `BOT_TOKEN`, `ADMIN_IDS`;
|
||||||
|
- `POSTGRES_PASSWORD`;
|
||||||
|
- `WEBAPP_SESSION_SECRET`, `WEBHOOK_SECRET_TOKEN`;
|
||||||
|
- `PANEL_API_URL`, `PANEL_API_KEY`, `PANEL_WEBHOOK_SECRET`.
|
||||||
|
|
||||||
|
## Проверка
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose ps
|
||||||
|
docker compose logs -f caddy backend worker frontend
|
||||||
|
```
|
||||||
|
|
||||||
|
Если нужна нестандартная логика Caddy, правьте `deploy/examples/caddy/Caddyfile` и перезапускайте:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d --force-recreate caddy
|
||||||
|
```
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# Deploy examples
|
||||||
|
|
||||||
|
В `deploy/examples` лежат самодостаточные Compose-варианты для разных способов публикации Minishop. Каждый пример запускается из своей директории и содержит собственный `docker-compose.yml`, `.env.example` и README.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
nano .env
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
После старта проверяйте:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose ps
|
||||||
|
docker compose logs -f backend worker frontend
|
||||||
|
```
|
||||||
|
|
||||||
|
## Какой вариант выбрать
|
||||||
|
|
||||||
|
| Вариант | Когда использовать | Где лежит |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| [Caddy](caddy.md) | Нужен самый простой публичный HTTPS с автоматическими сертификатами Let's Encrypt. | `deploy/examples/caddy` |
|
||||||
|
| [Nginx](nginx.md) | Уже используете Nginx и готовы положить TLS-сертификаты рядом с примером. | `deploy/examples/nginx` |
|
||||||
|
| [Pangolin/Newt](newt.md) | Публикуете сервисы через туннель без входящих портов на сервере приложения. | `deploy/examples/newt` |
|
||||||
|
| [No proxy](no-proxy.md) | Нужно напрямую открыть порты backend/frontend или проверить стек без reverse proxy. | `deploy/examples/no-proxy` |
|
||||||
|
|
||||||
|
## Два публичных URL
|
||||||
|
|
||||||
|
Для production обычно нужны два домена:
|
||||||
|
|
||||||
|
- webhook/backend URL для Telegram, платежных систем и Remnawave webhooks;
|
||||||
|
- Mini App/frontend URL для Telegram Mini App, Web App и админки.
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://webhooks.example.com -> backend:8080
|
||||||
|
https://app.example.com -> frontend:80
|
||||||
|
```
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# Pangolin / Newt
|
||||||
|
|
||||||
|
Вариант `deploy/examples/newt` подходит, если сервер приложения не должен принимать входящие соединения. Newt подключается к Pangolin, а публичные домены настраиваются ресурсами в панели Pangolin.
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd deploy/examples/newt
|
||||||
|
cp .env.example .env
|
||||||
|
nano .env
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
В `.env` заполните:
|
||||||
|
|
||||||
|
- `WEBHOOK_HOST` и `MINIAPP_HOST` - публичные домены ресурсов в Pangolin;
|
||||||
|
- `PANGOLIN_ENDPOINT`, `NEWT_ID`, `NEWT_SECRET` - значения из настроек site/client в Pangolin;
|
||||||
|
- обычные переменные приложения: `BOT_TOKEN`, `ADMIN_IDS`, `POSTGRES_PASSWORD`, секреты и доступ к Remnawave.
|
||||||
|
|
||||||
|
## Ресурсы Pangolin
|
||||||
|
|
||||||
|
Создайте два HTTP-ресурса для Newt site:
|
||||||
|
|
||||||
|
| Публичный домен | Upstream |
|
||||||
|
| --- | --- |
|
||||||
|
| `https://webhooks.example.com` | `http://backend:8080` |
|
||||||
|
| `https://app.example.com` | `http://frontend:80` |
|
||||||
|
|
||||||
|
Домены в Pangolin должны совпадать с `WEBHOOK_HOST` и `MINIAPP_HOST`.
|
||||||
|
|
||||||
|
Официальная инструкция Pangolin по установке Newt site: <https://docs.pangolin.net/manage/sites/install-site>.
|
||||||
|
|
||||||
|
## Проверка
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose ps
|
||||||
|
docker compose logs -f newt backend worker frontend
|
||||||
|
```
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# Nginx
|
||||||
|
|
||||||
|
Вариант `deploy/examples/nginx` поднимает Nginx в той же Docker-сети, что и приложение. Он подходит, если у вас уже есть TLS-сертификаты или нужен ручной контроль Nginx-конфига.
|
||||||
|
|
||||||
|
## Маршрутизация
|
||||||
|
|
||||||
|
- `WEBHOOK_HOST` проксируется в `backend:8080`.
|
||||||
|
- `MINIAPP_HOST` проксируется в `frontend:80`.
|
||||||
|
- `frontend` сам проксирует внутренние `/api`, `/auth` и ассеты тем в `backend:8081`.
|
||||||
|
|
||||||
|
## Подготовка
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd deploy/examples/nginx
|
||||||
|
cp .env.example .env
|
||||||
|
nano .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Положите TLS-сертификаты в `ssl/`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
ssl/
|
||||||
|
webhooks.example.com/
|
||||||
|
fullchain.pem
|
||||||
|
privkey.pem
|
||||||
|
app.example.com/
|
||||||
|
fullchain.pem
|
||||||
|
privkey.pem
|
||||||
|
```
|
||||||
|
|
||||||
|
Имена папок должны совпадать с `WEBHOOK_HOST` и `MINIAPP_HOST` в `.env`.
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
docker compose logs -f nginx backend worker frontend
|
||||||
|
```
|
||||||
|
|
||||||
|
Если нужно поменять заголовки, лимиты или TLS-настройки, правьте `deploy/examples/nginx/nginx.conf.template` и перезапускайте:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d --force-recreate nginx
|
||||||
|
```
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Без reverse proxy
|
||||||
|
|
||||||
|
Вариант `deploy/examples/no-proxy` напрямую публикует HTTP-порты backend и frontend. Он удобен для локальной проверки, внутренней сети или ситуации, когда HTTPS завершается внешней платформой.
|
||||||
|
|
||||||
|
## Порты
|
||||||
|
|
||||||
|
- backend/webhooks: `WEB_SERVER_BIND`, по умолчанию `0.0.0.0:8080`;
|
||||||
|
- frontend/Mini App: `FRONTEND_BIND`, по умолчанию `0.0.0.0:8082`.
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd deploy/examples/no-proxy
|
||||||
|
cp .env.example .env
|
||||||
|
nano .env
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Важно про HTTPS
|
||||||
|
|
||||||
|
Контейнеры приложения сами не выпускают TLS-сертификаты. Для реального Telegram webhook и Mini App публичные URL должны быть HTTPS.
|
||||||
|
|
||||||
|
Используйте этот вариант, если:
|
||||||
|
|
||||||
|
- проверяете стек локально;
|
||||||
|
- публикуете сервисы только во внутренней сети;
|
||||||
|
- TLS уже завершается внешним reverse proxy, load balancer или платформой.
|
||||||
|
|
||||||
|
## Проверка
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://127.0.0.1:8080/healthz
|
||||||
|
curl http://127.0.0.1:8082/health
|
||||||
|
docker compose logs -f backend worker frontend
|
||||||
|
```
|
||||||
+13
-13
@@ -1,7 +1,7 @@
|
|||||||
# Развертывание
|
# Развертывание
|
||||||
|
|
||||||
Документ описывает продакшен-запуск после разделения проекта на `backend`, `frontend` и `worker`.
|
Документ описывает продакшен-запуск после разделения проекта на `backend`, `frontend` и `worker`.
|
||||||
Перед стартом заполните минимальный `.env` по [configuration.md](configuration.md). Полный справочник переменных лежит в [env-vars.md](env-vars.md); после первого входа большинство продуктовых настроек удобнее менять через Web App админку.
|
Перед стартом заполните минимальный `.env` по [configuration.md](configuration.md). Полный справочник переменных лежит в [configuration/env-vars.md](configuration/env-vars.md); после первого входа большинство продуктовых настроек удобнее менять через Web App админку.
|
||||||
|
|
||||||
## Быстрый старт
|
## Быстрый старт
|
||||||
|
|
||||||
@@ -27,16 +27,16 @@ docker compose logs -f backend worker frontend
|
|||||||
|
|
||||||
## Готовые папки запуска
|
## Готовые папки запуска
|
||||||
|
|
||||||
Для production удобнее использовать не корневой compose, а отдельные примеры в
|
Для production удобнее использовать не корневой compose, а отдельные примеры из
|
||||||
[`deploy/examples`](../deploy/examples). В каждой папке лежат свой `docker-compose.yml`,
|
[Deploy examples](deploy-examples/index.md). В каждой папке лежат свой `docker-compose.yml`,
|
||||||
`.env.example`, README и нужный конфиг рядом:
|
`.env.example` и нужный конфиг рядом, а подробные инструкции хранятся в `docs/`:
|
||||||
|
|
||||||
| Папка | Назначение | Запуск |
|
| Папка | Назначение | Запуск |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| [`deploy/examples/caddy`](../deploy/examples/caddy) | Caddy с автоматическим HTTPS. | `cp .env.example .env`, заполнить `.env`, `docker compose up -d`. |
|
| [Caddy](deploy-examples/caddy.md) | Caddy с автоматическим HTTPS. | `cp .env.example .env`, заполнить `.env`, `docker compose up -d`. |
|
||||||
| [`deploy/examples/nginx`](../deploy/examples/nginx) | Nginx в Docker-сети приложения, TLS-сертификаты кладутся в `ssl/`. | `cp .env.example .env`, заполнить `.env`, положить сертификаты, `docker compose up -d`. |
|
| [Nginx](deploy-examples/nginx.md) | Nginx в Docker-сети приложения, TLS-сертификаты кладутся в `ssl/`. | `cp .env.example .env`, заполнить `.env`, положить сертификаты, `docker compose up -d`. |
|
||||||
| [`deploy/examples/newt`](../deploy/examples/newt) | Pangolin/Newt без входящих портов на сервере приложения. | `cp .env.example .env`, заполнить Newt credentials, создать ресурсы в Pangolin, `docker compose up -d`. |
|
| [Pangolin/Newt](deploy-examples/newt.md) | Pangolin/Newt без входящих портов на сервере приложения. | `cp .env.example .env`, заполнить Newt credentials, создать ресурсы в Pangolin, `docker compose up -d`. |
|
||||||
| [`deploy/examples/no-proxy`](../deploy/examples/no-proxy) | Прямая публикация портов backend/frontend. | `cp .env.example .env`, заполнить публичные URL и порты, `docker compose up -d`. |
|
| [No proxy](deploy-examples/no-proxy.md) | Прямая публикация портов backend/frontend. | `cp .env.example .env`, заполнить публичные URL и порты, `docker compose up -d`. |
|
||||||
|
|
||||||
Пример для Caddy:
|
Пример для Caddy:
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ docker compose logs migrate
|
|||||||
- `redis`: Redis 7 для FSM, кеша, rate-limit, очередей и locks.
|
- `redis`: Redis 7 для FSM, кеша, rate-limit, очередей и locks.
|
||||||
|
|
||||||
В production-примерах внешний доступ добавляют `caddy`, `nginx`, `newt` или прямые `ports` в
|
В production-примерах внешний доступ добавляют `caddy`, `nginx`, `newt` или прямые `ports` в
|
||||||
соответствующей папке из [`deploy/examples`](../deploy/examples).
|
соответствующем варианте из [Deploy examples](deploy-examples/index.md).
|
||||||
|
|
||||||
## Логи и проверка
|
## Логи и проверка
|
||||||
|
|
||||||
@@ -246,9 +246,9 @@ docker compose up -d backend worker
|
|||||||
|
|
||||||
Готовые reverse-proxy примеры лежат в:
|
Готовые reverse-proxy примеры лежат в:
|
||||||
|
|
||||||
- [`deploy/examples/caddy`](../deploy/examples/caddy) - Caddy, автоматический HTTPS;
|
- [Caddy](deploy-examples/caddy.md) - автоматический HTTPS;
|
||||||
- [`deploy/examples/nginx`](../deploy/examples/nginx) - Nginx, сертификаты кладутся рядом в `ssl/`;
|
- [Nginx](deploy-examples/nginx.md) - сертификаты кладутся рядом в `ssl/`;
|
||||||
- [`deploy/examples/newt`](../deploy/examples/newt) - Newt/Pangolin, без входящих портов на сервере приложения.
|
- [Newt/Pangolin](deploy-examples/newt.md) - без входящих портов на сервере приложения.
|
||||||
|
|
||||||
Во всех вариантах схема одинаковая:
|
Во всех вариантах схема одинаковая:
|
||||||
|
|
||||||
@@ -274,7 +274,7 @@ app.example.com {
|
|||||||
|
|
||||||
## Newt
|
## Newt
|
||||||
|
|
||||||
Для Newt используйте [`deploy/examples/newt`](../deploy/examples/newt). В compose уже есть сервис
|
Для Newt используйте [Pangolin / Newt](deploy-examples/newt.md). В compose уже есть сервис
|
||||||
`newt`, а в `.env.example` - поля `PANGOLIN_ENDPOINT`, `NEWT_ID` и `NEWT_SECRET`.
|
`newt`, а в `.env.example` - поля `PANGOLIN_ENDPOINT`, `NEWT_ID` и `NEWT_SECRET`.
|
||||||
|
|
||||||
В Pangolin создайте два HTTP-ресурса для этого Newt site:
|
В Pangolin создайте два HTTP-ресурса для этого Newt site:
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Основные возможности
|
||||||
|
|
||||||
|
Minishop закрывает путь от регистрации пользователя до оплаты, продления, поддержки и сопровождения подписки.
|
||||||
|
|
||||||
|
## Для пользователей
|
||||||
|
|
||||||
|
- Регистрация через Telegram Mini App или email-код.
|
||||||
|
- Просмотр подписки, срока действия, трафика и ссылки подключения.
|
||||||
|
- Покупка подписки, пакетов трафика и дополнительных устройств.
|
||||||
|
- Пробный период, промокоды и реферальные сценарии.
|
||||||
|
- Тикеты поддержки внутри Mini App.
|
||||||
|
- Встроенные инструкции установки и публичные ссылки `/s/<token>`.
|
||||||
|
|
||||||
|
## Для администраторов
|
||||||
|
|
||||||
|
- Поиск и управление пользователями.
|
||||||
|
- Настройка платежей, тарифов, внешнего вида и поддержки.
|
||||||
|
- Рассылки, промокоды и логи действий.
|
||||||
|
- Ручная синхронизация с Remnawave Panel.
|
||||||
|
- Редактор JSON-каталога тарифов.
|
||||||
|
|
||||||
|
Подробности: [админ-панель](admin-panel.md), [Mini App](web-app.md) и [поддержка](support.md).
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Платежи
|
||||||
|
|
||||||
|
Платежные методы включаются настройками и отображаются пользователю как кнопки оплаты в Mini App и Telegram-сценариях.
|
||||||
|
|
||||||
|
## Поддерживаемые провайдеры
|
||||||
|
|
||||||
|
- [YooKassa](../payments/yookassa.md)
|
||||||
|
- [FreeKassa](../payments/freekassa.md)
|
||||||
|
- [Platega](../payments/platega.md)
|
||||||
|
- [SeverPay](../payments/severpay.md)
|
||||||
|
- [Wata](../payments/wata.md)
|
||||||
|
- [CryptoPay](../payments/cryptopay.md)
|
||||||
|
- [Heleket](../payments/heleket.md)
|
||||||
|
- [Telegram Stars](../payments/telegram-stars.md)
|
||||||
|
|
||||||
|
## Типовой порядок настройки
|
||||||
|
|
||||||
|
1. Включите нужный провайдер в админке или через `.env`.
|
||||||
|
2. Заполните публичные параметры и секреты.
|
||||||
|
3. Настройте webhook URL у провайдера, если это требуется.
|
||||||
|
4. Проверьте порядок и подписи кнопок оплаты.
|
||||||
|
5. Выполните тестовый платеж и проверьте логи backend.
|
||||||
|
|
||||||
|
## Где смотреть параметры
|
||||||
|
|
||||||
|
- [Справочник `.env`](../configuration/env-vars.md) содержит все ключи провайдеров.
|
||||||
|
- [Админ-панель](admin-panel.md) описывает UI-настройки платежей.
|
||||||
|
- [Тарифы](tariffs.md) описывают цены, Stars и сценарии покупки.
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Подписки
|
||||||
|
|
||||||
|
Подписки управляются через каталог тарифов и синхронизируются с Remnawave Panel.
|
||||||
|
|
||||||
|
## Модели тарифов
|
||||||
|
|
||||||
|
- **Period** - подписка на срок с месячным лимитом трафика.
|
||||||
|
- **Traffic** - покупка пакетов трафика без привязки к периоду.
|
||||||
|
- **Premium** - отдельные premium-сквады и premium-лимит.
|
||||||
|
- **HWID-устройства** - докупка дополнительных устройств при включенном разделе устройств.
|
||||||
|
|
||||||
|
## Жизненный цикл
|
||||||
|
|
||||||
|
- создание пользователя в панели;
|
||||||
|
- применение пробного периода или покупки;
|
||||||
|
- продление и докупки;
|
||||||
|
- предупреждения по трафику;
|
||||||
|
- синхронизация подписки и статусов;
|
||||||
|
- обработка смены тарифа.
|
||||||
|
|
||||||
|
Подробности: [тарифы](tariffs.md) и [Mini App](web-app.md).
|
||||||
@@ -64,7 +64,7 @@ Email-уведомления администраторам включаются
|
|||||||
| `SUPPORT_ADMIN_NOTIFICATION_COOLDOWN_SECONDS` | Минимальная пауза между повторными Telegram/log уведомлениями по одному непрочитанному тикету. |
|
| `SUPPORT_ADMIN_NOTIFICATION_COOLDOWN_SECONDS` | Минимальная пауза между повторными Telegram/log уведомлениями по одному непрочитанному тикету. |
|
||||||
| `SUPPORT_ADMIN_EMAIL_COOLDOWN_SECONDS` | Минимальная пауза между повторными email-уведомлениями по одному непрочитанному тикету. |
|
| `SUPPORT_ADMIN_EMAIL_COOLDOWN_SECONDS` | Минимальная пауза между повторными email-уведомлениями по одному непрочитанному тикету. |
|
||||||
|
|
||||||
Все эти параметры описаны в [env-vars.md](env-vars.md). Основной рекомендуемый способ менять их - админка **Система -> Настройки -> Поддержка**; значения применяются как override поверх `.env`.
|
Все эти параметры описаны в [env-vars.md](../configuration/env-vars.md). Основной рекомендуемый способ менять их - админка **Система -> Настройки -> Поддержка**; значения применяются как override поверх `.env`.
|
||||||
|
|
||||||
## API и хранение
|
## API и хранение
|
||||||
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
- JSON-каталог тарифов из `TARIFFS_CONFIG_PATH` (по умолчанию `data/tariffs.json`);
|
- JSON-каталог тарифов из `TARIFFS_CONFIG_PATH` (по умолчанию `data/tariffs.json`);
|
||||||
- конфигурация через переменные `.env`, если JSON-файл отсутствует.
|
- конфигурация через переменные `.env`, если JSON-файл отсутствует.
|
||||||
|
|
||||||
JSON-каталог может содержать несколько тарифов разных моделей: подписки на срок, пакеты трафика без срока действия, разные наборы Internal Squads, лимиты устройств и пакеты докупки. Пример формата: [data/tariffs.example.json](../data/tariffs.example.json).
|
JSON-каталог может содержать несколько тарифов разных моделей: подписки на срок, пакеты трафика без срока действия, разные наборы Internal Squads, лимиты устройств и пакеты докупки. Пример формата: [data/tariffs.example.json](https://gitlab.com/3252a8/remnawave-minshop/-/blob/main/data/tariffs.example.json).
|
||||||
|
|
||||||
Коротко по моделям:
|
Коротко по моделям:
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ JSON-каталог может содержать несколько тариф
|
|||||||
|
|
||||||
После сохранения изменения применяются к новым запросам Web App сразу, потому что конфиг тарифов загружается из JSON при обращении. Уже созданные подписки сохраняют свой `tariff_key`; при удалении или отключении тарифа проверьте, что активные подписки с этим ключом не требуют дальнейшего продления или смены.
|
После сохранения изменения применяются к новым запросам Web App сразу, потому что конфиг тарифов загружается из JSON при обращении. Уже созданные подписки сохраняют свой `tariff_key`; при удалении или отключении тарифа проверьте, что активные подписки с этим ключом не требуют дальнейшего продления или смены.
|
||||||
|
|
||||||
Подробности по админ-панели, правам доступа, сохранению настроек и списку разделов есть в [admin.md](admin.md).
|
Подробности по админ-панели, правам доступа, сохранению настроек и списку разделов есть в [админ-панели](admin-panel.md).
|
||||||
|
|
||||||
## Как выбирается режим
|
## Как выбирается режим
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ Web App собирается в отдельный `frontend` image и отда
|
|||||||
- реферальную ссылку и статистику приглашений;
|
- реферальную ссылку и статистику приглашений;
|
||||||
- привязку email и Telegram к одному аккаунту.
|
- привязку email и Telegram к одному аккаунту.
|
||||||
|
|
||||||
Для администраторов из `ADMIN_IDS` Web App также показывает админ-панель: статистику, **пользователей** (поиск, фильтры, premium-трафик), поддержку, рассылки, промокоды, логи, настройки и редактор тарифов. Подробности: [admin.md](admin.md).
|
Для администраторов из `ADMIN_IDS` Web App также показывает админ-панель: статистику, **пользователей** (поиск, фильтры, premium-трафик), поддержку, рассылки, промокоды, логи, настройки и редактор тарифов. Подробности: [админ-панель](admin-panel.md).
|
||||||
|
|
||||||
## Настройки `.env`
|
## Настройки `.env`
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ Email-вход работает через одноразовый код:
|
|||||||
|
|
||||||
Для Brevo обычно подходит порт `587` с STARTTLS. Если основной порт недоступен, приложение пробует порты из `SMTP_FALLBACK_PORTS`; порт `465` используется через SSL.
|
Для Brevo обычно подходит порт `587` с STARTTLS. Если основной порт недоступен, приложение пробует порты из `SMTP_FALLBACK_PORTS`; порт `465` используется через SSL.
|
||||||
|
|
||||||
Полный список переменных, обязательные поля для включения email-входа и типичные ошибки подключения описаны в разделе **SMTP и вход по email** в [configuration.md](configuration.md).
|
Полный список переменных, обязательные поля для включения email-входа и типичные ошибки подключения описаны в разделе **SMTP и вход по email** в [configuration.md](../configuration.md).
|
||||||
|
|
||||||
## Проксирование
|
## Проксирование
|
||||||
|
|
||||||
@@ -131,12 +131,12 @@ Email-вход работает через одноразовый код:
|
|||||||
WebApp API на `backend:8081`, поэтому внешний reverse proxy обычно не должен отправлять эти пути в
|
WebApp API на `backend:8081`, поэтому внешний reverse proxy обычно не должен отправлять эти пути в
|
||||||
`backend:8081` напрямую.
|
`backend:8081` напрямую.
|
||||||
|
|
||||||
Готовые примеры лежат в [`deploy/examples`](../deploy/examples):
|
Готовые варианты описаны в [Deploy examples](../deploy-examples/index.md):
|
||||||
|
|
||||||
- `caddy` - Caddy с автоматическим HTTPS;
|
- [Caddy](../deploy-examples/caddy.md) - автоматический HTTPS;
|
||||||
- `nginx` - Nginx с сертификатами в соседней папке `ssl/`;
|
- [Nginx](../deploy-examples/nginx.md) - сертификаты в соседней папке `ssl/`;
|
||||||
- `newt` - Pangolin/Newt;
|
- [Pangolin/Newt](../deploy-examples/newt.md) - публикация без входящих портов на сервере приложения;
|
||||||
- `no-proxy` - прямая публикация портов для проверки или внешней TLS-платформы.
|
- [No proxy](../deploy-examples/no-proxy.md) - прямая публикация портов для проверки или внешней TLS-платформы.
|
||||||
|
|
||||||
В default `docker-compose.yml` наружу публикуются `frontend` и webhook/backend port, а внутри Docker
|
В default `docker-compose.yml` наружу публикуются `frontend` и webhook/backend port, а внутри Docker
|
||||||
network сервисы доступны друг другу по service DNS names:
|
network сервисы доступны друг другу по service DNS names:
|
||||||
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
@@ -0,0 +1,26 @@
|
|||||||
|
# Обзор
|
||||||
|
|
||||||
|
Remnawave Minishop состоит из Telegram-бота, backend API, worker-процессов, frontend/Mini App и инфраструктурных сервисов PostgreSQL и Redis. В production эти части запускаются через Docker Compose и общаются с Remnawave Panel по API и вебхукам.
|
||||||
|
|
||||||
|
## Основные компоненты
|
||||||
|
|
||||||
|
- **Backend** - Telegram webhook, платежные вебхуки, panel webhooks, API для Mini App и админки.
|
||||||
|
- **Worker** - фоновые задачи, синхронизация подписок, обработка очереди вебхуков и тарифных событий.
|
||||||
|
- **Frontend** - отдельный nginx-образ с Mini App и админкой.
|
||||||
|
- **PostgreSQL** - пользователи, платежи, настройки, поддержка, промокоды и служебные данные.
|
||||||
|
- **Redis** - FSM, кеши, rate limit, очередь вебхуков и distributed locks.
|
||||||
|
|
||||||
|
## Сценарии
|
||||||
|
|
||||||
|
- пользователь открывает Mini App, видит подписку и оплачивает тариф;
|
||||||
|
- платежный провайдер отправляет webhook в backend;
|
||||||
|
- worker применяет фоновые задачи и синхронизацию;
|
||||||
|
- Remnawave Panel хранит пользователя, подписку и ссылку подключения;
|
||||||
|
- администратор управляет тарифами, поддержкой, пользователями и настройками через админку.
|
||||||
|
|
||||||
|
## Куда идти дальше
|
||||||
|
|
||||||
|
- [Установка](setup.md) - базовый запуск через Compose.
|
||||||
|
- [Deploy examples](../deploy-examples/index.md) - готовые варианты публикации.
|
||||||
|
- [Архитектура](../architecture.md) - структура каталогов и сервисов.
|
||||||
|
- [Mini App](../features/web-app.md) - публичный frontend, Telegram OAuth и инструкции установки.
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# Установка
|
||||||
|
|
||||||
|
Начните с `.env`, затем поднимите Compose-стек и проверьте backend, worker и frontend.
|
||||||
|
|
||||||
|
## Минимальный запуск
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
nano .env
|
||||||
|
docker compose up -d --build
|
||||||
|
docker compose ps
|
||||||
|
docker compose logs -f backend worker frontend
|
||||||
|
```
|
||||||
|
|
||||||
|
## Что заполнить в первую очередь
|
||||||
|
|
||||||
|
- `BOT_TOKEN` и `ADMIN_IDS` для доступа к боту и админке.
|
||||||
|
- `WEBHOOK_BASE_URL` для Telegram, платежных и panel webhook URL.
|
||||||
|
- `SUBSCRIPTION_MINI_APP_URL` для Mini App и кнопок в Telegram.
|
||||||
|
- `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`.
|
||||||
|
- `WEBAPP_SESSION_SECRET`, `WEBHOOK_SECRET_TOKEN`, `PANEL_API_URL`, `PANEL_API_KEY`, `PANEL_WEBHOOK_SECRET`.
|
||||||
|
|
||||||
|
## Как выбрать Compose-вариант
|
||||||
|
|
||||||
|
- Для быстрого публичного HTTPS берите [Caddy](../deploy-examples/caddy.md).
|
||||||
|
- Если у вас уже есть TLS-сертификаты и нужен Nginx в Docker-сети, берите [Nginx](../deploy-examples/nginx.md).
|
||||||
|
- Если нельзя открывать входящие порты на сервере приложения, берите [Pangolin/Newt](../deploy-examples/newt.md).
|
||||||
|
- Для локальной проверки или внешнего TLS-терминатора берите [no-proxy](../deploy-examples/no-proxy.md).
|
||||||
|
|
||||||
|
## После первого входа
|
||||||
|
|
||||||
|
1. Откройте админку через Mini App.
|
||||||
|
2. Проверьте платежные методы в настройках.
|
||||||
|
3. Настройте каталог тарифов.
|
||||||
|
4. Проверьте инструкции подключения.
|
||||||
|
5. Сделайте тестовую покупку или пробную активацию.
|
||||||
|
|
||||||
|
Подробности: [настройка окружения](../configuration.md) и [развертывание](../deployment.md).
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# Remnawave Minishop
|
||||||
|
|
||||||
|
Remnawave Minishop - Telegram-бот и Mini App для продажи и управления подписками Remnawave. Документация помогает развернуть стек, настроить платежи, тарифы, админку, поддержку и публичный личный кабинет.
|
||||||
|
|
||||||
|
> Проект работает вместе с Remnawave Panel: панель хранит пользователей и подписки, а Minishop отвечает за Telegram, платежи, Mini App, тарифы и операционную админку.
|
||||||
|
|
||||||
|
## Быстрый старт
|
||||||
|
|
||||||
|
- [Обзор](getting-started/overview.md) - архитектура, сервисы и основные сценарии.
|
||||||
|
- [Установка](getting-started/setup.md) - путь от `.env` до первого запуска.
|
||||||
|
- [Deploy examples](deploy-examples/index.md) - Caddy, Nginx, Pangolin/Newt и no-proxy варианты.
|
||||||
|
- [Настройка платежей](features/payments.md) - включение провайдеров и проверка вебхуков.
|
||||||
|
- [Безопасность](configuration/security.md) - секреты, доступы и публичные URL.
|
||||||
|
- [Админ-панель](features/admin-panel.md) - пользователи, настройки, рассылки, поддержка и тарифы.
|
||||||
|
- [Миграции](migrations/index.md) - готовые сценарии переноса с других ботов.
|
||||||
|
- [Устранение неполадок](troubleshooting/issues.md) - быстрые проверки для частых проблем.
|
||||||
|
|
||||||
|
## Ключевые возможности
|
||||||
|
|
||||||
|
- **Продажа подписок** - period- и traffic-тарифы, докупки трафика, HWID-устройства, premium-сквады и Telegram Stars.
|
||||||
|
- **Жизненный цикл пользователей** - регистрация, пробный период, продление, синхронизация с панелью и предупреждения по трафику.
|
||||||
|
- **Mini App** - личный кабинет, инструкции установки, Telegram OAuth, email-вход и публичные referral-ссылки.
|
||||||
|
- **Операционные инструменты** - админка, тикеты поддержки, промокоды, рассылки, логи и настройки поверх `.env`.
|
||||||
|
|
||||||
|
## Справочник
|
||||||
|
|
||||||
|
- [Переменные окружения](configuration/env-vars.md)
|
||||||
|
- [Развертывание](deployment.md)
|
||||||
|
- [Тарифы](features/tariffs.md)
|
||||||
|
- [Темы Web App](features/webapp-themes.md)
|
||||||
|
- [Миграции](migrations/index.md)
|
||||||
|
- [Миграция с remnawave-tg-shop](migrations/remnawave-tg-shop.md)
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Миграции с других ботов
|
||||||
|
|
||||||
|
Этот раздел содержит готовые инструкции миграции в Remnawave Minishop из уже описанных источников. Каждая поддерживаемая миграция должна быть отдельным Markdown-файлом с конкретными шагами, ограничениями, командами и проверками.
|
||||||
|
|
||||||
|
Сейчас в документации есть только один готовый сценарий:
|
||||||
|
|
||||||
|
| Источник | Поддерживаемый случай | Инструкция |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `remnawave-tg-shop` `v2.7.0` и близкие версии | Переезд старого stack/volume PostgreSQL на split-архитектуру Minishop `v3.4+`, обновление `.env`, запуск `migrate`, проверка reverse proxy | [Миграция с remnawave-tg-shop](remnawave-tg-shop.md) |
|
||||||
|
|
||||||
|
## Что покрывает текущая миграция
|
||||||
|
|
||||||
|
Инструкция для `remnawave-tg-shop` рассчитана на родственный стек, где заранее известны Docker volumes, контейнеры, схема БД и путь обновления:
|
||||||
|
|
||||||
|
- перенос PostgreSQL volume `remnawave-tg-shop-db-data` в новый volume Minishop;
|
||||||
|
- создание новых пустых volumes `redis-data` и `shop-data`;
|
||||||
|
- перенос Caddy volumes при использовании Caddy-варианта;
|
||||||
|
- обновление переменных окружения, которые изменились после `v2.7.0`;
|
||||||
|
- запуск one-shot сервиса `migrate`;
|
||||||
|
- переход с одного upstream `remnawave-tg-shop:8000` на `backend:8080` и `frontend:80`;
|
||||||
|
- запуск через корневой compose или готовые deploy examples.
|
||||||
|
|
||||||
|
## Что пока не описано
|
||||||
|
|
||||||
|
Для других Telegram-ботов, самописных панелей и ручных таблиц готовой инструкции пока нет. Такие источники нельзя переносить по инструкции `remnawave-tg-shop`: у них могут отличаться таблицы пользователей, модель тарифов, статусы платежей, связь с Remnawave Panel, формат промокодов, рефералы и правила отката.
|
||||||
|
|
||||||
|
Когда для конкретного источника появится проверенный сценарий, он должен быть добавлен в этот раздел отдельным файлом и отдельной строкой в таблице выше.
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
# Миграция с `remnawave-tg-shop` (≤ v2.7.0) на `remnawave-minishop` (v3.4+)
|
# Миграция с `remnawave-tg-shop` (≤ v2.7.0) на `remnawave-minishop` (v3.4+)
|
||||||
|
|
||||||
|
Эта страница - готовый сценарий для legacy-стека `remnawave-tg-shop`. Это единственная миграция с другого бота, которая сейчас описана в документации. Для других Telegram-ботов, самописных панелей и ручных таблиц готового сценария пока нет: их нельзя переносить по этой инструкции без отдельного анализа схемы БД, тарифов, платежей и связи с Remnawave Panel.
|
||||||
|
|
||||||
|
Автоматический скрипт ниже рассчитан именно на родственный стек `remnawave-tg-shop`, где структура БД и Docker volumes известны заранее. Для других ботов нужен отдельный адаптер экспорта/импорта.
|
||||||
|
|
||||||
## Короткий путь без смены ветки и сборки
|
## Короткий путь без смены ветки и сборки
|
||||||
|
|
||||||
Если вы используете только готовые Docker-образы и не собираете проект
|
Если вы используете только готовые Docker-образы и не собираете проект
|
||||||
@@ -127,7 +131,7 @@ docker compose \
|
|||||||
| — | `REDIS_URL=redis://redis:6379/0` | Обязательна для воркера, очередей и rate-limit. По умолчанию в compose-файлах уже задана. |
|
| — | `REDIS_URL=redis://redis:6379/0` | Обязательна для воркера, очередей и rate-limit. По умолчанию в compose-файлах уже задана. |
|
||||||
| — | `WEBAPP_SESSION_SECRET`, `WEBAPP_ENABLED`, `WEBAPP_SERVER_PORT`, `WEBAPP_THEMES_DIR`, `TARIFFS_CONFIG_PATH` | Новые настройки Web App / тарифного каталога. Безопасные дефолты есть в `.env.example`. |
|
| — | `WEBAPP_SESSION_SECRET`, `WEBAPP_ENABLED`, `WEBAPP_SERVER_PORT`, `WEBAPP_THEMES_DIR`, `TARIFFS_CONFIG_PATH` | Новые настройки Web App / тарифного каталога. Безопасные дефолты есть в `.env.example`. |
|
||||||
|
|
||||||
Полный референс — [docs/configuration.md](configuration.md). Скрипт миграции
|
Полный референс — [docs/configuration.md](../configuration.md). Скрипт миграции
|
||||||
эти переменные **не правит** автоматически (только `POSTGRES_HOST`), потому
|
эти переменные **не правит** автоматически (только `POSTGRES_HOST`), потому
|
||||||
что у каждой инсталляции свой шаблон `.env` с кастомными значениями. Лучше
|
что у каждой инсталляции свой шаблон `.env` с кастомными значениями. Лучше
|
||||||
сравнить свой `.env` с `.env.example` глазами один раз, чем получить
|
сравнить свой `.env` с `.env.example` глазами один раз, чем получить
|
||||||
@@ -357,8 +361,8 @@ server {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Полные примеры (Caddy, Nginx, Newt/Pangolin и запуск без reverse proxy) — в
|
Полные примеры (Caddy, Nginx, Newt/Pangolin и запуск без reverse proxy) — в
|
||||||
[docs/deployment.md](deployment.md), [docs/webapp.md](webapp.md) и папке
|
[docs/deployment.md](../deployment.md), [docs/features/web-app.md](../features/web-app.md) и
|
||||||
[`deploy/examples`](../deploy/examples). Если раньше прокси указывал на
|
[Deploy examples](../deploy-examples/index.md). Если раньше прокси указывал на
|
||||||
`remnawave-tg-shop:8000` напрямую, после миграции нужно либо переключиться на
|
`remnawave-tg-shop:8000` напрямую, после миграции нужно либо переключиться на
|
||||||
`backend:8080` / `frontend:80`, либо использовать готовый Caddy/Nginx/Newt
|
`backend:8080` / `frontend:80`, либо использовать готовый Caddy/Nginx/Newt
|
||||||
пример, который уже знает правильную маршрутизацию.
|
пример, который уже знает правильную маршрутизацию.
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# CryptoPay
|
||||||
|
|
||||||
|
CryptoPay используется для криптовалютных платежей через отдельный токен и сеть Crypto Bot API.
|
||||||
|
|
||||||
|
## Что включить
|
||||||
|
|
||||||
|
- `CRYPTOPAY_ENABLED` - включает CryptoPay среди доступных методов.
|
||||||
|
- Presentation-ключи `PAYMENT_CRYPTOPAY_*` - подписи и иконки кнопки в Mini App и Telegram.
|
||||||
|
|
||||||
|
## Что настроить
|
||||||
|
|
||||||
|
1. Укажите `CRYPTOPAY_TOKEN`.
|
||||||
|
2. Выберите `CRYPTOPAY_NETWORK`: `mainnet` или `testnet`.
|
||||||
|
3. Задайте `CRYPTOPAY_CURRENCY_TYPE`: `fiat` или `crypto`.
|
||||||
|
4. Проверьте `CRYPTOPAY_ASSET`, например `RUB`, `USDT` или `BTC`.
|
||||||
|
5. Добавьте `cryptopay` в `PAYMENT_METHODS_ORDER`.
|
||||||
|
|
||||||
|
## Проверка
|
||||||
|
|
||||||
|
- Для тестов используйте соответствующую сеть: testnet-токен не должен попадать в mainnet-настройки.
|
||||||
|
- Выполните тестовый платеж и проверьте, что статус закрывается после callback от провайдера.
|
||||||
|
- Если сумма или asset выглядят неверно, проверьте сочетание `CRYPTOPAY_CURRENCY_TYPE` и `CRYPTOPAY_ASSET`.
|
||||||
|
|
||||||
|
## Где подробнее
|
||||||
|
|
||||||
|
- [Переменные CryptoPay](../configuration/env-vars.md#cryptopay)
|
||||||
|
- [Настройка платежей](../features/payments.md)
|
||||||
|
- [Логи и диагностика](../troubleshooting/logs.md)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# FreeKassa
|
||||||
|
|
||||||
|
FreeKassa подключается как отдельный платежный метод и обрабатывает входящие webhook-события через backend.
|
||||||
|
|
||||||
|
## Что настроить
|
||||||
|
|
||||||
|
- Включение провайдера: `FREEKASSA_ENABLED`.
|
||||||
|
- ID магазина, API/secret-ключи и настройки подписи.
|
||||||
|
- Trusted IP allowlist, если используется.
|
||||||
|
- Публичный webhook URL на `WEBHOOK_BASE_URL`.
|
||||||
|
|
||||||
|
## Где подробнее
|
||||||
|
|
||||||
|
- [Переменные FreeKassa](../configuration/env-vars.md#freekassa)
|
||||||
|
- [Платежи](../features/payments.md)
|
||||||
|
- [Логи и проверка](../troubleshooting/logs.md)
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# Heleket
|
||||||
|
|
||||||
|
Heleket используется для crypto-инвойсов с отдельными merchant ID, payment API key, валютой инвойса и настройками webhook-проверки.
|
||||||
|
|
||||||
|
## Что включить
|
||||||
|
|
||||||
|
- `HELEKET_ENABLED` - включает Heleket среди доступных методов.
|
||||||
|
- Presentation-ключи `PAYMENT_HELEKET_*` - подписи и иконки кнопки.
|
||||||
|
|
||||||
|
## Что настроить
|
||||||
|
|
||||||
|
1. Укажите `HELEKET_BASE_URL`, `HELEKET_MERCHANT_ID` и `HELEKET_API_KEY`.
|
||||||
|
2. Настройте `HELEKET_CURRENCY`.
|
||||||
|
3. При необходимости задайте `HELEKET_TO_CURRENCY` и `HELEKET_NETWORK`.
|
||||||
|
4. Проверьте `HELEKET_RETURN_URL` и `HELEKET_SUCCESS_URL`.
|
||||||
|
5. Настройте `HELEKET_LIFETIME_SECONDS`: допустимый диапазон 300..43200.
|
||||||
|
6. Если включаете проверку webhook, задайте `HELEKET_VERIFY_WEBHOOK_SIGNATURE`.
|
||||||
|
7. Для IP-фильтрации заполните `HELEKET_TRUSTED_IPS`.
|
||||||
|
8. Добавьте `heleket` в `PAYMENT_METHODS_ORDER`.
|
||||||
|
|
||||||
|
## Проверка
|
||||||
|
|
||||||
|
- Создайте тестовый инвойс и убедитесь, что пользователь получает корректную ссылку.
|
||||||
|
- Проверьте, что сеть и валюта соответствуют настройкам в кабинете Heleket.
|
||||||
|
- Если webhook отклоняется, проверьте подпись, allowlist и фактический payload в backend-логах.
|
||||||
|
|
||||||
|
## Где подробнее
|
||||||
|
|
||||||
|
- [Переменные Heleket](../configuration/env-vars.md#heleket)
|
||||||
|
- [Настройка платежей](../features/payments.md)
|
||||||
|
- [Логи и диагностика](../troubleshooting/logs.md)
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Platega
|
||||||
|
|
||||||
|
Platega подключается как отдельный платежный провайдер, но внутри Minishop может дать несколько кнопок: основную legacy-кнопку, СБП/карту и крипто-кнопку. Общие merchant-параметры задаются один раз, а method ID и подписи кнопок настраиваются отдельно.
|
||||||
|
|
||||||
|
## Что включить
|
||||||
|
|
||||||
|
- `PLATEGA_ENABLED` - общий флаг провайдера.
|
||||||
|
- `PLATEGA_SBP_ENABLED` - отдельная кнопка СБП/карта.
|
||||||
|
- `PLATEGA_CRYPTO_ENABLED` - отдельная crypto-кнопка Platega.
|
||||||
|
- `PLATEGA_PAYMENT_METHOD` - legacy/fallback method ID для старых callback и старых установок.
|
||||||
|
|
||||||
|
## Что настроить
|
||||||
|
|
||||||
|
1. Укажите `PLATEGA_BASE_URL`, `PLATEGA_MERCHANT_ID` и `PLATEGA_SECRET`.
|
||||||
|
2. Заполните `PLATEGA_SBP_METHOD` и/или `PLATEGA_CRYPTO_METHOD`, если используете отдельные кнопки.
|
||||||
|
3. Проверьте `PLATEGA_RETURN_URL` и `PLATEGA_FAILED_URL`.
|
||||||
|
4. Настройте тексты и иконки кнопок через `PAYMENT_PLATEGA_SBP_*` и `PAYMENT_PLATEGA_CRYPTO_*`.
|
||||||
|
5. Добавьте нужные методы в `PAYMENT_METHODS_ORDER`.
|
||||||
|
|
||||||
|
## Проверка
|
||||||
|
|
||||||
|
- После сохранения настроек откройте Mini App и убедитесь, что видны только включенные Platega-кнопки.
|
||||||
|
- Выполните тестовую оплату для каждой включенной кнопки: СБП/карта и crypto используют разные method ID.
|
||||||
|
- При ошибках проверьте backend-логи и ответ провайдера при создании платежной ссылки.
|
||||||
|
|
||||||
|
## Где подробнее
|
||||||
|
|
||||||
|
- [Переменные Platega](../configuration/env-vars.md#platega)
|
||||||
|
- [Настройка платежей](../features/payments.md)
|
||||||
|
- [Логи и диагностика](../troubleshooting/logs.md)
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# SeverPay
|
||||||
|
|
||||||
|
SeverPay подключается как отдельный платежный метод с собственным MID, token и сроком жизни платежной ссылки.
|
||||||
|
|
||||||
|
## Что включить
|
||||||
|
|
||||||
|
- `SEVERPAY_ENABLED` - показывает SeverPay среди доступных методов оплаты.
|
||||||
|
- Presentation-ключи `PAYMENT_SEVERPAY_*` - подписи и иконки кнопки в Mini App и Telegram.
|
||||||
|
|
||||||
|
## Что настроить
|
||||||
|
|
||||||
|
1. Укажите `SEVERPAY_BASE_URL`.
|
||||||
|
2. Заполните `SEVERPAY_MID` и `SEVERPAY_TOKEN`.
|
||||||
|
3. Настройте `SEVERPAY_RETURN_URL`.
|
||||||
|
4. При необходимости задайте `SEVERPAY_LIFETIME_MINUTES`.
|
||||||
|
5. Добавьте `severpay` в `PAYMENT_METHODS_ORDER`.
|
||||||
|
|
||||||
|
## Проверка
|
||||||
|
|
||||||
|
- Создайте тестовый платеж и проверьте, что пользователь получает платежную ссылку.
|
||||||
|
- Убедитесь, что ссылка живет ожидаемое время, если задан `SEVERPAY_LIFETIME_MINUTES`.
|
||||||
|
- После оплаты проверьте статус платежа в backend-логах и в админке.
|
||||||
|
|
||||||
|
## Где подробнее
|
||||||
|
|
||||||
|
- [Переменные SeverPay](../configuration/env-vars.md#severpay)
|
||||||
|
- [Настройка платежей](../features/payments.md)
|
||||||
|
- [Логи и диагностика](../troubleshooting/logs.md)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Telegram Stars
|
||||||
|
|
||||||
|
Telegram Stars используются напрямую и поддерживаются в legacy-ценах и JSON-каталоге тарифов.
|
||||||
|
|
||||||
|
## Где применяются Stars
|
||||||
|
|
||||||
|
- Цены периодов подписки.
|
||||||
|
- Пакеты трафика.
|
||||||
|
- Premium-докупки.
|
||||||
|
- HWID-докупки, если они включены в каталоге тарифов.
|
||||||
|
|
||||||
|
## Что проверить
|
||||||
|
|
||||||
|
- `STARS_ENABLED`.
|
||||||
|
- Stars-цены в legacy-настройках или JSON-каталоге.
|
||||||
|
- Корректное округление цены до целого количества Stars.
|
||||||
|
- Сценарии смены тарифа: XTR/Stars-докупки не конвертируются без явного курса.
|
||||||
|
|
||||||
|
Подробности: [переменные платежей](../configuration/env-vars.md#платежи) и [тарифы](../features/tariffs.md).
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Wata
|
||||||
|
|
||||||
|
Wata подключается как отдельный провайдер с bearer token, платежными ссылками и опциональной проверкой подписи webhook.
|
||||||
|
|
||||||
|
## Что включить
|
||||||
|
|
||||||
|
- `WATA_ENABLED` - включает Wata для пользователей.
|
||||||
|
- `WATA_ADMIN_ONLY_ENABLED` - оставляет метод доступным только для админских сценариев, если используется вместо публичного включения.
|
||||||
|
- Presentation-ключи `PAYMENT_WATA_*` - подписи и иконки кнопки.
|
||||||
|
|
||||||
|
## Что настроить
|
||||||
|
|
||||||
|
1. Укажите `WATA_BASE_URL` и `WATA_API_TOKEN`.
|
||||||
|
2. Проверьте `WATA_RETURN_URL` и `WATA_FAILED_URL`.
|
||||||
|
3. Настройте `WATA_LINK_TTL_MINUTES`: минимум 15 минут, максимум 43200.
|
||||||
|
4. Если включаете проверку подписи, задайте `WATA_WEBHOOK_VERIFY_SIGNATURE` и при необходимости `WATA_PUBLIC_KEY`.
|
||||||
|
5. Для дополнительной защиты заполните `WATA_TRUSTED_IPS`.
|
||||||
|
6. Добавьте `wata` в `PAYMENT_METHODS_ORDER`.
|
||||||
|
|
||||||
|
## Проверка
|
||||||
|
|
||||||
|
- Создайте тестовый платеж и убедитесь, что ссылка открывается у пользователя.
|
||||||
|
- Проверьте входящий webhook: подпись и IP-allowlist должны соответствовать фактическому запросу Wata.
|
||||||
|
- Если платеж остается в pending, проверьте backend-логи вокруг webhook и статуса ссылки.
|
||||||
|
|
||||||
|
## Где подробнее
|
||||||
|
|
||||||
|
- [Переменные Wata](../configuration/env-vars.md#wata)
|
||||||
|
- [Настройка платежей](../features/payments.md)
|
||||||
|
- [Логи и диагностика](../troubleshooting/logs.md)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# YooKassa
|
||||||
|
|
||||||
|
YooKassa используется для рублевых оплат и может участвовать в сценариях автопродления period-подписок.
|
||||||
|
|
||||||
|
## Что настроить
|
||||||
|
|
||||||
|
- Включение провайдера: `YOOKASSA_ENABLED`.
|
||||||
|
- Идентификаторы и секреты магазина.
|
||||||
|
- Webhook URL на backend-домен.
|
||||||
|
- Отображение кнопки оплаты и порядок платежных методов.
|
||||||
|
|
||||||
|
## Где подробнее
|
||||||
|
|
||||||
|
- [Переменные YooKassa](../configuration/env-vars.md#yookassa)
|
||||||
|
- [Платежи](../features/payments.md)
|
||||||
|
- [Тарифы и автопродление](../features/tariffs.md#автопродление-пробный-период-и-бонусы)
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# Проблемы
|
||||||
|
|
||||||
|
Начинайте диагностику с состояния контейнеров и логов, затем проверяйте публичные URL и секреты.
|
||||||
|
|
||||||
|
## Стек не стартует
|
||||||
|
|
||||||
|
- Проверьте `docker compose ps`.
|
||||||
|
- Посмотрите `docker compose logs migrate`.
|
||||||
|
- Убедитесь, что PostgreSQL и Redis здоровы.
|
||||||
|
- Проверьте обязательные переменные в `.env`.
|
||||||
|
|
||||||
|
## Telegram webhook не работает
|
||||||
|
|
||||||
|
- Проверьте `WEBHOOK_BASE_URL`.
|
||||||
|
- Убедитесь, что домен доступен по HTTPS.
|
||||||
|
- Проверьте `WEBHOOK_SECRET_TOKEN`.
|
||||||
|
- Посмотрите backend-логи на момент входящего события.
|
||||||
|
|
||||||
|
## Mini App не открывается
|
||||||
|
|
||||||
|
- Проверьте `SUBSCRIPTION_MINI_APP_URL`.
|
||||||
|
- Убедитесь, что URL указывает на frontend, а не на `/api` или webhook-домен.
|
||||||
|
- Проверьте настройки BotFather.
|
||||||
|
- Посмотрите frontend и backend-логи.
|
||||||
|
|
||||||
|
## Платеж не засчитался
|
||||||
|
|
||||||
|
- Проверьте включение провайдера.
|
||||||
|
- Проверьте webhook URL и секреты.
|
||||||
|
- Посмотрите backend-логи.
|
||||||
|
- Сверьте статус платежа в админке и кабинете провайдера.
|
||||||
|
|
||||||
|
Подробности: [логи](logs.md) и [развертывание](../deployment.md).
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
# Логи
|
||||||
|
|
||||||
|
Логи - главный источник диагностики при проблемах запуска, платежей, вебхуков и синхронизации с Remnawave Panel.
|
||||||
|
|
||||||
|
## Основные команды
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose logs -f backend
|
||||||
|
docker compose logs -f worker
|
||||||
|
docker compose logs -f frontend
|
||||||
|
docker compose logs migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
## Что искать
|
||||||
|
|
||||||
|
- ошибки миграций в `migrate`;
|
||||||
|
- ошибки Telegram webhook и payment webhook в `backend`;
|
||||||
|
- проблемы очереди вебхуков и фоновых задач в `worker`;
|
||||||
|
- ошибки проксирования `/api`, `/auth` и theme assets во `frontend`;
|
||||||
|
- ошибки авторизации Mini App и Telegram OAuth.
|
||||||
|
|
||||||
|
## Frontend proxy, `/api`, `/auth` и theme assets
|
||||||
|
|
||||||
|
`frontend` - это nginx-контейнер Mini App. Он отдает статику и проксирует Web App маршруты во внутренний backend WebApp server на `backend:8081`.
|
||||||
|
|
||||||
|
Сначала смотрите nginx-логи:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose logs -f frontend
|
||||||
|
```
|
||||||
|
|
||||||
|
Если видите `404`, `502`, `upstream` или `connect() failed`, проверьте маршруты:
|
||||||
|
|
||||||
|
- `/api/*` и `/auth/*` должны попадать в `frontend:80`, а уже frontend проксирует их в `backend:8081`;
|
||||||
|
- `/webapp-logo`, `/webapp-uploaded-logo/*`, `/webapp-favicon/*`, `/webapp-theme-css/*` и `/webapp-theme-assets/*` тоже проксируются через frontend;
|
||||||
|
- внешний reverse proxy не должен отдельно уводить `/api` или `/auth` на webhook-сервер `backend:8080`.
|
||||||
|
|
||||||
|
Быстрые проверки снаружи:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -i https://app.domain.com/health
|
||||||
|
curl -i https://app.domain.com/api/bootstrap
|
||||||
|
curl -i https://app.domain.com/auth/telegram/start
|
||||||
|
curl -i https://app.domain.com/webapp-theme-css/dark/style.css
|
||||||
|
```
|
||||||
|
|
||||||
|
Если `/health` отвечает, а `/api/bootstrap` или theme assets падают, смотрите одновременно frontend и backend:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose logs -f frontend backend
|
||||||
|
```
|
||||||
|
|
||||||
|
Где проверять конфигурацию:
|
||||||
|
|
||||||
|
- frontend nginx: `deploy/docker/frontend/nginx.conf`;
|
||||||
|
- внешний Caddy/Nginx: `deploy/examples/caddy/Caddyfile` или `deploy/examples/nginx/nginx.conf.template`;
|
||||||
|
- Web App домен: `SUBSCRIPTION_MINI_APP_URL`, он должен быть публичным HTTPS URL frontend, без `/api`, `/auth` или webhook-пути;
|
||||||
|
- WebApp server backend: `WEBAPP_ENABLED=True`, `WEBAPP_SERVER_HOST=0.0.0.0`, `WEBAPP_SERVER_PORT=8081`.
|
||||||
|
|
||||||
|
## Mini App auth и Telegram OAuth
|
||||||
|
|
||||||
|
Ошибки авторизации почти всегда видны в `backend`, потому что проверка Telegram Mini Apps `initData`, Telegram OAuth `id_token`, nonce/state и сессий выполняется на backend WebApp server.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose logs -f backend
|
||||||
|
```
|
||||||
|
|
||||||
|
Ищите сообщения:
|
||||||
|
|
||||||
|
- `Telegram WebApp initData hash mismatch`;
|
||||||
|
- `Telegram WebApp initData auth_date is stale`;
|
||||||
|
- `Failed to validate Telegram WebApp initData`;
|
||||||
|
- `Telegram OAuth nonce mismatch`;
|
||||||
|
- `Telegram OAuth ID token is stale`;
|
||||||
|
- `Failed to validate Telegram OAuth ID token`;
|
||||||
|
- `Telegram OAuth token exchange failed`;
|
||||||
|
- `Telegram OAuth callback failed`;
|
||||||
|
- `WebApp auth failed`.
|
||||||
|
|
||||||
|
Для Mini App внутри Telegram проверьте:
|
||||||
|
|
||||||
|
- `SUBSCRIPTION_MINI_APP_URL` совпадает с доменом, указанным в BotFather Mini Apps;
|
||||||
|
- открывается именно HTTPS frontend-домен, а не backend webhook-домен;
|
||||||
|
- время на сервере синхронизировано, иначе `auth_date is stale`;
|
||||||
|
- `WEBAPP_AUTH_MAX_AGE_SECONDS` не слишком маленький;
|
||||||
|
- `WEBAPP_SESSION_SECRET` постоянный между рестартами.
|
||||||
|
|
||||||
|
Для Telegram OAuth вне Mini App проверьте:
|
||||||
|
|
||||||
|
- `TELEGRAM_OAUTH_CLIENT_ID` и `TELEGRAM_OAUTH_CLIENT_SECRET`;
|
||||||
|
- callback в Telegram OAuth/BotFather: `https://app.domain.com/auth/telegram/callback`;
|
||||||
|
- `/auth/telegram/start` и `/auth/telegram/callback` проходят через frontend nginx в `backend:8081`;
|
||||||
|
- в браузере после callback нет статуса `telegram_auth=invalid_state`, `invalid_token`, `not_configured`, `unauthorized` или `failed`.
|
||||||
|
|
||||||
|
Подробности по маршрутам и настройке OAuth: [Web App / Mini App](../features/web-app.md).
|
||||||
|
|
||||||
|
## После изменения конфигурации
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
docker compose logs -f backend worker frontend
|
||||||
|
```
|
||||||
|
|
||||||
|
См. также [проблемы](issues.md) и [развертывание](../deployment.md).
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
"""Pin facts that ``docs/migration-to-minishop.md`` and
|
"""Pin facts that ``docs/migrations/remnawave-tg-shop.md`` and
|
||||||
``scripts/migrate_to_minishop.sh`` rely on.
|
``scripts/migrate_to_minishop.sh`` rely on.
|
||||||
|
|
||||||
Both documents are written for a user upgrading from ``remnawave-tg-shop``
|
Both documents are written for a user upgrading from ``remnawave-tg-shop``
|
||||||
@@ -18,7 +18,7 @@ import unittest
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||||
DOC_PATH = REPO_ROOT / "docs" / "migration-to-minishop.md"
|
DOC_PATH = REPO_ROOT / "docs" / "migrations" / "remnawave-tg-shop.md"
|
||||||
SCRIPT_PATH = REPO_ROOT / "scripts" / "migrate_to_minishop.sh"
|
SCRIPT_PATH = REPO_ROOT / "scripts" / "migrate_to_minishop.sh"
|
||||||
COMPOSE_FILES = (
|
COMPOSE_FILES = (
|
||||||
REPO_ROOT / "docker-compose.yml",
|
REPO_ROOT / "docker-compose.yml",
|
||||||
@@ -64,14 +64,14 @@ class MigrationDocumentationFactsTests(unittest.TestCase):
|
|||||||
missing = sorted(name for name in EXPECTED_CONTAINER_NAMES if name not in self.doc)
|
missing = sorted(name for name in EXPECTED_CONTAINER_NAMES if name not in self.doc)
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
missing,
|
missing,
|
||||||
f"migration-to-minishop.md is missing container names from current compose: {missing}",
|
f"migrations/remnawave-tg-shop.md is missing container names from current compose: {missing}",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_doc_lists_every_volume_in_current_compose(self):
|
def test_doc_lists_every_volume_in_current_compose(self):
|
||||||
missing = sorted(name for name in EXPECTED_VOLUME_NAMES if name not in self.doc)
|
missing = sorted(name for name in EXPECTED_VOLUME_NAMES if name not in self.doc)
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
missing,
|
missing,
|
||||||
f"migration-to-minishop.md is missing volume names from current compose: {missing}",
|
f"migrations/remnawave-tg-shop.md is missing volume names from current compose: {missing}",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_doc_warns_about_renamed_telegram_webhook_secret(self):
|
def test_doc_warns_about_renamed_telegram_webhook_secret(self):
|
||||||
@@ -234,7 +234,7 @@ class DocComposeFileReferencesTests(unittest.TestCase):
|
|||||||
self.assertIn(relpath, doc)
|
self.assertIn(relpath, doc)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
(REPO_ROOT / relpath).is_file(),
|
(REPO_ROOT / relpath).is_file(),
|
||||||
f"{relpath} is referenced in migration-to-minishop.md but missing on disk",
|
f"{relpath} is referenced in migrations/remnawave-tg-shop.md but missing on disk",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_doc_references_migrator_module_path(self):
|
def test_doc_references_migrator_module_path(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user