Files
sam-docs/plans/items-api-unified-plan.md
hskwon 26aeecd865 docs: Items API 통합 개발 계획 추가
- item_type 명명 체계 통일 계획
- Material CRUD 지원 추가 계획
- Phase 0 Seeder 수정 완료 체크
2025-12-09 20:28:47 +09:00

29 KiB

Items API 통합 개발 계획

Items API 명명 체계 통일 + Material CRUD 지원 추가

작성일: 2025-12-09 상태: 진행 예정


1. 개요

1.1 목표

  1. 명명 체계 통일: item_type 파라미터의 이중 의미 충돌 해소
  2. Material CRUD 지원: 수정/삭제/일괄삭제/코드조회 기능 추가

1.2 현재 문제점

item_type 이중 의미 충돌:

❌ 동일한 이름(item_type)이 두 가지 다른 의미로 사용됨

[의미 1] 품목 유형 (올바른 사용)
├─ item_pages.item_type = 'FG' | 'PT' | 'SM' | 'RM' | 'CS'
├─ common_codes (code_group='item_type')
└─ ItemsService.createItem() - product_type 파라미터

[의미 2] 테이블 구분 (잘못된 사용)
├─ ItemsService.getItem() - item_type = 'PRODUCT' | 'MATERIAL'
├─ ItemsController.show() - item_type 파라미터
└─ Swagger ItemsApi - item_type 값 정의

Material CRUD 미지원:

메서드 경로 Product Material 비고
GET /api/v1/items 통합 조회 정상
POST /api/v1/items 생성 정상
GET /api/v1/items/code/{code} Product만 지원
GET /api/v1/items/{id} item_type으로 분기
PUT /api/v1/items/{id} 수정 필요
DELETE /api/v1/items/{id} 수정 필요
DELETE /api/v1/items/batch 수정 필요

2. 설계 결정 사항

2.1 명명 규칙

용어 필드명 설명
품목 유형 item_type FG, PT, SM, RM, CS 비즈니스 분류 (API 파라미터)
저장 테이블 source_table products, materials 물리적 저장소 (내부 자동 매핑)
참조 타입 ref_type PRODUCT, MATERIAL 폴리모픽 관계용 (기존 유지)

2.2 품목 유형 → 테이블 매핑

item_type → source_table 자동 매핑

FG (완제품)  ─┐
PT (반제품)  ─┴─→ source_table = 'products'

SM (부자재)  ─┐
RM (원자재)  ─┼─→ source_table = 'materials'
CS (소모품)  ─┘

2.3 테넌트별 품목 유형 관리

  • 품목 유형은 테넌트(업체)별로 커스터마이징 가능
  • attributes JSON 필드 활용 (스키마 변경 없음)
  • 캐시를 통한 성능 최적화
// common_codes 레코드 예시
{
  "code_group": "item_type",
  "code": "FG",
  "name": "완제품",
  "attributes": {
    "source_table": "products"
  }
}

2.4 API 파라미터 변경 (Breaking Change)

Before: GET /api/v1/items/{id}?item_type=PRODUCT
After:  GET /api/v1/items/{id}?item_type=FG

Before: DELETE /api/v1/items/{id}  (item_type 없음)
After:  DELETE /api/v1/items/{id}?item_type=RM

2.5 기존 시스템 호환성 (변경 없음)

시스템 필드 상태
Prices API item_type_code PRODUCT, MATERIAL 유지
BOM API ref_type PRODUCT, MATERIAL 유지
ItemMaster API item_type FG, PT, SM, RM, CS 유지

3. 영향 범위

3.1 수정 파일

파일 경로 변경 내용
ItemTypeSeeder database/seeders/ItemTypeSeeder.php attributes.source_table 추가
ItemTypeHelper app/Helpers/ItemTypeHelper.php 신규 생성
ItemStoreRequest app/Http/Requests/Item/ItemStoreRequest.php Material 필드 추가
ItemUpdateRequest app/Http/Requests/Item/ItemUpdateRequest.php item_type 필수화 + Material 필드
ItemBatchDeleteRequest app/Http/Requests/Item/ItemBatchDeleteRequest.php item_type 필드 추가
ItemsService app/Services/ItemsService.php Material CRUD 메서드 추가
ItemsController app/Http/Controllers/Api/V1/ItemsController.php item_type 파라미터 처리
ItemsApi app/Swagger/v1/ItemsApi.php item_type 값 변경 + 스키마 보완

3.2 작업 완료 후 예상 상태

품목 유형 조회 생성 수정 삭제 일괄삭제 코드조회
제품(FG)
반제품(PT)
부자재(SM)
원자재(RM)
소모품(CS)

4. 작업 계획

Phase 0: Seeder 수정 (5분)

파일: database/seeders/ItemTypeSeeder.php

작업 내용:

  • attributes.source_table 추가

수정 후 코드:

$itemTypes = [
    ['code' => 'FG', 'name' => '완제품', 'attributes' => ['source_table' => 'products']],
    ['code' => 'PT', 'name' => '반제품', 'attributes' => ['source_table' => 'products']],
    ['code' => 'SM', 'name' => '부자재', 'attributes' => ['source_table' => 'materials']],
    ['code' => 'RM', 'name' => '원자재', 'attributes' => ['source_table' => 'materials']],
    ['code' => 'CS', 'name' => '소모품', 'attributes' => ['source_table' => 'materials']],
];

체크리스트:

  • ItemTypeSeeder.php 수정 (2025-12-09)
  • php artisan db:seed --class=ItemTypeSeeder 실행
  • DB 데이터 확인 (5개 item_type 코드 시딩 완료)

Phase 1: ItemTypeHelper 생성 (10분)

파일: app/Helpers/ItemTypeHelper.php (신규)

작업 내용:

  • 테넌트별 품목 유형 조회 (캐시 적용)
  • isMaterial(), isProduct(), getSourceTable() 메서드
  • 캐시 무효화 메서드

체크리스트:

  • app/Helpers/ 디렉토리 생성 (없으면)
  • ItemTypeHelper.php 생성
  • composer.json autoload 확인 (PSR-4로 자동 로드됨)

Phase 2: FormRequest 수정 (10분)

파일 3개:

2-1. ItemStoreRequest.php

// Material 전용 필드 추가
'specification' => 'nullable|string|max:255',
'remarks' => 'nullable|string',
'item_name' => 'nullable|string|max:255',
'search_tag' => 'nullable|string|max:255',
'is_inspection' => 'nullable|string|in:Y,N',
'options' => 'nullable|array',
'material_code' => 'nullable|string|max:50',

2-2. ItemUpdateRequest.php

// item_type 필수화 + Material 필드 추가
'item_type' => 'required|string|in:FG,PT,SM,RM,CS',
'material_code' => 'sometimes|string|max:50',
'specification' => 'nullable|string|max:255',
'remarks' => 'nullable|string',
'item_name' => 'nullable|string|max:255',
'search_tag' => 'nullable|string|max:255',
'is_inspection' => 'nullable|string|in:Y,N',
'options' => 'nullable|array',

2-3. ItemBatchDeleteRequest.php

// item_type 필드 추가
'item_type' => 'required|string|in:FG,PT,SM,RM,CS',

체크리스트:

  • ItemStoreRequest.php 수정
  • ItemUpdateRequest.php 수정
  • ItemBatchDeleteRequest.php 수정

Phase 3: ItemsService 수정 (20분)

파일: app/Services/ItemsService.php

작업 내용:

  1. import 추가: use App\Helpers\ItemTypeHelper;

  2. getItems() 수정: 목록 조회 시 specification 추가 + attributes 플랫 전개

    // Product 쿼리 select에 추가
    DB::raw('NULL as specification'),  // Product는 specification 컬럼 없음
    'attributes',
    
    // Material 쿼리 select에 추가
    'specification',
    'attributes',
    
    // 조회 후 attributes 플랫 전개 (후처리)
    $items->getCollection()->transform(function ($item) {
        $data = $item->toArray();
        $attributes = $data['attributes'] ?? [];
        unset($data['attributes']);
        return array_merge($data, $attributes);
    });
    
  3. getItem() 수정: item_type 파라미터를 FG/PT/SM/RM/CS로 받도록 변경

    // Before: getItem('PRODUCT', $id, ...)
    // After:  getItem($id, 'FG', ...)
    
  4. updateItem() 수정: Material 분기 추가

    public function updateItem(int $id, array $data): Product|Material
    {
        $itemType = strtoupper($data['item_type'] ?? 'FG');
        if (ItemTypeHelper::isMaterial($itemType, $this->tenantId())) {
            return $this->updateMaterial($id, $data);
        }
        return $this->updateProduct($id, $data);
    }
    
  5. updateMaterial() 추가: Material 수정 로직

  6. deleteItem() 수정: item_type 파라미터 추가

    public function deleteItem(int $id, string $itemType = 'FG'): void
    
  7. deleteMaterial() 추가: Material 삭제 로직

  8. batchDeleteItems() 수정: item_type 지원

  9. getItemByCode() 수정: Product 없으면 Material에서 조회

  10. checkMaterialUsageInBom() 추가: BOM 사용 여부 체크

체크리스트:

  • ItemTypeHelper import 추가
  • getItems() specification/attributes 추가 + 플랫 전개 후처리
  • getItem() 시그니처 및 로직 변경
  • updateItem() Material 분기 추가
  • updateMaterial() 메서드 추가
  • deleteItem() item_type 파라미터 추가
  • deleteMaterial() 메서드 추가
  • batchDeleteItems() Material 지원
  • getItemByCode() Material 지원
  • checkMaterialUsageInBom() 메서드 추가

Phase 4: ItemsController 수정 (5분)

파일: app/Http/Controllers/Api/V1/ItemsController.php

작업 내용:

  1. show() 수정: 기본값 'PRODUCT' → 'FG'

    $itemType = strtoupper($request->input('item_type', 'FG'));
    
  2. destroy() 수정: item_type 파라미터 추가

    public function destroy(Request $request, int $id)
    {
        $itemType = strtoupper($request->input('item_type', 'FG'));
        return ApiResponse::handle(function () use ($id, $itemType) {
            $this->service->deleteItem($id, $itemType);
            return 'success';
        }, __('message.item.deleted'));
    }
    
  3. batchDestroy() 수정: item_type 처리

    $itemType = strtoupper($request->validated()['item_type'] ?? 'FG');
    $this->service->batchDeleteItems($request->validated()['ids'], $itemType);
    

체크리스트:

  • show() 기본값 변경
  • destroy() item_type 파라미터 추가
  • batchDestroy() item_type 처리

Phase 5: Swagger 문서 수정 (15분)

파일: app/Swagger/v1/ItemsApi.php

작업 내용:

  1. Item 스키마 보완:

    • item_type (FG|PT|SM|RM|CS) - 품목 유형
    • Material 전용 필드 추가
  2. ItemCreateRequest 스키마 보완:

    • Material 전용 필드 추가
  3. ItemUpdateRequest 스키마 보완:

    • item_type 필수 (FG|PT|SM|RM|CS)
    • Material 전용 필드 추가
  4. ItemBatchDeleteRequest 스키마 보완:

    • item_type 필드 추가
  5. show 엔드포인트:

    • item_type 값 변경 (common_codes): PRODUCT|MATERIAL → FG|PT|SM|RM|CS
  6. destroy 엔드포인트:

    • item_type 쿼리 파라미터 추가
  7. batchDestroy 엔드포인트:

    • Request에 item_type 필드 추가
  8. showByCode 엔드포인트:

    • Product/Material 모두 지원 설명 추가

체크리스트:

  • Item 스키마 보완
  • ItemCreateRequest 스키마 보완
  • ItemUpdateRequest 스키마 보완
  • ItemBatchDeleteRequest 스키마 보완
  • show 엔드포인트 item_type 값 변경
  • destroy 엔드포인트 item_type 파라미터 추가
  • batchDestroy 엔드포인트 스키마 수정
  • showByCode 엔드포인트 설명 보완

Phase 6: 검증 (10분)

작업 내용:

  1. Pint 코드 포맷팅

    cd api && ./vendor/bin/pint
    
  2. Swagger 생성 테스트

    cd api && php artisan l5-swagger:generate
    
  3. API 테스트 (Swagger UI)

    • Product CRUD 정상 동작 확인
    • Material CRUD 정상 동작 확인
    • 코드 중복 체크 동작 확인
    • BOM 사용 중 삭제 방지 확인

체크리스트:

  • Pint 실행 및 오류 수정
  • Swagger 생성 성공
  • Product CRUD 테스트
  • Material CRUD 테스트

5. 예상 시간

Phase 작업 예상 시간
0 Seeder 수정 5분
1 ItemTypeHelper 생성 10분
2 FormRequest 수정 (3개) 10분
3 ItemsService 수정 20분
4 ItemsController 수정 5분
5 Swagger 문서 수정 15분
6 검증 10분
총계 약 75분

6. 아키텍처 다이어그램

┌─────────────────────────────────────────────────────────────┐
│                      API Request                             │
│                  item_type = 'FG' | 'SM' | ...               │
└─────────────────────────┬───────────────────────────────────┘
                          ▼
┌─────────────────────────────────────────────────────────────┐
│                   ItemTypeHelper                             │
│  ┌─────────────────────────────────────────────────────┐    │
│  │ getTypesByTenant($tenantId)                         │    │
│  │   → Cache::remember("item_types:tenant:{id}")       │    │
│  │   → CommonCode::where('code_group', 'item_type')    │    │
│  └─────────────────────────────────────────────────────┘    │
│  ┌─────────────────────────────────────────────────────┐    │
│  │ isMaterial($itemType, $tenantId)                    │    │
│  │ isProduct($itemType, $tenantId)                     │    │
│  │ getSourceTable($itemType, $tenantId)                │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────┬───────────────────────────────────┘
                          ▼
┌─────────────────────────────────────────────────────────────┐
│                    ItemsService                              │
│  if (ItemTypeHelper::isMaterial($itemType, $tenantId)) {    │
│      → materials 테이블                                      │
│  } else {                                                    │
│      → products 테이블                                       │
│  }                                                           │
└─────────────────────────────────────────────────────────────┘

7. 변경 이력

날짜 내용
2025-12-09 통합 문서 작성 (items-naming-convention.md + items-api-modification-plan.md 병합)

8. API별 Request/Response 예시

8.1 품목 목록 조회 (GET /api/v1/items)

🔧 변경: specification 추가 + attributes 플랫 전개 + 페이지네이션 구조 변경

Request:

GET /api/v1/items?type=FG,PT&search=스크린&page=1&size=20

Response:

{
  "success": true,
  "message": "조회되었습니다.",
  "data": [
    {
      "id": 1,
      "item_type": "FG",
      "code": "P-001",
      "name": "스크린 제품 A",
      "specification": null,
      "unit": "EA",
      "category_id": 1,
      "color": "white",
      "size": "100x200",
      "created_at": "2025-12-01 10:00:00",
      "deleted_at": null
    },
    {
      "id": 5,
      "item_type": "RM",
      "code": "M-001",
      "name": "스크린 원단",
      "specification": "1.2T x 1219 x 2438",
      "unit": "M",
      "category_id": 2,
      "thickness": "1.2T",
      "width": "1219",
      "created_at": "2025-12-01 11:00:00",
      "deleted_at": null
    }
  ],
  "pagination": {
    "current_page": 1,
    "per_page": 20,
    "total": 2,
    "last_page": 1,
    "from": 1,
    "to": 2
  }
}

응답 구조:

타입 설명
success boolean 성공 여부
message string 메시지
data array 품목 데이터 배열 (바로 접근 가능)
pagination object 페이지네이션 정보

data[] 필드 설명:

필드 Product Material 설명
id 품목 ID
item_type FG/PT SM/RM/CS 품목 유형
code 품목 코드
name 품목명
specification null 규격 (Material만 컬럼 존재)
unit 단위
category_id 카테고리 ID
{attr_key} attributes JSON 플랫 전개 (동적 필드)
created_at 생성일
deleted_at 삭제일 (soft delete)

pagination 필드 설명:

필드 타입 설명
current_page int 현재 페이지
per_page int 페이지당 항목 수
total int 전체 항목 수
last_page int 마지막 페이지
from int 현재 페이지 시작 번호
to int 현재 페이지 끝 번호

⚠️ 구현 (ItemsService.getItems()):

// 1. attributes 플랫 전개
$items->getCollection()->transform(function ($item) {
    $data = $item->toArray();
    $attributes = $data['attributes'] ?? [];
    unset($data['attributes']);
    return array_merge($data, $attributes);
});

// 2. 페이지네이션 구조 변환 (Controller에서)
return [
    'data' => $items->items(),
    'pagination' => [
        'current_page' => $items->currentPage(),
        'per_page' => $items->perPage(),
        'total' => $items->total(),
        'last_page' => $items->lastPage(),
        'from' => $items->firstItem(),
        'to' => $items->lastItem(),
    ],
];

8.2 품목 생성 (POST /api/v1/items)

🔧 변경: Request/Response 모두 플랫 구조 (품목기준관리 필드 기반)

Product 생성 (FG/PT)

Request:

{
  "code": "P-002",
  "name": "스크린 제품 B",
  "product_type": "FG",
  "unit": "EA",
  "category_id": 1,
  "description": "완제품 설명",
  "is_sellable": true,
  "is_purchasable": false,
  "is_producible": true,
  "safety_stock": 10,
  "lead_time": 7,
  "color": "white",
  "size": "100x200"
}

참고: 모든 필드는 플랫하게 전송. 백엔드에서 품목기준관리(item_fields) 정의에 따라 고정 컬럼과 attributes JSON 저장을 자동 분리.

Response:

{
  "success": true,
  "message": "품목이 등록되었습니다.",
  "data": {
    "id": 2,
    "tenant_id": 1,
    "code": "P-002",
    "name": "스크린 제품 B",
    "product_type": "FG",
    "unit": "EA",
    "category_id": 1,
    "description": "완제품 설명",
    "is_sellable": true,
    "is_purchasable": false,
    "is_producible": true,
    "is_active": true,
    "safety_stock": 10,
    "lead_time": 7,
    "color": "white",
    "size": "100x200",
    "created_at": "2025-12-09 10:00:00",
    "updated_at": "2025-12-09 10:00:00"
  }
}

Material 생성 (SM/RM/CS)

Request:

{
  "code": "M-002",
  "name": "철판 1.2T",
  "product_type": "RM",
  "unit": "EA",
  "category_id": 2,
  "item_name": "철판",
  "specification": "1.2T x 1219 x 2438",
  "is_inspection": "Y",
  "search_tag": "철판,원자재,1.2T",
  "remarks": "포스코산",
  "thickness": "1.2T",
  "width": "1219"
}

Response:

{
  "success": true,
  "message": "품목이 등록되었습니다.",
  "data": {
    "id": 10,
    "tenant_id": 1,
    "material_code": "M-002",
    "name": "철판 1.2T",
    "material_type": "RM",
    "unit": "EA",
    "category_id": 2,
    "item_name": "철판",
    "specification": "1.2T x 1219 x 2438",
    "is_inspection": "Y",
    "search_tag": "철판,원자재,1.2T",
    "remarks": "포스코산",
    "thickness": "1.2T",
    "width": "1219",
    "is_active": true,
    "created_at": "2025-12-09 10:05:00",
    "updated_at": "2025-12-09 10:05:00"
  }
}

8.3 품목 상세 조회 - ID (GET /api/v1/items/{id})

🔧 변경: item_type 파라미터 값 변경 + attributes 플랫 전개

Before (현재)

GET /api/v1/items/1?item_type=PRODUCT&include_price=true
GET /api/v1/items/10?item_type=MATERIAL

After (변경 후)

GET /api/v1/items/1?item_type=FG&include_price=true
GET /api/v1/items/10?item_type=RM

Response (Product):

{
  "success": true,
  "message": "조회되었습니다.",
  "data": {
    "id": 1,
    "item_type": "FG",
    "code": "P-001",
    "name": "스크린 제품 A",
    "unit": "EA",
    "category_id": 1,
    "category": {
      "id": 1,
      "name": "완제품"
    },
    "description": "완제품 설명",
    "is_sellable": true,
    "is_purchasable": false,
    "is_producible": true,
    "is_active": true,
    "safety_stock": 10,
    "lead_time": 7,
    "color": "white",
    "size": "100x200",
    "prices": {
      "sale": {
        "price": 150000,
        "currency": "KRW",
        "effective_from": "2025-01-01"
      },
      "purchase": null
    },
    "created_at": "2025-12-01 10:00:00",
    "updated_at": "2025-12-01 10:00:00"
  }
}

Response (Material):

{
  "success": true,
  "message": "조회되었습니다.",
  "data": {
    "id": 10,
    "item_type": "RM",
    "code": "M-002",
    "name": "철판 1.2T",
    "unit": "EA",
    "category_id": 2,
    "item_name": "철판",
    "specification": "1.2T x 1219 x 2438",
    "is_inspection": "Y",
    "search_tag": "철판,원자재,1.2T",
    "remarks": "포스코산",
    "thickness": "1.2T",
    "width": "1219",
    "is_active": true,
    "created_at": "2025-12-09 10:05:00",
    "updated_at": "2025-12-09 10:05:00"
  }
}

8.4 품목 상세 조회 - 코드 (GET /api/v1/items/code/{code})

🔧 변경: Material 코드 조회 지원 추가 + attributes 플랫 전개

Before (현재)

GET /api/v1/items/code/P-001?include_bom=true   # ✅ Product만 지원
GET /api/v1/items/code/M-002                     # ❌ 404 에러

After (변경 후)

GET /api/v1/items/code/P-001?include_bom=true   # ✅ Product 조회
GET /api/v1/items/code/M-002                     # ✅ Material 조회

Response (Product):

{
  "success": true,
  "message": "품목을 조회했습니다.",
  "data": {
    "id": 1,
    "item_type": "FG",
    "code": "P-001",
    "name": "스크린 제품 A",
    "unit": "EA",
    "category_id": 1,
    "category": {
      "id": 1,
      "name": "완제품"
    },
    "description": "완제품 설명",
    "is_sellable": true,
    "is_purchasable": false,
    "is_producible": true,
    "is_active": true,
    "safety_stock": 10,
    "lead_time": 7,
    "color": "white",
    "size": "100x200",
    "component_lines": [
      {
        "id": 1,
        "child_product": {
          "id": 2,
          "code": "PT-001",
          "name": "스크린 본체",
          "unit": "EA"
        },
        "quantity": 1
      }
    ],
    "created_at": "2025-12-01 10:00:00",
    "updated_at": "2025-12-01 10:00:00"
  }
}

Response (Material):

{
  "success": true,
  "message": "품목을 조회했습니다.",
  "data": {
    "id": 10,
    "item_type": "RM",
    "code": "M-002",
    "name": "철판 1.2T",
    "unit": "EA",
    "category_id": 2,
    "item_name": "철판",
    "specification": "1.2T x 1219 x 2438",
    "is_inspection": "Y",
    "search_tag": "철판,원자재,1.2T",
    "remarks": "포스코산",
    "thickness": "1.2T",
    "width": "1219",
    "is_active": true,
    "created_at": "2025-12-09 10:05:00",
    "updated_at": "2025-12-09 10:05:00"
  }
}

8.5 품목 수정 (PUT /api/v1/items/{id})

🔧 변경: item_type 필수화 + Material 수정 지원 + attributes 플랫 전개

Before (현재)

PUT /api/v1/items/1
Content-Type: application/json

{
  "name": "스크린 제품 A (수정)"   # ✅ Product만 지원
}

After (변경 후)

Product 수정:

PUT /api/v1/items/1
Content-Type: application/json

{
  "item_type": "FG",
  "name": "스크린 제품 A (수정)",
  "description": "수정된 설명",
  "safety_stock": 20,
  "color": "black",
  "size": "150x300"
}

참고: 모든 필드는 플랫하게 전송. 백엔드에서 품목기준관리(item_fields) 정의에 따라 고정 컬럼과 attributes JSON 저장을 자동 분리.

Response (Product):

{
  "success": true,
  "message": "품목이 수정되었습니다.",
  "data": {
    "id": 1,
    "item_type": "FG",
    "code": "P-001",
    "name": "스크린 제품 A (수정)",
    "unit": "EA",
    "category_id": 1,
    "description": "수정된 설명",
    "is_sellable": true,
    "is_purchasable": false,
    "is_producible": true,
    "is_active": true,
    "safety_stock": 20,
    "lead_time": 7,
    "color": "black",
    "size": "150x300",
    "created_at": "2025-12-01 10:00:00",
    "updated_at": "2025-12-09 11:00:00"
  }
}

Material 수정:

PUT /api/v1/items/10
Content-Type: application/json

{
  "item_type": "RM",
  "name": "철판 1.5T",
  "specification": "1.5T x 1219 x 2438",
  "remarks": "포스코산 (규격 변경)",
  "thickness": "1.5T",
  "width": "1219"
}

Response (Material):

{
  "success": true,
  "message": "품목이 수정되었습니다.",
  "data": {
    "id": 10,
    "item_type": "RM",
    "code": "M-002",
    "name": "철판 1.5T",
    "unit": "EA",
    "category_id": 2,
    "item_name": "철판",
    "specification": "1.5T x 1219 x 2438",
    "is_inspection": "Y",
    "search_tag": "철판,원자재,1.5T",
    "remarks": "포스코산 (규격 변경)",
    "thickness": "1.5T",
    "width": "1219",
    "is_active": true,
    "created_at": "2025-12-09 10:05:00",
    "updated_at": "2025-12-09 11:05:00"
  }
}

8.6 품목 삭제 (DELETE /api/v1/items/{id})

🔧 변경: item_type 쿼리 파라미터 추가 + Material 삭제 지원

Before (현재)

DELETE /api/v1/items/1   # ✅ Product만 삭제
DELETE /api/v1/items/10  # ❌ Material은 404 에러

After (변경 후)

DELETE /api/v1/items/1?item_type=FG    # ✅ Product 삭제
DELETE /api/v1/items/10?item_type=RM   # ✅ Material 삭제

Response (성공):

{
  "success": true,
  "message": "품목이 삭제되었습니다.",
  "data": "success"
}

Response (BOM 사용 중 - 삭제 불가):

{
  "success": false,
  "message": "다른 BOM의 구성품으로 사용 중입니다. (3건)",
  "error": {
    "code": "ITEM_IN_USE",
    "count": 3
  }
}

8.7 품목 일괄 삭제 (DELETE /api/v1/items/batch)

🔧 변경: item_type 필드 추가 + Material 일괄 삭제 지원

Before (현재)

DELETE /api/v1/items/batch
Content-Type: application/json

{
  "ids": [1, 2, 3]   # ✅ Product만 삭제
}

After (변경 후)

Product 일괄 삭제:

DELETE /api/v1/items/batch
Content-Type: application/json

{
  "item_type": "FG",
  "ids": [1, 2, 3]
}

Material 일괄 삭제:

DELETE /api/v1/items/batch
Content-Type: application/json

{
  "item_type": "RM",
  "ids": [10, 11, 12]
}

Response (성공):

{
  "success": true,
  "message": "품목이 일괄 삭제되었습니다.",
  "data": "success"
}

Response (일부 BOM 사용 중):

{
  "success": false,
  "message": "일부 품목이 BOM 구성품으로 사용 중입니다. (2건)",
  "error": {
    "code": "ITEMS_IN_USE",
    "count": 2
  }
}

8.8 에러 응답 예시

404 Not Found:

{
  "success": false,
  "message": "품목을 찾을 수 없습니다.",
  "error": {
    "code": "NOT_FOUND"
  }
}

400 Bad Request (코드 중복):

{
  "success": false,
  "message": "이미 사용 중인 품목코드입니다.",
  "error": {
    "code": "DUPLICATE_CODE"
  }
}

422 Validation Error:

{
  "success": false,
  "message": "입력값이 올바르지 않습니다.",
  "errors": {
    "item_type": ["품목 유형은 필수입니다."],
    "name": ["품목명은 255자 이내로 입력하세요."]
  }
}

9. 관련 문서 (삭제 완료)

아래 문서들은 이 통합 문서로 병합되어 삭제되었습니다:

  • docs/plans/items-naming-convention.md
  • docs/plans/items-api-modification-plan.md