# E4 UX-поток предупреждений: validate -> confirm -> apply Дата: 2026-03-05 Статус: in-progress (E4.2 foundation реализован в GUI controller) Владелец: Engineering ## 1) Цель - Зафиксировать единый UX-флоу для безопасного применения multi-client policy. - Исключить "тихие" конфликтные применения. - Дать пользователю прозрачный diff, риски и явное подтверждение. ## 2) Базовый сценарий 1. Пользователь редактирует routing policy. 2. UI вызывает `POST /api/v1/transport/policies/validate`. 3. UI показывает результат валидации: - `valid=true` и `block_count=0` -> можно применять. - `valid=false` или `block_count>0` -> блокируем apply до подтверждения/исправления. 4. Если пользователь выбирает принудительное применение: - UI показывает модал подтверждения риска, - использует `confirm_token` из validate. 5. UI вызывает `POST /api/v1/transport/policies/apply`. ### 2.1 Сценарий Engine Switch / Connect 1. Пользователь выбирает целевой engine (`singbox|dnstt|phoenix`) или нажимает `Connect`. 2. UI формирует draft policy, где default ownership переходит к выбранному `client_id`. 3. Дальше используется тот же pipeline: - `validate` -> (safe|risky) -> `confirm` -> `apply`. 4. После apply UI проверяет: - `GET /api/v1/transport/clients/{id}/health`, - расхождение `desired_engine` vs `active_engine`. 5. Если engine не поднялся, UI предлагает `rollback`. ## 3) Состояния UI ### 3.1 Draft - Политика редактируется, но не проверена. - Кнопка Apply отключена. - Доступна кнопка Validate. ### 3.2 Validated (safe) - `block_count=0`. - Показываем diff (`added/changed/removed`). - Apply активен без force режима. ### 3.3 Validated (risky) - Есть блокирующие конфликты (`ownership`, `cidr_overlap`, `unknown_client`). - Показываем список конфликтов и конкретные селекторы. - Обычный Apply отключен. - Доступен `Force apply` только через отдельный confirm-step. ### 3.4 Confirm required - Модал с явным предупреждением: - что будет перезаписано, - какие flow могут быть прерваны, - какие сайты/сети сменят client owner. - Кнопка подтверждения вызывает `apply` с `force_override=true` + `confirm_token`. ### 3.5 Applied - Показываем `policy_revision` и `apply_id`. - Обновляем текущую policy в UI. - Слушаем SSE `transport_policy_applied`. ### 3.6 Switching engine - Идёт переключение активного engine. - Кнопки mutating-действий блокируются до завершения. - Отображается прогресс: `Validating`, `Applying`, `Waiting for health`. ### 3.7 Switch failed - `apply` или `health` завершились ошибкой. - Показываем `last_error` активного клиента и причину валидации/применения. - Предлагаем быстрые действия: - `Rollback`, - `Switch back to previous engine`. ## 4) Тексты предупреждений (шаблоны) - `ownership`: - "Один и тот же селектор назначен разным клиентам. Это может вызвать нестабильную маршрутизацию." - `cidr_overlap`: - "CIDR-подсети пересекаются между клиентами. Пакеты могут идти не по ожидаемому интерфейсу." - `unknown_client`: - "Политика ссылается на несуществующий клиент. Сначала добавьте/включите клиент." Force confirm warning: - "Принудительное применение может вызвать кратковременный обрыв активных сессий и смену маршрута для части трафика." ## 5) UX-правила безопасности - Без `validate` кнопка `apply` неактивна. - `confirm_token` не хранится между сессиями UI и считается одноразовым. - При смене `policy_revision` в фоне UI обязан повторно выполнить validate. - При `POLICY_REVISION_MISMATCH` UI показывает "Конфигурация изменилась, нужно повторить проверку". ## 6) Web/iOS/Android паритет - Один и тот же флоу и тексты рисков для всех клиентов. - Разница только в визуальном представлении: - web: side panel + modal, - mobile: full-screen sheet. - Логика decision-state остается одинаковой: - draft -> validate -> (safe|risky) -> confirm -> apply. ## 7) Минимальный UI-чеклист внедрения - Отображение `summary.block_count/warn_count`. - Таблица `conflicts[]` с фильтром по severity/type. - Видимый diff `added/changed/removed`. - Модал force confirmation с явным перечислением рисков. - Бейдж текущей ревизии policy (`policy_revision`). - SSE-подписка на `transport_policy_validated`, `transport_policy_applied`, `transport_conflict_detected`. - Для engine UX: - индикатор `desired_engine / active_engine`, - кнопки `Connect`/`Switch`, - блокировка повторного switch, пока предыдущий не завершён, - action `Rollback to previous engine` при неуспехе. ## 8) Статус внедрения (2026-03-07) - E4.2 foundation в GUI controller реализован: `draft -> validate -> confirm -> apply`. - E4.3.1 foundation в GUI реализован: - на вкладке `AdGuardVPN` был добавлен foundation-блок `Transport engine`; - доступен выбор client и действия `Prepare/Connect/Disconnect/Restart` через API `/api/v1/transport/clients/{id}/*`; - отображается runtime-состояние выбранного engine (`status/iface/table/latency/last_error`); - refresh блока привязан к transport SSE-событиям. - E4.3.2 реализован: - engine-блок вынесен в отдельную вкладку `SingBox`; - `Connect/Switch` переведён на pipeline `validate -> confirm -> apply`, direct `start` для switch больше не используется; - добавлен `Rollback policy` button. - Следующий UX-этап: - `desired_engine/active_engine` индикаторы и блокировка повторного switch; - settings-переключатель видимости protocol tabs (`SingBox/DNSTT/Phoenix`).