# [IMPL-2025-11-27] 품목기준관리 실시간 동기화 수정

## 개요
품목기준관리 모듈에서 데이터 변경 시 새로고침 없이 UI가 즉시 업데이트되지 않는 문제들을 수정함.

---

## 핵심 구조 이해

### 상태 의존성 구조
```
sectionsAsTemplates (useMemo)
├── itemPages          → 모듈 섹션 (page_id가 있는 섹션)
└── independentSections → 일반 섹션 (page_id가 null인 섹션)
```

**중요**: `sectionsAsTemplates`는 `[itemPages, independentSections]` 두 상태를 의존성으로 가짐.
따라서 어떤 데이터든 변경되면 **두 상태 모두 업데이트**해야 UI가 즉시 반영됨.

### 탭별 데이터 소스
| 탭 | 데이터 소스 | 비고 |
|---|---|---|
| 계층구조탭 | `itemPages` | 페이지 → 섹션 → 필드 구조 |
| 섹션탭 (일반) | `sectionsAsTemplates` (section_type !== 'BOM') | independentSections 기반 |
| 섹션탭 (모듈) | `sectionsAsTemplates` (section_type === 'BOM') | itemPages 기반 |
| 항목탭 | `independentFields` / `itemMasterFields` | 독립 필드 목록 |

---

## 수정 내역

### 1. BOM 실시간 동기화 (`ItemMasterContext.tsx`)

**문제**: BOM 항목 추가/수정/삭제 시 계층구조탭에서 변경되지만 섹션탭에서는 새로고침 필요

**원인**: `addBOMItem`, `updateBOMItem`, `deleteBOMItem`이 `itemPages`만 업데이트하고 `independentSections`는 업데이트하지 않음

**해결**: 세 함수 모두에 `setIndependentSections` 업데이트 추가

```typescript
// addBOMItem, updateBOMItem, deleteBOMItem 모두에 추가
setIndependentSections(prev => prev.map(section =>
  section.id === sectionId
    ? { ...section, bom_items: [...(section.bom_items || []), newBOM] }
    : section
));
```

---

### 2. 섹션 복제 실시간 반영 (`ItemMasterContext.tsx`)

**문제**: 섹션 복제 후 새로고침해야 목록에 표시됨

**원인 1**: `page_id === null` 체크가 `undefined`를 처리하지 못함
- API 응답: `page_id: null`
- 변환 후: `page_id: undefined` (transformer에서 변환 시 undefined로 됨)
- `null === undefined` → `false` → 잘못된 분기 진입

**해결**: strict equality(`===`) → loose equality(`==`) 변경

```typescript
// 변경 전
if (clonedSection.page_id === null)

// 변경 후
if (clonedSection.page_id == null)  // null과 undefined 둘 다 true
```

**원인 2**: 모듈 섹션 복제 시 `itemPages` 업데이트 누락

**해결**: `else` 분기에 `setItemPages` 업데이트 추가

```typescript
if (clonedSection.page_id == null) {
  // 독립 섹션 → independentSections에 추가
  setIndependentSections(prev => [...prev, clonedSection]);
} else {
  // 모듈 섹션 → itemPages 내 해당 페이지에 추가
  setItemPages(prev => prev.map(page => {
    if (page.id === clonedSection.page_id) {
      return { ...page, sections: [...page.sections, clonedSection] };
    }
    return page;
  }));
}
```

---

### 3. 항목 수정 기능 (`useTemplateManagement.ts`)

**문제**: 섹션탭에서 항목 수정 버튼 클릭 시 아무 동작 없음

**원인**: `handleAddTemplateField` 함수가 추가 로직만 있고 수정 로직이 없음

**해결**: `editingTemplateFieldId` 체크 후 `updateField` API 호출 분기 추가

```typescript
const handleAddTemplateField = async () => {
  // 수정 모드
  if (editingTemplateFieldId) {
    const updateData = {
      field_name: templateFieldName,
      field_type: templateFieldInputType,
      is_required: templateFieldRequired,
      // ... 기타 필드
    };
    await updateField(editingTemplateFieldId, updateData);
    toast.success('항목이 수정되었습니다');
    resetTemplateFieldForm();
    return;
  }

  // 추가 모드 (기존 로직)
  // ...
};
```

---

## 백엔드 요청 사항 (미해결)

### 섹션 복제 시 필드 복제 문제

**API**: `POST /v1/item-master/sections/{id}/clone`

**현재 동작**: 섹션 복제 시 연결된 필드들도 새로운 레코드로 복제됨

**문제점**: 섹션-필드는 링크 관계이므로 섹션만 복제하고 필드는 기존 필드에 링크만 연결해야 함

**백엔드 수정 요청**:
```php
// 현재 코드 (문제)
foreach ($section->fields as $field) {
    $newField = $field->replicate();  // ❌ 새 필드 레코드 생성
    $newField->section_id = $clonedSection->id;
    $newField->save();
}

// 수정 요청
foreach ($section->fields as $field) {
    // ✅ 기존 필드를 새 섹션에 링크만 연결
    $clonedSection->fields()->attach($field->id);
}
```

**파일 위치**: `/sam-api/app/Services/ItemMaster/ItemSectionService.php` (Line 99-113)

---

## 디버깅 로그 (제거 가능)

개발 중 추가된 디버깅 로그들 (프로덕션 전 제거 권장):

```typescript
// ItemMasterContext.tsx - cloneSection
console.log('[cloneSection] API 응답 원본:', sectionData);
console.log('[cloneSection] 변환 후 섹션:', {...});
console.log('[cloneSection] 독립 섹션 추가 (independentSections)');
console.log('[cloneSection] independentSections 업데이트:', newSections.length);

// SectionsTab.tsx
console.log('[SectionsTab] 📥 sectionTemplates prop changed:', {...});
console.log('[SectionsTab] 🔄 Rendering section templates:', {...});

// ItemMasterDataManagement.tsx
console.log('[sectionsAsTemplates] useMemo 재계산!', {...});
console.log('[ItemMasterDataManagement] 📋 sectionsAsTemplates changed:', {...});
```

---

### 4. 페이지 삭제 시 섹션 동기화 (`ItemMasterContext.tsx`) - 2025-11-28

**문제**: 계층구조에서 페이지 삭제 시 연결된 섹션들이 섹션탭에서 사라짐

**예상 동작**: 페이지 삭제 → 연결된 섹션은 unlink만 되고 독립 섹션으로 복귀 → 섹션탭에서 표시

**실제 동작**: 페이지 삭제 → 섹션이 UI에서 완전히 사라짐 (삭제된 것처럼 보임)

**원인 분석**:
1. **백엔드는 정상**: `ItemPageService.php`의 `destroy()` 메서드가 독립 엔티티 아키텍처 준수
   - `entity_relationships`에서 페이지-섹션 관계만 삭제 (섹션 자체는 유지)
   - 섹션/필드는 독립 엔티티로 계속 존재
2. **프론트엔드 상태 동기화 누락**:
   - `deleteItemPage`가 `setItemPages`만 업데이트
   - `independentSections` 상태는 갱신 안 됨
   - `sectionsAsTemplates` useMemo가 `[itemPages, independentSections]` 의존
   - 결과: 섹션이 `itemPages`에서 제거되었지만 `independentSections`에도 없어서 UI에서 사라짐

**해결**: 페이지 삭제 후 `refreshIndependentSections()` 호출 추가

```typescript
// deleteItemPage 함수 수정
const deleteItemPage = async (id: number) => {
  try {
    const response = await itemMasterApi.pages.delete(id);

    if (!response.success) {
      throw new Error(response.message || '페이지 삭제 실패');
    }

    // state 업데이트
    setItemPages(prev => prev.filter(page => page.id !== id));

    // 2025-11-28: 페이지 삭제 후 독립 섹션 목록 갱신
    // 백엔드에서 섹션은 삭제되지 않고 연결만 해제되므로 (독립 엔티티 아키텍처)
    // 독립 섹션 목록을 새로고침해야 섹션 탭에서 해당 섹션이 표시됨
    try {
      await refreshIndependentSections();
      console.log('[ItemMasterContext] 페이지 삭제 후 독립 섹션 갱신 완료');
    } catch (refreshError) {
      // 갱신 실패해도 페이지 삭제는 성공한 상태이므로 경고만 출력
      console.warn('[ItemMasterContext] 독립 섹션 갱신 실패:', refreshError);
    }

    console.log('[ItemMasterContext] 페이지 삭제 성공:', id);
  } catch (error) {
    // ...
  }
};
```

**백엔드 코드 참조** (`ItemPageService.php:95-129`):
```php
/**
 * 페이지 삭제 (Soft Delete)
 * 독립 엔티티 아키텍처: 페이지만 삭제하고 연결된 섹션/필드는 unlink만 수행
 */
public function destroy(int $id): void
{
    // 1. entity_relationships에서 이 페이지의 모든 자식 관계 해제
    EntityRelationship::where('parent_type', EntityRelationship::TYPE_PAGE)
        ->where('parent_id', $id)
        ->where('is_locked', false)
        ->delete();

    // 2. 페이지만 Soft Delete (섹션/필드는 독립 엔티티로 유지)
    $page->update(['deleted_by' => $userId]);
    $page->delete();
}
```

---

## 수정된 파일 목록

| 파일 | 수정 내용 |
|---|---|
| `src/contexts/ItemMasterContext.tsx` | BOM 동기화, 섹션 복제 수정, **페이지 삭제 시 독립 섹션 갱신 (2025-11-28)** |
| `src/components/items/ItemMasterDataManagement/hooks/useTemplateManagement.ts` | 항목 수정 로직 추가 |
| `src/components/items/ItemMasterDataManagement/dialogs/TemplateFieldDialog.tsx` | prop 타입 수정 (void → void \| Promise<void>) |

---

## 향후 작업 시 주의사항

1. **양방향 동기화 필수**: 데이터 변경 시 `itemPages`와 `independentSections` 모두 업데이트해야 함
2. **null vs undefined**: API 응답의 null 값이 transformer 거치면서 undefined로 바뀔 수 있음 → `== null` 사용 권장
3. **useMemo 의존성**: `sectionsAsTemplates`의 의존성 배열 확인 → 두 상태가 모두 업데이트되어야 재계산됨
4. **독립 엔티티 아키텍처 인지**: 페이지/섹션/필드는 각각 독립 엔티티이며 `entity_relationships`로 연결됨
   - 페이지 삭제 시 → 섹션은 삭제 안 됨 (연결만 해제) → `refreshIndependentSections()` 필요
   - 섹션 삭제 시 → 필드는 삭제 안 됨 (연결만 해제) → `refreshIndependentFields()` 필요 (해당 시)
   - 프론트엔드에서 연결 해제된 엔티티들이 적절히 표시되도록 상태 갱신 필수