Files
sam-react-prod/claudedocs/item-master/[IMPL-2025-12-02] dynamic-item-form-rebuild.md
byeongcheolryu 3be5714805 refactor: 품목관리 시스템 리팩토링 및 Sales 페이지 추가
DynamicItemForm 개선:
- 품목코드 자동생성 기능 추가
- 조건부 표시 로직 개선
- 불필요한 컴포넌트 정리 (DynamicField, DynamicSection 등)
- 타입 시스템 단순화

새로운 기능:
- Sales 페이지 마이그레이션 (견적관리, 거래처관리)
- 공통 컴포넌트 추가 (atoms, molecules, organisms, templates)

문서화:
- 구현 문서 및 참조 문서 추가

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 12:48:41 +09:00

7.4 KiB

품목 등록 동적 페이지 재구현

작업 일자: 2025-12-02

문서 버전

버전 날짜 작성자 내용
1.0 2025-12-02 Claude 롤백 후 재구현 시작
1.1 2025-12-02 Claude Phase 1-8 완료

배경

  • 이전 작업에서 DynamicItemForm 구현이 디자인 누락으로 롤백됨
  • 기존 ItemForm (목업 데이터 기반)의 디자인을 100% 유지하면서 동적 렌더링 구현 필요

핵심 원칙

  1. 디자인 100% 동일: 기존 ItemForm과 완벽히 동일한 UI/UX
  2. 밸리데이션 동일: 에러 메시지 위치, 스타일 동일
  3. 버튼/아이콘 동일: 모든 버튼, 아이콘 위치 및 스타일 동일
  4. 화면 등장 순서 동일: 섹션 표시 순서, 조건부 렌더링 동일
  5. 동적 구성: 품목기준관리 API 기반으로 필드/섹션 동적 생성

체크리스트

Phase 1: 현재 상태 분석

  • 기존 ItemForm 디자인 완전 분석
    • 품목 유형 선택 UI
    • 기본 정보 섹션 레이아웃
    • BOM 섹션 레이아웃
    • 전개도 섹션 레이아웃
    • 버튼 위치 및 스타일
    • 밸리데이션 에러 표시 방식
  • 품목관리 API 응답 구조 확인 (init, pages.getStructure)

Phase 2: DynamicItemForm 폴더 생성

  • 기본 폴더 구조 생성
    src/components/items/DynamicItemForm/
    ├── index.tsx
    ├── types.ts
    ├── hooks/
    │   ├── index.ts
    │   ├── useFormStructure.ts
    │   └── useDynamicFormState.ts
    └── fields/
        ├── index.ts
        ├── TextField.tsx
        ├── DropdownField.tsx
        ├── NumberField.tsx
        ├── DateField.tsx
        ├── TextareaField.tsx
        ├── CheckboxField.tsx
        └── DynamicFieldRenderer.tsx
    

Phase 3: 타입 정의

  • types.ts - 동적 폼 관련 타입 정의
  • API 응답 타입과 프론트엔드 타입 매핑
  • SimpleUnitOption 타입 추가

Phase 4: 훅 구현

  • useFormStructure.ts - API에서 폼 구조 로드
  • useDynamicFormState.ts - 동적 상태 관리

Phase 5: 필드 컴포넌트 구현 (디자인 100% 동일)

  • TextField.tsx - 기존 Input 스타일 동일
  • DropdownField.tsx - 기존 Select 스타일 동일
  • NumberField.tsx - 기존 숫자 입력 스타일 동일
  • DateField.tsx - 기존 날짜 선택 스타일 동일
  • TextareaField.tsx - 기존 텍스트영역 스타일 동일
  • CheckboxField.tsx - 기존 체크박스 스타일 동일
  • DynamicFieldRenderer.tsx - 필드 타입별 렌더러

Phase 6: 메인 폼 컴포넌트

  • index.tsx - 메인 동적 폼 컴포넌트
    • 기존 ItemForm과 동일한 레이아웃
    • 동일한 헤더 스타일 (FormHeader 인라인)
    • 동일한 ValidationAlert 스타일
    • 동일한 섹션 Card 스타일
    • 동일한 버튼 배치

Phase 7: 기존 ItemForm 주석처리 및 전환

  • /items/create/page.tsx - DynamicItemForm으로 전환
  • 기존 ItemForm import 주석처리
  • 전환 테스트 준비

Phase 8: API 연동

  • POST /api/proxy/items 연동 구현
  • 품목 등록 후 목록 페이지 이동
  • 에러 처리

Phase 9: 테스트

  • TypeScript 빌드 검증 완료 (DynamicItemForm 에러 없음)
  • 품목 유형별 등록 테스트 (FG, PT, RM, SM, CS)
  • 밸리데이션 테스트
  • API 연동 테스트
  • 품목 목록에 등록된 데이터 표시 확인

테스트 가이드

사전 조건

  1. 백엔드 서버 실행 (sam-api)
  2. 프론트엔드 개발 서버 실행 (npm run dev)
  3. 품목기준관리에서 페이지/섹션/필드 설정 완료

테스트 항목

1. 품목 등록 페이지 접근

URL: http://localhost:3000/items/create
  • 페이지 로딩 시 "폼 구조를 불러오는 중..." 표시
  • 품목 유형 선택 전 안내 메시지 표시

2. 품목 유형 선택

  • FG (완제품) 선택 시 해당 폼 구조 로드
  • PT (부품) 선택 시 해당 폼 구조 로드
  • RM (원자재) 선택 시 해당 폼 구조 로드
  • SM (부자재) 선택 시 해당 폼 구조 로드
  • CS (소모품) 선택 시 해당 폼 구조 로드

3. 필드 렌더링

  • 텍스트 필드 정상 렌더링
  • 숫자 필드 정상 렌더링
  • 드롭다운 필드 정상 렌더링 (단위 옵션 포함)
  • 체크박스 필드 정상 렌더링
  • 날짜 필드 정상 렌더링
  • 텍스트영역 필드 정상 렌더링

4. 밸리데이션

  • 필수 필드 빈값 시 에러 메시지 표시
  • ValidationAlert에 에러 목록 표시
  • 에러 필드에 빨간 테두리 표시

5. API 연동

  • 저장 버튼 클릭 시 POST /api/proxy/items 호출
  • 저장 성공 시 /items 페이지로 이동
  • 저장 실패 시 에러 메시지 표시

6. 디자인 검증

  • 기존 ItemForm과 레이아웃 동일
  • 헤더 스타일 동일 (아이콘, 버튼 위치)
  • 섹션 Card 스타일 동일
  • 필드 라벨/에러 스타일 동일

생성된 파일

DynamicItemForm 컴포넌트

  • src/components/items/DynamicItemForm/index.tsx - 메인 폼 (388줄)
  • src/components/items/DynamicItemForm/types.ts - 타입 정의
  • src/components/items/DynamicItemForm/hooks/index.ts - 훅 export
  • src/components/items/DynamicItemForm/hooks/useFormStructure.ts - 폼 구조 로드
  • src/components/items/DynamicItemForm/hooks/useDynamicFormState.ts - 상태 관리
  • src/components/items/DynamicItemForm/fields/index.ts - 필드 export
  • src/components/items/DynamicItemForm/fields/TextField.tsx
  • src/components/items/DynamicItemForm/fields/NumberField.tsx
  • src/components/items/DynamicItemForm/fields/DropdownField.tsx
  • src/components/items/DynamicItemForm/fields/CheckboxField.tsx
  • src/components/items/DynamicItemForm/fields/DateField.tsx
  • src/components/items/DynamicItemForm/fields/TextareaField.tsx
  • src/components/items/DynamicItemForm/fields/DynamicFieldRenderer.tsx

수정된 파일

  • src/app/[locale]/(protected)/items/create/page.tsx - DynamicItemForm 사용으로 변경

API 흐름

1. useFormStructure(itemType)
   └─> itemMasterApi.init()
       └─> /api/proxy/item-master/init
           └─> pages, sections, fields, unitOptions 반환

2. itemMasterApi.pages.getStructure(pageId)
   └─> /api/proxy/item-master/pages/{id}/structure
       └─> page, sections, directFields 반환

3. 품목 등록
   └─> POST /api/proxy/items
       └─> body: DynamicFormData

디자인 매칭 요소

레이아웃

  • form > space-y-6
  • Card > CardHeader > CardTitle > CardContent
  • grid grid-cols-1 md:grid-cols-2 gap-4

필드 스타일

  • Label with required marker: <span className="text-red-500"> *</span>
  • Error state: className={error ? 'border-red-500' : ''}
  • Error message: <p className="text-xs text-red-500 mt-1">{error}</p>
  • Helper text: <p className="text-xs text-muted-foreground mt-1">* ...</p>

버튼 스타일

  • Cancel: variant="outline" size="sm"
  • Submit: size="sm" disabled={!selectedItemType || isSubmitting}
  • Icons: X, Save from lucide-react

변경 이력

날짜 작업 내용
2025-12-02 문서 생성, Phase 1 시작
2025-12-02 Phase 1-8 완료: DynamicItemForm 전체 구현