# 조직도 React 프론트엔드 구현 가이드 > **작성일**: 2026-03-22 > **상태**: API 완료, FE 구현 대기 > **대상**: React (Next.js) 프론트엔드 개발자 > **페이지 URL**: `/hr/org-chart` --- ## 1. 개요 MNG의 조직도 관리 기능을 React로 재구현한다. API는 이미 구현 완료(`/v1/org-chart`). 드래그 앤 드롭으로 직원 배치, 부서 순서/계층 변경, 부서 숨기기 기능을 제공한다. --- ## 2. API 엔드포인트 | Method | Path | 설명 | |--------|------|------| | GET | `/v1/org-chart` | 조직도 전체 (트리+직원+통계) | | GET | `/v1/org-chart/stats` | 통계 (전체/배치/미배치) | | GET | `/v1/org-chart/unassigned?q=` | 미배치 직원 검색 | | POST | `/v1/org-chart/assign` | 직원 → 부서 배치 | | POST | `/v1/org-chart/unassign` | 직원 미배치 처리 | | PUT | `/v1/org-chart/reorder-employees` | 직원 일괄 이동 | | PUT | `/v1/org-chart/reorder-departments` | 부서 순서/계층 변경 | | PATCH | `/v1/org-chart/departments/{id}/toggle-hide` | 부서 숨기기 토글 | > Swagger UI: `/api-docs` → "OrgChart" 태그 참조 --- ## 3. 응답 구조 ### 3.1 GET `/v1/org-chart` ```json { "success": true, "data": { "company": { "name": "주일산업", "ceo_name": "홍길동" }, "departments": [ { "id": 1, "name": "경영지원팀", "code": "MGT", "parent_id": null, "sort_order": 1, "is_active": true, "orgchart_hidden": false, "children": [], "employees": [ { "id": 5, "user_id": 3, "department_id": 1, "display_name": "김과장", "position_label": "과장" } ] } ], "hidden_departments": [ { "id": 5, "name": "해외사업팀", "code": "OVS" } ], "unassigned": [ { "id": 12, "user_id": 8, "display_name": "이사원", "position_label": "사원" } ], "stats": { "total": 50, "assigned": 42, "unassigned": 8 } } } ``` ### 3.2 요청 바디 예시 **POST `/v1/org-chart/assign`**: ```json { "employee_id": 5, "department_id": 3 } ``` **PUT `/v1/org-chart/reorder-employees`**: ```json { "moves": [ { "employee_id": 5, "department_id": 3 }, { "employee_id": 6, "department_id": null } ] } ``` **PUT `/v1/org-chart/reorder-departments`**: ```json { "orders": [ { "id": 1, "parent_id": null, "sort_order": 0 }, { "id": 2, "parent_id": 1, "sort_order": 1 } ] } ``` **PATCH `/v1/org-chart/departments/{id}/toggle-hide`**: ```json { "hidden": true } ``` --- ## 4. 컴포넌트 구조 (제안) ``` src/ ├── app/[locale]/(protected)/hr/ │ └── org-chart/ │ └── page.tsx ← 페이지 진입점 ├── components/hr/org-chart/ │ ├── index.tsx ← 메인 컨테이너 │ ├── OrgChartTree.tsx ← 부서 트리 렌더링 │ ├── DepartmentNode.tsx ← 부서 카드 (접기/펼치기, 숨기기) │ ├── EmployeeCard.tsx ← 직원 카드 (드래그 가능) │ ├── UnassignedPanel.tsx ← 미배치 직원 패널 (검색 포함) │ ├── HiddenDepartmentsPanel.tsx ← 숨겨진 부서 복원 패널 │ ├── OrgChartStats.tsx ← 상단 통계 표시 │ ├── CompanyHeader.tsx ← 회사명 + CEO 표시 │ ├── actions.ts ← Server Actions │ └── types.ts ← TypeScript 타입 정의 ``` --- ## 5. UI 구성 (MNG 참조) MNG 조직도 UI: `mng/resources/views/rd/org-chart.blade.php` ### 5.1 화면 레이아웃 ``` ┌───────────────────────────────────────────────────────┐ │ 조직도 관리 전체 50명 | 배치 42명 | 미배치 8명 │ ← 헤더 + 통계 ├───────────────────────────────────────────────────────┤ │ ┌─미배치 직원──────┐ ┌─조직도 트리───────────────────┐ │ │ │ 🔍 검색 │ │ ┌──────────────────────────┐ │ │ │ │ │ │ │ 회사명 │ │ │ │ │ ▪ 이사원 (사원) │ │ │ CEO: 홍길동 │ │ │ │ │ ▪ 박대리 (대리) │ │ └──────────────────────────┘ │ │ │ │ │ │ │ │ │ │ (드래그 가능) │ │ ┌─경영지원팀 (MGT)──────────┐ │ │ │ │ │ │ │ 김과장 (과장) [미배치 ✕] │ │ │ │ │ │ │ │ 최대리 (대리) [미배치 ✕] │ │ │ │ │ │ │ └──────────────────────────┘ │ │ │ │ │ │ ┌─생산팀 (PRD)───────────────┐ │ │ │ │ │ │ │ ... │ │ │ │ │ │ │ └────────────────────────────┘ │ │ │ └──────────────────┘ └──────────────────────────────┘ │ │ ┌─숨겨진 부서──────────────────────────────────────────┐ │ │ │ 해외사업팀 [복원] 영업3팀 [복원] │ │ │ └──────────────────────────────────────────────────────┘ │ └───────────────────────────────────────────────────────┘ ``` ### 5.2 인터랙션 | 동작 | 효과 | API 호출 | |------|------|---------| | 미배치 직원 → 부서 드래그 | 직원 배치 | `POST /assign` 또는 `PUT /reorder-employees` | | 부서 내 직원 → 미배치 패널 드래그 | 직원 미배치 | `POST /unassign` | | 부서 카드 드래그 (순서 변경) | 부서 순서/계층 변경 | `PUT /reorder-departments` | | 부서 카드 더블클릭 → "숨기기" | 조직도에서 숨김 | `PATCH /departments/{id}/toggle-hide` | | 숨겨진 부서 "복원" 클릭 | 조직도에 다시 표시 | `PATCH /departments/{id}/toggle-hide` | --- ## 6. 드래그 앤 드롭 구현 ### 6.1 라이브러리 권장 - **@dnd-kit**: React 전용, 접근성 지원, 트리 구조 지원 - **대안**: react-beautiful-dnd (유지보수 중단), react-dnd ### 6.2 핵심 구현 포인트 1. **직원 드래그**: 미배치 패널 ↔ 부서 카드 간 이동 2. **부서 드래그**: 부서 카드 간 순서/계층 변경 (parent_id + sort_order) 3. **순환 참조 방지**: 부서를 자기 자손에 드롭하면 무시 (API에서도 검증하지만 UI에서도 방지) 4. **Optimistic Update**: 드래그 완료 시 로컬 상태 즉시 업데이트 → API 호출 → 실패 시 롤백 ### 6.3 상태 관리 ``` 초기 로딩: GET /v1/org-chart → 로컬 상태 세팅 ├── departments (트리 구조) ├── unassigned (미배치 직원 배열) ├── hiddenDepartments (숨겨진 부서 배열) ├── stats (통계) └── company (회사 정보) 변경 시: API 호출 → 성공 시 로컬 상태 업데이트 ``` --- ## 7. MNG 참고 파일 | 파일 | 설명 | |------|------| | `mng/app/Http/Controllers/RdController.php` (L38-208) | 조직도 컨트롤러 로직 | | `mng/resources/views/rd/org-chart.blade.php` | 조직도 UI (Alpine.js + SortableJS) | | `mng/app/Models/Tenants/Department.php` | Department 모델 (options cast) | --- ## 관련 문서 | 문서 | 경로 | |------|------| | 이관 계획서 | `dev/dev_plans/org-chart-service-migration-plan.md` | | 조직도 시스템 (MNG) | `projects/org-chart/README.md` | | React 아키텍처 | `frontend/v1/01-architecture.md` | | API 패턴 | `frontend/v1/02-api-pattern.md` | | 인증 흐름 | `frontend/v1/07-auth-flow.md` | --- **최종 업데이트**: 2026-03-22