- history/2025-11/front-requests/ 프론트 요청 문서 이동 - history/2025-11/item-master-archived/ Item Master 구버전 문서 이동
21 KiB
품목기준관리 API 요청서
작성일: 2025-11-25 요청자: 프론트엔드 개발팀 대상: 백엔드 개발팀 프로젝트: SAM MES System - 품목기준관리 (Item Master Data Management)
1. 개요
1.1 목적
품목기준관리 화면에서 품목의 메타데이터(페이지, 섹션, 필드)를 동적으로 정의하기 위한 백엔드 API 개발 요청
1.2 프론트엔드 구현 현황
- 프론트엔드 UI 구현 완료
- API 클라이언트 코드 작성 완료 (
src/lib/api/item-master.ts) - 타입 정의 완료 (
src/types/item-master-api.ts) - Next.js API 프록시 구조 적용 (HttpOnly 쿠키 인증)
1.3 API 기본 정보
| 항목 | 값 |
|---|---|
| Base URL | /api/v1/item-master |
| 인증 방식 | auth.apikey + auth:sanctum (HttpOnly Cookie) |
| Content-Type | application/json |
| 응답 형식 | 표준 API 응답 래퍼 사용 |
1.4 표준 응답 형식
{
"success": true,
"message": "message.fetched",
"data": { ... }
}
2. 필수 API 엔드포인트
2.1 초기화 API (최우선)
GET /api/v1/item-master/init
목적: 화면 진입 시 전체 데이터를 한 번에 로드
Request: 없음 (JWT에서 tenant_id 자동 추출)
Response:
interface InitResponse {
pages: ItemPageResponse[]; // 페이지 목록 (섹션, 필드 포함)
sectionTemplates: SectionTemplateResponse[]; // 섹션 템플릿 목록
masterFields: MasterFieldResponse[]; // 마스터 필드 목록
customTabs: CustomTabResponse[]; // 커스텀 탭 목록
tabColumns: Record<number, TabColumnResponse[]>; // 탭별 컬럼 설정
unitOptions: UnitOptionResponse[]; // 단위 옵션 목록
}
중요: pages 응답 시 sections와 fields를 Nested로 포함해야 함
예시 응답:
{
"success": true,
"message": "message.fetched",
"data": {
"pages": [
{
"id": 1,
"page_name": "기본정보",
"item_type": "FG",
"is_active": true,
"sections": [
{
"id": 1,
"title": "품목코드 정보",
"type": "fields",
"order_no": 1,
"fields": [
{
"id": 1,
"field_name": "품목코드",
"field_type": "textbox",
"is_required": true,
"master_field_id": null,
"order_no": 1
}
]
}
]
}
],
"sectionTemplates": [...],
"masterFields": [...],
"customTabs": [...],
"tabColumns": {...},
"unitOptions": [...]
}
}
2.2 페이지 관리 API
POST /api/v1/item-master/pages
목적: 새 페이지 생성
Request Body:
interface ItemPageRequest {
page_name: string; // 페이지명 (필수)
item_type: 'FG' | 'PT' | 'SM' | 'RM' | 'CS'; // 품목유형 (필수)
absolute_path?: string; // 절대경로 (선택)
is_active?: boolean; // 활성화 여부 (기본: true)
}
Response: ItemPageResponse
PUT /api/v1/item-master/pages/{id}
목적: 페이지 수정
Path Parameter: id - 페이지 ID
Request Body: Partial<ItemPageRequest>
Response: ItemPageResponse
DELETE /api/v1/item-master/pages/{id}
목적: 페이지 삭제 (Soft Delete)
Path Parameter: id - 페이지 ID
Response: { success: true, message: "message.deleted" }
2.3 섹션 관리 API
POST /api/v1/item-master/pages/{pageId}/sections
목적: 페이지에 새 섹션 추가
Path Parameter: pageId - 페이지 ID
Request Body:
interface ItemSectionRequest {
title: string; // 섹션명 (필수)
type: 'fields' | 'bom'; // 섹션 타입 (필수)
template_id?: number; // 템플릿 ID (선택) - 템플릿에서 생성 시
}
중요 - 템플릿 적용 로직:
template_id가 전달되면 해당 템플릿의 필드들을 복사하여 새 섹션에 추가- 템플릿의 필드들은
master_field_id연결 관계도 복사
Response: ItemSectionResponse (생성된 섹션 + 필드 포함)
PUT /api/v1/item-master/sections/{id}
목적: 섹션 수정 (제목 변경 등)
Path Parameter: id - 섹션 ID
Request Body: Partial<ItemSectionRequest>
Response: ItemSectionResponse
DELETE /api/v1/item-master/sections/{id}
목적: 섹션 삭제
Path Parameter: id - 섹션 ID
Response: { success: true, message: "message.deleted" }
PUT /api/v1/item-master/pages/{pageId}/sections/reorder
목적: 섹션 순서 변경 (드래그앤드롭)
Path Parameter: pageId - 페이지 ID
Request Body:
interface SectionReorderRequest {
section_orders: Array<{
id: number; // 섹션 ID
order_no: number; // 새 순서
}>;
}
Response: ItemSectionResponse[]
2.4 필드 관리 API
POST /api/v1/item-master/sections/{sectionId}/fields
목적: 섹션에 새 필드 추가
Path Parameter: sectionId - 섹션 ID
Request Body:
interface ItemFieldRequest {
field_name: string; // 필드명 (필수)
field_type: 'textbox' | 'number' | 'dropdown' | 'checkbox' | 'date' | 'textarea'; // 필드 타입 (필수)
// 마스터 필드 연결 (핵심 기능)
master_field_id?: number; // 마스터 필드 ID (마스터에서 선택한 경우)
// 선택 속성
is_required?: boolean;
placeholder?: string;
default_value?: string;
options?: Array<{ label: string; value: string }>; // dropdown 옵션
validation_rules?: Record<string, any>;
properties?: Record<string, any>;
// 조건부 표시 설정 (신규 기능)
display_condition?: {
field_key: string; // 조건 필드 키
expected_value: string; // 예상 값
target_field_ids?: string[]; // 표시할 필드 ID 목록
target_section_ids?: string[]; // 표시할 섹션 ID 목록
}[];
}
중요 - master_field_id 처리:
- 프론트엔드에서 "마스터 항목 선택" 모드로 필드 추가 시
master_field_id전달 - 백엔드에서 해당 마스터 필드의 속성을 참조하여 기본값 설정
- 마스터 필드가 수정되면 연결된 필드도 동기화 필요 (옵션)
Response: ItemFieldResponse
PUT /api/v1/item-master/fields/{id}
목적: 필드 수정
Path Parameter: id - 필드 ID
Request Body: Partial<ItemFieldRequest>
Response: ItemFieldResponse
DELETE /api/v1/item-master/fields/{id}
목적: 필드 삭제
Path Parameter: id - 필드 ID
Response: { success: true, message: "message.deleted" }
PUT /api/v1/item-master/sections/{sectionId}/fields/reorder
목적: 필드 순서 변경 (드래그앤드롭)
Path Parameter: sectionId - 섹션 ID
Request Body:
interface FieldReorderRequest {
field_orders: Array<{
id: number; // 필드 ID
order_no: number; // 새 순서
}>;
}
Response: ItemFieldResponse[]
2.5 섹션 템플릿 API
GET /api/v1/item-master/section-templates
목적: 섹션 템플릿 목록 조회
Response: SectionTemplateResponse[]
POST /api/v1/item-master/section-templates
목적: 새 섹션 템플릿 생성
Request Body:
interface SectionTemplateRequest {
title: string; // 템플릿명 (필수)
type: 'fields' | 'bom'; // 타입 (필수)
description?: string; // 설명 (선택)
is_default?: boolean; // 기본 템플릿 여부 (선택)
// 템플릿에 포함될 필드들
fields?: Array<{
field_name: string;
field_type: string;
master_field_id?: number;
is_required?: boolean;
options?: Array<{ label: string; value: string }>;
properties?: Record<string, any>;
}>;
}
Response: SectionTemplateResponse
PUT /api/v1/item-master/section-templates/{id}
목적: 섹션 템플릿 수정
Response: SectionTemplateResponse
DELETE /api/v1/item-master/section-templates/{id}
목적: 섹션 템플릿 삭제
Response: { success: true, message: "message.deleted" }
2.6 마스터 필드 API
GET /api/v1/item-master/master-fields
목적: 마스터 필드 목록 조회
Response: MasterFieldResponse[]
POST /api/v1/item-master/master-fields
목적: 새 마스터 필드 생성
Request Body:
interface MasterFieldRequest {
field_name: string; // 필드명 (필수)
field_type: 'textbox' | 'number' | 'dropdown' | 'checkbox' | 'date' | 'textarea'; // 필드 타입 (필수)
category?: string; // 카테고리 (선택) - 예: "기본정보", "스펙정보"
description?: string; // 설명 (선택)
is_common?: boolean; // 공통 항목 여부 (선택)
default_value?: string;
options?: Array<{ label: string; value: string }>;
validation_rules?: Record<string, any>;
properties?: Record<string, any>;
}
Response: MasterFieldResponse
PUT /api/v1/item-master/master-fields/{id}
목적: 마스터 필드 수정
Response: MasterFieldResponse
DELETE /api/v1/item-master/master-fields/{id}
목적: 마스터 필드 삭제
주의: 해당 마스터 필드를 참조하는 필드(master_field_id)가 있을 경우 처리 방안 필요
- 옵션 1: 삭제 불가 (참조 무결성)
- 옵션 2: 참조 해제 후 삭제
Response: { success: true, message: "message.deleted" }
2.7 BOM 관리 API
POST /api/v1/item-master/sections/{sectionId}/bom-items
목적: BOM 항목 추가
Request Body:
interface BomItemRequest {
item_code?: string;
item_name: string; // 필수
quantity: number; // 필수
unit?: string;
unit_price?: number;
total_price?: number;
spec?: string;
note?: string;
}
Response: BomItemResponse
PUT /api/v1/item-master/bom-items/{id}
목적: BOM 항목 수정
Response: BomItemResponse
DELETE /api/v1/item-master/bom-items/{id}
목적: BOM 항목 삭제
Response: { success: true, message: "message.deleted" }
2.8 커스텀 탭 API
GET /api/v1/item-master/custom-tabs
목적: 커스텀 탭 목록 조회
Response: CustomTabResponse[]
POST /api/v1/item-master/custom-tabs
목적: 새 커스텀 탭 생성
Request Body:
interface CustomTabRequest {
label: string; // 탭 레이블 (필수)
icon?: string; // 아이콘 (선택)
is_default?: boolean; // 기본 탭 여부 (선택)
}
Response: CustomTabResponse
PUT /api/v1/item-master/custom-tabs/{id}
목적: 커스텀 탭 수정
Response: CustomTabResponse
DELETE /api/v1/item-master/custom-tabs/{id}
목적: 커스텀 탭 삭제
Response: { success: true, message: "message.deleted" }
PUT /api/v1/item-master/custom-tabs/reorder
목적: 탭 순서 변경
Request Body:
interface TabReorderRequest {
tab_orders: Array<{
id: number;
order_no: number;
}>;
}
Response: { success: true }
PUT /api/v1/item-master/custom-tabs/{id}/columns
목적: 탭별 컬럼 설정 업데이트
Request Body:
interface TabColumnUpdateRequest {
columns: Array<{
key: string;
label: string;
visible: boolean;
order: number;
}>;
}
Response: TabColumnResponse[]
2.9 단위 옵션 API
GET /api/v1/item-master/unit-options
목적: 단위 옵션 목록 조회
Response: UnitOptionResponse[]
POST /api/v1/item-master/unit-options
목적: 새 단위 옵션 추가
Request Body:
interface UnitOptionRequest {
label: string; // 표시명 (예: "개")
value: string; // 값 (예: "EA")
}
Response: UnitOptionResponse
DELETE /api/v1/item-master/unit-options/{id}
목적: 단위 옵션 삭제
Response: { success: true, message: "message.deleted" }
3. 데이터베이스 스키마 제안
3.1 item_master_pages
CREATE TABLE item_master_pages (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
tenant_id BIGINT UNSIGNED NOT NULL,
page_name VARCHAR(100) NOT NULL,
item_type ENUM('FG', 'PT', 'SM', 'RM', 'CS') NOT NULL,
absolute_path VARCHAR(500) NULL,
order_no INT NOT NULL DEFAULT 0,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_by BIGINT UNSIGNED NULL,
updated_by BIGINT UNSIGNED NULL,
deleted_by BIGINT UNSIGNED NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
deleted_at TIMESTAMP NULL,
INDEX idx_tenant (tenant_id),
FOREIGN KEY (tenant_id) REFERENCES tenants(id)
);
3.2 item_master_sections
CREATE TABLE item_master_sections (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
tenant_id BIGINT UNSIGNED NOT NULL,
page_id BIGINT UNSIGNED NOT NULL,
title VARCHAR(100) NOT NULL,
type ENUM('fields', 'bom') NOT NULL DEFAULT 'fields',
order_no INT NOT NULL DEFAULT 0,
created_by BIGINT UNSIGNED NULL,
updated_by BIGINT UNSIGNED NULL,
deleted_by BIGINT UNSIGNED NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
deleted_at TIMESTAMP NULL,
INDEX idx_tenant_page (tenant_id, page_id),
FOREIGN KEY (tenant_id) REFERENCES tenants(id),
FOREIGN KEY (page_id) REFERENCES item_master_pages(id) ON DELETE CASCADE
);
3.3 item_master_fields
CREATE TABLE item_master_fields (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
tenant_id BIGINT UNSIGNED NOT NULL,
section_id BIGINT UNSIGNED NOT NULL,
master_field_id BIGINT UNSIGNED NULL, -- 마스터 필드 참조
field_name VARCHAR(100) NOT NULL,
field_type ENUM('textbox', 'number', 'dropdown', 'checkbox', 'date', 'textarea') NOT NULL,
order_no INT NOT NULL DEFAULT 0,
is_required BOOLEAN NOT NULL DEFAULT FALSE,
placeholder VARCHAR(200) NULL,
default_value VARCHAR(500) NULL,
display_condition JSON NULL, -- 조건부 표시 설정
validation_rules JSON NULL,
options JSON NULL, -- dropdown 옵션
properties JSON NULL, -- 추가 속성 (컬럼 설정 등)
created_by BIGINT UNSIGNED NULL,
updated_by BIGINT UNSIGNED NULL,
deleted_by BIGINT UNSIGNED NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
deleted_at TIMESTAMP NULL,
INDEX idx_tenant_section (tenant_id, section_id),
INDEX idx_master_field (master_field_id),
FOREIGN KEY (tenant_id) REFERENCES tenants(id),
FOREIGN KEY (section_id) REFERENCES item_master_sections(id) ON DELETE CASCADE,
FOREIGN KEY (master_field_id) REFERENCES item_master_master_fields(id) ON DELETE SET NULL
);
3.4 item_master_master_fields (마스터 필드)
CREATE TABLE item_master_master_fields (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
tenant_id BIGINT UNSIGNED NOT NULL,
field_name VARCHAR(100) NOT NULL,
field_type ENUM('textbox', 'number', 'dropdown', 'checkbox', 'date', 'textarea') NOT NULL,
category VARCHAR(50) NULL,
description TEXT NULL,
is_common BOOLEAN NOT NULL DEFAULT FALSE,
default_value VARCHAR(500) NULL,
options JSON NULL,
validation_rules JSON NULL,
properties JSON NULL,
created_by BIGINT UNSIGNED NULL,
updated_by BIGINT UNSIGNED NULL,
deleted_by BIGINT UNSIGNED NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
deleted_at TIMESTAMP NULL,
INDEX idx_tenant (tenant_id),
INDEX idx_category (tenant_id, category),
FOREIGN KEY (tenant_id) REFERENCES tenants(id)
);
3.5 item_master_section_templates (섹션 템플릿)
CREATE TABLE item_master_section_templates (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
tenant_id BIGINT UNSIGNED NOT NULL,
title VARCHAR(100) NOT NULL,
type ENUM('fields', 'bom') NOT NULL DEFAULT 'fields',
description TEXT NULL,
is_default BOOLEAN NOT NULL DEFAULT FALSE,
created_by BIGINT UNSIGNED NULL,
updated_by BIGINT UNSIGNED NULL,
deleted_by BIGINT UNSIGNED NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
deleted_at TIMESTAMP NULL,
INDEX idx_tenant (tenant_id),
FOREIGN KEY (tenant_id) REFERENCES tenants(id)
);
3.6 item_master_template_fields (템플릿 필드)
CREATE TABLE item_master_template_fields (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
tenant_id BIGINT UNSIGNED NOT NULL,
template_id BIGINT UNSIGNED NOT NULL,
master_field_id BIGINT UNSIGNED NULL,
field_name VARCHAR(100) NOT NULL,
field_type ENUM('textbox', 'number', 'dropdown', 'checkbox', 'date', 'textarea') NOT NULL,
order_no INT NOT NULL DEFAULT 0,
is_required BOOLEAN NOT NULL DEFAULT FALSE,
placeholder VARCHAR(200) NULL,
default_value VARCHAR(500) NULL,
options JSON NULL,
properties JSON NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
INDEX idx_template (template_id),
FOREIGN KEY (tenant_id) REFERENCES tenants(id),
FOREIGN KEY (template_id) REFERENCES item_master_section_templates(id) ON DELETE CASCADE,
FOREIGN KEY (master_field_id) REFERENCES item_master_master_fields(id) ON DELETE SET NULL
);
4. 핵심 비즈니스 로직
4.1 마스터 필드 연결 (master_field_id)
시나리오: 사용자가 필드 추가 시 "마스터 항목 선택" 모드로 추가
프론트엔드 동작:
- 마스터 필드 목록에서 선택
- 선택된 마스터 필드의 속성을 폼에 자동 채움
- 저장 시
master_field_id포함하여 전송
백엔드 처리:
// ItemFieldService.php
public function create(int $sectionId, array $data): ItemField
{
// master_field_id가 있으면 마스터 필드에서 기본값 가져오기
if (!empty($data['master_field_id'])) {
$masterField = MasterField::findOrFail($data['master_field_id']);
// 마스터 필드의 속성을 기본값으로 사용 (명시적 값이 없는 경우)
$data = array_merge([
'field_type' => $masterField->field_type,
'options' => $masterField->options,
'validation_rules' => $masterField->validation_rules,
'properties' => $masterField->properties,
], $data);
}
return ItemField::create($data);
}
4.2 섹션 템플릿 적용
시나리오: 사용자가 섹션 추가 시 "템플릿에서 선택" 모드로 추가
프론트엔드 동작:
- 템플릿 목록에서 선택
- 선택된 템플릿 정보로 섹션 생성 요청
template_id포함하여 전송
백엔드 처리:
// ItemSectionService.php
public function create(int $pageId, array $data): ItemSection
{
$section = ItemSection::create([
'page_id' => $pageId,
'title' => $data['title'],
'type' => $data['type'],
]);
// template_id가 있으면 템플릿의 필드들을 복사
if (!empty($data['template_id'])) {
$templateFields = TemplateField::where('template_id', $data['template_id'])
->orderBy('order_no')
->get();
foreach ($templateFields as $index => $tf) {
ItemField::create([
'section_id' => $section->id,
'master_field_id' => $tf->master_field_id, // 마스터 연결 유지
'field_name' => $tf->field_name,
'field_type' => $tf->field_type,
'order_no' => $index,
'is_required' => $tf->is_required,
'options' => $tf->options,
'properties' => $tf->properties,
]);
}
}
return $section->load('fields');
}
4.3 조건부 표시 설정
JSON 구조:
{
"display_condition": [
{
"field_key": "item_type",
"expected_value": "FG",
"target_field_ids": ["5", "6", "7"]
},
{
"field_key": "item_type",
"expected_value": "PT",
"target_section_ids": ["3"]
}
]
}
활용: 프론트엔드에서 품목 데이터 입력 시 해당 조건에 따라 필드/섹션을 동적으로 표시/숨김
5. 우선순위
Phase 1 (필수 - 즉시)
GET /api/v1/item-master/init- 초기화 API- 페이지 CRUD API
- 섹션 CRUD API (순서변경 포함)
- 필드 CRUD API (순서변경 포함,
master_field_id지원)
Phase 2 (중요 - 1주 내)
- 마스터 필드 CRUD API
- 섹션 템플릿 CRUD API
- 템플릿 필드 관리
Phase 3 (선택 - 2주 내)
- BOM 항목 관리 API
- 커스텀 탭 API
- 단위 옵션 API
6. 참고 사항
6.1 프론트엔드 코드 위치
- API 클라이언트:
src/lib/api/item-master.ts - 타입 정의:
src/types/item-master-api.ts - 메인 컴포넌트:
src/components/items/ItemMasterDataManagement.tsx
6.2 기존 API 문서
claudedocs/[API-2025-11-24] item-management-dynamic-api-spec.md- 품목관리 동적 화면 API
6.3 Multi-Tenancy
- 모든 테이블에
tenant_id컬럼 필수 - JWT에서 tenant_id 자동 추출
BelongsToTenantTrait 적용 필요
6.4 에러 응답 형식
{
"success": false,
"message": "error.validation_failed",
"errors": {
"field_name": ["필드명은 필수입니다."],
"field_type": ["유효하지 않은 필드 타입입니다."]
}
}
7. 연락처
질문이나 협의 사항이 있으면 언제든 연락 바랍니다.
프론트엔드 담당: [담당자명] 작성일: 2025-11-25