# 품목관리 데이터 누락 조사 체크리스트

품목기준관리 데이터 기반 품목관리 등록/수정 시 데이터 매핑 분석

## 조사 방법
- **프론트엔드 → 백엔드**: DynamicItemForm submit 데이터 분석
- **백엔드 → 프론트엔드**: API 응답 → Edit 페이지 데이터 매핑 분석
- **DB 필드**: Material/Product 모델 fillable 필드 확인

---

## 1. 소모품 (SM - Supplies Material)

### 사용 모델: `Material`

### Material 모델 fillable 필드
| 필드명 | 타입 | 필수 | 설명 |
|--------|------|------|------|
| tenant_id | int | Y | 테넌트 ID |
| category_id | int | N | 분류 ID |
| name | string | Y | 품목명 |
| item_name | string | N | 품목명 (레거시) |
| specification | string | N | 규격 |
| material_code | string | Y | 품목코드 |
| material_type | string | Y | SM/RM/CS |
| unit | string | Y | 단위 |
| is_inspection | string | N | 검사 여부 |
| search_tag | string | N | 검색 태그 |
| remarks | string | N | 비고 |
| attributes | json | N | 동적 속성 |
| options | json | N | 옵션 배열 |
| created_by | int | N | 생성자 |
| updated_by | int | N | 수정자 |
| is_active | bool | N | 활성 상태 |

### 등록 시 데이터 매핑 체크리스트

#### 프론트엔드 → 백엔드
| 프론트엔드 필드 | 백엔드 필드 | 변환 함수 | 상태 | 비고 |
|----------------|------------|----------|------|------|
| - [ ] item_name / 품목명 | name | fieldKeyToBackendKey | | |
| - [ ] specification / 규격 | specification | standard_* → options + specification | | convertStandardFieldsToOptions() |
| - [ ] unit / 단위 | unit | fieldKeyToBackendKey | | |
| - [ ] note / 비고 | remarks | transformMaterialDataForSave | | note → remarks |
| - [ ] is_active / 상태 | is_active | boolean 변환 | | |
| - [ ] code (자동생성) | material_code | transformMaterialDataForSave | | name-specification |
| - [ ] product_type | material_type | transformMaterialDataForSave | | |
| - [ ] standard_* | options | convertStandardFieldsToOptions | | 배열로 변환 |

#### 백엔드 → 프론트엔드 (수정 시)
| 백엔드 필드 | 프론트엔드 필드 | 변환 위치 | 상태 | 비고 |
|------------|----------------|----------|------|------|
| - [ ] name | item_name | mapApiResponseToFormData | | |
| - [ ] specification | specification | mapApiResponseToFormData | | |
| - [ ] unit | unit | mapApiResponseToFormData | | |
| - [ ] remarks | note | mapApiResponseToFormData | | remarks → note |
| - [ ] is_active | is_active | mapApiResponseToFormData | | |
| - [ ] material_code | (참조만) | - | | 품목코드는 수정 불가 |
| - [ ] material_type | (참조만) | - | | 품목유형은 수정 불가 |
| - [ ] options | standard_* | convertOptionsToStandardFields | | 배열 → 개별 필드 |

### API 엔드포인트
- **등록**: POST `/api/v1/items` → ItemsService.createMaterial()
- **조회**: GET `/api/v1/items/{id}?item_type=MATERIAL`
- **수정**: PATCH `/api/v1/products/materials/{id}`

### 누락 가능성 분석
- [ ] **options 필드 로드 확인**: Edit 시 options 배열이 standard_* 필드로 정상 변환되는지
- [ ] **specification 생성 로직**: 등록 시 standard_* 값들이 specification으로 조합되는지
- [ ] **material_code 자동생성**: name-specification 형식으로 생성되는지
- [ ] **is_inspection 필드**: 프론트엔드에 검사여부 필드가 있는지

---

## 2. 원자재 (RM - Raw Material)

### 사용 모델: `Material` (SM과 동일)

### 등록/수정 데이터 매핑 (SM과 동일)
- SM과 동일한 Material 모델 사용
- material_type = 'RM'

### 원자재 특화 필드 체크리스트
| 프론트엔드 필드 | 백엔드 필드 | 상태 | 비고 |
|----------------|------------|------|------|
| - [ ] 분류 선택 (드롭다운) | category_id | | 원자재 카테고리 |
| - [ ] 규격 옵션들 (standard_*) | options | | 원자재별 규격 옵션 |

### 누락 가능성 분석
- [ ] **category_id 매핑**: 분류 선택이 제대로 저장되는지
- [ ] **원자재별 옵션 구조**: 품목기준관리에서 정의한 standard_1~N 필드들

---

## 3. 부자재 (CS - Consumable Supplies)

### 사용 모델: `Material` (SM, RM과 동일)

### 등록/수정 데이터 매핑 (SM과 동일)
- material_type = 'CS'

### 부자재 특화 필드 체크리스트
| 프론트엔드 필드 | 백엔드 필드 | 상태 | 비고 |
|----------------|------------|------|------|
| - [ ] 규격 옵션들 (standard_*) | options | | 부자재별 규격 옵션 |

### 누락 가능성 분석
- [ ] SM/RM과 동일한 구조 사용 확인

---

## 4. 조립부품 (PT - Assembly)

### 사용 모델: `Product`

### Product 모델 fillable 필드
| 필드명 | 타입 | 필수 | 설명 |
|--------|------|------|------|
| tenant_id | int | Y | 테넌트 ID |
| code | string | Y | 품목코드 |
| name | string | Y | 품목명 |
| unit | string | Y | 단위 |
| category_id | int | N | 분류 ID |
| product_type | string | Y | FG/PT |
| attributes | json | N | 동적 속성 |
| description | string | N | 설명 |
| is_sellable | bool | N | 판매가능 |
| is_purchasable | bool | N | 구매가능 |
| is_producible | bool | N | 생산가능 |
| safety_stock | int | N | 안전재고 |
| lead_time | int | N | 리드타임 |
| is_variable_size | bool | N | 가변사이즈 |
| product_category | string | N | 제품분류 |
| **part_type** | string | N | 부품유형 (ASSEMBLY/BENDING/PURCHASED) |
| bending_diagram | string | N | 전개도 경로 |
| bending_details | json | N | 절곡 상세 |
| specification_file | string | N | 시방서 경로 |
| certification_file | string | N | 인정서 경로 |
| is_active | bool | N | 활성 상태 |

### 조립부품 특화 필드 체크리스트

#### 프론트엔드 → 백엔드
| 프론트엔드 필드 | 백엔드 필드 | 변환 | 상태 | 비고 |
|----------------|------------|------|------|------|
| - [ ] 품목명 (드롭다운 선택) | name | autoAssemblyItemName | | "품목명 가로x세로" 형식 |
| - [ ] 측면규격(가로) | (attributes?) | | | side_spec_width |
| - [ ] 측면규격(세로) | (attributes?) | | | side_spec_height |
| - [ ] 길이 | (attributes?) | | | assembly_length |
| - [ ] 규격 (자동생성) | spec/description | autoAssemblySpec | | "가로x세로x길이" 형식 |
| - [ ] 품목코드 (자동생성) | code | autoGeneratedItemCode | | 영문약어-순번 |
| - [ ] 단위 | unit | | | |
| - [ ] 비고 | note/description | | | |
| - [ ] 품목상태 | is_active | | | |
| - [ ] 전개도 이미지 | bending_diagram | uploadItemFile() | | 파일 업로드 |
| - [ ] BOM 구성 | bom[] | | | 자재명세서 |

#### 백엔드 → 프론트엔드 (수정 시)
| 백엔드 필드 | 프론트엔드 필드 | 상태 | 비고 |
|------------|----------------|------|------|
| - [ ] name | item_name | | |
| - [ ] code | (참조만) | | 품목코드 |
| - [ ] part_type | part_type | | ASSEMBLY |
| - [ ] side_spec_width | 측면규격(가로) | | attributes에서? |
| - [ ] side_spec_height | 측면규격(세로) | | attributes에서? |
| - [ ] assembly_length | 길이 | | attributes에서? |
| - [ ] is_active | is_active | | |
| - [ ] bending_diagram | bending_diagram | | 기존 전개도 URL |

### 누락 가능성 분석
- [ ] **측면규격 가로/세로 필드**: 백엔드에서 별도 컬럼으로 저장되는지 vs attributes JSON
- [ ] **길이 필드**: assembly_length 저장 여부
- [ ] **전개도 이미지 로드**: Edit 시 기존 이미지 표시
- [ ] **BOM 데이터 로드**: component_lines 관계 로드 확인

---

## 5. 절곡부품 (PT - Bending)

### 사용 모델: `Product` (조립부품과 동일)

### 절곡부품 특화 필드 체크리스트

#### 프론트엔드 → 백엔드
| 프론트엔드 필드 | 백엔드 필드 | 변환 | 상태 | 비고 |
|----------------|------------|------|------|------|
| - [ ] 품목명 (드롭다운 선택) | name | | | bendingFieldKeys.itemName |
| - [ ] 재질 | (attributes?) | | | bendingFieldKeys.material |
| - [ ] 종류 | (attributes?) | | | bendingFieldKeys.category |
| - [ ] 폭 합계 | width_sum | | | bendingFieldKeys.widthSum |
| - [ ] 모양&길이 | (attributes?) | | | bendingFieldKeys.shapeLength |
| - [ ] 품목코드 (자동생성) | code | autoBendingItemCode | | "품목명+종류+모양길이" |
| - [ ] 단위 | unit | | | |
| - [ ] 비고 | note | | | |
| - [ ] 전개도 이미지 | bending_diagram | uploadItemFile() | | |
| - [ ] 절곡 상세 | bending_details | | | [{angle, length, type}] |

#### 백엔드 → 프론트엔드 (수정 시)
| 백엔드 필드 | 프론트엔드 필드 | 상태 | 비고 |
|------------|----------------|------|------|
| - [ ] name | item_name | | |
| - [ ] part_type | part_type | | BENDING |
| - [ ] bending_diagram | bending_diagram | | 전개도 URL |
| - [ ] bending_details | bendingDetails | | 절곡 상세 배열 |
| - [ ] width_sum | widthSum | | |
| - [ ] is_active | is_active | | |

### 누락 가능성 분석
- [ ] **재질/종류/모양길이 필드**: 저장 위치 (별도 컬럼 vs attributes)
- [ ] **절곡 상세 데이터**: bending_details JSON 저장 및 로드
- [ ] **전개도 파일 업로드**: 파일 경로 저장 확인

---

## 6. 구매부품 (PT - Purchased)

### 사용 모델: `Product` (조립/절곡부품과 동일)

### 구매부품 특화 필드 체크리스트

#### 프론트엔드 → 백엔드
| 프론트엔드 필드 | 백엔드 필드 | 변환 | 상태 | 비고 |
|----------------|------------|------|------|------|
| - [ ] 품목명 (전동개폐기 등) | name | | | purchasedFieldKeys.itemName |
| - [ ] 용량 | (attributes?) | | | purchasedFieldKeys.capacity |
| - [ ] 전원 | (attributes?) | | | purchasedFieldKeys.power |
| - [ ] 품목코드 (자동생성) | code | autoPurchasedItemCode | | "품목명+용량+전원" |
| - [ ] 단위 | unit | | | |
| - [ ] 비고 | note | | | |

#### 백엔드 → 프론트엔드 (수정 시)
| 백엔드 필드 | 프론트엔드 필드 | 상태 | 비고 |
|------------|----------------|------|------|
| - [ ] name | item_name | | |
| - [ ] part_type | part_type | | PURCHASED |
| - [ ] capacity | 용량 | | attributes에서? |
| - [ ] power | 전원 | | attributes에서? |
| - [ ] is_active | is_active | | |

### 누락 가능성 분석
- [ ] **용량/전원 필드**: 저장 위치 (별도 컬럼 vs attributes)
- [ ] **품목코드 자동생성**: "전동개폐기150KG380V" 형식 확인

---

## 7. 제품 (FG - Finished Goods)

### 사용 모델: `Product`

### 제품 특화 필드 체크리스트

#### 프론트엔드 → 백엔드
| 프론트엔드 필드 | 백엔드 필드 | 변환 | 상태 | 비고 |
|----------------|------------|------|------|------|
| - [ ] 품목명 | name | | | productName 필드 |
| - [ ] 품목코드 | code | = name | | 품목명이 품목코드 |
| - [ ] 제품분류 | product_category | | | |
| - [ ] 로트약어 | lot_abbreviation | | | |
| - [ ] 인정번호 | certification_number | | | |
| - [ ] 인정유효기간 시작 | certification_start_date | | | |
| - [ ] 인정유효기간 종료 | certification_end_date | | | |
| - [ ] 시방서 파일 | specification_file | uploadItemFile() | | |
| - [ ] 인정서 파일 | certification_file | uploadItemFile() | | |
| - [ ] 단위 | unit | 기본값 'EA' | | |
| - [ ] BOM 구성 | bom[] | | | |
| - [ ] 품목상태 | is_active | | | |

#### 백엔드 → 프론트엔드 (수정 시)
| 백엔드 필드 | 프론트엔드 필드 | 상태 | 비고 |
|------------|----------------|------|------|
| - [ ] name | item_name | | |
| - [ ] code | (참조만) | | |
| - [ ] product_category | product_category | | |
| - [ ] lot_abbreviation | lot_abbreviation | | |
| - [ ] certification_number | certification_number | | |
| - [ ] certification_start_date | certification_start_date | | |
| - [ ] certification_end_date | certification_end_date | | |
| - [ ] specification_file | specification_file | | 기존 시방서 URL |
| - [ ] specification_file_name | specification_file_name | | 파일명 |
| - [ ] certification_file | certification_file | | 기존 인정서 URL |
| - [ ] certification_file_name | certification_file_name | | 파일명 |
| - [ ] is_active | is_active | | |

### 누락 가능성 분석
- [ ] **인정서 관련 필드**: certification_* 필드들 저장 확인
- [ ] **시방서/인정서 파일**: Edit 시 기존 파일 표시 및 다운로드
- [ ] **BOM 데이터 로드**: 제품의 component_lines 관계 로드

---

## 공통 이슈 체크리스트

### 1. 필드명 매핑 이슈
- [ ] `note` vs `remarks`: Material은 remarks, Product는 description/note
- [ ] `is_active` boolean 변환: "활성"/"비활성" vs true/false
- [ ] field_key 형식: "{id}_{fieldName}" → 백엔드 필드명 변환

### 2. 동적 필드 저장 방식
- [ ] **attributes JSON**: 품목기준관리에서 정의한 추가 필드들이 attributes에 저장되는지
- [ ] **options JSON**: Material의 standard_* 필드들이 options 배열로 저장되는지

### 3. 파일 업로드
- [ ] 품목 저장 후 파일 업로드 순서
- [ ] Edit 시 기존 파일 표시
- [ ] 파일 삭제 기능

### 4. API 엔드포인트 일관성
- Material(SM, RM, CS):
  - 등록: POST `/api/v1/items`
  - 조회: GET `/api/v1/items/{id}?item_type=MATERIAL`
  - 수정: PATCH `/api/v1/products/materials/{id}` ⚠️ 경로 불일치

- Product(FG, PT):
  - 등록: POST `/api/v1/items`
  - 조회: GET `/api/v1/items/code/{code}?include_bom=true`
  - 수정: PUT `/api/v1/items/{id}`

---

## 조사 진행 상황

### 소모품 (SM) - 진행중
- [x] 모델 구조 분석
- [x] API 엔드포인트 확인
- [ ] 등록 데이터 흐름 테스트
- [ ] 수정 데이터 흐름 테스트
- [ ] 누락 필드 식별

### 원자재 (RM) - 대기
- [ ] 등록/수정 테스트
- [ ] SM과 차이점 확인

### 부자재 (CS) - 대기
- [ ] 등록/수정 테스트
- [ ] SM과 차이점 확인

### 조립부품 (PT-Assembly) - 대기
- [ ] 특화 필드 저장 위치 확인
- [ ] 등록/수정 테스트

### 절곡부품 (PT-Bending) - 대기
- [ ] 특화 필드 저장 위치 확인
- [ ] 전개도 업로드 테스트

### 구매부품 (PT-Purchased) - 대기
- [ ] 특화 필드 저장 위치 확인
- [ ] 등록/수정 테스트

### 제품 (FG) - 대기
- [ ] 인정서 관련 필드 확인
- [ ] 파일 업로드 테스트

---

## 발견된 이슈

### 이슈 #1: Material is_active 필드 누락
- **품목유형**: SM, RM, CS (Material 타입 전체)
- **현상**: 등록/수정 시 품목 상태(is_active) 필드가 백엔드로 전달되지 않음
- **원인**:
  1. `ItemsService.createMaterial()`에서 is_active 설정 O
  2. `MaterialService.setMaterial()`에서는 is_active 필드가 validation rules에 없음
  3. 프론트엔드 `transformMaterialDataForSave()`에서 is_active를 별도 처리하지 않음
- **해결방안**:
  - 백엔드: `MaterialService` validation rules에 `'is_active' => 'nullable|boolean'` 추가
  - 또는 프론트엔드에서 `/api/v1/items` 엔드포인트 사용 (이미 is_active 지원)
- **우선순위**: 🔴 높음

### 이슈 #2: Material 수정 API 경로 불일치
- **품목유형**: SM, RM, CS
- **현상**: 등록은 `/api/v1/items`, 수정은 `/api/v1/products/materials/{id}` 사용
- **원인**: 두 개의 다른 서비스 (`ItemsService` vs `MaterialService`)가 Material 처리
- **영향**:
  - `ItemsService.createMaterial()`: is_active, material_type 필드 처리 O
  - `MaterialService.updateMaterial()`: is_active 필드 validation 없음, material_type 변경 불가
- **해결방안**:
  - 통합: 수정도 `/api/v1/items/{id}` 사용하도록 프론트엔드 수정
  - 또는 백엔드: `MaterialService.updateMaterial()`에 is_active 필드 추가
- **우선순위**: 🟡 중간

### 이슈 #3: PT(부품) 특화 필드 저장 위치 불명확
- **품목유형**: PT (조립/절곡/구매 부품)
- **현상**: 측면규격, 용량, 전원 등 부품별 특화 필드가 어디에 저장되는지 불명확
- **원인**:
  - Product 모델에 `side_spec_width`, `side_spec_height`, `assembly_length` 등 컬럼 없음
  - `attributes` JSON에 저장되어야 하나, 프론트엔드에서 attributes 변환 로직 부재
- **영향**: 부품 수정 시 특화 필드 값이 유실될 수 있음
- **해결방안**:
  1. 백엔드: Product 모델에 부품 특화 필드 컬럼 추가 (마이그레이션)
  2. 또는: 프론트엔드에서 특화 필드를 `attributes` JSON으로 변환하여 저장
- **우선순위**: 🔴 높음

### 이슈 #4: BOM 데이터 저장 로직 누락
- **품목유형**: FG, PT (조립부품)
- **현상**: 프론트엔드에서 BOM 라인을 폼에 입력하지만 저장 시 무시됨
- **원인**:
  - `ItemsService.createProduct()`에서 `bom` 배열 처리 로직 없음
  - `ProductComponent` 모델에 데이터 생성하는 코드 부재
- **영향**: BOM 구성품 정보가 저장되지 않음
- **해결방안**:
  - 백엔드: `ItemsService.createProduct()` 후 `ProductComponent` 레코드 생성 로직 추가
  - 별도 API: `/api/v1/items/{id}/bom` 엔드포인트로 BOM 저장
- **우선순위**: 🔴 높음

### 이슈 #5: 품목기준관리 동적 필드와 백엔드 필드 불일치
- **품목유형**: 전체
- **현상**: 품목기준관리에서 정의한 필드가 백엔드 모델에 대응 컬럼이 없음
- **예시**:
  - 품목기준관리: `107_재질`, `108_종류`, `109_폭합계` 등
  - 백엔드 Product 모델: 해당 컬럼 없음
- **원인**: 동적 필드 구조 vs 고정 스키마 불일치
- **해결방안**:
  1. 동적 필드는 `attributes` JSON에 저장
  2. 프론트엔드: 품목기준관리 field_key를 `attributes[field_key]` 형태로 변환
  3. 백엔드: `attributes` 필드에서 동적 값 저장/조회 지원
- **우선순위**: 🔴 높음

### 이슈 #6: Material options 필드 Edit 시 로드 확인 필요
- **품목유형**: SM, RM, CS
- **현상**: 등록 시 standard_* → options 변환은 되지만, Edit 시 역변환 확인 필요
- **확인사항**:
  - `mapApiResponseToFormData()`에서 options → standard_* 변환 로직 있음 (line 123-129)
  - 하지만 Material API 응답에서 options가 제대로 포함되는지 확인 필요
- **해결방안**: 실제 데이터로 테스트 필요
- **우선순위**: 🟢 낮음

---

## 권장 조치사항

### 즉시 조치 (우선순위 높음)
1. **이슈 #1 해결**: `MaterialService.setMaterial()`과 `updateMaterial()`에 `is_active` validation 추가
2. **이슈 #3 해결**: PT 부품 특화 필드 저장 방식 결정
   - Option A: DB 마이그레이션으로 컬럼 추가
   - Option B: attributes JSON 활용
3. **이슈 #4 해결**: BOM 저장 API 구현

### 중기 조치 (우선순위 중간)
4. **이슈 #2 해결**: Material 등록/수정 API 일관성 확보
5. **이슈 #5 해결**: 동적 필드 ↔ attributes 매핑 체계 구축

### 테스트 필요
6. **이슈 #6 확인**: 실제 데이터로 Material Edit 플로우 테스트

---

## 다음 단계

- [ ] 각 이슈별 수정 작업 진행
- [ ] 실제 데이터로 등록/수정 흐름 테스트
- [ ] 누락된 필드 추가 발견 시 문서 업데이트
