Skip to content

[Feature/#232] 워크스페이스 역할 기반 접근 제어(RBAC) 도입#236

Merged
jjjsun merged 8 commits into
developfrom
feature/#232
May 27, 2026
Merged

[Feature/#232] 워크스페이스 역할 기반 접근 제어(RBAC) 도입#236
jjjsun merged 8 commits into
developfrom
feature/#232

Conversation

@jjjsun
Copy link
Copy Markdown
Collaborator

@jjjsun jjjsun commented May 26, 2026

🚨 관련 이슈

Closed #232

✨ 변경사항

  • 🐞 BugFix Something isn't working
  • 💻 CrossBrowsing Browser compatibility
  • 🌏 Deploy Deploy
  • 🎨 Design Markup & styling
  • 📃 Docs Documentation writing and editing (README.md, etc.)
  • ✨ Feature Feature
  • 🔨 Refactor Code refactoring
  • ⚙️ Setting Development environment setup
  • ✅ Test Test related (storybook, jest, etc.)

✏️ 작업 내용

워크스페이스 Role에 따라 접근 가능한 라우트/메뉴/UI를 제한하는 역할 기반 접근 제어를 도입했습니다. (ADMIN/MEMBER)
Role-Based Access Control

  • ADMIN 역할 -> 멤버 관리, 플랜/결제, 설정 편집 가능
  • MEMBER 역할 -> 대시보드, 캠페인만 접근 가능

1. 전역 역할 상태 관리

  • useWorkspaceStoremyRole, setMyRole 추가
  • MainLayout 초기 로드 시 및 WorkspaceSwitcher 전환 시 현재 워크스페이스의 myRole 자동 갱신
  • 조직마다 역할이 다를 수 있기때문에 워크스페이스 전환시에 권한 상태도 같이 갱신되도록 구현

2. RoleGuard 컴포넌트 구현

  • 기존 AuthGuard와 동일한 패턴으로 구현
  • myRole === null (초기화 중) 이면 랜더링 보류, 허용되지 않은 역할이면 /dashboard로 리다이렉트

3. ADMIN 전용 라우트 접근 제한

  • 멤버 관리, 플랜 및 결제 라우트에 RoleGuard 적용
  • URL 직접 입력시에도 동일하게 차단됨

4. 사이드바 메뉴 필터링

  • INavItem 타입에 requiredRole?: TMemberRole 필드 추가
  • 멤버 관리, 플랜 및 결제 항목에 requiredRole: "ADMIN" 마킹
  • Sidebar에서 myRole 기준으로 랜더링 전 필터링 처리 실행

5. 페이지 내 UI 읽기전용 처리

  • useIsAdmin() 훅 추가
  • WorkspaceSetting페이지에서 Role이 MEMBER일 경우에는 입력 필드 비활성화처리하고, 저장/삭제 버튼은 숨기 처리 구현

😅 미완성 작업

N/A

📢 논의 사항 및 참고 사항

멤버관리, 플랜 및 결제는 MEMBER에서 접근이 불가능 하게 처리하였고,
WorkspaceSetting(워크스페이스 정보)에서는 접근은 가능하지만, 읽기전용으로 보이도록 설정했습니다. 추후에 완전 차단이 필요하다면 라우트에 RoleGuard 추가하면 됩니다.

💬 리뷰어 가이드 (P-Rules)
P1: 필수 반영 (Critical) - 버그 가능성, 컨벤션 위반. 해결 전 머지 불가.
P2: 적극 권장 (Recommended) - 더 나은 대안 제시. 가급적 반영 권장.
P3: 제안 (Suggestion) - 아이디어 공유. 반영 여부는 드라이버 자율.
P4: 단순 확인/칭찬 (Nit) - 사소한 오타, 칭찬 등 피드백.

Summary by CodeRabbit

  • New Features
    • 사용자 역할 기반 메뉴 필터링 추가 — 사이드바에서 현재 역할에 맞는 항목만 표시됩니다.
    • 역할 기반 접근 제어 적용 — 멤버 관리·청구 관리 등 관리자 전용 페이지 접근이 제한됩니다.
    • 워크스페이스 전환 시 역할 자동 동기화 — 선택된 워크스페이스에 맞춰 역할 상태가 업데이트됩니다.
    • 관리자 감지 훅 추가 — UI 요소(설정/삭제/업로드 등) 노출이 역할에 따라 제어됩니다.
    • 일부 워크스페이스 메뉴 항목에 ADMIN 요구 역할 지정.

Review Change Stack

@jjjsun jjjsun requested review from Seojegyeong and YermIm May 26, 2026 09:42
@jjjsun jjjsun self-assigned this May 26, 2026
@jjjsun jjjsun added the ✨ Feature 기능 개발 label May 26, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

Warning

Review limit reached

@jjjsun, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 49 minutes and 48 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 858131bb-e72c-4e84-84cc-643572fe0c88

📥 Commits

Reviewing files that changed from the base of the PR and between b227a8d and 0beda2f.

📒 Files selected for processing (1)
  • src/routes/RoleGuard.tsx
📝 Walkthrough

Walkthrough

워크스페이스 역할(myRole)을 중앙 상태로 추가하고, 사이드바 필터링, RoleGuard 라우트 보호, 워크스페이스 전환 시 역할 동기화, WorkspaceSetting UI 제어를 통해 ADMIN 전용 기능을 제한합니다.

Changes

워크스페이스 역할 기반 인가 시스템

Layer / File(s) Summary
역할 상태 관리 기반 마련
src/store/useWorkspaceStore.ts, src/types/navigation/navItem.ts
Zustand에 myRole: TMemberRole | nullsetMyRole 추가. 네비게이션 타입 INavItemrequiredRole?: TMemberRole 필드 추가.
네비게이션 역할 기반 필터링 및 설정
src/components/sidebar/Sidebar.tsx, src/constants/sidebarNav.ts
Sidebar에 재귀적 filterNavByRole 추가하여 메뉴 항목을 requiredRole과 비교해 필터링. sidebarNav에서 일부 하위 항목에 requiredRole: "ADMIN" 지정.
라우트 접근 제어 및 RoleGuard 컴포넌트
src/routes/RoleGuard.tsx, src/routes/MainRoutes.tsx
신규 RoleGuard 추가: URL의 workspaceId 또는 전역 myRole을 검사해 allowedRoles 미포함 시 /dashboard로 리다이렉트. MainRoutes에서 관리자 전용 라우트를 RoleGuard로 래핑.
워크스페이스 전환 시 역할 동기화
src/components/sidebar/WorkspaceSwitcher.tsx, src/layout/main/MainLayout.tsx
Workspace 선택/초기화 흐름에 setMyRole 호출을 추가해 워크스페이스 전환 시 역할을 스토어와 동기화.
관리자 전용 UI 제어 및 유틸리티 훅
src/hooks/auth/useIsAdmin.ts, src/pages/workspace/WorkspaceSetting.tsx
useIsAdmin 훅 추가. WorkspaceSetting에서 관리자가 아닐 경우 입력 필드 disabled 처리 및 저장/삭제 버튼 영역을 렌더하지 않도록 변경.

Sequence Diagram

sequenceDiagram
  participant User
  participant WS as WorkspaceSwitcher
  participant Store as useWorkspaceStore
  participant Nav as Sidebar
  participant Guard as RoleGuard
  participant Page as AdminPage

  User->>WS: 워크스페이스 선택
  WS->>Store: setSelectedOrgId(orgId)
  WS->>Store: setMyRole(workspace.myRole)

  Store->>Nav: myRole 변경 알림
  Nav->>Nav: filterNavByRole 적용
  Nav-->>User: 역할 기반 메뉴 렌더링

  User->>Guard: 관리자 전용 경로 접근 시도
  Guard->>Store: myRole 확인
  alt myRole in allowedRoles
    Guard->>Page: children 렌더
    Page-->>User: 관리자 페이지 표시
  else
    Guard-->>User: /dashboard로 리다이렉트
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

🔨 Refactor

Suggested reviewers

  • YermIm

간단 리뷰 포인트 (구조·안정성·성능·버그 중심)

  • 상태/초기화: myRole 초기값이 null인 것은 적절. 다만 워크스페이스 로드 실패나 선택 불일치 시 명시적 setMyRole(null) 처리가 있는지 확인하세요(경계 상태 누락 방지).
  • 네비게이션 필터: myRole이 null일 때 항목을 숨기는 현재 동작은 보안상 옳습니다. 트리 크기 증가 시 useMemo 재계산 비용을 주시하세요.
  • RoleGuard: workspaceId 기반 검증 시 쿼리 로딩 중 null 반환으로 렌더 보류하는 방식은 안전합니다. 다만 리다이렉트 사유를 사용자에게 알리는 UX(토스트 등) 고려 권장.
  • 동기화 일관성: WorkspaceSwitcher과 MainLayout 모두에서 setMyRole를 호출하는데, 중복 로직을 유틸로 추출하면 유지보수성이 좋아집니다.
  • UI 제어: WorkspaceSetting에서 비관리자에게 입력을 비활성화하고 버튼을 숨기는 다층 방어 적용은 적절. 읽기 전용 노출 대신 완전 숨김이 필요한 경우 요구사항에 따라 조정하세요.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 명확하게 주요 변경사항(역할 기반 접근 제어 도입)을 반영하고 있으며, 이슈 번호(#232)도 포함되어 있다.
Description check ✅ Passed PR 설명에서 관련 이슈, 변경사항 체크, 작업 내용, 미완성 작업, 논의 사항을 모두 포함하고 있으며, 템플릿 구조를 잘 따르고 있다.
Linked Issues check ✅ Passed PR의 모든 변경사항이 #232의 요구사항을 충족한다. ADMIN/MEMBER 권한 정책 정의, 전역 역할 상태 관리, RoleGuard 구현, 라우트 제한, 메뉴 필터링, UI 처리 등 모든 체크리스트 항목이 구현되어 있다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #232에서 명시한 역할 기반 접근 제어 도입 범위 내에 있으며, 범위 밖의 변경사항은 없다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/#232

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

📚 Storybook 배포 완료

항목 링크
📖 Storybook https://69a147b60a56365d9e2185ef-vmozwsjgdn.chromatic.com/
🔍 Chromatic https://www.chromatic.com/build?appId=69a147b60a56365d9e2185ef&number=313

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/routes/RoleGuard.tsx`:
- Around line 17-27: RoleGuard currently uses the global myRole from
useWorkspaceStore to decide access, which can be wrong when URL workspaceId
differs; change RoleGuard to read the current workspaceId via useParams() and
fetch the role for that workspace (e.g., lookup in useWorkspaceStore by
workspaceId or call a selector like getRoleByWorkspaceId(workspaceId)) and then
compare that workspace-scoped role against allowedRoles before rendering or
Navigate; keep the existing null-loading guard but base it on the
workspace-specific role or an explicit lookup result rather than the global
myRole.

In `@src/store/useWorkspaceStore.ts`:
- Around line 7-9: The store defines myRole as TMemberRole | null but setMyRole
only accepts TMemberRole, which prevents clearing the role and can leave stale
state; update the setMyRole signature to accept TMemberRole | null (e.g.,
setMyRole: (role: TMemberRole | null) => void), then update any callers of
setMyRole to pass null when clearing/resetting the role and adjust types where
the setter is used to handle null values accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4844416a-6762-4069-b4dc-c24abb198f51

📥 Commits

Reviewing files that changed from the base of the PR and between d4d7b94 and b1ef77d.

📒 Files selected for processing (10)
  • src/components/sidebar/Sidebar.tsx
  • src/components/sidebar/WorkspaceSwitcher.tsx
  • src/constants/sidebarNav.ts
  • src/hooks/auth/useIsAdmin.ts
  • src/layout/main/MainLayout.tsx
  • src/pages/workspace/WorkspaceSetting.tsx
  • src/routes/MainRoutes.tsx
  • src/routes/RoleGuard.tsx
  • src/store/useWorkspaceStore.ts
  • src/types/navigation/navItem.ts

Comment thread src/routes/RoleGuard.tsx
Comment thread src/store/useWorkspaceStore.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/routes/RoleGuard.tsx`:
- Around line 22-29: The current guard returns null whenever workspaces is falsy
which hides the UI on API failures; update the RoleGuard logic that calls
useCoreQuery(["my-workspaces"], getMyWorkspaces) to inspect the query status
flags (e.g., isPending / isError) in addition to the data (workspaces) — when
isPending show a loading state, when isError perform an explicit redirect or
render an error UI, and only defer rendering (return null) while loading but not
on error; adjust the branches around workspaceId and workspaces to use these
flags so failures are handled deterministically.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c24361eb-ab4f-4f65-ae76-7bf3ec420430

📥 Commits

Reviewing files that changed from the base of the PR and between b1ef77d and b227a8d.

📒 Files selected for processing (2)
  • src/routes/RoleGuard.tsx
  • src/store/useWorkspaceStore.ts

Comment thread src/routes/RoleGuard.tsx Outdated
Copy link
Copy Markdown
Collaborator

@Seojegyeong Seojegyeong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P4: 확인했습니다. 고생하셨습니다!

@jjjsun jjjsun merged commit a321aee into develop May 27, 2026
1 check passed
@jjjsun jjjsun deleted the feature/#232 branch May 27, 2026 06:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨ [Feature] 워크스페이스 역할 기반 화면/라우트 인가 처리

2 participants