feat: [org-chart] 조직도 관리 API 이관 (8개 엔드포인트)

- OrgChartController + OrgChartService 신규 생성
- FormRequest 5개 (Assign/Unassign/ReorderEmployees/ReorderDepartments/ToggleHide)
- Department 모델 options cast 추가
- Swagger 문서 (OrgChartApi.php) 생성
- hr.php 라우트 그룹 추가 (/v1/org-chart)
This commit is contained in:
김보곤
2026-03-22 17:22:12 +09:00
parent d502c9b85d
commit 902f681f6e
11 changed files with 1588 additions and 24 deletions

View File

@@ -0,0 +1,359 @@
<?php
namespace App\Swagger\v1;
/**
* @OA\Tag(
* name="OrgChart",
* description="조직도 관리"
* )
*
* @OA\Schema(
* schema="OrgChartEmployee",
* type="object",
*
* @OA\Property(property="id", type="integer", example=5, description="프로필 ID"),
* @OA\Property(property="user_id", type="integer", example=3),
* @OA\Property(property="department_id", type="integer", nullable=true, example=1),
* @OA\Property(property="display_name", type="string", example="홍길동"),
* @OA\Property(property="position_label", type="string", nullable=true, example="과장")
* )
*
* @OA\Schema(
* schema="OrgChartDepartmentNode",
* type="object",
*
* @OA\Property(property="id", type="integer", example=1),
* @OA\Property(property="name", type="string", example="경영지원팀"),
* @OA\Property(property="code", type="string", nullable=true, example="MGT"),
* @OA\Property(property="parent_id", type="integer", nullable=true),
* @OA\Property(property="sort_order", type="integer", example=1),
* @OA\Property(property="is_active", type="boolean", example=true),
* @OA\Property(property="orgchart_hidden", type="boolean", example=false),
* @OA\Property(property="children", type="array", @OA\Items(ref="#/components/schemas/OrgChartDepartmentNode")),
* @OA\Property(property="employees", type="array", @OA\Items(ref="#/components/schemas/OrgChartEmployee"))
* )
*
* @OA\Schema(
* schema="OrgChartStats",
* type="object",
*
* @OA\Property(property="total", type="integer", example=50),
* @OA\Property(property="assigned", type="integer", example=42),
* @OA\Property(property="unassigned", type="integer", example=8)
* )
*
* @OA\Schema(
* schema="OrgChartAssignRequest",
* type="object",
* required={"employee_id", "department_id"},
*
* @OA\Property(property="employee_id", type="integer", example=5, description="직원 프로필 ID"),
* @OA\Property(property="department_id", type="integer", example=3, description="배치할 부서 ID")
* )
*
* @OA\Schema(
* schema="OrgChartUnassignRequest",
* type="object",
* required={"employee_id"},
*
* @OA\Property(property="employee_id", type="integer", example=5, description="직원 프로필 ID")
* )
*
* @OA\Schema(
* schema="OrgChartReorderEmployeesRequest",
* type="object",
* required={"moves"},
*
* @OA\Property(
* property="moves",
* type="array",
*
* @OA\Items(
* type="object",
* required={"employee_id"},
*
* @OA\Property(property="employee_id", type="integer", example=5),
* @OA\Property(property="department_id", type="integer", nullable=true, example=3)
* )
* )
* )
*
* @OA\Schema(
* schema="OrgChartReorderDepartmentsRequest",
* type="object",
* required={"orders"},
*
* @OA\Property(
* property="orders",
* type="array",
*
* @OA\Items(
* type="object",
* required={"id", "parent_id", "sort_order"},
*
* @OA\Property(property="id", type="integer", example=1),
* @OA\Property(property="parent_id", type="integer", nullable=true, example=null),
* @OA\Property(property="sort_order", type="integer", example=0)
* )
* )
* )
*
* @OA\Schema(
* schema="OrgChartToggleHideRequest",
* type="object",
* required={"hidden"},
*
* @OA\Property(property="hidden", type="boolean", example=true, description="숨기기 여부")
* )
*/
class OrgChartApi
{
/**
* @OA\Get(
* path="/api/v1/org-chart",
* tags={"OrgChart"},
* summary="조직도 전체 조회 (부서 트리 + 직원 + 통계)",
* security={{"ApiKeyAuth": {}}, {"BearerAuth": {}}},
*
* @OA\Parameter(name="include_hidden", in="query", description="숨겨진 부서 포함 여부 (기본: true)", @OA\Schema(type="boolean")),
*
* @OA\Response(
* response=200,
* description="성공",
*
* @OA\JsonContent(
* type="object",
*
* @OA\Property(property="success", type="boolean", example=true),
* @OA\Property(property="message", type="string"),
* @OA\Property(
* property="data",
* type="object",
* @OA\Property(property="company", type="object",
* @OA\Property(property="name", type="string", example="주일산업"),
* @OA\Property(property="ceo_name", type="string", example="홍길동")
* ),
* @OA\Property(property="departments", type="array", @OA\Items(ref="#/components/schemas/OrgChartDepartmentNode")),
* @OA\Property(property="hidden_departments", type="array", @OA\Items(type="object",
* @OA\Property(property="id", type="integer"),
* @OA\Property(property="name", type="string"),
* @OA\Property(property="code", type="string")
* )),
* @OA\Property(property="unassigned", type="array", @OA\Items(ref="#/components/schemas/OrgChartEmployee")),
* @OA\Property(property="stats", ref="#/components/schemas/OrgChartStats")
* )
* )
* )
* )
*/
public function index() {}
/**
* @OA\Get(
* path="/api/v1/org-chart/stats",
* tags={"OrgChart"},
* summary="조직도 통계 (전체/배치/미배치 인원)",
* security={{"ApiKeyAuth": {}}, {"BearerAuth": {}}},
*
* @OA\Response(
* response=200,
* description="성공",
*
* @OA\JsonContent(
* type="object",
*
* @OA\Property(property="success", type="boolean", example=true),
* @OA\Property(property="message", type="string"),
* @OA\Property(property="data", ref="#/components/schemas/OrgChartStats")
* )
* )
* )
*/
public function stats() {}
/**
* @OA\Get(
* path="/api/v1/org-chart/unassigned",
* tags={"OrgChart"},
* summary="미배치 직원 목록",
* security={{"ApiKeyAuth": {}}, {"BearerAuth": {}}},
*
* @OA\Parameter(name="q", in="query", description="이름 검색", @OA\Schema(type="string")),
*
* @OA\Response(
* response=200,
* description="성공",
*
* @OA\JsonContent(
* type="object",
*
* @OA\Property(property="success", type="boolean", example=true),
* @OA\Property(property="message", type="string"),
* @OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/OrgChartEmployee"))
* )
* )
* )
*/
public function unassigned() {}
/**
* @OA\Post(
* path="/api/v1/org-chart/assign",
* tags={"OrgChart"},
* summary="직원 부서 배치",
* security={{"ApiKeyAuth": {}}, {"BearerAuth": {}}},
*
* @OA\RequestBody(
* required=true,
*
* @OA\JsonContent(ref="#/components/schemas/OrgChartAssignRequest")
* ),
*
* @OA\Response(
* response=200,
* description="성공",
*
* @OA\JsonContent(
* type="object",
*
* @OA\Property(property="success", type="boolean", example=true),
* @OA\Property(property="message", type="string"),
* @OA\Property(property="data", type="object",
* @OA\Property(property="employee_id", type="integer"),
* @OA\Property(property="department_id", type="integer")
* )
* )
* )
* )
*/
public function assign() {}
/**
* @OA\Post(
* path="/api/v1/org-chart/unassign",
* tags={"OrgChart"},
* summary="직원 미배치 처리",
* security={{"ApiKeyAuth": {}}, {"BearerAuth": {}}},
*
* @OA\RequestBody(
* required=true,
*
* @OA\JsonContent(ref="#/components/schemas/OrgChartUnassignRequest")
* ),
*
* @OA\Response(
* response=200,
* description="성공",
*
* @OA\JsonContent(
* type="object",
*
* @OA\Property(property="success", type="boolean", example=true),
* @OA\Property(property="message", type="string"),
* @OA\Property(property="data", type="object",
* @OA\Property(property="employee_id", type="integer"),
* @OA\Property(property="department_id", type="integer", nullable=true)
* )
* )
* )
* )
*/
public function unassign() {}
/**
* @OA\Put(
* path="/api/v1/org-chart/reorder-employees",
* tags={"OrgChart"},
* summary="직원 일괄 배치/이동",
* security={{"ApiKeyAuth": {}}, {"BearerAuth": {}}},
*
* @OA\RequestBody(
* required=true,
*
* @OA\JsonContent(ref="#/components/schemas/OrgChartReorderEmployeesRequest")
* ),
*
* @OA\Response(
* response=200,
* description="성공",
*
* @OA\JsonContent(
* type="object",
*
* @OA\Property(property="success", type="boolean", example=true),
* @OA\Property(property="message", type="string"),
* @OA\Property(property="data", type="object",
* @OA\Property(property="processed", type="integer", example=3)
* )
* )
* )
* )
*/
public function reorderEmployees() {}
/**
* @OA\Put(
* path="/api/v1/org-chart/reorder-departments",
* tags={"OrgChart"},
* summary="부서 순서/계층 일괄 변경",
* security={{"ApiKeyAuth": {}}, {"BearerAuth": {}}},
*
* @OA\RequestBody(
* required=true,
*
* @OA\JsonContent(ref="#/components/schemas/OrgChartReorderDepartmentsRequest")
* ),
*
* @OA\Response(
* response=200,
* description="성공",
*
* @OA\JsonContent(
* type="object",
*
* @OA\Property(property="success", type="boolean", example=true),
* @OA\Property(property="message", type="string"),
* @OA\Property(property="data", type="object",
* @OA\Property(property="processed", type="integer", example=5)
* )
* )
* )
* )
*/
public function reorderDepartments() {}
/**
* @OA\Patch(
* path="/api/v1/org-chart/departments/{id}/toggle-hide",
* tags={"OrgChart"},
* summary="부서 숨기기/표시 토글",
* security={{"ApiKeyAuth": {}}, {"BearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="부서 ID", @OA\Schema(type="integer")),
*
* @OA\RequestBody(
* required=true,
*
* @OA\JsonContent(ref="#/components/schemas/OrgChartToggleHideRequest")
* ),
*
* @OA\Response(
* response=200,
* description="성공",
*
* @OA\JsonContent(
* type="object",
*
* @OA\Property(property="success", type="boolean", example=true),
* @OA\Property(property="message", type="string"),
* @OA\Property(property="data", type="object",
* @OA\Property(property="id", type="integer"),
* @OA\Property(property="orgchart_hidden", type="boolean")
* )
* )
* )
* )
*/
public function toggleHide() {}
}