Files
netrunner-landing/README.md
T
nineap 5f9d607d07 Обновить dev ACCOUNT_ORIGIN/API_URL под Caddy на 443 вместо 8443
netrunner-backend dev теперь проксирует Caddy на стандартный порт 443
(VPN-нода, ранее занимавшая его, перенесена на другой порт) — Telegram
Login Widget в браузере требует именно этот порт.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 20:00:15 +07:00

114 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Netrunner VPN — Landing
Промо-сайт и мини-платформа VPN-сервиса «Netrunner»: Next.js 16 (App Router) фронтенд
с двумя языками (en/ru), PocketBase в роли headless CMS и два самописных Rust-сервиса —
WebAssembly-движок анимированного фона «матрицы» и WebSocket/HTTP-шлюз с AI-модерацией
и speedtest-эндпоинтами.
## Стек
- **Next.js 16** (App Router, React 19, Server Components) + **TailwindCSS 4**
- **PocketBase** — headless CMS/БД для блога, FAQ, ссылок на загрузки и гостевой книги
- **Rust → WebAssembly** (`matrix-engine/`) — физика фоновой анимации, рендер через WebGL2 в Web Worker
- **Rust / Axum** (`proxy-ws/`) — прокси-шлюз: ONNX-модель токсичности для фильтрации сообщений + генератор нагрузки для speedtest
- **Docker Compose** — три контейнера в проде: `landing`, `netrunner-cms` (PocketBase), `ws-proxy`
## Структура репозитория
```
app/[lang]/ Страницы Next.js (App Router), маршруты локализованы через /en/* и /ru/*
components/sections/ Крупные блоки страниц (Hero, Pricing, Terminal-гостевая книга и т.д.)
components/ui/ 低-уровневые UI-примитивы (shadcn/radix обвязка)
lib/ Общие утилиты: клиент PocketBase, загрузчик словарей, типы
dictionaries/ JSON со строками локализации (en.json / ru.json)
matrix-engine/ Rust/WASM-движок фонового "дождя из матрицы" + его README
proxy-ws/ Rust/Axum-шлюз: AI-модерация комментариев и speedtest + его README
public/wasm-matrix/ Скомпилированный вывод matrix-engine, который реально грузит браузер
public/games/doom.zip Пасхалка — DOOM в браузере на /doom
proxy.ts Next.js "proxy" (аналог middleware) — определение и редирект локали
```
Подробности по Rust-подсистемам — в их собственных README:
[matrix-engine/README.md](matrix-engine/README.md) и [proxy-ws/README.md](proxy-ws/README.md).
Подробности по фронтенду — в [app/README.md](app/README.md), [components/README.md](components/README.md)
и [lib/README.md](lib/README.md).
## Как это работает вместе
1. Next.js middleware (`proxy.ts`) на каждый запрос без `/en` или `/ru` в пути определяет
язык браузера (`Negotiator` + `@formatjs/intl-localematcher`) и редиректит на `/{locale}/...`.
`/doom`, `/doom.html` и `/games/*` из этой логики специально исключены.
2. Серверные страницы в `app/[lang]/...` подгружают словарь (`lib/dictionaries.ts`) и контент
из PocketBase (`lib/pb.ts`) — блог, FAQ, ссылки на загрузки и т.п.
3. Фоновая WebGL-анимация (`matrix-engine`) инициализируется клиентским компонентом
`NetrunnerMatrix` — она работает в отдельном Web Worker поверх `OffscreenCanvas`,
не блокируя основной поток.
4. Гостевая книга (`components/sections/TerminalGuestbook.tsx`) отправляет сообщения не
напрямую в PocketBase, а через `/api/proxy/*` (rewrite в `next.config.ts` на `ws-proxy:3001`).
Rust-шлюз прогоняет никнейм и текст через ONNX-классификатор токсичности и только потом
пишет запись в PocketBase.
5. Спидтест (`components/sections/SpeedtestClient.tsx`, страница `/speedtest`) бьёт напрямую
в `ws-proxy` за `/api/speedtest/ping|download|upload`.
## Разработка
```bash
pnpm install
# WASM-движок собирается отдельно (нужен Rust + wasm-pack), результат кладётся в public/wasm-matrix
./build-wasm.sh
pnpm dev
```
Открыть [http://localhost:3000](http://localhost:3000) — редиректнёт на `/en` или `/ru` по языку браузера.
Полезные переменные окружения (`.env.local`):
| Переменная | Назначение |
|---|---|
| `NEXT_PUBLIC_PB_URL` | Публичный URL PocketBase (используется в браузере) |
| `PB_INTERNAL_URL` | Внутренний URL PocketBase для SSR (обычно `http://netrunner-cms:8090` в докере) |
| `NEXT_PUBLIC_PROXY_URL` | Публичный URL Rust-шлюза (для клиентских fetch, минуя rewrite) |
| `NEXT_PUBLIC_API_URL` | База API бэкенда (`netrunner-backend`) для auth-эндпоинтов — `/users/me`, `/auth/telegram`. По умолчанию `${NEXT_PUBLIC_ACCOUNT_ORIGIN}/api/v1` |
| `NEXT_PUBLIC_ACCOUNT_ORIGIN` | Origin ЛК (`netrunner-backend`, сабдомен `account.*`) — куда редиректить после успешного логина |
| `NEXT_PUBLIC_BOT_USERNAME` | Юзернейм Telegram-бота для виджета логина |
| `PB_ADMIN_EMAIL` / `PB_ADMIN_PASS` | Только для одноразового скрипта `upload.mjs` (сид данных в PocketBase) |
## Сборка и деплой
- `Dockerfile` — многостадийная сборка: сначала компилирует `matrix-engine` в WASM
(`wasm-pack build --target web --release`), кладёт результат в `public/wasm-matrix`,
затем собирает Next.js и упаковывает в минимальный `node:20-alpine` рантайм.
- `proxy-ws/Dockerfile` — отдельный образ Rust-шлюза (кэширует зависимости через
BuildKit cache mounts, чтобы не пересобирать crates на каждый билд).
- `docker-compose.yml` — прод: поднимает три сервиса: `landing`, `netrunner-cms`
(PocketBase) и `ws-proxy`, все в одной bridge-сети `netrunner-network`.
- `docker-compose.dev-remote.yml` — dev: тот же набор сервисов на отдельном dev VPS
(по аналогии с `netrunner-backend`, тот же хост — `45.76.161.137` / DNS
`dev.netrunner-vpn.com`), сам лендинг без reverse-proxy (порт `3000` открыт
напрямую, обычный HTTP), но смотрит на dev-бэкенд уже через Caddy на
`https://dev.netrunner-vpn.com` (порт 443, не голый `:8080`) — у
`netrunner-backend` там настоящий TLS, нужный и для Telegram Web Apps (кнопки
бота) и Secure-cookie, и для Telegram Login Widget (требует в браузере именно
порт 443).
Домен, а не IP: Telegram Login Widget требует настоящий домен, зарегистрированный
в BotFather под отдельным dev-ботом (`BOT_USERNAME` для этого стека —
обязательная переменная, без дефолта на прод-бота, см. комментарии в файле).
- `.github/workflows/build.yml` — на пуш в `main` (и вручную) собирает и пушит оба
образа (`netrunner-landing`, `netrunner-landing-proxy`) в GHCR.
- `.github/workflows/deploy.yml` — две джобы: `deploy-dev` срабатывает автоматически
сразу после `build.yml` и обновляет dev VPS (`docker-compose.dev-remote.yml`);
`deploy-prod` — только вручную (Actions → Run workflow), обновляет прод
(`docker-compose.yml`). Секреты: `VPS_IP`/`SSH_PRIVATE_KEY` (прод),
`DEV_VPS_IP`/`DEV_SSH_PRIVATE_KEY` (dev) — заводятся в Settings → Secrets репозитория.
- `deploy.sh` — тот же процесс вручную для прода, для локального запуска без ожидания CI.
- `ecosystem.config.js` — конфиг PM2, альтернативный способ запускать `next start`
без Docker (используется, если сервис поднимается процесс-менеджером на самом VPS).
Разовые dev-утилиты **не являются частью приложения** и не запускаются в проде:
- `collect_code.js` — сбрасывает все `.ts/.tsx` файлы из `app/`, `components/`, `lib/`
в один текстовый файл (удобно для передачи контекста в LLM).
- `upload.mjs` — одноразовый скрипт сидирования коллекций `downloads_en`/`downloads_ru`
в PocketBase тестовыми данными.