- 페이지 삭제 시 독립 섹션 목록 갱신 추가 (독립 엔티티 아키텍처) - ItemForm 컴포넌트 분리 완료 (1607→415줄, 74% 감소) - ItemMasterDataManagement 중복 코드 제거 (getInputTypeLabel 헬퍼) - 문서 업데이트 (realtime-sync-fixes.md) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1114 lines
27 KiB
Markdown
1114 lines
27 KiB
Markdown
# 품목관리 페이지 전체 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` 변경, 문서 전체 정합성 검토 완료 | |