# E3 План реализации мультиинтерфейса (execution roadmap) Дата: 2026-03-15 Статус: in-progress Владелец: Engineering ## 1) Цель - Реализовать мультиинтерфейсную архитектуру для transport-клиентов (`singbox`, далее `dnstt`, `phoenix`) без конфликтов маршрутизации. - Сохранить инвариант: вся логика маршрутизации живёт в Go-ядре, GUI/Web/Mobile остаются тонкими клиентами API. - Добавить безопасный path миграции без поломки текущего single-interface контура. ## 2) Инварианты реализации - Никаких прямых мутаций `ip rule`/`ip route`/`nft` из UI. - Один destination/intent может иметь только одного owner (до явного override). - Сначала foundation/state/contract, потом orchestration data-plane. - Каждый этап обратим (rollback), каждый этап проверяется `go test ./...`. ## 3) Фазы ### M1. Foundation интерфейсов (без изменения data-plane) - Добавить логический `iface_id` в `TransportClient` (default: `shared`). - Добавить state-файл интерфейсов (`transport-interfaces.json`) и нормализацию. - Добавить read-only endpoint `GET /api/v1/transport/interfaces`. - Обновить трекер и тесты миграции state. - Критерий: поведение runtime не меняется, старые профили продолжают работать. ### M2. Interface Orchestrator core (E3.3) - Ввести оркестратор `create/bind/start/stop/cleanup` по `iface_id`. - Разделить "логический интерфейс" (`iface_id`) и "runtime iface" (`tunX/dev`) с явным mapping. - Добавить lock-стратегию на уровне `iface_id`, чтобы исключить race между клиентами. - Критерий: один API-path для оркестрации всех движков, без дублирования per-client логики. ### M3. Policy compiler per-interface - Компилировать intents в наборы правил per `iface_id`: table/mark/pref/nft sets. - Гарантировать непересекаемые allocator-пулы для разных интерфейсов. - Подготовить атомарный apply-plan для группы интерфейсов. - Критерий: отдельные интерфейсы не перетирают таблицы/правила друг друга. ### M4. Anti-mixing и ownership guardrails (E3.4/E3.5) - Strict ownership registry (`domain/cidr/app`) с явным conflict reason. - Destination stickiness (`conntrack mark` + owner lock). - Predictable override-flow с подтверждением. - Критерий: один destination не может "гулять" между двумя интерфейсами без явного switch. ### M5. Transaction pipeline (E3.6) - Расширить apply до `validate -> plan -> confirm -> apply -> health-check -> commit`. - На любой ошибке health-check выполнять auto-rollback на previous snapshot. - Добавить idempotency/optimistic lock для multi-interface apply. - Критерий: частично применённой политики не остаётся. ### M6. Unified observability API (E6.6) - Добавить runtime endpoint для карточек/дашбордов: - `active_iface`, - `egress` (ip/country), - `latency`, - `last_error`, - counters per engine/policy. - Вынести метрики в единый DTO для GUI/Web/Mobile. - Критерий: UI не склеивает статус из нескольких endpoint-ов вручную. ### M7. UI/Web адаптация после backend-ready - Desktop: переключение iface/client через новый orchestration API. - Web/Mobile: reuse того же backend-контракта без новой бизнес-логики. - Добавить feature-flag/compat-mode для плавной миграции. - Критерий: backend-контракт единый для всех фронтов. - Текущий дизайн desktop-first зафиксирован: `docs/phase-e/E4_2_MULTI_INTERFACE_GUI_DESIGN.md`. ## 4) Что делаем прямо сейчас - M1 завершён: - `iface_id` + `transport-interfaces` state + `GET /transport/interfaces` + тесты. - M2 завершён: - добавлен per-`iface_id` lock manager для mutating lifecycle/provision (`start/stop/restart/provision`); - добавлен mapping-layer `iface_id -> runtime_iface/netns/routing_table` (dedicated iface defaults + interface hints + apply на create/patch/lifecycle/netns-toggle/provision); - закрыт owner-scope compile этап: `nft_set` генерируется в scope `iface+client+selector` (без shared-set mixing на одном `iface_id`). - M3 завершён (foundation): - добавлен compile-plan `iface_id -> table/mark/pref/nft sets` с persisted state (`transport-policies.plan.json`) и возвратом в `validate/apply/rollback/get-policy`; - добавлен atomic apply executor foundation (`transport-policies.runtime.json` + runtime snapshot/restore) и врезан в `apply/rollback` до commit policy revision; - подключён kernel stage в executor: per-interface CIDR nft sets apply/cleanup + optional `ip rule` stage под feature-flag; - ownership foundation (M4-start): добавлен persisted registry `transport-ownership.json` + `GET /api/v1/transport/owners`; - apply guardrails усилены: `force_override` допускается только для `owner_switch`, hard blocks не bypass-ятся override-флагом; - anti-mixing foundation (M4-start): owner switch теперь блокируется runtime owner-lock (если previous owner в статусе `up|starting|degraded`); - ownership observability: `GET /api/v1/transport/owners` аннотирует записи `owner_status/lock_active`, возвращает агрегат `lock_count` для UI/Web; - conntrack stickiness foundation: - kernel-stage (feature-flag `SVPN_TRANSPORT_POLICY_CONNTRACK_STICKY=1`) собирает destination-lock state из `conntrack -L -f ipv4` по `mark -> owner`; - persisted state: `transport-owner-locks.json`; - read-only endpoint: `GET /api/v1/transport/owner-locks`; - validate/apply добавляют `destination_lock` block для `cidr` owner-switch, если destination ещё sticky-locked на предыдущего owner. - owner-lock recovery: - endpoint `POST /api/v1/transport/owner-locks/clear` (point clear by `client_id` and/or `destination_ip(s)`); - двухшаговый confirm flow (`confirm_token`) для предотвращения случайного lock-loss. - следующий шаг: hardening kernel stage (расширение selector coverage, guardrails/observability) + M4 stickiness (`conntrack owner lock`).