Files
sam-react-prod/claudedocs/[IMPL-2025-11-27] item-master-api-refactor.md
byeongcheolryu 65a8510c0b fix: 품목기준관리 실시간 동기화 수정
- BOM 항목 추가/수정/삭제 시 섹션탭 즉시 반영
- 섹션 복제 시 UI 즉시 업데이트 (null vs undefined 이슈 해결)
- 항목 수정 기능 추가 (useTemplateManagement)
- 실시간 동기화 문서 추가

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-27 22:19:50 +09:00

11 KiB

품목기준관리 API 구조 변경 대응 작업

작업 일자: 2025-11-27


1. 백엔드 API 변경 요약

1.1 핵심 구조 변경: 독립 엔티티 + 링크 테이블

Before (CASCADE FK):

item_pages
  ↓ page_id FK (CASCADE) - 삭제 시 연쇄 삭제
item_sections
  ↓ section_id FK (CASCADE) - 삭제 시 연쇄 삭제
item_fields / item_bom_items

After (독립 + 링크):

item_pages (독립)
item_sections (독립)     → entity_relationships (링크 테이블)
item_fields (독립)
item_bom_items (독립)

1.2 item_master_fields 테이블 통합 → DROP

  • item_master_fields 테이블 삭제됨
  • item_fields 테이블에 통합:
    • section_id → nullable (독립 필드는 NULL)
    • category, description, is_common 컬럼 추가

결과: 마스터 항목 = item_fields WHERE section_id IS NULL

1.3 entity_relationships 테이블 구조

CREATE TABLE entity_relationships (
  id BIGINT PRIMARY KEY,
  tenant_id BIGINT,
  group_id INT DEFAULT 1,           -- 1: 품목관리
  parent_type ENUM('page', 'section'),
  parent_id BIGINT,
  child_type ENUM('section', 'field', 'bom'),
  child_id BIGINT,
  order_no INT DEFAULT 0,
  metadata JSON,
  created_at, updated_at
);

1.4 새 API 엔드포인트 (14개)

페이지-섹션 연결:

  • POST /pages/{pageId}/link-section - { child_id, order_no? }
  • DELETE /pages/{pageId}/unlink-section/{sectionId}

페이지-필드 직접 연결:

  • POST /pages/{pageId}/link-field - { child_id, order_no? }
  • DELETE /pages/{pageId}/unlink-field/{fieldId}

페이지 관계 조회:

  • GET /pages/{pageId}/relationships
  • GET /pages/{pageId}/structure 전체 구조 조회

섹션-필드 연결:

  • POST /sections/{sectionId}/link-field - { child_id, order_no? }
  • DELETE /sections/{sectionId}/unlink-field/{fieldId}

섹션-BOM 연결:

  • POST /sections/{sectionId}/link-bom - { child_id, order_no? }
  • DELETE /sections/{sectionId}/unlink-bom/{bomId}

섹션 관계 조회:

  • GET /sections/{sectionId}/relationships

순서 변경:

  • POST /relationships/reorder
    {
      "parent_type": "page",
      "parent_id": 1,
      "ordered_items": [
        { "child_type": "section", "child_id": 1 },
        { "child_type": "section", "child_id": 2 }
      ]
    }
    

1.5 독립 엔티티 API

섹션:

  • GET /sections - 독립 섹션 목록 (is_template 필터 가능)
  • POST /sections - 독립 섹션 생성
  • POST /sections/{id}/clone - 섹션 복제
  • GET /sections/{id}/usage - 섹션 사용처 조회

필드:

  • GET /fields - 독립 필드 목록
  • POST /fields - 독립 필드 생성
  • POST /fields/{id}/clone - 필드 복제
  • GET /fields/{id}/usage - 필드 사용처 조회

BOM:

  • GET /bom-items - 독립 BOM 목록
  • POST /bom-items - 독립 BOM 생성

2. 프론트엔드 수정 계획

2.1 타입 정의 수정 (item-master-api.ts) 완료

제거 또는 수정:

  • ItemMasterFieldItemField로 통합 (section_id = null)
  • MasterFieldRequest, MasterFieldResponse deprecated 표시

추가:

  • EntityRelationship 타입 추가 (EntityRelationshipResponse)
  • LinkEntityRequest 타입 추가
  • ReorderRelationshipsRequest 타입 추가
  • PageStructureResponse 타입 추가
  • LinkBomRequest 타입 추가

수정:

  • ItemFieldResponsecategory, description, is_common 추가
  • IndependentFieldRequestcategory, description, is_common 추가
  • InitResponsefields 필드 추가, masterFields deprecated

2.2 API 함수 수정 (lib/api/item-master.ts) 완료

deprecated 표시:

  • masterFields.list() - deprecated, fields.list() 사용 권장
  • masterFields.create() - deprecated, fields.createIndependent() 사용 권장
  • masterFields.update() - deprecated, fields.update() 사용 권장
  • masterFields.delete() - deprecated, fields.delete() 사용 권장

추가 (link/unlink API):

  • pages.linkSection() (기존)
  • pages.unlinkSection() (기존)
  • pages.linkField()
  • pages.unlinkField()
  • sections.linkField() (기존)
  • sections.unlinkField() (기존)
  • sections.linkBom()
  • sections.unlinkBom()
  • pages.getRelationships()
  • pages.getStructure() (기존)
  • sections.getRelationships()
  • relationships.reorder()

추가 (독립 엔티티 API) - 기존 구현됨:

  • sections.list()
  • sections.createIndependent()
  • sections.clone()
  • sections.getUsage()
  • fields.list()
  • fields.createIndependent()
  • fields.clone()
  • fields.getUsage()

2.3 Context 수정 (ItemMasterContext.tsx) 완료

상태 변경:

  • itemMasterFields → deprecated 표시 (기존 유지, independentFields 병행)
  • 독립 필드 = independentFields state 이미 존재

함수 변경 (API 마이그레이션 + deprecated 표시):

  • addItemMasterFieldfields.createIndependent() 사용
  • updateItemMasterFieldfields.update() 사용
  • deleteItemMasterFieldfields.delete() 사용
  • loadItemMasterFields → deprecated 표시 추가

신규 함수 (이미 구현됨):

  • linkSectionToPage(pageId, sectionId) (line 2225)
  • unlinkSectionFromPage(pageId, sectionId) (line 2294)
  • linkFieldToSection(sectionId, fieldId) (line 2328)
  • unlinkFieldFromSection(sectionId, fieldId) (line 2366)

2.4 UI 컴포넌트 수정

계층구조 탭 (HierarchyTab): 완료

  • 섹션 추가 시 → link-section API 사용 (기존 구현)
  • 섹션 제거 시 → unlink-section API 사용 (기존 구현)
  • 필드 제거 시 → unlinkFieldFromSection API 사용
  • confirm/toast 메시지 "연결 해제"로 변경
  • ItemMasterDataManagement.tsx에서 handleUnlinkFieldWithTracking 사용

섹션 탭 (SectionsTab): 완료 (2025-11-27)

  • handleDeleteTemplateField → unlinkFieldFromSection API 호출로 변경
  • SectionsTab.tsx 필드 삭제 아이콘 → Unlink 아이콘 (orange)
  • 버튼 title "삭제" → "연결 해제" 변경
  • confirm 메시지 "연결을 해제하시겠습니까?" 변경
  • toast 메시지 "항목 연결이 해제되었습니다" 변경
  • useTemplateManagement.ts에 linkFieldToSection, unlinkFieldFromSection import 추가

항목 탭 (MasterFieldTab → FieldTab): 완료

  • 데이터 소스: Context에서 fields.* API 사용 (2025-11-27)
  • CRUD → 독립 필드 API 사용 (fields.createIndependent(), fields.update(), fields.delete())
  • useMasterFieldManagement.ts에 deprecated 표시 추가
  • MasterFieldTab/index.tsx UI 텍스트 "항목"으로 변경
  • MasterFieldDialog 제목/설명 변경
  • toast 메시지 "마스터 항목" → "항목" 변경
  • 다이얼로그 텍스트 변경 완료 (FieldDialog, FieldDrawer, TemplateFieldDialog, ImportFieldDialog)

속성 탭 (AttributesTab): 분석 완료 - itemMasterFields 양방향 연동 (2025-11-27)

  • 데이터 소스: itemMasterFields (Context) + 로컬 옵션 state
  • 양방향 연동: 항목탭 ⇄ 속성탭 (같은 itemMasterFields 참조)
  • 항목 추가/수정/삭제 → 속성탭에도 반영
  • 속성 옵션 변경 → 해당 필드의 dropdown options 자동 업데이트 (useAttributeManagement.ts:131-161)

ImportFieldDialog: 탭 통합 완료 (2025-11-27)

  • 항목/독립필드 탭 → 단일 필드 목록으로 통합
  • fields prop 추가, independentFields/itemMasterFields deprecated
  • onImport 시그니처 단순화: (source?: ImportSource)()
  • handleImportField 함수: source 분기 제거 → linkFieldToSection 단일 호출

3. 삭제 동작 변경

3.1 기존 (CASCADE 삭제)

페이지 삭제 → 연결된 섹션도 삭제 → 연결된 필드도 삭제

3.2 변경 후 (unlink만)

페이지 삭제 → entity_relationships에서 링크만 제거
             → 섹션은 섹션 탭에 유지
             → 필드는 항목 탭에 유지

UI에서 "삭제" vs "연결 해제" 구분:

  • 연결 해제: 현재 페이지/섹션에서만 제거, 원본 유지
  • 실제 삭제: 엔티티 자체를 삭제 (모든 곳에서 사라짐)

4. 데이터 통일

4.1 필드 속성 공유

현재 문제:

  • 마스터 항목에서 is_required 설정
  • 계층구조/섹션에서는 복사본이라 반영 안됨

해결:

  • 이제 같은 item_fields 레코드를 링크로 참조
  • 한 곳에서 수정 → 모든 곳에 반영

4.2 UI 표시 통일

데이터 소스 용도
항목 탭 itemMasterFields (Context) 독립 필드 CRUD
속성 탭 itemMasterFields + 로컬 옵션 state 단위/재질/표면처리 + 필드 연동
계층구조 탭 entity_relationshipsitem_fields 페이지-섹션-필드 구조
섹션 탭 entity_relationshipsitem_fields 섹션-필드 연결 관리

핵심: 모든 탭이 item_fields를 공유 → 어디서 수정해도 전체 반영!


5. 작업 체크리스트

Phase 1: 타입 및 API 수정 완료

  • item-master-api.ts 타입 정의 수정
  • lib/api/item-master.ts API 함수 추가

Phase 2: Context 수정 완료

  • ItemMasterContext.tsx 상태 및 함수 수정

Phase 3: UI 컴포넌트 수정 완료

  • 계층구조 탭 - 필드 삭제 → unlink 변경
  • 섹션 탭 - handleDeleteTemplateField → unlinkFieldFromSection API 호출 (2025-11-27)
  • 항목 탭 - 데이터 소스 변경 + UI 텍스트 변경 (다이얼로그 포함 완료)
  • 속성 탭 - 동일 데이터 소스 사용 (통합됨)
  • ImportFieldDialog - 탭 통합 완료 (항목/독립필드 → 필드) (2025-11-27)

Phase 4: 테스트

  • 페이지 삭제 시 섹션 유지 확인
  • 섹션에서 필드 제거 시 항목 탭에 유지 확인
  • 필드 속성 변경 시 모든 탭에 반영 확인

6. 관련 파일

프론트엔드

  • src/types/item-master-api.ts
  • src/lib/api/item-master.ts
  • src/contexts/ItemMasterContext.tsx
  • src/components/items/ItemMasterDataManagement.tsx
  • src/components/items/ItemMasterDataManagement/tabs/HierarchyTab/
  • src/components/items/ItemMasterDataManagement/tabs/SectionsTab.tsx
  • src/components/items/ItemMasterDataManagement/tabs/MasterFieldTab/
  • src/components/items/ItemMasterDataManagement/dialogs/ImportFieldDialog.tsx

백엔드 (참조)

  • app/Models/ItemMaster/EntityRelationship.php
  • app/Swagger/v1/EntityRelationshipApi.php
  • routes/api.php