# 품목정보 (Item Info)

> Screen ID: /screens/140
> 메뉴 경로: 기준정보 > 품목정보
> 테이블: `item_info`

---

## ⚠️ 문서 사용 안내


> 
> ### 📌 중요: JSON 데이터는 참고용입니다!
> 
> 이 문서에 포함된 JSON 설정(레이아웃, 컴포넌트 구성 등)은 **품목정보 화면에 특화된 예시**입니다.
> 
> **다른 화면을 구현할 때:**
> 1. 이 JSON을 그대로 복사해서 사용하지 마세요
> 2. 해당 화면의 **테이블 구조를 먼저 분석**하세요
> 3. 화면의 **요구사항과 기능을 파악**하세요
> 4. 분석 결과에 맞는 **새로운 JSON 구조를 작성**하세요
> 
> ### 참고해야 할 항목
> - ✅ 문서 구조 및 작성 형식
> - ✅ V2 컴포넌트 종류 및 사용법
> - ✅ API 호출 방식 및 DB INSERT 절차
> - ✅ 컴포넌트 설정 패턴 (position, size, overrides 구조)
> 
> ### 복사하면 안 되는 항목
> - ❌ 테이블명 (`item_info` → 해당 화면의 테이블로 변경)
> - ❌ 컬럼 설정 (해당 테이블의 컬럼에 맞게 작성)
> - ❌ 필드명 (`fieldName`, `columnName` 등)
> - ❌ 화면명, screen_code, company_code
> - ❌ screen_id, targetScreenId (동적 생성되는 값)
> 
> ### 🚨 컴포넌트 부족 시 필수 명시 사항
> 
> 화면 분석 결과, **현재 V2 컴포넌트로 구현이 불가능한 기능**이 있을 경우:
> 
> 1. 문서에 **"구현 불가 항목"** 섹션을 반드시 추가
> 2. 다음 형식으로 명시:
> 
> ```markdown
> ## 🚫 구현 불가 항목 (컴포넌트 개발 필요)
> 
> | 기능 | 필요한 컴포넌트 | 현재 상태 | 비고 |
> |------|-----------------|-----------|------|
> | 트리 구조 표시 | v2-tree-view | 미구현 | 계층형 데이터 표시 필요 |
> | 드래그 앤 드롭 | v2-drag-drop | 미구현 | 순서 변경 기능 |
> ```
> 
> 3. 컴포넌트 개발 **우선순위/중요도** 명시

## 1. 테이블 선택 및 화면 구조

### 1.1 사용 테이블

| 테이블명 | 용도 | 비고 |
|----------|------|------|
| `item_info` | 품목 기본정보 | 주 테이블 |

### 1.2 테이블 컬럼 정의 (실제 DB 기준)

| 컬럼명 | 표시명 | 타입 | 필수 | 설명 |
|--------|--------|------|------|------|
| `id` | ID | varchar(500) | PK | UUID 자동 생성 |
| `item_number` | 품번코드 | varchar(500) | | 품목 고유 코드 |
| `item_name` | 품명 | varchar(500) | | 품목명 |
| `status` | 상태 | varchar(500) | | 정상, 품절, 대기, 단종 |
| `size` | 규격 | varchar(500) | | 규격 정보 |
| `material` | 재질 | varchar(500) | | 재질 정보 |
| `inventory_unit` | 재고단위 | varchar(500) | | EA, kg, L, Sheet, Box |
| `weight` | 중량 | varchar(500) | | 중량 값 |
| `unit` | 단위 | varchar(500) | | g, kg, kg/L, t |
| `image` | 이미지 | varchar(500) | | 품목 이미지 경로 |
| `division` | 구분 | varchar(500) | | 원자재, 중간재, 완제품, 포장재 (카테고리 코드) |
| `type` | 유형 | varchar(500) | | 용도별 유형 |
| `meno` | 메모 | varchar(500) | | 비고 (오타: memo) |
| `selling_price` | 판매가 | varchar(500) | | 기본값 '0' |
| `standard_price` | 기준가 | varchar(500) | | 기본값 '0' |
| `currency_code` | 통화코드 | varchar(500) | | 기본값 'KRW' |
| `writer` | 등록자 | varchar(500) | | 작성자 ID |
| `company_code` | 회사코드 | varchar(500) | | 멀티테넌시 |
| `created_date` | 등록일 | timestamp | | 자동 생성 |
| `updated_date` | 수정일 | timestamp | | 자동 갱신 |

### 1.3 화면 구조 개요

- **화면 유형**: 목록형 (단일 테이블 CRUD)
- **주요 기능**: 
  - 품목 조회/검색/필터링
  - 품목 등록/수정/삭제
  - 그룹핑 (Group By)
  - 코드 변경/합병
  - 엑셀 업로드
  - 컬럼 표시/숨기기 설정

---

## 2. 컴포넌트 배치도

### 2.1 전체 레이아웃

```
┌─────────────────────────────────────────────────────────────────────────────┐
│ [검색 영역]                                                                 │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ v2-table-search-widget                                                  │ │
│ │ ┌───────────┐ ┌───────────────┐ ┌───────────────┐ ┌─────────┐          │ │
│ │ │ 상태      │ │ 품번코드      │ │ 품명          │ │ [검색]  │          │ │
│ │ │ (select)  │ │ (text)        │ │ (text)        │ │         │          │ │
│ │ └───────────┘ └───────────────┘ └───────────────┘ └─────────┘          │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────────────┤
│ [테이블 헤더 + 액션 버튼]                                                   │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ [코드변경][업로드][다운로드]                   [등록][복사][수정][삭제]  │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────────────┤
│ [데이터 테이블]                                                             │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ v2-table-list                                                           │ │
│ │ ┌──┬────┬────────┬────────┬──────┬──────┬────────┬─────┬─────┬────────┐ │ │
│ │ │☐ │상태│품번코드│품명    │규격  │재질  │재고단위│중량 │단위 │구분    │ │ │
│ │ ├──┼────┼────────┼────────┼──────┼──────┼────────┼─────┼─────┼────────┤ │ │
│ │ │☐ │정상│R_001   │테스트A │100mm │SUS304│EA      │1.5  │kg   │원자재  │ │ │
│ │ │☐ │대기│R_002   │테스트B │200mm │AL    │kg      │2.0  │kg   │완제품  │ │ │
│ │ └──┴────┴────────┴────────┴──────┴──────┴────────┴─────┴─────┴────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
```

### 2.2 사용 가능한 V2 컴포넌트 목록

> 📌 **V2 컴포넌트 전체 목록** - 화면 구성 시 사용 가능한 컴포넌트

| 컴포넌트 ID | 설명 | 카테고리 |
|-------------|------|----------|
| `v2-input` | 텍스트, 숫자, 비밀번호, 이메일 등 입력 | 입력 |
| `v2-select` | 드롭다운, 콤보박스, 라디오, 체크박스 | 입력 |
| `v2-date` | 날짜/시간 입력 | 입력 |
| `v2-button-primary` | 버튼 | 액션 |
| `v2-table-list` | 테이블 리스트 (CRUD) | 테이블 |
| `v2-table-search-widget` | 테이블 검색/필터 위젯 | 유틸리티 |
| `v2-pivot-grid` | 피벗 그리드 (다차원 분석) | 테이블 |
| `v2-aggregation-widget` | 집계 위젯 | 위젯 |
| `v2-text-display` | 텍스트 표시 (읽기 전용) | 표시 |
| `v2-card-display` | 카드 표시 | 표시 |
| `v2-divider-line` | 구분선 | 레이아웃 |
| `v2-section-card` | 섹션 카드 (그룹핑) | 레이아웃 |
| `v2-section-paper` | 섹션 페이퍼 (그룹핑) | 레이아웃 |
| `v2-split-panel-layout` | 분할 패널 레이아웃 | 레이아웃 |
| `v2-repeat-container` | 반복 컨테이너 | 레이아웃 |
| `v2-repeater` | 리피터 (동적 행) | 레이아웃 |
| `v2-category-manager` | 카테고리 관리 | 특수 |
| `v2-numbering-rule` | 채번규칙 | 특수 |
| `v2-media` | 미디어 (이미지/영상) | 미디어 |
| `v2-rack-structure` | 랙 구조 (창고) | 특수 |
| `v2-location-swap-selector` | 위치 스왑 선택기 | 특수 |

### 2.3 이 화면에서 사용하는 컴포넌트

| 컴포넌트 타입 | 역할 |
|---------------|------|
| `v2-table-search-widget` | 검색 필터 |
| `v2-table-list` | 품목 데이터 테이블 |
| `v2-button-primary` | 코드변경 |
| `v2-button-primary` | 업로드 (엑셀) |
| `v2-button-primary` | 다운로드 (엑셀) |
| `v2-button-primary` | 등록 (모달 열기) |
| `v2-button-primary` | 복사 (모달 열기) |
| `v2-button-primary` | 수정 (모달 열기) |
| `v2-button-primary` | 삭제 |
| `v2-input` | 모달 - 텍스트 입력 필드 |
| `v2-select` | 모달 - 선택 필드 |

---

## 3. 화면 디자이너 설정 가이드

### 3.1 v2-table-search-widget (검색 필터) 설정

1. 좌측 컴포넌트 패널에서 `v2-table-search-widget` 드래그하여 화면 상단에 배치
2. 대상 테이블로 아래에 배치할 테이블 리스트 선택

> 💡 **참고**: 검색 필터는 사용자가 런타임에서 원하는 필드를 직접 추가/삭제하여 사용할 수 있습니다. 별도의 필드 설정이 필요 없습니다.

---

### 3.2 v2-table-list (품목 테이블) 설정

#### Step 1: 컴포넌트 추가
1. 좌측 컴포넌트 패널에서 `v2-table-list` 드래그하여 검색 필터 아래에 배치

#### Step 2: 데이터 소스 설정

| 설정 항목 | 설정 값 |
|-----------|---------|
| 테이블 선택 | `item_info` |
| 자동 컬럼 생성 | ✅ 체크 (테이블 컬럼 자동 로드) |

#### Step 3: 컬럼 설정

**[컬럼 설정]** 패널에서 표시할 컬럼 선택 및 순서 조정:

| 순서 | 컬럼 | 표시명 | 너비 | 정렬 | 표시 | 특수 설정 |
|------|------|--------|------|------|------|-----------|
| 1 | `status` | 상태 | 80 | 중앙 | ✅ | 뱃지 스타일 (색상별) |
| 2 | `item_number` | 품번코드 | 140 | 좌측 | ✅ | |
| 3 | `item_name` | 품명 | 200 | 좌측 | ✅ | 굵게 표시 |
| 4 | `size` | 규격 | 150 | 좌측 | ✅ | |
| 5 | `material` | 재질 | 150 | 좌측 | ✅ | |
| 6 | `inventory_unit` | 재고단위 | 100 | 중앙 | ✅ | |
| 7 | `weight` | 중량 | 80 | 우측 | ✅ | |
| 8 | `unit` | 단위 | 80 | 중앙 | ✅ | |
| 9 | `image` | 이미지 | 80 | 중앙 | ✅ | 이미지 미리보기 |
| 10 | `division` | 구분 | 100 | 중앙 | ✅ | 카테고리 표시 |
| 11 | `type` | 유형 | 100 | 중앙 | ✅ | |
| 12 | `selling_price` | 판매가 | 100 | 우측 | ☐ | 숫자 포맷 |
| 13 | `standard_price` | 기준가 | 100 | 우측 | ☐ | 숫자 포맷 |
| 14 | `meno` | 메모 | 180 | 좌측 | ☐ | |
| 15 | `writer` | 등록자 | 100 | 좌측 | ☐ | 읽기 전용 |
| 16 | `created_date` | 등록일 | 120 | 중앙 | ☐ | 읽기 전용 |
| 17 | `updated_date` | 수정일 | 120 | 중앙 | ☐ | 읽기 전용 |

#### Step 4: 기능 설정

| 설정 항목 | 설정 값 | 설명 |
|-----------|---------|------|
| 체크박스 | ✅ 사용 | 다중 선택 활성화 |
| 페이지네이션 | ✅ 사용 | |
| 페이지 크기 | 20 | 기본 표시 행 수 |
| 정렬 | ✅ 사용 | 컬럼 헤더 클릭 정렬 |
| 컬럼 리사이즈 | ✅ 사용 | 컬럼 너비 조정 |
| 그룹핑 | ✅ 사용 | Group By 기능 |

#### Step 5: 그룹핑 옵션 설정

Group By 드롭다운에 표시할 컬럼 선택:
- ✅ `status` (상태)
- ✅ `division` (구분)
- ✅ `type` (유형)
- ✅ `inventory_unit` (재고단위)
- ✅ `writer` (등록자)

---

### 3.3 버튼 설정

#### 좌측 버튼 그룹

##### 코드변경 버튼

| 설정 항목 | 설정 값 |
|-----------|---------|
| 라벨 | `코드변경` |
| 액션 타입 | `code_merge` |
| 스타일 | `secondary` |
| 선택 필수 | ✅ 체크 (복수 선택) |
| 병합 대상 컬럼 | `item_number` |
| 데이터플로우 연결 | 품번코드 통합 (flow_id: 18) |

##### 업로드 버튼

| 설정 항목 | 설정 값 |
|-----------|---------|
| 라벨 | `업로드` |
| 액션 타입 | `excel_upload` |
| 스타일 | `secondary` |
| 대상 테이블 | `item_info` |

##### 다운로드 버튼

| 설정 항목 | 설정 값 |
|-----------|---------|
| 라벨 | `다운로드` |
| 액션 타입 | `excel_download` |
| 스타일 | `secondary` |
| 대상 | 현재 테이블 리스트 |

#### 우측 버튼 그룹

##### 등록 버튼

| 설정 항목 | 설정 값 |
|-----------|---------|
| 라벨 | `등록` |
| 액션 타입 | `modal` |
| 스타일 | `default` |
| 연결 화면 | 품목 등록/수정 화면 (아래 3.4 참조) |
| 모달 제목 | 품목 등록 |
| 모달 사이즈 | `md` |

##### 복사 버튼

| 설정 항목 | 설정 값 |
|-----------|---------|
| 라벨 | `복사` |
| 액션 타입 | `copy` |
| 스타일 | `default` |
| 선택 필수 | ✅ 체크 (1개만) |
| 연결 화면 | 품목 등록/수정 화면 (아래 3.4 참조) |
| 동작 | 선택된 데이터를 복사하여 신규 등록 폼에 채움 |

##### 수정 버튼

| 설정 항목 | 설정 값 |
|-----------|---------|
| 라벨 | `수정` |
| 액션 타입 | `edit` |
| 스타일 | `default` |
| 선택 필수 | ✅ 체크 (1개만) |
| 연결 화면 | 품목 등록/수정 화면 (아래 3.4 참조) |
| 동작 | 선택된 데이터 수정 모드로 폼 열기 |

##### 삭제 버튼

| 설정 항목 | 설정 값 |
|-----------|---------|
| 라벨 | `삭제` |
| 액션 타입 | `delete` |
| 스타일 | `default` |
| 선택 필수 | ✅ 체크 (복수 선택 가능) |
| 확인 메시지 | 선택한 품목을 삭제하시겠습니까? |
| 삭제 후 동작 | 테이블 새로고침 |

---

### 3.4 품목 등록/수정 화면 (모달용 화면)

> 📌 **별도 화면 생성 필요**: 등록/복사/수정 버튼에 연결할 모달 화면을 새로 생성합니다.
> 
> 💡 **동일 화면 공유**: 등록, 복사, 수정 버튼 모두 동일한 폼 화면을 사용합니다.
> - **등록**: 빈 폼으로 열림
> - **복사**: 선택된 데이터가 채워진 상태로 열림 (신규 등록)
> - **수정**: 선택된 데이터가 채워진 상태로 열림 (기존 데이터 업데이트)

#### Step 1: 새 화면 생성

1. 화면 관리에서 **[+ 새 화면]** 클릭
2. 화면 정보 입력:
   - 화면명: `품목 등록/수정`
   - 테이블: `item_info`
   - 화면 유형: `모달`

#### Step 2: 폼 필드 배치

**모달 레이아웃 배치도**:

```
┌─────────────────────────────────────────────────────────────┐
│ 품목 등록/수정                                         [✕] │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────────────────┐ ┌─────────────────────────┐   │
│  │ 품번코드 *              │ │ 품명 *                  │   │
│  │ [____________________]  │ │ [____________________]  │   │
│  └─────────────────────────┘ └─────────────────────────┘   │
│                                                             │
│  ┌─────────────────────────┐ ┌─────────────────────────┐   │
│  │ 규격                    │ │ 재질                    │   │
│  │ [____________________]  │ │ [____________________]  │   │
│  └─────────────────────────┘ └─────────────────────────┘   │
│                                                             │
│  ┌─────────────────────────┐ ┌───────────┐ ┌───────────┐   │
│  │ 재고단위 *              │ │ 중량      │ │ 중량단위  │   │
│  │ [EA           ▼]       │ │ [_______] │ │ [kg   ▼]  │   │
│  └─────────────────────────┘ └───────────┘ └───────────┘   │
│                                                             │
│  ┌─────────────────────────┐ ┌─────────────────────────┐   │
│  │ 구분 *                  │ │ 유형                    │   │
│  │ [원자재         ▼]     │ │ [반도체용       ▼]     │   │
│  └─────────────────────────┘ └─────────────────────────┘   │
│                                                             │
│  ┌─────────────────────────┐ ┌─────────────────────────┐   │
│  │ 판매가                  │ │ 기준가                  │   │
│  │ [____________________]  │ │ [____________________]  │   │
│  └─────────────────────────┘ └─────────────────────────┘   │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 메모                                                │   │
│  │ [__________________________________________________]│   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ┌─────────────────────────┐                               │
│  │ 상태 *                  │                               │
│  │ [정상           ▼]     │                               │
│  └─────────────────────────┘                               │
│                                                             │
├─────────────────────────────────────────────────────────────┤
│                              [취소]  [💾 저장]              │
└─────────────────────────────────────────────────────────────┘
```

**필드 목록**:

| 순서 | 필드 (컬럼명) | 라벨 | 입력 타입 | 필수 | 비고 |
|------|---------------|------|-----------|------|------|
| 1 | `item_number` | 품번코드 | text | ✅ | |
| 2 | `item_name` | 품명 | text | ✅ | |
| 3 | `size` | 규격 | text | | |
| 4 | `material` | 재질 | text | | |
| 5 | `inventory_unit` | 재고단위 | select | ✅ | 옵션: EA, kg, L, Sheet, Box |
| 6 | `weight` | 중량 | number | | |
| 7 | `unit` | 중량단위 | select | | 옵션: g, kg, kg/L, t |
| 8 | `division` | 구분 | category | ✅ | 품목 구분 카테고리 |
| 9 | `type` | 유형 | select | | 옵션: 반도체용, 태양광용, 산업용, 의료용, 건축용, 사출용, 화장품용 |
| 10 | `selling_price` | 판매가 | number | | |
| 11 | `standard_price` | 기준가 | number | | |
| 12 | `meno` | 메모 | text | | |
| 13 | `status` | 상태 | select | ✅ | 옵션: 정상, 품절, 대기, 단종 |

#### Step 3: 버튼 배치

| 버튼 | 액션 타입 | 스타일 | 설정 |
|------|-----------|--------|------|
| 저장 | `저장` | primary | 저장 후 모달 닫기, 부모 화면 테이블 새로고침 |
| 취소 | `모달 닫기` | secondary | |

#### Step 4: 버튼에 화면 연결

1. 메인 화면(품목정보)으로 돌아가기
2. **등록 버튼** 선택 → 설정 패널에서:
   - 액션 타입: `modal`
   - 연결 화면: `품목 등록/수정` 선택
   - 모달 제목: `품목 등록`
3. **복사 버튼** 선택 → 설정 패널에서:
   - 액션 타입: `copy`
   - 연결 화면: `품목 등록/수정` 선택
   - 선택 필수: ✅ 체크
   - 동작: 선택된 데이터를 복사하여 폼에 채움 (신규 등록)
4. **수정 버튼** 선택 → 설정 패널에서:
   - 액션 타입: `edit`
   - 연결 화면: `품목 등록/수정` 선택
   - 선택 필수: ✅ 체크
   - 동작: 선택된 데이터를 수정 모드로 폼에 채움

> 💡 **참고**: 컬럼별 스타일(뱃지 색상, 카테고리 표시 등)은 컴포넌트 기본 스타일을 따릅니다. 필요시 테이블 관리에서 컬럼별 상세 설정을 조정할 수 있습니다.

---

## 4. 컴포넌트 연동 설정

### 4.1 이벤트 흐름

```
[검색 입력]
    │
    ▼
v2-table-search-widget
    │ onFilterChange
    ▼
v2-table-list (자동 재조회)
    │
    ▼
[데이터 표시]


[등록/복사/수정 버튼 클릭]
    │
    ▼
[모달 열기] → [폼 입력] → [저장]
    │                        │
    │                        ▼
    │                   refreshTable 이벤트
    │                        │
    └────────────────────────┘
                             │
                             ▼
                    v2-table-list (재조회)
```

### 4.2 연동 설정

| 소스 컴포넌트 | 이벤트/액션 | 대상 컴포넌트 | 동작 |
|---------------|-------------|---------------|------|
| 검색 위젯 | onFilterChange | 테이블 리스트 | 필터 적용, 재조회 |
| 등록 버튼 | click | 모달 | 빈 폼으로 모달 열기 |
| 복사 버튼 | click | 모달 | 선택 데이터가 채워진 폼 열기 (신규) |
| 수정 버튼 | click | 모달 | 선택 데이터가 채워진 폼 열기 (수정) |
| 삭제 버튼 | click | 테이블 리스트 | 선택 항목 삭제 |
| 모달 저장 | afterSave | 테이블 리스트 | refreshTable |

### 4.3 TableOptionsContext 연동

```
v2-table-search-widget ──── TableOptionsContext ──── v2-table-list
        │                           │                      │
        │ registeredTables에서      │                      │
        │ item-table 참조           │                      │
        │                           │                      │
        └── onFilterChange() ───────┼──────────────────────┘
                                    │
                                    ▼
                            필터 조건 전달 & 재조회
```

---

## 5. 사용자 사용 예시 시나리오

### 시나리오 1: 품목 조회

| 단계 | 사용자 동작 | 기대 결과 |
|------|-------------|-----------|
| 1 | 화면 진입 | 전체 품목 목록 표시 |
| 2 | 상태 필터를 "정상"으로 선택 | 자동 필터링 |
| 3 | 품명에 "폴리머" 입력 후 검색 | 품명에 "폴리머" 포함된 품목 표시 |
| 4 | Group by에서 "구분" 선택 | division별 그룹핑 |

### 시나리오 2: 품목 등록

| 단계 | 사용자 동작 | 기대 결과 |
|------|-------------|-----------|
| 1 | [등록] 버튼 클릭 | 빈 폼 모달 표시 |
| 2 | 데이터 입력 (품번코드, 품명, 규격 등) | 입력 필드 채움 |
| 3 | [저장] 버튼 클릭 | 저장 완료, 모달 닫힘, 목록 갱신 |

### 시나리오 3: 품목 복사

| 단계 | 사용자 동작 | 기대 결과 |
|------|-------------|-----------|
| 1 | 테이블에서 복사할 행 체크박스 선택 | 행 선택 표시 |
| 2 | [복사] 버튼 클릭 | 선택된 데이터가 채워진 폼 모달 표시 |
| 3 | 필요시 데이터 수정 (품번코드 등) | 필드 값 변경 |
| 4 | [저장] 버튼 클릭 | 신규 등록 완료, 목록 갱신 |

### 시나리오 4: 품목 수정

| 단계 | 사용자 동작 | 기대 결과 |
|------|-------------|-----------|
| 1 | 테이블에서 행 체크박스 선택 | 행 선택 표시 |
| 2 | [수정] 버튼 클릭 | 수정 모달 표시 (기존 데이터 로드) |
| 3 | 데이터 수정 | 필드 값 변경 |
| 4 | [저장] 버튼 클릭 | 저장 완료, 목록 갱신 |

### 시나리오 5: 품목 삭제

| 단계 | 사용자 동작 | 기대 결과 |
|------|-------------|-----------|
| 1 | 삭제할 행 체크박스 선택 (다중 가능) | 행 선택 표시 |
| 2 | [삭제] 버튼 클릭 | 삭제 확인 다이얼로그 표시 |
| 3 | 확인 | 삭제 완료, 목록 갱신 |

---

## 6. 검증 체크리스트

### 기본 기능
- [ ] 데이터 조회가 정상 동작하는가?
- [ ] 검색 필터 (상태, 품번코드, 품명)가 정상 동작하는가?
- [ ] 신규 등록이 정상 동작하는가?
- [ ] 복사 기능이 정상 동작하는가?
- [ ] 수정이 정상 동작하는가?
- [ ] 삭제가 정상 동작하는가?
- [ ] 코드변경이 정상 동작하는가?
- [ ] 엑셀 업로드가 정상 동작하는가?
- [ ] 엑셀 다운로드가 정상 동작하는가?

### 테이블 기능
- [ ] 페이지네이션이 정상 동작하는가?
- [ ] 정렬이 정상 동작하는가?
- [ ] 컬럼 너비 조정이 정상 동작하는가?
- [ ] 체크박스 선택이 정상 동작하는가?

### 검색 위젯 연동
- [ ] v2-table-search-widget과 v2-table-list 연동이 정상 동작하는가?
- [ ] 필터 변경 시 자동 재조회가 동작하는가?
- [ ] 초기화 버튼이 정상 동작하는가?

### 그룹핑 기능
- [ ] Group by 선택 시 그룹핑이 정상 동작하는가?
- [ ] 다중 그룹핑이 정상 동작하는가?

---

## 7. 참고 사항

### 관련 테이블
- `customer_item_mapping` - 거래처별 품목 매핑
- `supplier_item_mapping` - 공급업체별 품목 매핑
- `item_inspection_info` - 품목 검사 정보
- `item_routing_version` - 품목별 공정 버전
- `item_routing_detail` - 품목별 공정 상세

### 특이 사항
- `division` 컬럼은 카테고리 코드 (예: CATEGORY_191259)로 저장됨
- `meno` 컬럼은 오타로 보임 (원래 memo)
- `selling_price`, `standard_price`는 varchar로 저장됨 (숫자 형식 문자열)
- `company_code`는 멀티테넌시용 회사 코드

---

## 8. DB INSERT용 JSON 설정 (screen_layouts_v2 방식)

> 📌 실제 화면 저장은 `screen_definitions` + `screen_layouts_v2` 테이블을 사용합니다.
> `screen_layouts_v2`는 전체 레이아웃을 하나의 JSON (`layout_data`)으로 저장합니다.

> ⚠️ **주의: 아래 JSON은 "품목정보" 화면 전용 예시입니다!**
> 
> 다른 화면 구현 시:
> 1. **테이블 분석 필수** - 해당 화면이 사용하는 테이블 구조 파악
> 2. **컬럼 재정의** - `columns`, `fieldName` 등을 해당 테이블에 맞게 작성
> 3. **기능 요구사항 반영** - 버튼, 모달, 액션 등을 화면 요구사항에 맞게 구성
> 4. **ID 값 동적 처리** - `screen_id`, `targetScreenId`는 생성 시 할당되는 값 사용

### 8.1 테이블 구조

#### screen_definitions

| 컬럼명 | 타입 | 필수 | 기본값 | 설명 |
|--------|------|------|--------|------|
| `screen_id` | integer | PK | 자동 생성 (시퀀스) | 화면 고유 ID |
| `screen_name` | varchar(100) | ✅ | - | 화면명 |
| `screen_code` | varchar(50) | ✅ | **자동 생성** | `{company_code}_{순번}` 형식 |
| `table_name` | varchar(100) | | - | 기본 테이블명 |
| `company_code` | varchar(50) | ✅ | - | 회사 코드 |
| `description` | text | | - | 화면 설명 |
| `is_active` | char(1) | | `'Y'` | Y=활성, N=비활성, D=삭제 |
| `created_date` | timestamp | | `CURRENT_TIMESTAMP` | 생성일시 |
| `db_source_type` | varchar(10) | | `'internal'` | internal/external |
| `data_source_type` | varchar(20) | | `'database'` | database/rest_api |

#### screen_layouts_v2

| 컬럼명 | 타입 | 필수 | 기본값 | 설명 |
|--------|------|------|--------|------|
| `layout_id` | integer | PK | 자동 생성 (시퀀스) | 레이아웃 고유 ID |
| `screen_id` | integer | ✅ | - | 화면 ID (FK) |
| `company_code` | varchar(20) | ✅ | - | 회사 코드 |
| `layout_data` | jsonb | ✅ | `'{}'` | 전체 레이아웃 JSON |
| `created_at` | timestamp | | `now()` | 생성일시 |
| `updated_at` | timestamp | | `now()` | 수정일시 |

### 8.2 화면 정의 (screen_definitions)

> ⚠️ `screen_code`는 API 호출 시 자동 생성됩니다. (`{company_code}_{순번}` 형식)

**필수 입력 필드:**

```json
{
  "screenName": "품목정보",
  "tableName": "item_info",
  "companyCode": "COMPANY_7",
  "description": "품목 기본정보 관리 화면"
}
```

**전체 필드 (자동 생성 포함):**

```json
{
  "screen_id": 140,
  "screen_name": "품목정보",
  "screen_code": "COMPANY_7_3",
  "table_name": "item_info",
  "company_code": "COMPANY_7",
  "description": "품목 기본정보 관리 화면",
  "is_active": "Y",
  "db_source_type": "internal",
  "data_source_type": "database",
  "created_date": "2025-01-29T00:00:00.000Z"
}
```

### 8.2 레이아웃 데이터 (screen_layouts_v2.layout_data)

> 전체 레이아웃을 하나의 JSON으로 저장

```json
{
  "version": "2.0",
  "components": [
    {
      "id": "comp_search",
      "url": "@/lib/registry/components/v2-table-search-widget",
      "size": { "width": 1920, "height": 80 },
      "position": { "x": 0, "y": 20, "z": 1 },
      "overrides": {
        "type": "v2-table-search-widget",
        "label": "검색 필터",
        "webTypeConfig": {}
      },
      "displayOrder": 0
    },
    {
      "id": "comp_table",
      "url": "@/lib/registry/components/v2-table-list",
      "size": { "width": 1920, "height": 930 },
      "position": { "x": 0, "y": 150, "z": 1 },
      "overrides": {
        "type": "v2-table-list",
        "label": "테이블 리스트",
        "filter": { "enabled": true, "filters": [] },
        "height": "auto",
        "actions": { "actions": [], "bulkActions": false, "showActions": false },
        "columns": [
          { "align": "left", "order": 0, "format": "text", "visible": true, "sortable": true, "columnName": "status", "searchable": true, "displayName": "status" },
          { "align": "left", "order": 1, "format": "text", "visible": true, "sortable": true, "columnName": "item_number", "searchable": true, "displayName": "item_number" },
          { "align": "left", "order": 2, "format": "text", "visible": true, "sortable": true, "columnName": "item_name", "searchable": true, "displayName": "item_name" },
          { "align": "left", "order": 3, "format": "text", "visible": true, "sortable": true, "columnName": "size", "searchable": true, "displayName": "size" },
          { "align": "left", "order": 4, "format": "text", "visible": true, "sortable": true, "columnName": "material", "searchable": true, "displayName": "material" },
          { "align": "left", "order": 5, "format": "text", "visible": true, "sortable": true, "columnName": "inventory_unit", "searchable": true, "displayName": "inventory_unit" },
          { "align": "left", "order": 6, "format": "text", "visible": true, "sortable": true, "columnName": "weight", "searchable": true, "displayName": "weight" },
          { "align": "left", "order": 7, "format": "text", "visible": true, "sortable": true, "columnName": "unit", "searchable": true, "displayName": "unit" },
          { "align": "left", "order": 8, "format": "text", "visible": true, "sortable": true, "columnName": "division", "searchable": true, "displayName": "division" },
          { "align": "left", "order": 9, "format": "text", "visible": true, "sortable": true, "columnName": "type", "searchable": true, "displayName": "type" },
          { "align": "left", "order": 10, "format": "text", "visible": true, "sortable": true, "columnName": "writer", "searchable": true, "displayName": "writer" }
        ],
        "autoLoad": true,
        "checkbox": { "enabled": true, "multiple": true, "position": "left", "selectAll": true },
        "pagination": { "enabled": true, "pageSize": 20, "showPageInfo": true, "pageSizeOptions": [10, 20, 50, 100], "showSizeSelector": true },
        "showFooter": true,
        "showHeader": true,
        "tableStyle": { "theme": "default", "rowHeight": "normal", "borderStyle": "light", "headerStyle": "default", "hoverEffect": true, "alternateRows": true },
        "displayMode": "table",
        "stickyHeader": false,
        "selectedTable": "item_info",
        "webTypeConfig": {},
        "horizontalScroll": { "enabled": true, "maxColumnWidth": 300, "minColumnWidth": 100, "maxVisibleColumns": 8 }
      },
      "displayOrder": 1
    },
    {
      "id": "comp_btn_code_merge",
      "url": "@/lib/registry/components/v2-button-primary",
      "size": { "width": 88, "height": 40 },
      "position": { "x": 10, "y": 100, "z": 1 },
      "overrides": {
        "text": "코드변경",
        "type": "v2-button-primary",
        "label": "기본 버튼",
        "action": {
          "type": "code_merge",
          "errorMessage": "저장 중 오류가 발생했습니다.",
          "successMessage": "저장되었습니다.",
          "mergeColumnName": "item_number"
        },
        "variant": "primary",
        "actionType": "button",
        "webTypeConfig": { "variant": "default", "actionType": "custom" }
      },
      "displayOrder": 2
    },
    {
      "id": "comp_btn_upload",
      "url": "@/lib/registry/components/v2-button-primary",
      "size": { "width": 88, "height": 40 },
      "position": { "x": 110, "y": 100, "z": 1 },
      "overrides": {
        "text": "업로드",
        "type": "v2-button-primary",
        "label": "기본 버튼",
        "action": {
          "type": "excel_upload",
          "errorMessage": "업로드 중 오류가 발생했습니다.",
          "successMessage": "업로드되었습니다."
        },
        "variant": "primary",
        "actionType": "button",
        "webTypeConfig": { "variant": "default", "actionType": "custom" }
      },
      "displayOrder": 3
    },
    {
      "id": "comp_btn_download",
      "url": "@/lib/registry/components/v2-button-primary",
      "size": { "width": 88, "height": 40 },
      "position": { "x": 210, "y": 100, "z": 1 },
      "overrides": {
        "text": "다운로드",
        "type": "v2-button-primary",
        "label": "기본 버튼",
        "action": {
          "type": "excel_download",
          "errorMessage": "다운로드 중 오류가 발생했습니다.",
          "successMessage": "다운로드되었습니다."
        },
        "variant": "primary",
        "actionType": "button",
        "webTypeConfig": { "variant": "default", "actionType": "custom" }
      },
      "displayOrder": 4
    },
    {
      "id": "comp_btn_register",
      "url": "@/lib/registry/components/v2-button-primary",
      "size": { "width": 80, "height": 40 },
      "position": { "x": 1550, "y": 100, "z": 1 },
      "overrides": {
        "text": "등록",
        "type": "v2-button-primary",
        "label": "기본 버튼",
        "action": {
          "type": "modal",
          "modalSize": "lg",
          "modalTitle": "품목 등록",
          "targetScreenId": {{modal_screen_id}},
          "errorMessage": "저장 중 오류가 발생했습니다.",
          "successMessage": "저장되었습니다."
        },
        "variant": "primary",
        "actionType": "button",
        "webTypeConfig": { "variant": "default", "actionType": "custom" }
      },
      "displayOrder": 5
    },
    {
      "id": "comp_btn_copy",
      "url": "@/lib/registry/components/v2-button-primary",
      "size": { "width": 80, "height": 40 },
      "position": { "x": 1640, "y": 100, "z": 1 },
      "overrides": {
        "text": "복사",
        "type": "v2-button-primary",
        "label": "기본 버튼",
        "action": {
          "type": "copy",
          "modalSize": "lg",
          "modalTitle": "품목 복사",
          "targetScreenId": {{modal_screen_id}},
          "errorMessage": "복사 중 오류가 발생했습니다.",
          "successMessage": "복사되었습니다."
        },
        "variant": "primary",
        "actionType": "button",
        "webTypeConfig": { "variant": "default", "actionType": "custom" }
      },
      "displayOrder": 6
    },
    {
      "id": "comp_btn_edit",
      "url": "@/lib/registry/components/v2-button-primary",
      "size": { "width": 80, "height": 40 },
      "position": { "x": 1730, "y": 100, "z": 1 },
      "overrides": {
        "text": "수정",
        "type": "v2-button-primary",
        "label": "기본 버튼",
        "action": {
          "type": "edit",
          "modalSize": "lg",
          "modalTitle": "품목 수정",
          "targetScreenId": {{modal_screen_id}},
          "errorMessage": "수정 중 오류가 발생했습니다.",
          "successMessage": "수정되었습니다."
        },
        "variant": "primary",
        "actionType": "button",
        "webTypeConfig": { "variant": "default", "actionType": "custom" }
      },
      "displayOrder": 7
    },
    {
      "id": "comp_btn_delete",
      "url": "@/lib/registry/components/v2-button-primary",
      "size": { "width": 80, "height": 40 },
      "position": { "x": 1820, "y": 100, "z": 1 },
      "overrides": {
        "text": "삭제",
        "type": "v2-button-primary",
        "label": "기본 버튼",
        "action": {
          "type": "delete",
          "errorMessage": "삭제 중 오류가 발생했습니다.",
          "successMessage": "삭제되었습니다."
        },
        "variant": "danger",
        "actionType": "button",
        "webTypeConfig": { "variant": "default", "actionType": "custom" }
      },
      "displayOrder": 8
    }
  ]
}
```

### 8.3 모달 화면 (품목 등록/수정)

#### 화면 정의 (필수 입력)

```json
{
  "screenName": "품목 등록/수정",
  "tableName": "item_info",
  "companyCode": "COMPANY_7",
  "description": "품목 등록/수정 폼 화면"
}
```

#### 레이아웃 데이터 (screen_layouts_v2.layout_data)

> 📌 **실제 적용된 레이아웃** - 품목 등록/수정 폼 (모달용)

```json
{
  "version": "2.0",
  "components": [
    {
      "id": "comp_item_number",
      "url": "@/lib/registry/components/v2-input",
      "size": { "width": 300, "height": 60 },
      "position": { "x": 20, "y": 20, "z": 1 },
      "overrides": {
        "type": "v2-input",
        "label": "품번코드",
        "fieldName": "item_number",
        "placeholder": "품번코드를 입력하세요",
        "required": true
      },
      "displayOrder": 0
    },
    {
      "id": "comp_item_name",
      "url": "@/lib/registry/components/v2-input",
      "size": { "width": 300, "height": 60 },
      "position": { "x": 340, "y": 20, "z": 1 },
      "overrides": {
        "type": "v2-input",
        "label": "품명",
        "fieldName": "item_name",
        "placeholder": "품명을 입력하세요",
        "required": true
      },
      "displayOrder": 1
    },
    {
      "id": "comp_size",
      "url": "@/lib/registry/components/v2-input",
      "size": { "width": 300, "height": 60 },
      "position": { "x": 20, "y": 100, "z": 1 },
      "overrides": {
        "type": "v2-input",
        "label": "규격",
        "fieldName": "size",
        "placeholder": "규격을 입력하세요"
      },
      "displayOrder": 2
    },
    {
      "id": "comp_material",
      "url": "@/lib/registry/components/v2-input",
      "size": { "width": 300, "height": 60 },
      "position": { "x": 340, "y": 100, "z": 1 },
      "overrides": {
        "type": "v2-input",
        "label": "재질",
        "fieldName": "material",
        "placeholder": "재질을 입력하세요"
      },
      "displayOrder": 3
    },
    {
      "id": "comp_inventory_unit",
      "url": "@/lib/registry/components/v2-input",
      "size": { "width": 300, "height": 60 },
      "position": { "x": 20, "y": 180, "z": 1 },
      "overrides": {
        "type": "v2-input",
        "label": "재고단위",
        "fieldName": "inventory_unit",
        "placeholder": "재고단위를 입력하세요"
      },
      "displayOrder": 4
    },
    {
      "id": "comp_weight",
      "url": "@/lib/registry/components/v2-input",
      "size": { "width": 300, "height": 60 },
      "position": { "x": 340, "y": 180, "z": 1 },
      "overrides": {
        "type": "v2-input",
        "label": "중량",
        "fieldName": "weight",
        "placeholder": "중량을 입력하세요"
      },
      "displayOrder": 5
    },
    {
      "id": "comp_unit",
      "url": "@/lib/registry/components/v2-input",
      "size": { "width": 300, "height": 60 },
      "position": { "x": 20, "y": 260, "z": 1 },
      "overrides": {
        "type": "v2-input",
        "label": "단위",
        "fieldName": "unit",
        "placeholder": "단위를 입력하세요"
      },
      "displayOrder": 6
    },
    {
      "id": "comp_division",
      "url": "@/lib/registry/components/v2-input",
      "size": { "width": 300, "height": 60 },
      "position": { "x": 340, "y": 260, "z": 1 },
      "overrides": {
        "type": "v2-input",
        "label": "구분",
        "fieldName": "division",
        "placeholder": "구분을 입력하세요"
      },
      "displayOrder": 7
    },
    {
      "id": "comp_type",
      "url": "@/lib/registry/components/v2-input",
      "size": { "width": 300, "height": 60 },
      "position": { "x": 20, "y": 340, "z": 1 },
      "overrides": {
        "type": "v2-input",
        "label": "유형",
        "fieldName": "type",
        "placeholder": "유형을 입력하세요"
      },
      "displayOrder": 8
    },
    {
      "id": "comp_status",
      "url": "@/lib/registry/components/v2-select",
      "size": { "width": 300, "height": 60 },
      "position": { "x": 340, "y": 340, "z": 1 },
      "overrides": {
        "type": "v2-select",
        "label": "상태",
        "fieldName": "status",
        "config": {
          "mode": "dropdown",
          "source": "static",
          "options": [
            { "value": "정상", "label": "정상" },
            { "value": "품절", "label": "품절" },
            { "value": "대기", "label": "대기" },
            { "value": "단종", "label": "단종" }
          ]
        }
      },
      "displayOrder": 9
    },
    {
      "id": "comp_btn_save",
      "url": "@/lib/registry/components/v2-button-primary",
      "size": { "width": 100, "height": 40 },
      "position": { "x": 540, "y": 420, "z": 1 },
      "overrides": {
        "text": "저장",
        "type": "v2-button-primary",
        "label": "저장 버튼",
        "action": {
          "type": "save",
          "closeModalAfterSave": true,
          "refreshParentTable": true,
          "successMessage": "저장되었습니다.",
          "errorMessage": "저장 중 오류가 발생했습니다."
        },
        "variant": "primary",
        "actionType": "button"
      },
      "displayOrder": 10
    }
  ]
}
```

### 8.4 API 호출 방식

> 📌 실제 화면 생성은 API를 통해 진행됩니다. `screen_code`는 서버에서 자동 생성됩니다.

#### Step 1: 화면 코드 자동 생성 API

```http
GET /api/screens/generate-code?companyCode=COMPANY_7
```

**응답:**
```json
{
  "success": true,
  "data": { "screenCode": "COMPANY_7_4" }
}
```

#### Step 2: 화면 생성 API

```http
POST /api/screens
Content-Type: application/json
Authorization: Bearer {{token}}

{
  "screenName": "품목정보",
  "screenCode": "COMPANY_7_4",
  "tableName": "item_info",
  "companyCode": "COMPANY_7",
  "description": "품목 기본정보 관리 화면"
}
```

**응답:**
```json
{
  "success": true,
  "data": {
    "screenId": 141,
    "screenCode": "COMPANY_7_4",
    "screenName": "품목정보"
  }
}
```

#### Step 3: 레이아웃 저장 API

```http
PUT /api/screens/141/layout-v2
Content-Type: application/json
Authorization: Bearer {{token}}

{
  "layoutData": {
    "version": "2.0",
    "components": [ /* 8.2의 components 배열 */ ]
  }
}
```

### 8.5 SQL 직접 INSERT (실제 적용 방식)

> 📌 **실제 테스트 완료된 방식**입니다. Docker psql을 통해 직접 DB에 삽입합니다.

#### Step 1: 모달 화면 먼저 생성 (등록/수정 폼)

```sql
-- 모달 화면 정의
INSERT INTO screen_definitions (
  screen_code, screen_name, table_name, company_code, description, is_active
) VALUES (
  'COMPANY_19_ITEM_MODAL', 'Item Register/Edit Modal', 'item_info', 'COMPANY_19', 
  'Item registration and edit form modal', 'Y'
) RETURNING screen_id;
-- 예: screen_id = 3731 반환됨
```

#### Step 2: 모달 레이아웃 저장

```sql
-- 레이아웃 JSON을 파일로 저장 후 INSERT (한글 인코딩 문제 방지)
INSERT INTO screen_layouts_v2 (screen_id, company_code, layout_data, created_at, updated_at)
VALUES (
  3731,  -- Step 1에서 반환된 screen_id
  'COMPANY_19',
  '{"version":"2.0","components":[/* 8.3의 모달 components 배열 */]}'::jsonb,
  NOW(), NOW()
);
```

#### Step 3: 메인 화면 생성

```sql
-- 메인 화면 정의
INSERT INTO screen_definitions (
  screen_code, screen_name, table_name, company_code, description, is_active
) VALUES (
  'COMPANY_19_ITEM_INFO', 'Item Info', 'item_info', 'COMPANY_19', 
  'Item master data management', 'Y'
) RETURNING screen_id;
-- 예: screen_id = 3730 반환됨
```

#### Step 4: 메인 레이아웃 저장 (모달 연결)

```sql
-- targetScreenId를 Step 1에서 생성한 모달 screen_id로 치환
INSERT INTO screen_layouts_v2 (screen_id, company_code, layout_data, created_at, updated_at)
VALUES (
  3730,  -- Step 3에서 반환된 screen_id
  'COMPANY_19',
  '{"version":"2.0","components":[/* 8.2의 components 배열, targetScreenId: 3731 */]}'::jsonb,
  NOW(), NOW()
);
```

#### Step 5: 메뉴에 화면 연결 (선택사항)

```sql
-- 기존 메뉴에 화면 연결 (screen_menu_assignments 테이블 사용)
INSERT INTO screen_menu_assignments (screen_id, menu_id, company_code, display_order)
VALUES (3730, 55566, 'COMPANY_19', 1);
```

### 8.6 화면 생성 순서 (중요!)

```
1. 모달 화면 생성 (screen_definitions INSERT)
      │
      ▼
2. 모달 레이아웃 저장 (screen_layouts_v2 INSERT)
      │
      ▼
3. 메인 화면 생성 (screen_definitions INSERT)
      │
      ▼
4. 메인 레이아웃 저장 (screen_layouts_v2 INSERT)
   └── targetScreenId에 모달 screen_id 사용!
      │
      ▼
5. (선택) 메뉴에 화면 연결
```

### 8.7 주의사항

| 항목 | 설명 |
|------|------|
| `screen_code` | 회사별 고유, 형식: `{COMPANY_CODE}_{용도}` (예: `COMPANY_19_ITEM_INFO`) |
| `screen_id` | AUTO INCREMENT, INSERT 후 RETURNING으로 획득 |
| `component.id` | `comp_` prefix 권장, 화면 내 중복 불가 |
| `component.url` | `@/lib/registry/components/v2-xxx` 형식 정확히 사용 |
| `component.type` | `overrides.type`과 URL 마지막 부분 일치 필요 |
| `targetScreenId` | **숫자** (문자열 아님), 모달 화면 먼저 생성 필요 |
| `version` | 반드시 `"2.0"` 사용 |
| `layout_data` | JSONB 타입, 복잡한 JSON은 파일로 저장 후 `-f` 옵션으로 실행 |
| UNIQUE 제약 | `(screen_id, company_code)` 조합이 유니크 |
| 한글 처리 | Docker psql에서 한글 직접 입력 시 인코딩 문제 → 영문 사용 또는 파일 사용 |

### 8.8 컴포넌트 타입 레퍼런스

| 컴포넌트 | URL | type (overrides) |
|----------|-----|------------------|
| 텍스트 입력 | `v2-input` | `v2-input` |
| 선택 (드롭다운) | `v2-select` | `v2-select` |
| 날짜 입력 | `v2-date` | `v2-date` |
| 버튼 | `v2-button-primary` | `v2-button-primary` |
| 테이블 리스트 | `v2-table-list` | `v2-table-list` |
| 검색 위젯 | `v2-table-search-widget` | `v2-table-search-widget` |
| 텍스트 표시 | `v2-text-display` | `v2-text-display` |
| 구분선 | `v2-divider-line` | `v2-divider-line` |
| 섹션 카드 | `v2-section-card` | `v2-section-card` |

---

## 9. 화면 구현 체크리스트

> 📋 새로운 화면을 구현할 때 아래 체크리스트를 순서대로 확인하세요.

### 9.1 분석 단계

| 체크 | 항목 | 설명 |
|:----:|------|------|
| ☐ | **테이블 구조 분석** | 해당 화면이 사용할 테이블 스키마 확인 (컬럼명, 타입, 필수 여부) |
| ☐ | **화면 기능 파악** | 조회/등록/수정/삭제, 검색, 필터, 그룹핑 등 필요 기능 목록화 |
| ☐ | **컴포넌트 매핑** | 필요 기능 → V2 컴포넌트 매핑 (2.2 목록 참조) |
| ☐ | **구현 불가 항목 확인** | 현재 V2 컴포넌트로 구현 불가능한 기능 파악 |
| ☐ | **대체 방안 검토** | 구현 불가 항목에 대해 기존 컴포넌트 조합으로 대체 가능 여부 확인 |

### 9.2 문서 작성 단계

| 체크 | 항목 | 설명 |
|:----:|------|------|
| ☐ | **테이블 정의 작성** | 1.1~1.2 형식으로 테이블/컬럼 정보 작성 |
| ☐ | **레이아웃 배치도 작성** | 2.1 형식으로 ASCII 다이어그램 작성 |
| ☐ | **사용 컴포넌트 목록** | 2.3 형식으로 이 화면에서 사용할 컴포넌트 정리 |
| ☐ | **모달 화면 정의** | 등록/수정 모달이 필요하면 별도 레이아웃 작성 |
| ☐ | **JSON 설정 작성** | 8.2~8.3 형식으로 layout_data JSON 작성 |
| ☐ | **구현 불가/대체 방안 명시** | 해당 사항 있으면 문서에 섹션 추가 |

### 9.3 INSERT 전 확인

| 체크 | 항목 | 설명 |
|:----:|------|------|
| ☐ | **company_code 확인** | 대상 회사 코드 정확한지 확인 |
| ☐ | **screen_code 형식** | `{COMPANY_CODE}_{용도}` 형식 준수 |
| ☐ | **모달 먼저 생성** | 모달 화면이 있으면 반드시 먼저 INSERT |
| ☐ | **JSON 파일 준비** | 복잡한 JSON은 파일로 저장 (한글 인코딩 대비) |
| ☐ | **컴포넌트 ID 고유성** | `comp_` prefix, 화면 내 중복 없는지 확인 |
| ☐ | **컴포넌트 URL/type 일치** | `url`의 마지막 부분과 `overrides.type` 동일한지 확인 |
| ☐ | **targetScreenId 치환** | 모달 screen_id를 숫자로 정확히 입력 |

### 9.4 INSERT 후 검증

| 체크 | 항목 | 설명 |
|:----:|------|------|
| ☐ | **화면 접속 테스트** | `/screens/{screen_id}` URL로 접속 |
| ☐ | **컴포넌트 렌더링 확인** | 모든 컴포넌트가 "미구현" 없이 표시되는지 확인 |
| ☐ | **검색 기능 테스트** | 검색 위젯 동작 확인 |
| ☐ | **테이블 데이터 로드** | 테이블에 데이터 표시되는지 확인 |
| ☐ | **버튼 동작 테스트** | 등록/수정/삭제 버튼 클릭 시 모달/액션 동작 확인 |
| ☐ | **모달 폼 테스트** | 모달 열림, 입력 필드 표시, 저장 동작 확인 |
| ☐ | **메뉴 연결 확인** | (연결한 경우) 메뉴에서 화면 접근 가능한지 확인 |

### 9.5 문제 발생 시 확인 사항

| 증상 | 확인 사항 |
|------|-----------|
| 화면이 안 보임 | `screen_layouts_v2`에 데이터 있는지 확인, `company_code` 일치 여부 |
| "미구현 컴포넌트" 표시 | `url`과 `overrides.type` 일치 여부, 컴포넌트명 오타 확인 |
| 모달이 안 열림 | `targetScreenId`가 숫자인지, 해당 screen_id 존재하는지 확인 |
| 테이블 데이터 없음 | `selectedTable` 값 확인, 테이블에 데이터 존재 여부 |
| 버튼 동작 안 함 | `action.type` 값 확인, `actionType: "button"` 설정 여부 |
