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,188 @@
# E1 Дизайн multi-client маршрутизации (PBR)
Дата: 2026-03-04
Статус: draft
Владелец: Engineering
## 1) Цель
- Спроектировать расширение текущего ядра так, чтобы несколько transport-клиентов (`sing-box`, `dnstt-client`, `phoenix->slipstream`) работали под единым control-plane API.
- Сохранить один источник истины для маршрутизации: только Go-ядро управляет PBR/nft/ip rule, UI только вызывает API.
- Обеспечить безопасную многоклиентную схему без конфликтов: один трафик/сайт не должен одновременно идти через два интерфейса.
## 2) Текущий baseline (по коду)
- Сейчас модель маршрутизации бинарная: `vpn|direct` + глобальные `MARK`/`MARK_APP`/`MARK_DIRECT`/`MARK_INGRESS`.
- Runtime app routing хранится в `traffic-appmarks.json`, persistent launcher-профили в `traffic-app-profiles.json`.
- Центр оркестрации: `traffic_mode.go`, `traffic_appmarks.go`, `routes_update.go`.
- Ограничение: нет сущности "клиент-транспорт" как объекта с собственным iface/table/mark.
## 3) Архитектурный инвариант
- `PBR Engine` в Go-ядре остается единственным writer для:
- `ip rule`,
- `ip route table`,
- `nft chains/sets/rules`,
- `conntrack mark policy`.
- Transport backends (sing-box/dnstt/phoenix) подключаются через backend-адаптеры и не пишут маршруты напрямую.
- UI (desktop/web/iOS/android) оперирует одинаковым API-контрактом, не знает о внутреннем устройстве backend-клиентов.
## 4) Целевая модель данных
### 4.1 TransportClient
- `id`: стабильный ключ (`sb-main`, `dnstt-home`, `phoenix-eu`).
- `kind`: `singbox | dnstt | phoenix`.
- `enabled`: bool.
- `status`: `starting | up | degraded | down`.
- `iface`: фактический интерфейс/туннель.
- `routing_table`: имя таблицы (`agvpn_<id>`).
- `mark_hex`: выделенная fwmark клиента.
- `priority_base`: базовый диапазон `ip rule pref` для клиента.
- `capabilities`: `tcp`, `udp`, `dns_tunnel`, `ssh_tunnel`.
- `health`: last_check, latency, last_error.
### 4.2 RouteIntent
- Нормализованная запись назначения трафика к клиенту:
- `selector_type`: `domain | cidr | app_key | cgroup | uid`.
- `selector_value`: значение селектора.
- `client_id`: целевой клиент.
- `priority`: порядок применения.
- `mode`: `strict | fallback`.
### 4.3 ConflictRecord
- Запись о конфликте маршрутизации:
- `key`: нормализованный ключ пересечения.
- `owners`: список `client_id`.
- `severity`: `warn | block`.
- `reason`: человеко-читаемая причина.
- `suggested_resolution`: автоматическая подсказка.
## 5) Схема марков и таблиц (без конфликтов)
### 5.1 Mark allocator
- Ввести менеджер выделения марков из пула, например:
- `0x100-0x1FF` для client-specific route marks,
- `0x66/0x67/0x68/0x69` оставить для legacy/системных сценариев.
- Для каждого `client_id` выделяется:
- `client_mark`,
- `client_reply_mark` (если нужен отдельный ingress stickiness).
### 5.2 Table allocator
- Для каждого клиента заводится отдельная routing table:
- `agvpn_sb_main`, `agvpn_dnstt_home`, `agvpn_phoenix_eu`.
- В таблице только default route через iface клиента + локальные bypass-правила.
### 5.3 Rule priority allocator
- Для каждого клиента выделяется непересекаемый диапазон `pref`:
- пример: `13000-13049` клиент A, `13050-13099` клиент B.
- Это исключает перетирание правил между клиентами при apply/reconcile.
## 6) Защита от "мешанины" трафика
### 6.1 Destination ownership lock
- Один домен/cidr/app_key в активной конфигурации может иметь только одного владельца (`client_id`).
- При пересечении:
- по умолчанию `block` (HTTP `409` на apply),
- опционально `force_override` с явным подтверждением пользователя.
### 6.2 Flow stickiness (conntrack)
- Для первого пакета потока проставляется `ct mark = client_mark`.
- Для последующих пакетов mark восстанавливается из `ct mark`, чтобы один и тот же flow не перескакивал между интерфейсами.
- Правило действует в `output` и `prerouting`, аналогично текущему ingress-reply подходу.
### 6.3 DNS/IP coherence
- Для domain-based маршрутизации вводится owner-cache:
- `domain -> client_id -> ip set` с TTL.
- Один и тот же домен в активной политике не может одновременно резолвиться в разные клиентские set-цепочки.
### 6.4 Audit/guardrail
- Расширить `traffic_audit` на multi-client проверки:
- duplicate destination ownership,
- overlap CIDR между клиентами,
- app_key на двух клиентах одновременно,
- nft/rule drift по client chains.
## 7) UX дизайн (удобное добавление/переключение)
### 7.1 Экран "Клиенты"
- Список клиентов: имя, тип, статус, интерфейс, health.
- Действия: `Добавить`, `Включить/Выключить`, `Перезапустить`, `Удалить`.
- Мастер добавления:
- Шаг 1: тип клиента (`sing-box`, `dnstt`, `phoenix`),
- Шаг 2: параметры подключения,
- Шаг 3: health-check,
- Шаг 4: назначение default policy.
- Подпункты UX для engine:
- единый селектор `Active engine` с вариантами `singbox|dnstt|phoenix`;
- быстрые действия `Connect`, `Disconnect`, `Switch to ...`;
- явное отображение `desired_engine` vs `active_engine`;
- при деградации показывать `last_error` и action `Rollback to previous engine`.
### 7.2 Экран "Маршрутизация"
- Матрица `Селектор -> Клиент`.
- Массовое назначение списков IP/CIDR/доменов.
- Быстрый переключатель "перенести селектор на другой клиент" с dry-run проверкой конфликтов.
### 7.3 UX предупреждения
- Перед apply показывать diff:
- какие селекторы сменят владельца,
- какие потоки могут быть прерваны,
- какие конфликты заблокируют применение.
- При `force_override` обязательное подтверждение пользователя с явным риском:
- "Один и тот же сайт может потерять стабильность при частой смене интерфейса".
- При switch/connect engine:
- показывать предупреждение о кратковременном разрыве активных сессий;
- запрещать параллельные mutating-операции до завершения текущего switch;
- при failed switch предлагать rollback на предыдущий engine.
## 8) API-контракт (новые ручки, проект)
- `GET /api/v1/transport/clients`
- `POST /api/v1/transport/clients`
- `POST /api/v1/transport/clients/{id}/start`
- `POST /api/v1/transport/clients/{id}/stop`
- `GET /api/v1/transport/clients/{id}/health`
- `GET /api/v1/transport/policies`
- `POST /api/v1/transport/policies/validate`
- `POST /api/v1/transport/policies/apply`
- `GET /api/v1/transport/conflicts`
- `GET /api/v1/transport/capabilities`
Принцип:
- Все операции изменения policy идут через `validate -> apply`.
- `apply` атомарный: либо вся новая политика применена, либо rollback на предыдущую snapshot-конфигурацию.
## 9) Реализация по шагам
### E1.1 Контракты и состояние
- Ввести state-файлы:
- `transport-clients.json`,
- `transport-policies.json`,
- `transport-conflicts.json`.
- Добавить DTO и минимальные read endpoints.
### E1.2 PBR compiler v2
- Реализовать компиляцию RouteIntent в:
- nft sets/chains per client,
- ip rule pref ranges per client,
- table route entries per client.
### E1.3 Guardrails
- Валидация ownership/overlap до apply.
- Conntrack stickiness rules для стабильности flow.
### E1.4 UX-ready слой
- API предупреждений + dry-run diff.
- SSE события:
- `transport_client_state_changed`,
- `transport_policy_applied`,
- `transport_conflict_detected`.
## 10) Критерии готовности дизайна
- Можно добавить 2+ клиентов и поднять 2+ интерфейса без перезаписи чужих rule/table.
- Нельзя назначить один и тот же selector двум клиентам без explicit override.
- `traffic_audit` показывает целостную картину конфликтов и drift.
- UI получает понятные предупреждения до применения рискованной конфигурации.
## 11) Обратная совместимость
- Текущие `/api/v1/traffic/*` продолжают работать в legacy-режиме.
- При отсутствии multi-client политики ядро использует текущий single-client pipeline.
- Миграция: legacy `vpn|direct` может быть автоматически представлена как:
- `client_id=legacy-vpn`,
- `client_id=legacy-direct`.