# E4.4 Multi-Interface GUI Design (Desktop-first) Дата: 2026-03-15 Статус: planned (design approved) Владелец: Engineering ## 1) Ответ на ключевой вопрос - Да, это общий мультиинтерфейсный контур на всё приложение. - Источник истины: Go-ядро (`transport interfaces/policies/owners/owner-locks`). - GUI/Web/Mobile только рисуют состояние и вызывают API. ## 2) Границы - `AdGuardVPN` остаётся отдельным engine-контуром (autoloop/tun0) и не смешивается с transport policy ownership. - Мультиинтерфейс (`iface_id`, `routing_table`, owner-locks) относится к transport-движкам (`singbox`, далее `dnstt`, `phoenix`). - Дизайн делаем универсальным, без жёсткой привязки к одному протоколу. ## 3) UI-композиция (вкладка/модуль Transport) ### A. Interface Summary (верхний блок) - Карточки по `iface_id`: - `iface_id`, - `routing_table`, - количество клиентов на интерфейсе, - количество rule/intents. - Источники: - `GET /api/v1/transport/interfaces`, - `GET /api/v1/transport/policies`. ### B. Clients Grid (карточки подключений) - Карточки клиентов остаются, но группируются по `iface_id`. - На карточке: - `client name/id`, - `protocol/transport/security`, - `status/latency`, - `egress ip/country` (если доступно). - Источник: - `GET /api/v1/transport/clients`, - `GET /api/v1/egress/identity?scope=transport:`. ### C. Ownership & Locks Panel (новый блок) - Вкладки внутри панели: - `Ownership`: - данные из `GET /api/v1/transport/owners`, - поля: selector, owner client, iface, `owner_status`, `lock_active`. - `Destination locks`: - данные из `GET /api/v1/transport/owner-locks`, - поля: destination ip, owner client, mark, proto, updated_at. - Назначение: - быстро понять, почему блокируется owner-switch. ### D. Safe Lock Recovery (точечная очистка lock) - Кнопка: `Clear selected lock(s)` в `Destination locks`. - Только точечный режим: - по `client_id`, - по `destination_ip`/`destination_ips`. - Полный clear без фильтра запрещён. ## 4) UX-flow clear owner-lock (двухшаговый) 1. Пользователь выбирает фильтры и нажимает `Clear`. 2. GUI вызывает `POST /api/v1/transport/owner-locks/clear` без `confirm_token`. 3. Backend отвечает: - `OWNER_LOCK_CLEAR_CONFIRM_REQUIRED`, - `confirm_token`, - список matched lock. 4. GUI показывает confirm-диалог с последствиями (что удалится). 5. При подтверждении GUI повторяет запрос с `confirm_token`. 6. Успех: - перечитать `owner-locks`, - обновить `owners`, - показать `cleared_count`. ## 5) Правила безопасности UI - Нельзя отправить clear-запрос без фильтра. - Нельзя кешировать `confirm_token` между сессиями. - При `*_REVISION_MISMATCH` GUI обязан перечитать `owner-locks` и повторить выбор. - Все mutating-кнопки блокируются на время in-flight запроса. ## 6) События/обновление данных - В приоритете SSE refresh от уже существующих transport-событий. - На `transport_policy_applied`: - перечитать `owners`, - если включён sticky-режим, перечитать `owner-locks`. - После clear: - локально optimistic update запрещён, только re-fetch из API. ## 7) Контракт API для GUI (фикс) - `GET /api/v1/transport/interfaces` - `GET /api/v1/transport/clients` - `GET /api/v1/transport/policies` - `GET /api/v1/transport/owners` - `GET /api/v1/transport/owner-locks` - `POST /api/v1/transport/owner-locks/clear` - `POST /api/v1/transport/policies/validate` - `POST /api/v1/transport/policies/apply` ## 8) Порядок внедрения GUI 1. Добавить read-only `Ownership & Locks Panel`. 2. Подключить фильтры и таблицу `Destination locks`. 3. Подключить двухшаговый clear-flow с confirm-диалогом. 4. Встроить обновление после validate/apply и transport refresh. 5. После desktop-стабилизации переиспользовать UI-контракт в web/mobile.