From 607d686535041eaa3b53ce28f75ad8b949cda342 Mon Sep 17 00:00:00 2001 From: kjs Date: Mon, 26 Jan 2026 12:00:40 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20V2=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EA=B0=80=EC=9D=B4=EB=93=9C=20=EB=AC=B8=EC=84=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - V2 컴포넌트의 아키텍처, 설계 원칙, 사용법을 정리한 가이드를 추가하였습니다. - V2 컴포넌트의 개요, 목록, Core 인프라, 이벤트 시스템, 채번/카테고리 시스템, 설정 패널 가이드, 결합도 현황, Unified 폼 컴포넌트, 개발 가이드, 참고 자료 및 향후 계획을 포함하고 있습니다. - 각 컴포넌트의 특징과 사용법을 상세히 설명하여 개발자들이 V2 컴포넌트를 쉽게 이해하고 활용할 수 있도록 하였습니다. --- docs/V2_COMPONENT_GUIDE.md | 539 +++++++++++++++++++++++++++++++++++++ 1 file changed, 539 insertions(+) create mode 100644 docs/V2_COMPONENT_GUIDE.md diff --git a/docs/V2_COMPONENT_GUIDE.md b/docs/V2_COMPONENT_GUIDE.md new file mode 100644 index 00000000..b3e0fbc8 --- /dev/null +++ b/docs/V2_COMPONENT_GUIDE.md @@ -0,0 +1,539 @@ +# V2 컴포넌트 가이드 + +> 작성일: 2026-01-26 +> 목적: V2 컴포넌트 전반적인 아키텍처, 설계 원칙, 사용법 정리 + +--- + +## 1. V2 컴포넌트 개요 + +### 1.1 V2란? + +V2(Version 2) 컴포넌트는 기존 레거시 컴포넌트의 문제점을 해결하고 다음 목표를 달성하기 위해 재설계된 컴포넌트입니다: + +- **느슨한 결합 (Loose Coupling)**: 컴포넌트 간 직접 의존성 제거 +- **장애 격리 (Fault Isolation)**: 한 컴포넌트 오류가 다른 컴포넌트에 영향 없음 +- **화면 복제 용이성**: 메뉴/회사 종속적인 설정 제거 +- **점진적 마이그레이션**: 레거시 컴포넌트와 공존 가능 + +### 1.2 V2 vs 레거시 비교 + +| 항목 | 레거시 | V2 | +|------|--------|-----| +| 이벤트 통신 | `window.dispatchEvent` | V2 EventBus | +| 에러 처리 | 전역 오류 → 전체 중단 | ErrorBoundary → 해당만 실패 | +| 전역 상태 | `window.__xxx` | Context/Store | +| 채번/카테고리 | 메뉴에 종속 | 테이블 컬럼에 종속 | +| 설정 저장 | componentConfig에 ID 저장 | 표시 옵션만 저장 | + +--- + +## 2. V2 컴포넌트 목록 (19개) + +### 2.1 레이아웃 컴포넌트 + +| 컴포넌트 ID | 이름 | 설명 | +|------------|------|------| +| `v2-split-panel-layout` | 분할 패널 레이아웃 | 좌우/상하 분할 레이아웃 | +| `v2-section-card` | 섹션 카드 | 카드 형태 컨테이너 | +| `v2-section-paper` | 섹션 페이퍼 | 페이퍼 형태 컨테이너 | +| `v2-tabs-widget` | 탭 위젯 | 탭 기반 컨테이너 | +| `v2-repeat-container` | 리피터 컨테이너 | 반복 섹션 컨테이너 | +| `v2-divider-line` | 구분선 | 시각적 구분선 | + +### 2.2 데이터 표시 컴포넌트 + +| 컴포넌트 ID | 이름 | 설명 | +|------------|------|------| +| `v2-table-list` | 테이블 리스트 | 데이터 그리드/테이블 | +| `v2-card-display` | 카드 디스플레이 | 카드 형태 데이터 표시 | +| `v2-text-display` | 텍스트 디스플레이 | 텍스트 표시 | +| `v2-pivot-grid` | 피벗 그리드 | 피벗 테이블 | +| `v2-aggregation-widget` | 집계 위젯 | 데이터 집계 표시 | + +### 2.3 입력/관리 컴포넌트 + +| 컴포넌트 ID | 이름 | 설명 | +|------------|------|------| +| `v2-button-primary` | 기본 버튼 | 저장/삭제/모달 등 액션 버튼 | +| `v2-numbering-rule` | 채번 규칙 | 채번 규칙 설정 컴포넌트 | +| `v2-category-manager` | 카테고리 관리 | 트리 기반 카테고리 관리 | +| `v2-table-search-widget` | 테이블 검색 위젯 | 테이블 검색 UI | +| `v2-location-swap-selector` | 위치 교환 선택기 | 출발지/도착지 선택 | + +### 2.4 특수 컴포넌트 + +| 컴포넌트 ID | 이름 | 설명 | +|------------|------|------| +| `v2-rack-structure` | 렉 구조 | 창고 렉 구조 표시 | +| `v2-repeat-screen-modal` | 반복 화면 모달 | 반복 가능한 화면 모달 | +| `v2-unified-repeater` | 통합 리피터 | 통합 리피터 테이블 | + +--- + +## 3. V2 Core 인프라 + +### 3.1 파일 구조 + +``` +frontend/lib/v2-core/ +├── index.ts # 메인 내보내기 +├── init.ts # 앱 초기화 +├── events/ +│ ├── index.ts +│ ├── types.ts # 이벤트 타입 정의 (30+) +│ └── EventBus.ts # 타입 안전한 이벤트 버스 +├── components/ +│ ├── index.ts +│ └── V2ErrorBoundary.tsx # 에러 바운더리 +└── adapters/ + ├── index.ts + └── LegacyEventAdapter.ts # 레거시 브릿지 +``` + +### 3.2 V2 EventBus + +타입 안전한 Pub/Sub 이벤트 시스템입니다. + +**특징:** +- 타입 안전한 이벤트 발행/구독 +- 에러 격리 (Promise.allSettled) +- 타임아웃 및 재시도 지원 +- 디버그 모드 지원 + +**사용법:** + +```typescript +import { v2EventBus, V2_EVENTS } from "@/lib/v2-core"; + +// 이벤트 발행 +v2EventBus.emit(V2_EVENTS.TABLE_REFRESH, { + tableName: "item_info", + target: "single", +}); + +// 이벤트 구독 +const unsubscribe = v2EventBus.subscribe( + V2_EVENTS.TABLE_REFRESH, + (payload) => { + console.log("테이블 새로고침:", payload.tableName); + }, + { componentId: "my-component" } +); + +// 정리 (useEffect cleanup에서) +useEffect(() => { + return () => unsubscribe(); +}, []); +``` + +### 3.3 V2 ErrorBoundary + +컴포넌트별 에러 격리를 제공합니다. + +**특징:** +- 에러 발생 시 해당 컴포넌트만 폴백 UI 표시 +- 3가지 폴백 스타일 (minimal, compact, full) +- 재시도 기능 +- 에러 이벤트 자동 발행 + +**사용법:** + +```tsx +import { V2ErrorBoundary } from "@/lib/v2-core"; + +// 컴포넌트 래핑 + + + +``` + +### 3.4 Legacy Event Adapter + +기존 CustomEvent와 V2 EventBus 간 양방향 브릿지입니다. + +**특징:** +- 레거시 `window.dispatchEvent` → V2 EventBus 자동 변환 +- V2 EventBus → 레거시 CustomEvent 자동 변환 +- 무한 루프 방지 +- 점진적 마이그레이션 지원 + +--- + +## 4. 이벤트 시스템 + +### 4.1 주요 이벤트 목록 + +| 이벤트 | 설명 | 발행자 | 구독자 | +|--------|------|--------|--------| +| `v2:table:refresh` | 테이블 새로고침 | v2-button-primary | v2-table-list | +| `v2:table:data:change` | 테이블 데이터 변경 | v2-table-list | v2-aggregation-widget | +| `v2:form:save:collect` | 폼 저장 전 데이터 수집 | buttonActions | v2-repeat-container, UnifiedRepeater | +| `v2:modal:close` | 모달 닫기 | v2-button-primary | EditModal | +| `v2:modal:save:success` | 모달 저장 성공 | v2-button-primary | EditModal | +| `v2:repeater:save` | 리피터 저장 | buttonActions | UnifiedRepeater | +| `v2:component:error` | 컴포넌트 에러 | V2ErrorBoundary | 로깅/모니터링 | + +### 4.2 이벤트 흐름 다이어그램 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ V2 EventBus (중앙) │ +│ │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │TABLE_REFRESH│ │TABLE_DATA │ │FORM_SAVE │ │ +│ │ │ │ _CHANGE │ │ _COLLECT │ │ +│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ +└──────────│──────────────────│──────────────────│────────────────┘ + │ │ │ + ▼ ▼ ▼ + ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ + │ v2-table-list │ │v2-aggregation │ │v2-repeat │ + │ │ │ -widget │ │ -container │ + └───────────────┘ └───────────────┘ └───────────────┘ +``` + +--- + +## 5. 채번/카테고리 시스템 + +### 5.1 설계 원칙 + +**핵심: 메뉴 종속성 제거** + +- ❌ 이전: 채번/카테고리 설정이 화면 레이아웃(componentConfig)에 저장 +- ✅ 현재: 채번/카테고리 설정이 테이블 컬럼 정의에 저장 + +### 5.2 채번 규칙 동작 방식 + +``` +1. 테이블 타입 관리에서 컬럼에 input_type='numbering' 설정 +2. 해당 컬럼에 numbering_rule_id 연결 (테이블 정의에 저장) +3. 화면에서 해당 컬럼 사용 시 자동으로 채번 규칙 적용 +4. 화면 복제해도 테이블 정의는 그대로 → 채번 규칙 유지 +``` + +**관련 테이블:** +- `numbering_rules_test`: 채번 규칙 마스터 +- `numbering_rule_parts_test`: 채번 규칙 파트 +- `column_labels`: 컬럼별 input_type 및 설정 저장 + +### 5.3 카테고리 동작 방식 + +``` +1. 테이블 타입 관리에서 컬럼에 input_type='category' 설정 +2. category_values_test 테이블에 카테고리 값 저장 (트리 구조) +3. 화면에서 해당 컬럼 사용 시 자동으로 카테고리 드롭다운 표시 +4. 화면 복제해도 테이블 정의는 그대로 → 카테고리 유지 +``` + +**관련 테이블:** +- `category_values_test`: 카테고리 값 (트리 구조, 3단계 지원) + - `parent_id`: 부모 노드 ID + - `level`: 깊이 (1=대분류, 2=중분류, 3=소분류) + - `path`: 경로 (예: "1.2.3") + +### 5.4 화면 복제 시 이점 + +``` +이전 (메뉴 종속): +화면 복제 → 채번/카테고리 ID도 복제 → 잘못된 참조 → 수동 수정 필요 + +현재 (테이블 종속): +화면 복제 → 테이블 컬럼 정의 참조 → 자동으로 올바른 채번/카테고리 적용 +``` + +--- + +## 6. 설정 패널 (ConfigPanel) 가이드 + +### 6.1 설계 원칙 + +V2 컴포넌트의 ConfigPanel은 **표시/동작 옵션만** 저장합니다. + +**저장해야 하는 것:** +- 뷰 모드 (tree/list/card 등) +- 레이아웃 설정 (너비, 높이, 패딩) +- 표시 옵션 (readonly, showPreview 등) +- 스타일 설정 (색상, 폰트 등) + +**저장하면 안 되는 것:** +- ❌ 특정 채번 규칙 ID (numberingRuleId) +- ❌ 특정 카테고리 ID (categoryId) +- ❌ 메뉴 ID (menuObjid, menu_id) +- ❌ 회사 코드 (companyCode) - 런타임에 결정 + +### 6.2 ConfigPanel 예시 + +```tsx +// ✅ 올바른 ConfigPanel +export const MyComponentConfigPanel: React.FC = ({ config, onChange }) => { + return ( +
+ {/* 표시 옵션만 설정 */} +
+ + +
+ +
+ + onChange({ ...config, readonly: v })} + /> +
+
+ ); +}; + +// ❌ 잘못된 ConfigPanel +export const BadConfigPanel: React.FC = ({ config, onChange }) => { + return ( +
+ {/* 채번 규칙 ID를 저장하면 안 됨! */} + +
+ ); +}; +``` + +--- + +## 7. 결합도 현황 + +### 7.1 V2 컴포넌트 결합도 점수 + +| 결합도 수준 | 개수 | 컴포넌트 | +|------------|------|---------| +| 🔴 높음 (7-10점) | 0개 | - (마이그레이션 완료) | +| 🟠 중간 (4-6점) | 4개 | v2-repeat-container, v2-split-panel-layout, v2-aggregation-widget, v2-tabs-widget | +| 🟢 낮음 (1-3점) | 15개 | 나머지 모든 V2 컴포넌트 | + +### 7.2 마이그레이션 완료 컴포넌트 + +| 컴포넌트 | V2 EventBus | ErrorBoundary | 레거시 호환 | +|---------|-------------|---------------|-------------| +| v2-button-primary | ✅ | ✅ | ✅ | +| v2-table-list | ✅ | ✅ | ✅ | +| UnifiedRepeater | ✅ | ✅ | ✅ | + +### 7.3 장애 격리 검증 + +``` +v2-button-primary 에러 발생 시: +├── V2ErrorBoundary 캐치 → 버튼만 에러 UI 표시 +├── v2-table-list: 정상 동작 ✅ +└── UnifiedRepeater: 정상 동작 ✅ + +v2-table-list 에러 발생 시: +├── V2ErrorBoundary 캐치 → 테이블만 에러 UI 표시 +├── v2-button-primary: 정상 동작 ✅ +└── v2-aggregation-widget: 데이터 없음 상태 ✅ +``` + +--- + +## 8. Unified 폼 컴포넌트 + +### 8.1 목록 (11개) + +| 컴포넌트 | 파일 | 용도 | +|---------|------|------| +| UnifiedInput | UnifiedInput.tsx | 텍스트/숫자/이메일/채번 입력 | +| UnifiedSelect | UnifiedSelect.tsx | 선택박스/라디오/체크박스/카테고리 | +| UnifiedDate | UnifiedDate.tsx | 날짜/시간 입력 | +| UnifiedRepeater | UnifiedRepeater.tsx | 리피터 테이블 | +| UnifiedLayout | UnifiedLayout.tsx | 레이아웃 컨테이너 | +| UnifiedGroup | UnifiedGroup.tsx | 그룹 컨테이너 | +| UnifiedHierarchy | UnifiedHierarchy.tsx | 계층 구조 표시 | +| UnifiedList | UnifiedList.tsx | 리스트 표시 | +| UnifiedMedia | UnifiedMedia.tsx | 파일/이미지/비디오 | +| UnifiedBiz | UnifiedBiz.tsx | 비즈니스 컴포넌트 | +| UnifiedFormContext | UnifiedFormContext.tsx | 폼 상태 관리 | + +### 8.2 inputType 자동 처리 + +Unified 컴포넌트는 `inputType`에 따라 자동으로 적절한 UI를 렌더링합니다: + +```typescript +// UnifiedInput.tsx +switch (inputType) { + case "numbering": + // 채번 규칙 자동 조회 및 코드 생성 + break; + case "text": + case "email": + case "phone": + // 텍스트 입력 + break; +} + +// UnifiedSelect.tsx +switch (inputType) { + case "category": + // 카테고리 값 자동 조회 및 드롭다운 표시 + break; + case "select": + case "radio": + // 일반 선택 + break; +} +``` + +--- + +## 9. 개발 가이드 + +### 9.1 새 V2 컴포넌트 생성 + +```bash +frontend/lib/registry/components/v2-my-component/ +├── index.ts # 컴포넌트 정의 (createComponentDefinition) +├── types.ts # 타입 정의 +├── MyComponent.tsx # 메인 컴포넌트 +├── MyComponentRenderer.tsx # 렌더러 (선택) +├── MyComponentConfigPanel.tsx # 설정 패널 +└── README.md # 문서 +``` + +### 9.2 컴포넌트 정의 템플릿 + +```typescript +// index.ts +import { createComponentDefinition, ComponentCategory } from "@/types/component"; +import { MyComponent } from "./MyComponent"; +import { MyComponentConfigPanel } from "./MyComponentConfigPanel"; +import { defaultConfig } from "./types"; + +export const V2MyComponentDefinition = createComponentDefinition({ + id: "v2-my-component", + name: "내 컴포넌트", + nameEng: "My Component", + description: "컴포넌트 설명", + category: ComponentCategory.DISPLAY, + component: MyComponent, + defaultConfig, + configPanel: MyComponentConfigPanel, + tags: ["태그1", "태그2"], +}); +``` + +### 9.3 V2 EventBus 사용 체크리스트 + +- [ ] V2 EventBus import: `import { v2EventBus, V2_EVENTS } from "@/lib/v2-core";` +- [ ] 이벤트 구독 시 `componentId` 설정 +- [ ] `useEffect` cleanup에서 `unsubscribe()` 호출 +- [ ] 레거시 호환 필요 시 `window.addEventListener`도 유지 (점진적 마이그레이션) + +### 9.4 V2 ErrorBoundary 사용 체크리스트 + +- [ ] 컴포넌트 export에서 ErrorBoundary 래핑 +- [ ] `componentId`와 `componentType` 설정 +- [ ] 적절한 `fallbackStyle` 선택 + +--- + +## 10. 참고 자료 + +### 10.1 관련 문서 + +- [V2 컴포넌트 결합도 분석](./V2_COMPONENT_COUPLING_ANALYSIS.md) +- [채번 규칙 가이드](../frontend/lib/registry/components/v2-numbering-rule/README.md) +- [카테고리 트리 구조](../db/migrations/042_create_category_values_test.sql) + +### 10.2 관련 파일 + +``` +V2 Core: +- frontend/lib/v2-core/ + +V2 컴포넌트: +- frontend/lib/registry/components/v2-*/ + +Unified 폼 컴포넌트: +- frontend/components/unified/ + +채번/카테고리 테스트 테이블: +- db/migrations/040_create_numbering_rules_test.sql +- db/migrations/042_create_category_values_test.sql +``` + +### 10.3 디버깅 + +개발 환경에서 다음 전역 객체로 상태 확인 가능: + +```javascript +// 브라우저 콘솔에서 +window.__v2EventBus.printState() // EventBus 구독 상태 +window.__legacyEventAdapter.getMappings() // 레거시 이벤트 매핑 +``` + +--- + +## 11. 향후 계획 + +### 11.1 단기 (1-2주) + +- [ ] 나머지 중간 결합도 컴포넌트 마이그레이션 + - v2-repeat-container + - v2-split-panel-layout + - v2-aggregation-widget + - v2-tabs-widget + +### 11.2 중기 (1개월) + +- [ ] buttonActions.ts 분할 (7,145줄 → 여러 서비스) +- [ ] 전역 상태 (`window.__`) 제거 +- [ ] Zustand/Context로 상태 관리 전환 + +### 11.3 장기 + +- [ ] 레거시 컴포넌트 완전 제거 +- [ ] CustomEvent 완전 제거 +- [ ] V2 전용 모드 도입 + +--- + +## 부록: V2 컴포넌트 위치 + +``` +frontend/lib/registry/components/ +├── v2-aggregation-widget/ +├── v2-button-primary/ +├── v2-card-display/ +├── v2-category-manager/ +├── v2-divider-line/ +├── v2-location-swap-selector/ +├── v2-numbering-rule/ +├── v2-pivot-grid/ +├── v2-rack-structure/ +├── v2-repeat-container/ +├── v2-repeat-screen-modal/ +├── v2-section-card/ +├── v2-section-paper/ +├── v2-split-panel-layout/ +├── v2-table-list/ +├── v2-table-search-widget/ +├── v2-tabs-widget/ +├── v2-text-display/ +└── v2-unified-repeater/ +``` +