Skip to content

[Fix/#242] RBAC Role 판정 오류 수정 및 워크스페이스 선택 새로고침 유지 - #247

Merged
jjjsun merged 11 commits into
developfrom
fix/#242
Jun 18, 2026
Merged

[Fix/#242] RBAC Role 판정 오류 수정 및 워크스페이스 선택 새로고침 유지#247
jjjsun merged 11 commits into
developfrom
fix/#242

Conversation

@jjjsun

@jjjsun jjjsun commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

🚨 관련 이슈

Closed #242

✨ 변경사항

  • 🐞 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이 MEMBER인데 ADMIN 전용 UI들이 보이는 문제와
기준 워크스페이스 바꾼뒤에 새로고침하면 이전 워크스페이스로 돌아가는 문제 같이 수정했습니다.
(기존 Issue 내용 + 새로고침후에도 워크스페이스 유지 추가)

1. WorkspaceSetting role 판정 수정

문제

  • useIsAdmin()이 store의 myRole(선택된 워크스페이스 기준)을 사용
  • MEMBER가 /workspace/{id}/settings URL로 직접 접근시, 전택된 워크스페이스가 ADMIN이면 저장/삭제 버튼 노출 및 입력 가능

수정

  • useIsAdmin()제거
  • URL의 workspaceIdgetMyWorkspaces 목록에서 해당 워크스페이스의 myRole 직접 조회
  • myRole === "ADMIN" 일때만 수정 UI 노출

MEMBER 동작

  • 워크스페이스명/설명 입력 disabled
  • 로고 업로드/초기화/사진 버튼 disabled
  • 저장/삭제 버튼 미랜더링

2. 사이드바 메뉴 필터링 role 판정 수정

문제

  • filterNavByRole이 store의 myRole 기준으로만 필터링
  • URL 워크스페이스에서는 MEMBER인데, 선택된 워크스페이스가 ADMIN이면, 멤버 관리/플랜 및 결제 메뉴 노출

수정

  • URL에 workspaceId가 있으면, 해당 워크스페이스의 myRole로 필터링
  • URL에 workspaceId가 없으면(/dashboard, /workspace 등) selectedOrgId 기준 myRole로 필터링 (fallback)
  • 목록에 없으면 store myRole 사용

Role 결정 우선순위
URL workspaceId -> selectedOrgId -> store myRole

3. disabled 커서 스타일 수정

문제

  • Role이 MEMBER일때, WorkspaceSetting의 업로드/초기화/사진 버튼이 클릭불가/흐려짐은 되지만, cursor-not-allowed가 아님.

원인

  • base.cssbutton { cursor: pointer; } 전역 규칙이 우선시 되었음

수정
button:not(:disabled) { cursor: pointer; }
button:disabled { cursor: not-allowed; }

4. 새로고침 시 선택 워크스페이스 유지

문제

  • 워크스페이스 목록에서 다른 워크스페이스 선택시 세션 중에는 현재 대시보드 기준으로 변경됨
  • 그러나, 새로고침하면 예전 워크스페이스로 복원되는 문제 발생.

원인

  • 워크스페이스 선택하면 Zustand store(브라우저 메모리)에만 반영되고 서버에 저장됮 않음
  • saveSelectedWorkspace API는 사이드바 WorkspaceSwitcher에서만 호출
  • 목록 카드 선택시에는 /workspace/{id}/settings 이동시 store만 변경, 서버 저장 없음
  • 새로고침시 MainLayoutgetSavedWorkspace API로 서버에 저장된 예전 워크스페이스 복원

수정

  • WorkspaceManageLayout에서 URL workspaceId 진입시:
  1. store 즉시 반영
  2. saveSelectedWorkspace API 호출로 서버 저장
  3. 저장 성공 후 워크스페이스 관련 데이터 새로고침하여 전체 반영

😅 미완성 작업

N/A

📢 논의 사항 및 참고 사항

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

Summary by CodeRabbit

릴리스 노트

  • 버그 수정

    • 비활성 버튼의 커서 표시를 올바르게 적용했습니다.
    • 비활성 텍스트 영역의 비활성 텍스트 색상이 더 명확해졌습니다.
  • 스타일

    • 비활성 업로드/초기화 버튼의 시각적 피드백(불투명도 등)이 강화되었습니다.
  • 새로운 기능

    • 워크스페이스 선택이 서버와 동기화되어 저장됩니다.
  • 리팩토링

    • 관리자 권한 및 역할 판별 로직이 서버 데이터와 라우트 정보 기반으로 개선되었습니다.

@jjjsun
jjjsun requested review from Seojegyeong and YermIm June 17, 2026 16:44
@jjjsun jjjsun self-assigned this Jun 17, 2026
@jjjsun jjjsun added ✨ Feature 기능 개발 🐞 BugFix Something isn't working labels Jun 17, 2026
@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review Change Stack

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 50 minutes and 49 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ 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.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

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: 391b15e5-6a41-4966-a627-3c3d1461e38d

📥 Commits

Reviewing files that changed from the base of the PR and between b1632a2 and 2657b9d.

📒 Files selected for processing (1)
  • src/components/sidebar/Sidebar.tsx
📝 Walkthrough

Walkthrough

URL의 workspaceId 파라미터를 기준으로 my-workspaces API에서 myRole을 직접 조회하도록 Sidebar, WorkspaceSetting, WorkspaceManageLayout을 수정하고, 전역 스토어 기반의 useIsAdmin 훅을 제거한다. 워크스페이스 전환 시 서버 저장(saveSelectedWorkspace) 및 쿼리 무효화 흐름을 추가하며, 비활성 상태 커서·텍스트 색상 스타일을 정비한다.

Changes

워크스페이스 기반 역할 판별 및 UI 비활성화 처리

Layer / File(s) Summary
WorkspaceManageLayout: 서버 저장 및 myRole 동기화
src/layout/workspace/WorkspaceManageLayout.tsx
워크스페이스 전환 시 useMutation으로 saveSelectedWorkspace를 호출하고, 성공 시 my-workspaces·savedWorkspace 쿼리를 invalidate하며, 조회된 워크스페이스에서 setMyRole도 갱신하고, 실패 시 toast.error를 표시하도록 useEffect 로직을 확장한다.
Sidebar: URL workspaceId 기반 myRole 조회
src/components/sidebar/Sidebar.tsx
useParamsworkspaceId를 읽고 useCoreQuery(getMyWorkspaces)로 목록을 조회해, roleSourceId 매칭 결과를 useMemo로 계산하며, 실패 시 스토어 myRole을 폴백으로 사용한다.
WorkspaceSetting: isAdmin을 API 기반 useMemo로 교체
src/pages/workspace/WorkspaceSetting.tsx
useCoreQuery(my-workspaces)workspaceIduseMemo로 매칭해 myRole === "ADMIN" 여부로 isAdmin을 결정하며, 기존 useIsAdmin() 호출을 제거하고 로고 버튼에 disabled:opacity-40 disabled:hover:bg-surface-100 스타일을 추가한다.
비활성 상태 UI 스타일 일관화
src/styles/base.css, src/components/common/textarea/TextareaField.tsx
button:disabledcursor: not-allowed를 적용하고, TextareaFielddisabled:text-text-muted를 추가해 비활성 요소의 시각적 피드백을 통일한다.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(100, 150, 200, 0.5)
        Note over Sidebar,WorkspaceSetting: 페이지 진입 (URL workspaceId 기준 역할 조회)
    end
    participant Router
    participant Sidebar
    participant WorkspaceSetting
    participant getMyWorkspaces

    Router->>Sidebar: workspaceId (useParams)
    Sidebar->>getMyWorkspaces: useCoreQuery(my-workspaces)
    getMyWorkspaces-->>Sidebar: workspaces[]
    Sidebar->>Sidebar: useMemo → myRole (roleSourceId 매칭, 폴백: store)

    Router->>WorkspaceSetting: workspaceId (useParams)
    WorkspaceSetting->>getMyWorkspaces: useCoreQuery(my-workspaces)
    getMyWorkspaces-->>WorkspaceSetting: workspaces[]
    WorkspaceSetting->>WorkspaceSetting: useMemo → isAdmin (myRole === "ADMIN")
    
    rect rgba(200, 100, 100, 0.5)
        Note over Sidebar: 워크스페이스 전환 시
    end
    Sidebar->>Sidebar: 워크스페이스 선택
    Sidebar->>WorkspaceManageLayout: workspaceId 전달
    WorkspaceManageLayout->>WorkspaceManageLayout: setSelectedOrgId, setMyRole
    WorkspaceManageLayout->>getMyWorkspaces: saveWorkspace (mutation)
    getMyWorkspaces-->>WorkspaceManageLayout: onSuccess
    WorkspaceManageLayout->>WorkspaceManageLayout: invalidateQueries(my-workspaces, savedWorkspace)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • WhereYouAd/WhereYouAd-Frontend#150: WorkspaceManageLayout.tsxsaveSelectedWorkspace API 사용 및 my-workspaces/savedWorkspace 쿼리 무효화 패턴이 본 PR의 변경과 직접 연결됩니다.
  • WhereYouAd/WhereYouAd-Frontend#236: Sidebar.tsxWorkspaceSetting.tsxmyRole/isAdmin 처리 방식 변경이 역할 기반 접근 제어(RBAC) 도입 흐름을 이어받아 수정한 것이어서 코드 레벨에서 관련됩니다.
  • WhereYouAd/WhereYouAd-Frontend#75: WorkspaceSetting에서 workspaceIdgetMyWorkspaces 기반 권한 로직을 사용하는 부분이 직접 연결됩니다.

Suggested labels

📬 API

Suggested reviewers

  • Seojegyeong
  • YermIm
🚥 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 제목이 이슈 #242 해결과 RBAC 역할 판정 오류 수정, 워크스페이스 선택 새로고침 유지라는 핵심 변경사항을 명확하게 반영하고 있습니다.
Description check ✅ Passed PR 설명이 템플릿 구조를 따르고 있으며, 관련 이슈, 변경사항 체크박스, 상세한 작업 내용, 각 버그의 문제점과 수정 방안을 체계적으로 설명하고 있습니다.
Linked Issues check ✅ Passed 변경사항이 이슈 #242의 두 가지 핵심 요구사항을 충족합니다: (1) WorkspaceSetting에서 useIsAdmin() 제거 후 URL 기반 워크스페이스 역할 직접 조회 [#242], (2) 사이드바 필터링이 URL workspaceId 우선 적용 및 fallback 로직 구현 [#242]
Out of Scope Changes check ✅ Passed 모든 변경사항이 이슈 #242의 RBAC 역할 판정 오류 및 워크스페이스 선택 새로고침 문제 해결과 직접적으로 관련되어 있으며, 범위를 벗어난 변경은 없습니다.

✏️ 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 fix/#242

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

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown

📚 Storybook 배포 완료

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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/components/sidebar/Sidebar.tsx`:
- Around line 97-103: The current implementation in the myRole useMemo hook does
not properly handle the fallback when workspaceId matching fails. If workspaceId
exists but no matching workspace is found, it immediately returns
myRoleFromStore without attempting to match using selectedOrgId, which can
expose cached admin permissions from a previous workspace. Modify the logic in
the myRole useMemo hook to first attempt matching with workspaceId if it exists,
then attempt matching with selectedOrgId if the first lookup fails, and only
after both attempts fail should it fall back to myRoleFromStore as the final
fallback.

In `@src/layout/workspace/WorkspaceManageLayout.tsx`:
- Line 28: The error message in the toast.error call contains a Korean spelling
error where "실패헀습니다" should be corrected to "실패했습니다". Fix the typo in the
toast.error message string to ensure the workspace change failure message
displays the correct Korean text to users.
- Around line 17-25: The workspace save mutation is being triggered by changes
to the `workspaces` query data, causing a circular dependency where invalidating
the my-workspaces query after a successful save triggers the effect again and
causes duplicate POST requests. Separate the effect logic so that the
saveSelectedWorkspace mutation is only triggered by changes to the workspaceId
(or whichever identifier controls which workspace to save), not by changes to
the workspaces array itself. This can be achieved by splitting the logic into
two separate effects with distinct dependency arrays, or by restructuring the
mutation trigger to depend only on the specific workspace identifier that needs
to be saved.

In `@src/styles/base.css`:
- Around line 25-27: The global button:disabled rule in base.css applies cursor:
not-allowed which overrides the cursor-wait styling intended for loading buttons
in the Button component. Modify the button:disabled selector to add an exception
for loading state buttons by using a :not() pseudo-class to exclude buttons that
have loading state indicators (such as a loading class or data attribute that
the Button component sets when in loading state). This ensures disabled buttons
in loading state retain their cursor-wait appearance rather than being
overridden by the not-allowed cursor.
🪄 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: 2d6fa78a-ab68-49f4-b434-a880aff2a3c9

📥 Commits

Reviewing files that changed from the base of the PR and between a321aee and fe025ce.

📒 Files selected for processing (6)
  • src/components/common/textarea/TextareaField.tsx
  • src/components/sidebar/Sidebar.tsx
  • src/hooks/auth/useIsAdmin.ts
  • src/layout/workspace/WorkspaceManageLayout.tsx
  • src/pages/workspace/WorkspaceSetting.tsx
  • src/styles/base.css
💤 Files with no reviewable changes (1)
  • src/hooks/auth/useIsAdmin.ts

Comment thread src/components/sidebar/Sidebar.tsx
Comment thread src/layout/workspace/WorkspaceManageLayout.tsx
Comment thread src/layout/workspace/WorkspaceManageLayout.tsx Outdated
Comment thread src/styles/base.css Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/layout/workspace/WorkspaceManageLayout.tsx (1)

3-3: ⚡ Quick win

코딩 가이드라인에 따라 useCoreMutation을 사용해 주세요.

useMutation@tanstack/react-query에서 직접 import하고 있습니다. 가이드라인에서는 src/hooks/customQuery.tsuseCoreMutation을 사용하도록 권장하고 있어요.

♻️ 수정 제안
-import { useMutation, useQueryClient } from "`@tanstack/react-query`";
+import { useQueryClient } from "`@tanstack/react-query`";
 
-import { useCoreQuery } from "`@/hooks/customQuery`";
+import { useCoreQuery, useCoreMutation } from "`@/hooks/customQuery`";

그리고 mutation 선언 부분:

-  const { mutate: saveWorkspace } = useMutation({
+  const { mutate: saveWorkspace } = useCoreMutation({
     mutationFn: (orgId: number) => saveSelectedWorkspace(orgId),
🤖 Prompt for 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.

In `@src/layout/workspace/WorkspaceManageLayout.tsx` at line 3, The import
statement in WorkspaceManageLayout.tsx is directly importing useMutation from
`@tanstack/react-query`, but the coding guidelines require using useCoreMutation
from src/hooks/customQuery.ts instead. Remove useMutation from the
`@tanstack/react-query` import and add a new import for useCoreMutation from
src/hooks/customQuery.ts, then replace all usages of useMutation with
useCoreMutation throughout the file.

Source: Coding guidelines

🤖 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.

Nitpick comments:
In `@src/layout/workspace/WorkspaceManageLayout.tsx`:
- Line 3: The import statement in WorkspaceManageLayout.tsx is directly
importing useMutation from `@tanstack/react-query`, but the coding guidelines
require using useCoreMutation from src/hooks/customQuery.ts instead. Remove
useMutation from the `@tanstack/react-query` import and add a new import for
useCoreMutation from src/hooks/customQuery.ts, then replace all usages of
useMutation with useCoreMutation throughout the file.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1bce6cc7-0a51-4458-bd0f-c739b6c4a64f

📥 Commits

Reviewing files that changed from the base of the PR and between fe025ce and b1632a2.

📒 Files selected for processing (3)
  • src/components/sidebar/Sidebar.tsx
  • src/layout/workspace/WorkspaceManageLayout.tsx
  • src/styles/base.css
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/styles/base.css
  • src/components/sidebar/Sidebar.tsx

@Seojegyeong Seojegyeong left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

P4: 확인했습니다!

@YermIm YermIm left a comment

Copy link
Copy Markdown
Collaborator

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 18f490e into develop Jun 18, 2026
3 checks passed
@jjjsun
jjjsun deleted the fix/#242 branch June 18, 2026 11:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐞 BugFix Something isn't working ✨ Feature 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐞 [BugFix] MEMBER 역할 기반 UI 제한 미적용 버그

3 participants