Test Cases: Permission Assignment & Boundaries

Module: RBAC - Permission Assignment

Backend Endpoints:

Frontend Page: frontend/pwa-app/src/pages/AdminRolesPermissionsPage.tsx

Permission format: MODULE:ACTION:resource — e.g. FINANCE:VIEW:invoices, EVENTS:CREATE:events. There are 38 permission strings across 6 modules (MEMBERS, FINANCE, EVENTS, COMMUNICATIONS, ORGANIZATION, ADMIN). The ADMIN role holds all 38 via wildcard expansion.

Permission Catalog (38 permissions)

ModulePermission keys
MEMBERSVIEW:members, CREATE:members, EDIT:members, DELETE:members, VIEW:prospects, EDIT:prospects, VIEW:invitations, CREATE:invitations, CREATE:import
FINANCEVIEW:dashboard, VIEW:invoices, CREATE:invoices, EDIT:invoices, VIEW:payments, CREATE:payments, EDIT:payments, VIEW:dues, EDIT:dues, VIEW:donations, VIEW:bank-accounts, EDIT:bank-accounts
EVENTSVIEW:events, CREATE:events, EDIT:events, DELETE:events, VIEW:registrations, EDIT:registrations
COMMUNICATIONSVIEW:broadcasts, CREATE:broadcasts, EDIT:broadcasts, DELETE:broadcasts
ORGANIZATIONVIEW:settings, EDIT:settings, VIEW:workflows, EDIT:workflows
ADMINVIEW:dashboard, VIEW:roles, EDIT:roles, VIEW:audit-log, VIEW:content, EDIT:content

Each row's keys are prefixed by the module — e.g. the MEMBERS row's first key is MEMBERS:VIEW:members.

Per-Role Permission Sets (system roles)

RoleGranted permissions (summary)
ADMINAll 38 (via MODULE:*:* wildcards).
OFFICERMEMBERS:VIEW:members, EVENTS:VIEW:events, EVENTS:VIEW:registrations, FINANCE:VIEW:bank-accounts, ADMIN:VIEW:dashboard
FINANCE_MANAGERAll FINANCE:* (dashboard, invoices C/V/E, payments C/V/E, dues V/E, donations, bank-accounts V/E) + MEMBERS:VIEW:members, EVENTS:VIEW:events, EVENTS:VIEW:registrations, ADMIN:VIEW:dashboard
EVENT_MANAGERAll EVENTS:* + all COMMUNICATIONS:* + MEMBERS:VIEW:members, MEMBERS:VIEW:prospects, ADMIN:VIEW:dashboard
MEMBERSHIP_MANAGERMEMBERS: view/create/edit members, view/edit prospects, view/create invitations, create import + EVENTS:VIEW:events/registrations, ORGANIZATION:VIEW:workflows, ADMIN:VIEW:dashboard
COMMUNICATIONS_MANAGERAll COMMUNICATIONS:* + MEMBERS:VIEW:members, EVENTS:VIEW:events/registrations, ADMIN:VIEW:dashboard
MEMBER / PENDING_MEMBER / EXPIRED_MEMBER / GUESTOnly EVENTS:VIEW:events. (Member directory access is granted by the requireApprovedMember guard, not by a permission key.)

Test Cases

TC-RBAC-016: View All Permissions

StepActionExpected Result
1Login as ADMIN. Open Settings → Roles & Permissions. Select any role.Detail panel shows module tabs.
2Click through the module tabs: Members, Finance, Events, Communications, Organization, Admin.Each tab shows a matrix of resources × actions (View/Create/Edit/Delete).
3API: GET /api/admin/permissions as ADMIN.200 with { modules: [ { module, permissions: [...] } ] } — 38 permissions total across 6 modules.

TC-RBAC-017: Grant a Permission to a Role

StepActionExpected Result
1Select FINANCE_MANAGER. Open the Members tab.Matrix shown; only VIEW:members currently checked.
2Check EDIT:members. Click "Save Changes".Calls PUT /api/admin/roles/:roleId/permissions with the full new set. "Save Changes" disappears.
3Reload the page; reselect FINANCE_MANAGER → Members tab.MEMBERS:EDIT:members persists checked.
4(Restore) Uncheck EDIT:members, Save Changes.Reverted.

Tip: "Grant All" / "Revoke All" buttons toggle every permission in the current module tab.

TC-RBAC-018: Revoke a Permission from a Role

StepActionExpected Result
1Select EVENT_MANAGER → Events tab. Uncheck DELETE:events. Save Changes.Permission removed; persists on reload.
2Verify effect: a user with EVENT_MANAGER calling DELETE /api/events/admin/events/:id now gets 403.Action blocked. (Restore the permission afterward.)

TC-RBAC-019: Assign a Role to a Member (UI)

StepActionExpected Result
1Go to All Members → click Maria Cruz → Actions ▾ → Manage Roles."Manage Roles" modal with 6 built-in staff-role cards.
2Check Events Manager (EVENT_MANAGER). Click "Save Roles".Calls PUT /api/membership/members/:id/roles with ["EVENT_MANAGER"] (MEMBER auto-retained). Member chips show MEMBER + EVENT_MANAGER.
Limitation: the Manage Roles modal only lists the 6 built-in staff roles (ADMIN, OFFICER, FINANCE_MANAGER, EVENT_MANAGER, MEMBERSHIP_MANAGER, COMMUNICATIONS_MANAGER). Custom roles must be assigned via the API.

TC-RBAC-020: Remove a Role from a Member

StepActionExpected Result
1Maria Cruz → Manage Roles → uncheck Events Manager → Save Roles.PUT with ["MEMBER"]. Only MEMBER remains.
2Maria refreshes / re-logs in.Event-management sidebar items gone (allow for the 5-min permission cache / token refresh).

TC-RBAC-021: Assign Multiple Roles

StepActionExpected Result
1Maria Cruz → Manage Roles → check Events Manager + Communications → Save Roles.PUT with ["EVENT_MANAGER","COMMUNICATIONS_MANAGER"]; member has the union of both permission sets (+ MEMBER).

TC-RBAC-022: Non-Admin Cannot Open Manage Roles

StepActionExpected Result
1Login as Elena Torres (MEMBERSHIP_MANAGER). Open All Members → a member → Actions ▾.The "Manage Roles" item is not shown (requires ADMIN's canEditMember).
2API: PUT /api/membership/members/:id/roles as MEMBERSHIP_MANAGER.Status 403 (lacks ADMIN:EDIT:roles).

API Test Cases

TC-RBAC-API-007: GET /api/admin/permissions

Expected: 200 OK{ "modules": [ { "module": "FINANCE", "permissions": [ { "id", "action": "VIEW", "resource": "invoices", "description" }, ... ] }, ... ] }.

TC-RBAC-API-008: PUT /api/admin/roles/:roleId/permissions

Request: PUT /api/admin/roles/<FINANCE_MANAGER id>/permissions

{ "permissions": ["FINANCE:VIEW:dashboard", "FINANCE:VIEW:invoices", "FINANCE:VIEW:payments"] }

Expected: 200 OK — replaces the role's full permission set (this example would narrow FINANCE_MANAGER to read-only; don't run against the live role without restoring). Invalidates the permission cache.

TC-RBAC-API-009: PUT /api/membership/members/:id/roles

Request: PUT /api/membership/members/<memberId>/roles

{ "roles": ["MEMBER", "EVENT_MANAGER"] }

Expected: 200 OK — returns the updated member; both Member.roles and the RoleAssignment table are updated in one transaction. Method is PUT (not POST).

TC-RBAC-API-010: GET /api/admin/roles/:roleId/users

GET /api/admin/roles/<FINANCE_MANAGER id>/users200 OK { "users": [ { "id", "email", "firstName", "lastName", "assignedAt" } ] }.