feat: merge workspace web UX demo

This commit is contained in:
2026-09-18 17:41:10 +09:00
53 changed files with 3586 additions and 490 deletions
@@ -0,0 +1,104 @@
# Workspace Web Application Architecture
この文書は、Workspace Webのapplication shell、Header、Sidebar、nested
layoutのcomposition authorityを定義する。Navigation
IAは[`product-ux.md`](product-ux.md)、視覚とinteractionの共通規則は[`design-language.md`](design-language.md)、具体的なsource
pathとCSS
ownershipは[`../../../web/workspace/README.md`](../../../web/workspace/README.md)を参照する。
## Application shell
root layoutが唯一のapplication shellを所有する。
- Sidebar frame
- global fallback navigation
- Header frame
- main content
- SidebarとHeaderのoverride context
page routeはapplication shell、global Header、Sidebar、fold
controlを再実装しない。Pageのmarkupは標準shellのmainへ配置するcontentから始める。
## Header composition
Headerはroot shellが一度だけrenderする。Nested
layoutは`HeaderOverride`を通じて現在scopeのlocation contentを登録する。
- page componentはHeader frameを作らない。
- 最も深いactive overrideを表示する。
- layoutが破棄されたら直前のoverrideへ戻る。
- overrideがなければroot fallbackを表示する。
- route titleをmain contentへ複製しない。
## Sidebar composition
### Root
root shellは`SidebarFrame`と`GlobalSidebar`を一度だけrenderし、root
`SidebarController`を提供する。Overrideがない場合、`GlobalNavSections`がfallbackになる。
### Workspace
Workspace layoutは、親のroot
slotへ`WorkspaceSidebar`を登録する。同時に、さらに深いlayoutが使う新しい`SidebarController`をcontextへ設定する。
`WorkspaceSidebar`はWorkspace shortcut headerを保持し、その下へchild
slotをrenderする。Child overrideがない場合だけ、Workspace navigation
fallbackを表示する。
### Settings
Settings layoutは、Workspace layoutが提供したchild
slotへ`SettingsSidebar`を登録する。Workspace shortcut headerは残り、Workspace
navigation fallbackだけがSettings navigationへ置き換わる。
さらに深いscopeも同じcontractを使う。
## Override stack
`HeaderOverride`と`SidebarOverride`は、layout lifecycleにbindしたLIFO
stackとして扱う。
1. Layout mount時にparent controllerへregisterする。
2. Controllerは最も新しいactive registrationを表示する。
3. Nested layoutはchild controllerを新しく提供する。
4. Layout destroy時に自分のregistrationをremoveする。
5. 一つ前のregistrationがあれば復元する。
6. Stackが空ならfallbackへ戻る。
同じregistrationを複数回removeしても結果を変えない。古いcleanupが新しいactive
registrationを削除してはならない。
## Ownership
- `SidebarFrame`だけが`aside`、外枠、scroll領域、fold controlを所有する。
- `GlobalSidebar`、`WorkspaceSidebar`、`SettingsSidebar`は各scopeのcontentを所有する。
- `SidebarOverride`を登録できるのはscopeを定義するlayoutだけとする。
- page component、一時的なwidget、dialogはSidebarを差し替えない。
- child layoutは親navigationをcopyせず、自分のsidebar layerだけをregisterする。
- Global、Workspace、Settingsを一つのsnippetへ平坦化しない。
## Data authority
Sidebar compositionはnavigation
structureを決めるが、Workspace、permission、Worker
stateのauthorityにはならない。
- Workspace identityとpermissionはBackend projectionを使う。
- Worker listとstateはWorkspace protocol projectionを使う。
- route pathやdisplay labelからauthorityを推測しない。
- unavailable dataを架空の正常stateで置き換えない。
- permissionにより利用できないnavigationは、権威あるpermission
projectionに基づいて除外する。
## Design-lab
認証不要のstatic design-labはroot shellを再利用し、実際と同じnested
controllerとoverride stackを構成する。
Live Workspace protocolへbindするresource listだけは、同じscope layer内のstatic
fixtureへ置き換えてよい。Static fixtureへ別scopeのnavigationを混ぜず、production
componentと同じ順序、state表現を使う。
Design-lab固有のswitch controlでSidebarを差し替えず、route
hierarchyによってlayout lifecycleを発生させる。
+196
View File
@@ -0,0 +1,196 @@
# Workspace Web Design Language
この文書は、Workspace Webのrendered resultが満たす設計規則を定義する。Product固有のresource構成は[`product-ux.md`](product-ux.md)、application shellとSidebar slotの実装構造は[`application-architecture.md`](application-architecture.md)、CSSとsource配置は[`../../../web/workspace/README.md`](../../../web/workspace/README.md)、visual review手順は[`visual-review.md`](visual-review.md)をauthorityとする。
一つの規則は最も具体的な一箇所だけをauthorityとする。具体的な二案の一方を棄却できない文は規則として残さない。
## 1. Principles
複数の規則や要求が競合した場合だけ、この章の優先原理を使う。
### Task before explanation
次の有効なactionへ到達する前の操作、scroll、常設説明が少ない案を選ぶ。ただし、説明を省くと対象、結果、permission、不可逆性を誤認する場合は説明をactionより前に置く。
### Meaning before decoration
情報の関係、重要度、操作可能性、stateのいずれも変えない視覚差を追加しない。
### Authority before convenience
Backend authorityが確定していないdata、state、permission、actionを、UIの都合で補完または推測する案を棄却する。
## 2. Semantics / Grammar
### Information structure
- pageと、page内で一つのtaskまたは判断を完結させる領域をscopeとする。
- 各scopeで最も強い視覚要素はheading、現在判断が必要なattention、filled actionのいずれか一つだけにする。同じ強さのheading、attention、filled actionを複数置かない。
- hierarchyをcolorだけで表現しない。DOMと画面上の配置順を一致させた上で、size、weight、contrastを使う。
- scopeを識別するprimary titleは、一つのscopeにつき一度だけ表示する。
- actionは、そのactionが影響するscope内に置く。
- DTOにfieldが存在するという理由だけで表示せず、current taskの判断またはactionを変える値だけを常設する。
**Disclosure**
- Raw dataやデバッグ情報など、通常は必要としない詳細な情報は折りたたみ領域に隠す。
- 作成または編集のformを表示用screenへ常時同居させず、明示的なactionで開く折りたたみ領域または別pageに置く。
### Interaction and state
- actionにはbutton、navigationにはlink、選択には対応するform controlを使う。
- interactive elementはhover、focus、active、disabledを視覚的に区別する。
- staticなstatus、key、metadataをbuttonやpillの形にしない。
- clickable rowは遷移先を一つだけ持ち、row全体で同じ遷移を実行する。
- permissionがないactionをdisabled controlとして表示しない。
**State and operation**
- stateの違いによってユーザーの判断または利用できるactionが変わる場合、その違いを一つの表示へ統合しない。
- UI stateはそのstateを所有するauthorityから取得し、別domainやtransportのsignalから推測しない。
- 非同期mutationでは楽観的更新か悲観的更新を選ぶ。楽観的更新は暫定stateを明示し、failure時のrollbackまたは再取得を定義できる場合だけ使う。それ以外は確定済みstateを維持し、operationのpending stateを別に表示する。
- loading、failure、unavailableの表示は利用不能になった最小のscopeだけを置き換え、利用可能な親scopeとsibling scopeを残す。
- destructive actionは対象と結果を明記し、復元できない場合だけconfirmationを要求する。
### Language / Copy
- title、navigation label、control labelで明らかな内容を説明文で繰り返さない。
- 常設proseは、対象またはactionの選択を変えるwarning、permission、validation constraint、error recoveryに必要な内容だけにする。
- button labelには具体的なactionを表す動詞を使い、`Submit`と`OK`を使わない。
- identifier、API名、type名を別の語へ言い換えない。
### Responsive behavior
- page全体にhorizontal scrollを発生させない。
- wrappingまたはstack化によって情報の対応関係が失われる場合だけ、その領域内にbounded horizontal scrollを持たせる。それ以外のside-by-side layoutは一列にする。
- primary actionを初期viewportから追い出さない。
- contentをtruncateする場合、完全な値をcopyまたはdetailで取得できるようにする。
### Accessibility
- action、navigation、form controlを非semantic elementだけで実装しない。
- すべてのcontrolにaccessible nameを与える。
- keyboard focusを不可視にしない。
- tab orderを画面上の順序と一致させる。
- stateをcolorだけで区別しない。
- horizontal scroll regionをkeyboard focus可能にし、accessible nameを与える。
## 3. Primitives / Tokens
### Color / Theme
colorはCSS custom propertyをauthorityとし、通常のWorkspace colorはOKLCHで定義する。lightとdarkは同じsemantic token名を使う。
```css
--bg
--bg-raised
--bg-subtle
--line
--line-strong
--text
--text-strong
--text-muted
--text-faint
--code
--accent
--accent-muted
--success
--warning
--danger
--interactive-hover
--interactive-selected
--shadow-overlay
```
- `--bg`、`--bg-raised`、`--bg-subtle`へhueを持たせない。
- accentはfocus、current navigation、current selectionだけに使い、通常本文や通常actionの背景へ使わない。
- success、warning、dangerを、それぞれ対応するstate以外へ使わない。
- componentへraw colorを追加せず、上記semantic tokenを使う。
- ConsoleとterminalのANSI paletteを通常のstatusやformへ流用しない。
### Typography
font sizeは、その領域でユーザーが行う読み方によって選ぶ。
- defaultは`14px / 20px`とし、個々のtextを読むこと自体がtaskの中心になる領域に使う。
- 同じ構造の反復を一覧として走査する領域と、位置、順序、形、選択状態を中心に識別するUI chromeには`12px / 16px`を使う。textを読まなければactionの意味や結果を判断できない場合は`14px / 20px`を使う。
- `24px / 32px`はページまたはdocument内で唯一かつ最大のheadingだけに使う。
- 収めるため、または情報を弱く見せるためにfont sizeを下げない。`12px`未満と`13px`を使わない。
- 機械的な値にはmonospace familyを使う。
```css
--font-sans
--font-mono
--font-size-title /* 24px */
--line-height-title /* 32px */
--font-size-body /* 14px */
--line-height-body /* 20px */
--font-size-compact /* 12px */
--line-height-compact /* 16px */
```
### Spacing / Shape
```css
--space-1 /* 4px */
--space-2 /* 8px */
--space-3 /* 12px */
--space-4 /* 16px */
--space-5 /* 24px */
--space-6 /* 32px */
--radius-soft
```
- 一つの境界にspacing、line、surface backgroundを重ねず、primary cueを一つだけ使う。
- 汎用的な`Card` primitiveを設けない。
- nested surfaceでparentと同じ境界表現を繰り返さない。
- shadowは通常flowから浮くmenu、popover、Tooltipだけに使う。
- radiusはinteractive controlだけに使う。
### Motion
- motion完了をactionの受付、state change、content理解の条件にしない。
- 繰り返しまたは連続animationを、`prefers-reduced-motion: reduce`で停止する。
## 4. Components / Patterns
### Border / Structural edge
- `Bevel`は1pxの単色borderを描くvisual wrapperであり、照明、raised/inset、ridge/grooveを表現しない。
- `Bevel`自体へbackgroundやsurface toneを与えず、必要なbackgroundは内側のsemantic childが持つtext/content areaへ適用する。
- 隣接するsurfaceでは、実際に境界となる辺だけを有効にする。
- standaloneな閉じた領域は全辺を`Bevel`で囲う。Desktop shellではHeaderのbottom edgeとSidebarのright edgeだけを有効にし、viewport外周のtop/left edgeを描かない。
- `BevelLine`は開いた領域内の1px separatorだけに使う。同じlayerではheading、本文、Lineの端を揃え、Lineだけに端方向のpaddingやmarginを追加しない。
- nested layerでは親layoutがそのlayer全体へinline方向の余白を与え、content、row、Lineを一緒に移動する。Lineだけを短くしない。
- control自身のborder、focus ring、status marker、table gridを`Bevel`または`BevelLine`で置き換えない。
### Sidebar
- Desktop幅は`clamp(220px, 20vw, 280px)`とする。
- navigation contentだけをscrollさせる。
- Desktopのfold controlはSidebar下部、Mobileのfold controlはHeaderに置く。
- MobileでSidebarを表示するときはHeader下の残りviewport全体を使い、main contentと同時表示しない。
- navigationとscope control以外を置かない。
- navigation linkはSidebar幅全体を使うflat rowとする。
- active routeは一つの視覚cueと`aria-current="page"`で示す。
- iconだけでnavigation labelを置き換えない。
- fold controlは一つだけ置き、current stateに対応するaccessible nameを使う。
### Tooltip / Contextual help
- operationやtable全体を説明する常設proseを置く前に、button labelとcolumn headingだけで識別できるようにする。
- labelだけでは表現できない補助説明だけを、対象へbindしたTooltipに入れる。
- pointer hoverとkeyboard focusの両方で開く。
- triggerとTooltipを`aria-describedby`で関連付ける。
- hoverはdelay後、focusは直ちに表示する。
- `Escape`で閉じ、triggerからfocusを移動しない。
- 複数paragraph、form、link、buttonを入れない。
- error、permission、validation constraint、不可逆操作の結果、current stateをTooltipへ入れない。
- touch環境ではTooltipだけを説明への到達手段にしない。
### Generic component patterns
- **Form field**: label、control、constraintまたはhelp、field errorの順に配置する。
- **Key-value**: 一つのresourceの属性には`dl`を使う。
Design-labではcomponent名と実際のsampleだけを表示する。規則とrationaleをUIへ書かない。
+143
View File
@@ -0,0 +1,143 @@
# Workspace Web Product UX
この文書は、Workspace Webで扱うresource、navigationのinformation
architecture、resourceごとの主要taskを定義する。見せ方の共通文法は[`design-language.md`](design-language.md)、application
shellとSidebar
slotは[`application-architecture.md`](application-architecture.md)を参照する。
## Product position
Workspace
Webは、Workspace内の権威ある状態を確認し、注意が必要な箇所を判断し、一度に一つの操作を行うための作業面である。Marketing
dashboard、analytics画面、Backend DTOのraw viewerにはしない。
基本的な操作の流れは次とする。
```text
scopeを選ぶ
→ resourceを選ぶ
→ current stateを確認する
→ 次の有効なactionを行う
→ 結果を確認する
```
## Resource
主要resourceは次のとおり。
- Workspace
- Ticket
- Objective
- Merge Request
- Memory
- Worker
- Workdir
- Runtime
- Repository
通常の表示とURLにはcanonical resource keyを使う。内部UUIDをlabelやfallback
linkとして露出しない。
## Navigation IA
### Global
Workspaceを選ぶ前のscopeを扱う。
- Workspace catalog
- Account
- Device Login
- Workspace作成
### Workspace
一つのWorkspace内で日常的に扱うresourceを置く。
1. Tickets
2. Objectives
3. Merge Requests
4. Memory
- Document
- Staging
5. Workers
### Settings
Workspaceの管理と構成を扱う。
- Runtimes
- Configuration Sources
- Repositories
- Repository Access
- Profile Sources
- Workspace Identity
`Runtimes`、`Repositories`、`Repository Access`をWorkspace primary
navigationへ混ぜない。permissionにより利用できないSettings itemは表示しない。
## Page model
各routeは、主要な目的を一つだけ持つ。その目的は「Ticketを選ぶ」「このWorkerを確認する」「Repository
accessを設定する」のように、動詞と対象を一つずつ使って表現できなければならない。
Workspace pageは、次のいずれかを基本形とする。
1. **一覧またはboard** — resourceを探し、注意が必要な項目を見つける。
2. **詳細** — 一つのresourceを理解し、現在実行できる次の操作を行う。
3. **formまたはeditor** — 範囲の明確な設定変更を行う。
4. **Console** — 一つのWorkerを操作しながら、履歴とcurrent controlを確認する。
同じ目的を支える場合に限り、一つのrouteで複数の基本形を組み合わせてよい。
## Product pattern
### Tickets
- boardを一つの横方向の作業面として扱う。
- laneはworkflow stateを表し、隣接laneとの関係を維持する。
- Ticketはlane内でDesign Languageの`Resource row` patternを使う。
- Ticket key、title、優先判断を変えるmetadataだけを表示する。
- blockerとattentionはtextでも示す。
- narrow viewportでは、bounded horizontal scrollでlane比較を維持する。
### Resource index
- 同じfieldをresource間で比較する場合、flat listまたはtableを使う。
- 人が読むnameとcanonical keyを最初のcolumnに置く。
- columnは判断に必要な値だけに絞る。
- provider detail、revision、digestはdetailまたはtechnical disclosureへ移す。
### Resource detail
- identity、current state、attentionを最初に置く。
- narrativeまたはhistoryをprimary領域に置く。
- relation、target、review、workflowが別のauthorityを持つ場合、それぞれを独立したsectionにする。
- raw metadataはtechnical disclosureへ置く。
### Settingsとform
- 一つのSettings routeは一つの設定関心事を所有する。
- edit actionの前または同時に、現在有効な値を示す。
- 一つの判断に必要なfieldをgroup化する。
- narrow viewportでは一列にする。
- form内でfilled actionにするのはsave actionだけとする。
### Worker Console
- transcriptをprimary surfaceとする。
- direct SubWorkerを表示している場合も、Composerとrun
controlは親Workerへbindしたままにする。
- OverviewとNormalはpresentationだけを変え、authorityを変えない。
- command outputはterminalに近いcompactな表示とし、prose messageから分離する。
- live stateは権威あるWorker snapshotから導出する。
- connection stateやtransient eventでcurrent stateを置き換えない。
- hidden reasoningとraw system promptはdebug modeでも表示しない。
## Stateとpermission
- 存在しない、閲覧できない、読み込みに失敗したWorkspaceを別の状態として扱う。
- 別のWorkspaceへ暗黙に切り替えない。
- owner-only mutation controlをnon-ownerへ表示しない。
- read-onlyの場合は、有用なread viewを残す。
- Workerのdomain stateとWebSocket connection stateを混同しない。
- Mergeなど不可逆または重要なoperationは、対象と結果を明示してから実行する。
+272
View File
@@ -0,0 +1,272 @@
# Web visual review
この文書は、Web UIを変更する実装者が完了前に行うvisual
reviewの必須手順を定義する。Visual reviewは任意のpolish工程ではなく、type
check、linter、testと並ぶvalidationである。
[`design-language.md`](design-language.md)はWorkspace
Webが満たす視覚とinteractionの共通規則を定義する。Product固有の構成は[`product-ux.md`](product-ux.md)を参照する。[`tools/web-ux/README.md`](../../../tools/web-ux/README.md)はcapture
toolの操作方法を定義する。この文書は、誰が、いつ、何を目視し、どの証拠を残さなければ実装完了とみなせないかを定義する。
## 実装者の責任
Visual
reviewは、後段のReviewerやユーザーへ最初の発見を委ねない。UIを変更した実装者自身が、同じ変更の中で次を行う。
1. 変更前をcaptureする。
2. 変更後を同じ条件でcaptureする。
3. screenshotとbrowser evidenceを自分で確認する。
4. 発見した問題を修正する。
5. 修正後を再captureして確認する。
6. 変更と無関係な既存問題は、根拠を付けて分離する。
Agentが実装者の場合、そのAgent自身が`ViewImage`または同等のVLM入力で実画面を確認する。captureを生成しただけ、別のAgentへ画像を渡しただけ、HTTP
200を確認しただけでは完了しない。
## 適用範囲
次の変更ではvisual reviewを必須とする。
- page、layout、navigation、Sidebar、Header、Console、dialog
- componentのmarkupまたはstyle
- color、typography、spacing、border、radius、shadow、theme token
- copy、label、status、empty/loading/error/permission表示
- responsive breakpoint、container、overflow、scroll
- 表示dataの追加、削除、並び替え、progressive disclosure
- icon、focus、keyboard interaction、motion
- UIへ影響するgenerated typeまたはAPI projection
型、Backend、CLI、文書だけの変更でrendered Web
UIが変わらない場合は省略できる。省略する場合は、UIへ影響しない理由をvalidation
evidenceへ一文で残す。
## 必須の確認条件
変更したsurfaceに関係する条件だけを選ぶが、都合のよい一画面だけに限定しない。
### Persona
権限やdataが表示を変える場合は、該当するpersonaを分ける。
- owner
- non-owner
- anonymous
- read-onlyまたは操作権限なし
owner表示だけでpermission-aware UIを承認しない。
### Viewport
最低限、次を確認する。
- desktop: `1440px`幅を基準
- narrow: Sidebarとmainが競合する幅。現在は`768px`を基準
- mobile: `390px`幅を基準
`320px`対応、table、long form、Console、Sidebar
foldなどが変更対象なら、その境界も追加する。media
queryのviewport幅だけでなく、Sidebarやpanelを差し引いた実際のcontent幅を確認する。
### Theme
color、border、background、focus、status、code、terminalを変更した場合はlightとdarkの両方を確認する。片方のthemeで読めることを、もう片方のcontrastの証拠にしない。
### Data state
該当するstateを明示的に用意する。
- representative data
- empty
- loading
- error
- permission deniedまたはread-only
- long title、long key、long error、複数行content
- collectionの最小件数と、実際に起こりうる多い件数
happy pathだけでcomponentを承認しない。
## 目視確認の観点
### 情報のまとまり
- 同じ判断に使う情報がproximity、alignment、typographyによって一つのgroupに見えるか。
- 別の意味を持つ情報が、十分な距離または一つの明確なboundaryで分離されているか。
- 親子、peer、metadata、actionの関係が、DOMを読まなくても判別できるか。
- card、background、border、shadow、余白を重ねて同じgroupingを重複表現していないか。
- page title、Header、breadcrumb、section
heading、説明文が同じ意味を繰り返していないか。
### Separatorとborder
画面上のすべての線について、何と何を区切る線か説明できなければならない。
- Headerの終端、peer row間、section開始、table
cellなど、線の役割が一つに定まっているか。
- 近接した二本の線が同じboundaryを重複表現していないか。
- 線の上下の余白から、その線が前後どちらのgroupに属するか分かるか。
- すべてのsectionへ機械的に同じ線を置き、hierarchyを平坦化していないか。
- borderがなくてもspacingだけで十分な箇所へ線を追加していないか。
### Spacingとdensity
- 余白がtoken scaleに沿い、近い関係ほど狭く、別groupほど広くなっているか。
- labelとvalue、headingとcontent、rowとrow、sectionとsectionの間に一貫した大小関係があるか。
- 線の前後へ同程度の大きな余白を置き、boundaryの所属を曖昧にしていないか。
- 初期viewportにprimary contentまたは主要操作が存在するか。
- 空きすぎた領域が情報不足やhierarchyの弱さを隠していないか。
- 密度を上げるためにfont、touch target、line heightを過度に縮めていないか。
### Wrapping、overflow、可変長content
- 実際に起こりうる最長のlabel、title、key、ref、error、翻訳で確認したか。
- 一行を前提とするcontrolが意図せず二行にならないか。
- button labelが折り返されたとき、row heightとalignmentが壊れないか。
- title、metadata、code、URLが隣接actionを押し出さないか。
- truncateする場合、完全な値へaccessできるか。
- horizontal
scrollはtable、board、terminalなど、その意味を所有する領域だけに閉じているか。
- page全体へhorizontal overflowが発生していないか。
- `overflow-wrap`だけで問題を隠さず、可読性と比較可能性を維持しているか。
### Responsive layout
- DOM順、視覚順、keyboard順が一致しているか。
- Sidebar、Header、primary contentの順序がmobileでも目的に合うか。
- Sidebarだけで初期viewportを占有していないか。
- breakpoint直前と直後の両方で、content幅とcontrol配置が成立するか。
- viewport
queryだけでなく、containerの実幅に応じて一列化またはscrollを選べているか。
- desktopの比較関係を、理由なくmobile cardへ変換していないか。
### Typographyとcopy
- route titleが画面上で一度だけ表示されているか。
- page purpose、componentの存在理由、設計意図を説明するmeta
copyが残っていないか。
- proseが判断、warning、constraint、permission、recoveryのいずれかに実際に必要か。
- heading level、font size、weight、colorが同じhierarchyで揃っているか。
- metadataがbodyより強く見えていないか。
- uppercase、letter spacing、monospaceを装飾目的で多用していないか。
### State、permission、action
- loading、empty、error、permission denied、unavailableが見分けられるか。
- statusがcolorだけに依存していないか。
- 利用できないowner-only actionをdisabledで並べるのではなく、page
compositionから除外できているか。
- filled primary actionが同じscopeに複数ないか。
- destructive actionが通常のprimary pathと誤認されないか。
- errorとrecovery actionが、失敗したsurfaceの近くにあるか。
### Interactionとaccessibility
- keyboard focusが全controlで見えるか。
- focus順が画面の作業順と一致するか。
- fold、disclosure、dialog、menuを操作した後にfocusが失われないか。
- hoverでしか得られない必須情報がないか。
- scroll region、icon-only control、status markerにaccessible
nameまたはtextがあるか。
- reduced motionで意味が失われないか。
## 実行手順
### 1. Scenarioを決める
変更対象route、persona、viewport、theme、data state、capture
pointを列挙する。既存scenarioが目的を満たす場合は再利用し、満たさない場合は同じ変更内で追加または更新する。
### 2. 変更前をcaptureする
`tools/web-ux`を使い、変更前のsourceとscenarioを固定する。出力はrepositoryのproduction
sourceへ混ぜず、`target/web-ux`などの開発artifact領域へ置く。
### 3. 変更前を目視する
既存問題も含め、変更対象付近のgrouping、separator、spacing、wrapping、responsive、stateを確認する。変更前を見ずに、変更後の印象だけで改善を主張しない。
### 4. 実装する
発見した問題と、適用するUX規則を対応付けて修正する。screenshotだけを整えるfixture固有hackや、productionと異なるshell、CSS、data
authorityを作らない。
### 5. 同条件で再captureする
persona、route、viewport、theme、data
stateを揃える。変更後だけ別の好条件へ変えない。
### 6. Screenshotとreview contextを確認する
実装者自身が画像を開き、`review-context.json`も読む。次を確認する。
- document status
- visible UI error
- console error
- page error
- failed request
- accessibility snapshot
- screenshot hashとcapture point
HTTP 200でも画面に`401 Unauthorized`などが表示されていれば失敗とする。
### 7. Compareする
before/afterを比較し、差分が意図した領域に限定されているか確認する。pixel
differenceの大小だけで合否を決めない。意図しない移動、折返し、欠落、色変化を目視する。
### 8. Testとevidenceを揃える
source test、component test、E2E、type checkを実行し、visual
evidenceと一緒に記録する。test成功はvisual reviewの代替ではなく、visual
review成功もtestの代替ではない。
## 合格条件
次をすべて満たした場合だけvisual reviewを合格とする。
- 実装者自身がbefore/afterを目視した。
- 必要なpersona、viewport、theme、data stateを確認した。
- grouping、separator、spacing、wrapping、responsiveを確認した。
- visible、console、page、request errorが解決または明確にdispositionされた。
- 発見した新規問題を修正し、修正後を再captureした。
- 意図しないvisual regressionがない。
- artifact path、scenario、確認結果をhandoffへ記録した。
次は不合格である。
- capture commandが成功しただけ。
- screenshotを生成したが開いていない。
- desktopだけ、ownerだけ、happy pathだけを見た。
- 後段Reviewerまたはユーザーが目視する前提でhandoffした。
- 「好みの問題」として、説明できないseparator、spacing、overflowを未確認のまま残した。
- testまたはlinterが成功したため、visual reviewを省略した。
## Evidenceの記録
handoffには最低限、次を記録する。
```text
Visual review
- Scenario: <scenario path>
- Before: <run id or artifact path>
- After: <run id or artifact path>
- Personas: <list>
- Viewports: <list>
- Themes: <list>
- Data states: <list>
- Findings fixed: <bounded list>
- Known issues: <bounded list with disposition>
- Result: pass | fail
```
画像をTicketやGitへ大量にcommitしない。artifact pathとsource
revisionを結び付け、必要なreviewerが同じ条件を再現できるようにする。認証profile、cookie、token、secret、private
response bodyをartifactやhandoffへ含めない。
## Toolの位置付け
`tools/web-ux`はbrowser起動、scenario再現、capture、review
context、compareを提供する。Toolは視覚的な良否を自動決定しない。
Linterが構文規則を検査し、testが特定のbehaviorを検査するのと同様に、visual
reviewはrendered
resultの関係性を検査する。三者は補完関係であり、どれか一つで他を代替しない。
+14
View File
@@ -32,6 +32,20 @@ cargo check --workspace
Avoid repository-wide formatting churn when a validation failure is caused by pre-existing unrelated formatting.
## Web UI changes
Rendered Web UI changes require implementer-owned visual review in addition to type check, linter, and test. Follow [`ui-ux/visual-review.md`](ui-ux/visual-review.md).
Minimum evidence includes:
- before/after capture under the relevant persona, viewport, theme, and data state;
- the implementer’s own inspection of grouping, separator meaning, spacing, wrapping, overflow, responsive order, and visible errors;
- `review-context.json` inspection;
- disposition of every observed problem;
- artifact paths and a final `pass | fail` result.
A successful capture command, HTTP 200, screenshot generation, or later Reviewer inspection does not replace this validation.
## Work item checks
Run: