refactor(item-master): 독립 엔티티 아키텍처 적용 및 Swagger 보완

- FK 컬럼 제거: item_sections.page_id, item_fields.section_id, item_bom_items.section_id
- entity_relationships 테이블로 전환하여 독립 엔티티 구조 확립
- ItemMasterField 관련 파일 삭제 (Controller, Service, Model, Requests)
- destroy 메서드 독립 엔티티 아키텍처 적용 (관계 링크만 삭제)
- Swagger 스키마에서 FK 참조 제거
- FormRequest 및 Swagger에 group_id(계층번호) 필드 추가
This commit is contained in:
2025-11-27 10:28:51 +09:00
parent 1d2dadc7da
commit 9588945922
18 changed files with 361 additions and 550 deletions

View File

@@ -32,11 +32,11 @@
* @OA\Schema(
* schema="ItemSection",
* type="object",
* description="독립 엔티티 - 관계는 entity_relationships로 관리",
*
* @OA\Property(property="id", type="integer", example=1),
* @OA\Property(property="tenant_id", type="integer", example=1),
* @OA\Property(property="group_id", type="integer", nullable=true, example=1),
* @OA\Property(property="page_id", type="integer", nullable=true, example=1),
* @OA\Property(property="group_id", type="integer", nullable=true, example=1, description="계층번호"),
* @OA\Property(property="title", type="string", example="제품 상세"),
* @OA\Property(property="type", type="string", enum={"fields","bom"}, example="fields"),
* @OA\Property(property="order_no", type="integer", example=0),
@@ -63,10 +63,11 @@
* @OA\Schema(
* schema="ItemField",
* type="object",
* description="독립 엔티티 - 관계는 entity_relationships로 관리",
*
* @OA\Property(property="id", type="integer", example=1),
* @OA\Property(property="tenant_id", type="integer", example=1),
* @OA\Property(property="section_id", type="integer", example=1),
* @OA\Property(property="group_id", type="integer", nullable=true, example=1, description="계층번호"),
* @OA\Property(property="field_name", type="string", example="제품명"),
* @OA\Property(property="field_type", type="string", enum={"textbox","number","dropdown","checkbox","date","textarea"}, example="textbox"),
* @OA\Property(property="order_no", type="integer", example=0),
@@ -77,6 +78,9 @@
* @OA\Property(property="validation_rules", type="object", nullable=true, example=null),
* @OA\Property(property="options", type="object", nullable=true, example=null),
* @OA\Property(property="properties", type="object", nullable=true, example=null),
* @OA\Property(property="category", type="string", nullable=true, example="basic", description="필드 카테고리"),
* @OA\Property(property="description", type="string", nullable=true, example="필드 설명"),
* @OA\Property(property="is_common", type="boolean", example=false, description="공통 필드 여부"),
* @OA\Property(property="created_at", type="string", example="2025-11-20 10:00:00"),
* @OA\Property(property="updated_at", type="string", example="2025-11-20 10:00:00")
* )
@@ -84,10 +88,11 @@
* @OA\Schema(
* schema="ItemBomItem",
* type="object",
* description="독립 엔티티 - 관계는 entity_relationships로 관리",
*
* @OA\Property(property="id", type="integer", example=1),
* @OA\Property(property="tenant_id", type="integer", example=1),
* @OA\Property(property="section_id", type="integer", example=1),
* @OA\Property(property="group_id", type="integer", nullable=true, example=1, description="계층번호"),
* @OA\Property(property="item_code", type="string", nullable=true, example="ITEM001"),
* @OA\Property(property="item_name", type="string", example="부품 A"),
* @OA\Property(property="quantity", type="number", format="float", example=1.5),
@@ -115,25 +120,6 @@
* )
*
* @OA\Schema(
* schema="ItemMasterField",
* type="object",
*
* @OA\Property(property="id", type="integer", example=1),
* @OA\Property(property="tenant_id", type="integer", example=1),
* @OA\Property(property="field_name", type="string", example="제품명"),
* @OA\Property(property="field_type", type="string", enum={"textbox","number","dropdown","checkbox","date","textarea"}, example="textbox"),
* @OA\Property(property="category", type="string", nullable=true, example="basic"),
* @OA\Property(property="description", type="string", nullable=true, example="설명"),
* @OA\Property(property="is_common", type="boolean", example=true),
* @OA\Property(property="default_value", type="string", nullable=true, example=null),
* @OA\Property(property="options", type="object", nullable=true, example=null),
* @OA\Property(property="validation_rules", type="object", nullable=true, example=null),
* @OA\Property(property="properties", type="object", nullable=true, example=null),
* @OA\Property(property="created_at", type="string", example="2025-11-20 10:00:00"),
* @OA\Property(property="updated_at", type="string", example="2025-11-20 10:00:00")
* )
*
* @OA\Schema(
* schema="CustomTab",
* type="object",
*
@@ -187,6 +173,7 @@
* type="object",
* required={"title","type"},
*
* @OA\Property(property="group_id", type="integer", nullable=true, example=1, description="계층번호"),
* @OA\Property(property="title", type="string", maxLength=255, example="제품 상세"),
* @OA\Property(property="type", type="string", enum={"fields","bom"}, example="fields")
* )
@@ -196,7 +183,7 @@
* type="object",
* required={"title","type"},
*
* @OA\Property(property="group_id", type="integer", nullable=true, example=1),
* @OA\Property(property="group_id", type="integer", nullable=true, example=1, description="계층번호"),
* @OA\Property(property="title", type="string", maxLength=255, example="독립 섹션"),
* @OA\Property(property="type", type="string", enum={"fields","bom"}, example="fields"),
* @OA\Property(property="is_template", type="boolean", example=false),
@@ -209,7 +196,7 @@
* type="object",
* required={"field_name","field_type"},
*
* @OA\Property(property="group_id", type="integer", nullable=true, example=1),
* @OA\Property(property="group_id", type="integer", nullable=true, example=1, description="계층번호"),
* @OA\Property(property="field_name", type="string", maxLength=255, example="제품명"),
* @OA\Property(property="field_type", type="string", enum={"textbox","number","dropdown","checkbox","date","textarea"}, example="textbox"),
* @OA\Property(property="is_required", type="boolean", example=false),
@@ -226,7 +213,7 @@
* type="object",
* required={"item_name"},
*
* @OA\Property(property="group_id", type="integer", nullable=true, example=1),
* @OA\Property(property="group_id", type="integer", nullable=true, example=1, description="계층번호"),
* @OA\Property(property="item_code", type="string", nullable=true, maxLength=100, example="ITEM001"),
* @OA\Property(property="item_name", type="string", maxLength=255, example="부품 A"),
* @OA\Property(property="quantity", type="number", format="float", example=1),
@@ -240,9 +227,9 @@
* @OA\Schema(
* schema="SectionUsageResponse",
* type="object",
* description="섹션 사용처 응답 (entity_relationships 기반)",
*
* @OA\Property(property="section_id", type="integer", example=1),
* @OA\Property(property="direct_page", type="object", nullable=true),
* @OA\Property(property="linked_pages", type="array", @OA\Items(type="object")),
* @OA\Property(property="total_usage_count", type="integer", example=2)
* )
@@ -250,9 +237,9 @@
* @OA\Schema(
* schema="FieldUsageResponse",
* type="object",
* description="필드 사용처 응답 (entity_relationships 기반)",
*
* @OA\Property(property="field_id", type="integer", example=1),
* @OA\Property(property="direct_section", type="object", nullable=true),
* @OA\Property(property="linked_sections", type="array", @OA\Items(type="object")),
* @OA\Property(property="linked_pages", type="array", @OA\Items(type="object")),
* @OA\Property(property="total_usage_count", type="integer", example=3)
@@ -270,6 +257,7 @@
* type="object",
* required={"field_name","field_type"},
*
* @OA\Property(property="group_id", type="integer", nullable=true, example=1, description="계층번호"),
* @OA\Property(property="field_name", type="string", maxLength=255, example="제품명"),
* @OA\Property(property="field_type", type="string", enum={"textbox","number","dropdown","checkbox","date","textarea"}, example="textbox"),
* @OA\Property(property="is_required", type="boolean", example=true),
@@ -301,6 +289,7 @@
* type="object",
* required={"item_name"},
*
* @OA\Property(property="group_id", type="integer", nullable=true, example=1, description="계층번호"),
* @OA\Property(property="item_code", type="string", nullable=true, maxLength=100, example="ITEM001"),
* @OA\Property(property="item_name", type="string", maxLength=255, example="부품 A"),
* @OA\Property(property="quantity", type="number", format="float", example=1.5),
@@ -348,37 +337,6 @@
* )
*
* @OA\Schema(
* schema="ItemMasterFieldStoreRequest",
* type="object",
* required={"field_name","field_type"},
*
* @OA\Property(property="field_name", type="string", maxLength=255, example="제품명"),
* @OA\Property(property="field_type", type="string", enum={"textbox","number","dropdown","checkbox","date","textarea"}, example="textbox"),
* @OA\Property(property="category", type="string", nullable=true, maxLength=100, example="basic"),
* @OA\Property(property="description", type="string", nullable=true, example="설명"),
* @OA\Property(property="is_common", type="boolean", example=true),
* @OA\Property(property="default_value", type="string", nullable=true, example=null),
* @OA\Property(property="options", type="object", nullable=true, example=null),
* @OA\Property(property="validation_rules", type="object", nullable=true, example=null),
* @OA\Property(property="properties", type="object", nullable=true, example=null)
* )
*
* @OA\Schema(
* schema="ItemMasterFieldUpdateRequest",
* type="object",
*
* @OA\Property(property="field_name", type="string", maxLength=255, example="제품명"),
* @OA\Property(property="field_type", type="string", enum={"textbox","number","dropdown","checkbox","date","textarea"}, example="textbox"),
* @OA\Property(property="category", type="string", nullable=true, maxLength=100, example="basic"),
* @OA\Property(property="description", type="string", nullable=true, example="설명"),
* @OA\Property(property="is_common", type="boolean", example=true),
* @OA\Property(property="default_value", type="string", nullable=true, example=null),
* @OA\Property(property="options", type="object", nullable=true, example=null),
* @OA\Property(property="validation_rules", type="object", nullable=true, example=null),
* @OA\Property(property="properties", type="object", nullable=true, example=null)
* )
*
* @OA\Schema(
* schema="CustomTabStoreRequest",
* type="object",
* required={"label"},
@@ -451,13 +409,6 @@
* ),
*
* @OA\Property(
* property="masterFields",
* type="array",
*
* @OA\Items(ref="#/components/schemas/ItemMasterField")
* ),
*
* @OA\Property(
* property="customTabs",
* type="array",
*
@@ -570,7 +521,8 @@ public function updatePages() {}
* @OA\Delete(
* path="/api/v1/item-master/pages/{id}",
* tags={"ItemMaster"},
* summary="페이지 삭제 (Cascade)",
* summary="페이지 삭제",
* description="페이지를 삭제합니다. 연결된 섹션/필드는 삭제되지 않고 관계만 해제됩니다.",
* security={{"ApiKeyAuth":{}},{"BearerAuth":{}}},
*
* @OA\Parameter(name="id", in="path", required=true, @OA\Schema(type="integer")),
@@ -658,7 +610,7 @@ public function cloneSection() {}
* path="/api/v1/item-master/sections/{id}/usage",
* tags={"ItemMaster"},
* summary="섹션 사용처 조회",
* description="섹션이 어떤 페이지에 연결되어 있는지 조회합니다. FK 기반 연결과 entity_relationships 기반 연결 모두 조회됩니다.",
* description="섹션이 어떤 페이지에 연결되어 있는지 조회합니다 (entity_relationships 기반).",
* security={{"ApiKeyAuth":{}},{"BearerAuth":{}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="섹션 ID", @OA\Schema(type="integer")),
@@ -871,7 +823,8 @@ public function updateSections() {}
* @OA\Delete(
* path="/api/v1/item-master/sections/{id}",
* tags={"ItemMaster"},
* summary="섹션 삭제 (Cascade)",
* summary="섹션 삭제",
* description="섹션을 삭제합니다. 연결된 필드/BOM은 삭제되지 않고 관계만 해제됩니다.",
* security={{"ApiKeyAuth":{}},{"BearerAuth":{}}},
*
* @OA\Parameter(name="id", in="path", required=true, @OA\Schema(type="integer")),
@@ -1130,90 +1083,6 @@ public function updateSectionTemplates() {}
*/
public function destroySectionTemplates() {}
/**
* @OA\Get(
* path="/api/v1/item-master/master-fields",
* tags={"ItemMaster"},
* summary="마스터 필드 목록",
* security={{"ApiKeyAuth":{}},{"BearerAuth":{}}},
*
* @OA\Response(response=200, description="조회 성공",
*
* @OA\JsonContent(allOf={
*
* @OA\Schema(ref="#/components/schemas/ApiResponse"),
* @OA\Schema(@OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/ItemMasterField")))
* })
* ),
*
* @OA\Response(response=401, description="인증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
* )
*/
public function indexMasterFields() {}
/**
* @OA\Post(
* path="/api/v1/item-master/master-fields",
* tags={"ItemMaster"},
* summary="마스터 필드 생성",
* security={{"ApiKeyAuth":{}},{"BearerAuth":{}}},
*
* @OA\RequestBody(required=true, @OA\JsonContent(ref="#/components/schemas/ItemMasterFieldStoreRequest")),
*
* @OA\Response(response=200, description="생성 성공",
*
* @OA\JsonContent(allOf={
*
* @OA\Schema(ref="#/components/schemas/ApiResponse"),
* @OA\Schema(@OA\Property(property="data", ref="#/components/schemas/ItemMasterField"))
* })
* ),
*
* @OA\Response(response=422, description="검증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
* )
*/
public function storeMasterFields() {}
/**
* @OA\Put(
* path="/api/v1/item-master/master-fields/{id}",
* tags={"ItemMaster"},
* summary="마스터 필드 수정",
* security={{"ApiKeyAuth":{}},{"BearerAuth":{}}},
*
* @OA\Parameter(name="id", in="path", required=true, @OA\Schema(type="integer")),
*
* @OA\RequestBody(required=true, @OA\JsonContent(ref="#/components/schemas/ItemMasterFieldUpdateRequest")),
*
* @OA\Response(response=200, description="수정 성공",
*
* @OA\JsonContent(allOf={
*
* @OA\Schema(ref="#/components/schemas/ApiResponse"),
* @OA\Schema(@OA\Property(property="data", ref="#/components/schemas/ItemMasterField"))
* })
* ),
*
* @OA\Response(response=404, description="데이터 없음", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
* )
*/
public function updateMasterFields() {}
/**
* @OA\Delete(
* path="/api/v1/item-master/master-fields/{id}",
* tags={"ItemMaster"},
* summary="마스터 필드 삭제",
* security={{"ApiKeyAuth":{}},{"BearerAuth":{}}},
*
* @OA\Parameter(name="id", in="path", required=true, @OA\Schema(type="integer")),
*
* @OA\Response(response=200, description="삭제 성공", @OA\JsonContent(ref="#/components/schemas/ApiResponse")),
* @OA\Response(response=404, description="데이터 없음", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
* )
*/
public function destroyMasterFields() {}
/**
* @OA\Get(
* path="/api/v1/item-master/custom-tabs",