# 품목관리 세션 체크포인트

> 작성일: 2025-12-12
> 이전 세션: 2025-12-10
> 상태: ✅ 프론트엔드 작업 완료 (백엔드 API 대기)

---

## 🎯 오늘의 작업 목표

### 전개도 상세 입력 (폭 합계 연동) - ✅ 완료
### BOM 테이블 UI 수정 - ✅ 완료
### BOM 데이터 전송/로드 - ✅ 완료
### 파일 업로드 오류 수정 - ✅ 완료

---

## ✅ 완료된 작업

### 1. BOM API 연동 완료

**변경 사항**:
- `child_item_type` 필드 추가 (PRODUCT/MATERIAL 구분)
- BOM 저장 형식: `{ child_item_id, child_item_type, quantity }` 최소 필드만 저장
- 품목 유형 매핑: FG/PT → PRODUCT, SM/RM/CS → MATERIAL

**수정 파일**:
- `types.ts`: BOMLine에 `childItemType` 필드 추가
- `DynamicBOMSection.tsx`: `getChildItemType()` 헬퍼 함수 추가
- `index.tsx`: BOM 전송 형식 간소화

### 2. 수정 화면 BOM 로드 버그 수정

**문제**: `mapApiResponseToFormData`가 `bom`을 제외하여 `initialData`에 BOM이 없었음

**해결**: `initialBomLines` prop으로 BOM 데이터 별도 전달

**수정 파일**:
- `types.ts`: `DynamicItemFormProps`에 `initialBomLines?: BOMLine[]` 추가
- `edit/page.tsx`: API 응답에서 BOM 추출 → `initialBomLines` state → prop 전달
- `index.tsx`: `initialBomLines` prop 수신 → useEffect로 `setBomLines()` 호출

### 3. BOM key 값 중복 에러 수정

**문제**: BOM 항목에 id가 없을 때 빈 문자열로 key 중복 발생

**해결**: `page.tsx`의 `mapApiResponseToItemMaster`에서 fallback key 생성
```typescript
id: String(bomItem.id || bomItem.child_item_id || `bom-${index}`)
```

### 4. 이미지 업로드 500 에러 수정

**문제**: `bending_diagram`에 Base64 이미지 데이터가 JSON 본문에 포함되어 백엔드 500 에러

**해결**: API 호출 전 base64 이미지 데이터 제거 (파일은 별도 API로 업로드)

**수정 파일**:
- `edit/page.tsx`: base64 이미지 필드 제거 로직 추가
- `create/page.tsx`: 동일하게 적용

```typescript
// API 호출 전 이미지 데이터 제거
if (submitData.bending_diagram?.startsWith('data:')) delete submitData.bending_diagram;
if (submitData.specification_file?.startsWith('data:')) delete submitData.specification_file;
if (submitData.certification_file?.startsWith('data:')) delete submitData.certification_file;
```

### 5. bending_details 배열 전송 오류 수정

**문제**: `JSON.stringify()`로 문자열 전송 → 백엔드에서 "배열이어야 합니다" 오류

**해결**: PHP가 이해하는 배열 형태로 FormData 전송

**수정 파일**: `src/lib/api/items.ts`

```typescript
// 기존 (문자열)
formData.append('bending_details', JSON.stringify(options.bendingDetails));

// 수정 (배열 형태)
options.bendingDetails.forEach((detail, index) => {
  Object.entries(detail).forEach(([key, value]) => {
    formData.append(`bending_details[${index}][${key}]`, String(value));
  });
});
```

### 6. 제품 정보 섹션 빈 카드 숨김

**문제**: FG 품목 상세에서 "제품 정보" 섹션이 내용 없이 빈 카드로 표시

**해결**: 내용이 있을 때만 섹션 표시

**수정 파일**: `ItemDetailClient.tsx`

```typescript
// 기존
{item.itemType === 'FG' && (

// 수정
{item.itemType === 'FG' && (item.productCategory || item.lotAbbreviation || item.note) && (
```

---

## ⏳ 백엔드 대기 사항

### 1. 파일 다운로드 인증 문제 🔴

**현재 문제**:
- 파일 다운로드 URL(`/storage/{id}`)에 직접 접근 시 `"Unauthorized. Invalid or missing API key"` 에러
- 브라우저에서 `<a href="url">다운로드</a>` 클릭 시 API 키가 없어서 401 에러
- 시방서(PDF), 인정서(PDF), 전개도(이미지) 모두 동일한 문제

**수정 요청 옵션**:
1. **옵션 A (권장)**: Signed URL 방식 - 임시 토큰이 포함된 URL 생성 (만료 시간 설정)
2. **옵션 B**: 파일 다운로드 엔드포인트를 public으로 변경 (인증 불필요)
3. **옵션 C**: 프론트엔드 프록시 경유 (Next.js API route에서 API 키 추가)

### 2. 품목 조회 시 파일 URL 미반환 문제 🔴

**현재 문제**:
- `bending_diagram`, `specification_file`, `certification_file` 필드에 **file_id(숫자)**만 반환됨
- 프론트엔드에서 이미지/PDF를 표시하려면 **실제 다운로드 URL**이 필요
- 현재 file_id만 있어서 파일을 불러올 수 없음

**수정 요청**:
품목 조회 응답에서 file_id와 함께 실제 URL도 반환:

```json
{
  "id": 813,
  "bending_diagram": 123,
  "bending_diagram_url": "/api/v1/files/download/xxx",
  "specification_file": 456,
  "specification_file_url": "/api/v1/files/download/yyy",
  "certification_file": 789,
  "certification_file_url": "/api/v1/files/download/zzz"
}
```

---

## 🔄 코드 변경 요약

| 파일 | 변경 내용 |
|------|----------|
| `types.ts` | BOMLine에 `childItemType` 추가, DynamicItemFormProps에 `initialBomLines` 추가 |
| `DynamicBOMSection.tsx` | `getChildItemType()` 헬퍼 함수, 품목 선택 시 childItemType 설정 |
| `index.tsx` | BOM 전송 형식 간소화, initialBomLines prop 처리 |
| `edit/page.tsx` | initialBomLines 전달, base64 이미지 제거 로직 |
| `create/page.tsx` | base64 이미지 제거 로직 |
| `items/[id]/page.tsx` | BOM key fallback 처리 |
| `ItemDetailClient.tsx` | 제품 정보 섹션 조건부 표시 |
| `lib/api/items.ts` | bending_details 배열 형태로 전송 |

---

## 📋 다음 세션 TODO

### 백엔드 API 완료 후
- [ ] 파일 다운로드 URL 처리 (백엔드 응답 형식에 맞춰 적용)
- [ ] 전개도 이미지 표시 테스트
- [ ] 시방서/인정서 PDF 다운로드 테스트

### DynamicItemForm 분할 작업 🎯
- [ ] `index.tsx` 파일 분할 (현재 2000줄+ → 500줄 이하로)
- [ ] 섹션별 컴포넌트 분리:
  - `DynamicFormHeader.tsx` - 헤더/제목
  - `DynamicFormActions.tsx` - 저장/취소 버튼
  - `DynamicBendingSection.tsx` - 전개도 섹션 (기존)
  - `DynamicFileSection.tsx` - 파일 업로드 섹션
  - `useDynamicForm.ts` - 메인 로직 훅
- [ ] 상태 관리 정리 (props drilling 최소화)

### 파일 업로드 필드 동적화 🆕
> 참고: `[DESIGN-2025-12-12] item-master-form-builder-roadmap.md`

**현재 문제**:
- 파일 업로드가 `FileUpload.tsx`로 하드코딩되어 있음
- 품목기준관리에서 파일 필드를 동적으로 추가할 수 없음

**목표**:
- 새 필드 타입 `file`, `files`, `image` 추가
- 품목기준관리에서 파일 업로드 필드 동적 생성 가능

**구현 작업**:
- [ ] `field_type`에 `file` | `files` | `image` 타입 추가 (API 스키마)
- [ ] `FileField.tsx` 컴포넌트 생성 (DynamicItemForm/fields/)
- [ ] `ImageField.tsx` 컴포넌트 생성 (미리보기 포함)
- [ ] `DynamicFieldRenderer.tsx`에 file/image 케이스 추가
- [ ] `properties` 확장: `{ accept, maxSize, maxFiles }`
- [ ] 품목기준관리 UI에 파일 필드 타입 옵션 추가
- [ ] 기존 하드코딩된 FileUpload 컴포넌트 동적 필드로 마이그레이션

---

## 📚 관련 문서

| 문서 | 위치 |
|------|------|
| 이전 세션 컨텍스트 | `[NEXT-2025-12-10] item-crud-session-context.md` |
| DynamicForm 분리 계획 | `[PLAN-2025-12-08] dynamic-form-separation-plan.md` |
| Radix UI 버그 해결 | `claudedocs/guides/[FIX-2025-12-05] radix-ui-select-controlled-mode-bug.md` |