# 품목기준관리 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 응답 샘플 데이터" 섹션에 모든 초기 데이터의 상세 구조가 포함되어 있습니다.