Files
sam-docs/front/item-master-guide.md
hskwon 08a8259313 docs: 5130 레거시 분석 문서 및 기존 문서 초기 커밋
- 5130 레거시 시스템 분석 (00_OVERVIEW ~ 08_SAM_COMPARISON)
- MES 프로젝트 문서
- API/프론트엔드 스펙 문서
- 가이드 및 레퍼런스 문서
2025-12-04 18:47:19 +09:00

379 lines
12 KiB
Markdown

# 품목기준관리(ItemMaster) 프론트엔드 가이드
> 📌 **품목설정 시스템의 구조, API, 잠금 기능에 대한 프론트엔드 개발 가이드**
---
## 1. 개요
품목기준관리(ItemMaster)는 제품의 입력 화면을 구성하는 **페이지-섹션-필드** 구조를 관리하는 시스템입니다.
### 1.1 핵심 개념
| 엔티티 | 설명 | 예시 |
|--------|------|------|
| **Page** | 품목 유형별 화면 (FG, PT, SM, RM, CS) | "완제품 기본정보", "부품 상세" |
| **Section** | 페이지 내 논리적 영역 | "제품 상세", "BOM 정보" |
| **Field** | 섹션 내 입력 항목 | "제품명", "규격", "단가" |
| **BomItem** | BOM 섹션 내 부품 항목 | "부품A x 2개" |
### 1.2 아키텍처 특징
- **독립 엔티티 구조**: 섹션, 필드, BOM은 독립적으로 존재하며 재사용 가능
- **링크 테이블**: `entity_relationships`로 관계 관리
- **연결 잠금**: 중요한 구조는 잠금으로 보호 가능
---
## 2. 데이터 구조
### 2.1 엔티티 관계도
```
┌─────────────────────────────────────────────────────────────────┐
│ ItemPage │
│ (id, page_name, item_type, is_active) │
└─────────────┬──────────────────────────────────────────────────┘
│ entity_relationships (is_locked)
┌─────────────────────────────────────────────────────────────────┐
│ ItemSection │
│ (id, title, type, is_template, is_default) │
└─────────────┬───────────────────────────────────┬──────────────┘
│ entity_relationships │ entity_relationships
│ (is_locked) │ (is_locked)
▼ ▼
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ ItemField │ │ ItemBomItem │
│ (id, field_name, │ │ (id, item_code, │
│ field_type, is_required) │ │ item_name, quantity) │
└─────────────────────────────┘ └─────────────────────────────┘
```
### 2.2 entity_relationships 테이블
모든 엔티티 간 관계는 `entity_relationships` 테이블로 관리됩니다.
```typescript
interface EntityRelationship {
id: number;
tenant_id: number;
group_id: number; // 1: ItemMaster
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;
}
```
---
## 3. 잠금(Lock) 기능
### 3.1 잠금의 의미
**연결이 잠기면:**
- 해당 연결(관계)를 해제할 수 없음
- 연결된 자식 엔티티를 삭제할 수 없음
- 이름 변경, 속성 추가 등 **비구조적 수정은 허용**
```
예시: page→section 연결이 잠김
├─ ❌ 섹션을 페이지에서 분리할 수 없음
├─ ❌ 해당 섹션을 삭제할 수 없음
├─ ✅ 섹션 제목 변경 가능
└─ ✅ 섹션에 새 필드 추가 가능
```
### 3.2 잠금 상태 확인
init API 응답에 `is_locked` 필드가 포함됩니다.
```typescript
// GET /api/v1/item-master/init 응답
{
"pages": [
{
"id": 1,
"page_name": "완제품 기본정보",
"sections": [
{
"id": 10,
"title": "제품 상세",
"is_locked": true, // ⭐ 이 연결이 잠김
"fields": [
{
"id": 100,
"field_name": "제품명",
"is_locked": false // ⭐ 이 연결은 잠기지 않음
}
]
}
]
}
]
}
```
### 3.3 프론트엔드 처리 가이드
```typescript
// 잠금 상태에 따른 UI 처리 예시
interface SectionProps {
section: ItemSection;
isLocked: boolean; // 부모로부터 전달받은 잠금 상태
}
function SectionItem({ section, isLocked }: SectionProps) {
return (
<div className={isLocked ? 'locked-section' : ''}>
<h3>
{section.title}
{isLocked && <LockIcon />} {/* 잠금 아이콘 표시 */}
</h3>
{/* 잠금 시 삭제/분리 버튼 비활성화 */}
<button
disabled={isLocked}
onClick={handleUnlink}
>
분리
</button>
<button
disabled={isLocked}
onClick={handleDelete}
>
삭제
</button>
{/* 수정은 항상 가능 */}
<button onClick={handleEdit}>
수정
</button>
</div>
);
}
```
### 3.4 잠금 관련 에러 처리
잠금된 항목에 대해 삭제/해제 시도 시 에러가 반환됩니다.
```typescript
// 에러 응답 예시
{
"success": false,
"message": "잠금된 연결은 해제할 수 없습니다.",
"error": "relationship_locked"
}
// 프론트엔드 에러 처리
try {
await deleteSection(sectionId);
} catch (error) {
if (error.response?.data?.error === 'entity_protected_by_locked_relationship') {
toast.error('잠금된 연결로 보호된 항목은 삭제할 수 없습니다.');
}
}
```
---
## 4. API 엔드포인트
### 4.1 초기화 API
| Method | Endpoint | 설명 |
|--------|----------|------|
| GET | `/api/v1/item-master/init` | 전체 데이터 로드 (페이지, 섹션, 커스텀탭, 단위옵션) |
**응답 구조:**
```typescript
interface InitResponse {
pages: ItemPage[]; // 페이지 + 연결된 섹션/필드
sections: ItemSection[]; // 모든 독립 섹션 (재사용 풀)
customTabs: CustomTab[];
unitOptions: UnitOption[];
}
```
### 4.2 페이지 API
| 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}` | 페이지 삭제 |
### 4.3 섹션 API
| 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` | 사용처 조회 |
### 4.4 필드 API
| 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` | 사용처 조회 |
### 4.5 BOM API
| 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 삭제 |
### 4.6 순서 변경 API
| Method | Endpoint | 설명 |
|--------|----------|------|
| PUT | `/api/v1/item-master/pages/{pageId}/sections/reorder` | 섹션 순서 변경 |
| PUT | `/api/v1/item-master/sections/{sectionId}/fields/reorder` | 필드 순서 변경 |
---
## 5. 필드 타입
### 5.1 지원 필드 타입
| field_type | 설명 | 렌더링 컴포넌트 |
|------------|------|----------------|
| `textbox` | 텍스트 입력 | `<Input type="text" />` |
| `number` | 숫자 입력 | `<Input type="number" />` |
| `dropdown` | 드롭다운 선택 | `<Select />` |
| `checkbox` | 체크박스 | `<Checkbox />` |
| `date` | 날짜 선택 | `<DatePicker />` |
| `textarea` | 장문 텍스트 | `<Textarea />` |
### 5.2 필드 속성
```typescript
interface ItemField {
id: number;
field_name: string;
field_type: FieldType;
order_no: number;
is_required: boolean;
is_locked?: boolean; // init 응답에 포함
default_value?: string;
placeholder?: string;
display_condition?: object; // 조건부 표시
validation_rules?: object; // 유효성 검사 규칙
options?: object; // dropdown 옵션 등
properties?: object; // 추가 설정
category?: string;
description?: string;
is_common?: boolean;
}
```
---
## 6. 상태 관리 권장 패턴
### 6.1 Zustand Store 예시
```typescript
interface ItemMasterStore {
// 데이터
pages: ItemPage[];
sections: ItemSection[];
customTabs: CustomTab[];
unitOptions: UnitOption[];
// 상태
isLoading: boolean;
selectedPageId: number | null;
selectedSectionId: number | null;
// 액션
fetchInit: () => Promise<void>;
addSection: (pageId: number, data: CreateSectionDTO) => Promise<void>;
updateSection: (id: number, data: UpdateSectionDTO) => Promise<void>;
deleteSection: (id: number) => Promise<void>;
reorderSections: (pageId: number, items: ReorderItem[]) => Promise<void>;
// 유틸리티
getSectionsByPage: (pageId: number) => ItemSection[];
isEntityLocked: (entityType: string, entityId: number) => boolean;
}
```
### 6.2 잠금 상태 캐싱
```typescript
// 잠금 상태를 Map으로 캐싱
const lockStatusMap = new Map<string, boolean>();
function buildLockStatusMap(pages: ItemPage[]) {
pages.forEach(page => {
page.sections?.forEach(section => {
lockStatusMap.set(`section:${section.id}`, section.is_locked);
section.fields?.forEach(field => {
lockStatusMap.set(`field:${field.id}`, field.is_locked);
});
section.bom_items?.forEach(bom => {
lockStatusMap.set(`bom:${bom.id}`, bom.is_locked);
});
});
});
}
function isLocked(entityType: string, entityId: number): boolean {
return lockStatusMap.get(`${entityType}:${entityId}`) || false;
}
```
---
## 7. 주의사항
### 7.1 삭제 시 동작
- **페이지 삭제**: 연결된 섹션/필드는 삭제되지 않고 관계만 해제
- **섹션 삭제**: 연결된 필드/BOM은 삭제되지 않고 관계만 해제
- **잠금된 연결이 있으면**: 삭제/해제 불가
### 7.2 복제(Clone) 시 동작
- 섹션 복제: 섹션 + 필드 + BOM 모두 복제
- 필드 복제: 필드만 복제
- 복제된 항목은 독립 엔티티로 생성됨
### 7.3 순서 변경
- Drag & Drop 후 reorder API 호출 필요
- `items` 배열에 `{id, order_no}` 형태로 전달
---
## 8. 변경 이력
| 날짜 | 버전 | 변경 내용 |
|------|------|----------|
| 2025-11-27 | 1.0.0 | 잠금(Lock) 기능 추가 |
| 2025-11-26 | 0.9.0 | 독립 엔티티 아키텍처 적용 |
| 2025-11-20 | 0.8.0 | entity_relationships 링크 테이블 도입 |