platform: modularize api/gui, add docs-tests-web foundation, and refresh root config

This commit is contained in:
beckline
2026-03-26 22:40:54 +03:00
parent 0e2d7f61ea
commit 6a56d734c2
562 changed files with 70151 additions and 16423 deletions

View File

@@ -0,0 +1,72 @@
# C1 Подготовка ядра к веб-совместимости
Дата: 2026-02-27
Статус: draft
Владелец: Engineering
## 1) Цель
- Зафиксировать, какие компоненты Go-ядра уже готовы к внешнему доступу (SSE, REST, локальный API) и что нужно изменить/документировать для будущего веб-прототипа.
- Убедиться, что веб-интерфейс сможет работать с ядром через ожидаемые договоренности (binding, CORS, авторизация, long-polling/SSE).
- Зафиксировать архитектурный принцип повторного использования одного API-контракта для `web + iOS + Android`, без форков бизнес-логики по платформам.
- Выбор UI-стека вынесен в `docs/phase-c/C2_WEB_STACK_DECISION.md` (принято: `Vite + React + TypeScript` для MVP).
## 2) Критерии завершения
- Описан binding (`127.0.0.1:8080`), механизм SSE (`/api/v1/events/stream`), стандартные ответы (e.g. `CmdResult`, dataclasses) и авторизация через `vpn_login_session`.
- Зафиксированы необходимые изменения инфраструктуры (proxy/unix socket, CORS/CSRF, дополнительная аутентификация или токены).
- Собраны критические endpointы для веба (routes service/update/rollback, traffic mode/appmarks/profiles, DNS/SmartDNS, VPN, trace) и их характеристики (async операции, payload, ответы).
- Для мобильных клиентов описаны условия transport/auth/retry (TLS, токены, refresh, polling fallback к SSE, device session control).
## 3) Задачи
- Подтвердить, что SSE поток (`events/stream`) предоставляет status/login/trace/autoloop updates и определить, какие события нужно визуализировать (policy route, unit state, autoloop, SmartDNS, routes progress).
- Задокументировать payload/методы/JSON форматы для ключевых endpointов (`routes/service`, `routes/update`, `traffic/mode`, `dns/benchmark`, `smartdns/prewarm`, `vpn/login/session`), чтобы новый фронт мог повторить вызовы.
- Определить ограничения текущего binding (`127.0.0.1:8080`) и описать безопасный путь для проксирования (unix socket + nginx/systemd socket/reverse proxy).
- Проработать механизм авторизации: как web UI вызывает `/api/v1/vpn/login/session/start`, получает `login_state`, делает action, и как `/api/v1/auth/status`/`login/session/state` поддерживают health.
- Уточнить, какие операции требуют async-статуса (например, `routes update`, `routes/service restart`) и как отображать прогресс (SSE event `routes_nft_progress`, `status_changed`).
- Задокументировать headers/CORS (`allowed origin`, `Authorization`, `Content-Type`, `X-Requested-With`, `GET/POST`) и сценарии CSRF/preflight при использовании cookie.
- Утвердить единый API-versioning подход (`/api/v1`) и правила обратной совместимости для всех клиентов (веб и мобильных).
- Зафиксировать контракт ошибок (`ok`, `message`, `exitCode`, `stderr`) и политику idempotency/retry для мобильных сетевых условий.
## 4) SSE, watchers, trace
- `events_bus.go` собирает события `{ID, Kind, Ts, Data}` и поддерживает replay по `Last-Event-ID`/`since`. Web должен подписаться на `status_changed`, `login_state_changed`, `routes_nft_progress`, `unit_state_changed`, `autoloop_status_changed` и восстанавливать соединение при reconnect.
- `watchers.go` poll-ит `status.json`, `login_state.json`, `trace.log`, `autoloop.log`, state traffic appmarks TTL и systemd unitы (`routes_service`, `routes_timer`, `vpn_unit`, `smartdns_unit`). Эти события идут в SSE и дают realtime-статус на UI (health, trace, unit status).
- `trace_handlers.go` предоставляет `GET /api/v1/trace` (tail), `/trace-json` (structured), `/trace/append`. Убедиться, что web ограничивает JSON size (1<<20) и отображает `CmdResult` (stdout/stderr) при append.
- Нужно описать, какие watcher-события и trace-последствия критичны для UI (policy route check, SmartDNS runtime, traffic appmarks TTL) и как SSE clients обрабатывают disconnect/replay.
## 5) Проксирование и безопасность
- API должен быть доступен через безопасный proxy (unix socket + nginx, systemd socket или reverse proxy) и/или на изолированном интерфейсе, чтобы не экспонировать `127.0.0.1:8080` наружу.
- Proxy configuration:
- Systemd socket unit (`selective-vpn-api.socket`) слушает `/run/selective-vpn.sock`; nginx проксирует `location /api/``proxy_pass http://unix:/run/selective-vpn.sock:`.
- В nginx включаете `proxy_buffering off`, `proxy_http_version 1.1`, `proxy_set_header Connection keep-alive`, `proxy_set_header Host $host`, `proxy_set_header X-Real-IP $remote_addr`, чтобы SSE `/api/v1/events/stream` работал без задержек.
- Альтернатива — nginx на localhost:8080 с firewall, разрешающий соединения только от веб-интерфейса; при этом добавляется `allow 127.0.0.1` и `deny all`.
- CORS/CSRF:
- `Access-Control-Allow-Origin: https://selective-ui.local` (или переменная окружения). `Access-Control-Allow-Credentials: true` при использовании cookie.
- `Access-Control-Allow-Headers: Authorization, Content-Type, X-Requested-With`, `Access-Control-Allow-Methods: GET, POST`, `Access-Control-Expose-Headers: X-Request-Id`.
- Preflight (`OPTIONS`) обрабатывается proxy (nginx) или Go кодом, возвращая нужные заголовки и `204`.
- Авторизация:
- Web UI вызывает `POST /api/v1/vpn/login/session/start`, backend пишет `login_state.json` и возвращает `LoginState` (включая `state`/`msg`/`email`).
- Web сохраняет `login_state_id`, прикладывает его как `Authorization: Bearer $login_state_id` либо использует session cookie от proxy. Go middleware проверяет токен перед вызовом критичных endpointов.
- `/api/v1/auth/status` (или расширение `/api/v1/vpn/login/session/state`) сообщают, активна ли сессия; если нет, UI перенаправляет пользователя к login modal.
- `CmdResult` с `ok=false`, SSE `login_state_changed` или события `status_error` должна отображаться как alert и давать кнопку retry.
- Async операции и прогресс:
- `routes update` и `routes/service restart` занимают до 60 секунд. Web запускает POST `/api/v1/routes/update`, включает бесперебойный SSE и показывает progress bar, пока не придёт `CmdResult.ok=true` + event `routes_nft_progress`/`status_changed`.
- `dns/benchmark`, `smartdns/prewarm` и `traffic/mode/test` тоже могут длиться минуты — UI ожидает SSE `progress`/`status` и отключает повторные вызовы до завершения.
- Trace append (`/api/v1/trace/append`) возвращает `CmdResult`; UI показывает `stderr`/`exitCode` и ограничивает длину payload (<=1<<20).
## 6) Кросс-платформенная переиспользуемость (Web + iOS + Android)
- Backend-слой остается единым: бизнес-логика только в Go-ядре, клиенты используют одинаковые endpointы и payload-контракты.
- DTO/модели (`Status`, `CmdResult`, `TrafficModeStatus`, `LoginState`, `TrafficAppMarkItem`) считаются каноничными; изменение полей только с backward-compatible стратегией.
- Реaltime:
- Web: SSE как основной канал.
- Mobile: SSE при активном приложении + fallback polling для background/нестабильной сети.
- Авторизация:
- Веб-клиент может использовать cookie/token через proxy.
- Мобильные клиенты используют bearer access token + refresh token, хранят секреты в secure storage (iOS Keychain / Android Keystore).
- Надежность:
- Для mutating POST операций вводить `Idempotency-Key`, чтобы избежать дублей при ретраях на мобильной сети.
- Добавить request correlation (`X-Request-Id`) в ответы/логи для расследования инцидентов на всех клиентах.
- Транспорт:
- Только HTTPS, поддержка certificate pinning для мобильных приложений.
- Никаких прямых подключений к `127.0.0.1:8080` с клиентов; только через контролируемый gateway/proxy.
- Transport backends:
- Поддержать модель pluggable backend-клиентов (`sing-box`, `dnstt-client`, `phoenix->slipstream`) с единым API-контрактом ядра.
- UI-слой (web/iOS/Android) не должен зависеть от конкретного transport backend; различия покрываются capability endpoint/матрицей в Go.

View File

@@ -0,0 +1,37 @@
# C2 Решение по стеку web prototype
Дата: 2026-03-07
Статус: approved
Владелец: Engineering
## 1) Принятое решение
- Для web prototype используется `Vite + React + TypeScript` (SPA).
- Бэкенд-ядро остаётся в Go (`/api/v1` + SSE `/api/v1/events/stream`).
- `Next.js` на MVP-этапе не используется.
## 2) Почему так
- В проекте уже есть готовый Go API-контракт; отдельный Node/SSR-слой не обязателен.
- Цель текущего этапа: рабочая control-plane панель, а не SEO-публичный сайт.
- `Vite` даёт быстрый старт, простой билд и минимальные операционные риски.
## 3) Базовый frontend stack
- `react` + `typescript`
- `vite`
- `react-router`
- `@tanstack/react-query` для REST
- `EventSource` (SSE) для realtime
- lightweight UI state (например, `zustand`) только для локального состояния интерфейса
## 4) Когда рассматривать переход на Next.js
- Появляется требование SSR/SEO.
- Нужен встроенный BFF/edge middleware в самом фронтенд-проекте.
- Требуется server-side session orchestration, которую нецелесообразно держать в Go gateway.
## 5) Архитектурный инвариант
- Независимо от UI-фреймворка, источник истины остаётся в Go-ядре.
- UI не дублирует бизнес-логику маршрутизации/transport/policy.
- Контракт для web/iOS/Android остаётся единым: `/api/v1`.
## 6) Статус внедрения
- Создан модуль `selective-vpn-web/` (foundation level).
- На текущем этапе включены read-only проверки и SSE connectivity; mutating controls будут подключаться по фазам P1/E4.