diff --git a/INDEX.md b/INDEX.md index 1f0c971..4eaa014 100644 --- a/INDEX.md +++ b/INDEX.md @@ -77,7 +77,10 @@ docs/ |------|------|--------------| | [database-schema.md](specs/database-schema.md) | DB 구조 및 관계도 | DB 변경 전 | | [board-system-spec.md](specs/board-system-spec.md) | 게시판 시스템 설계 | 게시판 작업 전 | -| [item-master-integration.md](specs/item-master-integration.md) | 품목관리 통합 스펙 | 품목 관련 작업 전 | +| [**ITEM-MASTER-INDEX.md**](specs/ITEM-MASTER-INDEX.md) | **품목관리 문서 인덱스 (개발 현황)** | **품목 작업 전 필수** | +| [item-master-integration.md](specs/item-master-integration.md) | 품목관리 연동 설계 | 품목 연동 구현 시 | +| [item-master-field-key-validation.md](specs/item-master-field-key-validation.md) | ItemMaster 필드 키 검증 | 품목 필드 작업 전 | +| [item-master-field-integration.md](specs/item-master-field-integration.md) | ItemMaster 필드 통합 계획 | 품목 필드 통합 시 | | [docker-setup.md](specs/docker-setup.md) | Docker 환경 구성 | 환경 설정 시 | | [remote-work-setup.md](specs/remote-work-setup.md) | 원격 개발 설정 | 원격 작업 시 | @@ -106,12 +109,22 @@ docs/ |------|------| | [item-master-guide.md](front/item-master-guide.md) | 품목기준관리 페이지-섹션-필드 구조 | +> 날짜별 API 요청 문서는 `history/2025-11/front-requests/`로 이동됨 + +### data/ - 데이터 분석 +> 시스템 분석, 데이터 모델링 + +| 문서 | 설명 | +|------|------| +| [analysis/item-db-analysis.md](data/analysis/item-db-analysis.md) | Item DB/API 분석 최종본 | + ### features/ - 기능별 문서 | 문서 | 설명 | |------|------| | [boards/README.md](features/boards/README.md) | 게시판 시스템 구현 | | [boards/mng-implementation.md](features/boards/mng-implementation.md) | MNG 게시판 구현 상세 | +| [hr/hr-api-analysis.md](features/hr/hr-api-analysis.md) | HR API 분석 (근태/직원/부서) | ### projects/ - 프로젝트별 문서 @@ -125,7 +138,7 @@ docs/ | 기간 | 문서 | |------|------| -| **2025-11** | [item-master-gap-analysis.md](history/2025-11/item-master-gap-analysis.md), [item-master-spec.md](history/2025-11/item-master-spec.md) | +| **2025-11** | [item-master-gap-analysis.md](history/2025-11/item-master-gap-analysis.md), [item-master-spec.md](history/2025-11/item-master-spec.md), [front-requests/](history/2025-11/front-requests/), [item-master-archived/](history/2025-11/item-master-archived/) | | **2025-09** | [checkpoint.md](history/2025-09/checkpoint.md), [database-schema.md](history/2025-09/database-schema.md) | | **Roadmaps** | [december-2025.md](history/roadmaps/december-2025.md) | @@ -176,6 +189,25 @@ API Flow Tester에서 생성되는 JSON 파일 저장 경로 ## 🔄 문서 구조 변경 이력 +- **2025-12-09**: Item Master 문서 정리 및 인덱스 생성 + - `specs/ITEM-MASTER-INDEX.md` 생성 (개발 현황/필요 항목 정리) + - `history/2025-11/item-master-archived/` 생성 (구버전 문서 아카이브) + - 중복 문서 정리 (front-requests → history 이동) + +- **2025-12-09**: 문서 정리 및 통합 + - 중복 분석 문서 삭제 (v2, DB_Modeling) + - `SAM_Item_DB_API_Analysis_v3_FINAL.md` → `item-db-analysis.md` 리네임 + - `ITEM_MASTER_FIELD_INTEGRATION_PLAN.md` → `item-master-field-integration.md` 리네임 + - `HR_API_ANALYSIS.md` → `features/hr/hr-api-analysis.md` 이동 + - 날짜 접두사 front 문서 → `history/2025-11/front-requests/` 이동 + - api/docs에서 프로젝트 문서 분리 (swagger, api-flows만 유지) + +- **2025-12-09**: api/docs 문서 통합 + - `api/docs/analysis/` → `docs/data/analysis/` 이동 + - `api/docs/front/` → `docs/front/` 병합 + - `api/docs/specs/` → `docs/specs/` 병합 + - api/docs에는 API 구성/설정 문서만 유지 (swagger, api-flows) + - **2025-12-09**: `plans/` 폴더 추가 - 개발 계획 문서용 임시 폴더 - 작업 완료 후 정리 → 삭제 워크플로우 diff --git a/front/item-master-guide.md b/front/item-master-guide.md index a09effa..42c5def 100644 --- a/front/item-master-guide.md +++ b/front/item-master-guide.md @@ -1,70 +1,246 @@ -# 품목기준관리(ItemMaster) 프론트엔드 가이드 +# 품목기준관리(ItemMaster) API 가이드 -> 📌 **품목설정 시스템의 구조, API, 잠금 기능에 대한 프론트엔드 개발 가이드** +> 품목 입력 화면을 구성하는 **페이지-섹션-필드** 구조 관리 시스템 --- ## 1. 개요 -품목기준관리(ItemMaster)는 제품의 입력 화면을 구성하는 **페이지-섹션-필드** 구조를 관리하는 시스템입니다. - ### 1.1 핵심 개념 -| 엔티티 | 설명 | 예시 | -|--------|------|------| -| **Page** | 품목 유형별 화면 (FG, PT, SM, RM, CS) | "완제품 기본정보", "부품 상세" | -| **Section** | 페이지 내 논리적 영역 | "제품 상세", "BOM 정보" | -| **Field** | 섹션 내 입력 항목 | "제품명", "규격", "단가" | -| **BomItem** | BOM 섹션 내 부품 항목 | "부품A x 2개" | +| 엔티티 | 테이블 | 설명 | +|--------|--------|------| +| **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 아키텍처 특징 +### 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. 데이터 구조 +## 2. API 엔드포인트 -### 2.1 엔티티 관계도 +### 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) │ -└─────────────────────────────┘ └─────────────────────────────┘ +| Method | Endpoint | 설명 | +|--------|----------|------| +| GET | `/api/v1/item-master/init` | 전체 데이터 로드 | + +**응답 구조:** +```json +{ + "pages": [], // 페이지 + 연결된 섹션/필드 + "sections": [], // 모든 독립 섹션 + "fields": [], // 모든 독립 필드 + "customTabs": [], // 커스텀 탭 + "unitOptions": [] // 단위 옵션 +} ``` -### 2.2 entity_relationships 테이블 +### 2.2 페이지 -모든 엔티티 간 관계는 `entity_relationships` 테이블로 관리됩니다. +| 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; // 1: ItemMaster + group_id: number; parent_type: 'page' | 'section'; parent_id: number; child_type: 'section' | 'field' | 'bom'; child_id: number; order_no: number; - is_locked: boolean; // ⭐ 잠금 여부 + is_locked: boolean; locked_by?: number; locked_at?: string; metadata?: object; @@ -73,9 +249,9 @@ interface EntityRelationship { --- -## 3. 잠금(Lock) 기능 +## 4. 잠금(Lock) 기능 -### 3.1 잠금의 의미 +### 4.1 잠금의 의미 **연결이 잠기면:** - 해당 연결(관계)를 해제할 수 없음 @@ -90,175 +266,40 @@ interface EntityRelationship { └─ ✅ 섹션에 새 필드 추가 가능 ``` -### 3.2 잠금 상태 확인 +### 4.2 잠금 상태 확인 init API 응답에 `is_locked` 필드가 포함됩니다. -```typescript -// GET /api/v1/item-master/init 응답 +```json { - "pages": [ - { - "id": 1, - "page_name": "완제품 기본정보", - "sections": [ - { - "id": 10, - "title": "제품 상세", - "is_locked": true, // ⭐ 이 연결이 잠김 - "fields": [ - { - "id": 100, - "field_name": "제품명", - "is_locked": false // ⭐ 이 연결은 잠기지 않음 - } - ] - } - ] - } - ] + "pages": [{ + "id": 1, + "sections": [{ + "id": 10, + "is_locked": true, + "fields": [{ + "id": 100, + "is_locked": false + }] + }] + }] } ``` -### 3.3 프론트엔드 처리 가이드 +### 4.3 잠금 관련 에러 -```typescript -// 잠금 상태에 따른 UI 처리 예시 -interface SectionProps { - section: ItemSection; - isLocked: boolean; // 부모로부터 전달받은 잠금 상태 -} - -function SectionItem({ section, isLocked }: SectionProps) { - return ( -
-

- {section.title} - {isLocked && } {/* 잠금 아이콘 표시 */} -

- - {/* 잠금 시 삭제/분리 버튼 비활성화 */} - - - - - {/* 수정은 항상 가능 */} - -
- ); -} -``` - -### 3.4 잠금 관련 에러 처리 - -잠금된 항목에 대해 삭제/해제 시도 시 에러가 반환됩니다. - -```typescript -// 에러 응답 예시 +```json { "success": false, "message": "잠금된 연결은 해제할 수 없습니다.", - "error": "relationship_locked" -} - -// 프론트엔드 에러 처리 -try { - await deleteSection(sectionId); -} catch (error) { - if (error.response?.data?.error === 'entity_protected_by_locked_relationship') { - toast.error('잠금된 연결로 보호된 항목은 삭제할 수 없습니다.'); - } + "error": "entity_protected_by_locked_relationship" } ``` --- -## 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` | 텍스트 입력 | `` | @@ -268,111 +309,31 @@ interface InitResponse { | `date` | 날짜 선택 | `` | | `textarea` | 장문 텍스트 | `