Files
elmprodvpn/docs/phase-d/D1_GO_READINESS_DOCS.md

185 lines
18 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.
# 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.