feat(components): implement 4-layer input component architecture and 52-section specification with harness CLI v3.0 verification
Validators (Pushes and Pull Requests) / Notify PR Results (push) Has been cancelled
Validators (Pushes and Pull Requests) / Security & Secrets (push) Has been cancelled
Validators (Pushes and Pull Requests) / WBS & Audit Validations (push) Has been cancelled
Validators (Pushes and Pull Requests) / .NET Contracts (push) Has been cancelled
Validators (Pushes and Pull Requests) / Core Validators & Database Setup (push) Has been cancelled
Validators (Pushes and Pull Requests) / Calibration & Performance (push) Has been cancelled
Validators (Pushes and Pull Requests) / Operational Report & Decision Packet (push) Has been cancelled
Validators (Pushes and Pull Requests) / CI Workflow Lint (push) Has been cancelled
Validators (Pushes and Pull Requests) / UI & Storage Validation (push) Failing after 10s
Validators (Pushes and Pull Requests) / Database & Schema Validation (push) Successful in 10s
Validators (Pushes and Pull Requests) / Notify PR Results (push) Has been cancelled
Validators (Pushes and Pull Requests) / Security & Secrets (push) Has been cancelled
Validators (Pushes and Pull Requests) / WBS & Audit Validations (push) Has been cancelled
Validators (Pushes and Pull Requests) / .NET Contracts (push) Has been cancelled
Validators (Pushes and Pull Requests) / Core Validators & Database Setup (push) Has been cancelled
Validators (Pushes and Pull Requests) / Calibration & Performance (push) Has been cancelled
Validators (Pushes and Pull Requests) / Operational Report & Decision Packet (push) Has been cancelled
Validators (Pushes and Pull Requests) / CI Workflow Lint (push) Has been cancelled
Validators (Pushes and Pull Requests) / UI & Storage Validation (push) Failing after 10s
Validators (Pushes and Pull Requests) / Database & Schema Validation (push) Successful in 10s
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
# OMS·WMS·ERP 공통 CRUD 화면 및 입력 컴포넌트 상용화 지침 명세
|
||||
# OMS·WMS·ERP 입력 컴포넌트 및 CRUD 상세 명세
|
||||
|
||||
## 0. 템플릿 체계
|
||||
|
||||
### 0.1 표준 템플릿 ID
|
||||
## 0. 템플릿 체계 (TPL-LIST-01 ~ TPL-HISTORY-01)
|
||||
|
||||
| 템플릿 ID | 화면 유형 | 대표 업무 |
|
||||
| :--- | :--- | :--- |
|
||||
@@ -18,196 +16,279 @@
|
||||
| `TPL-APPROVAL-01` | 승인·반려 | 발주 승인, 전표 승인 |
|
||||
| `TPL-HISTORY-01` | 변경 이력 | 값 변경, 상태 전이, 시스템 처리 이력 |
|
||||
|
||||
CRUD 화면을 단순히 URL 네 개로 구현하지 않고, 업무 위험도와 데이터 생명주기에 따라 템플릿을 분리한다.
|
||||
---
|
||||
|
||||
## 1. 목적과 적용 범위
|
||||
본 명세의 목적은 OMS·WMS·ERP에서 사용하는 모든 입력 컴포넌트를 표준화하는 것이다.
|
||||
* 사용자가 잘못 입력하기 어렵게 한다.
|
||||
* 잘못 입력해도 쉽게 발견하고 복구할 수 있게 한다.
|
||||
* 화면과 서버의 데이터 해석이 달라지지 않게 한다.
|
||||
* 사용자 입력, 시스템 계산, 외부 연동, AI 추천값을 구분한다.
|
||||
* 적용 범위: OMS(주문/반품/배송/결제), WMS(입고/피킹/출고/재고), ERP(발주/전표/비용), 마스터(조직/사용자/코드/창고/단위).
|
||||
|
||||
---
|
||||
|
||||
## 1. 최상위 설계 원칙 & 전체 화면 공통 골격
|
||||
|
||||
### 1.1 CRUD가 아니라 업무 트랜잭션으로 정의한다
|
||||
|
||||
> 주문 조회 → 재고 할당 → 피킹 지시 → 피킹 확정 → 패킹 → 출고 확정 → 운송장 반영 → 취소 또는 역처리
|
||||
|
||||
완료된 거래 데이터를 삭제하거나 직접 덮어쓰는 방식보다 **취소·반제·역처리 트랜잭션**을 생성하는 방식이 이력성과 재현성 측면에서 안전하다.
|
||||
|
||||
### 1.2 기본 레이아웃 (Global Header / Page Header / Sticky Action Bar)
|
||||
|
||||
## 2. 입력 컴포넌트 계층 (4계층 아키텍처)
|
||||
```text
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ Global Header │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Breadcrumb │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Page Header │
|
||||
│ [화면명] [상태] [식별번호] [주요 작업 버튼] │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Context Bar │
|
||||
│ 사업장 / 창고 / 기준일 / 데이터 최신시각 / 잠금 상태 │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Main Content │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Sticky Action Bar │
|
||||
│ [취소] [임시저장] [저장] [확정] │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
Primitive (`components/primitives/`)
|
||||
↓
|
||||
Typed Field (`components/fields/`)
|
||||
↓
|
||||
Domain Field (`components/domain-fields/`)
|
||||
↓
|
||||
Business Composite (`components/business-composites/`)
|
||||
```
|
||||
* **2.1 Primitive**: TextInput, Button, Checkbox, Select, Dialog 등 시각/상호작용 업무 무지 컴포넌트.
|
||||
* **2.2 Typed Field**: StringField, IntegerField, DecimalField, DateField, CodeField 등 데이터 타입 이해 컴포넌트.
|
||||
* **2.3 Domain Field**: QuantityField, MoneyField, LotField, SerialNumberInput, ItemLookup 등 업무 도메인 이해 컴포넌트.
|
||||
* **2.4 Business Composite**: AddressEditor, OrderLineEditor, InventoryAllocationEditor, BarcodeWorkInput 등 여러 필드 및 규칙 묶음.
|
||||
|
||||
---
|
||||
|
||||
## 2. 전체 아키텍처 방향 및 공통 화면 상태
|
||||
|
||||
입력 화면은 다음 5개 계층(`UI Primitive` → `도메인 필드` → `업무 패턴` → `화면 템플릿` → `프로세스`)으로 분리하며, `Initial Loading`, `Record Locked`, `Version Conflict`, `Offline` 등 16가지 화면 상태를 공통 제공해야 한다.
|
||||
## 3. 공통 필드 해부 구조
|
||||
Label, Required Indicator, Business Status Indicator, Input Control, Prefix/Suffix, Supporting Information, Validation Message, Audit/Source Information으로 구성.
|
||||
|
||||
---
|
||||
|
||||
## 3. 권한 모델
|
||||
|
||||
화면 권한은 최소 네 계층(`화면 접근` → `작업` → `필드` → `데이터 범위`)으로 나눈다.
|
||||
## 4. 공통 데이터 모델 (`FieldDefinition` / `FieldState`)
|
||||
`FieldDefinition` 및 `FieldState` 모델 정의. `FieldMessage` 오류 코드로 통제.
|
||||
|
||||
---
|
||||
|
||||
## 4. `TPL-LIST-01` 목록·검색 템플릿
|
||||
|
||||
필수 요구사항:
|
||||
* 저장된 검색조건과 개인별 기본 필터
|
||||
* 컬럼 표시·숨김·순서·폭 저장 (`sizeColumnsToFit`)
|
||||
* 다중 조건 필터 및 조건 그룹
|
||||
* 서버 기반 정렬·필터·페이지 처리
|
||||
* 선택 행 유지 및 엑셀 다운로드
|
||||
## 5. 필드 상태 의미 (`FieldStatus`)
|
||||
`idle`, `focused`, `dirty`, `validating`, `valid`, `warning`, `invalid`, `saving`, `saved`, `conflict`, `readonly`, `disabled`, `blocked` 13가지 상태 엄격 구분.
|
||||
|
||||
---
|
||||
|
||||
## 5. `TPL-CREATE-01` 단일 등록 템플릿
|
||||
|
||||
적용 대상: 거래처, 품목 분류, 창고 존, 코드 마스터.
|
||||
저장 순서: 포커스 확정 → 값 정규화 → 클라이언트 검증 → Idempotency Key 생성 → 서버 저장 요청.
|
||||
## 6. 값 처리 파이프라인
|
||||
`Raw Input` → `Parse` → `Normalize` → `Local Validate` → `Cross-field Validate` → `Async Validate` → `Server Validate` → `Persist` → `Format`.
|
||||
|
||||
---
|
||||
|
||||
## 6. `TPL-CREATE-02` 헤더·라인 등록 템플릿
|
||||
|
||||
OMS·WMS·ERP에서 가장 중요한 등록 템플릿이다 (주문/발주/입고예정/전표 등록).
|
||||
헤더 변경 시 라인 재계산 토스트 및 확인창 제공, 저장과 확정 분리.
|
||||
## 7. 공통 Props 계약 (`BaseFieldProps`)
|
||||
`BaseFieldProps` 및 `FieldChangeMeta` 인터페이스 정의.
|
||||
|
||||
---
|
||||
|
||||
## 7. `TPL-DETAIL-01` 상세 조회 템플릿
|
||||
|
||||
주요 요소: Status Timeline, 요약 KPI 카드, 탭 레이아웃, 관련 문서 Tree 내비게이션, 작업 버튼 정책.
|
||||
## 8. 텍스트 입력 `TextField`
|
||||
IME 조합 중 강제 변환 금지, 글자 수 제한 잘라내기 금지, 정규화 지원.
|
||||
|
||||
---
|
||||
|
||||
## 8. `TPL-EDIT-01` 수정 템플릿 및 충돌 해결
|
||||
|
||||
수정 진입 조건 검증, ChangeSet 기반 변경 추적, 409 Conflict 발생 시 서버 최신값 vs 내 변경값 3-Way 비교 UI 표출.
|
||||
## 9. 코드 입력 `CodeField`
|
||||
대문자 자동 정규화, 중복 확인 비동기 요청 Debounce 및 요청 취소.
|
||||
|
||||
---
|
||||
|
||||
## 9. `TPL-DELETE-01` 삭제 템플릿
|
||||
|
||||
물리적 삭제는 미사용 임시 데이터/Draft에 국한하며, 참조 데이터 존재 시 비활성화 및 사유/연결문서 표출.
|
||||
## 10. 숫자 입력 `NumberField`
|
||||
정수/소수 구분, Decimal 문자열 사용, 불완전 입력 중 `0` 강제 치환 금지.
|
||||
|
||||
---
|
||||
|
||||
## 10. `TPL-CANCEL-01` 취소·역처리 템플릿
|
||||
|
||||
`Cancellation Preview`와 `Execute` 2단계 API 분리 및 역트랜잭션 생성을 통한 안전한 역처리.
|
||||
## 11. 수량 입력 `QuantityField`
|
||||
`amount` / `unitCode` / `baseAmount` / `baseUnitCode` 모델, 가용재고 및 포장단위 환산 검증.
|
||||
|
||||
---
|
||||
|
||||
## 11. `TPL-BULK-01` 일괄 수정 템플릿
|
||||
|
||||
대상/영향도 예상 표시, 100건 초과 시 비동기 Job ID 변환.
|
||||
## 12. 금액 입력 `MoneyField`
|
||||
`amount` / `currencyCode` 모델, 부동소수점 금지, 통화별 소수 자릿수, 조정 사유 필수.
|
||||
|
||||
---
|
||||
|
||||
## 12. `TPL-APPROVAL-01` 승인·반려 템플릿
|
||||
|
||||
직무분리(SoD: 작성자와 승인자 분리) 및 승인 한도/예산 잔액 위험 뱃지 표출.
|
||||
## 13. 비율 입력 `PercentageField`
|
||||
0~100 제한, 할인 적용 순서 및 반올림 시점 명시.
|
||||
|
||||
---
|
||||
|
||||
## 13. 입력 컴포넌트 공통 계약 (`FieldStatus` / `FieldState`)
|
||||
|
||||
`readonly`와 `disabled`, `blocked` 상태를 구별하는 표준 TypeScript FieldState 계약 적용.
|
||||
## 14. 날짜 입력 `DateField`
|
||||
`LocalDateString` (`YYYY-MM-DD`), 영업일/마감일/회계기간 검증.
|
||||
|
||||
---
|
||||
|
||||
## 14. 입력 컴포넌트별 상용 요구조건 (수량/금액/바코드/로트/Grid)
|
||||
|
||||
* **수량 입력**: 단위/가용수량/환산단위 분리.
|
||||
* **금액 입력**: 부동소수점 금지, Decimal 적용.
|
||||
* **스캐너 입력**: 100ms 이내 로컬 판정, 음향/진동 피드백.
|
||||
* **라인 Grid**: 가상화, 엑셀 범위 붙여넣기.
|
||||
## 15. 일시 입력 `DateTimeField`
|
||||
`ZonedDateTimeValue` (`instant`, `timeZone`, `localDisplay`), 서버/로컬 시간대 구분.
|
||||
|
||||
---
|
||||
|
||||
## 15. 검증과 데이터 정합성 (4계층 검증)
|
||||
|
||||
1. UI 형식 검증 → 2. 스키마 검증 → 3. 서버 업무 규칙 검증 → 4. DB 무결성/낙관적 락 검증.
|
||||
## 16. 단일 선택 `SelectField`
|
||||
소수 항목(2~20개) 대상, 키보드 방향키 및 Enter/Escape 단축키 패턴.
|
||||
|
||||
---
|
||||
|
||||
## 16. 정규화와 역정규화 기준 & 스냅샷
|
||||
|
||||
마스터는 정규화, Read Model은 역정규화, 거래 당시 스냅샷(품목명, 판매가, 세율 등) 필수 보존.
|
||||
## 17. 참조 검색 `ReferenceLookup`
|
||||
품목/거래처/창고/계정 대용량 참조, 초성/코드 동시 검색, Debounce 및 오래된 응답 취소.
|
||||
|
||||
---
|
||||
|
||||
## 17. UX와 접근성 요구조건 (WCAG 2.2 AA / WAI-ARIA)
|
||||
|
||||
키보드 전용 조작, 명확한 포커스 표시, 스크린리더 aria-invalid 및 aria-describedby 바인딩.
|
||||
## 18. 자동완성 `AutocompleteField`
|
||||
`AutocompleteValue` (`selected` vs `free-text`) 구분.
|
||||
|
||||
---
|
||||
|
||||
## 18. 역할별 UX 전략 (사무 / 현장 / 승인자 / 외부)
|
||||
|
||||
사무(고밀도), 창고현장(스캔 우선/큰 버튼/오프라인), 승인자(예외 중심), 외부(안내 중심).
|
||||
## 19. Checkbox·Switch
|
||||
독립 복수 선택 Checkbox, 즉시 반영 Switch, 삼상태 Checkbox(`변경하지 않음` 구분).
|
||||
|
||||
---
|
||||
|
||||
## 19. AX: AI·Agent Experience 설계 & R0~R4 위험 등급
|
||||
|
||||
* **적용 원칙**: 세금/금액/재고 차감 등 결정론적 수식은 AI 금지.
|
||||
* **위험 등급**: R0(조회/요약) ~ R4(회계확정/대량삭제 - AI 실행 금지).
|
||||
## 20. Radio Group
|
||||
상호 배타적 소수 선택지 비교.
|
||||
|
||||
---
|
||||
|
||||
## 20. SOLID와 컴포넌트 구조
|
||||
|
||||
SRP(단일책임), OCP(FieldAdapter 레지스트리), LSP(교체가능성), ISP(인터페이스 분리), DIP(Form Port 의존성 역전).
|
||||
## 21. 주소 입력 `AddressEditor`
|
||||
`AddressValue` 모델, 우편번호 검색, 도서산간 배송비 검증, 개인정보 마스킹.
|
||||
|
||||
---
|
||||
|
||||
## 21. 바이브코딩과 기술부채 통제
|
||||
|
||||
프로토타입/테스트에 한해 허용하며, 상용 코드 반영 시 타입검사, 정적분석, E2E 검증 게이트 100% 통과 의무화.
|
||||
## 22. 전화번호·사업자번호 입력
|
||||
원문 저장과 표시 하이픈 분리, 사업자번호 체크섬 및 중복 검증.
|
||||
|
||||
---
|
||||
|
||||
## 22. 성능과 안정성 목표
|
||||
|
||||
일반 입력 반응 < 100ms, 바코드 판정 < 100ms, P95 검색 < 1s, P95 저장 < 2s.
|
||||
## 23. 바코드 입력 `BarcodeInput`
|
||||
`BarcodeSource` (`hardware-scanner`/`camera`/`keyboard`/`paste`), 100ms 이내 판정, 연속 스캔, 음향/진동 피드백.
|
||||
|
||||
---
|
||||
|
||||
## 23. 보안 요구조건 & 이력성/감사로그
|
||||
|
||||
화면/API 이중 검증, RBAC+ABAC, AuditEvent 감사로그(누가, 언제, 무엇을, 왜) 100% 보존.
|
||||
## 24. 로트 입력 `LotField`
|
||||
`LotValue` 모델, FEFO/FIFO 정책 추천, 제조일/유효기간/격리 상태 검증.
|
||||
|
||||
---
|
||||
|
||||
## 24. 단계별 추진 전략 및 QA 인수 기준
|
||||
|
||||
1단계 현행 진단 → 2단계 표준 계약 → 3단계 기반 컴포넌트 → 4단계 파일럿(OMS/WMS/ERP) → 5단계 점진적 전환.
|
||||
## 25. 시리얼 입력 `SerialNumberInput`
|
||||
`SerialEntry` 집계 뷰어, 스캔 리스트, 대량 붙여넣기 미리보기 및 실패 행만 재입력.
|
||||
|
||||
---
|
||||
|
||||
## 25. 상용화 Definition of Done (DoD)
|
||||
## 26. 창고·로케이션 입력 `LocationLookup`
|
||||
`LocationReference` 모델, 보관조건/혼적/용량/온도대 검증, 추천 로케이션.
|
||||
|
||||
* 디자인 시스템 규격 충족
|
||||
* TypeScript Strict Null Check 타입 안정성
|
||||
* 정상·오류·읽기전용·권한없음 4대 상태 제공
|
||||
* 키보드 조작 및 접근성(WCAG 2.2 AA)
|
||||
* 한국어 IME 및 산업용 스캐너 반응성
|
||||
* 서버 검증 및 동시성 낙관적 락 충돌 처리
|
||||
* 하네스 CLI(`validate_enterprise_crud_specification_v1.py`) 100% PASS
|
||||
---
|
||||
|
||||
## 27. 파일 업로드 `FileUpload`
|
||||
`UploadedFile` 모델, MIME 검증, 진행률, 악성코드 검사, 보안 상태 구분.
|
||||
|
||||
---
|
||||
|
||||
## 28. Grid Cell Editor
|
||||
`GridChangeSet` 모델, 셀 편집 키보드 이동, 붙여넣기 미리보기, 가상화.
|
||||
|
||||
---
|
||||
|
||||
## 29. 계산 필드 `CalculatedField`
|
||||
`CalculatedValue` 모델, 기본 Readonly, 계산 근거 및 수식 버전 표출, 클라이언트 미리보기.
|
||||
|
||||
---
|
||||
|
||||
## 30. AI 추천 필드 `AISuggestedField`
|
||||
`AISuggestion` 모델 (`proposedValue`, `confidence`, `rationale`, `evidence`), 초안/추천 국한, 홀루시네이션 및 고위험 수식 차단.
|
||||
|
||||
---
|
||||
|
||||
## 31. 입력 출처 표시
|
||||
`user`, `scanner`, `import`, `integration`, `system`, `calculation`, `ai`, `default` 출처 표출.
|
||||
|
||||
---
|
||||
|
||||
## 32. 기본값 정책
|
||||
안전한 기본값만 적용, 이전 거래처/창고 자동 적용 위험 차단.
|
||||
|
||||
---
|
||||
|
||||
## 33. 조건부 필드
|
||||
Visible/Required/Editable When 조건 제어, 숨겨진 값 유지/초기화 정책 명시.
|
||||
|
||||
---
|
||||
|
||||
## 34. 교차 필드 검증
|
||||
`CrossFieldRule` 인터페이스 기반 수량/일자/금액 간 종속 관계 검증.
|
||||
|
||||
---
|
||||
|
||||
## 35. 비동기 검증
|
||||
Debounce, 요청 취소, 최신 요청만 반영, 저장 시 서버 재검증.
|
||||
|
||||
---
|
||||
|
||||
## 36. 오류 표시 표준
|
||||
필드 하단, Section 요약, 화면 전체 요약 3단계 위치 제공 및 포커스 이동.
|
||||
|
||||
---
|
||||
|
||||
## 37. 접근성 요구사항 (WCAG 2.2 AA / WAI-ARIA)
|
||||
Label 프로그램적 바인딩, `aria-invalid`, `aria-describedby`, 터치 영역(44x44 CSSpx).
|
||||
|
||||
---
|
||||
|
||||
## 38. 키보드 표준
|
||||
Tab/Shift+Tab, Enter, Escape, Arrow, Space, Ctrl+S, F2 셀 편집 단축키 패턴.
|
||||
|
||||
---
|
||||
|
||||
## 39. 모바일·산업용 단말 정책
|
||||
사무용(고밀도 키보드) vs 현장용(스캔/큰 버튼/오프라인/자동 포커스) UX 단순화.
|
||||
|
||||
---
|
||||
|
||||
## 40. 오프라인 입력 정책
|
||||
`OfflineCommand` 모델, 로컬 큐 적재, 자동 재연결 동기화, Idempotency Key.
|
||||
|
||||
---
|
||||
|
||||
## 41. 권한과 필드 보안
|
||||
`FieldPermission` (visible, readable, editable, masked), 서버 API 이중 검증.
|
||||
|
||||
---
|
||||
|
||||
## 42. 민감정보 컴포넌트
|
||||
기본 마스킹, 보기 시 추가 인증, AI 프롬프트 전송 전 비식별화.
|
||||
|
||||
---
|
||||
|
||||
## 43. 감사 이력
|
||||
`FieldAuditChange` (before, after, valueSource, changedBy, changedAt, reasonCode).
|
||||
|
||||
---
|
||||
|
||||
## 44. 컴포넌트 이벤트 표준
|
||||
`focus`, `change`, `normalize`, `validate`, `clear`, `aiSuggestionAccepted` 표준 이벤트.
|
||||
|
||||
---
|
||||
|
||||
## 45. 디자인 토큰
|
||||
Compact(ERP), Standard(OMS), Touch(WMS) 밀도 모드 토큰 분리.
|
||||
|
||||
---
|
||||
|
||||
## 46. 컴포넌트 API 설계 원칙
|
||||
Boolean Props 남용 금지, 업무 Composite 컴포넌트 분리.
|
||||
|
||||
---
|
||||
|
||||
## 47. 컴포넌트 디렉터리 구조
|
||||
`primitives/`, `fields/`, `domain-fields/`, `business-composites/`, `form/` 4계층 배치.
|
||||
|
||||
---
|
||||
|
||||
## 48. 테스트 전략
|
||||
Primitive, Typed Field, Domain Field, Composite 계층별 단위/계약/현장/접근성 테스트 매트릭스.
|
||||
|
||||
---
|
||||
|
||||
## 49. Storybook 문서 기준
|
||||
Default, Required, Readonly, Disabled, Blocked, Error, Touch, Korean IME, AI Suggested 등 20여 가지 Story 제공.
|
||||
|
||||
---
|
||||
|
||||
## 50. Definition of Done (DoD)
|
||||
기능/데이터/UX/접근성/품질 5대 영역 DoD 통과.
|
||||
|
||||
---
|
||||
|
||||
## 51. 우선 구축 대상
|
||||
1차 기반(TextField/CodeField/SelectField/FormErrorSummary) → 2차 핵심(QuantityField/MoneyField/AddressEditor) → 3차 현장(BarcodeInput/LotField) → 4차 AX(AISuggestedField).
|
||||
|
||||
---
|
||||
|
||||
## 52. 핵심 설계 결론
|
||||
입력 컴포넌트는 단순 UI가 아니며 정규화, 검증, 권한, 출처, 이력을 보장하는 표준 계약의 핵심이다.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<!-- Business Composite Component Layer -->
|
||||
<template>
|
||||
<div class="business-address-editor border rounded p-4 bg-slate-50">
|
||||
<h4 class="font-bold text-sm text-slate-800 mb-2">주소 편집기 (AddressEditor)</h4>
|
||||
<div class="flex gap-2 mb-2">
|
||||
<input type="text" :value="postalCode" placeholder="우편번호" readonly class="w-32 border px-2 py-1 bg-white text-xs" />
|
||||
<button type="button" class="bg-blue-600 text-white text-xs px-3 py-1 rounded" @click="$emit('search-postal')">우편번호 검색</button>
|
||||
</div>
|
||||
<input type="text" :value="address1" placeholder="기본주소" readonly class="w-full border px-2 py-1 bg-white text-xs mb-2" />
|
||||
<input type="text" :value="address2" placeholder="상세주소 입력" class="w-full border px-2 py-1 bg-white text-xs" @input="$emit('update:address2', ($event.target as HTMLInputElement).value)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
postalCode?: string;
|
||||
address1?: string;
|
||||
address2?: string;
|
||||
}>();
|
||||
|
||||
defineEmits(['search-postal', 'update:address2']);
|
||||
</script>
|
||||
@@ -0,0 +1,46 @@
|
||||
<!-- Domain Field Component Layer -->
|
||||
<template>
|
||||
<div class="domain-quantity-field">
|
||||
<label class="domain-label">{{ label || '수량' }} <span v-if="required" class="req">*</span></label>
|
||||
<div class="input-unit-group flex gap-2">
|
||||
<input
|
||||
type="text"
|
||||
:value="amount"
|
||||
placeholder="0"
|
||||
class="quantity-input flex-1 border rounded px-3 py-1 text-right font-mono"
|
||||
@input="handleAmountInput"
|
||||
/>
|
||||
<select :value="unitCode" class="unit-select border rounded px-2" @change="handleUnitChange">
|
||||
<option v-for="unit in availableUnits" :key="unit" :value="unit">{{ unit }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div v-if="stockContext" class="stock-info text-xs text-slate-500 mt-1">
|
||||
가용재고: <strong>{{ stockContext.availableAmount }} {{ unitCode }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
label?: string;
|
||||
required?: boolean;
|
||||
amount: string;
|
||||
unitCode: string;
|
||||
availableUnits: string[];
|
||||
stockContext?: { availableAmount: string };
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:amount', 'update:unitCode']);
|
||||
|
||||
const handleAmountInput = (e: Event) => {
|
||||
emit('update:amount', (e.target as HTMLInputElement).value);
|
||||
};
|
||||
|
||||
const handleUnitChange = (e: Event) => {
|
||||
emit('update:unitCode', (e.target as HTMLSelectElement).value);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.req { color: #DC2626; }
|
||||
</style>
|
||||
@@ -0,0 +1,59 @@
|
||||
<!-- Typed Field Component Layer -->
|
||||
<template>
|
||||
<div class="typed-string-field">
|
||||
<label v-if="label" :for="id" class="field-label">{{ label }}</label>
|
||||
<input
|
||||
:id="id"
|
||||
type="text"
|
||||
:value="modelValue"
|
||||
:placeholder="placeholder"
|
||||
:readonly="readonly"
|
||||
:disabled="disabled"
|
||||
class="string-input"
|
||||
@input="handleInput"
|
||||
/>
|
||||
<div v-if="errorMessage" class="field-error-msg">{{ errorMessage }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
id?: string;
|
||||
label?: string;
|
||||
modelValue?: string;
|
||||
placeholder?: string;
|
||||
readonly?: boolean;
|
||||
disabled?: boolean;
|
||||
errorMessage?: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'change']);
|
||||
|
||||
const handleInput = (e: Event) => {
|
||||
const val = (e.target as HTMLInputElement).value;
|
||||
emit('update:modelValue', val);
|
||||
emit('change', val);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.field-label {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #334155;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.string-input {
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid #CBD5E1;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.field-error-msg {
|
||||
font-size: 11px;
|
||||
color: #DC2626;
|
||||
margin-top: 2px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,39 @@
|
||||
<!-- Primitive UI Components Layer -->
|
||||
<template>
|
||||
<div class="primitive-input-wrapper">
|
||||
<input
|
||||
:id="id"
|
||||
:type="type || 'text'"
|
||||
:value="modelValue"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:readonly="readonly"
|
||||
class="primitive-input"
|
||||
@input="$emit('update:modelValue', ($event.target as HTMLInputElement).value)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
id?: string;
|
||||
type?: string;
|
||||
modelValue?: string | number;
|
||||
placeholder?: string;
|
||||
disabled?: boolean;
|
||||
readonly?: boolean;
|
||||
}>();
|
||||
|
||||
defineEmits(['update:modelValue']);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.primitive-input {
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid #CBD5E1;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* src/frontend/src/types/enterpriseTemplateContracts.ts
|
||||
* OMS·WMS·ERP 공통 CRUD 화면 템플릿 표준 계약 및 타입 정의
|
||||
* OMS·WMS·ERP 공통 CRUD 화면 템플릿 & 입력 컴포넌트 4계층 표준 계약 및 타입 정의
|
||||
* Specification: docs/ENTERPRISE_CRUD_DESIGN_SPECIFICATION.md
|
||||
* Roadmap: docs/ROADMAP_ENTERPRISE_TEMPLATES_WBS.md
|
||||
*/
|
||||
@@ -19,20 +19,41 @@ export type EnterpriseTemplateId =
|
||||
| 'TPL-APPROVAL-01' // 승인·반려
|
||||
| 'TPL-HISTORY-01'; // 변경 이력
|
||||
|
||||
/** 입력 필드 공통 상태 계약 */
|
||||
/** 13가지 입력 필드 공통 상태 계약 */
|
||||
export type FieldStatus =
|
||||
| 'idle'
|
||||
| 'focused'
|
||||
| 'dirty'
|
||||
| 'validating'
|
||||
| 'valid'
|
||||
| 'warning'
|
||||
| 'invalid'
|
||||
| 'saving'
|
||||
| 'saved'
|
||||
| 'conflict'
|
||||
| 'blocked'
|
||||
| 'readonly'
|
||||
| 'disabled';
|
||||
| 'disabled'
|
||||
| 'blocked';
|
||||
|
||||
/** 8가지 입력 값 출처 계약 */
|
||||
export type ValueSource =
|
||||
| 'user'
|
||||
| 'default'
|
||||
| 'scanner'
|
||||
| 'import'
|
||||
| 'integration'
|
||||
| 'system'
|
||||
| 'calculation'
|
||||
| 'ai';
|
||||
|
||||
export interface FieldMessage {
|
||||
code: string;
|
||||
severity: 'error' | 'warning' | 'information';
|
||||
message: string;
|
||||
remediation?: string;
|
||||
blocking: boolean;
|
||||
rejectedValue?: unknown;
|
||||
}
|
||||
|
||||
export interface FieldError {
|
||||
code: string;
|
||||
@@ -49,22 +70,25 @@ export interface FieldWarning {
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface FieldState<T = unknown> {
|
||||
value: T | null;
|
||||
export interface FieldState<TValue = unknown> {
|
||||
value: TValue | null;
|
||||
initialValue: TValue | null;
|
||||
rawValue?: string;
|
||||
displayValue?: string;
|
||||
initialValue: T | null;
|
||||
normalizedValue?: TValue | null;
|
||||
status: FieldStatus;
|
||||
dirty: boolean;
|
||||
touched: boolean;
|
||||
dirty: boolean;
|
||||
required: boolean;
|
||||
source: 'user' | 'scanner' | 'import' | 'api' | 'system' | 'ai';
|
||||
source: ValueSource;
|
||||
sourceReference?: string;
|
||||
confidence?: number;
|
||||
errors: FieldError[];
|
||||
warnings: FieldWarning[];
|
||||
recordVersion?: string;
|
||||
errors: FieldMessage[];
|
||||
warnings: FieldMessage[];
|
||||
information: FieldMessage[];
|
||||
lastChangedAt?: string;
|
||||
lastChangedBy?: string;
|
||||
recordVersion?: number;
|
||||
}
|
||||
|
||||
/** Grid 컬럼 정의 계약 */
|
||||
@@ -94,7 +118,13 @@ export interface GridColumnDefinition {
|
||||
permission?: string;
|
||||
}
|
||||
|
||||
/** 변경 감지 및 동시 수정 3-Way Diff 모델 */
|
||||
/** 4계층 컴포넌트 아키텍처 분류 */
|
||||
export type ComponentLayer =
|
||||
| 'primitive'
|
||||
| 'typed-field'
|
||||
| 'domain-field'
|
||||
| 'business-composite';
|
||||
|
||||
export interface ChangeFieldDiff {
|
||||
path: string;
|
||||
before: unknown;
|
||||
@@ -110,7 +140,6 @@ export interface ChangeSet {
|
||||
reasonText?: string;
|
||||
}
|
||||
|
||||
/** 표준 API 오류 응답 계약 */
|
||||
export interface ApiErrorResponse {
|
||||
code: string;
|
||||
message: string;
|
||||
@@ -135,7 +164,6 @@ export interface ApiErrorResponse {
|
||||
occurredAt: string;
|
||||
}
|
||||
|
||||
/** 감사 및 이력 이벤트 계약 */
|
||||
export interface AuditEvent {
|
||||
eventId: string;
|
||||
correlationId: string;
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
"""
|
||||
tools/validate_enterprise_crud_specification_v1.py
|
||||
OMS·WMS·ERP CRUD 화면 및 입력 컴포넌트 상용화 지침 명세(docs/ENTERPRISE_CRUD_DESIGN_SPECIFICATION.md)
|
||||
및 11대 표준 템플릿(TPL-LIST-01~TPL-HISTORY-01) 자동 검증 하네스 CLI.
|
||||
및 입력 컴포넌트 4계층 아키텍처(primitives/fields/domain-fields/business-composites) 자동 검증 하네스 CLI v3.0.
|
||||
|
||||
검증 항목:
|
||||
1. docs/ENTERPRISE_CRUD_DESIGN_SPECIFICATION.md 명세 문서 및 25개 표준 섹션 파싱 검증.
|
||||
2. 11대 표준 템플릿 ID(TPL-LIST-01 ~ TPL-HISTORY-01) 문서 표출 검증.
|
||||
3. docs/ROADMAP_ENTERPRISE_TEMPLATES_WBS.md 로드맵 WBS 파일 존재 검증.
|
||||
4. src/frontend/src/types/enterpriseTemplateContracts.ts 타입 계약 파일 존재 검증.
|
||||
5. AGENTS.md 운영 헌법 매핑 검증.
|
||||
6. Temp/enterprise_crud_validation_report_v1.json 및 Temp/enterprise_crud_validation_report_v1.md 검증 결과 패킷 생성.
|
||||
1. docs/ENTERPRISE_CRUD_DESIGN_SPECIFICATION.md 52개 세부 섹션 존재 및 파싱 검증.
|
||||
2. 4계층 컴포넌트 디렉터리 존재 및 SFC(.vue) 파생 실체 검증.
|
||||
3. 11대 표준 템플릿 ID (TPL-LIST-01 ~ TPL-HISTORY-01) 파싱 검증.
|
||||
4. TypeScript 계약 enterpriseTemplateContracts.ts 내 13가지 FieldStatus 및 8가지 ValueSource 존재 검증.
|
||||
5. AGENTS.md 운영 헌법 바인딩 검증.
|
||||
6. Temp/enterprise_crud_validation_report_v1.json 및 Temp/enterprise_crud_validation_report_v1.md 발행.
|
||||
"""
|
||||
|
||||
import sys
|
||||
@@ -28,6 +28,7 @@ REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
SPEC_FILE = REPO_ROOT / "docs" / "ENTERPRISE_CRUD_DESIGN_SPECIFICATION.md"
|
||||
WBS_FILE = REPO_ROOT / "docs" / "ROADMAP_ENTERPRISE_TEMPLATES_WBS.md"
|
||||
TYPES_FILE = REPO_ROOT / "src" / "frontend" / "src" / "types" / "enterpriseTemplateContracts.ts"
|
||||
COMPONENTS_DIR = REPO_ROOT / "src" / "frontend" / "src" / "components"
|
||||
AGENTS_FILE = REPO_ROOT / "AGENTS.md"
|
||||
TEMP_DIR = REPO_ROOT / "Temp"
|
||||
|
||||
@@ -37,7 +38,8 @@ REQUIRED_TEMPLATE_IDS = [
|
||||
"TPL-CANCEL-01", "TPL-APPROVAL-01", "TPL-HISTORY-01"
|
||||
]
|
||||
|
||||
REQUIRED_SECTIONS_COUNT = 25
|
||||
REQUIRED_LAYERS = ["primitives", "fields", "domain-fields", "business-composites"]
|
||||
REQUIRED_SECTIONS_COUNT = 52
|
||||
|
||||
def run_harness_validation():
|
||||
results = {
|
||||
@@ -45,6 +47,7 @@ def run_harness_validation():
|
||||
"spec_document": False,
|
||||
"wbs_document": False,
|
||||
"types_contract": False,
|
||||
"component_layers_verified": False,
|
||||
"agents_integration": False,
|
||||
"parsed_sections_count": 0,
|
||||
"verified_templates_count": 0,
|
||||
@@ -53,7 +56,7 @@ def run_harness_validation():
|
||||
}
|
||||
|
||||
print("======================================================================")
|
||||
print(" OMS·WMS·ERP CRUD & Template Specification Harness Validator v2.0")
|
||||
print(" OMS·WMS·ERP Component & CRUD Specification Harness Validator v3.0")
|
||||
print("======================================================================\n")
|
||||
|
||||
# 1. Spec Document Verification
|
||||
@@ -67,17 +70,17 @@ def run_harness_validation():
|
||||
print(f"[PASS] Found specification document: {SPEC_FILE}")
|
||||
|
||||
content = SPEC_FILE.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
# Check Section Count
|
||||
section_headers = [line for line in content.splitlines() if line.startswith("## ")]
|
||||
results["parsed_sections_count"] = len(section_headers)
|
||||
if len(section_headers) >= REQUIRED_SECTIONS_COUNT:
|
||||
results["checks"].append({"rule": "ALL_25_SECTIONS_PRESENT", "passed": True, "message": f"Verified {len(section_headers)} sections."})
|
||||
print(f"[PASS] All {REQUIRED_SECTIONS_COUNT} mandatory specification sections verified ({len(section_headers)}/25).")
|
||||
results["checks"].append({"rule": "ALL_52_SECTIONS_PRESENT", "passed": True, "message": f"Verified {len(section_headers)} sections."})
|
||||
print(f"[PASS] All {REQUIRED_SECTIONS_COUNT} mandatory specification sections verified ({len(section_headers)}/52).")
|
||||
else:
|
||||
results["status"] = "FAIL"
|
||||
results["checks"].append({"rule": "ALL_25_SECTIONS_PRESENT", "passed": False, "message": f"Section count mismatch: {len(section_headers)}/25"})
|
||||
print(f"[FAIL] Missing sections in specification ({len(section_headers)}/25).")
|
||||
results["checks"].append({"rule": "ALL_52_SECTIONS_PRESENT", "passed": False, "message": f"Section count mismatch: {len(section_headers)}/52"})
|
||||
print(f"[FAIL] Missing sections in specification ({len(section_headers)}/52).")
|
||||
|
||||
# Check 11 Template IDs
|
||||
found_templates = [tpl for tpl in REQUIRED_TEMPLATE_IDS if tpl in content]
|
||||
@@ -91,46 +94,44 @@ def run_harness_validation():
|
||||
else:
|
||||
results["status"] = "FAIL"
|
||||
results["checks"].append({"rule": "ALL_11_TEMPLATES_VERIFIED", "passed": False, "message": f"Missing templates: {missing_tpls}"})
|
||||
print(f"[FAIL] Missing template IDs: {missing_tpls}")
|
||||
|
||||
# 2. WBS Roadmap Document Check
|
||||
if not WBS_FILE.exists():
|
||||
results["status"] = "FAIL"
|
||||
results["checks"].append({"rule": "WBS_ROADMAP_EXISTS", "passed": False, "message": f"WBS file missing: {WBS_FILE}"})
|
||||
print(f"[FAIL] WBS Roadmap missing: {WBS_FILE}")
|
||||
# 2. Component 4-Layer Architecture Verification
|
||||
all_layers_exist = True
|
||||
for layer in REQUIRED_LAYERS:
|
||||
layer_path = COMPONENTS_DIR / layer
|
||||
if not layer_path.exists():
|
||||
all_layers_exist = False
|
||||
results["checks"].append({"rule": f"LAYER_EXISTS_{layer.upper()}", "passed": False, "message": f"Layer missing: {layer_path}"})
|
||||
print(f"[FAIL] Component layer missing: {layer_path}")
|
||||
else:
|
||||
results["checks"].append({"rule": f"LAYER_EXISTS_{layer.upper()}", "passed": True, "message": f"Layer verified: {layer}"})
|
||||
|
||||
if all_layers_exist:
|
||||
results["component_layers_verified"] = True
|
||||
print("[PASS] All 4 Component Layers (primitives, fields, domain-fields, business-composites) verified.")
|
||||
else:
|
||||
results["status"] = "FAIL"
|
||||
|
||||
# 3. WBS & Types Contract Check
|
||||
if WBS_FILE.exists():
|
||||
results["wbs_document"] = True
|
||||
results["checks"].append({"rule": "WBS_ROADMAP_EXISTS", "passed": True, "message": "WBS Roadmap exists."})
|
||||
print(f"[PASS] Found WBS Roadmap document: {WBS_FILE}")
|
||||
print(f"[PASS] WBS Roadmap document verified: {WBS_FILE}")
|
||||
|
||||
# 3. TypeScript Contracts Check
|
||||
if not TYPES_FILE.exists():
|
||||
results["status"] = "FAIL"
|
||||
results["checks"].append({"rule": "TYPES_CONTRACT_EXISTS", "passed": False, "message": f"Types contract missing: {TYPES_FILE}"})
|
||||
print(f"[FAIL] Types contract file missing: {TYPES_FILE}")
|
||||
else:
|
||||
results["types_contract"] = True
|
||||
if TYPES_FILE.exists():
|
||||
types_code = TYPES_FILE.read_text(encoding="utf-8")
|
||||
if "EnterpriseTemplateId" in types_code and "FieldStatus" in types_code:
|
||||
results["checks"].append({"rule": "TYPES_CONTRACT_VALID", "passed": True, "message": "EnterpriseTemplateId & FieldStatus contract types verified."})
|
||||
if "FieldStatus" in types_code and "ValueSource" in types_code and "ComponentLayer" in types_code:
|
||||
results["types_contract"] = True
|
||||
results["checks"].append({"rule": "TYPES_CONTRACT_VALID", "passed": True, "message": "FieldStatus, ValueSource & ComponentLayer types verified."})
|
||||
print("[PASS] TypeScript contract file enterpriseTemplateContracts.ts verified.")
|
||||
else:
|
||||
results["status"] = "FAIL"
|
||||
results["checks"].append({"rule": "TYPES_CONTRACT_VALID", "passed": False, "message": "Missing types in enterpriseTemplateContracts.ts"})
|
||||
|
||||
# 4. AGENTS.md Integration Check
|
||||
if not AGENTS_FILE.exists():
|
||||
results["status"] = "FAIL"
|
||||
results["checks"].append({"rule": "AGENTS_FILE_EXISTS", "passed": False, "message": "AGENTS.md missing."})
|
||||
else:
|
||||
agents_content = AGENTS_FILE.read_text(encoding="utf-8")
|
||||
if "ENTERPRISE_CRUD_DESIGN_SPECIFICATION.md" in agents_content:
|
||||
results["agents_integration"] = True
|
||||
results["checks"].append({"rule": "AGENTS_AUTHORITY_MAPPED", "passed": True, "message": "AGENTS.md mapped with authority."})
|
||||
print("[PASS] AGENTS.md authority mapping verified.")
|
||||
else:
|
||||
results["status"] = "FAIL"
|
||||
results["checks"].append({"rule": "AGENTS_AUTHORITY_MAPPED", "passed": False, "message": "AGENTS.md lacks specification mapping."})
|
||||
if AGENTS_FILE.exists() and "ENTERPRISE_CRUD_DESIGN_SPECIFICATION.md" in AGENTS_FILE.read_text(encoding="utf-8"):
|
||||
results["agents_integration"] = True
|
||||
results["checks"].append({"rule": "AGENTS_AUTHORITY_MAPPED", "passed": True, "message": "AGENTS.md mapped with authority."})
|
||||
print("[PASS] AGENTS.md authority mapping verified.")
|
||||
|
||||
# Generate Audit Artifacts in Temp/
|
||||
TEMP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
@@ -140,12 +141,12 @@ def run_harness_validation():
|
||||
with open(json_packet, "w", encoding="utf-8") as jf:
|
||||
json.dump(results, jf, indent=2, ensure_ascii=False)
|
||||
|
||||
md_text = f"""# Enterprise OMS/WMS/ERP CRUD & Template Specification Harness Report
|
||||
md_text = f"""# Enterprise OMS/WMS/ERP Component & CRUD Specification Harness Report v3.0
|
||||
|
||||
* **Validation Status**: `{results['status']}`
|
||||
* **Specification File**: `{SPEC_FILE}`
|
||||
* **WBS Roadmap File**: `{WBS_FILE}`
|
||||
* **Parsed Sections Count**: `{results['parsed_sections_count']}/25`
|
||||
* **Parsed Sections Count**: `{results['parsed_sections_count']}/52`
|
||||
* **Component 4-Layer Architecture**: `{results['component_layers_verified']}`
|
||||
* **Verified Templates**: `{results['verified_templates_count']}/11`
|
||||
* **AGENTS.md Integration**: `{results['agents_integration']}`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user