# KBX v31 Template · Component · Home Navigation Completion

## 1. 목적

v31은 표준 화면과 Navigation의 기능을 더 많이 추가하는 버전이 아니다. v30까지 정의된 계약이 실제 제품 화면에서 **잘못 조합되거나, 중복 구현되거나, 다중업무 Context를 잃거나, 저장된 Navigation State를 과도하게 신뢰하는 문제**를 줄이는 것이 목적이다.

```text
Screen Definition
→ Canonical Template
→ Runtime Type Guard
→ Standard Component
→ Workspace / Home
→ Safe Route Re-resolution
```

## 2. T01~T09 Runtime Type Guard

정적 Manifest와 Scaffolder만으로는 기존 코드가 잘못된 Template을 직접 사용할 가능성을 완전히 막을 수 없다.

v31부터 T01~T08은 `KbxScreenFrame`에 다음을 전달한다.

```text
expectedType
+ templateCode
```

예:

```text
KbxTransactionPage
→ expectedType = transaction
→ templateCode = T03
```

`screen.type`이 다르면 Command/업무 본문을 렌더링하지 않고 표준 Error Surface로 차단한다. 이는 Domain 보안이 아니라 **UX Contract 오배치 방어선**이다.

T09 `KbxWmsMobilePage`도 `screen.type === 'wms-mobile'`을 확인한다. Desktop Screen Definition을 Scanner/PDA 화면에 잘못 연결하는 경우 현장 입력을 진행하지 않는다.

## 3. SearchPanel SRP / 중복 제거

기존 `KbxSearchPanel`은 Primary Filter와 Secondary Filter에서 다음 구현을 두 번 반복했다.

- text
- date
- date-range
- select
- checkbox
- lookup

이 구조는 필드 타입 추가, 접근성 Label, Disabled 정책, Lookup 변경 시 두 영역이 쉽게 분화될 수 있다.

v31은 내부 `KbxSearchFieldControl`로 렌더링 책임을 단일화했다.

```text
KbxSearchPanel
 ├─ Primary fields
 ├─ Actions
 └─ Secondary fields
      ↓
KbxSearchFieldControl
```

SearchPanel은 검색조건 그룹, 상세조건, 초기화, 조건기억을 책임지고 실제 Control 렌더링은 내부 컴포넌트가 책임진다.

## 4. Home Workbench — Screen과 Work Instance 분리

v30은 Home 중복 제거를 `ScreenId` 중심으로 수행했다. 이는 Catalog 중복 제거에는 맞지만 Workspace에는 부족하다.

예:

```text
OMS-ORD-002 / 주문 A 편집
OMS-ORD-002 / 주문 B 편집
```

두 업무는 같은 Screen Definition이지만 서로 다른 Work Instance다.

v31은 다음 기준을 사용한다.

```text
열린/미저장 업무
→ tab.key 기준

즐겨찾기/최근/권장
→ ScreenId 기준
```

따라서 여러 열린 주문을 모두 이어서 작업할 수 있고, 해당 Screen이 열려 있으면 즐겨찾기/최근/권장 항목은 추가로 반복하지 않는다.

## 5. Home 정보 노출 정리

Reference Screen은 Screen ID를 일반 사용자에게 기본 노출하지 않고 Help 등에서 확인하도록 한다.

v31은 Home Workbench와 모듈별 업무 목록의 ScreenId 직접 노출을 제거했다. 화면코드 검색 기능은 Global Menu Search에 그대로 유지한다.

동일 Screen의 여러 열린 Instance에는 필요한 경우 route의 업무 식별 segment를 짧은 Context Hint로 보여준다. 이는 사용자가 이미 접근 가능한 Workspace route에서만 생성된다.

## 6. Workspace Tabs Keyboard / Pin

기존 Arrow/Home/End 처리는 active tab 변경 Event만 발생시키고 실제 Focus를 이동시키지 않았다.

v31:

```text
Arrow Left / Right
Home / End
→ Tab 선택
→ nextTick
→ 실제 Tab Button focus
```

또한 `Delete`를 탭 닫기에 사용하지 않는다. KBX의 Delete 문법과 충돌을 줄이고 명시적 `×`를 유지한다.

기존 Contract에 존재하던 `pinned` 상태도 실제 Action으로 연결했다.

```text
Pin
→ Workspace Store pinned=true
→ Capacity eviction 대상에서 제외
```

Dirty/Active/Pinned 보호정책이 실제 UI에서 사용할 수 있는 기능이 되었다.

## 7. Menu Search Focus Recovery

Menu Search는 Dialog를 열 때 Trigger를 기억하고 닫힌 후 그 Trigger로 Focus를 복귀한다.

```text
Header 검색 버튼
→ Ctrl K / Click
→ Search Dialog
→ Esc / 선택
→ 원래 Trigger Focus
```

검색어가 있을 때 결과 개수도 `aria-live`로 전달한다.

## 8. Application Shell Skip Navigation

Global Header + Workspace Tabs + Side Navigation이 있는 업무 Shell은 키보드 사용자가 반복 Navigation을 통과해야 한다.

v31은 다음 Skip Link를 추가한다.

```text
본문 바로가기
→ #kbx-main-workspace
```

Focus 시에만 보이도록 하며 Main Workspace 자체를 programmatic focus 가능한 대상으로 둔다.

## 9. Persisted Navigation Security

Workspace 현재 세션은 query/hash를 유지할 수 있지만 LocalStorage의 Recent에는 불필요하게 보존하지 않는다.

v31 정책:

```text
In-memory Workspace
→ authorized route pattern 통과 후 query/hash 허용

Persisted Recent
→ pathname만 저장
→ query/hash 제거
```

추가 차단:

- `%2F` encoded slash
- `%5C` encoded backslash
- `%00`, CR/LF/TAB
- encoded `..`
- raw backslash
- username/password URL form

Dynamic path 저장 자체는 기존 `recentPolicy='route'` opt-in을 유지한다.

## 10. 과유불급 / 기술부채 판단

v31은 다음을 만들지 않았다.

- 별도 Navigation Framework
- Runtime JSON Screen Engine
- 새 Search DSL
- 새 Router
- 새 Grid

기존 Vue Router, KBX Template, KBX SearchPanel, Workspace Store의 책임을 명확히 하고 반복과 누락을 줄이는 정공법을 사용했다.
