- BOMItem Omit 타입 시그니처 통일 (useTemplateManagement, SectionsTab, ItemMasterContext) - HeadersInit → Record<string, string> 타입 변경 - Zustand useShallow 마이그레이션 (zustand/react/shallow) - DataTable, ListPageTemplate 제네릭 타입 제약 추가 - 설정 관리 페이지 추가 (직급, 직책, 휴가정책, 근무일정, 권한) - HR 관리 페이지 추가 (급여, 휴가) - 단가관리 페이지 리팩토링 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
11 KiB
11 KiB
DynamicItemForm 품목별 분리 계획
작성일: 2025-12-08 수정일: 2025-12-09 상태: 🚀 Phase 1 진행 중
🎉 2025-12-09 업데이트
백엔드 작업 완료!
| 항목 | 상태 |
|---|---|
field_key 저장 방식 변경 (98_unit → unit) |
✅ 완료 |
| 시스템 예약어 검증 (SystemFields.php) | ✅ 완료 |
| 중복 검증 로직 | ✅ 완료 |
| 에러 메시지 | ✅ 완료 |
Phase 1 완료! ✅
제거된 레거시 코드:
- ✅
fieldAliases(영문 → 한글 매핑) - 25줄 - ✅
extractFieldName()함수 - 7줄 - ✅
fieldKeyMap생성 로직 - 25줄 - ✅ 대소문자 무시 매핑 - 15줄
- ✅ 별칭 fallback 매핑 - 10줄
- ✅
98_prefix 파싱 로직 - 8줄 - ✅
fieldKeyToBackendKey변환 테이블 - 30줄 - ✅ 복잡한 변환 로직 - 40줄
실제 결과: ~200줄 코드 삭제! 🎉
변경 요약
| 변경 내용 | Before | After |
|---|---|---|
| Edit 모드 매핑 | 155줄 복잡한 로직 | 15줄 직접 로드 |
| 저장 시 변환 | 75줄 변환 테이블 | 15줄 is_active만 처리 |
| 총 코드량 | ~230줄 | ~30줄 |
📊 현재 상태 분석
현재 구조
src/components/items/
├── DynamicItemForm/ # 현재: 모든 품목 처리 (1350+ lines)
│ ├── index.tsx # 메인 컴포넌트 (거대)
│ ├── fields/ # 필드 렌더러
│ ├── hooks/ # 상태 관리 훅
│ ├── sections/ # BOM 섹션
│ ├── types.ts
│ └── utils/
│
├── ItemForm/ # 기존: 하드코딩된 폼 (참고용)
│ ├── forms/
│ │ ├── ProductForm.tsx # FG(제품) 전용
│ │ ├── MaterialForm.tsx # RM(원자재) 전용
│ │ └── PartForm.tsx # PT(부품) → 하위 분기
│ │ └── parts/
│ │ ├── AssemblyPartForm.tsx # 조립부품
│ │ ├── BendingPartForm.tsx # 절곡부품
│ │ └── PurchasedPartForm.tsx # 구매부품
문제점
| 문제 | 영향도 | field_key 통일로 해결? |
|---|---|---|
| DynamicItemForm 1350+ lines | 🔴 유지보수 어려움 | ❌ |
| 품목별 특수 로직 혼재 | 🔴 버그 발생 원인 | ❌ |
| 조건부 렌더링 복잡도 | 🟡 코드 가독성 | ⚠️ 부분 해결 |
| 파일 업로드 로직 중복 | 🟡 DRY 위반 | ❌ |
| 테스트 어려움 | 🟡 품질 이슈 | ❌ |
품목 유형별 특수 로직
FG (제품):
- 시방서/인정서 파일 업로드
- 인정번호, 유효기간
- BOM 구성 (선택)
PT (부품):
- 부품 유형 선택 (ASSEMBLY/BENDING/PURCHASED)
- 조립부품: 측면규격, 길이, 설치유형, BOM
- 절곡부품: 전개도(바라시), 재질, 폭합계
- 구매부품: 전기개폐기, 모터, 체인 규격
SM (반제품):
- 규격 정보
- BOM 구성 (선택)
RM (원자재):
- 재질, 두께, 폭, 단위
- 단가 정보
CS (소모품):
- 기본 정보만
🎯 목표 구조 (2단계 분리)
Phase 1: field_key 통일 (백엔드 작업 대기)
- 품목기준관리 API와 품목 CRUD API 간 field_key 일치
- 데이터 일관성 확보 → 버그 60% 감소 예상
Phase 2: 컴포넌트 분리 (field_key 통일 후)
src/components/items/
├── DynamicItemForm/
│ ├── index.tsx # 컨테이너 (라우팅만)
│ ├── DynamicFormCore.tsx # 공통 폼 프레임워크
│ │
│ ├── itemTypes/ # 🆕 품목 유형별 컴포넌트
│ │ ├── index.ts # 내보내기
│ │ ├── FGFormFields.tsx # 제품 전용 (인정정보, 파일업로드)
│ │ ├── PTFormFields.tsx # 부품 라우터
│ │ │ ├── AssemblyFields.tsx # 조립부품 전용
│ │ │ ├── BendingFields.tsx # 절곡부품 전용 (전개도)
│ │ │ └── PurchasedFields.tsx # 구매부품 전용
│ │ ├── SMFormFields.tsx # 반제품 전용
│ │ ├── RMFormFields.tsx # 원자재 전용
│ │ └── CSFormFields.tsx # 소모품 전용
│ │
│ ├── shared/ # 🆕 공유 컴포넌트
│ │ ├── FileUploadSection.tsx # 파일 업로드 (FG, PT-절곡)
│ │ ├── BOMSection.tsx # BOM 관리 (FG, PT-조립, SM)
│ │ ├── StatusField.tsx # 활성/비활성
│ │ └── AutoItemCode.tsx # 품목코드 자동생성
│ │
│ ├── fields/ # 기존 유지
│ ├── hooks/ # 기존 유지 + 개선
│ ├── sections/ # → shared/로 이동
│ └── types.ts
📋 세부 작업 계획
Phase 2-1: 공통 컴포넌트 추출
| 작업 | 파일 | 예상 LOC |
|---|---|---|
| 파일 업로드 섹션 추출 | shared/FileUploadSection.tsx |
~150 |
| BOM 섹션 정리 | shared/BOMSection.tsx |
~100 |
| 품목코드 자동생성 | shared/AutoItemCode.tsx |
~50 |
| 상태 필드 | shared/StatusField.tsx |
~30 |
Phase 2-2: 품목 유형별 컴포넌트 생성
| 작업 | 파일 | 특수 로직 |
|---|---|---|
| FG 전용 | itemTypes/FGFormFields.tsx |
인정정보, 시방서/인정서 |
| PT 라우터 | itemTypes/PTFormFields.tsx |
부품유형 선택 후 분기 |
| PT-조립 | itemTypes/AssemblyFields.tsx |
측면규격, 설치유형, BOM |
| PT-절곡 | itemTypes/BendingFields.tsx |
전개도, 폭합계 |
| PT-구매 | itemTypes/PurchasedFields.tsx |
전기개폐기, 모터 규격 |
| SM 전용 | itemTypes/SMFormFields.tsx |
규격, BOM (선택) |
| RM 전용 | itemTypes/RMFormFields.tsx |
재질, 두께, 단가 |
| CS 전용 | itemTypes/CSFormFields.tsx |
기본 정보만 |
Phase 2-3: DynamicFormCore 리팩토링
// DynamicFormCore.tsx - 공통 프레임워크
interface DynamicFormCoreProps {
structure: FormStructure;
formData: DynamicFormData;
onChange: (key: string, value: any) => void;
renderCustomFields?: () => ReactNode; // 품목별 특수 필드
renderCustomSections?: () => ReactNode; // 품목별 특수 섹션
}
// index.tsx - 라우팅만
const ItemTypeComponents = {
FG: FGFormFields,
PT: PTFormFields,
SM: SMFormFields,
RM: RMFormFields,
CS: CSFormFields,
};
<DynamicFormCore
structure={structure}
formData={formData}
onChange={setFieldValue}
renderCustomFields={() => {
const Component = ItemTypeComponents[selectedItemType];
return Component ? <Component {...props} /> : null;
}}
/>
📊 예상 효과
Before (현재)
DynamicItemForm/index.tsx: 1350+ lines- 모든 품목 로직 혼재
- 수정 시 다른 품목 영향 우려
After (분리 후)
DynamicItemForm/index.tsx: ~200 lines (라우팅만)DynamicFormCore.tsx: ~400 lines (공통 프레임워크)- 품목별 컴포넌트: 각 100-200 lines
- 총 코드량 비슷하지만 책임 분리됨
장점
- 버그 격리: 조립부품 수정 → 절곡부품 영향 없음
- 유지보수 용이: 품목별 로직 파악 쉬움
- 테스트 가능: 품목별 단위 테스트 작성 가능
- 확장성: 새 품목 유형 추가 시 파일만 추가
- 협업: 여러 개발자가 다른 품목 동시 작업 가능
⏰ 작업 순서 및 의존성
┌─────────────────────────────────────────┐
│ Phase 1: field_key 통일 (백엔드) │ ← 현재 대기 중
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Phase 2-1: 공통 컴포넌트 추출 │
│ - FileUploadSection │
│ - BOMSection │
│ - AutoItemCode │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Phase 2-2: 품목별 컴포넌트 생성 │
│ - FG, PT(Assembly/Bending/Purchased) │
│ - SM, RM, CS │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Phase 2-3: DynamicFormCore 리팩토링 │
│ - index.tsx 슬림화 │
│ - 품목별 라우팅 │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Phase 3: 테스트 및 검증 │
│ - 품목별 CRUD 테스트 │
│ - 회귀 테스트 │
└─────────────────────────────────────────┘
❓ 결정 필요 사항
Q1. 기존 ItemForm 컴포넌트 처리
| 옵션 | 장점 | 단점 |
|---|---|---|
| A. 삭제 | 중복 제거, 혼란 방지 | 참고 코드 소실 |
| B. 유지 (참고용) | 마이그레이션 시 참고 가능 | 중복 유지보수 |
| C. archive 폴더로 이동 | 참고 가능 + 혼란 방지 | 폴더 추가 |
권장: C. archive 폴더로 이동
Q2. 분리 전략
| 옵션 | 설명 |
|---|---|
| A. 점진적 분리 | 한 품목씩 분리, 기존 코드 유지 |
| B. 전면 분리 | 한 번에 모든 품목 분리 |
권장: A. 점진적 분리 (PT-조립부품부터 시작)
Q3. 품목별 hooks 분리 여부
| 옵션 | 설명 |
|---|---|
| A. 공통 hooks 유지 | useDynamicFormState 그대로 사용 |
| B. 품목별 hooks 추가 | useAssemblyFormState 등 추가 |
권장: A. 공통 hooks 유지 (복잡도 관리)
📝 다음 단계
- ⏳ 백엔드 field_key 통일 답변 대기
- 📋 결정 필요 사항 확인 (Q1, Q2, Q3)
- 🚀 Phase 2-1 시작 (공통 컴포넌트 추출)
참고 문서
claudedocs/item-master/[API-2025-12-06] item-crud-backend-requests.md- field_key 통일 요청src/components/items/ItemForm/- 기존 하드코딩 폼 참고src/components/items/DynamicItemForm/- 현재 동적 폼