From 7a9ec8d02cbd30bbd16c5e5bacbb2fe00ba7c82d Mon Sep 17 00:00:00 2001 From: juseok2 Date: Fri, 30 Jan 2026 00:05:21 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20=ED=92=88=EB=AA=A9=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84=20=EA=B0=80=EC=9D=B4?= =?UTF-8?q?=EB=93=9C=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 품목정보 화면의 구현 예시를 추가하여 JSON 데이터 사용에 대한 주의사항을 명시하였습니다. - V2 컴포넌트 목록을 업데이트하고, 사용 가능한 컴포넌트에 대한 설명을 추가하였습니다. - 화면 구현 시 테이블 구조 분석 및 JSON 구조 작성 방법에 대한 지침을 포함하였습니다. - 각 컴포넌트의 역할과 사용법을 명확히 하여 개발자들이 쉽게 참고할 수 있도록 하였습니다. --- .../01_master-data/item-info.md | 468 +++++++++++++++--- 1 file changed, 396 insertions(+), 72 deletions(-) diff --git a/docs/screen-implementation-guide/01_master-data/item-info.md b/docs/screen-implementation-guide/01_master-data/item-info.md index 73ce4e38..b0ddd9e0 100644 --- a/docs/screen-implementation-guide/01_master-data/item-info.md +++ b/docs/screen-implementation-guide/01_master-data/item-info.md @@ -4,6 +4,53 @@ > 메뉴 경로: 기준정보 > 품목정보 > 테이블: `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 사용 테이블 @@ -83,19 +130,49 @@ └─────────────────────────────────────────────────────────────────────────────┘ ``` -### 2.2 컴포넌트 목록 +### 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-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` | 모달 - 선택 필드 | --- @@ -519,6 +596,14 @@ v2-table-search-widget ──── TableOptionsContext ──── v2-table-li > 📌 실제 화면 저장은 `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 @@ -635,7 +720,7 @@ v2-table-search-widget ──── TableOptionsContext ──── v2-table-li "webTypeConfig": {}, "horizontalScroll": { "enabled": true, "maxColumnWidth": 300, "minColumnWidth": 100, "maxVisibleColumns": 8 } }, - "displayOrder": 0 + "displayOrder": 1 }, { "id": "comp_btn_code_merge", @@ -654,16 +739,9 @@ v2-table-search-widget ──── TableOptionsContext ──── v2-table-li }, "variant": "primary", "actionType": "button", - "webTypeConfig": { - "variant": "default", - "actionType": "custom", - "dataflowConfig": { - "flowConfig": { "flowId": 18, "flowName": "품번코드 통합", "contextData": {}, "executionTiming": "after" }, - "selectedDiagramId": 18 - } - } + "webTypeConfig": { "variant": "default", "actionType": "custom" } }, - "displayOrder": 0 + "displayOrder": 2 }, { "id": "comp_btn_upload", @@ -676,14 +754,14 @@ v2-table-search-widget ──── TableOptionsContext ──── v2-table-li "label": "기본 버튼", "action": { "type": "excel_upload", - "errorMessage": "저장 중 오류가 발생했습니다.", - "successMessage": "저장되었습니다." + "errorMessage": "업로드 중 오류가 발생했습니다.", + "successMessage": "업로드되었습니다." }, "variant": "primary", "actionType": "button", "webTypeConfig": { "variant": "default", "actionType": "custom" } }, - "displayOrder": 0 + "displayOrder": 3 }, { "id": "comp_btn_download", @@ -696,14 +774,14 @@ v2-table-search-widget ──── TableOptionsContext ──── v2-table-li "label": "기본 버튼", "action": { "type": "excel_download", - "errorMessage": "저장 중 오류가 발생했습니다.", - "successMessage": "저장되었습니다." + "errorMessage": "다운로드 중 오류가 발생했습니다.", + "successMessage": "다운로드되었습니다." }, "variant": "primary", "actionType": "button", "webTypeConfig": { "variant": "default", "actionType": "custom" } }, - "displayOrder": 0 + "displayOrder": 4 }, { "id": "comp_btn_register", @@ -716,17 +794,17 @@ v2-table-search-widget ──── TableOptionsContext ──── v2-table-li "label": "기본 버튼", "action": { "type": "modal", - "modalSize": "md", + "modalSize": "lg", "modalTitle": "품목 등록", + "targetScreenId": {{modal_screen_id}}, "errorMessage": "저장 중 오류가 발생했습니다.", - "successMessage": "저장되었습니다.", - "targetScreenId": "{{modal_screen_id}}" + "successMessage": "저장되었습니다." }, "variant": "primary", "actionType": "button", "webTypeConfig": { "variant": "default", "actionType": "custom" } }, - "displayOrder": 0 + "displayOrder": 5 }, { "id": "comp_btn_copy", @@ -739,15 +817,17 @@ v2-table-search-widget ──── TableOptionsContext ──── v2-table-li "label": "기본 버튼", "action": { "type": "copy", - "errorMessage": "저장 중 오류가 발생했습니다.", - "successMessage": "저장되었습니다.", - "targetScreenId": "{{modal_screen_id}}" + "modalSize": "lg", + "modalTitle": "품목 복사", + "targetScreenId": {{modal_screen_id}}, + "errorMessage": "복사 중 오류가 발생했습니다.", + "successMessage": "복사되었습니다." }, "variant": "primary", "actionType": "button", "webTypeConfig": { "variant": "default", "actionType": "custom" } }, - "displayOrder": 0 + "displayOrder": 6 }, { "id": "comp_btn_edit", @@ -760,15 +840,17 @@ v2-table-search-widget ──── TableOptionsContext ──── v2-table-li "label": "기본 버튼", "action": { "type": "edit", - "errorMessage": "저장 중 오류가 발생했습니다.", - "successMessage": "저장되었습니다.", - "targetScreenId": "{{modal_screen_id}}" + "modalSize": "lg", + "modalTitle": "품목 수정", + "targetScreenId": {{modal_screen_id}}, + "errorMessage": "수정 중 오류가 발생했습니다.", + "successMessage": "수정되었습니다." }, "variant": "primary", "actionType": "button", "webTypeConfig": { "variant": "default", "actionType": "custom" } }, - "displayOrder": 0 + "displayOrder": 7 }, { "id": "comp_btn_delete", @@ -781,14 +863,14 @@ v2-table-search-widget ──── TableOptionsContext ──── v2-table-li "label": "기본 버튼", "action": { "type": "delete", - "errorMessage": "저장 중 오류가 발생했습니다.", - "successMessage": "저장되었습니다." + "errorMessage": "삭제 중 오류가 발생했습니다.", + "successMessage": "삭제되었습니다." }, - "variant": "primary", + "variant": "danger", "actionType": "button", "webTypeConfig": { "variant": "default", "actionType": "custom" } }, - "displayOrder": 0 + "displayOrder": 8 } ] } @@ -809,17 +891,19 @@ v2-table-search-widget ──── TableOptionsContext ──── v2-table-li #### 레이아웃 데이터 (screen_layouts_v2.layout_data) +> 📌 **실제 적용된 레이아웃** - 품목 등록/수정 폼 (모달용) + ```json { "version": "2.0", "components": [ { "id": "comp_item_number", - "url": "@/lib/registry/components/v2-text-input", + "url": "@/lib/registry/components/v2-input", "size": { "width": 300, "height": 60 }, "position": { "x": 20, "y": 20, "z": 1 }, "overrides": { - "type": "v2-text-input", + "type": "v2-input", "label": "품번코드", "fieldName": "item_number", "placeholder": "품번코드를 입력하세요", @@ -829,11 +913,11 @@ v2-table-search-widget ──── TableOptionsContext ──── v2-table-li }, { "id": "comp_item_name", - "url": "@/lib/registry/components/v2-text-input", + "url": "@/lib/registry/components/v2-input", "size": { "width": 300, "height": 60 }, "position": { "x": 340, "y": 20, "z": 1 }, "overrides": { - "type": "v2-text-input", + "type": "v2-input", "label": "품명", "fieldName": "item_name", "placeholder": "품명을 입력하세요", @@ -842,23 +926,123 @@ v2-table-search-widget ──── TableOptionsContext ──── v2-table-li "displayOrder": 1 }, { - "id": "comp_status", - "url": "@/lib/registry/components/v2-select-basic", + "id": "comp_size", + "url": "@/lib/registry/components/v2-input", "size": { "width": 300, "height": 60 }, "position": { "x": 20, "y": 100, "z": 1 }, "overrides": { - "type": "v2-select-basic", - "label": "상태", - "fieldName": "status", - "options": ["정상", "품절", "대기", "단종"] + "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": 80, "height": 40 }, - "position": { "x": 400, "y": 500, "z": 1 }, + "size": { "width": 100, "height": 40 }, + "position": { "x": 540, "y": 420, "z": 1 }, "overrides": { "text": "저장", "type": "v2-button-primary", @@ -873,7 +1057,7 @@ v2-table-search-widget ──── TableOptionsContext ──── v2-table-li "variant": "primary", "actionType": "button" }, - "displayOrder": 20 + "displayOrder": 10 } ] } @@ -940,35 +1124,175 @@ Authorization: Bearer {{token}} } ``` -### 8.5 SQL 직접 INSERT (참고용) +### 8.5 SQL 직접 INSERT (실제 적용 방식) -> ⚠️ 일반적으로 API를 사용하지만, 대량 마이그레이션 시 직접 SQL 사용 가능 +> 📌 **실제 테스트 완료된 방식**입니다. Docker psql을 통해 직접 DB에 삽입합니다. + +#### Step 1: 모달 화면 먼저 생성 (등록/수정 폼) ```sql --- Step 1: 화면 정의 (screen_code는 수동 지정 필요) +-- 모달 화면 정의 INSERT INTO screen_definitions ( - screen_name, screen_code, table_name, company_code, description + screen_code, screen_name, table_name, company_code, description, is_active ) VALUES ( - '품목정보', 'COMPANY_7_4', 'item_info', 'COMPANY_7', '품목 기본정보 관리 화면' + '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: 레이아웃 저장 (screen_id 사용) -INSERT INTO screen_layouts_v2 (screen_id, company_code, layout_data) +#### Step 2: 모달 레이아웃 저장 + +```sql +-- 레이아웃 JSON을 파일로 저장 후 INSERT (한글 인코딩 문제 방지) +INSERT INTO screen_layouts_v2 (screen_id, company_code, layout_data, created_at, updated_at) VALUES ( - 141, -- 위에서 반환된 screen_id - 'COMPANY_7', - '{"version": "2.0", "components": [...]}'::jsonb + 3731, -- Step 1에서 반환된 screen_id + 'COMPANY_19', + '{"version":"2.0","components":[/* 8.3의 모달 components 배열 */]}'::jsonb, + NOW(), NOW() ); ``` -### 8.6 주의사항 +#### 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` | API 사용 시 `generateScreenCode` 먼저 호출, 형식: `{company_code}_{순번}` | -| `screen_id` | 화면 생성 후 반환되는 값, 레이아웃 저장 시 필요 | -| `component.id` | 고유 ID (UUID 또는 `comp_` prefix), 중복 불가 | -| `component.url` | `@/lib/registry/components/v2-xxx` 형식 | -| `{{modal_screen_id}}` | 모달 화면 먼저 생성 후 실제 ID로 치환 | +| `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"` 사용 | -| UNIQUE 제약 | `screen_layouts_v2`는 `(screen_id, company_code)` 조합이 유니크 | +| `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"` 설정 여부 |