capability column and propagate it to membership.
45 file(s), +274 / -777 lines
| Path | Role | + | - |
|---|---|---|---|
| messages/en.json | Config | +5 | -4 |
| messages/hi.json | Config | +5 | -4 |
| openapi/app-api.json | Config | +33 | -128 |
| src/app/api/internal/members/[userId]/role/route.ts | App route | +0 | -43 |
| src/components/settings/matter-types/matter-type-sheet-parts.tsx | Component | +4 | -0 |
| src/components/settings/team/capability-select.tsx | Component | +9 | -3 |
| src/components/settings/team/firm-role-sheet.stories.tsx | Component | +13 | -1 |
| src/components/settings/team/firm-role-sheet.tsx | Component | +36 | -4 |
| src/components/settings/team/firm-role-table-row.tsx | Component | +4 | -1 |
| src/components/settings/team/firm-roles-table.tsx | Component | +1 | -0 |
| src/components/settings/team/member-table-row.tsx | Component | +8 | -2 |
| src/components/settings/team/presentation.ts | Component | +0 | -6 |
| src/components/settings/team/team-fixtures.ts | Component | +3 | -0 |
| src/components/settings/team/team-storybook-helpers.tsx | Component | +0 | -1 |
| src/components/settings/team/team-table-layout.ts | Component | +1 | -1 |
| src/components/settings/team/use-firm-role-sheet.tsx | Component | +14 | -2 |
| src/components/settings/team/use-team-list-actions.ts | Component | +0 | -14 |
| src/components/settings/team/use-team-mutations.ts | Component | +0 | -4 |
| src/gen/client/appUpdateMemberRole.ts | Generated contract | +0 | -73 |
| src/gen/client/index.ts | Generated contract | +0 | -1 |
| src/gen/hooks/index.ts | Generated contract | +0 | -4 |
| src/gen/hooks/useAppUpdateMemberRole.ts | Generated contract | +0 | -156 |
| src/gen/index.ts | Generated contract | +5 | -32 |
| src/gen/schemas/firmMemberRoleUpdateRequest.json | Generated contract | +0 | -17 |
| src/gen/schemas/firmRoleCapability.json | Generated contract | +7 | -0 |
| src/gen/schemas/firmRoleCreateRequest.json | Generated contract | +8 | -1 |
| src/gen/schemas/firmRoleListResponse.json | Generated contract | +9 | -1 |
| src/gen/schemas/firmRoleUpdateRequest.json | Generated contract | +13 | -0 |
| src/gen/schemas/firmRoleView.json | Generated contract | +9 | -1 |
| src/gen/types/AppUpdateMemberRole.ts | Generated contract | +0 | -76 |
| src/gen/types/FirmMemberRoleUpdateRequest.ts | Generated contract | +0 | -19 |
| src/gen/types/FirmRoleCapability.ts | Generated contract | +16 | -0 |
| src/gen/types/FirmRoleCreateRequest.ts | Generated contract | +7 | -0 |
| src/gen/types/FirmRoleUpdateRequest.ts | Generated contract | +6 | -0 |
| src/gen/types/FirmRoleView.ts | Generated contract | +7 | -1 |
| src/gen/types/index.ts | Generated contract | +4 | -14 |
| src/gen/zod/appUpdateMemberRoleSchema.ts | Generated contract | +0 | -96 |
| src/gen/zod/firmMemberRoleUpdateRequestSchema.ts | Generated contract | +0 | -24 |
| src/gen/zod/firmRoleCapabilitySchema.ts | Generated contract | +17 | -0 |
| src/gen/zod/firmRoleCreateRequestSchema.ts | Generated contract | +6 | -0 |
| src/gen/zod/firmRoleUpdateRequestSchema.ts | Generated contract | +9 | -0 |
| src/gen/zod/firmRoleViewSchema.ts | Generated contract | +7 | -1 |
| src/gen/zod/index.ts | Generated contract | +1 | -13 |
| src/lib/members/gateway.ts | Library | +0 | -27 |
| tests/unit/firm-roles-table.test.tsx | Test | +7 | -2 |
Before ADR-112, capability (Admin / Editor / Member) was set per member and the firm role (designation) was a separate, decorative label. ADR-112 inverts the relationship: the firm role is the single assignable, and capability is derived from it. A firm authors the role→capability binding once (Partner → Admin); assigning a member that role sets their access automatically. The standalone "Change capability" control is therefore retired — there is nothing left to set directly.
The vendored openapi/app-api.json was synced to
pramaan-functions main and pnpm codegen regenerated
src/gen (first commit). Cascade absorbed:
| Contract change | App-side fix |
|---|---|
appUpdateMemberRole (PATCH …/role) removed
|
Deleted the /api/internal/members/[userId]/role proxy,
membersGateway.updateRoleWithResponseHeaders, the
useAppUpdateMemberRole mutation, and every
updateCapability / updateMemberCapability
caller. Designation is the only member mutation — PATCH
…/firm-role.
|
FirmRoleView /
FirmRoleCreateRequest /
FirmRoleUpdateRequest gained required
capability; new FirmRoleCapability enum
(firm_admin | firm_editor | firm_member)
|
Role create/edit sheet authors it; the three
firmRoleFixtures carry it; the roles table shows it.
|
The member "⋯" menu keeps only Change role (designation
catalog picker + "No role" to clear) — no capability action. The Role
column now renders the firm role name with the
derived capability as a muted meta line beneath it
(member.role → Team.capabilities.* →
Admin / Editor / Member). A member with no firm role shows the
firm_member default ("Member") with an em-dash designation.
Because capability is propagated server-side, the meta line updates the
moment the role changes — no separate write.
FirmRoleSheet gains a capability selector
(reusing the existing CapabilitySelect radio cards, now
generalised with ariaLabel / idPrefix props).
Create and rename send capability in the payload. System
defaults (Partner / Senior Advocate / Member) are rename-only — ADR-112
locks their capability — so the selector is disabled and the PATCH omits
capability for them, with a hint explaining why.
The Settings "Firm configuration" group and the standalone Team roles page (promoted out of the Members tab strip) landed earlier in Story-1251 (#317), which is on this branch's base. This story completes ADR-112 on top of that IA: the Team roles page's roles table now carries the read-only Access column, and the sheet behind it authors the binding.
Dead keys removed (Team.members.changeCapability,
columnCapability, capabilityUpdatedToast). New
keys added to both messages/en.json and
messages/hi.json: Team.roles.columnCapability,
capabilityLabel, capabilityHint,
capabilityLockedHint. Per ux-guidelines §17 the raw word
"capability" never reaches counsel — it renders as Admin / Editor / Member
(column header "Access").
| Surface | Coverage |
|---|---|
FirmRolesTable |
Updated to assert the derived Access column (Partner → Admin, Senior Advocate → Editor; "Member" appears as both name and tier). |
MemberActions |
Existing test confirms no "Change capability" menuitem; role picker unaffected. |
FirmRoleSheet |
Stories: add, edit (editable selector),
DefaultRoleCapabilityLocked (locked tier), saving,
name-conflict.
|
pnpm lint clean (pre-existing
warnings only) · pnpm test
495 passed · pnpm build
compiles; the retired …/role route is gone,
…/firm-role remains · tsc --noEmit
clean · hardcoded-copy and color-literal scans
no hits · quality CI green (no
src/gen drift after the mirror sync).