# V2 컴포넌트 연동 가이드

## 목차

1. [개요](#1-개요)
2. [V2 표준 이벤트 시스템](#2-v2-표준-이벤트-시스템)
3. [이벤트 시스템 상세](#3-이벤트-시스템-상세)
4. [Context 시스템](#4-context-시스템)
5. [데이터 전달 인터페이스](#5-데이터-전달-인터페이스)
6. [컴포넌트별 연동 능력](#6-컴포넌트별-연동-능력)
7. [연동 가능한 조합](#7-연동-가능한-조합)
8. [연동 설정 방법](#8-연동-설정-방법)

---

## 1. 개요

V2 컴포넌트들은 세 가지 메커니즘을 통해 상호 통신합니다:

| 메커니즘 | 용도 | 특징 |
|----------|------|------|
| **이벤트 시스템** | 비동기 통신, 느슨한 결합 | V2 표준 이벤트 타입 사용 |
| **Context 시스템** | 상태 공유, 동기 통신 | React Context API |
| **데이터 전달 인터페이스** | 명시적 데이터 전송 | `DataProvidable` / `DataReceivable` |

---

## 2. V2 표준 이벤트 시스템

### 2.1 이벤트 타입 정의 파일

**파일 위치**: `frontend/types/component-events.ts`

모든 V2 컴포넌트는 이 파일에 정의된 **타입 안전한 이벤트 시스템**을 사용해야 합니다.

### 2.2 이벤트 이름 상수

```typescript
import { V2_EVENTS } from "@/types/component-events";

// 사용 가능한 이벤트
V2_EVENTS.TABLE_LIST_DATA_CHANGE    // "tableListDataChange"
V2_EVENTS.REPEATER_DATA_CHANGE      // "repeaterDataChange"
V2_EVENTS.BEFORE_FORM_SAVE          // "beforeFormSave"
V2_EVENTS.AFTER_FORM_SAVE           // "afterFormSave"
V2_EVENTS.REPEATER_SAVE             // "repeaterSave"
V2_EVENTS.REFRESH_TABLE             // "refreshTable"
V2_EVENTS.REFRESH_CARD_DISPLAY      // "refreshCardDisplay"
V2_EVENTS.COMPONENT_DATA_TRANSFER   // "componentDataTransfer"
V2_EVENTS.SPLIT_PANEL_DATA_TRANSFER // "splitPanelDataTransfer"
```

### 2.3 유틸리티 함수

#### 타입 안전한 이벤트 발행

```typescript
import { dispatchV2Event, V2_EVENTS } from "@/types/component-events";

// 올바른 방법 (타입 안전)
dispatchV2Event(V2_EVENTS.REPEATER_DATA_CHANGE, {
  componentId: "my-repeater",
  tableName: "order_detail",
  data: rows,
  selectedData: selectedRows,
});

// 잘못된 방법 (타입 오류 발생)
dispatchV2Event(V2_EVENTS.REPEATER_DATA_CHANGE, {
  wrongField: "value",  // 타입 에러!
});
```

#### 타입 안전한 이벤트 구독

```typescript
import { subscribeV2Event, V2_EVENTS, type RepeaterDataChangeDetail } from "@/types/component-events";

useEffect(() => {
  // 구독 (자동 cleanup 함수 반환)
  const unsubscribe = subscribeV2Event(
    V2_EVENTS.REPEATER_DATA_CHANGE,
    (event: CustomEvent<RepeaterDataChangeDetail>) => {
      const { componentId, data } = event.detail;
      // 타입 안전하게 데이터 접근
    }
  );

  return () => unsubscribe();
}, []);
```

### 2.4 이벤트 상세 타입

```typescript
// 테이블 리스트 데이터 변경
interface TableListDataChangeDetail {
  componentId: string;
  tableName: string;
  data: any[];
  selectedRows: string[] | number[];
}

// 리피터 데이터 변경
interface RepeaterDataChangeDetail {
  componentId: string;
  tableName: string;
  data: any[];
  selectedData?: any[];
}

// 폼 저장 전
interface BeforeFormSaveDetail {
  formData: Record<string, any>;
  skipDefaultSave?: boolean;
}

// 리피터 저장 (마스터-디테일 FK 연결용)
interface RepeaterSaveDetail {
  parentId?: string | number;
  masterRecordId: string | number;
  mainFormData: Record<string, any>;
  tableName: string;
}

// 컴포넌트 간 데이터 전달
interface ComponentDataTransferDetail {
  sourceComponentId: string;
  targetComponentId: string;
  data: any[];
  mode: "append" | "replace" | "merge";
  mappingRules?: MappingRule[];
}
```

### 2.5 마이그레이션 가이드

**이전 방식 (사용 금지)**:

```typescript
// ❌ 타입 안전하지 않음
window.addEventListener("tableListDataChange" as any, handler);
window.dispatchEvent(new CustomEvent("repeaterDataChange", { detail }));
```

**새로운 방식 (권장)**:

```typescript
// ✅ 타입 안전함
import { subscribeV2Event, dispatchV2Event, V2_EVENTS } from "@/types/component-events";

const unsubscribe = subscribeV2Event(V2_EVENTS.TABLE_LIST_DATA_CHANGE, handler);
dispatchV2Event(V2_EVENTS.REPEATER_DATA_CHANGE, detail);
```

---

## 3. 이벤트 시스템 상세

### 3.1 저장 관련 이벤트

#### `beforeFormSave`

폼 저장 직전에 발생하여 각 컴포넌트가 데이터를 수집할 기회를 제공합니다.

| 항목 | 내용 |
|------|------|
| **발행자** | `buttonActions.ts`, `UnifiedFormContext.tsx` |
| **구독자** | `UnifiedRepeater`, `SimpleRepeaterTable`, `ModalRepeaterTable`, `SelectedItemsDetailInput`, `RepeatScreenModal`, `UniversalFormModal` |
| **데이터 구조** | `{ formData: Record<string, any>, skipDefaultSave?: boolean }` |

```typescript
// 발행 예시
window.dispatchEvent(new CustomEvent("beforeFormSave", {
  detail: { formData: {}, skipDefaultSave: false }
}));

// 구독 예시
window.addEventListener("beforeFormSave", (event: CustomEvent) => {
  const { formData } = event.detail;
  formData["myField"] = myValue; // 데이터 추가
});
```

#### `afterFormSave`

폼 저장 완료 후 발생합니다.

| 항목 | 내용 |
|------|------|
| **발행자** | `UnifiedFormContext.tsx` |
| **데이터 구조** | `{ success: boolean, data?: any }` |

#### `repeaterSave`

마스터 저장 후 리피터에 FK를 전달하기 위해 발생합니다.

| 항목 | 내용 |
|------|------|
| **발행자** | `InteractiveScreenViewerDynamic.tsx` |
| **구독자** | `UnifiedRepeater.tsx` |
| **데이터 구조** | `{ parentId, masterRecordId, mainFormData, tableName }` |

```typescript
// 마스터-디테일 저장 흐름
// 1. 마스터 저장 완료
// 2. repeaterSave 이벤트 발행
window.dispatchEvent(new CustomEvent("repeaterSave", {
  detail: {
    masterRecordId: savedId,  // 마스터 ID
    tableName: "receiving_mng",
    mainFormData: formData
  }
}));

// 3. UnifiedRepeater에서 수신
// → 모든 행의 foreignKeyColumn에 masterRecordId 설정
// → 디테일 테이블에 저장
```

---

### 3.2 데이터 변경 이벤트

#### `tableListDataChange`

테이블 리스트의 데이터가 변경될 때 발생합니다.

| 항목 | 내용 |
|------|------|
| **발행자** | `v2-table-list`, `table-list` |
| **구독자** | `v2-repeat-container`, `v2-aggregation-widget`, `repeat-container`, `aggregation-widget` |
| **데이터 구조** | `{ componentId, tableName, data: any[], selectedRows: string[] }` |

```typescript
// 테이블 리스트 → 집계 위젯 연동
// 테이블 데이터 변경 시 자동으로 집계 갱신
```

#### `repeaterDataChange`

리피터 컴포넌트의 데이터가 변경될 때 발생합니다.

| 항목 | 내용 |
|------|------|
| **구독자** | `v2-repeat-container`, `v2-aggregation-widget` |

---

### 3.3 UI 갱신 이벤트

#### `refreshTable`

테이블 데이터를 다시 로드합니다.

| 항목 | 내용 |
|------|------|
| **발행자** | `v2-button-primary`, `InteractiveScreenViewerDynamic`, `ScreenModal`, `buttonActions.ts` |
| **구독자** | `v2-table-list`, `v2-split-panel-layout`, `InteractiveDataTable` |

```typescript
// 저장 후 테이블 새로고침
window.dispatchEvent(new CustomEvent("refreshTable"));
```

#### `refreshCardDisplay`

카드 디스플레이를 다시 로드합니다.

| 항목 | 내용 |
|------|------|
| **발행자** | `InteractiveScreenViewerDynamic`, `buttonActions.ts` |
| **구독자** | `v2-card-display`, `card-display` |

---

### 3.4 모달 제어 이벤트

#### `openEditModal`

편집 모달을 엽니다.

| 항목 | 내용 |
|------|------|
| **발행자** | `SplitPanelLayout2`, `InteractiveScreenViewer`, `InteractiveDataTable` |
| **구독자** | `EditModal.tsx`, 화면 페이지 |

#### `closeEditModal`

편집 모달을 닫습니다.

| 항목 | 내용 |
|------|------|
| **발행자** | `v2-button-primary`, `buttonActions.ts` |
| **구독자** | `EditModal.tsx` |

#### `saveSuccessInModal`

모달 내 저장 성공 시 발생합니다.

| 항목 | 내용 |
|------|------|
| **발행자** | `v2-button-primary`, `buttonActions.ts` |
| **구독자** | `ScreenModal.tsx` |

---

### 3.5 데이터 전달 이벤트

#### `componentDataTransfer`

컴포넌트 간 데이터 전달 시 발생합니다.

| 항목 | 내용 |
|------|------|
| **발행자** | `buttonActions.ts` |
| **구독자** | `UnifiedRepeater.tsx` |

#### `splitPanelDataTransfer`

분할 패널 간 데이터 전달 시 발생합니다.

| 항목 | 내용 |
|------|------|
| **발행자** | `buttonActions.ts` |
| **구독자** | `UnifiedRepeater.tsx`, `RepeaterFieldGroupRenderer.tsx` |

#### `screenDataTransfer`

화면 간 데이터 전달 시 발생합니다.

| 항목 | 내용 |
|------|------|
| **발행자** | `buttonActions.ts`, `useScreenDataTransfer.ts` |
| **구독자** | `useScreenDataTransfer.ts` |

---

### 3.6 연관 데이터 버튼 이벤트

#### `related-button-select`

연관 데이터 버튼 클릭 시 발생합니다.

| 항목 | 내용 |
|------|------|
| **발행자** | `RelatedDataButtonsComponent.tsx` |
| **구독자** | `v2-table-list`, `table-list`, `InteractiveDataTable` |
| **데이터 구조** | `{ targetTable, filterColumn, filterValue, selectedData }` |

#### `related-button-register` / `related-button-unregister`

연관 데이터 버튼이 대상 테이블을 등록/해제합니다.

| 항목 | 내용 |
|------|------|
| **발행자** | `RelatedDataButtonsComponent.tsx` |
| **구독자** | `v2-table-list`, `table-list` |

---

### 3.7 이벤트 흐름 다이어그램

```
┌─────────────────────────────────────────────────────────────────────────┐
│                           저장 플로우                                    │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  [저장 버튼 클릭]                                                        │
│        │                                                                 │
│        ▼                                                                 │
│  ┌─────────────────┐                                                    │
│  │ beforeFormSave  │ ────────────────────────────────────────────┐      │
│  └────────┬────────┘                                             │      │
│           │                                                      │      │
│           ▼                                                      ▼      │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐         │
│  │ UnifiedRepeater │  │ SimpleRepeater  │  │ ModalRepeater   │  ...    │
│  │ (데이터 수집)    │  │ (데이터 수집)    │  │ (데이터 수집)    │         │
│  └─────────────────┘  └─────────────────┘  └─────────────────┘         │
│           │                                                             │
│           ▼                                                             │
│  ┌─────────────────┐                                                    │
│  │   API 저장      │                                                    │
│  └────────┬────────┘                                                    │
│           │                                                             │
│           ▼                                                             │
│  ┌─────────────────┐         ┌─────────────────┐                       │
│  │ afterFormSave   │         │  repeaterSave   │ (마스터-디테일 시)     │
│  └────────┬────────┘         └────────┬────────┘                       │
│           │                           │                                 │
│           ▼                           ▼                                 │
│  ┌─────────────────┐         ┌─────────────────┐                       │
│  │  refreshTable   │         │ UnifiedRepeater │                       │
│  └─────────────────┘         │ (FK 설정 후 저장)│                       │
│                              └─────────────────┘                       │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────┐
│                        데이터 변경 플로우                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────────┐                                                    │
│  │  v2-table-list  │                                                    │
│  │ (데이터 로드/변경)│                                                    │
│  └────────┬────────┘                                                    │
│           │                                                             │
│           ▼                                                             │
│  ┌─────────────────────┐                                                │
│  │ tableListDataChange │                                                │
│  └────────┬────────────┘                                                │
│           │                                                             │
│           ├─────────────────────┬─────────────────────┐                 │
│           ▼                     ▼                     ▼                 │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐         │
│  │v2-aggregation-  │  │v2-repeat-       │  │ 기타 구독자     │         │
│  │widget (집계갱신) │  │container        │  │                 │         │
│  └─────────────────┘  └─────────────────┘  └─────────────────┘         │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘
```

---

## 4. Context 시스템

### 4.1 TableOptionsContext

**역할**: 화면 내 테이블 컴포넌트 등록/관리 및 필터링 연동

**파일**: `frontend/contexts/TableOptionsContext.tsx`

#### 제공하는 기능

| 함수/상태 | 설명 |
|-----------|------|
| `registeredTables` | 등록된 테이블 Map |
| `selectedTableId` | 현재 선택된 테이블 ID |
| `registerTable(tableId, registration)` | 테이블 등록 |
| `unregisterTable(tableId)` | 테이블 해제 |
| `getTable(tableId)` | 테이블 조회 |
| `setSelectedTableId(id)` | 선택 테이블 설정 |
| `updateTableDataCount(tableId, count)` | 데이터 건수 업데이트 |
| `getActiveTabTables()` | 활성 탭의 테이블만 반환 |

#### TableRegistration 구조

```typescript
interface TableRegistration {
  tableId: string;
  tableName: string;
  columns: ColumnInfo[];
  dataCount: number;
  parentTabId?: string;                    // 소속 탭 ID
  onFilterChange: (filters: TableFilter[]) => void;
  getColumnUniqueValues: (columnName: string) => Promise<SelectOption[]>;
}
```

#### 연동 흐름

```
┌─────────────────────────────────────────────────────────────────────────┐
│                     TableOptionsContext 연동                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────────┐                                                    │
│  │  v2-table-list  │                                                    │
│  └────────┬────────┘                                                    │
│           │ registerTable()                                             │
│           ▼                                                             │
│  ┌─────────────────────────────────────┐                                │
│  │      TableOptionsContext            │                                │
│  │  ┌─────────────────────────────┐    │                                │
│  │  │     registeredTables        │    │                                │
│  │  │  - tableId                  │    │                                │
│  │  │  - onFilterChange()         │    │                                │
│  │  │  - columns                  │    │                                │
│  │  └─────────────────────────────┘    │                                │
│  └────────────────┬────────────────────┘                                │
│                   │                                                      │
│                   ▼                                                      │
│  ┌─────────────────────────────────────┐                                │
│  │    v2-table-search-widget           │                                │
│  │  - 등록된 테이블 목록 표시           │                                │
│  │  - 필터 입력                        │                                │
│  │  - currentTable.onFilterChange()    │                                │
│  └────────────────┬────────────────────┘                                │
│                   │                                                      │
│                   ▼                                                      │
│  ┌─────────────────────────────────────┐                                │
│  │    v2-table-list (자동 재조회)       │                                │
│  └─────────────────────────────────────┘                                │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘
```

#### 사용 컴포넌트

| 컴포넌트 | 사용 방식 |
|----------|----------|
| `v2-table-list` | 테이블 등록/해제, 데이터 건수 업데이트 |
| `v2-table-search-widget` | 등록된 테이블 목록 조회, 필터 적용 |
| `v2-split-panel-layout` | 내부 테이블 등록/해제 |
| `v2-card-display` | 테이블 등록 (선택적) |

---

### 4.2 SplitPanelContext

**역할**: 좌우 분할 패널 간 데이터 전달 및 상태 관리

**파일**: `frontend/contexts/SplitPanelContext.tsx`

#### 제공하는 기능

| 함수/상태 | 설명 |
|-----------|------|
| `splitPanelId` | 분할 패널 ID |
| `leftScreenId`, `rightScreenId` | 좌우 화면 ID |
| `selectedLeftData` | 좌측 선택 데이터 |
| `setSelectedLeftData(data)` | 좌측 선택 데이터 설정 |
| `addedItemIds` | 우측에 추가된 항목 ID Set |
| `addItemIds(ids)` | 항목 ID 추가 |
| `registerReceiver(receiver)` | 데이터 수신자 등록 |
| `transferToOtherSide(data)` | 반대편으로 데이터 전달 |
| `linkedFilters` | 연결 필터 설정 |
| `parentDataMapping` | 부모 데이터 매핑 설정 |

#### 연동 흐름

```
┌─────────────────────────────────────────────────────────────────────────┐
│                     SplitPanelContext 연동                              │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │                    v2-split-panel-layout                         │    │
│  │                    (SplitPanelProvider)                          │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│         │                                             │                  │
│         ▼                                             ▼                  │
│  ┌─────────────────┐                         ┌─────────────────┐        │
│  │    좌측 패널     │                         │    우측 패널     │        │
│  │  (CardDisplay)  │                         │  (TableList)    │        │
│  └────────┬────────┘                         └────────┬────────┘        │
│           │                                           │                  │
│           │ 행 클릭                                   │                  │
│           ▼                                           │                  │
│  setSelectedLeftData(rowData)                         │                  │
│           │                                           │                  │
│           └──────────────────────────────────────────▶│                  │
│                                                       │                  │
│                     relation 설정에 따라              │                  │
│                     자동 필터링 (FK 기반)             │                  │
│                                                       ▼                  │
│                                             ┌─────────────────┐         │
│                                             │ 필터링된 데이터  │         │
│                                             │ 표시            │         │
│                                             └─────────────────┘         │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘
```

#### 사용 컴포넌트

| 컴포넌트 | 사용 방식 |
|----------|----------|
| `v2-split-panel-layout` | Provider 제공, 좌우 패널 관리 |
| `v2-table-list` | 분할 패널 데이터 수신자로 등록 |
| `v2-card-display` | 분할 패널 위치 확인, 데이터 수신 |
| `v2-button-primary` | 분할 패널 컨텍스트 확인 |

---

### 4.3 ScreenContext

**역할**: 같은 화면 내 컴포넌트 간 통신 (데이터 제공자/수신자 등록)

**파일**: `frontend/contexts/ScreenContext.tsx`

#### 제공하는 기능

| 함수/상태 | 설명 |
|-----------|------|
| `screenId` | 화면 ID |
| `tableName` | 테이블명 |
| `menuObjid` | 메뉴 OBJID (카테고리 값 조회용) |
| `splitPanelPosition` | 분할 패널 위치 (`left` \| `right`) |
| `formData` | 폼 데이터 |
| `updateFormData(field, value)` | 폼 데이터 업데이트 |
| `registerDataProvider(provider)` | 데이터 제공자 등록 |
| `registerDataReceiver(receiver)` | 데이터 수신자 등록 |
| `getDataProvider(id)` | 데이터 제공자 조회 |
| `getDataReceiver(id)` | 데이터 수신자 조회 |
| `getAllDataProviders()` | 모든 데이터 제공자 조회 |

#### 사용 컴포넌트

| 컴포넌트 | 사용 방식 |
|----------|----------|
| `v2-table-list` | 데이터 제공자/수신자로 등록 |
| `v2-card-display` | 화면 컨텍스트 확인 |
| `v2-button-primary` | 화면 컨텍스트 확인, 데이터 전달 실행 |
| `repeater-field-group` | 데이터 수신자 등록, formData 사용 |

---

### 4.4 UnifiedFormContext

**역할**: 폼 상태 관리, 조건부 로직, 저장/검증/초기화

**파일**: `frontend/components/unified/UnifiedFormContext.tsx`

#### 제공하는 기능

| 함수/상태 | 설명 |
|-----------|------|
| `formData` | 폼 데이터 |
| `originalData` | 원본 데이터 (수정 모드) |
| `status` | 폼 상태 (isSubmitting, isDirty, isValid 등) |
| `errors` | 필드 에러 배열 |
| `getValue(field)`, `setValue(field, value)` | 값 관리 |
| `submit(options)` | 폼 저장 |
| `reset()` | 폼 초기화 |
| `validate()` | 폼 검증 |
| `evaluateCondition(condition)` | 조건 평가 |
| `getRepeaterData(key)`, `setRepeaterData(key, data)` | 리피터 데이터 관리 |

---

### 4.5 ActiveTabContext

**역할**: 탭 컴포넌트의 활성 탭 추적

**파일**: `frontend/contexts/ActiveTabContext.tsx`

#### 제공하는 기능

| 함수/상태 | 설명 |
|-----------|------|
| `activeTabs` | 활성 탭 정보 Map |
| `setActiveTab(tabsId, tabId)` | 활성 탭 설정 |
| `getActiveTabId(tabsId)` | 특정 탭 컴포넌트의 활성 탭 ID |
| `getAllActiveTabIds()` | 전체 활성 탭 ID 목록 |

#### 사용 컴포넌트

| 컴포넌트 | 사용 방식 |
|----------|----------|
| `v2-table-search-widget` | 활성 탭 기반 테이블 필터링 |
| `v2-tabs-widget` | 탭 활성화 관리 |

---

### 4.6 ScreenPreviewContext

**역할**: 디자이너 모드와 실제 화면 모드 구분

**파일**: `frontend/contexts/ScreenPreviewContext.tsx`

#### 제공하는 기능

| 함수/상태 | 설명 |
|-----------|------|
| `isPreviewMode` | 미리보기 모드 여부 |

#### 사용 컴포넌트

| 컴포넌트 | 사용 방식 |
|----------|----------|
| `v2-table-search-widget` | 미리보기 모드에서 설정 버튼 비활성화 |
| `v2-button-primary` | 프리뷰 모드 확인 |

---

### 4.7 Context 계층 구조

```
┌─────────────────────────────────────────────────────────────────────────┐
│                        Context 계층 구조                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ScreenPreviewContext (최상위 - 디자이너/실제 화면 구분)                 │
│  │                                                                       │
│  └─── ScreenContext (화면 레벨)                                         │
│       │                                                                  │
│       ├─── TableOptionsContext (테이블 관리)                            │
│       │    │                                                             │
│       │    └─── ActiveTabContext (탭 필터링)                            │
│       │                                                                  │
│       └─── SplitPanelContext (분할 패널 - 선택적)                       │
│                                                                          │
│  UnifiedFormContext (폼 상태 관리 - 독립적, 선택적 사용)                │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘
```

---

## 5. 데이터 전달 인터페이스

### 5.1 DataProvidable 인터페이스

**데이터를 제공하는 컴포넌트**가 구현하는 인터페이스

```typescript
interface DataProvidable {
  componentId: string;
  componentType: string;
  
  // 선택된 데이터 반환
  getSelectedData(): any[];
  
  // 모든 데이터 반환
  getAllData(): any[];
  
  // 선택 초기화
  clearSelection(): void;
}
```

#### 구현 컴포넌트

| 컴포넌트 | 제공 데이터 |
|----------|------------|
| `v2-table-list` | 선택된 행 데이터, 전체 데이터 |
| `v2-card-display` | 선택된 카드 데이터 |
| `select-basic` | 선택된 값 |
| `conditional-container` | 조건부 컨테이너의 선택 값 |

### 5.2 DataReceivable 인터페이스

**데이터를 수신하는 컴포넌트**가 구현하는 인터페이스

```typescript
interface DataReceivable {
  componentId: string;
  componentType: DataReceivableComponentType;
  
  // 데이터 수신
  receiveData(data: any[], config: DataReceiverConfig): Promise<void>;
  
  // 현재 데이터 반환
  getData(): any;
}

type DataReceivableComponentType = 
  | "table-list" 
  | "unified-repeater" 
  | "repeater-field-group"
  | "simple-repeater-table";
```

#### 구현 컴포넌트

| 컴포넌트 | 수신 모드 |
|----------|----------|
| `v2-table-list` | append, replace, merge |
| `repeater-field-group` | append |
| `embedded-screen` | 화면 임베딩 데이터 수신 |

### 5.3 DataReceiverConfig

데이터 전달 시 설정

```typescript
interface DataReceiverConfig {
  // 타겟 컴포넌트 정보
  targetComponentId: string;
  targetComponentType: DataReceivableComponentType;
  
  // 수신 모드
  mode: "append" | "replace" | "merge";
  
  // 필드 매핑 규칙
  mappingRules: Array<{
    sourceField: string;      // 소스 필드
    targetField: string;      // 타겟 필드
    transform?: string;       // 변환 함수 (선택)
    defaultValue?: any;       // 기본값 (선택)
  }>;
  
  // 조건부 전달
  condition?: {
    field: string;
    operator: "=" | "!=" | ">" | "<";
    value: any;
  };
  
  // 검증 규칙
  validation?: {
    required: string[];       // 필수 필드
    unique?: string[];        // 중복 불가 필드
  };
}
```

### 5.4 데이터 전달 흐름

```
┌─────────────────────────────────────────────────────────────────────────┐
│                     데이터 전달 흐름 (버튼 액션)                         │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────────┐                                                    │
│  │ v2-button-      │                                                    │
│  │ primary         │ action.type = "transferData"                       │
│  └────────┬────────┘                                                    │
│           │                                                              │
│           ▼                                                              │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │                 handleTransferDataAction()                       │    │
│  ├─────────────────────────────────────────────────────────────────┤    │
│  │  1. ScreenContext에서 소스 컴포넌트 조회                         │    │
│  │     getDataProvider(sourceComponentId)                           │    │
│  │                                                                  │    │
│  │  2. 소스에서 데이터 가져오기                                     │    │
│  │     source.getSelectedData() 또는 source.getAllData()            │    │
│  │                                                                  │    │
│  │  3. 매핑 규칙 적용                                               │    │
│  │     mappingRules.forEach(rule => ...)                            │    │
│  │                                                                  │    │
│  │  4. ScreenContext에서 타겟 컴포넌트 조회                         │    │
│  │     getDataReceiver(targetComponentId)                           │    │
│  │                                                                  │    │
│  │  5. 타겟에 데이터 전달                                           │    │
│  │     target.receiveData(mappedData, config)                       │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│           │                                                              │
│           ▼                                                              │
│  ┌─────────────────┐                                                    │
│  │ 타겟 컴포넌트    │                                                    │
│  │ (v2-table-list, │                                                    │
│  │  repeater 등)   │                                                    │
│  └─────────────────┘                                                    │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘
```

---

## 6. 컴포넌트별 연동 능력

### 6.1 연동 능력 매트릭스

| 컴포넌트 | 이벤트 발행 | 이벤트 구독 | DataProvider | DataReceiver | Context 사용 |
|----------|:-----------:|:-----------:|:------------:|:------------:|:------------:|
| `v2-table-list` | ✅ | ✅ | ✅ | ✅ | TableOptions, Screen, SplitPanel |
| `v2-split-panel-layout` | ✅ | ✅ | ❌ | ❌ | TableOptions (Provider) |
| `v2-unified-repeater` | ✅ | ✅ | ✅ | ✅ | Screen |
| `v2-button-primary` | ✅ | ❌ | ❌ | ❌ | Screen, SplitPanel |
| `v2-table-search-widget` | ❌ | ❌ | ❌ | ❌ | TableOptions, ActiveTab |
| `v2-aggregation-widget` | ❌ | ✅ | ❌ | ❌ | - |
| `v2-repeat-container` | ❌ | ✅ | ❌ | ❌ | - |
| `v2-card-display` | ✅ | ✅ | ✅ | ❌ | TableOptions, Screen, SplitPanel |
| `v2-pivot-grid` | ❌ | ❌ | ❌ | ❌ | - |
| `v2-tabs-widget` | ❌ | ❌ | ❌ | ❌ | ActiveTab |

### 6.2 컴포넌트별 상세

#### v2-table-list

**발행 이벤트**:
- `tableListDataChange` - 데이터 로드/변경 시

**구독 이벤트**:
- `refreshTable` - 테이블 새로고침
- `related-button-select` - 연관 버튼 선택
- `related-button-register/unregister` - 연관 버튼 등록/해제

**DataProvidable 구현**:
```typescript
getSelectedData(): any[]    // 체크된 행 데이터
getAllData(): any[]         // 전체 데이터
clearSelection(): void      // 선택 초기화
```

**DataReceivable 구현**:
```typescript
receiveData(data, config): Promise<void>
// mode: "append" - 기존 데이터에 추가
// mode: "replace" - 데이터 교체
// mode: "merge" - 키 기준 병합
```

---

#### v2-unified-repeater

**발행 이벤트**:
- `repeaterDataChange` - 데이터 변경 시 (V2 표준 이벤트)

**구독 이벤트**:
- `beforeFormSave` - 저장 전 데이터 수집
- `repeaterSave` - 마스터 저장 후 FK 설정
- `componentDataTransfer` - 컴포넌트 간 데이터 전달
- `splitPanelDataTransfer` - 분할 패널 간 데이터 전달

**DataProvidable 구현**:
- `getSelectedData()` - 선택된 행 데이터 반환
- `getAllData()` - 전체 데이터 반환
- `clearSelection()` - 선택 초기화

**DataReceivable 구현**:
- `receiveData(data, config)` - 데이터 수신 (append, replace, merge 모드 지원)
- `getData()` - 현재 데이터 반환

**Context 등록**:
- ScreenContext에 DataProvider/DataReceiver 자동 등록

---

#### v2-button-primary

**발행 이벤트**:
- `refreshTable` - 저장 후 테이블 갱신
- `closeEditModal` - 모달 닫기
- `saveSuccessInModal` - 모달 저장 성공

**역할**:
- 저장, 삭제, 데이터 전달 등 액션 실행
- `buttonActions.ts`의 함수들 호출

---

#### v2-table-search-widget

**Context 의존**:
- `TableOptionsContext` - 등록된 테이블 조회, 필터 적용
- `ActiveTabContext` - 활성 탭 기반 테이블 필터링

**동작**:
1. `TableOptionsContext.registeredTables`에서 테이블 목록 조회
2. 사용자가 필터 입력
3. `currentTable.onFilterChange(filters)` 호출
4. 해당 테이블이 자동으로 재조회

---

#### v2-aggregation-widget

**구독 이벤트**:
- `tableListDataChange` - 테이블 데이터 변경 시 집계 갱신
- `repeaterDataChange` - 리피터 데이터 변경 시 집계 갱신

---

#### v2-split-panel-layout

**Provider 제공**:
- `SplitPanelContext` - 좌우 패널 데이터 전달

**발행 이벤트**:
- `openScreenModal` - 화면 모달 열기

**구독 이벤트**:
- `refreshTable` - 내부 테이블 갱신

**커스텀 모드 (displayMode: "custom")**:
- 패널 내부에 자유롭게 컴포넌트 배치 가능 (v2-tabs-widget과 동일 구조)
- 컴포넌트 클릭 시 좌측 설정 패널에서 속성 편집
- 드래그앤드롭으로 컴포넌트 이동, 리사이즈 핸들로 크기 조절
- 디자인 모드에서 실제 컴포넌트 렌더링 (미리보기)

```typescript
// 커스텀 모드 설정 예시
leftPanel: {
  displayMode: "custom",
  components: [
    {
      id: "btn-1",
      componentType: "v2-button-primary",
      label: "저장",
      position: { x: 10, y: 10 },
      size: { width: 100, height: 40 },
      componentConfig: { buttonAction: "save" }
    }
  ]
}
```

---

## 7. 연동 가능한 조합

### 7.1 검색/필터 연동

#### v2-table-search-widget ↔ v2-table-list

```
┌─────────────────────────────────────────────────────────────────────────┐
│                     검색 위젯 ↔ 테이블 리스트                           │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │              v2-table-search-widget                              │    │
│  │  ┌─────┐ ┌─────────┐ ┌──────────┐ ┌────────┐                    │    │
│  │  │ 이름 │ │ 날짜범위 │ │ 상태선택 │ │ 초기화 │                    │    │
│  │  └──┬──┘ └────┬────┘ └────┬─────┘ └────────┘                    │    │
│  └─────┼─────────┼───────────┼──────────────────────────────────────┘    │
│        │         │           │                                           │
│        └─────────┴───────────┘                                           │
│                  │ onFilterChange(filters)                               │
│                  ▼                                                       │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │              v2-table-list                                       │    │
│  │  ┌─────────────────────────────────────────────────────────┐    │    │
│  │  │ 필터링된 데이터 표시                                     │    │    │
│  │  └─────────────────────────────────────────────────────────┘    │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                                                                          │
│  연결 방식: TableOptionsContext                                         │
│  설정: v2-table-search-widget의 targetPanelPosition 설정               │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘
```

**설정 방법**:
- `v2-table-search-widget`의 `filterMode`: `"dynamic"` 또는 `"preset"`
- `v2-table-search-widget`의 `targetPanelPosition`: `"left"`, `"right"`, `"auto"`
- `v2-table-list`는 자동으로 `TableOptionsContext`에 등록됨

---

### 7.2 마스터-디테일 연동

#### v2-split-panel-layout (좌측 ↔ 우측)

```
┌─────────────────────────────────────────────────────────────────────────┐
│                     마스터-디테일 (분할 패널)                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌──────────────────────────────────────────────────────────────────┐   │
│  │                    v2-split-panel-layout                          │   │
│  │  ┌────────────────────┐  │  ┌────────────────────────────────┐   │   │
│  │  │    좌측 패널        │  │  │          우측 패널              │   │   │
│  │  │   (마스터 목록)     │  │  │         (디테일 정보)           │   │   │
│  │  │                    │  │  │                                │   │   │
│  │  │  - 부서 목록       │  │  │  - 선택된 부서의 직원 목록      │   │   │
│  │  │  - dept_info       │ ──▶ │  - user_info                   │   │   │
│  │  │                    │  │  │  - dept_code = 선택값          │   │   │
│  │  └────────────────────┘  │  └────────────────────────────────┘   │   │
│  └──────────────────────────────────────────────────────────────────┘   │
│                                                                          │
│  연결 방식: SplitPanelContext + relation 설정                           │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘
```

**설정 방법**:
```typescript
rightPanel: {
  tableName: "user_info",
  relation: {
    type: "detail",
    leftColumn: "dept_code",      // 좌측 테이블의 컬럼
    rightColumn: "dept_code",     // 우측 테이블의 필터 컬럼
    // 또는 복합키
    keys: [
      { leftColumn: "company_id", rightColumn: "company_id" },
      { leftColumn: "dept_code", rightColumn: "dept_code" }
    ]
  }
}
```

---

### 7.3 폼 저장 연동

#### v2-button-primary → v2-unified-repeater

```
┌─────────────────────────────────────────────────────────────────────────┐
│                     폼 저장 + 리피터 저장                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │  [폼 입력 필드들]                                                │    │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐                         │    │
│  │  │ 입고번호  │ │ 입고일자  │ │ 거래처   │                         │    │
│  │  └──────────┘ └──────────┘ └──────────┘                         │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │  v2-unified-repeater (입고 상세)                                 │    │
│  │  ┌─────────────────────────────────────────────────────────┐    │    │
│  │  │ 품목코드 │ 품목명 │ 수량 │ 단가 │ 금액                   │    │    │
│  │  ├─────────────────────────────────────────────────────────┤    │    │
│  │  │ ITEM001  │ ...    │ 10   │ 1000 │ 10000                 │    │    │
│  │  │ ITEM002  │ ...    │ 5    │ 2000 │ 10000                 │    │    │
│  │  └─────────────────────────────────────────────────────────┘    │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                                                                          │
│  ┌─────────────────┐                                                    │
│  │   [저장 버튼]    │                                                    │
│  │  v2-button-     │                                                    │
│  │  primary        │                                                    │
│  └────────┬────────┘                                                    │
│           │                                                              │
│           ▼                                                              │
│  1. beforeFormSave 발행 → 리피터가 데이터 수집                          │
│  2. 마스터 테이블 저장 (receiving_mng)                                   │
│  3. repeaterSave 발행 → 리피터가 FK 설정 후 저장                        │
│  4. 디테일 테이블 저장 (receiving_detail)                               │
│  5. refreshTable 발행 → 테이블 갱신                                     │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘
```

**설정 방법**:
```typescript
// v2-button-primary
action: {
  type: "save",
  saveMode: "withRepeater",       // 리피터와 함께 저장
  tableName: "receiving_mng"
}

// v2-unified-repeater
dataSource: {
  tableName: "receiving_detail",
  foreignKey: "receiving_id",     // 마스터 FK 컬럼
  referenceKey: "id"              // 마스터 PK 컬럼
}
```

---

### 7.4 데이터 전달 연동

#### v2-table-list → v2-unified-repeater (버튼으로 데이터 추가)

```
┌─────────────────────────────────────────────────────────────────────────┐
│                     테이블 선택 → 리피터 추가                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │  v2-table-list (품목 선택)                                       │    │
│  │  ┌─────────────────────────────────────────────────────────┐    │    │
│  │  │ ☑ │ 품목코드 │ 품목명         │ 단가                    │    │    │
│  │  ├─────────────────────────────────────────────────────────┤    │    │
│  │  │ ☑ │ ITEM001  │ 노트북         │ 1,000,000              │    │    │
│  │  │ ☑ │ ITEM002  │ 마우스         │ 50,000                 │    │    │
│  │  │ ☐ │ ITEM003  │ 키보드         │ 100,000                │    │    │
│  │  └─────────────────────────────────────────────────────────┘    │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                                                                          │
│  ┌─────────────────┐                                                    │
│  │   [추가 버튼]    │ action.type = "transferData"                      │
│  │  v2-button-     │                                                    │
│  │  primary        │                                                    │
│  └────────┬────────┘                                                    │
│           │                                                              │
│           ▼                                                              │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │  v2-unified-repeater (주문 상세)                                 │    │
│  │  ┌─────────────────────────────────────────────────────────┐    │    │
│  │  │ 품목코드 │ 품목명         │ 수량 │ 단가      │ 금액      │    │    │
│  │  ├─────────────────────────────────────────────────────────┤    │    │
│  │  │ ITEM001  │ 노트북         │ 1    │ 1,000,000 │ 1,000,000│    │    │
│  │  │ ITEM002  │ 마우스         │ 1    │ 50,000    │ 50,000   │    │    │
│  │  └─────────────────────────────────────────────────────────┘    │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘
```

**설정 방법**:
```typescript
// v2-button-primary
action: {
  type: "transferData",
  sourceComponentId: "item-table-list",
  targetComponentId: "order-detail-repeater",
  mappingRules: [
    { sourceField: "item_code", targetField: "item_code" },
    { sourceField: "item_name", targetField: "item_name" },
    { sourceField: "unit_price", targetField: "unit_price" },
    { sourceField: "", targetField: "quantity", defaultValue: 1 }
  ],
  mode: "append"
}
```

---

### 7.5 데이터 집계 연동

#### v2-table-list → v2-aggregation-widget

```
┌─────────────────────────────────────────────────────────────────────────┐
│                     테이블 데이터 → 집계 위젯                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │  v2-aggregation-widget                                           │    │
│  │  ┌───────────────┐ ┌───────────────┐ ┌───────────────┐          │    │
│  │  │ 📊 총 건수     │ │ 💰 총 금액    │ │ 📈 평균 단가   │          │    │
│  │  │    15건       │ │ ₩3,500,000   │ │ ₩233,333     │          │    │
│  │  └───────────────┘ └───────────────┘ └───────────────┘          │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                              ▲                                           │
│                              │ tableListDataChange 이벤트               │
│                              │                                           │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │  v2-table-list                                                   │    │
│  │  (데이터 변경 시 자동으로 이벤트 발행)                           │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                                                                          │
│  연결 방식: tableListDataChange 이벤트 자동 구독                        │
│  설정: v2-aggregation-widget의 dataSourceType = "table"                 │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘
```

**설정 방법**:
```typescript
// v2-aggregation-widget
{
  dataSourceType: "table",
  items: [
    { columnName: "id", aggregationType: "count", label: "총 건수" },
    { columnName: "amount", aggregationType: "sum", label: "총 금액" },
    { columnName: "unit_price", aggregationType: "avg", label: "평균 단가" }
  ]
}
```

---

### 7.6 연관 데이터 버튼 연동

#### related-data-buttons ↔ v2-table-list

```
┌─────────────────────────────────────────────────────────────────────────┐
│                     연관 데이터 버튼 ↔ 테이블                           │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  좌측 패널 (거래처 선택)                                                │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │  v2-card-display (거래처 목록)                                   │    │
│  │  ┌─────────────────────────────────────────────────────────┐    │    │
│  │  │ [선택됨] ABC상사                                          │    │    │
│  │  │          DEF물산                                          │    │    │
│  │  └─────────────────────────────────────────────────────────┘    │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                              │                                           │
│                              ▼ 선택 데이터 전달                          │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │  related-data-buttons                                            │    │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐                         │    │
│  │  │ 품목정보  │ │ 단가정보  │ │ 거래내역  │                         │    │
│  │  │   (5)    │ │   (3)    │ │   (12)   │                         │    │
│  │  └────┬─────┘ └──────────┘ └──────────┘                         │    │
│  └───────┼─────────────────────────────────────────────────────────┘    │
│          │ related-button-select 이벤트                                 │
│          ▼                                                               │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │  v2-table-list (품목정보)                                        │    │
│  │  - customer_code = "ABC상사" 조건으로 필터링                     │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘
```

---

### 7.7 탭 기반 테이블 필터링

#### v2-tabs-widget → v2-table-search-widget → v2-table-list

```
┌─────────────────────────────────────────────────────────────────────────┐
│                     탭 기반 테이블 필터링                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │  v2-tabs-widget                                                  │    │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐                         │    │
│  │  │ [주문]    │ │  입고    │ │  재고    │                         │    │
│  │  └──────────┘ └──────────┘ └──────────┘                         │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                              │                                           │
│                              ▼ ActiveTabContext                         │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │  v2-table-search-widget                                          │    │
│  │  (활성 탭에 해당하는 테이블만 대상으로 표시)                      │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                              │                                           │
│                              ▼ onFilterChange                           │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │  v2-table-list (주문 탭 내)                                      │    │
│  │  - parentTabId가 활성 탭과 일치하는 테이블만 필터 적용           │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘
```

---

## 8. 연동 설정 방법

### 8.1 검색 위젯 + 테이블 리스트

**필요한 컴포넌트**:
- `v2-table-search-widget`
- `v2-table-list`

**설정**:

```typescript
// v2-table-search-widget 설정
{
  filterMode: "preset",                 // 또는 "dynamic"
  presetFilters: [
    { columnName: "name", filterType: "text", columnLabel: "이름" },
    { columnName: "created_at", filterType: "date", columnLabel: "등록일" },
    { columnName: "status", filterType: "select", columnLabel: "상태" }
  ],
  targetPanelPosition: "auto"           // "left" | "right" | "auto"
}

// v2-table-list는 특별한 설정 불필요 (자동 등록)
```

---

### 8.2 분할 패널 마스터-디테일

**필요한 컴포넌트**:
- `v2-split-panel-layout`

**설정**:

```typescript
{
  leftPanel: {
    title: "부서 목록",
    tableName: "dept_info",
    displayMode: "list",
    columns: [
      { name: "dept_code", label: "부서코드" },
      { name: "dept_name", label: "부서명" }
    ]
  },
  rightPanel: {
    title: "직원 목록",
    tableName: "user_info",
    displayMode: "table",
    columns: [
      { name: "user_id", label: "사번" },
      { name: "user_name", label: "이름" },
      { name: "position", label: "직책" }
    ],
    relation: {
      type: "detail",
      leftColumn: "dept_code",
      rightColumn: "dept_code"
    }
  },
  splitRatio: 30,
  resizable: true
}
```

---

### 8.3 폼 + 리피터 저장

**필요한 컴포넌트**:
- 입력 컴포넌트들 (text-input, date-input 등)
- `v2-unified-repeater`
- `v2-button-primary`

**설정**:

```typescript
// v2-unified-repeater 설정
{
  renderMode: "inline",
  dataSource: {
    tableName: "order_detail",
    foreignKey: "order_id",           // 마스터 테이블의 FK
    referenceKey: "id"                // 마스터 테이블의 PK
  },
  columns: [
    { name: "item_code", label: "품목코드" },
    { name: "quantity", label: "수량" },
    { name: "unit_price", label: "단가" }
  ],
  features: {
    showAddButton: true,
    showDeleteButton: true,
    inlineEdit: true
  }
}

// v2-button-primary 설정
{
  text: "저장",
  action: {
    type: "save",
    saveMode: "withRepeater"
  }
}
```

---

### 8.4 데이터 전달 (테이블 → 리피터)

**필요한 컴포넌트**:
- `v2-table-list` (소스)
- `v2-button-primary` (전달 트리거)
- `v2-unified-repeater` (타겟)

**설정**:

```typescript
// v2-button-primary 설정
{
  text: "추가",
  action: {
    type: "transferData",
    config: {
      sourceComponentId: "item-selection-table",
      targetComponentId: "order-detail-repeater",
      mode: "append",
      mappingRules: [
        { sourceField: "item_code", targetField: "item_code" },
        { sourceField: "item_name", targetField: "item_name" },
        { sourceField: "unit_price", targetField: "unit_price" },
        { sourceField: "", targetField: "quantity", defaultValue: 1 }
      ],
      validation: {
        unique: ["item_code"]           // 중복 방지
      }
    }
  }
}
```

---

### 8.5 집계 위젯 연동

**필요한 컴포넌트**:
- `v2-table-list` 또는 `v2-unified-repeater`
- `v2-aggregation-widget`

**설정**:

```typescript
// v2-aggregation-widget 설정
{
  dataSourceType: "table",              // 또는 "repeater"
  // sourceComponentId는 자동 감지 (같은 화면의 첫 번째 테이블)
  items: [
    {
      id: "total-count",
      label: "총 건수",
      columnName: "id",
      aggregationType: "count",
      icon: "FileText"
    },
    {
      id: "total-amount",
      label: "총 금액",
      columnName: "amount",
      aggregationType: "sum",
      format: {
        prefix: "₩",
        thousandSeparator: true
      }
    }
  ],
  layout: "horizontal",
  refreshOnFormChange: true
}
```

---

## 연동 조합 요약표

| 소스 컴포넌트 | 타겟 컴포넌트 | 연동 방식 | 용도 |
|--------------|--------------|----------|------|
| `v2-table-search-widget` | `v2-table-list` | TableOptionsContext | 검색/필터 |
| `v2-split-panel-layout` 좌 | `v2-split-panel-layout` 우 | SplitPanelContext | 마스터-디테일 |
| `v2-button-primary` | `v2-unified-repeater` | beforeFormSave/repeaterSave | 저장 |
| `v2-table-list` | `v2-unified-repeater` | DataProvidable/DataReceivable | 데이터 전달 |
| `v2-table-list` | `v2-aggregation-widget` | tableListDataChange | 집계 |
| `v2-unified-repeater` | `v2-aggregation-widget` | repeaterDataChange | 집계 |
| `v2-tabs-widget` | `v2-table-search-widget` | ActiveTabContext | 탭 필터링 |
| `related-data-buttons` | `v2-table-list` | related-button-select | 연관 데이터 |
| `v2-button-primary` | `v2-table-list` | refreshTable | 새로고침 |
| `v2-card-display` | `v2-table-list` | SplitPanelContext | 선택 연동 |

---

## 관련 파일 참조

| 파일 | 역할 |
|------|------|
| `frontend/lib/utils/buttonActions.ts` | 버튼 액션 실행, 이벤트 발행 |
| `frontend/contexts/TableOptionsContext.tsx` | 테이블 관리 Context |
| `frontend/contexts/SplitPanelContext.tsx` | 분할 패널 Context |
| `frontend/contexts/ScreenContext.tsx` | 화면 Context |
| `frontend/contexts/ActiveTabContext.tsx` | 활성 탭 Context |
| `frontend/components/unified/UnifiedFormContext.tsx` | 폼 Context |
| `frontend/types/data-transfer.ts` | 데이터 전달 타입 |
