# 권한 시스템 마이그레이션 완료 보고서

## 실행 완료 ✅

날짜: 2025-10-27  
대상 데이터베이스: `plm` (39.117.244.52:11132)

---

## 실행된 마이그레이션

### 1. **028_add_company_code_to_authority_master.sql** ✅

**목적**: 권한 그룹 시스템 개선 (회사별 격리)

**주요 변경사항**:

- `authority_master.company_code` 컬럼 추가 (회사별 권한 그룹 격리)
- 외래 키 제약 조건 추가 (`authority_sub_user` ↔ `authority_master`, `user_info`)
- 권한 요약 뷰 생성 (`v_authority_group_summary`)
- 유틸리티 함수 생성 (`get_user_authority_groups`)

### 2. **031_add_menu_auth_columns.sql** ✅

**목적**: 메뉴 기반 권한 시스템 개선 (동적 화면 대응)

**주요 변경사항**:

- `menu_info.screen_code`, `menu_info.menu_code` 컬럼 추가
- `rel_menu_auth.execute_yn`, `rel_menu_auth.export_yn` 컬럼 추가
- 화면 생성 시 자동 메뉴 추가 트리거 (`auto_create_menu_for_screen`)
- 화면 삭제 시 자동 메뉴 비활성화 트리거 (`auto_deactivate_menu_for_screen`)
- 권한 체크 함수 (`check_menu_crud_permission`)
- 사용자 메뉴 조회 함수 (`get_user_menus_with_permissions`)
- 권한 요약 뷰 (`v_menu_permission_summary`)

---

## 현재 데이터베이스 구조

### 1. 권한 그룹 시스템

#### `authority_master` (권한 그룹)

```
objid           | NUMERIC     | 권한 그룹 ID (PK)
auth_name       | VARCHAR(50) | 권한 그룹 이름
auth_code       | VARCHAR(50) | 권한 그룹 코드
company_code    | VARCHAR(20) | 회사 코드 ⭐ (회사별 격리)
status          | VARCHAR(20) | 활성/비활성
```

#### `authority_sub_user` (권한 그룹 멤버)

```
master_objid    | NUMERIC     | 권한 그룹 ID (FK)
user_id         | VARCHAR(50) | 사용자 ID (FK)
```

#### 현재 권한 그룹 현황

- COMPANY_1: 2개 그룹
- COMPANY_2: 2개 그룹
- COMPANY_3: 7개 그룹
- COMPANY_4: 2개 그룹
- ILSHIN: 3개 그룹

### 2. 메뉴 권한 시스템

#### `menu_info` (메뉴 정보)

```
objid           | NUMERIC      | 메뉴 ID (PK)
menu_name_kor   | VARCHAR(64)  | 메뉴 이름 (한글)
menu_name_eng   | VARCHAR(64)  | 메뉴 이름 (영어)
menu_code       | VARCHAR(50)  | 메뉴 코드 ⭐ (신규)
menu_url        | VARCHAR(256) | 메뉴 URL
menu_type       | NUMERIC      | 메뉴 타입 (0=일반, 1=시스템, 2=동적생성 ⭐)
screen_code     | VARCHAR(50)  | 화면 코드 ⭐ (동적 메뉴 연동)
company_code    | VARCHAR(50)  | 회사 코드
parent_obj_id   | NUMERIC      | 부모 메뉴 ID
seq             | NUMERIC      | 정렬 순서
status          | VARCHAR(32)  | 상태
```

#### `rel_menu_auth` (메뉴별 권한)

```
menu_objid      | NUMERIC     | 메뉴 ID (FK)
auth_objid      | NUMERIC     | 권한 그룹 ID (FK)
create_yn       | VARCHAR(50) | 생성 권한
read_yn         | VARCHAR(50) | 읽기 권한
update_yn       | VARCHAR(50) | 수정 권한
delete_yn       | VARCHAR(50) | 삭제 권한
execute_yn      | CHAR(1)     | 실행 권한 ⭐ (신규)
export_yn       | CHAR(1)     | 내보내기 권한 ⭐ (신규)
```

---

## 자동화 기능

### 1. 화면 생성 시 자동 메뉴 추가 🤖

```sql
-- 사용자가 화면 생성
INSERT INTO screen_definitions (screen_name, screen_code, company_code, ...)
VALUES ('계약 관리', 'SCR_CONTRACT', 'ILSHIN', ...);

-- ↓ 트리거 자동 실행 ↓

-- menu_info에 자동 추가됨!
-- menu_type = 2 (동적 생성)
-- screen_code = 'SCR_CONTRACT'
-- menu_url = '/screen/SCR_CONTRACT'
```

### 2. 화면 삭제 시 자동 메뉴 비활성화 🤖

```sql
-- 화면 삭제
UPDATE screen_definitions
SET is_active = 'D'
WHERE screen_code = 'SCR_CONTRACT';

-- ↓ 트리거 자동 실행 ↓

-- 메뉴 비활성화됨!
UPDATE menu_info
SET status = 'inactive'
WHERE screen_code = 'SCR_CONTRACT';
```

---

## 사용 가이드

### 1. 권한 그룹 생성

```sql
-- 예: ILSHIN 회사의 "개발팀" 권한 그룹 생성
INSERT INTO authority_master (objid, auth_name, auth_code, company_code, status, writer, regdate)
VALUES (nextval('seq_authority_master'), '개발팀', 'DEV_TEAM', 'ILSHIN', 'active', 'admin', NOW());
```

### 2. 권한 그룹에 멤버 추가

```sql
-- 예: '개발팀'에 사용자 'dev1' 추가
INSERT INTO authority_sub_user (master_objid, user_id)
VALUES (
    (SELECT objid FROM authority_master WHERE auth_code = 'DEV_TEAM' AND company_code = 'ILSHIN'),
    'dev1'
);
```

### 3. 메뉴 권한 설정

```sql
-- 예: '개발팀'에게 특정 메뉴의 CRUD 권한 부여
INSERT INTO rel_menu_auth (menu_objid, auth_objid, create_yn, read_yn, update_yn, delete_yn, execute_yn, export_yn, writer)
VALUES (
    1005,  -- 메뉴 ID
    (SELECT objid FROM authority_master WHERE auth_code = 'DEV_TEAM' AND company_code = 'ILSHIN'),
    'Y', 'Y', 'Y', 'Y', 'Y', 'N',  -- CRUD + Execute 권한
    'admin'
);
```

### 4. 사용자 권한 확인

```sql
-- 예: 'dev1' 사용자가 메뉴 1005를 수정할 수 있는지 확인
SELECT check_menu_crud_permission('dev1', 1005, 'update');
-- 결과: TRUE 또는 FALSE

-- 예: 'dev1' 사용자가 접근 가능한 모든 메뉴 조회
SELECT * FROM get_user_menus_with_permissions('dev1', 'ILSHIN');
```

---

## 다음 단계

### 1. 백엔드 API 구현

**필요한 API**:

- `GET /api/roles/:id/menu-permissions` - 권한 그룹의 메뉴 권한 조회
- `POST /api/roles/:id/menu-permissions` - 메뉴 권한 설정
- `GET /api/users/menus` - 현재 사용자가 접근 가능한 메뉴 목록
- `POST /api/menu-permissions/check` - 특정 메뉴에 대한 권한 확인

**구현 파일**:

- `backend-node/src/services/RoleService.ts`
- `backend-node/src/controllers/roleController.ts`
- `backend-node/src/middleware/permissionMiddleware.ts`

### 2. 프론트엔드 UI 개발

**필요한 페이지/컴포넌트**:

1. **권한 그룹 상세 페이지** (`/admin/roles/[id]`)

   - 기본 정보 (이름, 코드, 회사)
   - 멤버 관리 (Dual List Box) ✅ 이미 구현됨
   - **메뉴 권한 설정** (체크박스 그리드) ⬅️ 신규 개발 필요

2. **메뉴 권한 설정 그리드**

   ```
   ┌─────────────────┬────────┬────────┬────────┬────────┬────────┬────────┐
   │ 메뉴            │ 생성   │ 읽기   │ 수정   │ 삭제   │ 실행   │ 내보내기│
   ├─────────────────┼────────┼────────┼────────┼────────┼────────┼────────┤
   │ 대시보드        │   ☐    │   ☑    │   ☐    │   ☐    │   ☐    │   ☐    │
   │ 계약 관리       │   ☑    │   ☑    │   ☑    │   ☐    │   ☐    │   ☑    │
   │ 사용자 관리     │   ☐    │   ☑    │   ☐    │   ☐    │   ☐    │   ☐    │
   └─────────────────┴────────┴────────┴────────┴────────┴────────┴────────┘
   ```

3. **네비게이션 메뉴** (사용자별 권한 필터링)

   - `get_user_menus_with_permissions` 함수 활용
   - 읽기 권한이 있는 메뉴만 표시

4. **버튼/액션 권한 제어**
   - 생성 버튼: `can_create`
   - 수정 버튼: `can_update`
   - 삭제 버튼: `can_delete`
   - 실행 버튼: `can_execute` (플로우, DDL)
   - 내보내기 버튼: `can_export`

**구현 파일**:

- `frontend/components/admin/RoleDetailManagement.tsx` (메뉴 권한 탭 추가)
- `frontend/components/admin/MenuPermissionGrid.tsx` (신규)
- `frontend/lib/api/role.ts` (메뉴 권한 API 추가)
- `frontend/hooks/useMenuPermission.ts` (신규)

### 3. 테스트 시나리오

**시나리오 1: 영업팀 권한 설정**

1. 영업팀 권한 그룹 생성
2. 멤버 추가 (3명)
3. 메뉴 권한 설정:
   - 대시보드: 읽기만
   - 계약 관리: CRUD + 내보내기
   - 플로우 관리: 읽기 + 실행
4. 영업팀 사용자로 로그인하여 검증

**시나리오 2: 동적 화면 생성 및 권한 설정**

1. "배송 현황" 화면 생성
2. 자동으로 메뉴 추가 확인
3. 영업팀에게 읽기 권한 부여
4. 영업팀 사용자 로그인하여 메뉴 표시 확인

---

## 주의사항

### 1. 기존 데이터 호환성

- 기존 `menu_info` 테이블 구조는 그대로 유지
- 새로운 컬럼만 추가되어 기존 데이터에 영향 없음

### 2. 권한 타입 매핑

- `menu_type`이 `numeric`에서 `VARCHAR`로 변경되지 않음 (기존 구조 유지)
- `menu_type = 2`가 동적 생성 메뉴를 의미

### 3. 데이터 마이그레이션 불필요

- 기존 권한 데이터는 그대로 유지
- 새로운 권한 그룹은 수동으로 설정 필요

---

## 검증 체크리스트

- [x] `authority_master.company_code` 컬럼 존재 확인
- [x] `menu_info.screen_code`, `menu_info.menu_code` 컬럼 존재 확인
- [x] `rel_menu_auth.execute_yn`, `rel_menu_auth.export_yn` 컬럼 존재 확인
- [x] 트리거 함수 생성 확인 (`auto_create_menu_for_screen`, `auto_deactivate_menu_for_screen`)
- [x] 권한 체크 함수 생성 확인 (`check_menu_crud_permission`)
- [x] 사용자 메뉴 조회 함수 생성 확인 (`get_user_menus_with_permissions`)
- [x] 권한 요약 뷰 생성 확인 (`v_menu_permission_summary`)
- [ ] 백엔드 API 구현
- [ ] 프론트엔드 UI 구현
- [ ] 테스트 시나리오 실행

---

## 관련 문서

- `docs/메뉴_기반_권한_시스템_가이드.md` - 사용자 가이드
- `docs/권한_체계_가이드.md` - 3단계 권한 체계 개요
- `db/migrations/028_add_company_code_to_authority_master.sql` - 권한 그룹 마이그레이션
- `db/migrations/031_add_menu_auth_columns.sql` - 메뉴 권한 마이그레이션

---

## 문의사항

기술적 문의사항이나 추가 기능 요청은 개발팀에 문의하세요.
