Files
harbor-net/docs/goals/windows-client-service-control-ui-system/PLAN.md

26 KiB
Raw Blame History

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.tsx and 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.ts remains 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.tsx grows 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.tsx
  • apps/windows-client/src/ui/IconButton.tsx
  • apps/windows-client/src/ui/Tabs.tsx
  • apps/windows-client/src/ui/ServiceControlRow.tsx
  • apps/windows-client/src/ui/StatusPill.tsx
  • apps/windows-client/src/ui/Field.tsx
  • apps/windows-client/src/ui/ActionMenu.tsx
  • apps/windows-client/src/ui/LogDock.tsx
  • apps/windows-client/src/ui/index.ts
  • apps/windows-client/src/app/readiness.ts
  • apps/windows-client/src/app/viewModel.ts or smaller helpers if they reduce App.tsx without creating duplicate truth.

Files to modify:

  • apps/windows-client/src/app/App.tsx
  • apps/windows-client/src/styles/app.css
  • apps/windows-client/src/api/tauriCommands.ts only for compile-safe preview/error wrapper changes if needed.
  • apps/windows-client/src/domain/types.ts only if component/view-model types need shared aliases.
  • docs/goals/windows-client-service-control-ui-system/EVIDENCE.md during 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.tsx calls getSavedState, 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 updateConfig only when readiness says they are actionable.

Contract boundary:

  • Button owns variants/states/loading/disabled look, not business readiness.
  • ServiceControlRow owns layout for a service, not installing/starting logic.
  • Tabs owns keyboard behavior and active styling, not panel content.
  • LogDock owns display/collapse/history behavior, not logging policy.
  • readiness.ts owns 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:

  • renderTabs local tab button markup.
  • renderProxiFyreCard and renderSingBoxCard duplicated finder/service-card markup.
  • renderApplyActions always-green apply command row.
  • log-dock raw 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 with aria-label and title/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 opacity and transform.
  • 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.tsx
  • apps/windows-client/src/ui/IconButton.tsx
  • apps/windows-client/src/ui/Tabs.tsx
  • apps/windows-client/src/ui/StatusPill.tsx
  • apps/windows-client/src/ui/Field.tsx
  • apps/windows-client/src/ui/index.ts
  • apps/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.tsx
  • apps/windows-client/src/styles/app.css
  • apps/windows-client/src/ui/*

Scope:

  • Replace local renderTabs markup with Tabs.
  • 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.ts
  • apps/windows-client/src/app/App.tsx
  • apps/windows-client/src/styles/app.css

Scope:

  • Create pure helper functions for apply blockers and action labels.
  • Replace always-green renderApplyActions behavior with readiness-aware disabled/loading/blocker UI.
  • Keep updateConfig validation 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 updateConfig still 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.tsx
  • apps/windows-client/src/ui/ActionMenu.tsx
  • apps/windows-client/src/app/App.tsx
  • apps/windows-client/src/styles/app.css

Scope:

  • Create generic ServiceControlRow.
  • Migrate renderProxiFyreCard and 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.tsx
  • apps/windows-client/src/styles/app.css
  • apps/windows-client/src/ui/ServiceControlRow.tsx
  • apps/windows-client/src/ui/ActionMenu.tsx

Scope:

  • Reuse ServiceControlRow for 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.tsx
  • apps/windows-client/src/app/App.tsx
  • apps/windows-client/src/styles/app.css
  • apps/windows-client/src/api/tauriCommands.ts only 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 invoke failure to friendly title/text while preserving raw details in history.
  • Keep aria-live concise.

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.tsx
  • apps/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.tsx becomes 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.css
  • apps/windows-client/src/app/App.tsx
  • apps/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 build
  • rg -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.
  • rg output 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.md is 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.