Skip to content

Add management operations for agents, groups, roles and users - #130

Merged
brionmario merged 1 commit into
thunder-id:mainfrom
brionmario:feat-cp-dp-separation
Oct 27, 2026
Merged

brionmario merged 1 commit into
thunder-id:mainfrom
brionmario:feat-cp-dp-separation

Conversation

@brionmario

@brionmario brionmario commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Purpose

Adds agent, group, role and user management to the JavaScript SDKs: the management operations, the hooks and composables over them, and admin components for each. Roles carry their permissions, and the SDKs can read the permissions an access token grants to decide what to show.

Approach

  • Endpoints: endpoints.groups, endpoints.roles and endpoints.agentTypes join the existing management keys. A collection URL resolves from the call's url, then endpoints.<key>, then {baseUrl}/{collection}.
  • @thunderid/javascript:
    • Group and role APIs: list, get, create, update and delete, plus group members and role assignments.
    • Agent groups, agent roles, agent types and user groups.
    • getTokenPermissions() and hasPermission(): read the permissions an access token grants and match them the way the server does (system:user covers system:user:view).
    • createResourceInvalidator moves here from @thunderid/react. resolveManagedIdentityName and toManagementErrorMessage are new.
  • @thunderid/react and @thunderid/vue:
    • Query and mutation hooks (composables in Vue) for every new resource, and useGrantedPermissions().
    • Admin components for users, groups, roles and agents (list, create, details, members, permissions and assignments), each with a Base* variant.
    • Search and filters: UserList and AgentList search on the server (users by username or email, agents by name), and RoleAssignments filters by assignee type. The server matches one attribute exactly, so the search applies on submit. getAgents gains filter, and toEqualityFilter builds the expression. Groups, roles and group members have no server filter, so they stay unfiltered.
    • Render props on every admin component, the same pattern as SignIn: a children function in React and the default scoped slot in Vue receive the data, loading and error state, and handlers, so the UI can come from any library. A list hands over its rows, default columns, limit, offset, totalResults, onPageChange and onSelect, enough to drive a third-party data grid with server-side paging; a form hands over values, handleInputChange, handleSubmit and isValid.
    • A DataTable primitive and an Attribution component.
  • @thunderid/nextjs: the admin components and hooks, with management calls relayed through server actions (managementRequestAction, getGrantedPermissionsAction), so the browser never calls the management API or holds the token.
  • @thunderid/nuxt: a management module option that auto-imports the admin components and composables, and a /api/auth/management route that relays management calls.
  • @thunderid/node and @thunderid/express: client.management(sessionId) and managementFromRequest(req) bind management operations to a session. The session's token stays on the server and is read on every call.
  • @thunderid/react-router and @thunderid/tanstack-router: admin routes (createAdminRoutes, AdminPage).
  • i18n: the admin strings are translated in every locale.
  • Layout: the code is grouped by function instead of by kind. Components are in auth/ (with buttons/, flow/ and guards/), account/, admin/ and common/, and primitives/ is unchanged. APIs, hooks, composables and Next.js server actions are in auth/, account/ and management/. Every package exports the same names as before.

Related Issues

Related PRs

Playgrounds

Every playground exercises the new APIs:

  • capability checks
  • admin, DataTable and Attribution stories with sample data and live variants
  • hooks and composables views
  • a Custom rendering group: UserList as an MUI DataGrid, GroupCreate as an MUI form and UserDetails as an MUI card in React and Next.js, and the same with PrimeVue in Vue and Nuxt (playground-only dependencies)
  • a card showing where each management collection resolves

They read THUNDERID_ENDPOINT_<KEY> (with VITE_ or NUXT_PUBLIC_ where the framework needs it) to override one management collection's URL. The server playgrounds show management calls going through the server. The SDK gaps the playgrounds hit are listed in each README.

Screenshots

From the React playground's component explorer, with sample data.

Admin components, including the server-side search and the assignee type filter:

UserList UserList, searching by email
UserList UserList, searching by email
UserDetails UserCreate
UserDetails UserCreate
GroupMembers RoleAssignments, filtered to groups
GroupMembers RoleAssignments, filtered to groups

Custom rendering through render props, drawn with MUI. Each admin component has a Custom (MUI) story; the Code tab shows the render function:

UserList as an MUI DataGrid, with search The render function
UserList as an MUI DataGrid, with search The render function
GroupCreate as an MUI form UserDetails as an MUI card
GroupCreate as an MUI form UserDetails as an MUI card
GroupMembers with an MUI picker RoleAssignments with type chips
GroupMembers with an MUI picker RoleAssignments with type chips
RolePermissions as MUI cards AgentCreate as an MUI form
RolePermissions as MUI cards AgentCreate as an MUI form

Vue, through the default scoped slot with PrimeVue:

UserList as a PrimeVue DataTable GroupCreate UserDetails
UserList as a PrimeVue DataTable GroupCreate UserDetails

Verified locally:

  • pnpm build (18/18) and pnpm test across the packages (2,233 passed, 3 skipped).
  • Typecheck, lint and format:check for all seven playgrounds, and builds for React, Vue, Next.js and Nuxt.
  • Admin stories rendered in headless Chromium without errors.
  • Render props: React (459 tests) and Vue (346 passed, 3 skipped) suites include the new render props tests; the MUI and PrimeVue stories rendered headlessly in React, Next.js, Vue and Nuxt, with the grid's paging driving onPageChange.
  • The live management checks have only run signed out so far.

@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

🔀 Cross-SDK feature parity, ports raised

This pull request is labelled parity/prs-raised, so the capability it introduces is expected in the other ThunderID SDKs as well.

Ports (DO NOT EDIT)

  • thunder-id/ios-sdks, iOS => #33
  • thunder-id/android-sdks, Android => #41
  • thunder-id/flutter-sdks, Flutter => #51

3 of 3 sibling SDKs accounted for.

Every sibling SDK is accounted for.

The contract is in the SDK development specification.

@brionmario
brionmario force-pushed the feat-cp-dp-separation branch from 5bb8d0d to 51f46d4 Compare October 22, 2026 11:33
@brionmario brionmario changed the title Add groups, roles and permissions management, and let management APIs live on a separate control plane Add groups, roles and permissions management Oct 22, 2026
@brionmario brionmario changed the title Add groups, roles and permissions management Add management operations for agents, groups, roles and users Oct 26, 2026
@brionmario
brionmario force-pushed the feat-cp-dp-separation branch from b0ab054 to 176bef6 Compare October 26, 2026 11:53
@brionmario brionmario added the parity/prs-raised Ports exist in the other SDKs, or are recorded as not applying there label Oct 26, 2026
@brionmario
brionmario force-pushed the feat-cp-dp-separation branch from 176bef6 to 51d9190 Compare October 26, 2026 12:29
Adds group and role management to the JavaScript SDKs alongside the
existing user and agent operations: list, get, create, update and
delete, group members and role assignments, agent and user groups and
roles, and agent types. endpoints.groups, endpoints.roles and
endpoints.agentTypes join the management endpoint keys.

getTokenPermissions() and hasPermission() read the permissions an access
token grants and match them the way the server does.

React and Vue gain query and mutation hooks and composables for every
resource, useGrantedPermissions(), and admin components for users,
groups, roles and agents (list, create, details, members, permissions
and assignments), each with a Base variant and render props that let
any UI library draw them. UserList and AgentList search on the server,
and RoleAssignments filters by assignee type. A DataTable primitive and
an Attribution component are added.

Next.js relays management calls through server actions, Nuxt adds a
management module option and relay route, Node and Express bind
management operations to a session, and the router packages add admin
routes. The admin strings are translated in every locale.

The code is now grouped by function instead of by kind: components
into auth (with buttons, flow and guards), account, admin and common;
APIs, hooks, composables and server actions into auth, account and
management. Every package exports the same names as before.

The playgrounds exercise the new APIs, including custom rendering with
MUI and PrimeVue.

Refs thunder-id/thunderid#5162

Signed-off-by: Brion <info@brionmario.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

parity/prs-raised Ports exist in the other SDKs, or are recorded as not applying there

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants