Skip to content

feat: migrate SDK to use SetProjectMemberRole and RemoveProjectMember RPCs#1508

Open
whoAbhishekSah wants to merge 3 commits intomainfrom
feat/sdk-project-member-management
Open

feat: migrate SDK to use SetProjectMemberRole and RemoveProjectMember RPCs#1508
whoAbhishekSah wants to merge 3 commits intomainfrom
feat/sdk-project-member-management

Conversation

@whoAbhishekSah
Copy link
Copy Markdown
Member

@whoAbhishekSah whoAbhishekSah commented Apr 3, 2026

Summary

Replace policy-based project member management with the new atomic RPCs across React SDK and Admin SDK.

Before: SDK manipulated policies directly (createPolicyForProject, listPolicies → deletePolicy x N → createPolicy)
After: SDK uses SetProjectMemberRole and RemoveProjectMember

Inconsistency found and fixed

The "Add member" flow was passing role names (e.g., app_project_viewer) as the roleId, while the "Change role" dropdown was passing role UUIDs from the fetched roles list. The backend SetProjectMemberRole expects a UUID.

Fix: All flows now fetch project-scoped roles via listRoles and resolve the role UUID before calling the RPC. This makes add member, role change, and service account assignment all consistent.

Net result: simpler code, no client-side policy orchestration.

Closes #1462

Test plan

  • Verify add member to project (user + team)
  • Verify role change on project member
  • Verify remove member from project
  • Verify service account project assignment
  • Verify manage service user projects toggle
  • Verify admin add/remove/assign-role flows
  • No policy RPCs in network tab

🤖 Generated with Claude Code

… RPCs

Replace policy-based member management (createPolicyForProject,
listPolicies, deletePolicy, createPolicy) with the new atomic RPCs.

React SDK:
- project-members.tsx: addMember/addTeam use SetProjectMemberRole
- project-member-columns.tsx: updateRole uses SetProjectMemberRole
- remove-project-member-dialog.tsx: uses RemoveProjectMember
- add-service-account-dialog.tsx: uses SetProjectMemberRole
- manage-service-user-projects-dialog.tsx: uses both RPCs

Admin SDK:
- use-add-project-members.tsx: uses SetProjectMemberRole
- remove-member.tsx: uses RemoveProjectMember
- assign-role.tsx: uses SetProjectMemberRole

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 3, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
frontier Ready Ready Preview, Comment Apr 3, 2026 6:55am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 3, 2026

Warning

Rate limit exceeded

@whoAbhishekSah has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 1 minutes and 34 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 1 minutes and 34 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, 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 have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 574d4249-f707-4da1-9b03-c9851a6b7028

📥 Commits

Reviewing files that changed from the base of the PR and between ccc1d41 and 6e6778f.

📒 Files selected for processing (1)
  • web/sdk/react/views/projects/details/project-members.tsx
📝 Walkthrough

Walkthrough

This PR implements the migration from policy-based member management to role-based member management across multiple SDK files. It replaces client-side policy CRUD operations (listPolicies, deletePolicy, createPolicy) with direct role-assignment mutations (setProjectMemberRole, removeProjectMember) for projects and service users. Role IDs are resolved via listRoles queries, and the proton dependency is updated.

Changes

Cohort / File(s) Summary
Project Member Role Management
web/sdk/admin/views/organizations/details/projects/members/assign-role.tsx, web/sdk/react/views/projects/details/project-member-columns.tsx, web/sdk/react/views/projects/details/project-members.tsx
Replaced policy list/delete/create workflows with setProjectMemberRole mutation; added role ID resolution via listRoles query and gated mutations on role availability; updated async flow from parallel Promise.all to sequential await calls.
Project Member Removal
web/sdk/admin/views/organizations/details/projects/members/remove-member.tsx, web/sdk/react/views/projects/details/remove-project-member-dialog.tsx
Replaced policy enumeration and deletion with removeProjectMember mutation; removed policy-listing query logic; updated RemoveProjectMemberDialogProps to accept optional memberType parameter.
Project Member Addition Hook
web/sdk/admin/views/organizations/details/projects/use-add-project-members.tsx
Replaced createPolicy with setProjectMemberRole mutation; added listRoles query to resolve default viewer role ID; gated member addition on role availability.
Service User/API Key Project Management
web/sdk/react/views/api-keys/details/manage-service-user-projects-dialog.tsx, web/sdk/react/views/api-keys/list/add-service-account-dialog.tsx
Replaced policy creation/deletion with setProjectMemberRole and removeProjectMember mutations; added owner role ID resolution via listRoles query; updated error handling for missing role IDs.
Dependencies
web/sdk/package.json
Updated @raystack/proton dependency from 0.1.0-fcb776fb2962a9a0378ea4216177b7c2686efc15 to 0.1.0-aed9df8ec21ade1d1a56e6fe041cc29284b8e7ca.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~28 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • rsbh
  • rohilsurana
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR successfully migrates SDK project member management from policy-based RPCs to role-based RPCs (SetProjectMemberRole and RemoveProjectMember) as required in issue #1462.
Out of Scope Changes check ✅ Passed All code changes are directly aligned with the PR objectives of migrating policy-based member management to role-based RPCs; no unrelated changes detected.

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


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.

…ions

Fetch project-scoped roles via listRoles and resolve the role UUID
before calling SetProjectMemberRole. Consistent with the role change
dropdown which already uses UUIDs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
AddMemberDropdown is a separate child component that needs the
roles array to resolve the viewer role UUID.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@whoAbhishekSah
Copy link
Copy Markdown
Member Author

Manual Testing — PASS

Tested locally with client demo app on clean Frontier + SpiceDB.

Flow Principal Result
Add member to project User PASS
Add member to project Group PASS
Change role on project member User PASS
Remove member from project User PASS
Service account project assignment Service User PASS
Manage service user projects toggle Service User PASS

All flows use SetProjectMemberRole / RemoveProjectMember RPCs. No policy RPCs (createPolicyForProject, listPolicies, deletePolicy) in network tab.

@whoAbhishekSah whoAbhishekSah requested review from rohanchkrabrty and rsbh and removed request for rohanchkrabrty April 3, 2026 07:03
Copy link
Copy Markdown
Contributor

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
web/sdk/admin/views/organizations/details/projects/members/assign-role.tsx (1)

88-107: ⚠️ Potential issue | 🔴 Critical

setProjectMemberRole only preserves the last role in this loop.

This RPC replaces the member’s project role set; it does not append to it. Iterating assignedRolesArr here means each call overwrites the previous one, so only the last role survives while onRoleUpdate still reports every selected role locally.

Suggested fix
   const onSubmit = async (data: FormData) => {
     try {
       const assignedRolesArr = Array.from(data.roleIds);
+      if (assignedRolesArr.length !== 1) {
+        throw new Error("Project members can only have one direct project role");
+      }

-      for (const roleId of assignedRolesArr) {
-        await setProjectMemberRole(
-          create(SetProjectMemberRoleRequestSchema, {
-            projectId,
-            principalId: user?.id || "",
-            principalType: "app/user",
-            roleId,
-          }),
-        );
-      }
+      await setProjectMemberRole(
+        create(SetProjectMemberRoleRequestSchema, {
+          projectId,
+          principalId: user?.id || "",
+          principalType: "app/user",
+          roleId: assignedRolesArr[0],
+        }),
+      );
web/sdk/react/views/projects/details/remove-project-member-dialog.tsx (1)

20-25: ⚠️ Potential issue | 🟠 Major

Make memberType required instead of defaulting to 'user'.

This makes missing caller updates look valid. web/sdk/react/views/projects/details/project-detail-page.tsx:255-260 still opens the dialog without memberType, so removing a team member will continue to send app/user and fail. Making the prop required forces the remaining call sites to pass the correct principal type.

Suggested fix
 export interface RemoveProjectMemberDialogProps {
     open: boolean;
     onOpenChange?: (value: boolean) => void;
     projectId: string;
     memberId: string;
-    memberType?: 'user' | 'group';
+    memberType: 'user' | 'group';
 }
@@
 export const RemoveProjectMemberDialog = ({
     open,
     onOpenChange,
     projectId,
     memberId,
-    memberType = 'user'
+    memberType
 }: RemoveProjectMemberDialogProps) => {

Also applies to: 32-33, 52-57


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 96b266ff-0062-46b1-bc94-f27ec9d10147

📥 Commits

Reviewing files that changed from the base of the PR and between 1b73eaf and ccc1d41.

⛔ Files ignored due to path filters (1)
  • web/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • web/sdk/admin/views/organizations/details/projects/members/assign-role.tsx
  • web/sdk/admin/views/organizations/details/projects/members/remove-member.tsx
  • web/sdk/admin/views/organizations/details/projects/use-add-project-members.tsx
  • web/sdk/package.json
  • web/sdk/react/views/api-keys/details/manage-service-user-projects-dialog.tsx
  • web/sdk/react/views/api-keys/list/add-service-account-dialog.tsx
  • web/sdk/react/views/projects/details/project-member-columns.tsx
  • web/sdk/react/views/projects/details/project-members.tsx
  • web/sdk/react/views/projects/details/remove-project-member-dialog.tsx

Comment on lines +166 to 169
const ownerRoleId = useMemo(
() => rolesData?.roles?.find(r => r.name === PERMISSIONS.RoleProjectOwner)?.id ?? '',
[rolesData]
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
sed -n '157,224p' web/sdk/react/views/api-keys/details/manage-service-user-projects-dialog.tsx

Repository: raystack/frontier

Length of output: 2157


onAccessChange closes over a stale ownerRoleId.

The callback uses ownerRoleId at line 200 and line 206, but ownerRoleId is missing from the dependency array at line 223. When the dialog opens and listRoles populates the role ID, onAccessChange still holds the stale empty string from initial render, causing "Project owner role not found" errors on subsequent project access changes.

Suggested fix
-    [serviceUserId, setProjectMemberRole, removeProjectMember]
+    [serviceUserId, ownerRoleId, setProjectMemberRole, removeProjectMember]

Comment on lines +111 to +114
const ownerRoleId = useMemo(
() => rolesData?.roles?.find(r => r.name === PERMISSIONS.RoleProjectOwner)?.id ?? '',
[rolesData]
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
sed -n '111,209p' web/sdk/react/views/api-keys/list/add-service-account-dialog.tsx

Repository: raystack/frontier

Length of output: 3022


Validate and include ownerRoleId in the useCallback dependency array.

The validation of ownerRoleId occurs after the service user is created (line ~147), which can leave an orphaned user if the roles query is slow or fails. Additionally, the dependency array (lines 201-209) omits ownerRoleId despite using it in the handler, causing the callback to close over the initial empty string even after listRoles resolves.

Suggested fix
   const onSubmit = useCallback(
     async (data: FormData) => {
       if (!orgId) return;

       try {
+        if (!ownerRoleId) {
+          throw new Error('Project owner role not found');
+        }
+
         const serviceUserResponse = await createServiceUser(
           create(CreateServiceUserRequestSchema, {
             orgId,
             body: create(ServiceUserRequestBodySchema, {
               title: data.title
             })
           })
         );

         const serviceUserId = serviceUserResponse.serviceuser?.id;
         if (!serviceUserId) return;

-        if (!ownerRoleId) throw new Error('Project owner role not found');
         await setProjectMemberRole(
           create(SetProjectMemberRoleRequestSchema, {
             projectId: data.project_id,
             principalId: serviceUserId,
             principalType: PERMISSIONS.ServiceUserPrincipal,
             roleId: ownerRoleId
           })
         );
@@
     [
       orgId,
+      ownerRoleId,
       createServiceUser,
       setProjectMemberRole,
       createServiceUserToken,
       queryClient,
       transport,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate React SDK and Admin SDK to use new role-based RPCs

1 participant