Files
vexplor/docs/V2_COMPONENT_GUIDE.md
kjs 607d686535 docs: V2 컴포넌트 가이드 문서 추가
- V2 컴포넌트의 아키텍처, 설계 원칙, 사용법을 정리한 가이드를 추가하였습니다.
- V2 컴포넌트의 개요, 목록, Core 인프라, 이벤트 시스템, 채번/카테고리 시스템, 설정 패널 가이드, 결합도 현황, Unified 폼 컴포넌트, 개발 가이드, 참고 자료 및 향후 계획을 포함하고 있습니다.
- 각 컴포넌트의 특징과 사용법을 상세히 설명하여 개발자들이 V2 컴포넌트를 쉽게 이해하고 활용할 수 있도록 하였습니다.
2026-01-26 12:00:40 +09:00

17 KiB

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)
  • 타임아웃 및 재시도 지원
  • 디버그 모드 지원

사용법:

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)
  • 재시도 기능
  • 에러 이벤트 자동 발행

사용법:

import { V2ErrorBoundary } from "@/lib/v2-core";

// 컴포넌트 래핑
<V2ErrorBoundary
  componentId="my-component-id"
  componentType="MyComponent"
  fallbackStyle="compact"
>
  <MyComponent {...props} />
</V2ErrorBoundary>

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 예시

// ✅ 올바른 ConfigPanel
export const MyComponentConfigPanel: React.FC<Props> = ({ config, onChange }) => {
  return (
    <div className="space-y-4">
      {/* 표시 옵션만 설정 */}
      <div>
        <Label> 모드</Label>
        <Select 
          value={config.viewMode} 
          onValueChange={(v) => onChange({ ...config, viewMode: v })}
        >
          <SelectItem value="list">리스트</SelectItem>
          <SelectItem value="card">카드</SelectItem>
        </Select>
      </div>
      
      <div>
        <Label>읽기 전용</Label>
        <Switch
          checked={config.readonly}
          onCheckedChange={(v) => onChange({ ...config, readonly: v })}
        />
      </div>
    </div>
  );
};

// ❌ 잘못된 ConfigPanel
export const BadConfigPanel: React.FC<Props> = ({ config, onChange }) => {
  return (
    <div>
      {/* 채번 규칙 ID를 저장하면 안 됨! */}
      <Select 
        value={config.numberingRuleId}  // ❌
        onValueChange={(v) => onChange({ ...config, numberingRuleId: v })}
      >
        {numberingRules.map(rule => (
          <SelectItem value={rule.id}>{rule.name}</SelectItem>
        ))}
      </Select>
    </div>
  );
};

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를 렌더링합니다:

// 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 컴포넌트 생성

frontend/lib/registry/components/v2-my-component/
├── index.ts                    # 컴포넌트 정의 (createComponentDefinition)
├── types.ts                    # 타입 정의
├── MyComponent.tsx             # 메인 컴포넌트
├── MyComponentRenderer.tsx     # 렌더러 (선택)
├── MyComponentConfigPanel.tsx  # 설정 패널
└── README.md                   # 문서

9.2 컴포넌트 정의 템플릿

// 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 래핑
  • componentIdcomponentType 설정
  • 적절한 fallbackStyle 선택

10. 참고 자료

10.1 관련 문서

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 디버깅

개발 환경에서 다음 전역 객체로 상태 확인 가능:

// 브라우저 콘솔에서
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/