Files
KArtSell.Aegis/docs/Design/kbx-foundation-v60-status-canonical-contract-hardening/docs/frontend/KBX-FE-Workflow-Queue-Runtime-Hardening-v58.md
T
kjh2064 3f293d8aa8
deploy / deploy (push) Successful in 1m52s
deploy / notify (push) Successful in 1s
V13-FE-006: consolidate approved UI and contract hardening
2026-08-13 02:41:00 +09:00

8.3 KiB

KBX FE Workflow Truth · Queue Signal · Runtime Hardening v58

1. 냉정한 진단

v57까지 KBX는 T01~T09 Template, Home Workbench, Import Recovery, Reconcile/Operations authoritative outcome, WMS retry/idempotency, Playwright 실행계약까지 상당히 정리되었다. 그러나 실제 FE 코드를 다시 보면 여전히 “문서/정적 Gate는 강한데 Browser Interaction은 틀릴 수 있는” 결함이 남아 있었다.

이번에 발견한 핵심은 네 가지다.

  1. Selection Contract 불일치 — OMS 클레임은 KbxDataGridupdate:selection을 제공하지 않는데 v-model:selection을 사용하고 있었다. 동시에 KbxListPageselectionCount를 전달하지 않아 Command의 requiresSelection 계약도 실제 선택과 연결되지 않았다.
  2. Workflow UI와 실제 Command 불일치 — WorkflowBar는 start/complete를 노출하지만 Page command handler는 approve/hold만 API로 전송했다. 보이는 Action과 실행 가능한 Action이 달랐다.
  3. Queue Signal 왜곡 — WMS 작업 Queue의 기본 검색이 READY였고 예외 카운터를 현재 rows에서 계산해, 실제 BLOCKED 작업이 존재해도 첫 화면에서 확인 필요 0으로 보일 수 있었다.
  4. Vue writable model 위험KbxSearchPanel은 새 객체를 update:modelValue로 반환하는데 일부 Page는 const search = reactive(...) 전체 객체를 v-model로 넘겼다. 정적 TypeScript Syntax Gate는 통과하지만 Browser에서 const reactive binding 재할당 위험이 있는 패턴이다.

이 네 가지는 모두 “코드량/컴포넌트 수”가 아니라 실제 업무 실행 Truth 문제다.

2. OMS-CLM-001 — Selection/Workflow Closure

기존 문제

  • v-model:selection + selection="multiple"가 동시에 존재
  • 실제 KbxDataGridselectionChanged만 emit
  • KbxListPage의 selection count는 0으로 남을 수 있음
  • WorkflowBar start/complete가 보이지만 command handler는 실행하지 않음
  • HOLD는 Command에는 있으나 Workflow state에는 없음
  • 여러 건 승인/보류 중 일부 실패하면 첫 실패에서 전체 흐름이 끊길 수 있음

v58 변경

  • @selection-changed="selected=$event"로 실제 Grid 계약 사용
  • :selection-count="selected.length"를 T01 CommandBar까지 전달
  • approve / hold / start / complete 전체 Transition을 동일 실행경로로 연결
  • HOLD를 semantic hold 상태로 명시
  • Transition별 server result를 기다린 뒤 재조회
  • 행별 실패를 수집하고 나머지 행은 계속 처리
  • 요청 / 성공 / 실패를 persistent receipt로 표시
  • 처리 후 receipt로 Keyboard Focus 이동

중요한 원칙은 성공 Toast를 늘린 것이 아니라, 선택 → Command → Server → 결과 → 재조회 → Focus가 한 업무 흐름으로 닫히게 한 것이다.

3. Demo Claims — Runtime Fixture를 실제 계약으로 복원

기존 Demo Claims는 실제 Backend DTO와 달랐다.

  • status: '접수'처럼 한글 표시값을 API value로 사용
  • channelName, requestedQty, ownerName 누락
  • 모든 transition이 현재 상태와 무관하게 성공

v58은 Demo를 다음 실제 업무 상태로 정렬했다.

REQUESTED → APPROVED → IN_PROGRESS → COMPLETED

그리고 REQUESTED → HOLD를 별도로 둔다.

허용되지 않은 Transition은 실제 Axios rejection + business-rule Problem으로 처리한다. Demo는 보기 좋은 샘플 데이터가 아니라 Browser Runtime에서 실제 FE 계약을 검증하는 실행 Fixture여야 한다.

4. WMS-WORK-001 — Queue Signal Truth

기존 문제

기본 검색조건이 status='READY'였다. 따라서 화면 진입 후 사용자가 조회하면 BLOCKED/IN_PROGRESS가 기본적으로 제외된다.

더 큰 문제는 예외 카운터를 rows.filter(status==='BLOCKED')로 계산한 것이다. 현재 rows가 READY만 포함하면 실제 예외가 있어도 0으로 보인다.

T06 Work Queue가 사용자의 “지금 처리해야 할 업무”를 보여줘야 한다는 목적과 충돌한다.

v58 변경

  • 기본 상태를 전체로 변경
  • 화면 진입 시 자동으로 내 작업 조회
  • WmsWorkSearchSummary 도입
  • 상태 필터 적용 전 summary rows에서 ready / inProgress / blocked 계산
  • Grid count는 현재 필터 결과, Summary/Exception은 동일 기본조건의 전체 업무 압력을 표시
  • BLOCKED 선택 시 작업 시작을 disabled
  • “예외 작업은 행을 열어 원인을 먼저 확인”이라는 다음 행동 표시
  • Double Click은 작업 상세 Context 진입을 유지

즉 상태 필터를 좁혀도 “예외가 존재한다”는 운영 신호는 사라지지 않는다.

5. SearchPanel Whole-object v-model Runtime Contract

이번에 추가한 Gate는 다음 패턴을 전체 apps/web/src에서 금지한다.

const search = reactive(...)
<KbxSearchPanel v-model="search" />

KbxSearchPanelupdate:modelValue새 객체를 반환하는 구조에서는 writable ref가 맞다.

v58에서 수정한 화면:

  • OMS Claims
  • WMS Work Queue
  • COMMON UX Metrics
  • ERP Item Master

Component Catalog는 이미 ref<Record<string,unknown>>를 사용하고 있어 그대로 유지한다.

이 Gate의 의미는 특정 화면 1건을 고치는 데 있지 않다. 같은 Runtime-class 결함이 다시 추가되는 것을 자동 차단한다는 데 있다.

6. Home — 화면 수의 사실성

Home의 사용 가능 화면전체 N개 화면props.entries.length를 사용하면 menuVisible=false인 Utility/Hidden entry까지 사용자에게 실행 가능한 화면처럼 계산될 수 있다.

v58은 menuVisible !== false인 launchable entry만 센다.

작은 숫자 차이처럼 보이지만 Home은 업무 탐색의 Source of Truth다. 숫자가 실제 Explorer와 다르면 사용자는 Navigation 자체를 신뢰하지 않게 된다.

7. QA/E2E 보강

추가 E2E:

OMS Claims

  • F3 조회
  • 실제 Grid row selection
  • WorkflowBar 승인
  • authoritative receipt Focus
  • APPROVED → 처리 시작
  • HOLD 상태 명시 / 다음 Action 없음 확인

WMS Work Queue

  • 화면 진입만으로 전체 내 작업 조회
  • BLOCKED 작업이 초기 결과에서 보임
  • 예외 요약이 1건을 표시
  • 예외 필터 적용
  • BLOCKED 작업에서 시작 Action disabled

Runtime package 설치가 가능한 환경에서는 이 시나리오가 기존 Playwright Desktop/WMS project에 그대로 포함된다.

8. 검증 결과

node scripts/validate-kbx.mjs 전체 PASS.

  • Design Tokens: 161
  • Screens: 20
  • Components: 86
  • Core APIs: 34
  • TypeScript/Vue script units: 311
  • T01~T09: 9/9
  • Design Debt: 116 <= 131
  • Design-Code Parity: PASS
  • Release Governance: major PASS
  • v41~v58 FE regression: PASS

v58 전용 Gate도 PASS.

9. Runtime 제한 — 여전히 BLOCKED

현재 container에서 Corepack pnpm@10.33.4 실행을 다시 시도했으나 npm registry DNS가 EAI_AGAIN으로 실패한다.

따라서 다음은 PASS라고 주장하지 않는다.

  • pnpm install --frozen-lockfile
  • Vue production typecheck/build
  • Vitest runtime
  • Playwright Desktop/WMS runtime

System Chromium을 사용한 Static Reference --dump-dom도 다시 시도했으나 DBus/zygote 환경에서 timeout되었다.

정적/계약 검증 PASS와 Browser Runtime PASS는 계속 분리한다.

10. 다음 P0 — Status Grid Rendering

v58 이후 가장 우선순위가 높은 FE Component 부채는 KbxDataGridtype:'status'다.

현재 Grid는 status type을 가운데 정렬하는 수준이며 KbxStatusDefinition(value/label/semantic)을 Cell Renderer까지 일관되게 연결하지 않는다. 이 상태에서는 Backend value인 REQUESTED, IN_PROGRESS, BLOCKED가 사용자 화면에 그대로 노출될 가능성이 있다.

다음 단계에서는 새 UI Framework가 아니라:

  1. Domain status value → KBX Status Definition mapping
  2. Grid status cell에서 Familiar Korean label + semantic cue
  3. Filter/Excel export는 canonical value와 표시 label의 역할 분리
  4. 미정의 상태는 조용히 오표시하지 않고 Unknown/Fallback 정책 적용
  5. OMS/WMS/ERP 상태 Dictionary 중복 제거

를 우선하는 것이 맞다.

이 작업은 미관 개선이 아니라 Familiar First + Explicit State + Hallucination/오표시 방지를 Grid 핵심 계약에 내리는 작업이다.