Refactor VPN proxy routing logic
This commit is contained in:
188
docs/audits/windows-client-ux-2026-07-08/AUDIT.md
Normal file
188
docs/audits/windows-client-ux-2026-07-08/AUDIT.md
Normal file
@@ -0,0 +1,188 @@
|
||||
# UX/UI-аудит Windows-клиента
|
||||
|
||||
Дата: 2026-07-08
|
||||
|
||||
## Область аудита
|
||||
|
||||
Проверен текущий React UI `apps/windows-client` для Vite/Tauri как компактная Windows-утилита управления proxy-маршрутизацией приложений. Аудит выполнялся в browser-preview на `http://127.0.0.1:5174/`, поэтому нативные Tauri-команды были недоступны, а интерфейс показывал preview/runtime-ошибки. Все выводы ниже привязаны к скриншотам, снятым в этом прогоне.
|
||||
|
||||
## Цель пользователя
|
||||
|
||||
Главная задача пользователя - быстро управлять службами и понять:
|
||||
|
||||
- какие компоненты установлены;
|
||||
- какие службы запущены, остановлены или отсутствуют;
|
||||
- какое действие доступно прямо сейчас: установить, удалить, запустить, остановить, обновить, добавить или применить;
|
||||
- что сейчас маршрутизируется;
|
||||
- через какую цепочку компонентов идет трафик;
|
||||
- готовы ли ProxiFyre и опциональный Local sing-box;
|
||||
- можно ли безопасно применить изменения;
|
||||
- что делать дальше, если что-то сломано.
|
||||
|
||||
Цель по доступности: интерфейс должен быть управляемым с клавиатуры, с понятными статусами, читаемым восстановлением после ошибок, предсказуемыми focus states и устойчивой адаптацией к узким размерам Windows-окна.
|
||||
|
||||
## Доказательства
|
||||
|
||||
1. `01-summary-desktop.png` - панель "Сводка", desktop-ширина. Состояние: смешанное. Главный статус виден, но примененное состояние еще "загружается", а рядом уже показан бейдж "Совпадает".
|
||||
2. `02-proxifyre-desktop.png` - панель ProxiFyre, desktop-ширина. Состояние: в целом рабочее. Состав компонента и список приложений компактны, но главное действие apply доступно даже при отсутствующих prerequisites.
|
||||
3. `03-proxy-desktop.png` - панель "VPN / Прокси", desktop-ширина. Состояние: рабочее. Настройка маршрута понятна, но route path выглядит как вторичный текст, а apply-action выглядит валидным до того, как маршрут может успешно примениться.
|
||||
4. `04-proxy-validation-desktop.png` - невалидный proxy input. Состояние: хорошая база. Inline-валидация находится рядом с полем и отключает действие проверки.
|
||||
5. `05-summary-narrow.png` - панель "Сводка", узкая ширина. Состояние: напряженное. Контент перестраивается, но нижний log dock и длинные сообщения обрезают важную информацию.
|
||||
6. `06-proxifyre-narrow.png` - панель ProxiFyre, узкая ширина. Состояние: напряженное. Контролы складываются неплохо, но setup chips переполняются по горизонтали, а нижний dock конкурирует с основной задачей.
|
||||
|
||||
## Доменное направление
|
||||
|
||||
Ключевые понятия домена: цепочка маршрута, здоровье компонентов, локальный runtime, внешний endpoint, выбранные приложения, сгенерированный конфиг, граница apply/restart, диагностика.
|
||||
|
||||
Цветовой мир: темная Windows-оболочка, терминальный черный, зеленый для driver/service ready, amber для предупреждений, красный для блокеров/firewall, синий для links/actions, slate для config-файлов.
|
||||
|
||||
Сигнатурный элемент, который стоит усилить: `Service Control Row` - повторяемая строка компонента, где слева состояние службы, в центре человекочитаемый статус, справа одно главное действие и меню дополнительных действий. Route-chain readout тоже нужен, но как объяснение эффекта этих служб: `Apps -> ProxiFyre -> target -> VPN/server`.
|
||||
|
||||
Дефолты, которые стоит отбрасывать:
|
||||
|
||||
- generic dashboard cards -> service-control utility;
|
||||
- большая зеленая apply-кнопка всегда видна -> apply gated by readiness + inline blockers;
|
||||
- raw logs как главный error surface -> сначала человеческое recovery-сообщение, raw details вторым уровнем.
|
||||
- разрозненные кнопки и анимации -> shared component base с едиными variants/states/motion tokens.
|
||||
|
||||
## Сильные стороны
|
||||
|
||||
- Приложение уже ощущается как компактная desktop-утилита, а не как сайт. Фиксированный header, tabs, плотные панели и темная системная палитра подходят задаче.
|
||||
- Продуктовая модель сильная: ProxiFyre и Local sing-box разделены, sing-box не сделан обязательным.
|
||||
- Inline-валидация SOCKS5-поля расположена рядом с полем и отключает "Проверить", когда формат неверный.
|
||||
- Зона добавления приложения использует иконки с доступными labels и tooltip, поэтому плотный workflow остается сканируемым.
|
||||
- Для основных анимаций есть `prefers-reduced-motion`.
|
||||
- UI использует настоящие `button` и tab roles, а не click-only divs. Это хорошая база для доступности.
|
||||
|
||||
## UX-риски
|
||||
|
||||
1. Apply выглядит доступным, когда маршрут еще не actionable.
|
||||
- Доказательства: `02-proxifyre-desktop.png`, `03-proxy-desktop.png`.
|
||||
- ProxiFyre отсутствует и список приложений пуст, но "Обновить конфиг" / "Обновить маршрут" ярко-зеленые. Это провоцирует failed action вместо направленного setup.
|
||||
|
||||
2. Главная цепочка маршрута не является визуальным фокусом.
|
||||
- Доказательства: `01-summary-desktop.png`, `03-proxy-desktop.png`.
|
||||
- Самая важная mental model - путь трафика, но сейчас он показан plain text в таблице или вторичном блоке. Пользователь вынужден читать фрагменты статуса вместо того, чтобы сразу увидеть цепочку.
|
||||
|
||||
3. В "Сводке" есть противоречивое состояние.
|
||||
- Доказательство: `01-summary-desktop.png`.
|
||||
- "Состояние загружается" показано рядом с "Совпадает", а система одновременно говорит "Не настроено". Это может создать ощущение, что действий не требуется.
|
||||
|
||||
4. Preview/native command failures слишком сырые.
|
||||
- Доказательства: все скриншоты.
|
||||
- Dock показывает `Cannot read properties of undefined (reading 'invoke')`. Для разработчика это полезно, но как первичный пользовательский error surface это шум.
|
||||
|
||||
5. Bottom log dock конфликтует с узкой компоновкой.
|
||||
- Доказательства: `05-summary-narrow.png`, `06-proxifyre-narrow.png`.
|
||||
- Важные сообщения обрезаются до "Компонен..." и "Cannot read prop..."; dock постоянно занимает вертикальное место в и так коротком окне.
|
||||
|
||||
6. ProxiFyre setup chips плохо перестраиваются.
|
||||
- Доказательство: `06-proxifyre-narrow.png`.
|
||||
- Горизонтальная chip-лента скрывает третий dependency и ухудшает диагностическую ясность.
|
||||
|
||||
7. Терминология немного смешана.
|
||||
- Доказательства: `01-summary-desktop.png`, `03-proxy-desktop.png`.
|
||||
- `config`, `TCP check`, `VPN сервер`, `Local sing-box`, `ProxiFyre` - все эти термины допустимы, но нужен единый принцип: сначала пользовательский русский, технический идентификатор вторым уровнем.
|
||||
|
||||
8. Компонентная база пока не выражена как система.
|
||||
- Доказательства: `02-proxifyre-desktop.png`, `03-proxy-desktop.png`, `06-proxifyre-narrow.png`.
|
||||
- Кнопки "Обновить", "Установить", "Открыть", "Проверить", add-icon buttons и service actions выглядят близко, но пока не читаются как строгая система variants. Из-за этого сложно гарантировать одинаковые hover/loading/disabled/focus states и одинаковую motion-модель.
|
||||
|
||||
## Риски доступности
|
||||
|
||||
- Tablist использует `role="tab"`, но не видно поддержки ожидаемого arrow-key behavior и roving tab index. Пользователю с клавиатурой, вероятно, придется проходить все tabs через Tab вместо Left/Right.
|
||||
- Focus visibility есть через browser defaults, но визуально она тяжелая и не согласована со стилем приложения. Нужен отдельный `:focus-visible` token для buttons, tabs, inputs и icon controls.
|
||||
- Status dots сильно полагаются на цвет. Стоит дублировать состояние видимым текстом или `aria-label`/screen-reader text там, где текст рядом не объясняет статус.
|
||||
- Footer использует `aria-live`, но повторяющиеся raw runtime errors могут быть шумными для assistive tech. Сначала стоит объявлять короткий статус, а подробный error text держать за "Посмотреть".
|
||||
- На узкой ширине truncation может скрывать actionable-часть сообщений и button labels.
|
||||
- Скриншоты не доказывают полный keyboard order, screen-reader output или contrast ratios. Для этого нужен интерактивный accessibility pass.
|
||||
|
||||
## План улучшений
|
||||
|
||||
### P0 - Сделать service-control flow заслуживающим доверия
|
||||
|
||||
1. Ввести shared component base:
|
||||
- `Button` с variants: `primary`, `neutral`, `add`, `danger`, `icon`;
|
||||
- `Tabs` с единым keyboard behavior и animation contract;
|
||||
- `ServiceControlRow` для ProxiFyre, Local sing-box и будущих служб;
|
||||
- `StatusPill`, `Field`, `ActionMenu`, `LogDock`;
|
||||
- единые states: default, hover, active, focus-visible, disabled, loading.
|
||||
|
||||
2. Нормализовать motion tokens:
|
||||
- button press: 100-140ms;
|
||||
- tab switch: 180-240ms, только `opacity` + `transform`;
|
||||
- popover/menu: 150-180ms;
|
||||
- service operation: видимый loading state, чтобы интерфейс не ощущался зависшим;
|
||||
- не использовать `transition: all`.
|
||||
|
||||
3. Заменить raw preview/native invocation failures на дружелюбное состояние:
|
||||
- "Desktop-команды недоступны в browser preview. Запусти через Tauri для управления службами."
|
||||
- Raw error оставить только в деталях лога.
|
||||
|
||||
4. Заблокировать primary apply actions до готовности:
|
||||
- disabled + explanation, когда список приложений пуст;
|
||||
- disabled + explanation, когда ProxiFyre отсутствует;
|
||||
- disabled + explanation, когда выбран local route без установленного/запущенного sing-box или выбранного сервера;
|
||||
- "Открыть конфиг" оставить вторичным действием, не равным apply по весу.
|
||||
|
||||
5. Исправить язык summary-state:
|
||||
- использовать взаимоисключающие состояния: "Проверяю", "Не готово", "Готово к применению", "Применено", "Есть черновик";
|
||||
- не показывать "Совпадает", пока saved/applied state реально не загружен.
|
||||
|
||||
### P1 - Пересобрать главную mental model
|
||||
|
||||
6. Вынести route-chain component как объясняющий элемент:
|
||||
- узел `Apps` с количеством;
|
||||
- узел `ProxiFyre` со статусом installed/running;
|
||||
- узел `Target`: external SOCKS5 или Local sing-box;
|
||||
- узел `Server`, когда активен local sing-box;
|
||||
- каждый сломанный узел показывает одно следующее действие.
|
||||
|
||||
7. Переработать "Сводку" в command center:
|
||||
- сверху: route-chain и readiness системы;
|
||||
- посередине: applied vs draft diff, только если есть отличие;
|
||||
- снизу: максимум два next actions;
|
||||
- длинные config paths и подробный состав компонентов убрать из первого взгляда.
|
||||
|
||||
8. Разделить "настроить маршрут" и "применить маршрут":
|
||||
- Proxy panel отвечает за endpoint choice и connection check;
|
||||
- ProxiFyre panel отвечает за app selection и service readiness;
|
||||
- Summary подтверждает объединенный маршрут и применяет только при готовности.
|
||||
|
||||
### P2 - Усилить responsive и component craft
|
||||
|
||||
7. Превратить setup chips в wrapping checklist на узких ширинах.
|
||||
|
||||
8. Сделать log dock адаптивным:
|
||||
- desktop: persistent compact dock подходит;
|
||||
- narrow: collapsed toast/details sheet вместо постоянного full-width footer.
|
||||
|
||||
9. Определить design tokens:
|
||||
- surfaces: canvas, panel, inset, elevated;
|
||||
- text: primary, secondary, muted, disabled;
|
||||
- status: ready, warning, blocked, checking;
|
||||
- focus ring и border intensities.
|
||||
|
||||
10. Стандартизировать copy:
|
||||
- последовательно использовать "конфиг" или "конфигурация";
|
||||
- заменить "TCP check" на "TCP-проверка";
|
||||
- `Local sing-box` оставить техническим именем компонента, но в user-facing headings связывать с "локальный прокси".
|
||||
|
||||
### P3 - Verification pass
|
||||
|
||||
11. Добавить focused interaction QA:
|
||||
- keyboard tab order;
|
||||
- arrow-key tab navigation;
|
||||
- focus return из menus/popovers;
|
||||
- disabled-action explanations;
|
||||
- empty, loading, error, missing-component, ready и unapplied-change states.
|
||||
|
||||
12. Добавить responsive visual snapshots:
|
||||
- 1280x720 desktop;
|
||||
- 800x600 compact desktop;
|
||||
- 420x720 narrow window;
|
||||
- длинные proxy/server names и длинные Windows paths.
|
||||
|
||||
## Рекомендуемый первый redesign slice
|
||||
|
||||
Сначала стоит сделать shared UI foundation: `Button`, `Tabs`, `ServiceControlRow`, `StatusPill`, `Field`, `ActionMenu`, `LogDock` и motion tokens. После этого собрать ProxiFyre и Local sing-box через один `ServiceControlRow`, а route-chain использовать как объясняющий компонент в "Сводке" и "VPN / Прокси". Такой порядок сначала стабилизирует поведение кнопок/табы/анимации, затем улучшит ориентацию и recovery без переписывания всего UI.
|
||||
Reference in New Issue
Block a user