29 KiB
Items API 통합 개발 계획
Items API 명명 체계 통일 + Material CRUD 지원 추가
작성일: 2025-12-09 상태: 진행 예정
1. 개요
1.1 목표
- 명명 체계 통일:
item_type파라미터의 이중 의미 충돌 해소 - 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 테넌트별 품목 유형 관리
- 품목 유형은 테넌트(업체)별로 커스터마이징 가능
attributesJSON 필드 활용 (스키마 변경 없음)- 캐시를 통한 성능 최적화
// 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
작업 내용:
-
import 추가:
use App\Helpers\ItemTypeHelper; -
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); }); -
getItem() 수정: item_type 파라미터를 FG/PT/SM/RM/CS로 받도록 변경
// Before: getItem('PRODUCT', $id, ...) // After: getItem($id, 'FG', ...) -
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); } -
updateMaterial() 추가: Material 수정 로직
-
deleteItem() 수정: item_type 파라미터 추가
public function deleteItem(int $id, string $itemType = 'FG'): void -
deleteMaterial() 추가: Material 삭제 로직
-
batchDeleteItems() 수정: item_type 지원
-
getItemByCode() 수정: Product 없으면 Material에서 조회
-
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
작업 내용:
-
show() 수정: 기본값 'PRODUCT' → 'FG'
$itemType = strtoupper($request->input('item_type', 'FG')); -
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')); } -
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
작업 내용:
-
Item 스키마 보완:
item_type(FG|PT|SM|RM|CS) - 품목 유형- Material 전용 필드 추가
-
ItemCreateRequest 스키마 보완:
- Material 전용 필드 추가
-
ItemUpdateRequest 스키마 보완:
item_type필수 (FG|PT|SM|RM|CS)- Material 전용 필드 추가
-
ItemBatchDeleteRequest 스키마 보완:
item_type필드 추가
-
show 엔드포인트:
- item_type 값 변경 (common_codes): PRODUCT|MATERIAL → FG|PT|SM|RM|CS
-
destroy 엔드포인트:
- item_type 쿼리 파라미터 추가
-
batchDestroy 엔드포인트:
- Request에 item_type 필드 추가
-
showByCode 엔드포인트:
- Product/Material 모두 지원 설명 추가
체크리스트:
- Item 스키마 보완
- ItemCreateRequest 스키마 보완
- ItemUpdateRequest 스키마 보완
- ItemBatchDeleteRequest 스키마 보완
- show 엔드포인트 item_type 값 변경
- destroy 엔드포인트 item_type 파라미터 추가
- batchDestroy 엔드포인트 스키마 수정
- showByCode 엔드포인트 설명 보완
Phase 6: 검증 (10분)
작업 내용:
-
Pint 코드 포맷팅
cd api && ./vendor/bin/pint -
Swagger 생성 테스트
cd api && php artisan l5-swagger:generate -
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.mddocs/plans/items-api-modification-plan.md