2890 lines
36 KiB
Markdown
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 플랫폼**이다. |