diff --git a/claudedocs/item-master/[IMPL-2025-12-24] item-master-test-and-zustand.md b/claudedocs/item-master/[IMPL-2025-12-24] item-master-test-and-zustand.md index 0974e5ad..d24f87dd 100644 --- a/claudedocs/item-master/[IMPL-2025-12-24] item-master-test-and-zustand.md +++ b/claudedocs/item-master/[IMPL-2025-12-24] item-master-test-and-zustand.md @@ -10,16 +10,87 @@ | 항목 | 상태 | |------|------| -| 훅 분리 작업 | ✅ 완료 (2025-12-16) | -| index.tsx 줄 수 | 2,161줄 → 1,050줄 (51% 감소) | +| 훅 분리 작업 | ✅ 완료 (2025-12-24) | +| 메인 컴포넌트 줄 수 | 1,799줄 → 971줄 (46% 감소) | +| 타입 에러 수정 | ✅ 완료 (55개 → 0개) | +| 무한 로딩 버그 수정 | ✅ 완료 | +| **Zustand 연동** | ✅ 완료 (2025-12-24) | | 빌드 | ✅ 성공 | -| 수동 테스트 | ⏳ 진행 필요 | --- -## Phase 1: 수동 테스트 +## Phase 1: 훅 분리 작업 ✅ -### 1.1 품목 유형별 등록 테스트 +### 완료된 훅 (11개) + +| # | 훅 이름 | 용도 | 상태 | +|---|--------|------|------| +| 1 | usePageManagement | 페이지 CRUD | ✅ 기존 | +| 2 | useSectionManagement | 섹션 CRUD | ✅ 기존 | +| 3 | useFieldManagement | 필드 CRUD | ✅ 기존 | +| 4 | useMasterFieldManagement | 마스터 필드 | ✅ 기존 | +| 5 | useTemplateManagement | 템플릿 관리 | ✅ 기존 | +| 6 | useAttributeManagement | 속성/옵션 관리 | ✅ 기존 | +| 7 | useTabManagement | 탭 관리 | ✅ 기존 | +| 8 | useInitialDataLoading | 초기 데이터 로딩 | ✅ 신규 | +| 9 | useImportManagement | 섹션/필드 불러오기 | ✅ 신규 | +| 10 | useReorderManagement | 순서 변경 | ✅ 신규 | +| 11 | useDeleteManagement | 삭제 관리 | ✅ 신규 | + +### UI 컴포넌트 분리 (1개) + +| # | 컴포넌트 | 용도 | 상태 | +|---|---------|------|------| +| 1 | AttributeTabContent | 속성 탭 (~500줄) | ✅ 완료 | + +--- + +## Phase 2: Zustand 연동 ✅ + +### 2.1 구조 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ useInitialDataLoading │ +│ ┌─────────────────────┐ ┌─────────────────────────────┐│ +│ │ Context 로드 │ AND │ Zustand Store 로드 ││ +│ │ (기존 호환성 유지) │ │ (정규화된 상태) ││ +│ └─────────────────────┘ └─────────────────────────────┘│ +│ ↓ ↓ │ +│ 기존 컴포넌트 → Context 새 컴포넌트 → useItemMasterStore│ +└─────────────────────────────────────────────────────────────┘ +``` + +### 2.2 연동 방식: 병행 운영 + +- **Context**: 기존 컴포넌트 호환성 유지 +- **Zustand**: 새 컴포넌트에서 직접 사용 가능 +- **점진적 마이그레이션**: Context → Zustand로 단계적 전환 + +### 2.3 수정된 파일 + +| 파일 | 변경 내용 | +|------|----------| +| `useInitialDataLoading.ts` | `useItemMasterStore` import, `initFromApi()` 호출 | + +### 2.4 Zustand Store 기능 + +`src/stores/item-master/useItemMasterStore.ts` (1,139줄) + +| 영역 | 기능 | +|------|------| +| 페이지 | loadPages, createPage, updatePage, deletePage | +| 섹션 | loadSections, createSection, updateSection, deleteSection, reorderSections | +| 필드 | loadFields, createField, updateField, deleteField, reorderFields | +| BOM | loadBomItems, createBomItem, updateBomItem, deleteBomItem | +| 속성 | addUnit, updateUnit, deleteUnit, addMaterial, updateMaterial, deleteMaterial | +| API | initFromApi() - API 호출 후 정규화된 상태 저장 | + +--- + +## Phase 3: 테스트 (다음 단계) + +### 3.1 품목 유형별 등록 테스트 | # | 품목 유형 | 테스트 URL | 상태 | |---|----------|-----------|------| @@ -31,90 +102,31 @@ | 6 | RM (원자재) | `/ko/items/create` → 원자재 선택 | ⬜ | | 7 | CS (소모품) | `/ko/items/create` → 소모품 선택 | ⬜ | -### 1.2 품목 수정 테스트 - -| # | 테스트 항목 | 상태 | -|---|------------|------| -| 1 | 기존 품목 불러오기 | ⬜ | -| 2 | 필드 값 수정 후 저장 | ⬜ | -| 3 | 수정 후 목록에서 확인 | ⬜ | - -### 1.3 핵심 기능 테스트 - -| # | 기능 | 테스트 방법 | 상태 | -|---|------|-----------|------| -| 1 | 품목코드 자동생성 | 절곡부품 선택 → 재질/두께 입력 → 코드 확인 | ⬜ | -| 2 | 조건부 필드 표시 | 부품 유형 변경 시 필드 변화 확인 | ⬜ | -| 3 | BOM 추가/수정/삭제 | BOM 섹션에서 CRUD 테스트 | ⬜ | -| 4 | 파일 업로드 | 시방서/인정서 파일 첨부 | ⬜ (백엔드 수정 대기) | -| 5 | 파일 다운로드 | 기존 파일 다운로드 | ⬜ | -| 6 | 파일 삭제 | 첨부된 파일 삭제 | ⬜ | - -### 1.4 부품 유형 변경 테스트 - -| # | 테스트 시나리오 | 상태 | -|---|---------------|------| -| 1 | 절곡 → 조립 변경 시 필드 초기화 확인 | ⬜ | -| 2 | 조립 → 구매 변경 시 필드 초기화 확인 | ⬜ | -| 3 | 폭 합계 자동 계산 (절곡부품) | ⬜ | - ---- - -## Phase 2: 테스트 결과 정리 - -### 발견된 이슈 - -| # | 이슈 | 심각도 | 상태 | 비고 | -|---|------|--------|------|------| -| - | - | - | - | - | - -### 테스트 완료 확인 - -- [ ] 모든 품목 유형 등록 테스트 완료 -- [ ] 모든 품목 수정 테스트 완료 -- [ ] 핵심 기능 테스트 완료 -- [ ] 발견된 이슈 수정 완료 -- [ ] **Phase 1 완료 승인** - ---- - -## Phase 3: Zustand 도입 - -### 3.1 사전 준비 - -- [ ] 기존 Zustand 스토어 분석 (`stores/item-master/`) -- [ ] 기존 품목기준관리 Context 분석 (`ItemMasterContext.tsx`) -- [ ] 마이그레이션 전략 수립 - -### 3.2 Zustand 적용 대상 - -| # | 대상 | 현재 상태 관리 | Zustand 적용 | -|---|------|---------------|-------------| -| 1 | 품목기준관리 설정 페이지 | Context | ⬜ | -| 2 | 품목관리 페이지 | 로컬 state | ⬜ | -| 3 | DynamicItemForm | 로컬 state + props | ⬜ | - -### 3.3 Zustand 마이그레이션 단계 - -- [ ] 1단계: 참조 데이터 (단위, 재질, 표면처리 등) Zustand로 이동 -- [ ] 2단계: 페이지/섹션/필드 CRUD Zustand로 이동 -- [ ] 3단계: 기존 Context 제거 -- [ ] 4단계: 테스트 및 검증 - --- ## 작업 로그 -| 날짜 | 작업 내용 | 상태 | +| 날짜 | 작업 내용 | 커밋 | |------|----------|------| -| 2025-12-24 | 체크리스트 문서 생성 | ✅ | -| - | 수동 테스트 시작 | ⬜ | -| - | Zustand 도입 | ⬜ | +| 2025-12-24 | Phase 1+2 훅/컴포넌트 분리 | `a823ae0` | +| 2025-12-24 | unused 코드 정리 및 import 최적화 | `1664599` | +| 2025-12-24 | 타입 에러 및 무한 로딩 버그 수정 | `028932d` | +| 2025-12-24 | **Zustand 연동 완료** | (현재) | + +--- + +## 다음 단계 + +1. 수동 테스트 진행 +2. 새 컴포넌트에서 `useItemMasterStore` 직접 사용 +3. Context 의존성 점진적 제거 +4. 동적 페이지 생성 구현 --- ## 참고 문서 -- `[PLAN-2025-12-16] dynamicitemform-hook-extraction.md` - 훅 분리 계획서 -- `[DESIGN-2025-12-20] item-master-zustand-refactoring.md` - Zustand 설계서 -- `[NEXT-2025-12-20] zustand-refactoring-session-context.md` - 세션 컨텍스트 \ No newline at end of file +- `[PLAN-2025-12-24] hook-extraction-plan.md` - 훅 분리 계획서 +- `src/stores/item-master/useItemMasterStore.ts` - Zustand Store +- `src/stores/item-master/types.ts` - Store 타입 정의 +- `src/stores/item-master/normalizers.ts` - API 응답 정규화 diff --git a/src/components/items/ItemMasterDataManagement/hooks/useInitialDataLoading.ts b/src/components/items/ItemMasterDataManagement/hooks/useInitialDataLoading.ts index 1ea67c82..5a2c1d06 100644 --- a/src/components/items/ItemMasterDataManagement/hooks/useInitialDataLoading.ts +++ b/src/components/items/ItemMasterDataManagement/hooks/useInitialDataLoading.ts @@ -2,6 +2,7 @@ import { useState, useEffect, useCallback, useRef } from 'react'; import { useItemMaster } from '@/contexts/ItemMasterContext'; +import { useItemMasterStore } from '@/stores/item-master/useItemMasterStore'; import { itemMasterApi } from '@/lib/api/item-master'; import { getErrorMessage, ApiError } from '@/lib/api/error-handler'; import { @@ -43,6 +44,9 @@ export function useInitialDataLoading({ loadIndependentFields, } = useItemMaster(); + // ✅ 2025-12-24: Zustand store 연동 + const initFromApi = useItemMasterStore((state) => state.initFromApi); + const [isInitialLoading, setIsInitialLoading] = useState(true); const [error, setError] = useState(null); @@ -54,6 +58,16 @@ export function useInitialDataLoading({ setIsInitialLoading(true); setError(null); + // ✅ Zustand store 초기화 (정규화된 상태로 저장) + // Context와 병행 운영 - 점진적 마이그레이션 + try { + await initFromApi(); + console.log('✅ [Zustand] Store initialized'); + } catch (zustandError) { + // Zustand 초기화 실패해도 Context로 fallback + console.warn('⚠️ [Zustand] Init failed, falling back to Context:', zustandError); + } + const data = await itemMasterApi.init(); // 1. 페이지 데이터 로드 (섹션이 이미 포함되어 있음)