26 KiB
Windows Client Service-Control UI System Implementation Plan
Intent: Превратить текущий Windows-клиент в простую service-control утилиту с единой компонентной базой, предсказуемыми состояниями кнопок/табов/служебных строк, readiness-блокерами и аккуратными motion tokens.
Current Behavior: apps/windows-client/src/app/App.tsx и apps/windows-client/src/styles/app.css остаются крупным монолитом. Кнопки, табы, service cards, add controls, apply/open actions, log dock, validation и анимации задаются ad hoc через локальные JSX-блоки и классы вроде service-button, apply-button, ghost-button, add-tile, route-switch, finder-card, log-dock.
Expected Outcome: Пользователь видит плотную Windows-утилиту, где ProxiFyre и Local sing-box управляются через один повторяемый service-control паттерн, все кнопки имеют понятные variants/states, apply недоступен до готовности prerequisites, ошибки preview/native команд показываются человечески, а вкладки/меню/loading состояния двигаются одинаково и не создают ощущения зависшего UI.
Target-Perspective Output: Пользователь открывает клиент и за несколько секунд понимает, какие компоненты установлены, какие службы запущены/остановлены/отсутствуют, какую одну кнопку можно нажать дальше, почему apply заблокирован, и где посмотреть детали. На desktop и узкой ширине интерфейс не обрезает ключевые действия и не показывает raw runtime errors как основной текст.
Truth Owner: Источник правды для профилей, targets, компонентов, Local sing-box, generated config и apply остается в Rust/Tauri командах и JSON-файлах под C:\ProgramData\VpnProxy. Источник правды для UI-паттернов и визуальных контрактов после этого плана: .interface-design/system.md и shared UI components под apps/windows-client/src/ui.
Contract Boundary: React UI вызывает typed wrappers из apps/windows-client/src/api/tauriCommands.ts. Shared UI components не вызывают Tauri напрямую и не владеют persistent state; они получают props, emit callbacks и отображают states. App.tsx/panel containers владеют orchestration, draft state, loading state, readiness blockers и вызовами существующих handlers.
Cutover: Старые ad hoc JSX/CSS paths для кнопок, табов, service cards, log dock, fields и menus постепенно заменяются shared components. После cutover в App.tsx не должно оставаться нового прямого <button className="apply-button|service-button|ghost-button|add-tile|open-config-button"> как доминирующего паттерна; старые классы либо удалены, либо превращены в internal classes shared components.
Displaced Path: Вытесняется путь "каждый render-блок сам рисует свою кнопку/таб/service card/loading/error". Также демотируется route-chain-first направление: route chain остается объясняющим элементом, но основная модель UI - управление службами и их состояниями.
Value Density: Самый ценный срез: Button/IconButton, Tabs, ServiceControlRow, LogDock, readiness blockers для apply, friendly preview error. Это сразу исправляет доверие к действиям и закладывает базу для дальнейшего разбиения панелей.
Evidence Gate: Приемка требует npm run build плюс пользовательские доказательства: desktop и narrow screenshots для Summary, ProxiFyre, VPN/Proxy; screenshot или DOM-state, что apply disabled с explanation при missing ProxiFyre/empty apps; screenshot, что raw invoke preview error не показывается как главный текст.
Acceptance Evidence: Build проходит; visual evidence показывает единые button variants/states, tabs с keyboard/active behavior, ServiceControlRow для ProxiFyre и Local sing-box, disabled apply blockers, adaptive log dock, friendly preview/native error. Если реальная elevated Tauri установка/удаление служб не проверялась, service execution lane помечается как implemented but unproven.
Evidence Lane: Доказательства исполнения записывать в docs/goals/windows-client-service-control-ui-system/EVIDENCE.md.
Kill Criteria: Нет второго источника UI truth вне shared components; нет прямой записи generated config из UI; нет скрытой установки компонентов при apply/open/refresh; нет новых изменений в root src/web/* или src/server/*; нет raw preview Cannot read properties...invoke как основного user-facing сообщения; нет зеленого primary apply без readiness.
Architecture Slice: Создать shared UI layer под apps/windows-client/src/ui; при необходимости создать view-model helpers под apps/windows-client/src/app; модифицировать apps/windows-client/src/app/App.tsx и apps/windows-client/src/styles/app.css; не менять backend, кроме точечных type/import изменений, если вскроется compile-only необходимость.
Plan Review Gate: Requires PRE review before execution.
Outcome Contract
Plan title: Windows Client Service-Control UI System
Intent: стабилизировать UI как простую утилиту управления службами, а не dashboard.
Current behavior: большие участки JSX и CSS повторяют однотипные buttons, service status cards, tabs, fields, menus и log surfaces без общего контракта.
Expected outcome: shared UI foundation контролирует внешний вид, states, motion и accessibility для повторяемых элементов; ProxiFyre и Local sing-box отображаются через один service-control паттерн; apply actions gated by readiness.
Target-perspective output: пользователь видит понятные состояния "установлено/не установлено/запущено/остановлено/проверяю/ошибка", одну главную кнопку на службу, объяснение блокеров и одинаковые transitions при переключении вкладок/меню/loading.
Truth owner:
- Data truth: Rust/Tauri commands +
C:\ProgramData\VpnProxy. - UI pattern truth:
.interface-design/system.md+apps/windows-client/src/ui/*. - Orchestration truth:
apps/windows-client/src/app/App.tsxand extracted app-level helpers.
Contract boundary:
src/ui/*is presentational and callback-driven.src/app/*containers compose view models, draft state and command handlers.src/api/tauriCommands.tsremains the typed command boundary.
Cutover:
- First introduce shared components without changing backend behavior.
- Then migrate existing render functions to shared components.
- Then remove/demote old CSS selectors so new work cannot keep using ad hoc paths.
Displaced path:
- Direct ad hoc buttons/tabs/service-card styles in
App.tsx/app.css. - Raw runtime error text as primary user-facing status.
- Always-green apply actions regardless of prerequisites.
Value density:
- Strongest first slice is shared component layer + apply blockers + friendly preview error.
- Panel extraction is valuable only after component contracts exist.
Evidence gate:
- Build proof.
- Visual proof at desktop and narrow widths.
- Interaction proof for disabled apply reasons, tab focus/keyboard behavior, service action loading state and log dock behavior.
Acceptance evidence:
cd apps/windows-client && npm run build.- Browser/Tauri screenshots saved under this goal's evidence folder or linked from
EVIDENCE.md. - Notes of any unverified elevated service operations.
Evidence lane:
docs/goals/windows-client-service-control-ui-system/EVIDENCE.md.
Kill criteria:
- If old button classes remain public and newly used after migration, the cutover is incomplete.
- If
App.tsxgrows with more ad hoc JSX instead of shrinking or delegating to shared components, stop and refactor the slice. - If summary/route work starts before shared buttons/tabs/service rows, stop and restore priority.
Non-goals:
- No backend service rewrite.
- No new route modes.
- No new installer behavior.
- No root web/server redesign.
- No full visual rebrand.
- No dependency-heavy component library unless explicitly approved.
Risk if wrong:
- The UI may look slightly cleaner but remain structurally unmaintainable, with duplicated states and inconsistent actions. The user will still see green buttons that fail, raw preview errors, and inconsistent loading/disabled/motion states.
Architecture Slice
Files to create:
apps/windows-client/src/ui/Button.tsxapps/windows-client/src/ui/IconButton.tsxapps/windows-client/src/ui/Tabs.tsxapps/windows-client/src/ui/ServiceControlRow.tsxapps/windows-client/src/ui/StatusPill.tsxapps/windows-client/src/ui/Field.tsxapps/windows-client/src/ui/ActionMenu.tsxapps/windows-client/src/ui/LogDock.tsxapps/windows-client/src/ui/index.tsapps/windows-client/src/app/readiness.tsapps/windows-client/src/app/viewModel.tsor smaller helpers if they reduceApp.tsxwithout creating duplicate truth.
Files to modify:
apps/windows-client/src/app/App.tsxapps/windows-client/src/styles/app.cssapps/windows-client/src/api/tauriCommands.tsonly for compile-safe preview/error wrapper changes if needed.apps/windows-client/src/domain/types.tsonly if component/view-model types need shared aliases.docs/goals/windows-client-service-control-ui-system/EVIDENCE.mdduring execution.
Files to avoid:
src/web/*src/server/*- Docker/compose/entrypoint files.
- Installer scripts.
- Rust backend files unless a compile break proves a tiny typed-boundary fix is necessary.
- Existing goal packages, except cross-reference notes in evidence.
Source of truth:
- UI system:
.interface-design/system.md. - Profiles/targets/components/subscription/activity/generated config: Rust/Tauri commands and
C:\ProgramData\VpnProxy. - Current draft state: React state in app containers only.
Read path:
App.tsxcallsgetSavedState,getComponents,getProxiFyreSetupStatus,getSingBoxStatus,getSingBoxSetupStatus.- View-model helpers derive service states, button readiness, route summary and blocker copy from existing state.
- Shared components receive already-derived props and do no data fetching.
Write path:
- Existing handlers remain the only write path: install/start/stop/uninstall service handlers, app add/remove handlers, route mode/proxy/subscription/server handlers,
updateConfig,openConfig. - Shared components only call callbacks passed by containers.
- Apply actions call
updateConfigonly when readiness says they are actionable.
Contract boundary:
Buttonowns variants/states/loading/disabled look, not business readiness.ServiceControlRowowns layout for a service, not installing/starting logic.Tabsowns keyboard behavior and active styling, not panel content.LogDockowns display/collapse/history behavior, not logging policy.readiness.tsowns blocker computation and copy.
Integration points:
- ProxiFyre row uses existing
proxyfier,setupStatus,serviceAction,installProxiFyrePackage,setProxiFyreServiceRunning,uninstallProxiFyrePackage. - Local sing-box row uses existing
singbox,singBoxSetupStatus,singBoxStatus,singBoxAction,installSingBoxPackage,setSingBoxServiceRunning,uninstallSingBoxPackage. - App list uses existing
items,addItem,removeItem,pickAndAddItem,isProcessInputOpen,processInput. - Route panel uses existing
routeMode,proxyInput,proxyPing,pingExternalProxy, subscription/server handlers. - Log dock uses existing
logEntries,activeLog,isLogOpen.
Migration/cutover:
- Introduce shared components alongside old CSS.
- Migrate one component family at a time.
- After migration, delete or privatize old selectors from
app.css. - Keep build green after each task.
- Do not split backend concerns into UI components.
Displaced path:
renderTabslocal tab button markup.renderProxiFyreCardandrenderSingBoxCardduplicated finder/service-card markup.renderApplyActionsalways-green apply command row.log-dockraw error display.- Direct CSS button families:
.ghost-button,.service-button,.apply-button,.open-config-button,.add-tile,.route-switch button.
Acceptance evidence gate:
- Visual proof is required because this is UI/system work.
- Build proof alone is not enough.
- If Browser preview cannot prove native service actions, capture preview proof and mark native actions
implemented but unproven.
UI Contract
Button Variants
Button must support:
primary: one main ready action; green only when action is safe and ready.neutral: refresh/open/cancel/secondary.add: add process/EXE/folder/target; icon-first.danger: stop/delete/uninstall/destructive.icon: square icon-only action witharia-labelandtitle/tooltip.
Required states:
- default
- hover
- active
- focus-visible
- disabled
- loading
Loading text should name the action: Проверяю, Устанавливаю, Запускаю, Останавливаю, Применяю, not only ....
Tabs
Tabs must support:
role="tablist",role="tab",role="tabpanel".- Left/Right arrow navigation.
- Enter/Space activation if focus and selection are separated.
- Active underline.
- 180-240ms panel transition using only
opacityandtransform. - Reduced motion support.
ServiceControlRow
ServiceControlRow props should express:
- service name.
- state:
checking | missing | installed | running | stopped | error. - title and detail.
- primary action label/loading/disabled.
- optional secondary menu actions.
- optional expanded details/checklist.
- optional inline actions/details toggle.
It must be generic enough for both ProxiFyre and Local sing-box.
Readiness Blockers
Apply readiness must be computed before rendering the action:
- no apps -> blocked with
Добавь хотя бы одно приложение. - ProxiFyre missing -> blocked with
Установи ProxiFyre. - local route + sing-box missing -> blocked with
Установи Local sing-box. - local route + no selected server -> blocked with
Выбери сервер Local sing-box. - external route + invalid proxy -> blocked with accepted format copy.
- pending service action/apply -> loading and disabled.
Blocked apply must not be bright green.
Friendly Preview Error
Browser-preview/native command errors should render as:
- title:
Desktop-команды недоступны - text:
Запусти клиент через Tauri, чтобы управлять службами и применять конфиг. - raw error only inside log details/history.
Motion Tokens
CSS variables:
--motion-fast: 120ms--motion-standard: 180ms--motion-panel: 220ms--ease-out: cubic-bezier(0.23, 1, 0.32, 1)--ease-standard: cubic-bezier(0.22, 0.72, 0.18, 1)
Do not use transition: all.
Tasks
Task 1: Create Shared UI Foundation
Allowed files:
apps/windows-client/src/ui/Button.tsxapps/windows-client/src/ui/IconButton.tsxapps/windows-client/src/ui/Tabs.tsxapps/windows-client/src/ui/StatusPill.tsxapps/windows-client/src/ui/Field.tsxapps/windows-client/src/ui/index.tsapps/windows-client/src/styles/app.css
Scope:
- Create presentational components only.
- Add CSS tokens/classes for button variants, tab states, focus-visible, loading and reduced motion.
- Do not wire business handlers yet beyond simple props.
Expected output:
- Components compile under strict TypeScript.
- No backend or app state behavior changes.
Verification command:
cd apps/windows-client && npm run build
Acceptance evidence:
- Build output recorded in
EVIDENCE.md. - Short note listing component contracts and CSS tokens/classes.
Parallel-safe: no. This establishes shared write scope.
Task 2: Replace Tabs And Basic Buttons
Allowed files:
apps/windows-client/src/app/App.tsxapps/windows-client/src/styles/app.cssapps/windows-client/src/ui/*
Scope:
- Replace local
renderTabsmarkup withTabs. - Replace header refresh, summary navigation buttons, route switch buttons, neutral/open buttons and add icon buttons with shared
Button/IconButton. - Preserve active panel state and current handlers.
Expected output:
- Tabs have consistent ARIA and keyboard behavior.
- Buttons share variants and loading labels.
- No behavior regression in panel switching or refresh.
Verification command:
cd apps/windows-client && npm run build
Acceptance evidence:
- Screenshot or DOM note showing tab ARIA/active state.
- Desktop screenshot showing migrated button variants.
Parallel-safe: no. Touches App.tsx and shared UI.
Task 3: Add Readiness Model And Gate Apply Actions
Allowed files:
apps/windows-client/src/app/readiness.tsapps/windows-client/src/app/App.tsxapps/windows-client/src/styles/app.css
Scope:
- Create pure helper functions for apply blockers and action labels.
- Replace always-green
renderApplyActionsbehavior with readiness-aware disabled/loading/blocker UI. - Keep
updateConfigvalidation as backend/handler safety, but do not let obviously blocked actions look ready.
Expected output:
- Apply disabled with explanation when ProxiFyre is missing, apps empty, external proxy invalid, local route lacks sing-box/server, or service/apply action is running.
- Primary green appears only when action is ready.
Verification command:
cd apps/windows-client && npm run build
Acceptance evidence:
- Screenshot/state showing disabled apply + blocker copy in missing ProxiFyre/empty apps preview state.
- Note that
updateConfigstill validates at action time.
Parallel-safe: no. Depends on shared buttons and touches core apply behavior.
Task 4: Implement ServiceControlRow And Migrate ProxiFyre
Allowed files:
apps/windows-client/src/ui/ServiceControlRow.tsxapps/windows-client/src/ui/ActionMenu.tsxapps/windows-client/src/app/App.tsxapps/windows-client/src/styles/app.css
Scope:
- Create generic
ServiceControlRow. - Migrate
renderProxiFyreCardand setup strip/details into this pattern. - Preserve install/start/stop/uninstall confirm boundary and loading states.
- Keep ProxiFyre setup checklist readable on narrow widths.
Expected output:
- ProxiFyre service state row uses the generic component.
- The old ProxiFyre-specific button/card markup is removed or demoted.
Verification command:
cd apps/windows-client && npm run build
Acceptance evidence:
- Desktop and narrow screenshots of ProxiFyre panel.
- Note showing one primary service action plus overflow menu.
Parallel-safe: no. Touches App.tsx, service UI and CSS.
Task 5: Migrate Local Sing-box To ServiceControlRow
Allowed files:
apps/windows-client/src/app/App.tsxapps/windows-client/src/styles/app.cssapps/windows-client/src/ui/ServiceControlRow.tsxapps/windows-client/src/ui/ActionMenu.tsx
Scope:
- Reuse
ServiceControlRowfor Local sing-box. - Preserve setup details, info popover/actions, subscription workspace, server list and install note.
- Keep Local sing-box controls only in VPN/Proxy context, unless already present by selected route.
Expected output:
- Local sing-box service controls visually and behaviorally match ProxiFyre.
- No duplicate service-control patterns remain for sing-box.
Verification command:
cd apps/windows-client && npm run build
Acceptance evidence:
- Screenshot of VPN/Proxy local route state or preview missing state.
- Note confirming ProxiFyre and sing-box share the same component.
Parallel-safe: no. Depends on Task 4.
Task 6: Friendly LogDock And Preview Error Handling
Allowed files:
apps/windows-client/src/ui/LogDock.tsxapps/windows-client/src/app/App.tsxapps/windows-client/src/styles/app.cssapps/windows-client/src/api/tauriCommands.tsonly if a tiny safe error-normalization helper is required.
Scope:
- Move log dock rendering into shared
LogDock. - Collapse/adapt it on narrow widths.
- Normalize preview/native
invokefailure to friendly title/text while preserving raw details in history. - Keep
aria-liveconcise.
Expected output:
- Main footer no longer shows raw
Cannot read properties of undefined (reading 'invoke')as primary text. - Narrow width does not hide the primary app task behind long raw error text.
Verification command:
cd apps/windows-client && npm run build
Acceptance evidence:
- Browser-preview screenshot showing friendly desktop-command message.
- Narrow screenshot showing adaptive/collapsed log behavior.
Parallel-safe: no. Touches global app surface.
Task 7: Extract Panel/View Helpers Without Moving Truth
Allowed files:
apps/windows-client/src/app/App.tsxapps/windows-client/src/app/viewModel.ts- Optional pure panel files under
apps/windows-client/src/app/panels/*if and only if prop boundaries are clear. apps/windows-client/src/styles/app.css
Scope:
- Extract pure view-model helpers for summary/system state, route labels, service labels and display copy.
- Optionally split large panel JSX into pure components that receive props/callbacks.
- Do not move Tauri command calls into presentational components.
- Do not create duplicate React state for profiles/targets/components.
Expected output:
App.tsxbecomes smaller and more orchestration-focused.- UI components stay reusable and business state remains in containers/helpers.
Verification command:
cd apps/windows-client && npm run build
Acceptance evidence:
- Note listing extracted helpers/components and confirming no duplicate truth path.
Parallel-safe: no. Refactor touches core composition.
Task 8: Motion, Responsive And CSS Cutover Cleanup
Allowed files:
apps/windows-client/src/styles/app.cssapps/windows-client/src/app/App.tsxapps/windows-client/src/ui/*
Scope:
- Replace one-off transitions with motion variables.
- Remove or privatize old selectors after migration.
- Ensure setup checklists wrap on narrow widths.
- Ensure text/path/server names wrap or truncate intentionally.
- Ensure no
transition: all.
Expected output:
- Consistent animation durations/easing.
- No layout overlap on 1280x720, 800x600, 420x720.
- Old ad hoc public selector families are not the dominant styling path.
Verification command:
cd apps/windows-client && npm run buildrg -n "transition:\\s*all|className=\"(apply-button|service-button|ghost-button|add-tile|open-config-button)" apps/windows-client/src
Acceptance evidence:
- Desktop + narrow screenshots.
rgoutput or note proving no new ad hoc button paths remain.
Parallel-safe: no. Final CSS integration pass.
Task 9: Final Verification And Evidence
Allowed files:
docs/goals/windows-client-service-control-ui-system/EVIDENCE.md
Scope:
- Record final build/test commands and outputs.
- Capture visual evidence for Summary, ProxiFyre, VPN/Proxy at desktop and narrow widths.
- Record interactive evidence for tabs keyboard behavior, disabled apply blocker, service action loading state and friendly preview error.
- Record any unverified native/elevated service operations as residual risk.
Expected output:
EVIDENCE.mdis sufficient for a reviewer to judge the user-facing outcome.
Verification command:
cd apps/windows-client && npm run build- If Rust/backend changed:
cd apps/windows-client/src-tauri && cargo test
Acceptance evidence:
- Evidence file filled with commands, screenshots/state notes and residual risks.
Parallel-safe: no.
PRE Review Prompt
Use C:\Users\PC\.agents\skills\krypton-planning\plan-reviewer-prompt.md with:
MODE: PRE
Plan file:
docs/goals/windows-client-service-control-ui-system/PLAN.md
Original request:
Составить план на основании UX/UI-аудита и уточнения, что Windows-клиент должен быть максимально простой service-control утилитой: управлять состояниями служб, устанавливать/удалять их, иметь нормальную компонентную базу для кнопок, табов, добавления, обновления, анимаций и loading states.
Outcome contract:
Windows-клиент становится service-control utility с shared UI foundation, readiness-gated actions, едиными tabs/buttons/service rows/log dock/motion tokens и evidence from target perspective.
Architecture slice:
Create `apps/windows-client/src/ui/*`, optional pure helpers under `apps/windows-client/src/app`, modify `App.tsx` and `app.css`, avoid backend/root web/server unless compile-only boundary fix is necessary.
Acceptance evidence requirement:
Build plus desktop/narrow visual proof of Summary, ProxiFyre and VPN/Proxy; disabled apply blocker; friendly preview error; shared service rows; keyboard/active tab behavior.
Known non-goals:
No backend rewrite, no installer changes, no root web/server changes, no full visual rebrand, no hidden component installation, no route-mode expansion.
Unsafe paths or layers:
Duplicating truth in React, putting Tauri calls in UI components, leaving old ad hoc button paths as dominant, showing raw invoke errors, making apply green while blocked, changing generated config directly.