# 품목관리 페이지 전체 API 요청서

## 작업 일자: 2025-11-28

## 문서 버전
| 버전 | 날짜 | 작성자 | 내용 |
|------|------|--------|------|
| 1.0 | 2025-11-28 | Claude | 초안 작성 (동적 렌더링만) |
| 2.0 | 2025-11-28 | Claude | 전체 CRUD + 리스트 + 페이징 추가 |
| 3.0 | 2025-11-28 | Claude | 백엔드 스키마/기존 API 기반 재검토 |
| 3.1 | 2025-11-28 | Claude | **ID 기반으로 통일** (백엔드 결정 반영) |

---

## 🔴 백엔드 검토 결과 요약

### 기존 API와의 정합성 분석 (v3.1 - ID 기반 통일)

| 항목 | 최종 결정 | 비고 |
|------|----------|------|
| 품목 수정/삭제 | `/{id}` (ID 기반) | ✅ **ID 기반으로 통일** |
| 품목 조회 | `item_type` 파라미터 선택 | 서버에서 자동 감지 가능 |
| 페이징 파라미터 | `size` | 기존 백엔드 컨벤션 유지 |
| item-master init | 기존 API 활용 | `ItemMasterService@init` |
| BOM API | `/items/{id}/bom` | ✅ **ID 기반으로 통일** |
| 파일 API | `/files/upload` | 별도 파일 API |
| 테넌트 격리 | `tenant_id` 자동 | 서버 자동 처리 |

### 주요 백엔드 아키텍처 특성 (반영 필요)

```yaml
multi_tenancy:
  - 모든 테이블에 tenant_id 필수
  - BelongsToTenant 글로벌 스코프 적용
  - API 레벨에서 자동 격리 (클라이언트 처리 불필요)

soft_delete:
  - deleted_at, deleted_by 컬럼 사용
  - 삭제 시 실제 삭제가 아닌 soft delete

audit_columns:
  - created_by, updated_by, deleted_by
  - 사용자 추적 자동 처리

api_response_format:
  success: true/false
  data: {} | []
  message: string (i18n key)
```

---

## 작업 체크리스트

### Phase 1: 분석 단계
- [x] 품목기준관리 API 저장/수정/삭제 검토
- [x] 현재 품목관리 페이지 구조 분석
- [x] 품목기준관리 저장 데이터 구조 확인
- [x] 품목관리 리스트/상세/등록/수정 페이지 분석

### Phase 2: 설계 단계
- [x] 품목 리스트 API (페이징, 필터, 검색)
- [x] 품목 CRUD API (생성, 조회, 수정, 삭제)
- [x] 동적 페이지 렌더링 API
- [x] BOM 관리 API
- [x] 파일 업로드 API
- [x] 통계/대시보드 API

### Phase 3: 검토 단계 ✅ 완료
- [x] 백엔드 DB 스키마 검토 (`database-schema.md`)
- [x] 기존 item-master-spec 검토 (`item-master-spec.md`)
- [x] sam-api 기존 API 구조 확인 (`api.php`, Controllers)
- [x] API 스펙 정합성 조정

### Phase 4: 확정 단계
- [ ] 백엔드 팀 최종 리뷰
- [ ] API 스펙 확정
- [ ] 프론트엔드 연동 테스트

---

## 1. 개요

### 1.1 목적
품목관리 페이지(`/items/*`)에서 필요한 **모든 API**를 정의합니다:
- 품목 목록 조회 (페이징, 필터, 검색)
- 품목 CRUD (생성, 조회, 수정, 삭제)
- 동적 폼 렌더링 (품목기준관리 연동)
- BOM 관리
- 파일 업로드/다운로드
- 통계 정보

### 1.2 관련 페이지
| 경로 | 페이지 | 필요 API |
|------|--------|----------|
| `/items` | 품목 목록 | 리스트, 검색, 필터, 페이징, 통계, 삭제 |
| `/items/create` | 품목 등록 | 동적 폼 구조, 생성, BOM 검색, 파일 업로드 |
| `/items/[id]` | 품목 상세 | 단건 조회, BOM 조회 |
| `/items/[id]/edit` | 품목 수정 | 단건 조회, 수정, BOM 관리, 파일 업로드 |

---

## 2. 품목 목록 API (List)

### API 2.1: 품목 목록 조회 (페이징)

> ⚠️ **기존 API 존재**: `ItemsController@index` - 파라미터명 조정 필요

```
GET /api/v1/items
```

**Query Parameters** (기존 백엔드 기준):
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|----------|------|------|--------|------|
| page | number | N | 1 | 페이지 번호 |
| size | number | N | 20 | 페이지당 항목 수 (기존: `size`, 변경 금지) |
| type | string | N | - | 품목유형 필터 (FG, PT, SM, RM, CS) |
| search | string | N | - | 검색어 (품목코드, 품목명) |
| q | string | N | - | 검색어 (search와 동일, 호환용) |
| category_id | number | N | - | 카테고리 ID 필터 |
| is_active | boolean | N | - | 활성 상태 필터 **(신규 요청)** |
| sort_by | string | N | created_at | 정렬 기준 **(신규 요청)** |
| sort_order | string | N | desc | 정렬 순서 **(신규 요청)** |

**Request Example**:
```
GET /api/v1/items?page=1&size=20&type=FG&search=스크린
```

**Response**:
```json
{
  "success": true,
  "data": {
    "items": [
      {
        "id": 1,
        "item_code": "KD-FG-001",
        "item_name": "스크린 제품 A",
        "item_type": "FG",
        "unit": "EA",
        "specification": "2000x2000",
        "is_active": true,
        "category1": "본체부품",
        "category2": "가이드시스템",
        "sales_price": 150000,
        "purchase_price": 100000,
        "product_category": "SCREEN",
        "current_revision": 0,
        "is_final": false,
        "created_at": "2025-01-10T00:00:00Z",
        "updated_at": "2025-01-10T00:00:00Z"
      }
    ],
    "pagination": {
      "current_page": 1,
      "per_page": 20,
      "total_items": 150,
      "total_pages": 8,
      "has_next": true,
      "has_prev": false
    }
  }
}
```

---

### API 2.2: 품목 통계 조회

> 🆕 **신규 API 요청**

```
GET /api/v1/items/stats
```

**Response**:
```json
{
  "success": true,
  "data": {
    "total_count": 500,
    "by_item_type": {
      "FG": 50,
      "PT": 200,
      "SM": 100,
      "RM": 100,
      "CS": 50
    },
    "active_count": 450,
    "inactive_count": 50
  },
  "message": "message.fetched"
}
```

---

### API 2.3: 품목 검색 (BOM용 자동완성)
```
GET /api/v1/items/search
```

**Query Parameters**:
| 파라미터 | 타입 | 필수 | 설명 |
|----------|------|------|------|
| q | string | Y | 검색어 (최소 2자) |
| item_type | string | N | 품목유형 필터 (복수 가능: PT,SM) |
| limit | number | N | 결과 개수 제한 (기본 10, 최대 50) |

**Request Example**:
```
GET /api/v1/items/search?q=가이드&item_type=PT&limit=10
```

**Response**:
```json
{
  "success": true,
  "data": [
    {
      "id": 2,
      "item_code": "KD-PT-001",
      "item_name": "가이드레일(벽면형)",
      "item_type": "PT",
      "unit": "EA",
      "specification": "2438mm",
      "sales_price": 50000
    }
  ]
}
```

---

## 3. 품목 CRUD API

### API 3.1: 품목 단건 조회 (ID 기반)

> ⚠️ **기존 API 존재**: `ItemsController@show` - `item_type` 파라미터 필수

```
GET /api/v1/items/{id}
```

**Path Parameters**:
| 파라미터 | 타입 | 필수 | 설명 |
|----------|------|------|------|
| id | number | Y | 품목 ID |

**Query Parameters** (기존 백엔드 기준):
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|----------|------|------|--------|------|
| item_type | string | Y | PRODUCT | 품목 유형 (PRODUCT, MATERIAL) |
| include_price | boolean | N | false | 가격 정보 포함 여부 |
| client_id | number | N | - | 고객별 가격 조회 시 |
| price_date | string | N | - | 가격 기준일 (YYYY-MM-DD) |

### API 3.1.1: 품목 단건 조회 (Code 기반)

> ✅ **기존 API 존재**: `ItemsController@showByCode`

```
GET /api/v1/items/code/{code}
```

**Path Parameters**:
| 파라미터 | 타입 | 필수 | 설명 |
|----------|------|------|------|
| code | string | Y | 품목 코드 (예: KD-FG-001) |

**Query Parameters**:
| 파라미터 | 타입 | 필수 | 설명 |
|----------|------|------|------|
| include_bom | boolean | N | BOM 정보 포함 여부 |

**Response**:
```json
{
  "success": true,
  "data": {
    "id": 1,
    "item_code": "KD-FG-001",
    "item_name": "스크린 제품 A",
    "item_type": "FG",
    "unit": "EA",
    "specification": "2000x2000",
    "is_active": true,
    "product_category": "SCREEN",
    "lot_abbreviation": "KD",

    "category1": "본체부품",
    "category2": "가이드시스템",
    "category3": null,

    "purchase_price": 100000,
    "sales_price": 150000,
    "margin_rate": 50,
    "processing_cost": 10000,
    "labor_cost": 5000,
    "install_cost": 3000,

    "certification_number": "인정번호-001",
    "certification_start_date": "2025-01-01",
    "certification_end_date": "2028-01-01",
    "specification_file": "/files/spec-001.pdf",
    "specification_file_name": "시방서.pdf",
    "certification_file": "/files/cert-001.pdf",
    "certification_file_name": "인정서.pdf",
    "note": "비고 내용",

    "current_revision": 0,
    "is_final": false,
    "finalized_date": null,
    "finalized_by": null,

    "bom": [
      {
        "id": 1,
        "child_item_code": "KD-PT-001",
        "child_item_name": "가이드레일(벽면형)",
        "quantity": 2,
        "unit": "EA",
        "unit_price": 50000,
        "quantity_formula": "H / 1000",
        "note": "높이에 따라 수량 변동"
      }
    ],

    "revisions": [],
    "created_at": "2025-01-10T00:00:00Z",
    "updated_at": "2025-01-10T00:00:00Z",
    "created_by": 1,
    "updated_by": 1
  }
}
```

---

### API 3.2: 품목 생성
```
POST /api/v1/items
```

**Request Body**:
```json
{
  "item_type": "FG",
  "item_name": "스크린 제품 신규",
  "unit": "EA",
  "specification": "2500x2500",
  "is_active": true,
  "product_category": "SCREEN",
  "lot_abbreviation": "KD",

  "category1": "본체부품",
  "category2": "가이드시스템",

  "purchase_price": 120000,
  "sales_price": 180000,

  "certification_number": "인정번호-002",
  "certification_start_date": "2025-01-01",
  "certification_end_date": "2028-01-01",
  "note": "신규 제품",

  "bom": [
    {
      "child_item_id": 2,
      "quantity": 2,
      "unit": "EA",
      "quantity_formula": "H / 1000",
      "note": "높이에 따라 수량 변동"
    }
  ]
}
```

**Response**:
```json
{
  "success": true,
  "data": {
    "id": 10,
    "item_code": "KD-FG-010",
    "item_name": "스크린 제품 신규",
    "message": "품목이 성공적으로 생성되었습니다."
  }
}
```

---

### API 3.3: 품목 수정

> ⚠️ **기존 API 존재**: `ItemsController@update` - **ID 기반 경로**

```
PUT /api/v1/items/{id}
```

**Path Parameters**:
| 파라미터 | 타입 | 필수 | 설명 |
|----------|------|------|------|
| id | number | Y | 품목 ID |

**Request Body**: (생성과 동일, 변경할 필드만 전송)
```json
{
  "item_name": "스크린 제품 A (수정)",
  "sales_price": 160000,
  "note": "가격 조정됨",
  "bom": [
    {
      "id": 1,
      "quantity": 3
    },
    {
      "child_item_id": 5,
      "quantity": 10,
      "unit": "EA"
    }
  ]
}
```

**Response**:
```json
{
  "success": true,
  "data": {
    "id": 1,
    "item_code": "KD-FG-001",
    "message": "품목이 성공적으로 수정되었습니다."
  }
}
```

---

### API 3.4: 품목 삭제

> ⚠️ **기존 API 존재**: `ItemsController@destroy` - **ID 기반 경로**

```
DELETE /api/v1/items/{id}
```

**Path Parameters**:
| 파라미터 | 타입 | 필수 | 설명 |
|----------|------|------|------|
| id | number | Y | 품목 ID |

**Response**:
```json
{
  "success": true,
  "data": {
    "message": "품목이 성공적으로 삭제되었습니다."
  }
}
```

**Error Response** (사용 중인 품목):
```json
{
  "success": false,
  "error": {
    "code": "ITEM_IN_USE",
    "message": "해당 품목은 다른 BOM에서 사용 중이므로 삭제할 수 없습니다.",
    "details": {
      "used_in": [
        {"item_code": "KD-FG-001", "item_name": "스크린 제품 A"}
      ]
    }
  }
}
```

---

### API 3.5: 품목 일괄 삭제

> 🆕 **신규 API 요청** - ID 기반 일괄 삭제

```
DELETE /api/v1/items/batch
```

**Request Body**:
```json
{
  "ids": [1, 2, 3]
}
```

**Response**:
```json
{
  "success": true,
  "data": {
    "deleted_count": 2,
    "failed_count": 1,
    "failed_items": [
      {
        "id": 3,
        "item_code": "KD-PT-003",
        "reason": "BOM에서 사용 중"
      }
    ],
    "message": "2개 품목이 삭제되었습니다. 1개 품목은 삭제할 수 없습니다."
  }
}
```

---

## 4. 동적 폼 렌더링 API

### API 4.1: 품목 유형별 폼 구조 조회
```
GET /api/v1/item-master/form-structure/{item_type}
```

**Path Parameters**:
| 파라미터 | 타입 | 필수 | 설명 |
|----------|------|------|------|
| item_type | string | Y | 품목 유형 (FG, PT, SM, RM, CS) |

**Query Parameters**:
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|----------|------|------|--------|------|
| include_conditions | boolean | N | true | 조건부 필드 포함 여부 |

**Response**:
```json
{
  "success": true,
  "data": {
    "page": {
      "id": 1,
      "page_name": "제품 등록",
      "item_type": "FG",
      "description": "제품(완제품) 등록 페이지"
    },
    "sections": [
      {
        "id": 101,
        "title": "기본 정보",
        "section_type": "BASIC",
        "order_no": 1,
        "is_collapsible": false,
        "is_default_open": true,
        "fields": [
          {
            "id": 1001,
            "field_name": "품목명",
            "field_key": "item_name",
            "field_type": "textbox",
            "order_no": 1,
            "is_required": true,
            "placeholder": "품목명을 입력하세요",
            "validation_rules": {
              "maxLength": 100
            },
            "grid_row": 1,
            "grid_col": 1,
            "grid_span": 2
          },
          {
            "id": 1002,
            "field_name": "품목 상태",
            "field_key": "status",
            "field_type": "dropdown",
            "order_no": 2,
            "is_required": true,
            "default_value": "DEV",
            "options": [
              {"label": "개발", "value": "DEV"},
              {"label": "양산", "value": "PROD"},
              {"label": "단종", "value": "EOL"}
            ],
            "grid_row": 2,
            "grid_col": 1,
            "grid_span": 1
          }
        ]
      },
      {
        "id": 102,
        "title": "인정 정보",
        "section_type": "BASIC",
        "order_no": 2,
        "is_collapsible": true,
        "is_default_open": false,
        "fields": [
          {
            "id": 1010,
            "field_name": "인정번호",
            "field_key": "certification_number",
            "field_type": "textbox",
            "order_no": 1,
            "is_required": false
          },
          {
            "id": 1011,
            "field_name": "시방서",
            "field_key": "specification_file",
            "field_type": "file",
            "order_no": 2,
            "is_required": false,
            "component_type": "file-upload",
            "properties": {
              "accept": ".pdf,.doc,.docx",
              "max_size_mb": 10
            }
          }
        ]
      },
      {
        "id": 103,
        "title": "부품 구성 (BOM)",
        "section_type": "BOM",
        "order_no": 3,
        "is_collapsible": true,
        "is_default_open": false,
        "bom_config": {
          "columns": [
            {"key": "child_item_code", "label": "품목코드", "width": 120, "editable": false},
            {"key": "child_item_name", "label": "품목명", "width": 200, "editable": false},
            {"key": "quantity", "label": "수량", "width": 80, "type": "number", "editable": true},
            {"key": "unit", "label": "단위", "width": 60, "editable": false},
            {"key": "quantity_formula", "label": "수량식", "width": 120, "editable": true},
            {"key": "note", "label": "비고", "width": 150, "editable": true}
          ],
          "allow_search": true,
          "search_endpoint": "/api/v1/items/search",
          "searchable_item_types": ["PT", "SM", "RM"]
        }
      }
    ],
    "conditional_sections": [
      {
        "condition": {
          "field_key": "needs_bom",
          "operator": "equals",
          "value": true
        },
        "show_sections": [103]
      }
    ]
  }
}
```

---

### API 4.2: 부품(PT) 조건부 필드 조회
```
GET /api/v1/item-master/form-structure/PT/conditional
```

**Query Parameters**:
| 파라미터 | 타입 | 필수 | 설명 |
|----------|------|------|------|
| part_type | string | Y | 부품유형 (ASSEMBLY, BENDING, PURCHASED) |
| category1 | string | N | 대분류 값 |

**Request Example**:
```
GET /api/v1/item-master/form-structure/PT/conditional?part_type=BENDING&category1=가이드레일
```

**Response**:
```json
{
  "success": true,
  "data": {
    "part_type": "BENDING",
    "category1": "가이드레일",
    "additional_sections": [
      {
        "id": 201,
        "title": "절곡품 정보",
        "section_type": "CUSTOM",
        "order_no": 2,
        "fields": [
          {
            "id": 2001,
            "field_name": "재질",
            "field_key": "material",
            "field_type": "dropdown",
            "is_required": true,
            "options": [
              {"label": "EGI 1.55T", "value": "EGI_155"},
              {"label": "SUS 1.2T", "value": "SUS_12"},
              {"label": "SPCC 1.6T", "value": "SPCC_16"}
            ]
          },
          {
            "id": 2002,
            "field_name": "길이",
            "field_key": "length",
            "field_type": "dropdown",
            "is_required": true,
            "options": [
              {"label": "2438mm", "value": "2438"},
              {"label": "3000mm", "value": "3000"},
              {"label": "4000mm", "value": "4000"}
            ]
          }
        ]
      },
      {
        "id": 202,
        "title": "전개도",
        "section_type": "CUSTOM",
        "order_no": 3,
        "fields": [
          {
            "id": 2010,
            "field_name": "전개도 이미지",
            "field_key": "bending_diagram",
            "field_type": "custom",
            "component_type": "drawing-canvas",
            "is_required": false,
            "properties": {
              "width": 800,
              "height": 400,
              "tools": ["pen", "line", "eraser", "text"]
            }
          },
          {
            "id": 2011,
            "field_name": "전개도 상세",
            "field_key": "bending_details",
            "field_type": "custom",
            "component_type": "bending-detail-table",
            "is_required": false
          }
        ]
      }
    ]
  }
}
```

---

## 5. BOM 관리 API

### API 5.1: 품목 BOM 조회
```
GET /api/v1/items/{id}/bom
```

**Response**:
```json
{
  "success": true,
  "data": {
    "item_id": 1,
    "item_code": "KD-FG-001",
    "item_name": "스크린 제품 A",
    "bom_lines": [
      {
        "id": 1,
        "child_item_id": 2,
        "child_item_code": "KD-PT-001",
        "child_item_name": "가이드레일(벽면형)",
        "quantity": 2,
        "unit": "EA",
        "unit_price": 50000,
        "total_price": 100000,
        "quantity_formula": "H / 1000",
        "note": "높이에 따라 수량 변동",
        "order_no": 1
      }
    ],
    "total_cost": 250000
  }
}
```

---

### API 5.2: BOM 항목 추가
```
POST /api/v1/items/{id}/bom
```

**Request Body**:
```json
{
  "child_item_id": 5,
  "quantity": 10,
  "unit": "EA",
  "quantity_formula": null,
  "note": "추가 부품"
}
```

---

### API 5.3: BOM 항목 수정
```
PUT /api/v1/items/{item_id}/bom/{bom_id}
```

**Request Body**:
```json
{
  "quantity": 15,
  "note": "수량 증가"
}
```

---

### API 5.4: BOM 항목 삭제
```
DELETE /api/v1/items/{item_id}/bom/{bom_id}
```

---

## 6. 파일 관리 API

### API 6.1: 파일 업로드
```
POST /api/v1/files/upload
```

**Content-Type**: `multipart/form-data`

**Form Data**:
| 필드 | 타입 | 필수 | 설명 |
|------|------|------|------|
| file | File | Y | 업로드할 파일 |
| type | string | Y | 파일 유형 (specification, certification, bending_diagram) |
| item_id | number | N | 연결할 품목 ID (수정 시) |

**Response**:
```json
{
  "success": true,
  "data": {
    "file_id": "uuid-1234-5678",
    "file_name": "시방서.pdf",
    "file_url": "/files/uuid-1234-5678/시방서.pdf",
    "file_size": 1024000,
    "mime_type": "application/pdf"
  }
}
```

---

### API 6.2: 파일 다운로드
```
GET /api/v1/files/{file_id}/download
```

---

### API 6.3: 파일 삭제
```
DELETE /api/v1/files/{file_id}
```

---

## 7. 마스터 데이터 조회 API

### API 7.1: 단위 목록 조회
```
GET /api/v1/master/units
```

**Response**:
```json
{
  "success": true,
  "data": [
    {"value": "EA", "label": "EA (개)"},
    {"value": "SET", "label": "SET (세트)"},
    {"value": "M", "label": "M (미터)"},
    {"value": "KG", "label": "KG (킬로그램)"},
    {"value": "L", "label": "L (리터)"}
  ]
}
```

---

### API 7.2: 카테고리 목록 조회
```
GET /api/v1/master/categories
```

**Query Parameters**:
| 파라미터 | 타입 | 필수 | 설명 |
|----------|------|------|------|
| item_type | string | N | 품목유형별 필터 |
| parent_id | number | N | 상위 카테고리 ID |

---

### API 7.3: 재질 목록 조회
```
GET /api/v1/master/materials
```

**Response**:
```json
{
  "success": true,
  "data": [
    {"value": "EGI_155", "label": "EGI 1.55T", "thickness": "1.55"},
    {"value": "SUS_12", "label": "SUS 1.2T", "thickness": "1.2"},
    {"value": "SPCC_16", "label": "SPCC 1.6T", "thickness": "1.6"}
  ]
}
```

---

### API 7.4: 규격 목록 조회 (원자재/부자재)
```
GET /api/v1/master/specifications
```

**Query Parameters**:
| 파라미터 | 타입 | 필수 | 설명 |
|----------|------|------|------|
| item_type | string | Y | RM 또는 SM |
| item_name | string | N | 품목명 필터 (예: SPHC-SD) |

---

## 8. API 요약 테이블

### 8.1 필수 API (MVP)
| 우선순위 | 메서드 | 엔드포인트 | 설명 | 상태 |
|----------|--------|------------|------|------|
| 🔴 P0 | GET | `/api/v1/items` | 품목 목록 조회 (페이징) | ⚠️ 기존 |
| 🔴 P0 | GET | `/api/v1/items/{id}` | 품목 단건 조회 (ID) | ⚠️ 기존 |
| 🔴 P0 | GET | `/api/v1/items/code/{code}` | 품목 단건 조회 (코드) | ⚠️ 기존 |
| 🔴 P0 | POST | `/api/v1/items` | 품목 생성 | ⚠️ 기존 |
| 🔴 P0 | PUT | `/api/v1/items/{id}` | 품목 수정 (ID 기반) | ⚠️ 기존 |
| 🔴 P0 | DELETE | `/api/v1/items/{id}` | 품목 삭제 (ID 기반) | ⚠️ 기존 |
| 🔴 P0 | GET | `/api/v1/items/search` | 품목 검색 (BOM용) | 🆕 신규 |

### 8.2 중요 API
| 우선순위 | 메서드 | 엔드포인트 | 설명 |
|----------|--------|------------|------|
| 🟡 P1 | GET | `/api/v1/item-master/form-structure/{type}` | 동적 폼 구조 조회 |
| 🟡 P1 | GET | `/api/v1/items/stats` | 품목 통계 |
| 🟡 P1 | DELETE | `/api/v1/items/batch` | 품목 일괄 삭제 |
| 🟡 P1 | POST | `/api/v1/files/upload` | 파일 업로드 |

### 8.3 추가 API
| 우선순위 | 메서드 | 엔드포인트 | 설명 |
|----------|--------|------------|------|
| 🟢 P2 | GET | `/api/v1/item-master/form-structure/PT/conditional` | PT 조건부 필드 |
| 🟢 P2 | GET | `/api/v1/items/{id}/bom` | BOM 조회 |
| 🟢 P2 | POST | `/api/v1/items/{id}/bom` | BOM 항목 추가 |
| 🟢 P2 | PUT | `/api/v1/items/{id}/bom/{bom_id}` | BOM 항목 수정 |
| 🟢 P2 | DELETE | `/api/v1/items/{id}/bom/{bom_id}` | BOM 항목 삭제 |
| 🟢 P2 | GET | `/api/v1/master/units` | 단위 목록 |
| 🟢 P2 | GET | `/api/v1/master/categories` | 카테고리 목록 |
| 🟢 P2 | GET | `/api/v1/master/materials` | 재질 목록 |
| 🟢 P2 | GET | `/api/v1/master/specifications` | 규격 목록 |
| 🟢 P2 | GET | `/api/v1/files/{id}/download` | 파일 다운로드 |
| 🟢 P2 | DELETE | `/api/v1/files/{id}` | 파일 삭제 |

---

## 9. 에러 응답 형식

### 공통 에러 응답
```json
{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "사용자 친화적 에러 메시지",
    "details": {}
  }
}
```

### 에러 코드 목록
| 코드 | HTTP Status | 설명 |
|------|-------------|------|
| VALIDATION_ERROR | 400 | 입력값 검증 실패 |
| ITEM_NOT_FOUND | 404 | 품목을 찾을 수 없음 |
| ITEM_IN_USE | 409 | 품목이 다른 곳에서 사용 중 |
| DUPLICATE_ITEM_CODE | 409 | 중복된 품목코드 |
| FILE_TOO_LARGE | 413 | 파일 크기 초과 |
| UNAUTHORIZED | 401 | 인증 필요 |
| FORBIDDEN | 403 | 권한 없음 |
| INTERNAL_ERROR | 500 | 서버 내부 오류 |

---

## 10. 데이터 모델 참조

### 10.1 품목(Item) 테이블 필드
```sql
CREATE TABLE items (
  id SERIAL PRIMARY KEY,
  tenant_id INTEGER NOT NULL,
  item_code VARCHAR(50) UNIQUE NOT NULL,
  item_name VARCHAR(200) NOT NULL,
  item_type VARCHAR(10) NOT NULL, -- FG, PT, SM, RM, CS
  unit VARCHAR(20) NOT NULL,
  specification VARCHAR(200),
  is_active BOOLEAN DEFAULT true,

  -- 제품(FG) 전용
  product_category VARCHAR(20), -- SCREEN, STEEL
  lot_abbreviation VARCHAR(10),
  certification_number VARCHAR(100),
  certification_start_date DATE,
  certification_end_date DATE,
  specification_file VARCHAR(500),
  specification_file_name VARCHAR(200),
  certification_file VARCHAR(500),
  certification_file_name VARCHAR(200),

  -- 부품(PT) 전용
  part_type VARCHAR(20), -- ASSEMBLY, BENDING, PURCHASED
  part_usage VARCHAR(50),
  installation_type VARCHAR(50),
  assembly_type VARCHAR(10),
  assembly_length VARCHAR(20),
  side_spec_width VARCHAR(20),
  side_spec_height VARCHAR(20),
  material VARCHAR(50),
  length VARCHAR(20),
  bending_diagram TEXT, -- Base64 이미지
  bending_details JSONB, -- 전개도 상세 데이터

  -- 분류
  category1 VARCHAR(100),
  category2 VARCHAR(100),
  category3 VARCHAR(100),

  -- 가격
  purchase_price DECIMAL(15,2),
  sales_price DECIMAL(15,2),
  margin_rate DECIMAL(5,2),
  processing_cost DECIMAL(15,2),
  labor_cost DECIMAL(15,2),
  install_cost DECIMAL(15,2),

  -- 재고
  safety_stock INTEGER,
  lead_time INTEGER,

  -- 버전 관리
  current_revision INTEGER DEFAULT 0,
  is_final BOOLEAN DEFAULT false,
  finalized_date TIMESTAMP,
  finalized_by INTEGER,

  note TEXT,
  created_by INTEGER,
  updated_by INTEGER,
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);
```

### 10.2 BOM 테이블
```sql
CREATE TABLE item_bom (
  id SERIAL PRIMARY KEY,
  tenant_id INTEGER NOT NULL,
  parent_item_id INTEGER REFERENCES items(id),
  child_item_id INTEGER REFERENCES items(id),
  quantity DECIMAL(10,3) NOT NULL,
  unit VARCHAR(20),
  unit_price DECIMAL(15,2),
  quantity_formula VARCHAR(100), -- 예: "H / 1000"
  note TEXT,
  order_no INTEGER DEFAULT 0,
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);
```

---

## 11. 참고 문서

- `src/components/items/ItemListClient.tsx` - 품목 목록 UI
- `src/components/items/ItemForm/index.tsx` - 품목 등록/수정 폼
- `src/contexts/ItemMasterContext.tsx` - 품목기준관리 데이터 구조
- `[API-2025-11-25] item-master-data-management-api-request.md` - 품목기준관리 API

---

## 변경 이력

| 날짜 | 버전 | 변경 내용 |
|------|------|----------|
| 2025-11-28 | 1.0 | 초안 작성 (동적 렌더링만) |
| 2025-11-28 | 2.0 | **전체 CRUD + 리스트 + 페이징 + BOM + 파일 + 마스터 데이터 추가** |
| 2025-11-28 | 3.0 | **백엔드 스키마/기존 API 기반 재검토**: `/{id}` → `/{code}` 경로 변경, `per_page` → `size` 파라미터 변경, 기존 API 주석 추가, 일괄삭제 코드 기반 변경 |
| 2025-11-28 | 3.1 | **ID 기반으로 통일** (백엔드 결정): PUT/DELETE `/{code}` → `/{id}` 롤백, 일괄삭제 `codes` → `ids` 변경, 문서 전체 정합성 검토 완료 |