# Frontend React / Vite / Design ## Source Of Truth Frontend visual and interaction design uses the installed `frontend-design` skill as the primary design authority. `docs/产品设计规则.md` remains a product experience and business-boundary fact source, not a visual, brand or aesthetic rulebook. For PC/mobile/WeCom pages, add Playwright or visual verification when reasonable. This spec keeps hyb-oa-specific React/Vite, shared-component, business-boundary and verification contracts. Do not copy broad aesthetic guidance from `frontend-design` into this file; use the skill directly for design judgment. ## Rules - Use existing React/Vite/Tailwind patterns and shared components before adding page-local UI systems. - When `frontend-design` and older project visual rules conflict, follow `frontend-design` for visual direction while preserving security, privacy, Trellis, deployment and business data boundaries. - Default product framing is a small-team Chinese workbench for domestic tech startups with fewer than 10 people. User-facing copy should be natural Chinese; avoid English product words such as `Portal`, `Dashboard` and `Workflow` unless they are internal test fixtures or technical identifiers. - PC pages should keep dense but orderly OA layouts: clear header, filters, table/list, status, details and predictable actions. - Mobile pages must reuse the existing unified mobile shell, card/list rows, safe-area and sticky action patterns unless the current task intentionally redesigns them with `frontend-design`. - Do not add decorative landing-page styling to operational OA pages. - Run `cd client && npm run typecheck && npm run build` for frontend changes. ## Frozen / Boundary Items Frozen modules and Enterprise WeChat-owned HR/attendance entries must be labeled or hidden according to the current Trellis task; do not silently re-enable them. - Use the shared `WorkspaceNotice` pattern for trial boundaries, safety notes, and post-trial capabilities instead of page-local warning blocks. - Trial-facing PC lists must hide obvious TEST/SMOKE records by default when a page-level toggle exists; the toggle may reveal them for troubleshooting. ## Scenario: Business Flow Tests And Frozen Modules ### 1. Scope / Trigger - Trigger: Playwright or QA shell tests need to create workflow data while some product modules are frozen for launch. - Applies to `client/tests/e2e/**`, `scripts/qa/run-business-flow-gates.sh`, and frontend route/permission assertions. ### 2. Signatures - QA command: `BUSINESS_FLOW_GROUPS= bash scripts/qa/run-business-flow-gates.sh local`. - Frozen-module API expectation: non-admin launch roles may receive `403` for frozen module list/create/submit endpoints. - Enabled workflow test data sources should use active entities such as leave, reimbursement or procurement unless the task explicitly reopens the frozen module. ### 3. Contracts - Do not use a frozen module as fixture setup for an unrelated enabled feature. Example: mobile approval offline sync should not create a travel request when travel permissions are intentionally frozen. - Permission direct-access tests must assert the frozen contract directly, such as employee `GET /api/travel-requests?...` returning `403`. - UI route smoke may still verify that a frozen page displays a boundary state without entering a management or write-capable mode. - Do not loosen roles or seed permissions merely to make old E2E data setup pass. ### 4. Validation & Error Matrix - Frozen role calls frozen module create/submit/list endpoint -> `403` or the documented feature-gate status. - Enabled workflow feature needs pending task data -> create data through an enabled workflow entity. - E2E fails with `PERM_001` while setting up unrelated feature data -> update the test data source before changing app permissions. ### 5. Good/Base/Bad Cases - Good: mobile approval offline test creates a submitted leave request, then verifies pending-task deep link, offline queue, sync success and conflict. - Base: travel-specific tests are skipped or admin-scoped while travel remains frozen. - Bad: grant employee `travel.create` only so a mobile approval test can build a fixture. ### 6. Tests Required - Focused E2E group that previously failed. - Full affected business-flow group after the focused fix. - `cd client && npm run typecheck && npm run build` when TypeScript test code changes. ### 7. Wrong vs Correct #### Wrong ```ts await createSubmittedTravelRequestViaApi({ user: EMPLOYEE }); ``` #### Correct ```ts await createSubmittedLeaveViaApi({ user: EMPLOYEE }); ``` ## Convention: PC Operation List Density **What**: PC list/workflow pages that combine status metrics, tabs/filters, range controls, export and table/list content should reuse the shared operation classes in `client/src/index.css`: - `ops-status-strip` for compact status metrics. - `ops-command-bar`, `ops-command-bar__row`, `ops-command-bar__tabs`, `ops-command-bar__actions` and `ops-filter-label` for tabs, filters and secondary actions. - `ops-table-focus` for the primary desktop table container. - `ops-inline-alert` for temporary mode hints such as batch operation notices. - `PrimaryTable` already applies `ops-table-focus` by default; page code may add responsive visibility classes such as `hidden md:block`, but should not recreate a separate table frame. - Finance/admin status summaries should prefer the shared `finance-status-strip` and `finance-metric-card` classes unless the task introduces a new reusable metric component. **Why**: This keeps high-frequency PC pages dense and predictable without recreating page-local Tailwind command bars. It also lets `frontend-design` change the visual treatment once while preserving component contracts. **Example**: ```tsx
待处理
...
... ``` **Tests Required**: - `cd client && npm run typecheck` - `cd client && npm run build` - Focused Playwright screenshot coverage when changing login, Portal, primary PC list pages or command-bar/table styling. ## Convention: Global Shell And Page Header Baseline **What**: PC page redesigns should preserve the shared Wave0-2 shell and header baseline instead of recreating page-local wrappers: - `AppShellLayout` owns the PC shell background and content offset through `app-shell` and `app-shell-main`. - `Sidebar` and `NavLinks` own role-aware task navigation. The mental model is a short primary task list plus collapsed `更多`; management configuration is represented by one `管理` entry instead of many sidebar rows. - `Topbar` is a compact command surface: page title, group badge, user context, global search and notifications. Do not expand it back into a large hero. - `PageHeader` and `WorkspaceHeader` should use `page-header-shell`, `page-header-shell__eyebrow`, `page-header-shell__title`, `page-header-shell__subtitle` and `page-header-shell__actions`. - Auth guidance and step hints may use `ux-command-note`, `ux-step-list` and `ux-step-item` when they explain the next action without adding page-local warning cards. **Why**: The shell/header baseline gives Wave3-5 pages a stable visual entry point and prevents each route from inventing a different title/action layout. **Navigation Rules**: - Sidebar entries should be role-aware and task-first for domestic tech startups under 10 people; do not expose all permission-allowed modules as a default module catalog. - Approvers see `待我处理`; ordinary employees should not see `待办` or `审批待办` in the sidebar by default. - PC leave navigation uses `请假记录` unless the current task explicitly opens OA emergency leave submission. - `个人设置` stays in the topbar account menu. Notifications stay in the topbar bell and notification center. - Finance labels should use work names such as `付款`, `应付账款` and `票据`; internal platform words like `AP 运营`, `ERP 集成` and `功能开关` should be hidden behind management wording or renamed for users. - `更多` is a lightweight collapsed row for low-frequency entries; do not add a sidebar explanation card, subtitle or onboarding copy around it. - Playwright navigation helpers should use exact names or anchored regex for short sidebar labels such as `管理`, otherwise fuzzy role-name matching can click longer labels such as `预算管理`. **Example**: ```tsx ``` **Tests Required**: - `cd client && npm run typecheck` - `cd client && npm run build` - Focused Playwright coverage when changing `AppShellLayout`, `Sidebar`, `Topbar`, `NavLinks`, `PageHeader`, `WorkspaceHeader`, login, Portal or other A-class pages. ## Convention: A-Class PC Task-First Pages **What**: A-class PC pages such as Portal, approvals, reimbursement list and reimbursement detail should make the current user task obvious before exposing secondary operations: - Treat the primary persona as a small-team operator wearing multiple hats, not a dedicated OA clerk. The first screen should reduce decision cost for a founder, finance/admin owner, project lead or employee who may switch roles during the same session. - First visible task surface should answer: what needs attention, what can be started, and where recent progress lives. - Keep one primary action in the first screen. Allow at most two secondary entries; move export, batch, delete, templates, complex filters, statistics and admin/finance tools into `更多`, `高级 / 台账`, detail actions, role-only panels or confirmation dialogs. - Do not turn small-team workflows into platform-builder surfaces by default: approval designers, broad configuration matrices, multi-level enterprise dashboards and batch admin consoles need explicit Trellis task scope. - Explanation text should only be default-visible for risk, exception or empty states. Do not use repeated subtitles or notice cards to explain normal workflow steps that the layout can express. - Low-frequency capabilities are hidden or moved, not removed, unless the current Trellis task explicitly deletes the capability. - Portal/workbench first screen should use a compact status summary plus `今日待处理`; do not use a persistent welcome hero, fixed `报销进度` button, general announcement feed, or folded placeholder sections such as `团队与通知`, `角色重点` or `试点观测摘要`. - Workbench sections after `今日待处理` must be conditional: `团队卡点` only for real blockers, `管理提醒` only for real admin/trial issues, and `我的进度` only for reliable status updates. Empty data should disappear, not render as collapsed drawers or statistic cards. - Each workbench action row should state what the item is, why the current user is involved, current status/timing, and one next action. Do not represent raw application counts as progress unless the payload includes an actionable or status-level signal. - PC reimbursement list defaults to the initiator's own forms even for users with finance/approval roles. The first screen may use task cards for rejected corrections, drafts and reviewing progress; ledger/export/batch, proxy submit, templates and travel-linking remain secondary and must be hidden unless the current user has a real matching capability. Row workflow copy should distinguish `待你处理` from read-only `当前节点`. **Why**: hyb-oa serves small teams with overlapping roles. Core pages must make the next click clear for ordinary employees and approvers, while keeping finance and admin tools available without dominating the default path. **Tests Required**: - `cd client && npm run typecheck` - `cd client && npm run build` - Focused Playwright or screenshot checks for changed A-class PC pages, asserting the task surface, primary action and secondary/advanced entry behavior. ### Convention: Approval Task List Defaults **What**: PC approval task lists such as `/workflow/tasks` should make `查看处理` the default row action. List-level `通过` is only a secondary shortcut for low-risk items where the row itself carries enough decision context. **Contracts**: - The row must answer what the item is, who requested it, why it is assigned to the current user, how long it has waited, and the public business reference. - History entry text should be explicit, such as `已处理记录`; avoid user-facing `高级 / 历史` on the default task surface. - Time labels should prefer `已等待多久` and `接收于` over database-shaped labels such as `更新时间` when the source field is task creation/arrival time. - A quick `通过` button may appear only when the task is pending, the server allows `approve`, the item is a low-risk leave/attendance task, required row summary fields are present, and the task has not exceeded the pending window available to the frontend. Reimbursement, procurement, travel, contract and other amount/evidence-heavy tasks should route through `查看处理` first. - The confirm dialog for list quick approval must still explain action consequences and include the specific task summary. **Why**: Small-team approvers need to clear work quickly without training themselves to approve financial or evidence-heavy items from an under-specified row. ## Convention: Workbench Onboarding And Profile Scope **What**: PC workbench and account settings should stay task-first, not become training or permission-maintenance surfaces: - Do not add a persistent `快速上手` / onboarding checklist to the workbench by default. If first-login guidance is needed, use a dismissible welcome dialog with at most three real business entries. - Welcome or onboarding entries must point to executable user tasks, such as `处理待办`, `提交报销` or `请假`; do not use explanatory entries like `了解流程`, and do not route users to settings or notifications as a substitute for task guidance. - `个人设置` default content is account identity, notification preference and Enterprise WeChat binding. Organization, report line and role summary may be folded under `账号详情`; permission code lists and full employee dossier fields stay out of the default view. **Why**: Small teams need fewer default decisions. Persistent onboarding and permission-heavy profile pages make ordinary users inspect system internals before doing work. **Tests Required**: - Focused Playwright coverage for changed workbench or profile routes. - Screenshot evidence for first-login welcome, workbench first screen and profile default view when changing these surfaces. ## Convention: Detail And Mobile Command Surfaces **What**: PC detail pages and notification-like flows should reuse the Wave3 surface classes in `client/src/index.css` before adding page-local Tailwind card systems: - `detail-workspace-grid` for the main PC detail two-column workspace. - `detail-command-panel`, `detail-fact-grid` and `detail-fact-card` for compact status, summary, payment, export and evidence facts. - `detail-evidence-card` for attachments, invoices and other proof material. - `detail-timeline` and `detail-timeline-item` for approval progress and history. - `detail-action-stack` and `detail-action-card` for approve/reject/return, payment and other high-risk command groups. - `notification-inbox`, `notification-row-card` and `notification-row-card--unread` for PC notification streams; avoid reverting notifications to a desktop table unless a task explicitly requires tabular comparison. Mobile key pages should reuse the mobile command classes in `client/src/styles/mobile-touch.css`: - `mobile-focus-card` for the current task, current list or account summary. - `mobile-command-surface` for tabs, search and filters. - `mobile-list-card--focus` and `mobile-list-card--unread` for state emphasis. **Why**: Detail pages should feel like quiet command surfaces: status, summary, primary action, evidence and history have predictable places. Mobile pages should stay card/list based, with no PC tables, no horizontal overflow and no button text squeeze. **Tests Required**: - `cd client && npm run typecheck` - `cd client && npm run build` - Focused Playwright screenshot coverage for changed PC detail, notification and mobile pages. - UI design rules check when changing shared visual classes. ## Scenario: Auth Pages And PWA Updates ### 1. Scope / Trigger - Trigger: login, password change, password recovery or other unauthenticated forms are active while the PWA service worker finds a new frontend version. - Applies to `client/src/pwa.ts`, `client/src/layouts/AuthLayout.tsx`, and auth routes such as `/login`, `/change-password`, `/forgot-password`, and future reset-password pages. ### 2. Signatures - Event name: `hyb-oa:pwa-update-ready`. - Event detail: `{ applyUpdate?: () => void | Promise }`. - Route predicate: auth input pages must be checked by pathname before calling `updateServiceWorker(true)`. ### 3. Contracts - Auth input pages must not auto-reload when `onNeedRefresh()` fires. - Auth input pages must show an explicit update prompt with a user-triggered refresh action. - Non-auth pages may keep automatic service-worker update behavior when the task does not change broader runtime policy. - Passwords and verification codes must stay only in React component state; do not write them to `localStorage`, `sessionStorage`, URL params, reports, or Trellis task evidence. - Password visibility controls must use icon buttons with accessible labels and preserve the current input value. ### 4. Validation & Error Matrix - PWA update on `/login` -> dispatch update-ready event and keep form state. - PWA update on `/forgot-password` -> dispatch update-ready event and keep email/code/password fields in memory. - User clicks refresh in the prompt -> run the captured update handler. - User dismisses prompt -> no reload and no form reset. - Password reset request returns success for any email -> show generic sent message; do not reveal whether the account exists. ### 5. Good/Base/Bad Cases - Good: user is typing a password, update prompt appears, typed values remain. - Base: user is on a normal portal page, PWA update can refresh per existing runtime behavior. - Bad: service-worker update auto-refreshes an auth form and clears credentials. - Bad: tests use real-looking personal email addresses or persist example passwords outside the test file. ### 6. Tests Required - Frontend typecheck and build. - Focused Playwright auth UX test asserting: - login password can be shown/hidden without losing value; - forgot-password flow calls request-code and reset endpoints; - auth-page PWA update prompt appears without clearing inputs. - UI design rules check when auth page layout changes. - Any Playwright test that renders `/login`, `/forgot-password` or another auth route with mocked `/api/*` responses must mock `/api/auth/capabilities` with `emailDelivery.ready`, `emailLoginCode.enabled` and `passwordReset.enabled`. Returning `{}` for unknown auth APIs can crash auth pages before the visual or navigation assertion actually runs. ### 7. Wrong vs Correct #### Wrong ```ts onNeedRefresh() { void updateServiceWorker?.(true); } ``` #### Correct ```ts onNeedRefresh() { if (isAuthInputPath(window.location.pathname)) { window.dispatchEvent(new CustomEvent(PWA_UPDATE_READY_EVENT, { detail: { applyUpdate } })); return; } applyUpdate(); } ``` ## Scenario: Auth Page Layout And Login Entry Hierarchy ### 1. Scope / Trigger - Trigger: login, password recovery, forced password change or future unauthenticated auth forms need layout changes. - Applies to `client/src/layouts/AuthLayout.tsx`, shared auth components under `client/src/components/auth/`, and auth routes such as `/login`, `/forgot-password` and `/change-password`. ### 2. Component Contract - Auth routes should use one shared auth panel for brand, page title, subtitle, content and optional footer links. - `AuthLayout` owns only the auth page shell: background, width constraint, centering, PWA update prompt and route outlet. - Page implementations own only their form fields, submit actions, validation messages and route-specific login-entry choices. ### 3. Visual Contracts - Do not nest a form card inside another login card. - Put the brand block inside the auth panel so logo, system name, title and form share one visual axis. - Keep the panel width stable around the current auth-shell width; auth pages should feel like an OA workstation entry, not a marketing split hero. - Place `忘记密码?` beside the password label or directly below the password input on the right; do not bury it in help text or page footer. - Keep the DOM/tab order aligned with the main form flow even when CSS places `忘记密码?` visually beside the password label: username/email input -> password input -> secondary controls. Do not render the forgot-password link before the password input in DOM order. - Use password visibility icon buttons with accessible labels and preserve the current input value. ### 4. Login Entry Hierarchy - Normal browser: account/password login is primary; Enterprise WeChat and OIDC entries belong below the primary submit button as secondary methods. - Enterprise WeChat WebView: Enterprise WeChat one-click entry is primary; account/password login remains available as the fallback path. - Enterprise WeChat entry changes must remain frontend entry hierarchy changes unless the task explicitly approves backend OAuth, binding or WeCom API work. - Email verification-code login is a separate login mode. Do not infer it from password-recovery verification-code flows without a backend login-code contract and abuse-control plan. ### 5. Tests Required - Frontend typecheck and build. - Focused auth E2E covering: - password visibility and forgot-password navigation on `/login`; - keyboard Tab from the username/email field lands on the password input, not the forgot-password link; - password recovery request-code and reset flow on `/forgot-password`; - normal-browser Enterprise WeChat entry as secondary CTA; - WeCom WebView Enterprise WeChat entry as primary CTA with password fallback. - UI design rules check and Playwright screenshot evidence when the auth layout changes visibly. ### 6. Wrong vs Correct #### Wrong ```tsx ``` #### Correct ```tsx ``` #### Wrong ```tsx 忘记密码? ``` #### Correct ```tsx 忘记密码? ``` ## Convention: Finance And Admin Console Surfaces **What**: PC finance and C-class admin pages should reuse Wave4 shared classes from `client/src/index.css` before creating page-local card/table layouts: - `finance-status-strip`, `finance-metric-card`, `finance-metric-card__label` and `finance-metric-card__value` for compact five-column status summaries. - `finance-workspace-grid`, `finance-command-panel`, `finance-list-card` and `finance-list-card--active` for payment/AP/invoice operational workspaces. - `admin-command-panel`, `admin-tile-grid`, `admin-tile-card` and `admin-workspace-grid` for settings, workflow, feature-flag, user, master data, notification-channel and audit pages. **Why**: Finance/admin pages are lower-frequency but high-risk operational surfaces. They need dense scanability, stable command regions and clear risk hierarchy without turning every page into a bespoke Tailwind card system. **Example**: ```tsx
可处理
{actionableCount}
...
...
``` **Tests Required**: - `cd client && npm run typecheck` - `cd client && npm run build` - Focused Playwright coverage for changed finance/admin pages. The Wave4 baseline test is `client/tests/e2e/pc-finance-admin-visual-wave4.spec.ts`. - UI design rules check when changing these shared classes.