fix: 품목기준관리 실시간 동기화 수정

- BOM 항목 추가/수정/삭제 시 섹션탭 즉시 반영
- 섹션 복제 시 UI 즉시 업데이트 (null vs undefined 이슈 해결)
- 항목 수정 기능 추가 (useTemplateManagement)
- 실시간 동기화 문서 추가

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
byeongcheolryu
2025-11-27 22:19:50 +09:00
parent b73603822b
commit 65a8510c0b
130 changed files with 11031 additions and 2287 deletions

View File

@@ -31,10 +31,17 @@ export interface PaginationMeta {
/**
* 초기화 API 응답 - 화면 진입 시 전체 데이터 로드
* GET /v1/item-master/init
*
* 2025-11-27 변경사항:
* - masterFields → 독립 필드(item_fields WHERE section_id IS NULL)로 대체 예정
* - fields 필드 추가: 모든 필드 목록 (독립 필드 + 섹션 내 필드)
*/
export interface InitResponse {
pages: ItemPageResponse[];
sections?: ItemSectionResponse[]; // 2025-11-26 추가: 모든 섹션 (독립 섹션 포함)
fields?: ItemFieldResponse[]; // 2025-11-27 추가: 모든 필드 (독립 필드 = section_id IS NULL)
sectionTemplates: SectionTemplateResponse[];
/** @deprecated 2025-11-27: item_fields로 통합됨. fields 필드 사용 권장 */
masterFields: MasterFieldResponse[];
customTabs: CustomTabResponse[];
tabColumns: Record<number, TabColumnResponse[]>; // tab_id를 key로 사용
@@ -65,8 +72,10 @@ export interface ItemPageResponse {
tenant_id: number;
page_name: string;
item_type: string;
description: string | null; // 2025-11-26 추가: 페이지 설명
absolute_path: string | null;
is_active: boolean;
order_no: number; // 2025-11-26 추가: 순서 번호
created_by: number | null;
updated_by: number | null;
created_at: string;
@@ -101,33 +110,84 @@ export interface ItemSectionRequest {
/**
* 섹션 응답
* 2025-11-26: section_templates 테이블 통합으로 is_template, is_default, description, group_id 추가
*/
export interface ItemSectionResponse {
id: number;
tenant_id: number;
page_id: number;
group_id: number | null; // 그룹 ID (독립 섹션 그룹화용)
page_id: number | null; // 페이지 ID (null이면 독립 섹션)
title: string;
type: 'fields' | 'bom';
order_no: number;
is_template: boolean; // 템플릿 여부 (section_templates 통합)
is_default: boolean; // 기본 템플릿 여부
description: string | null; // 섹션 설명
created_by: number | null;
updated_by: number | null;
created_at: string;
updated_at: string;
fields?: ItemFieldResponse[]; // Nested 조회 시 포함
bomItems?: BomItemResponse[]; // Nested 조회 시 포함
bomItems?: BomItemResponse[]; // Nested 조회 시 포함 (camelCase)
bom_items?: BomItemResponse[]; // 2025-11-27: 백엔드가 snake_case로 반환
}
/**
* 섹션 순서 변경 요청
* PUT /v1/item-master/pages/{pageId}/sections/reorder
* 백엔드 API는 'items' 필드를 기대함
*/
export interface SectionReorderRequest {
section_orders: Array<{
items: Array<{
id: number;
order_no: number;
}>;
}
/**
* 독립 섹션 생성 요청
* POST /v1/item-master/sections
* 2025-11-26 신규 API
*/
export interface IndependentSectionRequest {
group_id?: number;
title: string;
type: 'fields' | 'bom';
is_template?: boolean;
is_default?: boolean;
description?: string;
}
/**
* 섹션 사용처 응답
* GET /v1/item-master/sections/{id}/usage
* 2025-11-26 신규 API
*/
export interface SectionUsageResponse {
section_id: number;
direct_page: {
id: number;
page_name: string;
item_type: string;
} | null;
linked_pages: Array<{
id: number;
page_name: string;
item_type: string;
}>;
total_usage_count: number;
}
/**
* 페이지에 섹션 연결 요청
* POST /v1/item-master/pages/{id}/link-section
* 2025-11-26 신규 API
*/
export interface LinkSectionRequest {
child_id: number; // 연결할 섹션 ID (백엔드: child_id)
order_no?: number;
}
// ============================================
// 필드 관리
// ============================================
@@ -151,11 +211,14 @@ export interface ItemFieldRequest {
/**
* 필드 응답
* 2025-11-26: section_id를 nullable로 변경 (독립 필드 지원)
* 2025-11-27: item_master_fields 테이블 통합으로 category, description, is_common 추가
*/
export interface ItemFieldResponse {
id: number;
tenant_id: number;
section_id: number;
group_id: number | null; // 그룹 ID (독립 필드 그룹화용)
section_id: number | null; // 섹션 ID (null이면 독립 필드/마스터 항목)
master_field_id?: number | null; // 마스터 항목 ID (마스터에서 가져온 경우)
field_name: string;
field_type: 'textbox' | 'number' | 'dropdown' | 'checkbox' | 'date' | 'textarea';
@@ -167,6 +230,10 @@ export interface ItemFieldResponse {
validation_rules: Record<string, any> | null;
options: Array<{ label: string; value: string }> | null;
properties: Record<string, any> | null;
// 2025-11-27 추가: item_master_fields 통합으로 추가된 필드
category: string | null; // 카테고리 (예: "공통", "완제품", "부품")
description: string | null; // 필드 설명
is_common: boolean; // 공통 필드 여부
created_by: number | null;
updated_by: number | null;
created_at: string;
@@ -184,6 +251,59 @@ export interface FieldReorderRequest {
}>;
}
/**
* 독립 필드 생성 요청
* POST /v1/item-master/fields
* 2025-11-26 신규 API
* 2025-11-27: item_master_fields 통합으로 category, description, is_common 추가
*/
export interface IndependentFieldRequest {
group_id?: number;
field_name: string;
field_type: 'textbox' | 'number' | 'dropdown' | 'checkbox' | 'date' | 'textarea';
is_required?: boolean;
default_value?: string;
placeholder?: string;
options?: Array<{ label: string; value: string }>;
properties?: Record<string, any>;
validation_rules?: Record<string, any>;
display_condition?: Record<string, any>;
// 2025-11-27 추가: item_master_fields 통합으로 추가된 필드
category?: string;
description?: string;
is_common?: boolean;
}
/**
* 필드 사용처 응답
* GET /v1/item-master/fields/{id}/usage
* 2025-11-26 신규 API
*/
export interface FieldUsageResponse {
field_id: number;
direct_section: {
id: number;
title: string;
type: 'fields' | 'bom';
} | null;
linked_sections: Array<{
id: number;
title: string;
type: 'fields' | 'bom';
}>;
total_usage_count: number;
}
/**
* 섹션에 필드 연결 요청
* POST /v1/item-master/sections/{id}/link-field
* 2025-11-26 신규 API
*/
export interface LinkFieldRequest {
child_id: number; // 연결할 필드 ID (백엔드: child_id)
order_no?: number;
}
// ============================================
// BOM 관리
// ============================================
@@ -206,11 +326,13 @@ export interface BomItemRequest {
/**
* BOM 항목 응답
* 2025-11-26: section_id를 nullable로 변경 (독립 BOM 지원)
*/
export interface BomItemResponse {
id: number;
tenant_id: number;
section_id: number;
group_id: number | null; // 그룹 ID (독립 BOM 그룹화용)
section_id: number | null; // 섹션 ID (null이면 독립 BOM)
item_code: string | null;
item_name: string;
quantity: number;
@@ -225,6 +347,115 @@ export interface BomItemResponse {
updated_at: string;
}
/**
* 독립 BOM 항목 생성 요청
* POST /v1/item-master/bom-items
* 2025-11-26 신규 API
*/
export interface IndependentBomItemRequest {
group_id?: number;
item_code?: string;
item_name: string;
quantity?: number;
unit?: string;
unit_price?: number;
spec?: string;
note?: string;
}
// ============================================
// 엔티티 관계 (Entity Relationships)
// 2025-11-27 신규: 독립 엔티티 + 링크 테이블 구조
// ============================================
/**
* 엔티티 타입 상수
*/
export type EntityType = 'page' | 'section' | 'field' | 'bom';
export type ParentEntityType = 'page' | 'section';
export type ChildEntityType = 'section' | 'field' | 'bom';
/**
* 엔티티 관계 응답
* entity_relationships 테이블의 레코드
*/
export interface EntityRelationshipResponse {
id: number;
tenant_id: number;
group_id: number; // 그룹 ID (1: 품목관리)
parent_type: ParentEntityType;
parent_id: number;
child_type: ChildEntityType;
child_id: number;
order_no: number;
metadata: Record<string, any> | null;
created_at: string;
updated_at: string;
}
/**
* 엔티티 연결 요청 (공통)
* POST /pages/{pageId}/link-section
* POST /pages/{pageId}/link-field
* POST /sections/{sectionId}/link-field
* POST /sections/{sectionId}/link-bom
*/
export interface LinkEntityRequest {
child_id: number;
order_no?: number;
}
/**
* 관계 순서 변경 요청
* POST /v1/item-master/relationships/reorder
*/
export interface ReorderRelationshipsRequest {
parent_type: ParentEntityType;
parent_id: number;
ordered_items: Array<{
child_type: ChildEntityType;
child_id: number;
}>;
}
/**
* 섹션에 BOM 연결 요청
* POST /v1/item-master/sections/{id}/link-bom
*/
export interface LinkBomRequest {
child_id: number;
order_no?: number;
}
// ============================================
// 페이지 구조 조회
// ============================================
/**
* 페이지 전체 구조 응답
* GET /v1/item-master/pages/{id}/structure
* 2025-11-27 업데이트: 링크 테이블 기반 구조
*/
export interface PageStructureResponse {
page: ItemPageResponse;
sections: Array<{
section: ItemSectionResponse;
order_no: number;
fields: Array<{
field: ItemFieldResponse;
order_no: number;
}>;
bom_items: Array<{
bom_item: BomItemResponse;
order_no: number;
}>;
}>;
direct_fields: Array<{
field: ItemFieldResponse;
order_no: number;
}>;
}
// ============================================
// 섹션 템플릿
// ============================================
@@ -258,13 +489,17 @@ export interface SectionTemplateResponse {
}
// ============================================
// 마스터 필드
// 마스터 필드 (DEPRECATED)
// 2025-11-27: item_master_fields 테이블이 item_fields로 통합됨
// 독립 필드 = item_fields WHERE section_id IS NULL
// IndependentFieldRequest 및 ItemFieldResponse 사용 권장
// ============================================
/**
* 마스터 필드 생성/수정 요청
* POST /v1/item-master/master-fields
* PUT /v1/item-master/master-fields/{id}
* @deprecated 2025-11-27: item_fields로 통합됨. IndependentFieldRequest 사용 권장
* POST /v1/item-master/master-fields → POST /v1/item-master/fields 사용
* PUT /v1/item-master/master-fields/{id} → PUT /v1/item-master/fields/{id} 사용
*/
export interface MasterFieldRequest {
field_name: string;
@@ -280,6 +515,8 @@ export interface MasterFieldRequest {
/**
* 마스터 필드 응답
* @deprecated 2025-11-27: item_fields로 통합됨. ItemFieldResponse 사용 권장
* 독립 필드 조회: GET /v1/item-master/fields?section_id=null
*/
export interface MasterFieldResponse {
id: number;