# 품목기준관리(ItemMaster) 프론트엔드 가이드 > 📌 **품목설정 시스템의 구조, API, 잠금 기능에 대한 프론트엔드 개발 가이드** --- ## 1. 개요 품목기준관리(ItemMaster)는 제품의 입력 화면을 구성하는 **페이지-섹션-필드** 구조를 관리하는 시스템입니다. ### 1.1 핵심 개념 | 엔티티 | 설명 | 예시 | |--------|------|------| | **Page** | 품목 유형별 화면 (FG, PT, SM, RM, CS) | "완제품 기본정보", "부품 상세" | | **Section** | 페이지 내 논리적 영역 | "제품 상세", "BOM 정보" | | **Field** | 섹션 내 입력 항목 | "제품명", "규격", "단가" | | **BomItem** | BOM 섹션 내 부품 항목 | "부품A x 2개" | ### 1.2 아키텍처 특징 - **독립 엔티티 구조**: 섹션, 필드, BOM은 독립적으로 존재하며 재사용 가능 - **링크 테이블**: `entity_relationships`로 관계 관리 - **연결 잠금**: 중요한 구조는 잠금으로 보호 가능 --- ## 2. 데이터 구조 ### 2.1 엔티티 관계도 ``` ┌─────────────────────────────────────────────────────────────────┐ │ ItemPage │ │ (id, page_name, item_type, is_active) │ └─────────────┬──────────────────────────────────────────────────┘ │ entity_relationships (is_locked) ▼ ┌─────────────────────────────────────────────────────────────────┐ │ ItemSection │ │ (id, title, type, is_template, is_default) │ └─────────────┬───────────────────────────────────┬──────────────┘ │ entity_relationships │ entity_relationships │ (is_locked) │ (is_locked) ▼ ▼ ┌─────────────────────────────┐ ┌─────────────────────────────┐ │ ItemField │ │ ItemBomItem │ │ (id, field_name, │ │ (id, item_code, │ │ field_type, is_required) │ │ item_name, quantity) │ └─────────────────────────────┘ └─────────────────────────────┘ ``` ### 2.2 entity_relationships 테이블 모든 엔티티 간 관계는 `entity_relationships` 테이블로 관리됩니다. ```typescript interface EntityRelationship { id: number; tenant_id: number; group_id: number; // 1: ItemMaster parent_type: 'page' | 'section'; parent_id: number; child_type: 'section' | 'field' | 'bom'; child_id: number; order_no: number; is_locked: boolean; // ⭐ 잠금 여부 locked_by?: number; locked_at?: string; metadata?: object; } ``` --- ## 3. 잠금(Lock) 기능 ### 3.1 잠금의 의미 **연결이 잠기면:** - 해당 연결(관계)를 해제할 수 없음 - 연결된 자식 엔티티를 삭제할 수 없음 - 이름 변경, 속성 추가 등 **비구조적 수정은 허용** ``` 예시: page→section 연결이 잠김 ├─ ❌ 섹션을 페이지에서 분리할 수 없음 ├─ ❌ 해당 섹션을 삭제할 수 없음 ├─ ✅ 섹션 제목 변경 가능 └─ ✅ 섹션에 새 필드 추가 가능 ``` ### 3.2 잠금 상태 확인 init API 응답에 `is_locked` 필드가 포함됩니다. ```typescript // GET /api/v1/item-master/init 응답 { "pages": [ { "id": 1, "page_name": "완제품 기본정보", "sections": [ { "id": 10, "title": "제품 상세", "is_locked": true, // ⭐ 이 연결이 잠김 "fields": [ { "id": 100, "field_name": "제품명", "is_locked": false // ⭐ 이 연결은 잠기지 않음 } ] } ] } ] } ``` ### 3.3 프론트엔드 처리 가이드 ```typescript // 잠금 상태에 따른 UI 처리 예시 interface SectionProps { section: ItemSection; isLocked: boolean; // 부모로부터 전달받은 잠금 상태 } function SectionItem({ section, isLocked }: SectionProps) { return (

{section.title} {isLocked && } {/* 잠금 아이콘 표시 */}

{/* 잠금 시 삭제/분리 버튼 비활성화 */} {/* 수정은 항상 가능 */}
); } ``` ### 3.4 잠금 관련 에러 처리 잠금된 항목에 대해 삭제/해제 시도 시 에러가 반환됩니다. ```typescript // 에러 응답 예시 { "success": false, "message": "잠금된 연결은 해제할 수 없습니다.", "error": "relationship_locked" } // 프론트엔드 에러 처리 try { await deleteSection(sectionId); } catch (error) { if (error.response?.data?.error === 'entity_protected_by_locked_relationship') { toast.error('잠금된 연결로 보호된 항목은 삭제할 수 없습니다.'); } } ``` --- ## 4. API 엔드포인트 ### 4.1 초기화 API | Method | Endpoint | 설명 | |--------|----------|------| | GET | `/api/v1/item-master/init` | 전체 데이터 로드 (페이지, 섹션, 커스텀탭, 단위옵션) | **응답 구조:** ```typescript interface InitResponse { pages: ItemPage[]; // 페이지 + 연결된 섹션/필드 sections: ItemSection[]; // 모든 독립 섹션 (재사용 풀) customTabs: CustomTab[]; unitOptions: UnitOption[]; } ``` ### 4.2 페이지 API | Method | Endpoint | 설명 | |--------|----------|------| | GET | `/api/v1/item-master/pages` | 페이지 목록 | | POST | `/api/v1/item-master/pages` | 페이지 생성 | | PUT | `/api/v1/item-master/pages/{id}` | 페이지 수정 | | DELETE | `/api/v1/item-master/pages/{id}` | 페이지 삭제 | ### 4.3 섹션 API | Method | Endpoint | 설명 | |--------|----------|------| | GET | `/api/v1/item-master/sections` | 독립 섹션 목록 | | POST | `/api/v1/item-master/sections` | 독립 섹션 생성 | | POST | `/api/v1/item-master/pages/{pageId}/sections` | 섹션 생성 + 페이지 연결 | | PUT | `/api/v1/item-master/sections/{id}` | 섹션 수정 | | DELETE | `/api/v1/item-master/sections/{id}` | 섹션 삭제 | | POST | `/api/v1/item-master/sections/{id}/clone` | 섹션 복제 | | GET | `/api/v1/item-master/sections/{id}/usage` | 사용처 조회 | ### 4.4 필드 API | Method | Endpoint | 설명 | |--------|----------|------| | GET | `/api/v1/item-master/fields` | 독립 필드 목록 | | POST | `/api/v1/item-master/fields` | 독립 필드 생성 | | POST | `/api/v1/item-master/sections/{sectionId}/fields` | 필드 생성 + 섹션 연결 | | PUT | `/api/v1/item-master/fields/{id}` | 필드 수정 | | DELETE | `/api/v1/item-master/fields/{id}` | 필드 삭제 | | POST | `/api/v1/item-master/fields/{id}/clone` | 필드 복제 | | GET | `/api/v1/item-master/fields/{id}/usage` | 사용처 조회 | ### 4.5 BOM API | Method | Endpoint | 설명 | |--------|----------|------| | GET | `/api/v1/item-master/bom-items` | 독립 BOM 목록 | | POST | `/api/v1/item-master/bom-items` | 독립 BOM 생성 | | POST | `/api/v1/item-master/sections/{sectionId}/bom-items` | BOM 생성 + 섹션 연결 | | PUT | `/api/v1/item-master/bom-items/{id}` | BOM 수정 | | DELETE | `/api/v1/item-master/bom-items/{id}` | BOM 삭제 | ### 4.6 순서 변경 API | Method | Endpoint | 설명 | |--------|----------|------| | PUT | `/api/v1/item-master/pages/{pageId}/sections/reorder` | 섹션 순서 변경 | | PUT | `/api/v1/item-master/sections/{sectionId}/fields/reorder` | 필드 순서 변경 | --- ## 5. 필드 타입 ### 5.1 지원 필드 타입 | field_type | 설명 | 렌더링 컴포넌트 | |------------|------|----------------| | `textbox` | 텍스트 입력 | `` | | `number` | 숫자 입력 | `` | | `dropdown` | 드롭다운 선택 | `