# InvRepeaterConfigPanel — 신규 설계 (V2 → Inv 마이그레이션)

날짜: 2026-04-28
작성자: gbpark + Claude + Codex (예정)
대상: `V2RepeaterConfigPanel.tsx` (2029줄) → `InvRepeaterConfigPanel.tsx` 재작성
이유: 사용자가 본체 디자인이 cp 표준과 어긋남을 지적 — 자체 SwitchRow + shadcn 잔존 (Popover/Command/Collapsible/Checkbox)

진실의 원천 우선순위 (cp-panel-standard.md §12):
1. cp 패널 표준 (`2026-04-28-cp-panel-standard.md`)
2. **V2FieldConfigPanel.tsx + V2PropertiesPanel.tsx (Reference Implementation)** ← 이게 살아있는 본체 패턴
3. CPPrimitives.tsx + CPChrome.tsx + cp.css

---

## 1. 현재 V2RepeaterConfigPanel 옵션 인벤토리

### 1.1 모드 축
- `render_mode`: `inline` (직접입력) / `modal` (엔티티검색) / `button` (미구현)

### 1.2 cp 톤 이미 적용된 섹션
- **CPSection "① 데이터 소속"** (L800~877)
  - 저장 테이블 (CPSelect)
  - FK 컬럼 / PK 컬럼 (CPText, 조건부)
- **CPSection "② 입력 모드"** (L880~975)
  - 입력방식 (CPSegment: inline/modal/button)
  - 모달일 때: 검색 엔티티(CPSelect) + 모달제목 + 검색버튼 텍스트

### 1.3 cp 표준 미준수 (사용자가 "이전이랑 느낌 비슷" 지적)
- **CPGroup "기능 옵션 6개"** (L977~1016)
  - SwitchRow 자체 컴포넌트 — cp 표준은 `CPRow + CPSwitch`
  - 항목: show_add_button / show_delete_button / inline_edit / multi_select / show_row_number / selectable
- **CPGroup "고급 설정"** (L1018~1142)
  - shadcn Popover / Command / Input 잔존
  - 소스 디테일 자동 조회 (table_name / foreign_key / parent_key)
- **CPGroup "컬럼"** (L1144~)
  - shadcn Collapsible / Checkbox / Badge / Button / GripVertical 잔존
  - 입력 컬럼 토글 / 소스 컬럼 토글 / Entity 조인 / 선택된 컬럼 드래그 / 자동입력(autoFill)

### 1.4 자동입력 (auto_fill) 5종
- `none` / `numbering` (채번 규칙) / `fromMainForm` (메인 폼 값) / `fixed` (고정값) / `parentSequence` (부모 순번)

### 1.5 계산 규칙 (modal 전용)
- `calculation_rules[]` — formula / target_column / label

### 1.6 Entity 조인
- `entity_joins[]` — source_column / reference_table / columns[{ reference_field, display_field }]

### 1.7 모달 sub-config
- `modal { size, title, button_text, search_fields[], source_display_columns[], screen_id, title_template }`

---

## 2. V2FieldConfigPanel (입력폼) 패턴 — 따라야 할 reference

```
<CPCrumb /> ← 정체성 (kind ▸ type)

<div padding=12>
  ① CPSection "① 데이터 소속" (always)
     CPRow label="역할"  → CPSegment
     CPRow label="테이블" → CPSelect/DimText
     CPRow label="컬럼"   → CPSelect/DimText

  ② CPSection "② 유형별 설정" (always)
     {showFormatTrigger && <CPFormatTrigger formats=... value=... onChange=... />}
     <FormatBody kind=... type=... format=... ... />  ← 디스패처

  ③ CPSection "③ 데이터 필터" (조건부 — kind===choice && format ∈ {code,entity,status})

  ▾ CPGroup "고급 설정" defaultOpen=false (kind!==auto)
</div>
```

### 분류 체계
```ts
type Kind = "input" | "choice" | "auto" | "attach";  // 4
type Type = ...;                                       // 10
const KINDS: { id: Kind; name; icon }[] = [...];
const TYPES_BY_KIND: Record<Kind, CPCrumbType[]> = {...};
const FORMATS_BY_TYPE: Record<Type, CPFormatItem[]> = {...};
const KIND_OF_TYPE: Record<Type, Kind> = {...};
```

### resolver/writer
- `resolveTriple(config, componentType, metaInputType) → { kind, type, format }` — legacy config 로딩
- `applyTriple(prev, kind, type, format, ctx) → 새 config` — brumb 변경 시 정합성 보장

### FormatBody 디스패처
- `(kind, type, format)` 별로 옵션 컴포넌트 라우팅
- 11개 옵션 컴포넌트 (TextOptions / NumberOptions / MoneyOptions / DateOptions / SelectOptions / CategoryOptions / EntityOptions / StatusOptions / BooleanOptions / TagsOptions / FileOptions / FormulaOptions / AuditOptions / NumberingOptions)

---

## 3. 리피터에 매핑 (1차 안 — Codex 검증 대상)

### 3.1 분류 체계 후보

```ts
type RepKind = "repeater";  // 1개 (리피터 단일)
type RepType = "inline" | "modal" | "button" | "import";  // 4개?
                                                            // (현재 inline/modal/button)
                                                            // (import = CSV/엑셀 업로드 — 추가 후보)

const FORMATS_BY_TYPE: Record<RepType, ...> = {
  inline: [
    "flat",       // 평면 행 (기본)
    "grouped",    // 컬럼별 그룹
  ],
  modal: [
    "pick-one",   // 한 행씩 추가 (현재)
    "pick-many",  // 모달에서 다중 선택
    "auto-fill",  // 마스터 선택 → 자식 자동 펼침 (source_detail_config)
  ],
  button: [
    "external",   // 외부 화면 이동
  ],
  import: [
    "csv",        // CSV 업로드
    "excel",      // 엑셀 업로드
  ],
};
```

### 3.2 4-section 흐름 매핑

```
<CPCrumb kind="리피터" type="모달 선택" format="다건 추가" />

① CPSection "① 데이터 소속" (always)
   CPRow "저장 테이블"  → CPSelect (currentTable / relatedTables / allTables)
   CPRow "FK 컬럼"      → CPText (조건부)
   CPRow "PK 컬럼"      → CPText (조건부)

② CPSection "② 유형별 설정" (always)
   CPFormatTrigger (flat/grouped/pick-one/pick-many/...)
   <RepeaterFormatBody>
     - inline.flat:    컬럼 토글 + 자동입력
     - inline.grouped: + 그룹 컬럼 선택
     - modal.pick-one: 검색 엔티티 + 모달 제목 + 검색버튼 + 컬럼매핑
     - modal.pick-many: + 중복 허용 / 결과 표시
     - modal.auto-fill: + 소스 디테일 (table/fk/parent_key)
     - button.external: 화면 ID + 파라미터
     - import.csv/excel: 헤더 행 / 컬럼 매핑

③ CPSection "③ 데이터 필터" (modal 모드일 때만)
   - 검색 엔티티 옵션을 불러올 때 적용할 WHERE 조건

▾ CPGroup "행 동작" (default open)
   기본 6 + 추가 후보:
   ┌─ 행 추가/삭제 (CPRow + CPSwitch)
   ├─ 행 복제 (NEW)
   ├─ 행 정렬 드래그 (NEW)
   ├─ 행 잠금 (NEW)
   └─ 다중 선택

▾ CPGroup "편집" (default open)
   ├─ 인라인 편집
   ├─ 실시간 검증 (NEW)
   ├─ 키보드 네비 (NEW)
   └─ 자동 저장 (NEW)

▾ CPGroup "표시" (default closed)
   ├─ 행 번호
   ├─ 합계 행 (NEW)
   ├─ 헤더 고정 (NEW)
   └─ 페이지네이션 (NEW)

▾ CPGroup "컬럼 구성" (default closed)
   - 입력 컬럼 토글 + 소스 표시 컬럼 + Entity 조인 + 드래그 정렬
   - 선택된 컬럼 펼침 → 자동입력(채번/parent/fixed) 설정

▾ CPGroup "계산 규칙" (default closed, modal 일 때만)
   - formula / target_column / label
   - 컬럼명 삽입 토큰 + Korean 미리보기

▾ CPGroup "도구" (default closed)
   ├─ CSV 내보내기 (NEW)
   └─ 행 선택 체크박스
```

### 3.3 추가 기능 후보 (각 역할)

| 후보 | 역할 | 우선 |
|---|---|---|
| drag_sort (행 드래그) | 사용자가 행 순서 조정 (현재 컬럼만 드래그) | 高 |
| duplicate_row (행 복제) | 같은 품목 다른 수량 등 빠른 입력 | 高 |
| inline_validation (실시간 검증) | 필수/패턴/범위 셀 단위 즉시 표시 | 高 |
| footer_summary (합계 행) | 숫자 컬럼 자동 SUM/AVG | 中 |
| keyboard_nav | Enter=다음행, Tab=다음셀 | 中 |
| auto_save (셀 변경 즉시 POST) | 수기저장 버튼 없이 | 中 |
| pagination | 100행 넘을 때 | 中 |
| sticky_header | 스크롤 시 헤더 고정 | 中 |
| row_lock | 저장된 행 편집 불가 (감사 용) | 低 |
| export_csv | 우상단 ⤓ → CSV | 低 |
| import csv/excel (type 자체) | 파일 업로드로 일괄 입력 | 低 (별도 type 으로 빼는 게 나을 수도) |

---

## 4. 이름/파일 변경

| 현재 | 신규 |
|---|---|
| `frontend/components/v2/config-panels/V2RepeaterConfigPanel.tsx` | `frontend/components/v2/config-panels/InvRepeaterConfigPanel.tsx` |
| `V2RepeaterConfigPanel` (export) | `InvRepeaterConfigPanel` |
| `V2RepeaterConfigPanelProps` | `InvRepeaterConfigPanelProps` |

### 호출처 갱신
- `frontend/components/v2/config-panels/InvDataConfigPanel.tsx:23` — import 경로
- `frontend/components/v2/config-panels/InvDataConfigPanel.tsx:158-167` — 컴포넌트 호출
- `frontend/components/v2/registerV2Components.ts` — 직접 사용 시
- `frontend/lib/utils/getComponentConfigPanel.tsx` — 직접 매핑 시
- `frontend/lib/registry/components/v2-repeater/index.ts` — 직접 사용 시
- 기타 `grep -rn "V2RepeaterConfigPanel" frontend/` 0건 검증

---

## 5. Codex 검토 요청 항목

1. §3.1 분류 체계 (kind 1 / type 4 / format 다양) — 적절? type=import 빠뜨릴까?
2. §3.2 4-section 흐름 — 입력폼 패턴 맞게 매핑? CPGroup 개수 너무 많지 않은가?
3. §3.3 추가 기능 우선순위 — 빠진 게 있는가? 高/中/低 분류 적절?
4. config 스키마 호환 — 기존 `V2RepeaterConfig` 키 (`render_mode`, `features.{...}`, `columns[]`, `auto_fill`, `modal{}`, `data_source{}`, `column_mappings[]`, `calculation_rules[]`, `entity_joins[]`, `source_detail_config`) 어떻게 새 (kind/type/format/features.*) 로 mapping?
5. resolver / writer 패턴 V2FieldConfigPanel 처럼 둘지, 더 단순화?

---

## 6. 작업 순서 (Codex 컨펌 후)

1. Codex 의 분류 체계 / 추가 기능 / section 흐름 컨펌
2. `InvRepeaterConfigPanel.tsx` 신규 작성 (전부 cp 프리미티브)
3. `InvDataConfigPanel.tsx` 의 호출 경로 갱신
4. `V2RepeaterConfigPanel.tsx` 삭제
5. 검증
   - `grep -rn "V2RepeaterConfigPanel" frontend/` → 0건
   - `grep -E "from.*['\"]@/components/ui/(select|input|switch|collapsible|popover|command|checkbox|badge)['\"]" InvRepeaterConfigPanel.tsx` → 0건
   - `npx tsc --noEmit | grep InvRepeater` → 새 에러 0건
   - 브라우저: 좌측 "데이터 조회/선택" 클릭 → brumb 입력/리피터 → 본체 cp 톤
