# 12. 권한 기반 페이지 접근 제어 (화이트리스트)

> **대상**: 프론트엔드/백엔드 개발자
> **버전**: 1.0.0
> **최종 수정**: 2026-03-20

---

## 1. 개요

PermissionGate가 **화이트리스트 방식**으로 동작합니다.
메뉴 권한에 등록되지 않은 페이지는 접근이 차단됩니다.

```
메뉴 권한에 있음 + view: true  → 허용
메뉴 권한에 있음 + view: false → 차단 (AccessDenied)
메뉴 권한에 없음              → 차단 (AccessDenied)
```

---

## 2. 왜 화이트리스트?

| 방식 | 동작 | 문제 |
|------|------|------|
| 블랙리스트 (이전) | 권한에 없으면 허용 | 메뉴 미할당 페이지에 URL 직접 접근 가능 |
| **화이트리스트 (현재)** | 권한에 없으면 차단 | 메뉴 등록된 페이지만 접근 가능 |

기존 정책과 일치:
```
테넌트 생성 → 글로벌 메뉴 동기화 → 역할 생성 → 메뉴 권한 설정 → 접근 가능
```

메뉴 권한이 설정되지 않은 페이지는 접근할 수 없는 것이 정상 동작입니다.

---

## 3. 바이패스 경로

메뉴 권한 없이도 항상 접근 가능한 시스템 페이지:

| 경로 | 이유 |
|------|------|
| `/settings/permissions` | 자기 잠금 방지 (권한 설정 페이지) |
| `/settings/account-info` | 내 계정 설정 |
| `/dashboard` | 대시보드 (모든 유저 필수, `startsWith`로 type2~5 포함) |
| `/company-info` | 회사 정보 |
| `/subscription` | 구독 관리 |
| `/dev`, `/test` | 개발 도구 (개발 환경에서만 활성화) |

### 바이패스 추가/관리

파일: `src/contexts/PermissionContext.tsx`

```typescript
const BYPASS_PATHS = [
  '/settings/permissions',
  '/settings/account-info',
  '/dashboard',
  '/company-info',
  '/subscription',
  ...(process.env.NODE_ENV === 'development' ? ['/dev', '/test'] : []),
];
```

- `startsWith` 매칭: `/dashboard` → `/dashboard_type2`, `/dashboard_type3` 등 모두 포함
- 비즈니스 페이지는 바이패스에 추가하지 않음 (권한으로 제어)

---

## 4. 접근 제어 흐름

```
유저가 페이지 접근
  │
  ├─ 권한 로딩 중 → 빈 화면 (로딩)
  │
  ├─ permissionMap 없음 (로딩 실패) → 통과 (안전장치)
  │
  ├─ BYPASS_PATHS 매칭 → 통과
  │
  └─ findMatchingUrl (longest prefix match)
       ├─ 매칭됨 + view: true → 허용
       ├─ 매칭됨 + view: false → AccessDenied
       └─ 매칭 없음 → AccessDenied
```

### findMatchingUrl 동작

```
접근: /accounting/deposits/123
permissionMap: { "/accounting/deposits": { view: true, ... } }

1. 정확히 매칭: /accounting/deposits/123 → 없음
2. Prefix 매칭: /accounting/deposits → 있음! → view 확인
```

상위 경로에 권한이 있으면 하위 경로도 접근 가능합니다.

---

## 5. 프론트엔드 개발자 체크리스트

| 항목 | 설명 |
|------|------|
| 새 페이지 추가 시 | 백엔드 메뉴 등록 필수 (미등록 = 접근 불가) |
| 시스템 페이지 추가 시 | BYPASS_PATHS에 추가 검토 |
| 개발 중 접근 차단 시 | 해당 메뉴의 권한 설정 확인 |
| 테넌트별 접근 제어 | 메뉴 권한으로 제어 (프론트 코드 변경 불필요) |

---

## 6. 백엔드 개발자 참고

| 항목 | 설명 |
|------|------|
| 새 메뉴 추가 시 | 글로벌 메뉴 등록 → 테넌트 동기화 → 역할별 권한 설정 |
| 테넌트별 페이지 차단 | 해당 테넌트에 메뉴 미할당 또는 view: false |
| industry 기반 프리셋 (향후) | 테넌트 생성 시 업종별 메뉴 프리셋 자동 적용 |

---

## 7. 모듈 시스템과의 역할 분담

| 역할 | PermissionGate | 모듈 시스템 (useModules) |
|------|---|---|
| 페이지 접근 차단 | O | X (제거 검토) |
| 메뉴 표시/숨김 | O (백엔드 메뉴 응답) | X |
| 대시보드 섹션 ON/OFF | X | O |
| 대시보드 API 호출 최적화 | X | O |
| JSON 동적 페이지 초석 | X | O |

- **PermissionGate**: 접근 제어 ("누가 어디에 들어갈 수 있는가")
- **모듈 시스템**: 화면 구성 ("들어간 페이지에 뭘 보여줄 것인가")