# 부서관리 화면 구현 체크리스트

> **생성일**: 2025-12-05
> **상태**: 구현 완료 (API 연동 대기)
> **경로**: `인사관리 > 부서관리`
> **테스트 URL**: `http://localhost:3000/ko/hr/department-management`

---

## 0. 핵심 요구사항

### 트리 구조 - 무제한 깊이

```
회사명
├── 부서A
│   ├── 팀A-1
│   │   ├── 파트A-1-1
│   │   │   └── ... (무제한)
│   │   └── 파트A-1-2
│   └── 팀A-2
├── 부서B
│   └── 팀B-1
└── 부서C
```

- **깊이 제한 없음**: 부서 > 하위부서 > 하위부서 > ... 무한 재귀 가능
- **재귀적 데이터 구조**: `children` 배열로 무한 중첩 표현
- **동적 들여쓰기**: depth에 따라 padding-left 계산 (`depth * 24px` 등)
- **+/- 토글**: 하위 항목이 있는 모든 노드에 펼침/접힘 버튼 표시

---

## 1. 화면 분석 요약

### 1.1 스크린샷 기반 기능 정리

| 번호 | 구분 | 기능 | 설명 |
|------|------|------|------|
| 01 | 전체 선택 | 체크박스 | 전체 선택/해제 토글, 디폴트 해제 |
| 02 | 개별 선택 | 체크박스 | 개별 선택/해제 토글, 디폴트 해제 |
| 03 | 추가 버튼 | 상단 액션 | 관리 권한 없으면 숨김, 선택한 부서의 하위 부서 일괄 생성 |
| 04 | 삭제 버튼 | 상단 액션 | 관리 권한 없으면 숨김, "선택한 부서 N개를 삭제하시겠습니까?" Alert |
| 05 | 축소 버튼 | 트리 (-) | 클릭 시 확대 버튼으로 변경, 하위 부서 숨김 |
| 06 | 확대 버튼 | 트리 (+) | 클릭 시 축소 버튼으로 변경, 하위 부서 표시 |
| 07 | 추가 버튼 | 행 호버 | 관리 권한 없으면 숨김, 부서 추가 팝업 표시 |
| 08 | 수정 버튼 | 행 호버 | 관리 권한 없으면 숨김, 부서 수정 팝업 표시 |
| 09 | 삭제 버튼 | 행 호버 | 관리 권한 없으면 숨김, "{부서명} 부서를 삭제하시겠습니까?" Alert |

### 1.2 팝업 구성

| 팝업 | 구성요소 | 비고 |
|------|----------|------|
| 부서 추가 | 부서명 인풋박스 + 취소/등록 버튼 | 기존 부서명 표시, 수정 가능 |
| 부서 수정 | 부서명 인풋박스 + 취소/수정 버튼 | 기존 부서명 표시 |

### 1.3 삭제 로직

- 삭제 시 해당 부서의 인원은 **회사(기본) 인원으로 변경**됨

---

## 2. 컴포넌트 구조

```
src/
├── app/[locale]/(protected)/hr/
│   └── department-management/
│       └── page.tsx                    # 페이지 진입점
│
└── components/hr/
    └── DepartmentManagement/
        ├── index.tsx                   # 메인 컴포넌트
        ├── DepartmentStats.tsx         # 전체 부서 카운트 카드
        ├── DepartmentToolbar.tsx       # 검색 + 추가/삭제 버튼
        ├── DepartmentTree.tsx          # 트리 구조 테이블
        ├── DepartmentTreeItem.tsx      # 트리 행 (재귀)
        ├── DepartmentDialog.tsx        # 추가/수정 팝업
        └── types.ts                    # 타입 정의
```

---

## 3. 타입 정의

```typescript
// types.ts

/**
 * 부서 데이터 (무제한 깊이 재귀 구조)
 * - depth: 렌더링 시 들여쓰기 계산용 (0부터 시작, 제한 없음)
 * - children: 하위 부서 배열 (재귀적으로 무한 중첩 가능)
 */
interface Department {
  id: number;
  name: string;
  parentId: number | null;
  depth: number;           // 깊이 (0: 최상위, 1, 2, 3, ... 무제한)
  children?: Department[]; // 하위 부서 (재귀 - 무제한 깊이)
}

interface DepartmentDialogProps {
  isOpen: boolean;
  onOpenChange: (open: boolean) => void;
  mode: 'add' | 'edit';
  parentDepartment?: Department;  // 추가 시 부모 부서
  department?: Department;        // 수정 시 대상 부서
  onSubmit: (name: string) => void;
}

/**
 * 트리 아이템 Props (재귀 렌더링)
 */
interface DepartmentTreeItemProps {
  department: Department;
  depth: number;                    // 현재 깊이 (들여쓰기 계산용)
  isExpanded: boolean;              // 펼침 상태
  isSelected: boolean;              // 선택 상태
  onToggleExpand: (id: number) => void;
  onToggleSelect: (id: number) => void;
  onAdd: (parentId: number) => void;
  onEdit: (department: Department) => void;
  onDelete: (department: Department) => void;
  expandedIds: Set<number>;         // 전체 펼침 상태 (하위 재귀용)
  selectedIds: Set<number>;         // 전체 선택 상태 (하위 재귀용)
}
```

---

## 4. 구현 체크리스트

### Phase 1: 기본 구조 설정
- [x] `types.ts` - Department 타입 및 Props 인터페이스 정의
- [x] `page.tsx` - 라우트 페이지 생성 (`/hr/department-management`)
- [x] `index.tsx` - DepartmentManagement 메인 컴포넌트 (PageLayout + PageHeader)

### Phase 2: 상단 영역 구현
- [x] `DepartmentStats.tsx` - 전체 부서 카운트 카드 ("전체 부서 N개")
- [x] `DepartmentToolbar.tsx` - 검색창 구현
- [x] `DepartmentToolbar.tsx` - 선택 카운트 표시 ("총 N건 | N건 선택")
- [x] `DepartmentToolbar.tsx` - 추가 버튼 (선택한 부서 하위에 일괄 추가)
- [x] `DepartmentToolbar.tsx` - 삭제 버튼 (선택한 부서 일괄 삭제)

### Phase 3: 트리 테이블 구현
- [x] `DepartmentTree.tsx` - 테이블 헤더 (전체 선택 체크박스 + 부서명 + 작업)
- [x] `DepartmentTreeItem.tsx` - 트리 행 기본 구조 (체크박스 + 들여쓰기 + 부서명)
- [x] `DepartmentTreeItem.tsx` - +/- 버튼 (하위 부서 펼침/접힘)
- [x] `DepartmentTreeItem.tsx` - 호버 시 작업 버튼 표시 (추가, 수정, 삭제)
- [x] `DepartmentTreeItem.tsx` - 재귀 렌더링 (하위 부서 표시)

### Phase 4: 다이얼로그 구현
- [x] `DepartmentDialog.tsx` - 부서 추가 팝업 (부서명 입력 + 취소/등록)
- [x] `DepartmentDialog.tsx` - 부서 수정 팝업 (부서명 입력 + 취소/수정)
- [x] AlertDialog - 단일 삭제 확인 ("{부서명} 부서를 삭제하시겠습니까?")
- [x] AlertDialog - 일괄 삭제 확인 ("선택한 부서 N개를 삭제하시겠습니까?")

### Phase 5: 상태 관리 & 인터랙션
- [x] 체크박스 선택 상태 관리 (selectedIds: Set)
- [x] 전체 선택/해제 로직 구현
- [x] 트리 펼침/접힘 상태 관리 (expandedIds: Set)
- [ ] 검색 필터링 로직 구현 (TODO: 추후 구현)
- [x] 목업 데이터 생성 및 연동

### Phase 6: 스타일 및 마무리
- [x] 기존 프로젝트 디자인 패턴 적용 확인
- [x] 반응형 레이아웃 확인 (모바일/데스크톱)
- [x] 호버 애니메이션 및 트랜지션 확인
- [ ] 접근성 확인 (키보드 네비게이션) (TODO: 추후 보완)

---

## 5. 디자인 기준 (기존 프로젝트 패턴)

### 5.1 레이아웃
- **페이지 패딩**: `p-4 md:p-6`
- **섹션 간격**: `space-y-4 md:space-y-6`
- **카드**: `border rounded-lg p-4`

### 5.2 컴포넌트
| 요소 | 컴포넌트 | 비고 |
|------|----------|------|
| 페이지 래퍼 | `PageLayout` | maxWidth="full" |
| 헤더 | `PageHeader` | icon + title + description |
| 카드 | `Card` | 전체 부서 카운트 |
| 입력창 | `Input` | 검색, 부서명 |
| 버튼 | `Button` | variant: default, outline, ghost, destructive |
| 체크박스 | `Checkbox` | 전체/개별 선택 |
| 팝업 | `Dialog` | 추가/수정 |
| 확인창 | `AlertDialog` | 삭제 확인 |

### 5.3 아이콘 (lucide-react)
- `Building2` - 페이지 아이콘
- `Search` - 검색
- `Plus` - 추가
- `Trash2` - 삭제
- `Pencil` - 수정
- `ChevronRight` / `ChevronDown` - 트리 펼침/접힘
- `Minus` - 트리 접힘 버튼

### 5.4 인터랙션
- **행 호버**: `hover:bg-gray-50 transition-colors`
- **작업 버튼**: 호버 시에만 표시 (`opacity-0 group-hover:opacity-100`)

---

## 6. 목업 데이터

```typescript
/**
 * 무제한 깊이 트리 구조 목업 데이터
 * - depth 0: 회사
 * - depth 1: 부서
 * - depth 2: 팀
 * - depth 3+: 파트, 셀, ... (무제한)
 */
const mockDepartments: Department[] = [
  {
    id: 1,
    name: '회사명',
    parentId: null,
    depth: 0,
    children: [
      {
        id: 2,
        name: '경영지원본부',
        parentId: 1,
        depth: 1,
        children: [
          {
            id: 4,
            name: '인사팀',
            parentId: 2,
            depth: 2,
            children: [
              {
                id: 7,
                name: '채용파트',
                parentId: 4,
                depth: 3,
                children: [
                  { id: 10, name: '신입채용셀', parentId: 7, depth: 4, children: [] },
                  { id: 11, name: '경력채용셀', parentId: 7, depth: 4, children: [] },
                ]
              },
              { id: 8, name: '교육파트', parentId: 4, depth: 3, children: [] },
            ]
          },
          { id: 5, name: '총무팀', parentId: 2, depth: 2, children: [] },
        ]
      },
      {
        id: 3,
        name: '개발본부',
        parentId: 1,
        depth: 1,
        children: [
          { id: 6, name: '프론트엔드팀', parentId: 3, depth: 2, children: [] },
          { id: 9, name: '백엔드팀', parentId: 3, depth: 2, children: [] },
        ]
      },
    ]
  }
];

/**
 * 전체 부서 수 계산 유틸리티 (재귀)
 */
const countAllDepartments = (departments: Department[]): number => {
  return departments.reduce((count, dept) => {
    return count + 1 + (dept.children ? countAllDepartments(dept.children) : 0);
  }, 0);
};

/**
 * 모든 부서 ID 추출 유틸리티 (재귀 - 전체 선택용)
 */
const getAllDepartmentIds = (departments: Department[]): number[] => {
  return departments.flatMap(dept => [
    dept.id,
    ...(dept.children ? getAllDepartmentIds(dept.children) : [])
  ]);
};
```

---

## 7. 참고 파일

| 파일 | 참고 내용 |
|------|-----------|
| `src/components/items/ItemMasterDataManagement.tsx` | 전체 구조 패턴 |
| `src/components/organisms/PageHeader.tsx` | 헤더 컴포넌트 |
| `src/components/organisms/PageLayout.tsx` | 레이아웃 컴포넌트 |
| `src/components/ui/dialog.tsx` | 다이얼로그 사용법 |
| `src/components/ui/alert-dialog.tsx` | 확인 다이얼로그 |
| `src/components/ui/checkbox.tsx` | 체크박스 |

---

## 8. 진행 로그

| 날짜 | 작업 내용 | 상태 |
|------|-----------|------|
| 2025-12-05 | 계획서 작성 | 완료 |
| 2025-12-05 | Phase 1: 기본 구조 (types, page, index) | 완료 |
| 2025-12-05 | Phase 2: 상단 영역 (Stats, Toolbar) | 완료 |
| 2025-12-05 | Phase 3: 트리 테이블 (Tree, TreeItem) | 완료 |
| 2025-12-05 | Phase 4: 다이얼로그 (Dialog, AlertDialog) | 완료 |
| 2025-12-05 | Phase 5: 상태 관리 (선택, 펼침, 추가/수정/삭제) | 완료 |
| 2025-12-05 | 빌드 테스트 | 성공 |

---

## 9. 이슈 및 메모

- API 연동 없이 화면만 먼저 구현 (목업 데이터 사용)
- 권한 체크 로직은 추후 API 연동 시 구현 예정
- 삭제 시 인원 이동 로직은 백엔드 API 의존