# 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 (