340 lines
10 KiB
Markdown
340 lines
10 KiB
Markdown
# 품목기준관리(ItemMaster) API 가이드
|
|
|
|
> 품목 입력 화면을 구성하는 **페이지-섹션-필드** 구조 관리 시스템
|
|
|
|
---
|
|
|
|
## 1. 개요
|
|
|
|
### 1.1 핵심 개념
|
|
|
|
| 엔티티 | 테이블 | 설명 |
|
|
|--------|--------|------|
|
|
| **Page** | `item_pages` | 품목 유형별 화면 (FG, PT, SM, RM, CS) |
|
|
| **Section** | `item_sections` | 페이지 내 논리적 영역 |
|
|
| **Field** | `item_fields` | 섹션 내 입력 항목 |
|
|
| **BomItem** | `item_bom_items` | BOM 섹션 내 부품 항목 |
|
|
| **CustomTab** | `custom_tabs` | 커스텀 탭 설정 |
|
|
| **UnitOption** | `unit_options` | 단위 옵션 |
|
|
|
|
### 1.2 아키텍처
|
|
|
|
- **독립 엔티티 구조**: 섹션, 필드, BOM은 독립적으로 존재하며 재사용 가능
|
|
- **링크 테이블**: `entity_relationships`로 관계 관리
|
|
- **연결 잠금**: 중요한 구조는 잠금으로 보호 가능
|
|
|
|
```
|
|
ItemPage (item_type: FG, PT, SM, RM, CS)
|
|
│
|
|
│ entity_relationships (is_locked)
|
|
▼
|
|
ItemSection (type: default, bom, custom)
|
|
│
|
|
├─ entity_relationships → ItemField
|
|
└─ entity_relationships → ItemBomItem
|
|
```
|
|
|
|
---
|
|
|
|
## 2. API 엔드포인트
|
|
|
|
### 2.1 초기화
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|--------|----------|------|
|
|
| GET | `/api/v1/item-master/init` | 전체 데이터 로드 |
|
|
|
|
**응답 구조:**
|
|
```json
|
|
{
|
|
"pages": [], // 페이지 + 연결된 섹션/필드
|
|
"sections": [], // 모든 독립 섹션
|
|
"fields": [], // 모든 독립 필드
|
|
"customTabs": [], // 커스텀 탭
|
|
"unitOptions": [] // 단위 옵션
|
|
}
|
|
```
|
|
|
|
### 2.2 페이지
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|--------|----------|------|
|
|
| GET | `/api/v1/item-master/pages` | 페이지 목록 |
|
|
| POST | `/api/v1/item-master/pages` | 페이지 생성 |
|
|
| PUT | `/api/v1/item-master/pages/{id}` | 페이지 수정 |
|
|
| DELETE | `/api/v1/item-master/pages/{id}` | 페이지 삭제 |
|
|
|
|
### 2.3 섹션
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|--------|----------|------|
|
|
| GET | `/api/v1/item-master/sections` | 독립 섹션 목록 |
|
|
| POST | `/api/v1/item-master/sections` | 독립 섹션 생성 |
|
|
| POST | `/api/v1/item-master/pages/{pageId}/sections` | 섹션 생성 + 페이지 연결 |
|
|
| PUT | `/api/v1/item-master/sections/{id}` | 섹션 수정 |
|
|
| DELETE | `/api/v1/item-master/sections/{id}` | 섹션 삭제 |
|
|
| POST | `/api/v1/item-master/sections/{id}/clone` | 섹션 복제 |
|
|
| GET | `/api/v1/item-master/sections/{id}/usage` | 사용처 조회 |
|
|
| PUT | `/api/v1/item-master/pages/{pageId}/sections/reorder` | 섹션 순서 변경 |
|
|
|
|
### 2.4 필드
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|--------|----------|------|
|
|
| GET | `/api/v1/item-master/fields` | 독립 필드 목록 |
|
|
| POST | `/api/v1/item-master/fields` | 독립 필드 생성 |
|
|
| POST | `/api/v1/item-master/sections/{sectionId}/fields` | 필드 생성 + 섹션 연결 |
|
|
| PUT | `/api/v1/item-master/fields/{id}` | 필드 수정 |
|
|
| DELETE | `/api/v1/item-master/fields/{id}` | 필드 삭제 |
|
|
| POST | `/api/v1/item-master/fields/{id}/clone` | 필드 복제 |
|
|
| GET | `/api/v1/item-master/fields/{id}/usage` | 사용처 조회 |
|
|
| PUT | `/api/v1/item-master/sections/{sectionId}/fields/reorder` | 필드 순서 변경 |
|
|
|
|
### 2.5 BOM
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|--------|----------|------|
|
|
| GET | `/api/v1/item-master/bom-items` | 독립 BOM 목록 |
|
|
| POST | `/api/v1/item-master/bom-items` | 독립 BOM 생성 |
|
|
| POST | `/api/v1/item-master/sections/{sectionId}/bom-items` | BOM 생성 + 섹션 연결 |
|
|
| PUT | `/api/v1/item-master/bom-items/{id}` | BOM 수정 |
|
|
| DELETE | `/api/v1/item-master/bom-items/{id}` | BOM 삭제 |
|
|
|
|
### 2.6 섹션 템플릿
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|--------|----------|------|
|
|
| GET | `/api/v1/item-master/section-templates` | 템플릿 목록 |
|
|
| POST | `/api/v1/item-master/section-templates` | 템플릿 생성 |
|
|
| PUT | `/api/v1/item-master/section-templates/{id}` | 템플릿 수정 |
|
|
| DELETE | `/api/v1/item-master/section-templates/{id}` | 템플릿 삭제 |
|
|
|
|
### 2.7 커스텀 탭
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|--------|----------|------|
|
|
| GET | `/api/v1/item-master/custom-tabs` | 탭 목록 |
|
|
| POST | `/api/v1/item-master/custom-tabs` | 탭 생성 |
|
|
| PUT | `/api/v1/item-master/custom-tabs/{id}` | 탭 수정 |
|
|
| DELETE | `/api/v1/item-master/custom-tabs/{id}` | 탭 삭제 |
|
|
| PUT | `/api/v1/item-master/custom-tabs/reorder` | 탭 순서 변경 |
|
|
|
|
### 2.8 단위 옵션
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|--------|----------|------|
|
|
| GET | `/api/v1/item-master/unit-options` | 단위 목록 |
|
|
| POST | `/api/v1/item-master/unit-options` | 단위 생성 |
|
|
| DELETE | `/api/v1/item-master/unit-options/{id}` | 단위 삭제 |
|
|
|
|
### 2.9 엔티티 관계 (Link/Unlink)
|
|
|
|
**페이지-섹션 연결:**
|
|
| Method | Endpoint | 설명 |
|
|
|--------|----------|------|
|
|
| POST | `/api/v1/item-master/pages/{pageId}/link-section` | 섹션 연결 |
|
|
| DELETE | `/api/v1/item-master/pages/{pageId}/unlink-section/{sectionId}` | 섹션 연결 해제 |
|
|
|
|
**페이지-필드 연결:**
|
|
| Method | Endpoint | 설명 |
|
|
|--------|----------|------|
|
|
| POST | `/api/v1/item-master/pages/{pageId}/link-field` | 필드 연결 |
|
|
| DELETE | `/api/v1/item-master/pages/{pageId}/unlink-field/{fieldId}` | 필드 연결 해제 |
|
|
|
|
**섹션-필드 연결:**
|
|
| Method | Endpoint | 설명 |
|
|
|--------|----------|------|
|
|
| POST | `/api/v1/item-master/sections/{sectionId}/link-field` | 필드 연결 |
|
|
| DELETE | `/api/v1/item-master/sections/{sectionId}/unlink-field/{fieldId}` | 필드 연결 해제 |
|
|
|
|
**섹션-BOM 연결:**
|
|
| Method | Endpoint | 설명 |
|
|
|--------|----------|------|
|
|
| POST | `/api/v1/item-master/sections/{sectionId}/link-bom` | BOM 연결 |
|
|
| DELETE | `/api/v1/item-master/sections/{sectionId}/unlink-bom/{bomId}` | BOM 연결 해제 |
|
|
|
|
**관계 조회/정렬:**
|
|
| Method | Endpoint | 설명 |
|
|
|--------|----------|------|
|
|
| GET | `/api/v1/item-master/pages/{pageId}/relationships` | 페이지 관계 조회 |
|
|
| GET | `/api/v1/item-master/pages/{pageId}/structure` | 페이지 구조 조회 |
|
|
| GET | `/api/v1/item-master/sections/{sectionId}/relationships` | 섹션 관계 조회 |
|
|
| POST | `/api/v1/item-master/relationships/reorder` | 관계 순서 변경 |
|
|
|
|
---
|
|
|
|
## 3. 데이터 구조
|
|
|
|
### 3.1 ItemPage
|
|
|
|
```typescript
|
|
interface ItemPage {
|
|
id: number;
|
|
tenant_id: number;
|
|
group_id: number;
|
|
page_name: string;
|
|
item_type: 'FG' | 'PT' | 'SM' | 'RM' | 'CS';
|
|
source_table: 'products' | 'materials';
|
|
absolute_path?: string;
|
|
is_active: boolean;
|
|
sections: ItemSection[]; // init 응답에 포함
|
|
}
|
|
```
|
|
|
|
### 3.2 ItemSection
|
|
|
|
```typescript
|
|
interface ItemSection {
|
|
id: number;
|
|
tenant_id: number;
|
|
group_id: number;
|
|
title: string;
|
|
type: string;
|
|
order_no: number;
|
|
is_template: boolean;
|
|
is_default: boolean;
|
|
is_locked?: boolean; // 연결 잠금 상태
|
|
description?: string;
|
|
fields?: ItemField[];
|
|
bom_items?: ItemBomItem[];
|
|
}
|
|
```
|
|
|
|
### 3.3 ItemField
|
|
|
|
```typescript
|
|
interface ItemField {
|
|
id: number;
|
|
tenant_id: number;
|
|
group_id: number;
|
|
field_name: string;
|
|
field_key: string; // 저장 시 사용할 키
|
|
field_type: FieldType;
|
|
order_no: number;
|
|
is_required: boolean;
|
|
is_common: boolean;
|
|
is_active: boolean;
|
|
is_locked: boolean;
|
|
default_value?: string;
|
|
placeholder?: string;
|
|
display_condition?: object; // 조건부 표시
|
|
validation_rules?: object; // 유효성 검사 규칙
|
|
options?: object; // dropdown 옵션 등
|
|
properties?: object; // 추가 설정
|
|
category?: string;
|
|
description?: string;
|
|
}
|
|
|
|
type FieldType = 'textbox' | 'number' | 'dropdown' | 'checkbox' | 'date' | 'textarea';
|
|
```
|
|
|
|
### 3.4 EntityRelationship
|
|
|
|
```typescript
|
|
interface EntityRelationship {
|
|
id: number;
|
|
tenant_id: number;
|
|
group_id: number;
|
|
parent_type: 'page' | 'section';
|
|
parent_id: number;
|
|
child_type: 'section' | 'field' | 'bom';
|
|
child_id: number;
|
|
order_no: number;
|
|
is_locked: boolean;
|
|
locked_by?: number;
|
|
locked_at?: string;
|
|
metadata?: object;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. 잠금(Lock) 기능
|
|
|
|
### 4.1 잠금의 의미
|
|
|
|
**연결이 잠기면:**
|
|
- 해당 연결(관계)를 해제할 수 없음
|
|
- 연결된 자식 엔티티를 삭제할 수 없음
|
|
- 이름 변경, 속성 추가 등 **비구조적 수정은 허용**
|
|
|
|
```
|
|
예시: page→section 연결이 잠김
|
|
├─ ❌ 섹션을 페이지에서 분리할 수 없음
|
|
├─ ❌ 해당 섹션을 삭제할 수 없음
|
|
├─ ✅ 섹션 제목 변경 가능
|
|
└─ ✅ 섹션에 새 필드 추가 가능
|
|
```
|
|
|
|
### 4.2 잠금 상태 확인
|
|
|
|
init API 응답에 `is_locked` 필드가 포함됩니다.
|
|
|
|
```json
|
|
{
|
|
"pages": [{
|
|
"id": 1,
|
|
"sections": [{
|
|
"id": 10,
|
|
"is_locked": true,
|
|
"fields": [{
|
|
"id": 100,
|
|
"is_locked": false
|
|
}]
|
|
}]
|
|
}]
|
|
}
|
|
```
|
|
|
|
### 4.3 잠금 관련 에러
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"message": "잠금된 연결은 해제할 수 없습니다.",
|
|
"error": "entity_protected_by_locked_relationship"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5. 필드 타입
|
|
|
|
| field_type | 설명 | 렌더링 컴포넌트 |
|
|
|------------|------|----------------|
|
|
| `textbox` | 텍스트 입력 | `<Input type="text" />` |
|
|
| `number` | 숫자 입력 | `<Input type="number" />` |
|
|
| `dropdown` | 드롭다운 선택 | `<Select />` |
|
|
| `checkbox` | 체크박스 | `<Checkbox />` |
|
|
| `date` | 날짜 선택 | `<DatePicker />` |
|
|
| `textarea` | 장문 텍스트 | `<Textarea />` |
|
|
|
|
---
|
|
|
|
## 6. 주의사항
|
|
|
|
### 6.1 삭제 시 동작
|
|
- **페이지 삭제**: 연결된 섹션/필드는 삭제되지 않고 관계만 해제
|
|
- **섹션 삭제**: 연결된 필드/BOM은 삭제되지 않고 관계만 해제
|
|
- **잠금된 연결이 있으면**: 삭제/해제 불가
|
|
|
|
### 6.2 복제(Clone) 시 동작
|
|
- 섹션 복제: 섹션 + 필드 + BOM 모두 복제
|
|
- 필드 복제: 필드만 복제
|
|
- 복제된 항목은 독립 엔티티로 생성됨
|
|
|
|
### 6.3 순서 변경
|
|
- Drag & Drop 후 reorder API 호출 필요
|
|
- `items` 배열에 `{id, order_no}` 형태로 전달
|
|
|
|
---
|
|
|
|
## 7. 변경 이력
|
|
|
|
| 날짜 | 변경 내용 |
|
|
|------|----------|
|
|
| 2025-12-09 | 시스템 기반 문서 전면 재작성 |
|
|
| 2025-11-27 | 잠금(Lock) 기능 추가 |
|
|
| 2025-11-26 | 독립 엔티티 아키텍처 적용 |
|
|
| 2025-11-20 | entity_relationships 링크 테이블 도입 |
|