Commit 4bea3f8
authored
fix(auth): grant billing_manager same UI and backend permissions as owner (#1084)
<img width="1243" height="776" alt="image"
src="https://github.com/user-attachments/assets/2e5b557b-ffc2-403e-bde5-996ba12e582a"
/>
<img width="1397" height="541" alt="image"
src="https://github.com/user-attachments/assets/f76c83ff-7c2b-4529-99aa-81ad1503ddbe"
/>
## Summary
- The backend `organizationOwnerProcedure` (in
`src/routers/organizations/utils.ts:127`) already grants
`billing_manager` the same access as `owner`, but multiple frontend
permission checks and one backend route only checked for
`currentUserRole === 'owner'`, effectively hiding actions from billing
managers that the API would allow.
- This PR aligns all frontend permission gates and one backend access
check with the intended `organizationOwnerProcedure` behavior.
**Frontend fixes (4 files):**
- `OrganizationMembersCard.tsx`: `canRemoveMember`, `canEditRole`,
`canEditLimit`, `canDelete` (invitations), `canCopy` (invite URL) now
include `billing_manager` via a shared `isPrivilegedRole` helper
- `SeatUsageCard.tsx`: "Manage" subscription link now visible to
`billing_manager`
- `OrganizationDataCollectionCard.tsx`: `canEdit` now includes
`billing_manager`; corrected help text from "admins" to "billing
managers"
- `InviteMemberDialog.tsx`: removed stale `admin` entry from
`ROLE_LABELS` (not a valid `OrganizationRole`)
**Backend fix (1 file):**
- `organization-subscription-router.ts`: `getSubscriptionStripeUrl` now
allows `['owner', 'billing_manager']` when prior subscriptions exist,
aligning with all other subscription routes that use
`organizationOwnerProcedure`
## Verification
- [x] `pnpm typecheck` — all 29 workspace projects pass with zero errors
- [x] Manual review of every `organizationOwnerProcedure` usage to
confirm backend already allows `billing_manager`
- [x] Verified no other frontend `currentUserRole === 'owner'` checks
exist that should include `billing_manager` (remaining owner-only checks
are for SSO config and admin-only routes, which are intentionally
restricted)
## Visual Changes
N/A
## Reviewer Notes
- The `isPrivilegedRole` helper in `OrganizationMembersCard.tsx`
centralizes the `owner || billing_manager` check to avoid repeating the
pattern. It's intentionally scoped to that file since other files only
have 1-2 checks.
- SSO routes (`organization-sso-router.ts`) and admin-gated routes
(`organization-router.ts` `updateSeatsRequired`/`seatPurchases`) remain
`['owner']`-only, as they also require `adminProcedure` and are
Kilo-admin operations.
- The `cloudflare-ai-attribution/src/schemas.ts` zod enum still omits
`billing_manager` — this is a separate service and was left out of
scope, but is a known inconsistency worth tracking.5 files changed
Lines changed: 20 additions & 16 deletions
File tree
- src
- components/organizations
- members
- routers/organizations
Lines changed: 3 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
73 | 73 | | |
74 | 74 | | |
75 | 75 | | |
76 | | - | |
| 76 | + | |
| 77 | + | |
77 | 78 | | |
78 | 79 | | |
79 | 80 | | |
| |||
134 | 135 | | |
135 | 136 | | |
136 | 137 | | |
137 | | - | |
| 138 | + | |
138 | 139 | | |
139 | 140 | | |
140 | 141 | | |
| |||
Lines changed: 15 additions & 11 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
70 | 70 | | |
71 | 71 | | |
72 | 72 | | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
73 | 76 | | |
74 | 77 | | |
75 | | - | |
| 78 | + | |
76 | 79 | | |
77 | 80 | | |
78 | 81 | | |
| |||
86 | 89 | | |
87 | 90 | | |
88 | 91 | | |
89 | | - | |
90 | | - | |
| 92 | + | |
| 93 | + | |
91 | 94 | | |
92 | 95 | | |
93 | 96 | | |
| |||
150 | 153 | | |
151 | 154 | | |
152 | 155 | | |
153 | | - | |
| 156 | + | |
154 | 157 | | |
155 | | - | |
| 158 | + | |
156 | 159 | | |
157 | 160 | | |
158 | 161 | | |
| |||
189 | 192 | | |
190 | 193 | | |
191 | 194 | | |
192 | | - | |
| 195 | + | |
193 | 196 | | |
194 | 197 | | |
195 | 198 | | |
| |||
242 | 245 | | |
243 | 246 | | |
244 | 247 | | |
245 | | - | |
246 | | - | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
247 | 251 | | |
248 | 252 | | |
249 | 253 | | |
| |||
412 | 416 | | |
413 | 417 | | |
414 | 418 | | |
415 | | - | |
| 419 | + | |
416 | 420 | | |
417 | 421 | | |
418 | 422 | | |
419 | 423 | | |
420 | | - | |
| 424 | + | |
421 | 425 | | |
422 | 426 | | |
423 | 427 | | |
424 | | - | |
| 428 | + | |
425 | 429 | | |
426 | 430 | | |
427 | 431 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
85 | | - | |
| 85 | + | |
86 | 86 | | |
87 | 87 | | |
88 | 88 | | |
| |||
Lines changed: 0 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | | - | |
44 | 43 | | |
45 | 44 | | |
46 | 45 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
143 | 143 | | |
144 | 144 | | |
145 | 145 | | |
146 | | - | |
| 146 | + | |
147 | 147 | | |
148 | 148 | | |
149 | 149 | | |
| |||
0 commit comments