# D1 Документирование готовности ядра Дата: 2026-03-02 Статус: in-progress Владелец: Engineering ## 1) Цель - Дать точный endpoint-level срез: что уже можно подключать в веб, что требует инфраструктурных условий, и где нужен отдельный UX-поток. - Зафиксировать критерии перехода к веб-прототипу на базе фактического кода `selective-vpn-api`. ## 2) Легенда статусов - `ready-read` — готово для веба как read endpoint. - `ready-write` — готово для веба как write endpoint, но обязательно через auth/rbac/audit/proxy. - `ready-async` — write endpoint готов, но требуется async UX (SSE progress/polling). - `ready-interactive` — endpoint готов, но требует интерактивного flow (session state/action). ## 3) Глобальные условия для веба - API должен ходить через proxy (unix socket + nginx/systemd socket) и не быть публично открыт напрямую на `127.0.0.1:8080`. - Для всех mutating endpoints обязательны auth/rbac и аудит вызовов. - Для SSE (`/api/v1/events/stream`) нужен корректный proxy режим (`proxy_buffering off`). - Для async операций (`routes update`, `smartdns prewarm`, `dns benchmark`) веб должен слушать SSE/статусы и блокировать повторные конкурирующие действия. - Архитектурный инвариант: один контракт `/api/v1` для `web + iOS + Android`, без платформенных форков backend-логики. ## 4) Матрица endpoint -> web-ready | Endpoint | Method | Handler | Статус | Комментарий для веба | | --- | --- | --- | --- | --- | | `/healthz` | GET | `handleHealthz` | `ready-read` | Базовый liveness probe. | | `/api/v1/events/stream` | GET | `handleEventsStream` | `ready-read` | SSE source для realtime UI. | | `/api/v1/status` | GET | `handleGetStatus` | `ready-read` | Карточка статуса маршрутов. | | `/api/v1/routes/status` | GET | `handleGetStatus` | `ready-read` | Алиас статуса. | | `/api/v1/vpn/login-state` | GET | `handleVPNLoginState` | `ready-read` | Текущий state логина VPN. | | `/api/v1/systemd/state` | GET | `handleSystemdState` | `ready-read` | Проверка unit state по query `unit`. | | `/api/v1/routes/service/start` | POST | `makeRoutesServiceActionHandler("start")` | `ready-write` | Чувствительная операция systemd. | | `/api/v1/routes/service/stop` | POST | `makeRoutesServiceActionHandler("stop")` | `ready-write` | Чувствительная операция systemd. | | `/api/v1/routes/service/restart` | POST | `makeRoutesServiceActionHandler("restart")` | `ready-write` | Чувствительная операция systemd. | | `/api/v1/routes/service` | POST | `handleRoutesService` | `ready-write` | Универсальный action endpoint. | | `/api/v1/routes/update` | POST | `handleRoutesUpdate` | `ready-async` | Запуск async job; прогресс через SSE/events. | | `/api/v1/routes/timer` | GET/POST | `handleRoutesTimer` | `ready-write` | GET состояние, POST переключение. | | `/api/v1/routes/timer/toggle` | POST | `handleRoutesTimerToggle` | `ready-write` | Legacy toggle для совместимости. | | `/api/v1/routes/rollback` | POST | `handleRoutesClear` | `ready-write` | Очистка nft/routes с риском влияния на трафик. | | `/api/v1/routes/clear` | POST | `handleRoutesClear` | `ready-write` | Алиас rollback. | | `/api/v1/routes/cache/restore` | POST | `handleRoutesCacheRestore` | `ready-write` | Восстановление из clear-cache. | | `/api/v1/routes/precheck/debug` | POST | `handleRoutesPrecheckDebug` | `ready-async` | Debug flow + опциональный async restart. | | `/api/v1/routes/fix-policy-route` | POST | `handleFixPolicyRoute` | `ready-write` | Ремонт policy route по status.json. | | `/api/v1/routes/fix-policy` | POST | `handleFixPolicyRoute` | `ready-write` | Алиас fix-policy-route. | | `/api/v1/traffic/mode` | GET/POST | `handleTrafficMode` | `ready-write` | Ключевой control-plane endpoint. | | `/api/v1/traffic/mode/test` | GET/POST | `handleTrafficModeTest` | `ready-read` | Проверка health/probe для UI. | | `/api/v1/traffic/advanced/reset` | POST | `handleTrafficAdvancedReset` | `ready-write` | Сброс advanced bypass state. | | `/api/v1/traffic/interfaces` | GET | `handleTrafficInterfaces` | `ready-read` | Список интерфейсов и active iface. | | `/api/v1/traffic/candidates` | GET | `handleTrafficCandidates` | `ready-read` | Подсказки subnet/unit/uid. | | `/api/v1/traffic/appmarks` | GET/POST | `handleTrafficAppMarks` | `ready-write` | Runtime app marking, требует RBAC. | | `/api/v1/traffic/appmarks/items` | GET | `handleTrafficAppMarksItems` | `ready-read` | Список текущих runtime marks. | | `/api/v1/traffic/app-profiles` | GET/POST/DELETE | `handleTrafficAppProfiles` | `ready-write` | CRUD профилей приложений. | | `/api/v1/traffic/audit` | GET | `handleTrafficAudit` | `ready-read` | Sanity-check и issues report. | | `/api/v1/trace` | GET | `handleTraceTailPlain` | `ready-read` | Plain tail trace. | | `/api/v1/trace-json` | GET | `handleTraceJSON` | `ready-read` | Structured trace view. | | `/api/v1/trace/append` | POST | `handleTraceAppend` | `ready-write` | Write в trace; ограничить доступ и размер body. | | `/api/v1/dns-upstreams` | GET/POST | `handleDNSUpstreams` | `ready-write` | Конфиг upstreams. | | `/api/v1/dns/upstream-pool` | GET/POST | `handleDNSUpstreamPool` | `ready-write` | Конфиг pool. | | `/api/v1/dns/status` | GET | `handleDNSStatus` | `ready-read` | Состояние DNS mode/runtime. | | `/api/v1/dns/mode` | POST | `handleDNSModeSet` | `ready-write` | Переключение DNS resolver mode. | | `/api/v1/dns/benchmark` | POST | `handleDNSBenchmark` | `ready-async` | Долгий бенчмарк; нужен UX ожидания. | | `/api/v1/dns/smartdns-service` | POST | `handleDNSSmartdnsService` | `ready-write` | Start/stop/restart smartdns unit. | | `/api/v1/smartdns/service` | GET/POST | `handleSmartdnsService` | `ready-write` | GET state + POST action. | | `/api/v1/smartdns/runtime` | GET/POST | `handleSmartdnsRuntime` | `ready-write` | Runtime nftset hook toggle. | | `/api/v1/smartdns/prewarm` | POST | `handleSmartdnsPrewarm` | `ready-async` | Потенциально долгий prewarm. | | `/api/v1/domains/table` | GET | `handleDomainsTable` | `ready-read` | Таблица nft/ipset dump. | | `/api/v1/domains/file` | GET/POST | `handleDomainsFile` | `ready-write` | File-backed editor; нужен ACL по name. | | `/api/v1/smartdns/wildcards` | GET/POST | `handleSmartdnsWildcards` | `ready-write` | CRUD wildcard list. | | `/api/v1/vpn/autoloop-status` | GET | `handleVPNAutoloopStatus` | `ready-read` | Статус autoloop parser. | | `/api/v1/vpn/status` | GET | `handleVPNStatus` | `ready-read` | VPN state + unit state. | | `/api/v1/vpn/autoconnect` | POST | `handleVPNAutoconnect` | `ready-write` | Управление adgvpn unit. | | `/api/v1/vpn/locations` | GET | `handleVPNListLocations` | `ready-read` | Список location options. | | `/api/v1/vpn/location` | POST | `handleVPNSetLocation` | `ready-write` | Смена desired location + unit restart. | | `/api/v1/vpn/login/session/start` | POST | `handleVPNLoginSessionStart` | `ready-interactive` | Старт интерактивной PTY login session. | | `/api/v1/vpn/login/session/state` | GET | `handleVPNLoginSessionState` | `ready-interactive` | Poll состояния и линий с `since`. | | `/api/v1/vpn/login/session/action` | POST | `handleVPNLoginSessionAction` | `ready-interactive` | Команды open/check/cancel. | | `/api/v1/vpn/login/session/stop` | POST | `handleVPNLoginSessionStop` | `ready-interactive` | Cleanup/stop interactive session. | | `/api/v1/vpn/logout` | POST | `handleVPNLogout` | `ready-write` | Logout + refresh login state. | ## 5) Скриптовые smoke-тесты - `tests/api_sanity.sh` — read endpoints + method guard + SSE headers. - `tests/trace_append.sh` — append + readback (`/trace`, `/trace-json`). - `tests/events_stream.py` — SSE stream + активный триггер `trace_append`. - `tests/vpn_login_flow.py` — start/state/action/stop для login session. - `tests/transport_flow_smoke.py` — API-flow `draft/validate/confirm/apply/rollback` для transport policy. - `tests/transport_platform_compatibility_smoke.py` — проверка кроссплатформенного transport-контракта (`web/iOS/Android`) через capabilities + policy endpoints. - `tests/transport_runbook_cli_smoke.sh` — smoke операционного runbook helper (`scripts/transport_runbook.py`) по lifecycle transport-клиента. - `tests/transport_recovery_runbook_smoke.sh` — smoke recovery runbook (`scripts/transport_recovery_runbook.py`) для сценария `health->restart->fallback->diagnostics`. - `tests/transport_systemd_real_e2e.py` — real-systemd e2e для `singbox/dnstt(+ssh)/phoenix` + проверка cleanup unit artifacts. - `tests/transport_production_like_e2e.py` — production-like e2e для template-команд и `packaging_profile=bundled` на `systemd` backend. - `tests/transport_singbox_e2e.py` — backend-first e2e для `singbox` lifecycle/guards. - `tests/transport_dnstt_e2e.py` — backend-first e2e для `dnstt` lifecycle/guards (`ssh overlay`, template checks). - `tests/transport_phoenix_e2e.py` — backend-first e2e для `phoenix` lifecycle/guards. - `tests/run_all.sh` — общий запуск набора. ## 6) Факт прогона (2026-03-02) - Команда: `API_URL=http://127.0.0.1:8080 ./tests/run_all.sh`. - Результат: `api_sanity`, `trace_append`, `events_stream`, `vpn_login_flow` — `passed`. - Дополнение (2026-03-07): - Расширенный `run_all` с transport smoke/e2e и packaging smoke проходит `passed`; - включён и проходит `tests/transport_platform_compatibility_smoke.py` (capabilities + policy contract); - при запуске старого backend-процесса `transport_*_e2e` могут завершаться `SKIP` (без `provision/metrics`); - после пересборки и перезапуска `selective-vpn-api` из текущего кода `transport_singbox_e2e`, `transport_dnstt_e2e`, `transport_phoenix_e2e` прошли без `SKIP`. - в `run_all` включены и проходят `transport_systemd_real_e2e` + `transport_production_like_e2e` (template-commands + packaging profile checks на `runner=systemd`). ## 7) Вывод для веб-прототипа - Срез по legacy-матрице (53 endpoint из Phase D): - `ready-read`: 18 - `ready-write`: 27 - `ready-async`: 4 - `ready-interactive`: 4 - Дополнение 2026-03-07: - В ядро добавлены `8` базовых mux-route `/api/v1/transport/*` + action-subpath `GET /api/v1/transport/clients/{id}/metrics` (контракт D4.1). - Их контракт и rollout описаны в `docs/phase-e/E2_TRANSPORT_API_CONTRACT.md`. - По API-ядру нет endpoint, который блокирует веб-прототип на уровне контракта. - Ограничения не в ручках, а в обвязке: auth/rbac, proxy/CORS/CSRF, и UX для async/interactive сценариев. - Практический старт веба можно делать сразу: read панели + write действия под admin scope + SSE realtime слой. ## 8) Условия переиспользования для смартфонов (iOS/Android) - Серверная обвязка: - gateway/proxy с TLS и токен-авторизацией; - refresh/access токены и управление device sessions; - аудит и rate-limit для mutating endpoints. - Контракт: - стабильные DTO и error contract (`ok`, `message`, `exitCode`, `stderr`); - versioning через `/api/v1` и backward-compatible изменения. - Realtime и фоновые ограничения: - веб использует SSE постоянно; - mobile использует SSE в foreground и polling fallback в background. - Надежность мобильной сети: - idempotency key для POST операций; - retry policy с экспоненциальной паузой; - correlation id для трассировки запросов. - Безопасность клиента: - iOS Keychain / Android Keystore для токенов; - certificate pinning для production приложений. ## 9) D3: Последовательность запуска multi-client - D3.1: Завершить gateway/auth слой (TLS, токены, RBAC, audit). - D3.2: Подключить web-клиент к уже готовой матрице endpoint и SSE. - D3.3: Ввести mobile transport profile (polling fallback + retry/idempotency). - D3.4: Запустить iOS/Android клиенты на том же `/api/v1` без изменения бизнес-логики ядра. ## 10) D4: Transport Integration Backlog - D4.1 `sing-box client`: - Роль: универсальный клиент-транспорт для сценариев proxy/tun. - Требование к ядру: запуск/остановка/health через backend-адаптер, без переноса логики в UI. - Статус: `in-progress` (2026-03-07: в API введён минимальный общий backend-контракт lifecycle/health/metrics/errors, добавлен `GET /api/v1/transport/clients/{id}/metrics`). - E2E шаг (backend-first): `tests/transport_singbox_e2e.py`: - проверяет успешный lifecycle на `runner=mock` (`provision/start/health/restart/stop/metrics`); - проверяет guard `runtime_mode=embedded` -> `TRANSPORT_BACKEND_RUNTIME_MODE_UNSUPPORTED`; - проверяет fail-fast `require_binary=true` для отсутствующего `singbox_bin`. - Примечание: если в рантайме запущен старый процесс API без `provision/metrics`, тест завершится `SKIP`; для полного прогона нужен перезапуск backend из актуального кода. - D4.2 `dnstt-client`: - Роль: отдельный клиент для DNSTT-протокола (как самостоятельный backend). - Требование к ядру: управление lifecycle + состояние/ошибки через общий API слой. - Уточнение: поддержать режим `dnstt + ssh overlay` (туннель поверх SSH как единая система, аналогично phoenix UX-модели). - Статус: `in-progress` (2026-03-07: в Go добавлены adapter foundation, `POST /api/v1/transport/clients/{id}/provision`, template-команды запуска, systemd restart/watchdog tuning, unit hardening-профили, `runtime_mode` foundation `exec|embedded|sidecar`, packaging profiles (`system|bundled`) и manual pinned updater/rollback scripts; `config.exec_start` работает как optional override). - E2E шаг (backend-first): `tests/transport_dnstt_e2e.py`: - проверяет успешный lifecycle на `runner=mock`; - проверяет guard `ssh_overlay` конфигурации (`ssh_host` обязателен, `ssh_unit` валидируется); - проверяет template-валидацию DNSTT при неполном config. - Примечание: как и для singbox, при старом API-процессе без `provision` тест завершится `SKIP`; нужен перезапуск backend из текущего кода. - D4.3 `phoenix -> slipstream`: - Роль: отдельный backend-клиент для подключения к удаленному `slipstream` серверу. - Требование к ядру: конфиг/статус/управление сессией через backend-адаптер и общий контракт. - Статус: `in-progress` (2026-03-07: добавлен backend-first e2e тест `tests/transport_phoenix_e2e.py` для lifecycle/guards на API-контракте). - E2E шаг (backend-first): `tests/transport_phoenix_e2e.py`: - проверяет успешный lifecycle на `runner=mock` (`provision/start/health/restart/stop/metrics`); - проверяет guard `runtime_mode=embedded` -> `TRANSPORT_BACKEND_RUNTIME_MODE_UNSUPPORTED`; - проверяет fail-fast `require_binary=true` для отсутствующего `phoenix_bin`. - Примечание: при старом API-процессе без `provision/metrics` тест завершится `SKIP`; для полного прогона нужен перезапуск backend из актуального кода. - D4.4 Общий инвариант: - Для `web + iOS + Android` UI не знает о внутренней реализации backend-клиента; он работает с единым API ядра. - Все transport-backend различия прячутся в Go-слое (feature flags, capability matrix, unified error contract). ## 11) D4.3: Матрица совместимости web + iOS + Android - Отдельный артефакт: `docs/phase-d/D4_PLATFORM_COMPATIBILITY_MATRIX.md`. - Зафиксировано: - единый control-plane контракт `/api/v1` для всех платформ; - transport-runtime работает только в backend (`exec`), UI работает через capabilities/policies flow; - mobile использует тот же API, с fallback `polling` при недоступном SSE в background.