Skip to content

Teams, Members & Permissions

This area covers 29 features. Watch the walkthrough, then use the reference below — each feature links to the exact moment it appears (▶).

Who this is for: Org admin / project lead. Each feature below lists the role/permission it requires.

Features

List teams in organization ▶ 00:00

As an org admin, I want to see all teams in my organization with member/project counts, so that I can manage team structure and composition.

How it works. Navigate to /teams. Page loads with grid of team cards showing team name, member count, project count, and 'Member' badge if user is in team. When no teams exist, show 'No teams in this org yet.' message. When org not selected, show 'Select an organization' prompt.

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/components/org/TeamsList.tsx:34-173
src/lib/frontier/teams.ts:13-16

Search teams by name ▶ 00:00

As an org admin with many teams, I want to search teams by name, so that I can quickly find a specific team.

How it works. On /teams page when teams exist, a search input (type=search, placeholder='Search teams…') appears. Typing filters teams by case-insensitive name substring match. Empty search shows all teams. When no teams match, show 'No teams match "[query]"' with a 'Clear' button.

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/components/org/TeamsList.tsx:44,63-68,101-149

Sort teams by name, member count, or project count ▶ 00:00

As an org admin, I want to sort teams by different metrics, so that I can prioritize attention on larger/busier teams.

How it works. On /teams page when teams exist, a Select dropdown appears with 3 options: 'Name (A–Z)', 'Members (most first)', 'Projects (most first)'. Default is 'Name'. Sorting is applied instantly to the displayed list.

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/components/org/TeamsList.tsx:18-32,45,110-127

Create a team ▶ 00:06

As an org admin, I want to create a new team, so that I can group members and grant them project access together.

How it works. On /teams page, an admin sees a 'New team' button. Clicking it reveals an inline form with 'Team name' (required) and 'Description (optional)' inputs plus 'Create' and 'Cancel' buttons. Submitting POSTs to /api/v2/orgs/:orgId/groups, navigates to /teams/:groupId on success. Non-admins (level < 600) do not see the button.

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/components/org/TeamsList.tsx:47,77-98
src/lib/frontier/teams.ts:24-28

View team details (members and projects) ▶ 00:06

As an org admin, I want to see all members and projects assigned to a team, so that I can understand the team's scope and composition.

How it works. Navigate to /teams/:teamId. Page shows team name as h1, description (if set), Members section listing all team members with usernames and org-level roles, and Projects section listing all attached projects with granted role levels. Loading state shows 'Loading…' spinner. Team-not-found state shows 'Team not found.' message. When no members/projects, show empty-state text.

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/components/org/TeamDetail.tsx:70-230,318-571
src/lib/frontier/teams.ts:18-21

Edit team name and description ▶ 00:00

As an org admin, I want to rename a team and update its description, so that I can keep team metadata current.

How it works. On team detail page, admin sees 'Edit' and 'Delete team' buttons. Clicking 'Edit' replaces the display with inline inputs pre-filled with current name and description. 'Save' button POSTs PATCH to /api/v2/orgs/:orgId/groups/:groupId with name and description. 'Cancel' dismisses edit mode. Non-admins do not see the button.

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/components/org/TeamDetail.tsx:151-164,213-292
src/lib/frontier/teams.ts:30-34

Delete a team ▶ 00:00

As an org admin, I want to delete a team I no longer need, so that I can clean up obsolete team structure.

How it works. On team detail page, admin clicks 'Delete team' button. An inline confirmation box appears with text 'Delete '[team name]'? This removes the team and all its grants.' and 'Confirm' / 'Cancel' buttons. Clicking 'Confirm' DELETEs /api/v2/orgs/:orgId/groups/:groupId and navigates to /teams. 'Cancel' dismisses the confirmation. Non-admins do not see the button.

WhoProject lead / owner PermissionsLifecycle ops: project_lead(500)+ / owner(700)
Key files

src/components/org/TeamDetail.tsx:166-170,294-314
src/lib/frontier/teams.ts:36-39

Add member to team ▶ 00:00

As an org admin, I want to add org members to a team, so that I can group people for project access.

How it works. On team detail page, admin sees 'Add member' link. Clicking it reveals a combobox (searchable dropdown) pre-populated with available org members not already in team, a 'Add' button, and 'Cancel' button. Typing filters member list. Selecting a member and clicking 'Add' POSTs to /api/v2/orgs/:orgId/groups/:groupId/members with username. Member appears in Members list. If all org members already in team, show 'All org members are already in this team.' message and disable the Add button.

WhoProject lead / owner PermissionsManage members/invites: project_lead(500); role changes: maintainer/owner(≥600); link role capped at contributor(400)
Key files

src/components/org/TeamDetail.tsx:104-107,135-142,172-178,318-373,578-683
src/lib/frontier/teams.ts:41-45

Remove member from team ▶ 00:00

As an org admin, I want to remove a member from a team, so that I can adjust team composition without removing them from the org.

How it works. In Members section of team detail page, each member row has a 'Remove' link (red underline). Clicking it DELETEs /api/v2/orgs/:orgId/groups/:groupId/members/:userId and the member disappears from the list immediately. Non-admins do not see the Remove button.

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/components/org/TeamDetail.tsx:180-184,420-428
src/lib/frontier/teams.ts:47-50

Change member org-level role within team context ▶ 00:00

As an org owner, I want to change a team member's org-level role, so that I can adjust their permissions across the organization.

How it works. On team detail page, if caller is owner (level 700+), each member row shows a role-picker (Select dropdown) with all 7 role options. Changing role calls handleChangeMemberRole() which POSTs to /api/v2/orgs/:orgId/members with username and new role. If caller is not owner, the role is shown as a locked badge with a '?' help icon; hovering shows tooltip explaining the role and that it can only be changed by an org owner.

WhoProject lead / owner PermissionsManage members/invites: project_lead(500); role changes: maintainer/owner(≥600); link role capped at contributor(400)
Key files

src/components/org/TeamDetail.tsx:78-80,201-205,383-419
src/lib/frontier/teams.ts:N/A (uses addOrgMember from orgs.ts)

Attach project to team with granted role ▶ 00:00

As an org admin, I want to grant a team access to a project at a specific role level, so that all team members inherit that project access together.

How it works. On team detail page, admin sees 'Attach project' link. Clicking it reveals a Projects section select dropdown (filtered to projects not already attached) and a Role dropdown (7 options). Selecting a project and role and clicking 'Attach' POSTs to /api/v2/orgs/:orgId/groups/:groupId/projects with projectId and roleLevel. Project appears in Projects list with granted role. Non-admins do not see the link.

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/components/org/TeamDetail.tsx:186-193,445-519
src/lib/frontier/teams.ts:52-56

Change team's granted role on a project ▶ 00:00

As an org admin, I want to adjust the role level a team has on an attached project, so that I can fine-tune team access permissions.

How it works. In Projects section of team detail page, each project row shows a role-picker (Select dropdown with 6 options; Owner is excluded). Changing role calls handleChangeProjectRole() which PATCHes /api/v2/orgs/:orgId/groups/:groupId/projects/:projectId with new roleLevel. Role updates immediately. Non-admins do not see the dropdown.

WhoProject lead / owner PermissionsManage members/invites: project_lead(500); role changes: maintainer/owner(≥600); link role capped at contributor(400)
Key files

src/components/org/TeamDetail.tsx:195-199,535-553
src/lib/frontier/teams.ts:58-62

Detach project from team ▶ 00:00

As an org admin, I want to remove a team's access to a project, so that I can clean up stale project attachments.

How it works. In Projects section of team detail page, each project row has a 'Detach' link (red underline). Clicking it DELETEs /api/v2/orgs/:orgId/groups/:groupId/projects/:projectId. Project disappears from the list. Non-admins do not see the link.

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/components/org/TeamDetail.tsx:207-211,553-559
src/lib/frontier/teams.ts:64-67

View org members with roles ▶ 00:00

As an org admin, I want to see all members of my organization and their roles, so that I can manage org-wide access.

How it works. Navigate to /members page. Shows 'Members' heading with org name in subtitle. Renders a member roster (MembersPanel) listing all org members with usernames, org-level roles (Viewer/Contributor/Project Lead/Maintainer), and source badge. 'Last active X ago' chip shown if lastActiveAt is set. Stale members (>30 days) get amber highlight. When loading, show 'Loading members…' spinner. When error, show error text with red background. When no org selected, show 'Select an organization' prompt.

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/pages/MembersPage.tsx:48-245
src/components/MembersPanel.tsx:48-199
src/lib/frontier/orgs.ts:155-161

Add org member by username ▶ 00:00

As an org admin, I want to add an existing Aquilla user to my organization, so that they can access all org projects at their assigned role.

How it works. On /members page, MembersPanel shows an 'Add' row at bottom with a username typeahead input, role dropdown (Viewer/Contributor/Project Lead/Maintainer default), and 'Add' button. Typing in typeahead searches across all Aquilla users (scopedSearch=false). Selecting username and role and clicking 'Add' calls onAdd() which POSTs to /api/v2/orgs/:orgId/members. If username not found, error message 'Could not add user. Username may not exist.' displays. Member appears in list on success.

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/pages/MembersPage.tsx:137-152,281-295
src/components/MembersPanel.tsx:71-85,157-194
src/lib/frontier/orgs.ts:163-176

Change org member role ▶ 00:00

As an org owner, I want to change a member's org-level role, so that I can adjust their permissions without removing them.

How it works. On /members page, each member row shows a role-picker (Select dropdown). Changing role calls onChangeRole() which POSTs to /api/v2/orgs/:orgId/members with username and new role. Role updates on the row. Role picker is only enabled for non-locked members and non-self rows. Locked members (org owner source) show read-only badge without picker.

WhoProject lead / owner PermissionsManage members/invites: project_lead(500); role changes: maintainer/owner(≥600); link role capped at contributor(400)
Key files

src/pages/MembersPage.tsx:281-295
src/components/MembersPanel.tsx:86,109-134

Remove org member ▶ 00:00

As an org admin, I want to remove a member from my organization, so that they lose org-wide access and I can clean up inactive users.

How it works. On /members page, each member row has a trash icon button. Clicking it opens a confirmation dialog (RemoveOrgMemberDialog) showing 'Remove [username] from [orgName]?' with warning that they lose org-wide access but keep per-project direct grants. Dialog lists all projects where member has direct grants with checkboxes (default unchecked). User can opt-in to remove from specific projects. 'Remove from org' (or 'Remove from org and N projects' if checked) button confirms. Clicking removes from org and (optionally) from selected projects. Non-owners cannot remove self.

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/pages/MembersPage.tsx:216-230,287-291
src/components/RemoveOrgMemberDialog.tsx:21-132
src/lib/frontier/orgs.ts:178-189

View per-member project access breakdown (MemberAccessRow expansion) ▶ 00:00

As an org manager, I want to drill down on a member to see all their project access paths (direct/team/org/creator) and resolved effective roles, so that I can understand and manage their complete access picture (AD-12 max-wins).

How it works. On /members page below the main roster, a 'Project access' section shows each member as an expandable row (chevron icon + username). Clicking expands to show: org-level role applicability note, then per-project rows. Each project row displays: project name, resolved effective role (the max), and chips for each contributing path (e.g., 'direct: contributor', 'team Translators: reviewer', 'org: viewer', 'creator'). Direct grants have a 'Revoke direct grant' button. Non-removable paths (team/org/creator) show pointer text 'Also via … — manage in Teams / Members.' Lazy-loading: expansion fetches via GET /api/v2/orgs/:orgId/members/:userId/access when row is first expanded.

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/pages/MembersPage.tsx:297-311
src/components/org/MemberAccessPanel.tsx:17-189
src/lib/frontier/orgs.ts:141-145

Invite org members to specific projects (multi-project invite dialog) ▶ 00:00

As an operational PM, I want to add an existing org member to multiple projects in one flow without granting org-wide access, so that I can quickly onboard contributors to the projects they need.

How it works. On /members page, 'Add to projects' button (UsersRound icon) opens MultiProjectInviteDialog. Dialog has username typeahead (existing Aquilla user), multi-select checkboxes for projects, and per-project role pickers (default Contributor). Submitting POSTs to /api/v2/projects/:projectId/members for each selected project with username and role. Success shows 'Invite complete' or per-project statuses. Email mode shows explanation that per-project invite links are available in Share panels instead of direct add.

WhoProject lead / owner PermissionsManage members/invites: project_lead(500); role changes: maintainer/owner(≥600); link role capped at contributor(400)
Key files

src/pages/MembersPage.tsx:168-182,232-242
src/components/MultiProjectInviteDialog.tsx:28-100+ (partial read)

View and revoke pending invitations (targeted email + open link) ▶ 00:00

As an org owner, I want to see all outstanding share-link invitations to my projects and revoke them if they're no longer needed, so that I can manage access hygiene.

How it works. On /members page, 'Pending invitations' section (owner-only, gated server-side via 403) lists all unredeemed project invites across the org. Each row shows: project name, role (capitalized), email badge (if targeted) or 'open link' badge, creator username, expiry label (e.g., 'expires in 2 days', 'expired', 'no expiry'), and trash icon. Clicking trash DELETEs /projects/:projectId/invites/:token. Row disappears optimistically; if server errors, re-fetch restores it. Non-owners see no section.

WhoProject lead / owner PermissionsManage members/invites: project_lead(500); role changes: maintainer/owner(≥600); link role capped at contributor(400)
Key files

src/pages/MembersPage.tsx:326-355,356-437
src/lib/frontier/orgs.ts:75-88

View external collaborators (non-org members with project access) ▶ 00:00

As a maintainer+ org admin, I want to see all non-members who have access to org projects (via invite links, direct adds, or teams), so that I can govern external access.

How it works. On /members page, 'External collaborators' section (maintainer+ only, FRO-326) lists everyone accessing org projects who is NOT an org member. Each row shows: username, 'external' badge (amber), list of projects they access, and per-project inline 'Revoke' buttons. Clicking revoke DELETEs /projects/:projectId/members/:userId. Section hidden if no externals. Derived on read from members-matrix; not a stored org_members variant.

WhoProject lead / owner PermissionsManage members/invites: project_lead(500); role changes: maintainer/owner(≥600); link role capped at contributor(400)
Key files

src/pages/MembersPage.tsx:207-213
src/components/org/ExternalCollaboratorsSection.tsx:26-160+ (partial)

View per-project members with role sources and secondary paths ▶ 00:00

As a project admin, I want to see everyone with access to a project and their effective role, including where their access comes from (org/team/direct/creator), so that I can manage project membership.

How it works. Navigate to /project/:projectId/members. Renders MembersTab in a two-tab interface (Members / Invite link). Current members list shows each person with: username, source badge ('via org' / 'via team' / 'creator' / none for direct override), role (capability name + level), secondary sources list (e.g., '+ team:reviewer, org:contributor'). Members are sorted and grouped; loading state shows 'Loading members…'. Empty state shows 'No members yet.'

WhoProject lead / owner PermissionsManage members/invites: project_lead(500); role changes: maintainer/owner(≥600); link role capped at contributor(400)
Key files

src/components/ProjectMembersPage.tsx:62-126,136-394
src/lib/frontier/members.ts:70-82

Add project member by username ▶ 00:00

As a project maintainer, I want to add an existing Aquilla user directly to a project, so that I can grant them access without org membership.

How it works. On project members page, 'Add member' section shows username input, role dropdown (Viewer to Maintainer, max-capped by caller), and 'Add' button. Typing username searches/validates. Clicking 'Add' POSTs to /api/v2/projects/:projectId/members with username and role. Submitting shows 'Adding…' state. On success, member appears in the list. On error, shows 'No user found with that username' or server error.

WhoProject lead / owner PermissionsManage members/invites: project_lead(500); role changes: maintainer/owner(≥600); link role capped at contributor(400)
Key files

src/components/ProjectMembersPage.tsx:158-175,325-378

Change project member role ▶ 00:00

As a project maintainer, I want to change a member's role on the project, so that I can adjust their permissions (e.g., promote contributor to lead).

How it works. On project members page, each member row shows a role-picker (Select dropdown) IF the member has a direct grant (source='override') and is not self. Picker shows grantable roles (capped by caller's level). Changing role calls add() with new role, which PATCHes/POSTs to /api/v2/projects/:projectId/members with username and new level. Non-direct members (org/team/creator sources) show read-only role display with locked state; attempting role change shows tooltip explaining the source.

WhoProject lead / owner PermissionsManage members/invites: project_lead(500); role changes: maintainer/owner(≥600); link role capped at contributor(400)
Key files

src/components/ProjectMembersPage.tsx:251-283

Remove project member (direct grant only) ▶ 00:00

As a project maintainer, I want to remove a member's direct access to a project, so that I can clean up explicit grants.

How it works. On project members page, each member with direct override grant (source='override', not self) shows a 'Remove' button. Clicking DELETEs /api/v2/projects/:projectId/members/:userId. Member disappears from the list. Non-direct members (org/team/creator) show locked tooltip explaining the source instead of Remove button.

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/components/ProjectMembersPage.tsx:286-302

Revoke all project access (all grant paths) ▶ 00:00

As a project maintainer, I want to completely revoke a member's access to a project, removing all paths (direct/team/org), so that I can ensure they can no longer see or edit the project.

How it works. On project members page, each member has a 'Revoke all' button (red, ShieldOff icon) when session exists and caller is maintainer+. Clicking opens RevokeAllDialog with: member's username, warning that this removes the direct grant and explains non-removable paths (org/team/creator), list of current grant paths with 'removable' / 'stays' indicators, confirmation text-input requiring user to type member's username, and 'Revoke access' button. POSTs to /api/v2/projects/:projectId/members/:userId/revoke-all. On success, shows summary of what was removed and which paths remain.

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/components/ProjectMembersPage.tsx:304-320,380-550

Create project invite link with role and optional email ▶ 00:00

As a project lead, I want to generate a share link that grants access to my project at a specific role, optionally pre-filling an email, so that I can invite people without adding them to the org.

How it works. On project members page, 'Invite link' tab shows form with: Role dropdown (Viewer/Commenter/Reviewer/Contributor only, not managerial roles), 'Recipient email (optional)' input, Link expires dropdown (1/7/30 days or no expiry, default 7 days). 'Create invite link' button POSTs to /api/v2/projects/:projectId/invites with role, email, expiresInDays. On success, shows generated URL (copyable button, shows 'Copied!' on click), explanation, and 'Create another link' button. Email validation enforces valid format or blank. Server-side caps role to contributor (400).

WhoProject lead / owner PermissionsManage members/invites: project_lead(500); role changes: maintainer/owner(≥600); link role capped at contributor(400)
Key files

src/components/ProjectMembersPage.tsx:556-767

View role level help / access-level definitions (org and project) ▶ 00:00

As an org or project user, I want to understand what each role level allows, so that I can make informed decisions about member access.

How it works. On team detail page Members section header, a '?' icon in a circle appears next to 'Members' heading (AppTooltip). Hovering/focusing shows all 7 role descriptions (100-700) stacked vertically in a tooltip. Similar help available in project members page role pickers where individual role names appear on hover. Org-side MembersPage doesn't duplicate the help (roles already shown in picker).

WhoOrg admin / project lead PermissionsView members: viewer(100); add/remove members & assign: project_lead(500); change roles: maintainer/owner(≥600)
Key files

src/components/org/TeamDetail.tsx:49-57,322-331
src/lib/frontier/roles.ts:42-108

Role-level authorization gates (UI surface by level) ▶ 00:00

As a user, I want role-based UI to adapt based on my org/project level, so that I only see actions I have permission to perform.

How it works. Across all members/teams/project pages: 'New team' button only visible if org role >= 600 (maintainer). 'Add member' / 'Edit team' / 'Delete team' / 'Attach project' only visible to maintainer+ (600+). Role-change pickers gated by org ownership (700+) or caller max-role cap. Member remove buttons only visible for non-locked members. Revoke-all only visible when session exists. All gates checked client-side (UX convenience) AND server-side (security boundary). When caller can't see a button, alternative read-only display shown (e.g., locked role badge).

WhoProject lead / owner PermissionsManage members/invites: project_lead(500); role changes: maintainer/owner(≥600); link role capped at contributor(400)
Key files

src/components/org/TeamsList.tsx:47,77
src/components/org/TeamDetail.tsx:78-80,236,333,420,447
src/components/ProjectMembersPage.tsx:145-147