역할 관리
- 대상 사용자 : 최고 관리자(admin), 인사관리자
- 화면의 목적
- 직원에게 부여할 역할(권한)을 관리 및 설정을 위한 페이지
1. 화면
- 상태 필터링
- default : 전체
- 조건 : 전체, 활성, 비활성
- 역할 검색란
- placeholder : 역할
- 검색한 역할이 없을 때
- 리스트 뷰에 안내 문구 제공
- 문구 : 검색 결과가 없어요
- 리스트 뷰에 안내 문구 제공
- 팀/커스텀/시스템 라벨 삭제
- 상태
- 활성 : 변화 없음
- 비활성 : 역할 박스 전체 회색으로 표시
- 역할 권한 보여주기
- default : 닫힌 상태
- 펼치면 해당 역할이 보유한 권한 리스트 제공
- 권한 정리는 7월말해서 8월 초에 적용 예정
- 리스트 순서 : 역할명, 설명, 상태, 기능(관리) 버튼
최고 관리자(admin)인 경우
- [삭제] 버튼 비활성화
- 툴팁 : 최고 관리자는 삭제할 수 없어요.
2. 역할 추가 팝업
- 역할명
- 필수 조건 표시
- placeholder: 역할
- 설명
- placeholder : 설명
- 상태
- default : 활성
- 제공 : 활성, 비활성
- 드롭다운으로 제공
- 권한 선택
- 전체 선택/전체 해제
- 하나의 버튼 제공
- 선택 시 : 전체 선택
- 해제 시 : 전체 선택 해제
- 하나의 버튼 제공
- 전체 선택/전체 해제
- [취소] 버튼
- [취소] 버튼 클릭 시 해당 팝업 닫힘
- [저장] 버튼
- 역할명 입력해야 [저장] 버튼 활성화
- [저장] 버튼 클릭 시, 역할 저장되고 해당 팝업 닫힘
3. 역할 수정 팝업
- [편집] 버튼을 누르면 제공되는 팝업
- 역할명
- 역할 추가 팝업의 역할명과 공통
- 설명
- 역할 추가 팝업의 설명과 공통
- 상태
- 역할 추가 팝업의 상태와 공통
- 권한 선택
- 역할 추가 팝업의 권한 선택과 공통
- [취소] 버튼
- [취소] 버튼 클릭 시 해당 팝업 닫힘
- [저장] 버튼
- [저장] 버튼 활성화 조건
- 역할명 입력
- 수정된 내역 있을 때
- [저장] 버튼 클릭 시, 수정 내역 저장되고 해당 팝업 닫힘
- [저장] 버튼 활성화 조건
최고 관리자(admin)인 경우
- 역할명
- 역할 추가 팝업의 역할명과 공통
- 설명
- 역할 추가 팝업의 설명과 공통
- 상태
- default : 활성
- 수정 불가능
- 권한 선택
- 수정 불가능
- 그외 역할 추가 팝업의 권한 선택과 공통
- [취소] 버튼
- [취소] 버튼 클릭 시 해당 팝업 닫힘
- [저장] 버튼
- [저장] 버튼 활성화 조건
- 역할명 입력
- 수정된 내역 있을 때
- [저장] 버튼 클릭 시, 수정 내역 저장되고 해당 팝업 닫힘
- [저장] 버튼 활성화 조건
- 역할명
4. 정책
- 비활성 역할은 [[common-policy]] 비활성화 규칙을 따른다.
- 역할 삭제 시, 해당 역할을 가지고 있는 경우 삭제 불가
- [삭제] 버튼을 클릭하면 팝업 발생
- 문구 : 해당 역할을 가진 직원이 있어서 삭제할 수 없어요.
- [확인] 버튼 : 해당 팝업만 닫힘
⚠️ 구현 현황 · 하드닝 후보 (2026-08-13)
CODE가 진실이에요. 정책과 코드가 어긋나는 지점을 기록해요.
role.updatePermissions 에 최고 관리자(SUPER_ADMIN) 가드 부재 [기능 수정 후보 — 인증 무결성]
- 문서 기술: §3 최고 관리자 팝업 — 권한 선택 "수정 불가능"(
roles.md:72-73). SUPER_ADMIN 권한 세트는 불변이어야 함. - 실제 구현:
role.updatePermissions(packages/api/src/routers/role.router.ts:244-275)에는role.code === "SUPER_ADMIN"체크가 없어요. 반면 역할 수정/삭제 경로에는 가드가 있어요(role.router.ts:167,:194).ROLE:UPDATE권한만으로 게이트되고 HR_ADMIN 이 role 리소스 전체를 보유하므로(default-permissions.ts), owner 가 아닌 관리자가 SUPER_ADMIN 역할의 권한 행을 비우거나 교체할 수 있어요. - 영향: 최초 owner 는
isSystemAdmin바이패스로 보호되지만(trpc.ts),isSystemAdmin=false인 두 번째 SUPER_ADMIN 보유자는 role→permission 조인으로만 권한을 얻으므로 권한을 스트립당하면 잠겨요. 백엔드 가드가 없고 프론트 비활성화에만 의존해요. (추가로 이 findOne 은organizationId필터 없이id로만 조회해요 — 다중 조직 스코프 공백도 함께 검토 필요.)
삭제 관련 문구가 코드와 다름 / 영문 throw 메시지 [문서 수정]
- 삭제 차단 문구: 문서(
roles.md:88) "해당 역할을 가진 직원이 있어서 삭제할 수 없어요." ↔ 실제(role.router.ts) "이 역할에 배정된 인원이 {n}명 있어 삭제할 수 없습니다. 먼저 배정을 해제하세요."(합쇼체, 문구 다름). role.router.ts:197message: "Cannot delete the SUPER_ADMIN role",updatePermissions의"Role not found"등 영문 throw 메시지 가 남아 있어요 — 프로젝트 규칙(사용자 노출 메시지는 한글 해요체)과 어긋나고, 문서(roles.md:26)는 "최고 관리자는 삭제할 수 없어요." 로 명시해요.