Files
harbor-net/docs/audits/windows-client-ux-2026-07-08/AUDIT.md

189 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.