Files
KArtSell.Aegis/docs/Design/KBX Design System v1.0.md
T

2890 lines
36 KiB
Markdown

# KBX Design System v1.0
## OMS · WMS · ERP Component Contract & Design Tokens
---
# 1. 설계 목표
KBX Design System의 목적은 예쁜 UI 라이브러리를 만드는 것이 아니다.
다음 문제를 구조적으로 제거하는 것이 목적이다.
- 화면별 입력 높이가 다름
- 조회 버튼 위치가 다름
- Lookup 방법이 다름
- Enter 동작이 다름
- Excel 처리 방식이 다름
- Grid 설정이 화면마다 다름
- 오류 표현이 다름
- 저장 후 Feedback이 다름
- AI Action 방식이 다름
- 개발자마다 PrimeVue 사용 방식이 다름
최종 원칙:
> Vertical Slice는 업무를 구현하고, KBX는 UX를 구현한다.
---
# 2. 기술 계층
```text
Vue 3 / TypeScript
KBX Screen Templates
KBX Business Components
KBX Primitives
├──────── PrimeVue
└──────── AG Grid
```
Vertical Slice에서 PrimeVue 및 AG Grid를 직접 사용하는 것은 예외로 취급한다.
---
# 3. 패키지 구조
권장:
```text
src/
└─ shared/
└─ kbx/
├─ tokens/
├─ primitives/
├─ business/
├─ grid/
├─ forms/
├─ lookup/
├─ excel/
├─ feedback/
├─ ai/
├─ templates/
├─ composables/
├─ directives/
├─ schemas/
└─ testing/
```
업무 모듈에서는:
```text
modules/
├─ oms/
├─ wms/
└─ erp/
```
형태로 KBX를 소비한다.
---
# 4. Component 계층 규칙
## Level 1 — Primitive
업무 의미를 모른다.
```text
KbxButton
KbxInput
KbxNumberInput
KbxDatePicker
KbxSelect
KbxCheckbox
KbxRadio
KbxTextarea
KbxDialog
KbxDrawer
KbxTabs
KbxBadge
KbxTooltip
```
---
## Level 2 — Business Component
업무용 UX 규칙을 포함한다.
```text
KbxLookup
KbxSearchPanel
KbxCommandBar
KbxDataGrid
KbxMoneyField
KbxQuantityField
KbxBarcodeField
KbxStatus
KbxAuditTrail
KbxExcelImport
KbxBulkActionBar
KbxJobProgress
KbxHelpPanel
KbxAiPanel
KbxProposalPanel
```
---
## Level 3 — Screen Template
업무 화면 골격을 책임진다.
```text
KbxListPage
KbxMasterPage
KbxTransactionPage
KbxFastEntryPage
KbxMasterDetailPage
KbxQueuePage
KbxReconcilePage
KbxImportPage
KbxWmsMobilePage
```
---
# 5. 핵심 금지 규칙
Vertical Slice에서 다음과 같은 구현을 반복하지 않는다.
```vue
<InputText />
<Button />
<Dialog />
```
그리고 각 화면이 직접:
```ts
window.addEventListener("keydown", ...)
```
방식으로 F2/F3/F8을 구현하지 않는다.
KBX에서 공통 관리한다.
---
# 6. Design Token 체계
Token은 다음 계층으로 관리한다.
```text
Primitive Token
Semantic Token
Component Token
```
---
# 7. Primitive Spacing Token
기준 Unit:
`4px`
```text
space-0 0
space-1 4px
space-2 8px
space-3 12px
space-4 16px
space-5 20px
space-6 24px
space-8 32px
space-10 40px
space-12 48px
```
업무 Desktop에서는 `8px`을 기본 간격으로 사용한다.
과도한 24~32px 여백을 Form 내부에 반복하지 않는다.
---
# 8. Typography
기본 Font Stack:
```text
Pretendard
"Apple SD Gothic Neo"
"Noto Sans KR"
Arial
sans-serif
```
권장 Token:
```text
font-xs 12px
font-sm 13px
font-md 14px
font-lg 16px
font-xl 18px
font-2xl 20px
```
사용:
```text
Grid 13px
Helper 12~13px
Form 14px
Section Heading 16px
Page Heading 20px
```
업무 본문에서 16px 이상을 무조건 기본으로 사용하지 않는다.
---
# 9. Font Weight
```text
regular 400
medium 500
semibold 600
bold 700
```
일반 업무 데이터:
`400`
Label:
`500`
Section:
`600`
Page Title:
`600`
Bold 남용 금지.
---
# 10. Size Token
Desktop:
```text
control-xs 28px
control-sm 32px
control-md 36px
control-lg 40px
```
KBX 기본:
`control-sm / 32~34px`
일반 업무 입력:
`34px`
WMS Mobile:
`48px 이상`
---
# 11. Radius
```text
radius-sm 4px
radius-md 6px
radius-lg 8px
```
업무 화면 기본:
`4px`
Dashboard 카드가 아닌 Form과 Grid에 과도한 12~20px Radius를 사용하지 않는다.
---
# 12. Semantic Color
색상 자체보다 의미를 우선한다.
```text
surface
surface-muted
border
border-strong
text
text-muted
primary
success
warning
danger
info
focus
disabled
```
특정 업무 상태를 RGB 값으로 직접 작성하지 않는다.
---
# 13. 상태 색상 사용 원칙
색상은 보조수단이다.
예:
```text
⚠ 재고 부족
```
에서 `⚠`와 텍스트를 함께 사용한다.
단순히 행 전체를 빨간색으로 표시하지 않는다.
---
# 14. Density Token
```text
compact
comfortable
touch
```
### Compact
ERP/OMS Desktop 기본.
```text
Input 32~34
Grid row 32~34
```
### Comfortable
일반관리 및 가독성 우선.
```text
Input 36~40
Grid row 38~40
```
### Touch
WMS PDA/Mobile.
```text
48px+
```
---
# 15. KbxButton
## 목적
버튼의 외형뿐 아니라 다음 UX를 통제한다.
- 중요도
- Keyboard Hint
- Loading
- Disabled
- Permission
- Confirmation
---
## Variants
```text
primary
secondary
tertiary
danger
ghost
```
---
## 사용 규칙
한 Command 영역에 Primary 버튼은 원칙적으로 하나.
예:
```text
[조회]
[신규]
[저장]
```
`저장`만 Primary.
---
# 16. KbxButton API
개념 계약:
```ts
interface KbxButtonProps {
label: string
variant?: 'primary' | 'secondary' | 'tertiary' | 'danger' | 'ghost'
size?: 'sm' | 'md' | 'lg'
shortcut?: string
loading?: boolean
disabled?: boolean
permission?: string
confirm?: ConfirmDefinition
}
```
사용:
```vue
<KbxButton
label="저장"
shortcut="F8"
variant="primary"
:loading="saving"
@click="save"
/>
```
표시:
```text
[저장 F8]
```
---
# 17. 버튼 Label 정책
좋음:
```text
조회
저장
출고확정
재고조정
주문취소
```
나쁨:
```text
실행
처리
확인
Action
OK
```
업무 결과를 설명하는 동사를 사용한다.
---
# 18. KbxInput
기본 계약:
```ts
interface KbxInputProps {
modelValue?: string | null
label?: string
required?: boolean
readonly?: boolean
disabled?: boolean
placeholder?: string
helpText?: string
error?: string
maxLength?: number
}
```
---
# 19. Input 상태
모든 입력 컴포넌트는 동일하게 다음 상태를 지원한다.
```text
Default
Hover
Focus
Filled
Readonly
Disabled
Changed
Error
Warning
AI Suggested
```
`readonly``disabled`를 동일하게 표현하지 않는다.
---
# 20. Readonly 규칙
Readonly:
- 값 복사 가능
- Focus 허용 여부는 화면 목적에 따라 결정
- 수정 불가
Disabled:
- 업무 조건상 사용할 수 없음
- 일반적으로 Tab Stop 제외
사용자가 둘의 차이를 시각적으로 알 수 있어야 한다.
---
# 21. KbxNumberField
숫자를 String Input처럼 다루지 않는다.
지원:
```text
integer
decimal
quantity
money
percentage
```
내부 값과 Display Format은 분리한다.
예:
```text
Model = 1250000
Display = 1,250,000
```
---
# 22. KbxMoneyField
다음 정책을 가진다.
```text
decimal precision
currency
negative allowed
zero allowed
max
min
```
사용:
```vue
<KbxMoneyField
v-model="unitPrice"
label="단가"
/>
```
---
# 23. KbxQuantityField
수량은 Money와 의미가 다르다.
추가 속성:
```text
unit
availableQuantity
allowNegative
precision
```
예:
```text
출고수량
[ 10 ] EA
가용 8 EA
```
오류:
```text
출고 가능 수량은 8개입니다.
```
---
# 24. KbxDateField
기본적으로 지원:
```text
직접입력
Calendar
YYYY-MM-DD
Keyboard
```
사용자가 날짜를 마우스로만 선택하도록 강제하지 않는다.
가능:
```text
20260808
```
입력 후:
```text
2026-08-08
```
로 Normalize할 수 있다.
---
# 25. KbxDateRange
ERP 조회화면 핵심 Component.
빠른 선택:
```text
오늘
어제
최근 7일
이번달
지난달
직접선택
```
하지만 화면마다 빠른 기간 옵션을 다르게 만들지 않는다.
---
# 26. KbxSelect
값이 10~20개 이상이거나 검색 필요성이 높으면 Select보다 Lookup을 검토한다.
Select는 짧고 고정된 Enum에 사용한다.
적합:
```text
상태
단위
사용여부
주문유형
```
부적합:
```text
품목 50,000건
거래처 20,000건
```
---
# 27. KbxLookup
KBX에서 가장 중요한 Form Component 중 하나다.
목적:
`Code + Name + Search + Keyboard`
를 한 컴포넌트에서 해결한다.
---
# 28. KbxLookup 구조
```text
거래처
[10001] [대한상사 ] [검색]
```
상태에 따라:
```text
Code
Display
Search
```
구성.
---
# 29. Lookup API
개념 계약:
```ts
interface KbxLookupProps<TId> {
modelValue: TId | null
entity: string
label?: string
required?: boolean
disabled?: boolean
readonly?: boolean
allowCodeInput?: boolean
allowNameInput?: boolean
recent?: boolean
favorite?: boolean
}
```
---
# 30. Lookup Entity Provider
Lookup UI가 API URL을 직접 알지 않는다.
```ts
interface LookupProvider {
search(request: LookupSearchRequest): Promise<LookupResult>
resolve(request: LookupResolveRequest): Promise<LookupItem | null>
}
```
화면:
```text
Customer Lookup
```
은 Provider만 지정한다.
---
# 31. Lookup Keyboard Contract
```text
F2
→ 검색 Popup
Enter
→ 코드 Resolve 또는 선택
Esc
→ Popup 닫기
↑ ↓
→ 결과 이동
Enter
→ 결과 확정
```
선택 후:
`다음 Form Control`
로 Focus 이동.
---
# 32. Lookup 검색 결과
기본 컬럼은 Entity별로 Schema화한다.
Customer:
```text
코드
거래처명
사업자번호
대표자
상태
```
Item:
```text
품목코드
품목명
규격
단위
가용재고
```
Warehouse:
```text
창고코드
창고명
구분
```
---
# 33. Lookup에서 AI 사용
검색 정확도를 높이기 위한 보조 용도로만 쓴다.
사용자:
```text
대한 강남
```
AI/검색엔진이 후보를 넓힐 수 있지만 결과는 반드시 실제 Entity여야 한다.
AI가 Entity 자체를 생성하지 않는다.
---
# 34. KbxSearchPanel
조회 화면의 검색조건을 표준화한다.
구조:
```text
Primary Filters
More Filters
Search Action
Reset
Saved Search
```
---
# 35. Search Panel API
```ts
interface KbxSearchPanelProps {
schema: SearchSchema
modelValue: Record<string, unknown>
remember?: boolean
savedSearch?: boolean
}
```
업무 화면에서 각 Label/Grid를 직접 배치하지 않는다.
---
# 36. Search Schema 예
```ts
const orderSearchSchema = [
{
field: 'period',
type: 'dateRange',
label: '주문기간'
},
{
field: 'channelId',
type: 'lookup',
label: '판매채널'
},
{
field: 'status',
type: 'select',
label: '상태'
}
]
```
단, 모든 복잡 화면을 Schema화할 필요는 없다.
---
# 37. 조회 Keyboard
화면 어디서든:
```text
F3 = 조회
```
단 입력 Editor나 브라우저 기능과 충돌 여부를 KBX Keyboard Manager에서 판단한다.
---
# 38. KbxCommandBar
Command 순서를 통제한다.
Slot을 무제한으로 열어주지 않는다.
논리 그룹:
```text
query
edit
workflow
output
more
```
---
# 39. Command Bar 예
```vue
<KbxCommandBar>
<KbxCommand group="query" action="search" />
<KbxCommand group="edit" action="new" />
<KbxCommand group="edit" action="save" />
<KbxCommand group="workflow" action="ship" />
<KbxCommand group="output" action="excel" />
</KbxCommandBar>
```
렌더링:
```text
[조회] [신규] [저장] │ [출고지시] │ [엑셀▼]
```
---
# 40. KbxDataGrid
AG Grid를 직접 외부 API처럼 노출하지 않는다.
`KbxDataGrid`가 다음을 통합한다.
- 기본 Theme
- Header
- Row density
- Selection
- Clipboard
- Excel
- Editing
- Validation
- Status
- Empty
- Loading
- Saved columns
- Permission
- Keyboard
---
# 41. Grid API
개념:
```ts
interface KbxDataGridProps<T> {
rows: T[]
columns: KbxGridColumn<T>[]
rowKey: keyof T
loading?: boolean
selection?: 'none' | 'single' | 'multiple'
editable?: boolean
clipboard?: boolean
exportable?: boolean
personalization?: boolean
summary?: KbxGridSummary[]
}
```
---
# 42. Column Contract
```ts
interface KbxGridColumn<T> {
field: keyof T
header: string
width?: number
minWidth?: number
align?: 'left' | 'center' | 'right'
type?: GridDataType
editable?: boolean
sortable?: boolean
filterable?: boolean
pinned?: 'left' | 'right'
lookup?: LookupDefinition
formatter?: string
permission?: string
}
```
---
# 43. Grid Data Type
공통:
```text
text
code
number
quantity
money
percent
date
datetime
status
boolean
lookup
link
```
타입에 따라 정렬과 포맷을 자동 설정한다.
예:
```text
type = money
→ right align
→ thousand separator
```
---
# 44. Grid Column 기본 너비
권장:
```text
Checkbox 42
Status 80~100
Code 110~140
Date 110
DateTime 150~170
Quantity 90~110
Money 120~150
Name 180~240
Remark 240+
```
무조건 Auto Size해서 화면이 흔들리게 하지 않는다.
---
# 45. Grid Selection
Checkbox selection은 항상 왼쪽에 위치한다.
```text
□ │ 상태 │ 주문번호 ...
```
Header Checkbox:
현재 Filter 결과 전체 선택인지 현재 Page 선택인지 명확히 표시한다.
대량 데이터에서 클라이언트 전체 Select라고 오해하게 만들지 않는다.
---
# 46. Grid Multi Selection
선택하면 하단 또는 상단에:
```text
17건 선택
```
을 명시한다.
BulkActionBar와 연결한다.
---
# 47. KbxBulkActionBar
```text
17건 선택
[출고지시]
[보류]
[담당자 변경]
```
선택이 0이면 숨기거나 Disabled.
Action마다:
```text
minSelection
maxSelection
permission
allowedStatuses
```
설정 가능.
---
# 48. Grid Editing
편집 상태를 Row 전체가 아니라 Cell 중심으로 표시한다.
변경 Cell:
```text
Changed
```
Validation 실패:
```text
Error + message
```
저장 성공:
Changed 상태 제거.
---
# 49. Grid Clipboard
Excel 호환성이 최우선이다.
지원:
```text
Ctrl+C
Ctrl+V
multi-cell copy
multi-row paste
```
붙여넣기 전에 각 Cell 타입 변환.
예:
```text
"1,200"
→ decimal 1200
```
---
# 50. 대량 Paste Validation
100행 붙여넣었다고 Validation Modal 100개를 띄우지 않는다.
Grid:
```text
7개 셀 오류
```
표시.
오류 탐색:
```text
[첫 오류로]
[다음 오류]
```
지원.
---
# 51. Enter 동작
Editing Grid:
```text
Enter
→ 입력 확정
→ 다음 Cell 또는 다음 Row
```
구체적인 이동방향은 Template에서 정의하되 같은 유형 화면에서 일관되어야 한다.
---
# 52. Tab 동작
Tab은 Editor 안에 갇히면 안 된다.
Grid 내부:
```text
Tab
→ 다음 Editable Cell
```
마지막 Cell:
새 Row가 허용되는 Fast Entry에서는:
```text
새 행
```
일반 조회 Grid에서는 Grid 밖 다음 Control.
---
# 53. KbxStatus
제품 전체 상태 Dictionary를 사용한다.
공통 Semantic:
```text
draft
pending
ready
processing
completed
hold
warning
error
cancelled
disabled
```
업무 상태는 여기에 Domain Label을 Mapping한다.
예:
```text
Domain: PickingCompleted
Semantic: completed
Label: 피킹완료
```
---
# 54. Status 난립 방지
신규 상태 정의 전 다음을 확인한다.
```text
이미 같은 의미가 존재하는가?
업무적으로 정말 다른 상태인가?
UI 표시만 다른 것인가?
```
`완료`, `완료됨`, `처리완료` 같은 중복 상태명 생성을 막는다.
---
# 55. KbxFormSection
Master/Transaction의 Section 표준.
```text
기본정보
────────────────────────
```
Accordion은 정보가 많을 때 사용하지만 핵심 Section을 기본 접힘으로 만들지 않는다.
---
# 56. Form Grid
기본 Desktop:
```text
12-column
```
그러나 개발자가 Bootstrap처럼 자유롭게 조합하게 두지 않는다.
대표 폭 Preset:
```text
field-sm
field-md
field-lg
field-full
```
---
# 57. Label Width
기본:
```text
96px
```
업무별 장문 Label:
```text
120px
```
한 화면에서 Label 폭을 가능한 한 통일한다.
---
# 58. 오류 Message
Field 오류는 Field 바로 아래.
```text
주문수량
[-1]
주문수량은 0보다 커야 합니다.
```
전체 오류가 있으면 상단에 Summary도 허용.
```text
저장할 수 없습니다. 3개 항목을 확인하세요.
```
클릭 시 오류 Field로 이동 가능.
---
# 59. Business Error
Field에 귀속되지 않는 업무 오류:
```text
출고할 수 없습니다.
주문 3건에 재고가 부족합니다.
[부족 주문 보기]
```
사용자가 다음 행동을 알 수 있어야 한다.
---
# 60. KbxDialog
Modal은 제한적으로 사용한다.
Size Preset:
```text
sm
md
lg
```
전체 화면 Modal은 원칙적으로 금지.
복잡 업무는 Page 또는 Drawer.
---
# 61. Dialog Keyboard
```text
Esc = 닫기
Enter = Primary Action
```
단 Textarea/Form 입력 중 Enter submit을 무조건 발생시키지 않는다.
Focus Trap 필수.
닫힌 뒤 Focus Restore 필수.
---
# 62. KbxDrawer
사용 용도:
- 상세 조회
- Audit
- Help
- AI
- Contextual Detail
편집이 길어지면 Page로 승격.
---
# 63. KbxToast
성공:
```text
저장했습니다.
```
실패:
중요 업무 오류는 Toast만 사용하지 않는다.
Toast는 시간이 지나면 사라지므로 해결이 필요한 오류에는 부적합하다.
---
# 64. Confirm 표준
위험 수준:
```text
low
medium
high
```
Low:
Undo 가능한 작업은 Confirmation 생략 가능.
High:
```text
출고를 확정하시겠습니까?
128건의 주문이 출고 상태로 변경됩니다.
확정 후 주문수량을 수정할 수 없습니다.
[취소]
[출고 확정]
```
---
# 65. KbxExcelMenu
모든 입력형 화면의 Excel 메뉴:
```text
엑셀 ▼
├ 현재 조회결과 다운로드
├ 업로드 양식 다운로드
├ 엑셀 업로드
├ Excel 붙여넣기
└ 최근 업로드 결과
```
화면별 메뉴명을 임의로 바꾸지 않는다.
---
# 66. Import Field Definition
공통 Field Metadata:
```ts
interface KbxFieldDefinition {
key: string
label: string
aliases?: string[]
dataType: string
required?: boolean
maxLength?: number
precision?: number
scale?: number
lookup?: string
importable?: boolean
exportable?: boolean
readonly?: boolean
sensitive?: boolean
}
```
---
# 67. Excel Mapping Confidence
자동 Mapping 유형:
```text
Exact
Alias
Saved
AI
Manual
```
UI에서 Source를 식별 가능하게 한다.
예:
```text
상품코드 → 품목코드
Alias 일치
```
AI:
```text
업체 → 거래처코드
AI 추천 87%
```
AI 추천을 확정값처럼 보이지 않는다.
---
# 68. Import Validation
구분:
```text
Format Error
Reference Error
Business Error
Duplicate
Warning
```
예:
```text
Format
날짜 형식 오류
Reference
존재하지 않는 품목
Business
출고완료 주문 수정 불가
Duplicate
동일 주문번호 중복
```
---
# 69. KbxJobProgress
Hangfire 기반 장시간 작업 UX.
상태:
```text
Queued
Running
Completed
PartiallyCompleted
Failed
Cancelled
```
UI:
```text
주문 Excel Import
13,421 / 17,894
75%
정상 13,218
오류 203
```
---
# 70. SignalR 연결
장시간 작업은 Polling만으로 구현하지 않는다.
권장:
```text
Command
→ Job 생성
→ Hangfire
→ Progress 저장
→ SignalR push
```
Refresh 후에도 Job 상태를 API로 복구한다.
SignalR은 편의 Channel이지 Source of Truth가 아니다.
---
# 71. KbxAuditTrail
필수 표현:
```text
Actor
Time
Action
Old
New
Reason
Source
```
Source:
```text
User
System
Import
API
AIApproved
Batch
```
---
# 72. 사용자용 Audit와 기술 Audit 분리
사용자:
```text
수량 10 → 8
```
기술 추적:
```text
CorrelationId
RequestId
EventId
CommandId
OutboxId
```
기술 ID를 일반 화면에 노출하지 않는다.
`상세 기술정보`에서만 확인 가능.
---
# 73. KbxHelpPanel
Help는 Screen ID와 연결한다.
```text
screenId = OMS-ORD-001
```
구성:
```text
화면 목적
기본 사용법
단축키
주요 상태
자주 발생하는 오류
관련 화면
```
---
# 74. 도움말 유지보수
화면 코드 내부에 긴 도움말 문자열을 직접 넣지 않는다.
Help Content는 버전 관리 가능한 별도 콘텐츠로 관리.
ScreenVersion과 연계하면 더 좋다.
---
# 75. KbxAiPanel
AI Panel이 직접 Domain API를 임의 호출하지 않는다.
AI interaction:
```text
Screen Context
AI Service
Tool/Query
Proposal
Domain Command
```
---
# 76. AI Context
AI에 보낼 수 있는 Context는 명시적으로 정의한다.
예:
```ts
interface AiScreenContext {
screenId: string
module: string
selectedIds?: string[]
filters?: unknown
currentEntityId?: string
}
```
화면 전체 DOM이나 민감 데이터 전체를 무차별 전달하지 않는다.
---
# 77. AI Action Contract
AI 응답을 자연어로 Parsing하여 실행하지 않는다.
Structured Action:
```text
type
entityIds
parameters
reason
confidence
source
```
형태로 검증한다.
---
# 78. AI Proposal Component
모든 변경 제안은 공통 UX:
```text
AI 제안
대상
17건
변경
서울센터 → 인천센터
근거
인천센터 가용재고 충분
[취소]
[상세보기]
[적용]
```
---
# 79. AI Permission
AI가 사용자보다 높은 권한을 가지면 안 된다.
```text
AI effective permission
=
current user permission
AI allowed actions
```
로 이해하면 된다.
---
# 80. AI Hallucination Guard
Action 실행 전 Server가 반드시 확인:
```text
Entity 존재
현재 상태
권한
Version
Business Rule
Reference Integrity
```
AI confidence는 Domain Validation을 대체하지 않는다.
---
# 81. Optimistic Concurrency UX
업무 시스템에서 중요한 항목이다.
사용자가 오래 열어둔 주문을 다른 사용자가 수정한 경우:
```text
다른 사용자가 이 주문을 변경했습니다.
현재 화면
수량 10
최신 값
수량 8
[최신 내용 보기]
```
무조건 마지막 저장자가 덮어쓰게 하지 않는다.
---
# 82. Version Token
Transaction에:
```text
version
rowVersion
updatedAt
```
등의 동시성 기준을 둔다.
PostgreSQL 환경에서는 별도 Version Column을 명시적으로 운영하는 편이 감사·재현성 측면에서 이해하기 쉽다.
---
# 83. Unsaved Change Standard
Form Dirty 상태는 공통 Composable에서 관리한다.
```text
useKbxDirtyState()
```
Page/Workspace Tab 이동 모두 동일한 규칙 적용.
---
# 84. Keyboard Manager
전역 단축키는 하나의 Manager에서 관리한다.
개념:
```text
useKbxShortcut()
```
Scope:
```text
Application
Page
Grid
Dialog
Editor
```
우선순위가 있어야 한다.
---
# 85. Shortcut Priority
예:
Dialog Open 상태에서:
```text
Esc
```
는 Page가 아니라 Dialog가 처리한다.
Grid Cell Editing 중:
```text
Enter
```
는 Global Command가 아니라 Cell Editor가 처리한다.
---
# 86. 공통 단축키
```text
F2 Lookup
F3 조회
F8 저장/Primary commit
Ctrl+S 저장
Esc Context cancel
```
화면별 임의 F-Key 추가는 검토 후 승인.
---
# 87. Browser Shortcut 보호
다음 키는 함부로 Override하지 않는다.
```text
F5
Ctrl+L
Ctrl+T
Ctrl+W
Ctrl+R
```
웹 앱이 Desktop ERP를 흉내낸다는 이유로 브라우저 기본 기능을 파괴하지 않는다.
---
# 88. WMS Barcode Component
`KbxBarcodeCapture`
필요 기능:
```text
keyboard wedge
camera scanner
duplicate debounce
terminator handling
offline queue
sound feedback
vibration
```
---
# 89. Barcode 중복 입력 방지
Scanner가 동일 Barcode를 매우 짧은 시간에 중복 전송할 수 있다.
Client UX 레벨 debounce와 Server Idempotency를 모두 둔다.
Client만으로 중복을 막지 않는다.
---
# 90. Offline Command
WMS 일부 업무가 Offline Queue를 허용한다면 Command마다 정책을 명확히 한다.
```text
offlineAllowed
requiresOnlineValidation
conflictPolicy
```
모든 업무를 무조건 Offline 지원하려 하지 않는다.
재고 확정 등 강한 정합성이 필요한 Action은 Online 요구가 더 적절할 수 있다.
---
# 91. Network Indicator
PDA 상단:
```text
● 온라인
```
불안정:
```text
▲ 연결 불안정
3건 전송 대기
```
오프라인:
```text
○ 오프라인
```
사용자가 동일 작업을 반복하지 않게 한다.
---
# 92. KbxWmsActionButton
현장 CTA는 Desktop Button과 별도 규격.
```text
높이 52~56
큰 Label
아이콘은 보조
```
예:
```text
[작업 시작]
[재고부족 신고]
[다음 주문]
```
---
# 93. WMS 오류 우선순위
1. 사용자가 지금 무엇을 해야 하는가
2. 무엇이 잘못되었는가
3. 기술적인 상세
예:
좋음:
```text
A-03-02 위치로 이동하세요.
현재 스캔한 위치는 A-03-01입니다.
```
나쁨:
```text
Location validation failed.
```
---
# 94. Screen Template Contract
모든 Template은 기본적으로 다음 Slot을 가진다.
```text
title
commands
search
content
summary
utility
```
임의 위치에 버튼을 넣는 것을 제한한다.
---
# 95. KbxListPage
표준:
```text
PageHeader
CommandBar
SearchPanel
KPI/QuickFilter(optional)
Grid
Summary
UtilityRail
```
---
# 96. KbxMasterPage
표준:
```text
PageHeader
CommandBar
MasterList(optional)
Form
Tabs(optional)
Audit
```
---
# 97. KbxTransactionPage
표준:
```text
PageHeader
CommandBar
HeaderForm
DetailGrid
Summary
Workflow
Audit
```
---
# 98. KbxFastEntryPage
표준:
```text
Minimal Header
Compact Command
Fast Entry Grid
Validation Summary
Total
```
불필요한 카드/Section을 줄인다.
---
# 99. KbxQueuePage
```text
Work Summary
Exception Summary
Queue Grid
Quick Actions
```
시각적 Dashboard보다 Actionable Queue를 우선한다.
---
# 100. KbxReconcilePage
```text
Criteria
Summary
Mismatch Filter
Comparison Grid
Resolution Action
Audit
```
---
# 101. Empty/Loading/Error Contract
모든 데이터 컴포넌트가 세 상태를 반드시 구현한다.
```text
Loading
Empty
Error
```
화면마다 임의로 만들지 않는다.
---
# 102. Loading
첫 조회:
```text
조회 중...
```
재조회:
기존 데이터를 유지하고 작은 Loading Indicator를 추가.
사용자가 화면 Context를 잃지 않게 한다.
---
# 103. Error Recovery
API 실패:
```text
주문을 조회하지 못했습니다.
네트워크 연결을 확인한 후 다시 시도하세요.
[다시 조회]
```
가능하면 사용자가 입력한 검색조건을 보존한다.
---
# 104. Permission UX
권한 없음의 두 종류를 구분한다.
### 기능 자체가 필요 없는 사용자
숨김 가능.
### 기능 존재를 알아야 하지만 실행 권한 없음
Disabled + 이유.
예:
```text
[출고취소]
권한이 없습니다.
```
업무 맥락에 따라 결정한다.
---
# 105. Masking
개인정보:
```text
010-****-1234
```
권한이 있는 사용자는:
```text
[전체보기]
```
Audit을 남기도록 설계 가능.
---
# 106. Component Telemetry
공통 Component에 최소한의 UX Event를 구조화한다.
예:
```text
screen.open
search.execute
lookup.open
lookup.select
grid.bulk_action
excel.import
validation.error
ai.proposal
ai.accept
```
사용자 감시가 아니라 UX 개선과 장애 분석 목적.
민감 값을 Telemetry에 직접 넣지 않는다.
---
# 107. UX Metric 연결
이벤트로 다음을 계산할 수 있어야 한다.
```text
Task completion time
Clicks per task
Manual intervention
Validation failure
Import failure
Bulk action rate
AI acceptance
Exception resolution time
```
---
# 108. Component Version
주요 공통 Component:
```text
KbxDataGrid 1.4.2
KbxLookup 1.2.0
```
식의 Version을 배포 Artifact 수준에서 식별 가능하게 한다.
운영 오류 재현에 도움이 된다.
---
# 109. SOLID — SRP
`KbxLookup`은 Lookup UX를 담당한다.
거래처 Business Rule까지 넣지 않는다.
```text
Lookup UX
Customer Domain
```
---
# 110. OCP
새 Entity Lookup:
기존 KbxLookup 변경보다 Provider 추가를 우선한다.
```text
CustomerLookupProvider
ItemLookupProvider
WarehouseLookupProvider
```
---
# 111. LSP
모든 Lookup Provider는 동일한 기본 Search/Resolve 계약을 지켜야 한다.
특정 Provider만 Enter가 다르게 동작하는 방식은 피한다.
---
# 112. ISP
거대한:
```text
IKbxEverythingService
```
를 만들지 않는다.
예:
```text
LookupProvider
ExcelSchemaProvider
PermissionProvider
HelpProvider
```
로 책임 분리.
---
# 113. DIP
KBX Component가 OMS/WMS/ERP Module을 직접 의존하지 않는다.
업무 Module이 KBX Contract를 구현한다.
---
# 114. Pattern 선택
적극 사용할 패턴:
```text
Adapter
Strategy
Command
Specification
Provider
Policy
Composite
State
```
패턴 자체가 목적이 되어서는 안 된다.
---
# 115. 과도한 추상화 금지
컴포넌트 2개에서만 쓰는 로직을 미리 범용 Framework로 만들지 않는다.
원칙:
```text
반복이 관찰된 뒤 추상화
```
단, Excel, Grid, Lookup, Audit처럼 반복이 명백한 핵심 영역은 선제 표준화한다.
---
# 116. Normalization
Field Dictionary는 정규화된 Concept를 유지한다.
```text
CustomerId
CustomerCode
CustomerName
```
화면마다:
```text
Cust
Client
Partner
Customer
```
식으로 내부 FieldKey를 달리 만들지 않는다.
표시 Label은 업무별 변경 가능.
---
# 117. Denormalized Read Model
Grid 성능과 UX를 위해:
```text
OrderSearchRow
```
에는:
```text
CustomerName
ChannelName
ItemSummary
ExceptionCount
```
등을 포함할 수 있다.
정규화 원칙을 UX 조회 Projection에 기계적으로 적용하지 않는다.
---
# 118. 코드 리팩토링 기준
다음 신호가 보이면 KBX로 끌어올릴지 검토한다.
```text
동일 UI 코드 3회 이상
동일 Keyboard 처리 반복
동일 Validation 표시 반복
동일 Grid option 반복
동일 Excel 처리 반복
```
단 업무 Rule이 다르다면 공통화하지 않는다.
---
# 119. 기술부채 등록
KBX 예외 구현은 반드시 이유를 남긴다.
예:
```text
KBX Exception
Screen: WMS-PACK-003
Reason:
Bluetooth scale integration requires custom input lifecycle.
Review:
2026-Q4
```
예외가 조용히 영구 기술부채가 되지 않게 한다.
---
# 120. Vibe Coding 규칙
AI Coding Agent에게 자유 디자인을 맡기지 않는다.
Prompt 계약:
```text
Screen Template:
KbxListPage
Search:
OrderSearchSchema
Grid:
OrderGridSchema
Actions:
search, ship, hold, excel
```
AI가 결정할 영역:
```text
업무 연결 코드
Type 정의
API 호출
테스트
```
AI가 임의 결정하지 않을 영역:
```text
버튼 위치
Grid UX
Keyboard
Excel UX
Status UX
```
---
# 121. Hallucination 방지 — Code Generation
AI가 존재하지 않는 KBX Component를 생성하면 안 된다.
Component Manifest를 제공한다.
예:
```text
KbxButton
KbxLookup
KbxDataGrid
...
```
Manifest에 없는 Component는 새로 만들기 전에 검토한다.
---
# 122. Component Manifest
각 Component에:
```text
Name
Purpose
AllowedUse
ForbiddenUse
Props
Events
Keyboard
Accessibility
Examples
Version
Owner
```
를 기록한다.
이 문서가 AI Coding Grounding 자료가 된다.
---
# 123. Storybook 수준의 Component Catalog 권장
컴포넌트별:
```text
Default
Readonly
Disabled
Required
Error
Loading
Keyboard
Compact
```
을 재현 가능하게 한다.
어떤 도구를 사용하든 목적은 동일하다.
**컴포넌트 상태를 독립적으로 재현 가능하게 만드는 것.**
---
# 124. Visual Regression
공통 Component 변경 시:
```text
Desktop Compact
Desktop Comfortable
WMS Touch
```
최소 세 Density 검증.
---
# 125. Vitest Contract Test
예: `KbxLookup`
반드시 확인:
```text
F2 opens lookup
Esc closes
Enter resolves
Arrow navigation
Enter selects
Focus returns
Readonly blocks edit
Disabled removes interaction
Invalid code shows error
```
---
# 126. Playwright Screen Test
OMS 주문조회:
```text
화면 진입
→ 주문기간 확인
→ F3 조회
→ Grid 결과
→ 행 선택
→ Bulk Action
→ 결과 확인
```
---
# 127. Keyboard E2E
별도 Mouse 사용 없이:
```text
주문등록 진입
→ 거래처 F2
→ 검색
→ Enter
→ 품목
→ 수량
→ F8 저장
```
완료 가능한지를 자동화한다.
이 테스트가 실제 ERP UX 품질을 상당히 잘 검증한다.
---
# 128. Excel E2E
```text
양식 다운로드
→ 샘플 업로드
→ Mapping
→ Validation
→ Commit
→ 결과 확인
```
그리고 오류 파일 Scenario도 테스트한다.
---
# 129. WMS E2E
Scanner Event를 모사하여:
```text
Location scan
→ Item scan
→ Quantity 증가
→ 다음 상품
```
을 검증한다.
중복 Scan과 Network 재시도도 포함한다.
---
# 130. UX Definition of Done
새 Component는 다음을 만족해야 한다.
```text
Design Token 사용
Keyboard 정의
Mouse 정의
Loading 정의
Readonly 정의
Disabled 정의
Error 정의
Accessibility 정의
Permission 정의
Testing 정의
Documentation 정의
```
---
# 131. Screen Definition of Done
새 화면은:
```text
Template 선택
Command 표준
Search 표준
Grid 표준
Keyboard 지원
Excel 정책
Validation
Audit
Permission
Error Recovery
Empty
Loading
Unsaved Change
Playwright
```
가 정의되어야 한다.
---
# 132. 사용자 교육 최소화 검증
디자인 리뷰 때 화면을 처음 보는 내부 사용자에게 설명 없이 다음 업무를 시켜본다.
예:
```text
오늘 주문을 조회하세요.
재고부족 주문을 찾아보세요.
주문 3건을 선택해서 출고지시하세요.
```
사용자가 메뉴얼 없이 수행할 수 있어야 한다.
---
# 133. UX 혁신 판단
새 Component 제안이 나왔을 때:
```text
기존 사용문법으로 해결 가능한가?
```
YES:
기존 문법을 우선.
새로운 Interaction이:
```text
클릭 감소
입력 감소
오류 감소
판단 감소
```
중 명확한 이익을 주지 않으면 도입하지 않는다.
---
# 134. 최종 Component 구성
KBX 1차 필수 구현 범위:
```text
KbxButton
KbxInput
KbxNumberField
KbxMoneyField
KbxQuantityField
KbxDateField
KbxDateRange
KbxSelect
KbxLookup
KbxPageHeader
KbxCommandBar
KbxSearchPanel
KbxFormSection
KbxDataGrid
KbxBulkActionBar
KbxStatus
KbxDialog
KbxDrawer
KbxToast
KbxConfirm
KbxExcelMenu
KbxExcelImport
KbxJobProgress
KbxAuditTrail
KbxHelpPanel
KbxAiPanel
KbxProposalPanel
KbxListPage
KbxMasterPage
KbxTransactionPage
KbxMasterDetailPage
KbxQueuePage
KbxReconcilePage
KbxWmsMobilePage
```
이 정도면 OMS/WMS/ERP 초기 업무 화면 대부분을 커버할 수 있다.
---
# 135. 가장 중요한 구현 원칙
PrimeVue와 AG Grid를 없애거나 대체하는 것이 목표가 아니다.
오히려 검증된 제품을 적극 사용한다.
다만:
```text
PrimeVue API
AG Grid API
```
가 제품 화면 전체로 새어나가지 않게 한다.
우리 제품이 의존해야 할 API는:
```text
KBX Business UX Contract
```
이다.
그래야 라이브러리 업그레이드, UX 개선, 키보드 정책 변경을 공통 계층에서 해결할 수 있다.
---
# 136. KBX의 최종 가치
이 구조가 정착되면 신규 화면을 만들 때 질문이 달라진다.
기존:
> 버튼은 어디에 두죠?
> 검색창은 어떻게 만들죠?
> Grid는 어떤 옵션을 쓰죠?
> Excel 업로드는 어떻게 하죠?
> F2는 어떻게 처리하죠?
KBX 이후:
> 이 화면은 어떤 업무인가?
> 사용자가 정말 판단해야 하는 것은 무엇인가?
> 어떤 입력을 자동화할 수 있는가?
> 어떤 예외만 사용자에게 보여줄 것인가?
디자인 결정의 상당 부분이 이미 끝나 있기 때문이다.
그 상태가 우리가 원하는 **표준화된 한국형 업무 UX/AX 플랫폼**이다.