- ItemMasterDataManagement 컴포넌트 구조화 (tabs, dialogs, components 분리) - HierarchyTab 타입 에러 수정 (BOMItem section_id, updated_at 추가) - API 클라이언트 구현 (item-master.ts, 13개 엔드포인트) - ItemMasterContext 구현 (상태 관리 및 데이터 흐름) - 백엔드 요구사항 문서 작성 (CORS 설정, API 스펙 등) - SSR 호환성 수정 (navigator API typeof window 체크) - 미사용 변수 ESLint 에러 해결 - Context 리팩토링 (AuthContext, RootProvider 추가) - API 유틸리티 추가 (error-handler, logger, transformers) 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
1388 lines
31 KiB
Markdown
1388 lines
31 KiB
Markdown
# 품목기준관리 API 구조
|
|
|
|
## 목차
|
|
1. [최초 화면 접근 시 필요한 API](#최초-화면-접근-시-필요한-api)
|
|
2. [각 항목별 저장 API](#각-항목별-저장-api)
|
|
3. [API 응답 구조](#api-응답-구조)
|
|
4. [에러 처리](#에러-처리)
|
|
|
|
---
|
|
|
|
## 최초 화면 접근 시 필요한 API
|
|
|
|
페이지 로드 시 `tenant.id` 기준으로 모든 기준정보를 조회합니다.
|
|
|
|
### 1. 전체 설정 조회 (통합 API)
|
|
|
|
**엔드포인트**: `GET /api/tenants/{tenantId}/item-master-config`
|
|
|
|
**목적**: 모든 기준정보를 한 번에 조회 (성능 최적화)
|
|
|
|
**Next.js 프록시**: `/api/tenants/[tenantId]/item-master-config/route.ts`
|
|
|
|
**요청 예시**:
|
|
```http
|
|
GET /api/tenants/282/item-master-config HTTP/1.1
|
|
Authorization: Bearer {access_token}
|
|
X-API-KEY: {api_key}
|
|
```
|
|
|
|
**PHP 백엔드 엔드포인트**:
|
|
```
|
|
GET /api/v1/tenants/282/item-master-config
|
|
```
|
|
|
|
**응답 구조**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"tenantId": 282,
|
|
"itemMasters": [],
|
|
"specificationMasters": [...],
|
|
"materialItemNames": [...],
|
|
"itemCategories": [...],
|
|
"itemUnits": [...],
|
|
"itemMaterials": [...],
|
|
"surfaceTreatments": [...],
|
|
"partTypeOptions": [...],
|
|
"partUsageOptions": [...],
|
|
"guideRailOptions": [...],
|
|
"itemMasterFields": [...],
|
|
"itemPages": [...]
|
|
}
|
|
}
|
|
```
|
|
|
|
### 2. 개별 조회 API (선택적 사용)
|
|
|
|
필요 시 개별 항목만 조회할 수 있습니다.
|
|
|
|
#### 2.1 규격 마스터
|
|
```http
|
|
GET /api/tenants/{tenantId}/item-master-config/specification-masters
|
|
```
|
|
|
|
#### 2.2 자재 품목명
|
|
```http
|
|
GET /api/tenants/{tenantId}/item-master-config/material-item-names
|
|
```
|
|
|
|
#### 2.3 품목 카테고리
|
|
```http
|
|
GET /api/tenants/{tenantId}/item-master-config/item-categories
|
|
```
|
|
|
|
#### 2.4 품목 단위
|
|
```http
|
|
GET /api/tenants/{tenantId}/item-master-config/item-units
|
|
```
|
|
|
|
#### 2.5 품목 재질
|
|
```http
|
|
GET /api/tenants/{tenantId}/item-master-config/item-materials
|
|
```
|
|
|
|
#### 2.6 표면처리
|
|
```http
|
|
GET /api/tenants/{tenantId}/item-master-config/surface-treatments
|
|
```
|
|
|
|
#### 2.7 부품 타입 옵션
|
|
```http
|
|
GET /api/tenants/{tenantId}/item-master-config/part-type-options
|
|
```
|
|
|
|
#### 2.8 부품 용도 옵션
|
|
```http
|
|
GET /api/tenants/{tenantId}/item-master-config/part-usage-options
|
|
```
|
|
|
|
#### 2.9 가이드레일 옵션
|
|
```http
|
|
GET /api/tenants/{tenantId}/item-master-config/guide-rail-options
|
|
```
|
|
|
|
#### 2.10 품목 마스터 필드
|
|
```http
|
|
GET /api/tenants/{tenantId}/item-master-config/item-master-fields
|
|
```
|
|
|
|
#### 2.11 품목 페이지
|
|
```http
|
|
GET /api/tenants/{tenantId}/item-master-config/item-pages
|
|
```
|
|
|
|
---
|
|
|
|
## 각 항목별 저장 API
|
|
|
|
각 섹션의 저장 버튼 클릭 시 호출되는 API입니다.
|
|
|
|
### 1. 규격 마스터 (Specification Master)
|
|
|
|
#### 등록
|
|
```http
|
|
POST /api/tenants/{tenantId}/item-master-config/specification-masters
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"specificationCode": "1219*1200",
|
|
"itemType": "RM",
|
|
"itemName": "SPHC-SD",
|
|
"fieldCount": "1",
|
|
"thickness": "1.6",
|
|
"widthA": "1219",
|
|
"length": "1200",
|
|
"isActive": true
|
|
}
|
|
```
|
|
|
|
#### 수정
|
|
```http
|
|
PUT /api/tenants/{tenantId}/item-master-config/specification-masters/{specId}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"specificationCode": "1219*1200",
|
|
"thickness": "1.8",
|
|
"isActive": true
|
|
}
|
|
```
|
|
|
|
#### 삭제
|
|
```http
|
|
DELETE /api/tenants/{tenantId}/item-master-config/specification-masters/{specId}
|
|
```
|
|
|
|
#### 일괄 저장 (추천)
|
|
```http
|
|
POST /api/tenants/{tenantId}/item-master-config/specification-masters/bulk
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"items": [
|
|
{ "specificationCode": "1219*1200", ... },
|
|
{ "specificationCode": "1219*2438", ... }
|
|
]
|
|
}
|
|
```
|
|
|
|
### 2. 자재 품목명 (Material Item Name)
|
|
|
|
#### 등록
|
|
```http
|
|
POST /api/tenants/{tenantId}/item-master-config/material-item-names
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"itemType": "RM",
|
|
"itemName": "SPHC-SD",
|
|
"category": "냉연강판",
|
|
"description": "일반냉연강판",
|
|
"isActive": true
|
|
}
|
|
```
|
|
|
|
#### 수정
|
|
```http
|
|
PUT /api/tenants/{tenantId}/item-master-config/material-item-names/{materialId}
|
|
```
|
|
|
|
#### 삭제
|
|
```http
|
|
DELETE /api/tenants/{tenantId}/item-master-config/material-item-names/{materialId}
|
|
```
|
|
|
|
#### 일괄 저장
|
|
```http
|
|
POST /api/tenants/{tenantId}/item-master-config/material-item-names/bulk
|
|
```
|
|
|
|
### 3. 품목 카테고리 (Item Category)
|
|
|
|
#### 등록
|
|
```http
|
|
POST /api/tenants/{tenantId}/item-master-config/item-categories
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"categoryType": "PRODUCT",
|
|
"category1": "스크린",
|
|
"code": "SC",
|
|
"description": "스크린 셔터",
|
|
"isActive": true
|
|
}
|
|
```
|
|
|
|
#### 수정
|
|
```http
|
|
PUT /api/tenants/{tenantId}/item-master-config/item-categories/{categoryId}
|
|
```
|
|
|
|
#### 삭제
|
|
```http
|
|
DELETE /api/tenants/{tenantId}/item-master-config/item-categories/{categoryId}
|
|
```
|
|
|
|
### 4. 품목 단위 (Item Unit)
|
|
|
|
#### 등록
|
|
```http
|
|
POST /api/tenants/{tenantId}/item-master-config/item-units
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"unitCode": "EA",
|
|
"unitName": "EA (개)",
|
|
"description": "낱개 단위",
|
|
"isActive": true
|
|
}
|
|
```
|
|
|
|
#### 수정
|
|
```http
|
|
PUT /api/tenants/{tenantId}/item-master-config/item-units/{unitId}
|
|
```
|
|
|
|
#### 삭제
|
|
```http
|
|
DELETE /api/tenants/{tenantId}/item-master-config/item-units/{unitId}
|
|
```
|
|
|
|
### 5. 품목 재질 (Item Material)
|
|
|
|
#### 등록
|
|
```http
|
|
POST /api/tenants/{tenantId}/item-master-config/item-materials
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"materialCode": "EGI-1.2T",
|
|
"materialName": "EGI 1.2T",
|
|
"materialType": "STEEL",
|
|
"thickness": "1.2T",
|
|
"description": "전기아연도금강판",
|
|
"isActive": true
|
|
}
|
|
```
|
|
|
|
#### 수정
|
|
```http
|
|
PUT /api/tenants/{tenantId}/item-master-config/item-materials/{materialId}
|
|
```
|
|
|
|
#### 삭제
|
|
```http
|
|
DELETE /api/tenants/{tenantId}/item-master-config/item-materials/{materialId}
|
|
```
|
|
|
|
### 6. 표면처리 (Surface Treatment)
|
|
|
|
#### 등록
|
|
```http
|
|
POST /api/tenants/{tenantId}/item-master-config/surface-treatments
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"treatmentCode": "POWDER",
|
|
"treatmentName": "파우더도장",
|
|
"treatmentType": "PAINTING",
|
|
"description": "분체도장",
|
|
"isActive": true
|
|
}
|
|
```
|
|
|
|
#### 수정
|
|
```http
|
|
PUT /api/tenants/{tenantId}/item-master-config/surface-treatments/{treatmentId}
|
|
```
|
|
|
|
#### 삭제
|
|
```http
|
|
DELETE /api/tenants/{tenantId}/item-master-config/surface-treatments/{treatmentId}
|
|
```
|
|
|
|
### 7. 부품 타입 옵션 (Part Type Option)
|
|
|
|
#### 등록
|
|
```http
|
|
POST /api/tenants/{tenantId}/item-master-config/part-type-options
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"partType": "ASSEMBLY",
|
|
"optionCode": "ASSY",
|
|
"optionName": "조립품",
|
|
"description": "여러 부품을 조립하는 부품",
|
|
"isActive": true
|
|
}
|
|
```
|
|
|
|
#### 수정
|
|
```http
|
|
PUT /api/tenants/{tenantId}/item-master-config/part-type-options/{optionId}
|
|
```
|
|
|
|
#### 삭제
|
|
```http
|
|
DELETE /api/tenants/{tenantId}/item-master-config/part-type-options/{optionId}
|
|
```
|
|
|
|
### 8. 부품 용도 옵션 (Part Usage Option)
|
|
|
|
#### 등록
|
|
```http
|
|
POST /api/tenants/{tenantId}/item-master-config/part-usage-options
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"usageCode": "GUIDE_RAIL",
|
|
"usageName": "가이드레일",
|
|
"description": "가이드레일용 부품",
|
|
"isActive": true
|
|
}
|
|
```
|
|
|
|
#### 수정
|
|
```http
|
|
PUT /api/tenants/{tenantId}/item-master-config/part-usage-options/{optionId}
|
|
```
|
|
|
|
#### 삭제
|
|
```http
|
|
DELETE /api/tenants/{tenantId}/item-master-config/part-usage-options/{optionId}
|
|
```
|
|
|
|
### 9. 가이드레일 옵션 (Guide Rail Option)
|
|
|
|
#### 등록
|
|
```http
|
|
POST /api/tenants/{tenantId}/item-master-config/guide-rail-options
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"optionType": "MODEL_TYPE",
|
|
"optionCode": "SCREEN",
|
|
"optionName": "스크린용",
|
|
"description": "스크린 셔터용 가이드레일",
|
|
"parentOption": null,
|
|
"isActive": true
|
|
}
|
|
```
|
|
|
|
#### 수정
|
|
```http
|
|
PUT /api/tenants/{tenantId}/item-master-config/guide-rail-options/{optionId}
|
|
```
|
|
|
|
#### 삭제
|
|
```http
|
|
DELETE /api/tenants/{tenantId}/item-master-config/guide-rail-options/{optionId}
|
|
```
|
|
|
|
### 10. 품목 마스터 필드 (Item Master Field)
|
|
|
|
#### 등록
|
|
```http
|
|
POST /api/tenants/{tenantId}/item-master-config/item-master-fields
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"name": "품목코드",
|
|
"fieldKey": "itemCode",
|
|
"property": {
|
|
"inputType": "textbox",
|
|
"required": true,
|
|
"row": 1,
|
|
"col": 1
|
|
},
|
|
"category": "공통",
|
|
"description": "품목의 고유 코드",
|
|
"isActive": true
|
|
}
|
|
```
|
|
|
|
#### 수정
|
|
```http
|
|
PUT /api/tenants/{tenantId}/item-master-config/item-master-fields/{fieldId}
|
|
```
|
|
|
|
#### 삭제
|
|
```http
|
|
DELETE /api/tenants/{tenantId}/item-master-config/item-master-fields/{fieldId}
|
|
```
|
|
|
|
### 11. 품목 페이지 (Item Page)
|
|
|
|
#### 페이지 조회
|
|
```http
|
|
GET /api/tenants/{tenantId}/item-master-config/pages/{pageId}
|
|
```
|
|
|
|
**Next.js 프록시**: `/api/tenants/[tenantId]/item-master-config/pages/[pageId]/route.ts`
|
|
|
|
#### 페이지 생성
|
|
```http
|
|
POST /api/tenants/{tenantId}/item-master-config/pages
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"pageName": "품목 등록",
|
|
"itemType": "FG",
|
|
"isActive": true,
|
|
"sections": [
|
|
{
|
|
"title": "기본정보",
|
|
"order": 1,
|
|
"isCollapsible": true,
|
|
"isCollapsed": false,
|
|
"fields": [
|
|
{
|
|
"name": "품목코드",
|
|
"fieldKey": "itemCode",
|
|
"property": { "inputType": "textbox", "required": true, "row": 1, "col": 1 }
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
#### 페이지 수정
|
|
```http
|
|
PUT /api/tenants/{tenantId}/item-master-config/pages/{pageId}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"pageName": "품목 등록 (수정)",
|
|
"isActive": true,
|
|
"sections": [...]
|
|
}
|
|
```
|
|
|
|
**Next.js 프록시**: `/api/tenants/[tenantId]/item-master-config/pages/[pageId]/route.ts`
|
|
|
|
#### 페이지 삭제
|
|
```http
|
|
DELETE /api/tenants/{tenantId}/item-master-config/pages/{pageId}
|
|
```
|
|
|
|
**Next.js 프록시**: `/api/tenants/[tenantId]/item-master-config/pages/[pageId]/route.ts`
|
|
|
|
---
|
|
|
|
## API 응답 샘플 데이터
|
|
|
|
아래 샘플 데이터는 프론트엔드에서 주석 처리한 Mock 데이터이며, **백엔드 API 응답의 실제 구조 및 데이터 예시**입니다.
|
|
|
|
### 1. 규격 마스터 (Specification Masters)
|
|
|
|
**샘플 데이터** (27개 중 일부):
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": "spec-001",
|
|
"specificationCode": "1219*1200",
|
|
"itemType": "RM",
|
|
"itemName": "SPHC-SD",
|
|
"fieldCount": "1",
|
|
"thickness": "1.6",
|
|
"widthA": "1219",
|
|
"length": "1200",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-19T10:00:00Z"
|
|
},
|
|
{
|
|
"id": "spec-002",
|
|
"specificationCode": "1219*2438",
|
|
"itemType": "RM",
|
|
"itemName": "SPHC-SD",
|
|
"fieldCount": "1",
|
|
"thickness": "1.6",
|
|
"widthA": "1219",
|
|
"length": "2438",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-19T10:00:00Z"
|
|
},
|
|
{
|
|
"id": "spec-022",
|
|
"specificationCode": "1219*1200",
|
|
"itemType": "RM",
|
|
"itemName": "STS304",
|
|
"fieldCount": "1",
|
|
"thickness": "1.5",
|
|
"widthA": "1219",
|
|
"length": "1200",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-19T10:00:00Z"
|
|
}
|
|
]
|
|
```
|
|
|
|
**데이터 설명**:
|
|
- 총 27개 규격: SPHC-SD, SPCC-SD, SECC, SGCC, SPHD, SS330, SS400, STS304, STS430
|
|
- 각 자재별로 3가지 길이 (1200, 2438, 3000mm) 규격 존재
|
|
|
|
### 2. 자재 품목명 (Material Item Names)
|
|
|
|
**샘플 데이터** (139개 중 일부):
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": "mat-001",
|
|
"itemType": "RM",
|
|
"itemName": "SPHC-SD",
|
|
"category": "냉연강판",
|
|
"description": "일반냉연강판",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-19T10:00:00Z"
|
|
},
|
|
{
|
|
"id": "mat-008",
|
|
"itemType": "RM",
|
|
"itemName": "STS304",
|
|
"category": "스테인리스",
|
|
"description": "스테인리스강판 304",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-19T10:00:00Z"
|
|
},
|
|
{
|
|
"id": "mat-101",
|
|
"itemType": "SM",
|
|
"itemName": "육각볼트",
|
|
"category": "체결부품",
|
|
"description": "육각머리볼트",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-19T10:00:00Z"
|
|
},
|
|
{
|
|
"id": "mat-201",
|
|
"itemType": "SM",
|
|
"itemName": "용접봉",
|
|
"category": "용접재료",
|
|
"description": "용접봉",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-19T10:00:00Z"
|
|
},
|
|
{
|
|
"id": "mat-301",
|
|
"itemType": "SM",
|
|
"itemName": "도료(백색)",
|
|
"category": "도장재료",
|
|
"description": "백색도료",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-19T10:00:00Z"
|
|
}
|
|
]
|
|
```
|
|
|
|
**데이터 분류**:
|
|
- **원자재 (RM)**: 21개 (냉연강판, 스테인리스, 알루미늄, 파이프류, 형강류, 비철금속)
|
|
- **부자재 (SM)**: 118개
|
|
- 체결부품 (mat-101~111): 볼트, 너트, 와셔, 나사 등
|
|
- 용접/접착 (mat-201~207): 용접봉, 실리콘, 에폭시 등
|
|
- 도장/표면처리 (mat-301~306): 도료, 프라이머 등
|
|
- 연마/연삭 (mat-401~404): 연마지, 절단석 등
|
|
- 기타 부자재 (mat-501~539): 패킹, 베어링, 모터, 샤프트 등
|
|
|
|
### 3. 품목 카테고리 (Item Categories)
|
|
|
|
**샘플 데이터** (14개):
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": "CAT-001",
|
|
"categoryType": "PRODUCT",
|
|
"category1": "스크린",
|
|
"code": "SC",
|
|
"description": "스크린 셔터",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "CAT-101",
|
|
"categoryType": "PART",
|
|
"category1": "가이드레일",
|
|
"code": "GR",
|
|
"description": "가이드레일 부품",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "CAT-201",
|
|
"categoryType": "MATERIAL",
|
|
"category1": "강판",
|
|
"code": "SP",
|
|
"description": "강판 원자재",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "CAT-301",
|
|
"categoryType": "SUB_MATERIAL",
|
|
"category1": "볼트너트",
|
|
"code": "BN",
|
|
"description": "볼트/너트",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
}
|
|
]
|
|
```
|
|
|
|
**카테고리 타입 분류**:
|
|
- **PRODUCT**: 완제품 (스크린, 철재문, 블라인드)
|
|
- **PART**: 부품 (가이드레일, 하단마감재, 케이스, 도어, 브라켓)
|
|
- **MATERIAL**: 원자재 (강판, 알루미늄, 플라스틱)
|
|
- **SUB_MATERIAL**: 부자재 (볼트너트, 나사, 페인트)
|
|
|
|
### 4. 품목 단위 (Item Units)
|
|
|
|
**샘플 데이터** (7개):
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": "UNIT-001",
|
|
"unitCode": "EA",
|
|
"unitName": "EA (개)",
|
|
"description": "낱개 단위",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "UNIT-002",
|
|
"unitCode": "SET",
|
|
"unitName": "SET (세트)",
|
|
"description": "세트 단위",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "UNIT-003",
|
|
"unitCode": "M",
|
|
"unitName": "M (미터)",
|
|
"description": "길이 단위",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "UNIT-004",
|
|
"unitCode": "KG",
|
|
"unitName": "KG (킬로그램)",
|
|
"description": "무게 단위",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "UNIT-006",
|
|
"unitCode": "M2",
|
|
"unitName": "㎡ (제곱미터)",
|
|
"description": "면적 단위",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "UNIT-007",
|
|
"unitCode": "BOX",
|
|
"unitName": "BOX (박스)",
|
|
"description": "박스 단위",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
}
|
|
]
|
|
```
|
|
|
|
### 5. 품목 재질 (Item Materials)
|
|
|
|
**샘플 데이터** (7개):
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": "MAT-001",
|
|
"materialCode": "EGI-1.2T",
|
|
"materialName": "EGI 1.2T",
|
|
"materialType": "STEEL",
|
|
"thickness": "1.2T",
|
|
"description": "전기아연도금강판",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "MAT-002",
|
|
"materialCode": "EGI-1.55T",
|
|
"materialName": "EGI 1.55T",
|
|
"materialType": "STEEL",
|
|
"thickness": "1.55T",
|
|
"description": "전기아연도금강판",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "MAT-004",
|
|
"materialCode": "SUS-1.2T",
|
|
"materialName": "SUS 1.2T",
|
|
"materialType": "STEEL",
|
|
"thickness": "1.2T",
|
|
"description": "스테인리스 강판",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "MAT-006",
|
|
"materialCode": "AL-6063",
|
|
"materialName": "알루미늄 6063",
|
|
"materialType": "ALUMINUM",
|
|
"description": "알루미늄 압출재",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
}
|
|
]
|
|
```
|
|
|
|
**재질 타입**:
|
|
- **STEEL**: EGI (전기아연도금강판), SUS (스테인리스)
|
|
- **ALUMINUM**: AL-6063, AL-6061
|
|
|
|
### 6. 표면처리 (Surface Treatments)
|
|
|
|
**샘플 데이터** (5개):
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": "TREAT-001",
|
|
"treatmentCode": "NONE",
|
|
"treatmentName": "무도장",
|
|
"treatmentType": "NONE",
|
|
"description": "표면처리 없음",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "TREAT-002",
|
|
"treatmentCode": "POWDER",
|
|
"treatmentName": "파우더도장",
|
|
"treatmentType": "PAINTING",
|
|
"description": "분체도장",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "TREAT-003",
|
|
"treatmentCode": "ANODIZING",
|
|
"treatmentName": "아노다이징",
|
|
"treatmentType": "COATING",
|
|
"description": "알루미늄 양극산화처리",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "TREAT-004",
|
|
"treatmentCode": "ZINC",
|
|
"treatmentName": "아연도금",
|
|
"treatmentType": "PLATING",
|
|
"description": "아연 도금처리",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
}
|
|
]
|
|
```
|
|
|
|
**처리 타입**:
|
|
- **NONE**: 무도장
|
|
- **PAINTING**: 도장 (파우더도장)
|
|
- **COATING**: 코팅 (아노다이징)
|
|
- **PLATING**: 도금 (아연도금, 크롬도금)
|
|
|
|
### 7. 부품 타입 옵션 (Part Type Options)
|
|
|
|
**샘플 데이터** (3개):
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": "PTYPE-001",
|
|
"partType": "ASSEMBLY",
|
|
"optionCode": "ASSY",
|
|
"optionName": "조립품",
|
|
"description": "여러 부품을 조립하는 부품",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "PTYPE-002",
|
|
"partType": "BENDING",
|
|
"optionCode": "BEND",
|
|
"optionName": "절곡품",
|
|
"description": "절곡 가공 부품",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "PTYPE-003",
|
|
"partType": "PURCHASED",
|
|
"optionCode": "PURCH",
|
|
"optionName": "구매품",
|
|
"description": "외부에서 구매하는 부품",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
}
|
|
]
|
|
```
|
|
|
|
### 8. 부품 용도 옵션 (Part Usage Options)
|
|
|
|
**샘플 데이터** (6개):
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": "USAGE-001",
|
|
"usageCode": "GUIDE_RAIL",
|
|
"usageName": "가이드레일",
|
|
"description": "가이드레일용 부품",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "USAGE-002",
|
|
"usageCode": "BOTTOM_FINISH",
|
|
"usageName": "하단마감재",
|
|
"description": "하단마감재용 부품",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "USAGE-003",
|
|
"usageCode": "CASE",
|
|
"usageName": "케이스",
|
|
"description": "케이스용 부품",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "USAGE-004",
|
|
"usageCode": "DOOR",
|
|
"usageName": "도어",
|
|
"description": "도어용 부품",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
}
|
|
]
|
|
```
|
|
|
|
### 9. 가이드레일 옵션 (Guide Rail Options)
|
|
|
|
**샘플 데이터** (13개 중 일부):
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": "GR-001",
|
|
"optionType": "MODEL_TYPE",
|
|
"optionCode": "SCREEN",
|
|
"optionName": "스크린용",
|
|
"description": "스크린 셔터용 가이드레일",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "GR-011",
|
|
"optionType": "MODEL",
|
|
"optionCode": "T40",
|
|
"optionName": "T40",
|
|
"parentOption": "SCREEN",
|
|
"description": "T40 모델",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "GR-021",
|
|
"optionType": "CERTIFICATION",
|
|
"optionCode": "KFI",
|
|
"optionName": "KFI인증",
|
|
"description": "KFI 인증",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "GR-031",
|
|
"optionType": "SHAPE",
|
|
"optionCode": "ROUND",
|
|
"optionName": "R형",
|
|
"description": "라운드형",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "GR-041",
|
|
"optionType": "FINISH",
|
|
"optionCode": "POWDER",
|
|
"optionName": "파우더도장",
|
|
"description": "파우더 도장 마감",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "GR-051",
|
|
"optionType": "LENGTH",
|
|
"optionCode": "3000",
|
|
"optionName": "3000mm",
|
|
"description": "3미터",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
}
|
|
]
|
|
```
|
|
|
|
**옵션 타입 분류**:
|
|
- **MODEL_TYPE**: 제품 유형 (스크린용, 철재용)
|
|
- **MODEL**: 모델명 (T40, T60, 프리미엄) - `parentOption` 참조
|
|
- **CERTIFICATION**: 인증 (KFI인증, 미인증)
|
|
- **SHAPE**: 형상 (R형, ㄱ형)
|
|
- **FINISH**: 마감 (파우더도장, 아노다이징)
|
|
- **LENGTH**: 길이 (3000mm, 4000mm, 5000mm)
|
|
|
|
### 10. 품목 마스터 필드 (Item Master Fields)
|
|
|
|
**샘플 데이터** (5개):
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": "MASTER-001",
|
|
"name": "품목코드",
|
|
"fieldKey": "itemCode",
|
|
"property": {
|
|
"inputType": "textbox",
|
|
"required": true,
|
|
"row": 1,
|
|
"col": 1
|
|
},
|
|
"category": "공통",
|
|
"description": "품목의 고유 코드",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "MASTER-002",
|
|
"name": "품목명",
|
|
"fieldKey": "itemName",
|
|
"property": {
|
|
"inputType": "textbox",
|
|
"required": true,
|
|
"row": 1,
|
|
"col": 1
|
|
},
|
|
"category": "공통",
|
|
"description": "품목의 이름",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "MASTER-003",
|
|
"name": "단위",
|
|
"fieldKey": "unit",
|
|
"property": {
|
|
"inputType": "dropdown",
|
|
"required": true,
|
|
"row": 1,
|
|
"col": 1,
|
|
"options": ["EA", "SET", "KG", "M", "BOX"]
|
|
},
|
|
"category": "공통",
|
|
"description": "품목의 단위",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
},
|
|
{
|
|
"id": "MASTER-004",
|
|
"name": "재질",
|
|
"fieldKey": "material",
|
|
"property": {
|
|
"inputType": "dropdown",
|
|
"required": false,
|
|
"row": 1,
|
|
"col": 1,
|
|
"options": ["EGI 1.2T", "SUS 1.2T", "AL 1.5T"]
|
|
},
|
|
"category": "부품",
|
|
"description": "부품의 재질",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01"
|
|
}
|
|
]
|
|
```
|
|
|
|
**inputType 종류**:
|
|
- `textbox`: 텍스트 입력
|
|
- `dropdown`: 드롭다운 선택 (options 필수)
|
|
|
|
### 11. 품목 페이지 (Item Pages)
|
|
|
|
**샘플 구조** (실제 Mock 데이터는 빈 배열):
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": "PAGE-001",
|
|
"pageName": "제품 등록",
|
|
"itemType": "FG",
|
|
"isActive": true,
|
|
"createdAt": "2025-01-01",
|
|
"sections": [
|
|
{
|
|
"id": "SECTION-001",
|
|
"title": "기본정보",
|
|
"order": 1,
|
|
"isCollapsible": true,
|
|
"isCollapsed": false,
|
|
"fields": [
|
|
{
|
|
"name": "품목코드",
|
|
"fieldKey": "itemCode",
|
|
"property": {
|
|
"inputType": "textbox",
|
|
"required": true,
|
|
"row": 1,
|
|
"col": 1
|
|
}
|
|
},
|
|
{
|
|
"name": "품목명",
|
|
"fieldKey": "itemName",
|
|
"property": {
|
|
"inputType": "textbox",
|
|
"required": true,
|
|
"row": 1,
|
|
"col": 2
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
```
|
|
|
|
### 전체 설정 조회 API 응답 예시
|
|
|
|
`GET /api/tenants/282/item-master-config` 응답:
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"tenantId": 282,
|
|
"itemMasters": [],
|
|
"specificationMasters": [
|
|
/* 위의 27개 규격 마스터 데이터 */
|
|
],
|
|
"materialItemNames": [
|
|
/* 위의 139개 자재 품목명 데이터 */
|
|
],
|
|
"itemCategories": [
|
|
/* 위의 14개 품목 카테고리 데이터 */
|
|
],
|
|
"itemUnits": [
|
|
/* 위의 7개 품목 단위 데이터 */
|
|
],
|
|
"itemMaterials": [
|
|
/* 위의 7개 품목 재질 데이터 */
|
|
],
|
|
"surfaceTreatments": [
|
|
/* 위의 5개 표면처리 데이터 */
|
|
],
|
|
"partTypeOptions": [
|
|
/* 위의 3개 부품 타입 옵션 데이터 */
|
|
],
|
|
"partUsageOptions": [
|
|
/* 위의 6개 부품 용도 옵션 데이터 */
|
|
],
|
|
"guideRailOptions": [
|
|
/* 위의 13개 가이드레일 옵션 데이터 */
|
|
],
|
|
"itemMasterFields": [
|
|
/* 위의 5개 품목 마스터 필드 데이터 */
|
|
],
|
|
"itemPages": []
|
|
}
|
|
}
|
|
```
|
|
|
|
**주의사항**:
|
|
- `id` 필드는 백엔드에서 자동 생성 (UUID 또는 Auto Increment)
|
|
- `createdAt`, `updatedAt` 필드는 백엔드에서 자동 관리
|
|
- Mock 데이터의 날짜는 예시용이며, 실제로는 백엔드에서 생성된 timestamp 사용
|
|
|
|
---
|
|
|
|
## API 응답 구조
|
|
|
|
### 성공 응답
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": "spec-001",
|
|
"specificationCode": "1219*1200",
|
|
"itemType": "RM",
|
|
"itemName": "SPHC-SD",
|
|
"createdAt": "2025-01-19T10:00:00Z",
|
|
"updatedAt": "2025-01-19T10:00:00Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
### 에러 응답
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "VALIDATION_ERROR",
|
|
"message": "필수 필드가 누락되었습니다.",
|
|
"details": {
|
|
"field": "itemName",
|
|
"reason": "required"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### 일괄 저장 응답
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"total": 10,
|
|
"created": 8,
|
|
"updated": 2,
|
|
"failed": 0,
|
|
"items": [...]
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 에러 처리
|
|
|
|
### HTTP 상태 코드
|
|
|
|
| 코드 | 의미 | 설명 |
|
|
|------|------|------|
|
|
| 200 | OK | 성공 |
|
|
| 201 | Created | 생성 성공 |
|
|
| 400 | Bad Request | 잘못된 요청 |
|
|
| 401 | Unauthorized | 인증 실패 |
|
|
| 403 | Forbidden | 권한 없음 (테넌트 불일치) |
|
|
| 404 | Not Found | 리소스 없음 |
|
|
| 409 | Conflict | 중복 데이터 |
|
|
| 500 | Internal Server Error | 서버 오류 |
|
|
|
|
### 에러 코드
|
|
|
|
| 에러 코드 | 설명 |
|
|
|----------|------|
|
|
| `VALIDATION_ERROR` | 유효성 검사 실패 |
|
|
| `UNAUTHORIZED` | 인증 필요 |
|
|
| `FORBIDDEN` | 권한 없음 |
|
|
| `NOT_FOUND` | 리소스 없음 |
|
|
| `DUPLICATE` | 중복 데이터 |
|
|
| `SERVER_ERROR` | 서버 오류 |
|
|
|
|
---
|
|
|
|
## Next.js API Routes 구조
|
|
|
|
### 기존 구현 완료
|
|
1. ✅ `/api/tenants/[tenantId]/item-master-config/route.ts`
|
|
- GET: 전체 설정 조회
|
|
- POST: 전체 설정 생성
|
|
- PUT: 전체 설정 수정
|
|
|
|
2. ✅ `/api/tenants/[tenantId]/item-master-config/pages/[pageId]/route.ts`
|
|
- GET: 특정 페이지 조회
|
|
- PUT: 특정 페이지 수정
|
|
- DELETE: 특정 페이지 삭제
|
|
|
|
### 추가 필요 (선택사항)
|
|
개별 항목 CRUD가 필요한 경우 추가 라우트 생성:
|
|
```
|
|
/api/tenants/[tenantId]/item-master-config/
|
|
├── specification-masters/
|
|
├── material-item-names/
|
|
├── item-categories/
|
|
├── item-units/
|
|
├── item-materials/
|
|
├── surface-treatments/
|
|
├── part-type-options/
|
|
├── part-usage-options/
|
|
├── guide-rail-options/
|
|
├── item-master-fields/
|
|
└── pages/
|
|
└── [pageId]/
|
|
```
|
|
|
|
---
|
|
|
|
## 캐싱 전략
|
|
|
|
### TenantAwareCache 사용
|
|
```typescript
|
|
// ItemMasterContext.tsx에서 구현됨
|
|
cache.set('itemMasters', data, 3600000); // 1시간 TTL
|
|
cache.set('specificationMasters', data, 3600000);
|
|
// ... 기타 항목들
|
|
```
|
|
|
|
### 캐시 키 구조
|
|
```
|
|
mes-{tenantId}-itemMasters
|
|
mes-{tenantId}-specificationMasters
|
|
mes-{tenantId}-materialItemNames
|
|
mes-{tenantId}-itemCategories
|
|
mes-{tenantId}-itemUnits
|
|
mes-{tenantId}-itemMaterials
|
|
mes-{tenantId}-surfaceTreatments
|
|
mes-{tenantId}-partTypeOptions
|
|
mes-{tenantId}-partUsageOptions
|
|
mes-{tenantId}-guideRailOptions
|
|
mes-{tenantId}-itemMasterFields
|
|
mes-{tenantId}-itemPages
|
|
```
|
|
|
|
### 캐시 무효화
|
|
- 테넌트 전환 시: 이전 테넌트 캐시 자동 삭제
|
|
- 로그아웃 시: 현재 테넌트 캐시 삭제
|
|
- 데이터 저장 시: 해당 항목 캐시 무효화
|
|
|
|
---
|
|
|
|
## 프론트엔드 구현 체크리스트
|
|
|
|
### ItemMasterContext.tsx
|
|
- [ ] Mock 데이터 주석 처리
|
|
- [ ] API 호출 함수 구현
|
|
- [ ] TenantAwareCache 연동
|
|
- [ ] 에러 처리 추가
|
|
- [ ] 로딩 상태 관리
|
|
|
|
### ItemMasterDataManagement.tsx
|
|
- [ ] 각 섹션별 저장 버튼 이벤트
|
|
- [ ] API 호출 로직
|
|
- [ ] 성공/실패 토스트 메시지
|
|
- [ ] 낙관적 업데이트 (Optimistic UI)
|
|
- [ ] 에러 핸들링
|
|
|
|
### 백엔드 요구사항
|
|
|
|
#### 필수 구현
|
|
- [ ] PHP `/api/v1/tenants/{tenantId}/item-master-config` 엔드포인트 구현
|
|
- [ ] 테넌트 검증 로직 (인증된 사용자의 tenant.id와 URL의 tenantId 일치 확인)
|
|
- [ ] 데이터베이스 테이블 생성
|
|
- [ ] 트랜잭션 처리
|
|
- [ ] 에러 응답 표준화
|
|
|
|
#### DB 초기 데이터 등록 (Seeding)
|
|
|
|
**중요**: 모든 데이터는 API로 제공되므로, DB에 초기 데이터 등록이 필수입니다.
|
|
|
|
**시스템 기본값** (모든 테넌트 공통 또는 테넌트 생성 시 자동 복사):
|
|
|
|
1. **품목 단위** (7개)
|
|
- EA, SET, M, KG, L, M2, BOX
|
|
- 우선순위: 🔴 높음 (필수)
|
|
|
|
2. **품목 재질** (7개)
|
|
- EGI-1.2T, EGI-1.55T, EGI-2.0T, SUS-1.2T, SUS-1.5T, AL-6063, AL-6061
|
|
- 우선순위: 🔴 높음 (필수)
|
|
|
|
3. **표면처리** (5개)
|
|
- 무도장, 파우더도장, 아노다이징, 아연도금, 크롬도금
|
|
- 우선순위: 🔴 높음 (필수)
|
|
|
|
4. **품목 카테고리** (14개)
|
|
- PRODUCT, PART, MATERIAL, SUB_MATERIAL 타입별 카테고리
|
|
- 우선순위: 🟡 중간
|
|
|
|
5. **부품 타입 옵션** (3개)
|
|
- 조립품, 절곡품, 구매품
|
|
- 우선순위: 🟡 중간
|
|
|
|
6. **부품 용도 옵션** (6개)
|
|
- 가이드레일, 하단마감재, 케이스, 도어, 브라켓, 일반
|
|
- 우선순위: 🟡 중간
|
|
|
|
7. **품목 마스터 필드** (5개)
|
|
- 품목코드, 품목명, 단위, 재질, 표면처리
|
|
- 우선순위: 🟡 중간
|
|
|
|
**테넌트별 데이터** (선택적, 빈 배열로 시작 가능):
|
|
|
|
8. **규격 마스터** (27개 샘플)
|
|
- 우선순위: 🟢 낮음 (테스트/샘플 데이터)
|
|
|
|
9. **자재 품목명** (139개 샘플)
|
|
- 우선순위: 🟢 낮음 (테스트/샘플 데이터)
|
|
|
|
10. **가이드레일 옵션** (13개 샘플)
|
|
- 우선순위: 🟢 낮음 (테스트/샘플 데이트)
|
|
|
|
**초기 데이터 등록 방법**:
|
|
```sql
|
|
-- 예시: 품목 단위 초기 데이터
|
|
INSERT INTO item_units (tenant_id, unitCode, unitName, description, isActive) VALUES
|
|
(NULL, 'EA', 'EA (개)', '낱개 단위', true), -- tenant_id NULL = 전체 공통
|
|
(NULL, 'SET', 'SET (세트)', '세트 단위', true),
|
|
(NULL, 'M', 'M (미터)', '길이 단위', true),
|
|
(NULL, 'KG', 'KG (킬로그램)', '무게 단위', true),
|
|
(NULL, 'L', 'L (리터)', '부피 단위', true),
|
|
(NULL, 'M2', '㎡ (제곱미터)', '면적 단위', true),
|
|
(NULL, 'BOX', 'BOX (박스)', '박스 단위', true);
|
|
|
|
-- 또는 테넌트 생성 시 자동 복사
|
|
CREATE TRIGGER copy_default_data_on_tenant_create
|
|
AFTER INSERT ON tenants
|
|
FOR EACH ROW
|
|
BEGIN
|
|
-- 기본값 자동 복사 로직
|
|
END;
|
|
```
|
|
|
|
**API 응답 예시**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"tenantId": 282,
|
|
"itemUnits": [
|
|
{
|
|
"id": "UNIT-001",
|
|
"unitCode": "EA",
|
|
"unitName": "EA (개)",
|
|
"description": "낱개 단위",
|
|
"isActive": true
|
|
}
|
|
// ... 6개 더
|
|
],
|
|
"itemMaterials": [/* 7개 기본 재질 */],
|
|
"surfaceTreatments": [/* 5개 기본 표면처리 */],
|
|
"itemCategories": [/* 14개 */],
|
|
"partTypeOptions": [/* 3개 */],
|
|
"partUsageOptions": [/* 6개 */],
|
|
"itemMasterFields": [/* 5개 */],
|
|
"specificationMasters": [], // 빈 배열 (테넌트별 데이터)
|
|
"materialItemNames": [],
|
|
"guideRailOptions": [],
|
|
"itemPages": []
|
|
}
|
|
}
|
|
```
|
|
|
|
**참고**: 위의 "API 응답 샘플 데이터" 섹션에 모든 초기 데이터의 상세 구조가 포함되어 있습니다. |