# KBX FE QA Hardening v41

## 1. 결론

v40은 HTML/CSS/JavaScript FE Reference Lab에서 T01~T09의 완료 루프를 상당 부분 닫았다. 그러나 현장 QA 기준으로는 **Reference Lab이 좋아졌다는 사실과 실제 Vue 제품 화면이 좋아졌다는 사실을 동일시할 수 없다.**

v41은 BE 구조와 Metadata Framework를 확장하지 않고 실제 Vue Golden Screen과 공통 FE Component를 대조했다. 그 결과 다음 운영 결함을 확인했다.

1. OMS 주문관리 주문번호 Link가 `drillDownRequested`를 emit하지만 Page가 받지 않아 no-op이었다.
2. 주문 Grid Double Click은 Detail Drawer가 아니라 Edit Page로 이동하여 조회 Context를 잃었다.
3. 외부 `selectionState`가 비워져도 AG Grid 내부 Selection이 남을 수 있어 시각 Selection과 실제 Command 대상이 달라질 위험이 있었다.
4. ERP 품목관리에서 Dirty 상태로 다른 Master를 선택하면 현재 편집값이 새 Row 데이터로 덮어써질 수 있었다.
5. 주문등록 Grid F2 Lookup은 값은 반영하지만 다음 Editable Cell로 Focus가 이어지지 않았다.
6. `KbxLookup` 직접 코드 Enter 성공은 Dialog 선택과 달리 Focus continuation이 없었다.
7. `KbxUnsavedChangesDialog`는 Modal 외관은 있지만 Tab Focus Trap / Esc / Focus Restore가 충분하지 않았다.
8. OMS 주문관리의 `보류` Command는 실제 Handler가 없는 no-op이었다.
9. Grid 오류 개수에 Header/Form 오류가 섞일 수 있어 “셀 오류” 숫자가 실제 Cell 오류보다 많아질 수 있었다.
10. Side Navigation의 즐겨찾기 버튼은 보조기술에서 대상 화면명이 빠진 동일한 이름으로 반복됐다.

이 문제들은 화면 미관보다 우선순위가 높다. **사용자가 보고 있는 상태와 실제 Command 대상이 다르거나, 클릭했는데 아무 일도 일어나지 않거나, 편집값이 전환 과정에서 사라지는 문제는 P0/P1 제품 결함**이다.

---

## 2. v41 수정 사항

### P0/P1 — OMS-ORD-001 List Context / Detail Contract

- 주문번호 Link `drillDownRequested` → 실제 `openDetail(row)` 연결
- Row Double Click → 동일 Detail Drawer로 통일
- Drawer에서만 전체 편집 Page로 승격
- Drawer open 시 기존 Search/Grid Context 유지
- Detail request마다 sequence를 부여하여 Drawer가 닫히거나 다른 주문으로 바뀐 뒤 늦게 도착한 응답이 현재 화면을 덮어쓰지 않게 함
- 전화번호는 Drawer 기본 표시에서 masking

Reference Screen의 “목록 Context를 유지하고 복잡한 수정만 전체 Page로 전환” 규칙을 실제 Vue에 반영한다.

### P0 — Controlled Grid Selection

`KbxDataGrid`의 Selection을 AG Grid 내부 상태에만 맡기지 않는다.

- `selectionState` 외부 모델과 실제 Grid row selection을 동기화
- Programmatic sync 중 `selectionChanged` 재귀 emit 차단
- explicit selected ids가 비워지면 Grid 선택도 해제
- active row와 selection을 rows 갱신 후 재동기화
- multi-row는 checkbox/header checkbox를 명시
- `selectRowByKey`, `clearSelection` API 제공

대량처리 화면에서 **보이는 선택과 Command payload 대상은 반드시 같은 Source of Truth**를 가져야 한다.

### P1 — Grid Error Scope

기존 `errors` 전체를 “셀 오류”로 취급하지 않고 다음 조건만 Grid Cell 오류로 본다.

- `rowKey` 존재
- `field` 존재
- 해당 field가 현재 Grid Column에 존재

따라서 Header Validation과 Detail Cell Validation이 섞여도 “N개 셀 오류”와 첫/다음 오류 Navigation이 실제 Grid 범위만 가리킨다.

### P1 — ERP-MST-ITEM-001 Dirty Master Transition

Master 선택과 신규 전환 전에 Dirty 여부를 검사한다.

- Dirty 없음 → 즉시 선택/신규
- Dirty 있음 → pending transition 저장
- Grid selection을 현재 item으로 복원
- `계속 편집 / 변경 버리기 / 저장 후 이동` 선택 후 전환
- 저장 실패 시 전환하지 않음

Master/Detail에서 가장 위험한 데이터 유실 패턴인 **“왼쪽 목록 클릭 한 번으로 오른쪽 미저장 편집값 소실”**을 제거한다.

### P1 — OMS-ORD-002 Fast Transaction Focus

F2 품목 Lookup 완료 후:

1. 원래 line/clientId와 field Context를 보존한다.
2. 선택 item을 해당 line에 적용한다.
3. Dialog 종료 후 `focusNextEditableCell()`로 다음 Cell에 Focus한다.

또한 `신규`/`주문복사`도 현재 Transaction이 Dirty면 3-way Guard를 거친다. Copy는 Order identity/version을 복사하지 않고 line clientId를 새로 만든다.

### P1 — KbxLookup Focus Contract

- Dialog 선택 → 다음 Control
- Dialog 취소 → 원래 Trigger
- 직접 Code Enter resolve 성공 → 다음 Control
- Label은 `${업무명} 코드`, `${업무명} 선택된 이름`, `${업무명} 검색`으로 고유화

즉 Lookup 경로에 따라 Enter 후 Focus가 제각각 움직이지 않는다.

### P1 — KbxUnsavedChangesDialog Keyboard Safety

- Open 시 이전 Active Element 기억
- 첫 focusable action으로 Focus 이동
- Tab / Shift+Tab Focus Trap
- Esc = 계속 편집
- Saving 중 Esc/background close 차단
- Close 후 원래 Focus 복원
- `aria-describedby`로 미저장 변경 설명 연결

### P1 — Fake Command 제거

OMS 주문관리의 `보류`는 실제 backend operation/handler가 없는 상태였으므로 표시만 남겨두지 않고 제거했다.

**실무에서 빠진 버튼보다 더 위험한 것은 동작하는 것처럼 보이는 버튼이다.** 구현되지 않은 업무 Action을 UI 완성도로 계산하지 않는다.

### Accessibility — Side Navigation

- `주문관리 즐겨찾기 추가`처럼 대상 화면명을 accessible name에 포함
- 즐겨찾기 목록의 현재 화면에도 `aria-current="page"` 적용

---

## 3. Home Navigation에 대한 v41 판단

v40에서 Home은 이미 다음 구조를 갖는다.

- 확인 필요
- 바로 시작: 미저장/고정/열린 업무 우선
- 즐겨찾기/최근/권장 중복 제거
- 모듈별 업무
- Ctrl+K 메뉴/화면 검색
- 실패 작업/중요 알림/진행 작업에서 실제 Context 이동

v41에서는 Home에 카드나 KPI를 더 추가하지 않았다. 현재 병목은 Home 정보량 부족이 아니라 **Home에서 들어간 실제 Golden Screen이 동일한 Context/Selection/Focus 계약을 지키는가**였다.

따라서 Home 자체는 Side Navigation 접근성·현재상태 표현만 보강하고, 투자 우선순위를 실제 Screen parity로 옮겼다. 이것이 과유불급을 피하는 판단이다.

---

## 4. 보안·안정성 판단

### FE는 Trust Boundary가 아니다

다음 v41 수정은 오조작·데이터 유실·UI race를 방지하는 FE 안정성이다.

- Dirty Guard
- controlled selection
- stale detail response sequence guard
- masked sensitive display
- disabled/permission UX
- client validation

하지만 다음은 Server가 최종 Enforcement 해야 한다.

- Permission
- 상태전이
- 재고/금액/Reference Integrity
- Concurrency
- Idempotency
- Audit
- DB Constraint
- Outbox/Inbox

UI에서 Command가 숨거나 disabled된 것을 보안으로 간주하지 않는다.

### Async stale response

주문 A Drawer를 열고 곧 주문 B를 열거나 Drawer를 닫았을 때 A 요청이 늦게 완료되더라도 현재 Drawer 상태를 덮어쓰지 않도록 request sequence로 무효화한다.

이는 단순 UX polish가 아니라 운영 중 잘못된 주문 정보를 현재 주문 정보처럼 표시할 수 있는 race를 줄이는 방어선이다.

---

## 5. 잔여 결함 — 완료로 계산하지 않음

### P1 — Excel Standard 미완료

OMS 주문조회 `엑셀` Action은 현재 AG Grid CSV export에 연결되어 있다.

KBX 표준이 요구하는 다음 계약 전체와 같지 않다.

- 현재 조회결과 Excel 다운로드
- 업로드 양식 다운로드
- Excel 업로드
- Excel 붙여넣기
- 최근 업로드 결과

특히 현재 로드된 Row CSV와 **전체 검색조건 결과 Export**는 같은 개념이 아니다. 서버 기반 Export/Job 정책과 `KbxExcelMenu` 실제 통합이 필요하다.

### P1 — 실제 Vue Runtime E2E / Visual Regression

현재 산출물에는 `node_modules`가 없고 `pnpm` 실행파일도 없다. 따라서 v41의 실제 Vue/PrimeVue/AG Grid app runtime을 띄워 Playwright로 검증하지 못했다.

이번 증적은 다음 범위다.

- TypeScript/Vue script transpile syntax
- static contract/parity validator
- 전체 Foundation governance
- design debt ratchet

이를 실제 runtime E2E를 통과한 것으로 표현하지 않는다.

### P2 — brittle legacy validator

v33 validator 일부는 의미가 아니라 `?'idle'` 같은 source 문자열 형태를 검사한다. 동작상 동일한 `? 'idle'` formatting도 실패한다.

이번에는 기존 재현성을 위해 source를 호환시켰다. 향후 AST/semantic validator로 교체하는 것이 맞지만 FE 기능 작업과 섞어 큰 리팩터링을 만들지 않았다.

---

## 6. 30년 현장 QA 관점의 판단

### 1. Reference Screen과 실제 제품 Screen은 별도로 합격시켜야 한다

Prototype이 정상이라고 Production Component가 정상인 것은 아니다. v41에서 발견한 no-op Link와 selection desync가 그 증거다.

### 2. Grid Selection은 데이터 정합성 UX다

Bulk Command에서 Checkbox는 장식이 아니다. 사용자가 선택했다고 보는 Row와 Server로 보낼 대상이 다르면 가장 위험한 유형의 업무 오류가 된다.

### 3. Master/Detail의 핵심 QA는 “다른 Row 클릭”이다

저장 버튼 Happy Path보다 먼저 확인해야 할 것은 편집 중 왼쪽 Master를 바꿨을 때 데이터가 사라지는지다.

### 4. Lookup의 완성도는 Popup 모양이 아니라 Focus 이후다

F2가 열리고 Enter로 선택되는 것까지는 절반이다. 선택 후 사용자가 Mouse를 다시 잡아야 한다면 ERP Keyboard Flow는 끊긴다.

### 5. 모르는 기능을 화면에 두지 않는다

Backend Handler가 없는 `보류`를 Command Bar에 두는 것은 “나중에 구현할 자리”가 아니라 운영 UI의 거짓 약속이다.

### 6. 다음에는 새 Component보다 실제 Runtime QA가 먼저다

v41 이후 우선순위는 다음이다.

1. 실제 Vue 앱 install/build/typecheck
2. OMS-ORD-001 Playwright: F3 → selection → Drawer → bulk → reset selection
3. OMS-ORD-002 keyboard-only: F2 → Enter → quantity → F8
4. ERP-MST-ITEM-001 Dirty row switch 3-way Guard
5. 1280×720 / 1440×900 / 200% zoom visual regression
6. KbxExcelMenu + server-side full-query export
7. Permission/Conflict/Integration failure 실제 API contract E2E

이 Gate 전에는 T10 추가, Runtime JSON UI Builder, 새로운 Grid abstraction을 우선하지 않는다.
