chore(lor-pivot): remove bans, timeouts, warden tier (phase 2)#56
Conversation
Strip ban / timeout features (Discord-style community moderation) and
the warden tier from the granular better-auth permission system.
Keep the per-guild permission architecture intact —
`assertGuildPermission`,
dynamic role grants via guild_role table, and the `createAccessControl`
machinery all stay. The trims align the system with Lor's scope:
workspace admin removes members (kick); no banishment, no timeouts, no
moderator middle tier.
Schema:
- Delete guild-bans.ts.
- Drop communicationDisabledUntil/By/Reason columns from guild-members.
- Change guild_member.role from text({enum}) to plain text() — follows
better-auth's organization-member pattern, allows dynamic role names
defined per-guild via guild_role table.
Permissions:
- Drop `announcement` resource from the statement map (no announcement
channels in Lor).
- Drop `ban` and `timeout` actions from the guildMember statement.
- Drop the warden role entirely (positions/labels/rate-limits collapse
to
owner/admin/member; assignableGuildRoles = ["admin", "member"]).
- Rename "Citizen" label to "Member".
- Delete isCommunicationDisabled / assertMemberCanCommunicate helpers
in apps/api/src/lib/permissions.ts.
API:
- Delete banGuildMember, timeoutGuildMember, clearGuildMemberTimeout
handlers + routes + zod schemas + .openapi() mounts.
- Strip communicationDisabled* fields from listGuildMembers selects and
the toGuildMemberPresence shape.
- Remove the guild-ban check from invites/handlers.ts.
- Remove the communicationDisabledUntil check from uploads/handlers.ts.
Realtime:
- Drop the communication-disabled gate from message:send.
- rate-limit.ts falls back to member tier (30/min) for unknown custom
role values (since role is now plain text).
Web:
- Strip ban + timeout UI / mutations / dialogs from guild-members-panel.
- Keep kick + role-edit UI (role select offers admin/member only).
- Narrow `authClient.organization.getActiveMember()` return at the
queryFn
boundary in guild-header.tsx and channel-list.tsx — collapses the
better-auth defensive index signature workaround down to clean
`{ userId: string; role: string } | null`.
PIVOT.md updated: granular perm system + dynamic roles stay (decision
reversed mid-pass); only the feature-tied trims land.
Refs PIVOT.md "Delete aggressively" §banishment-and-timeouts.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR removes guild ban/timeout features and the "warden" role, removes communication-disabled fields and guild bans schema, refactors permission checks from role-only to member+guild-based across API, realtime services, rate-limiting, and web UI, and updates auth and docs to the final three-role model (owner/admin/member). ChangesRemove Banishment & Timeouts, Simplify Permission Model
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/src/routes/_authenticated/$guildSlug/$channelId.tsx (1)
338-338:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winOutdated reference to "wardens" in disabled message.
The
disabledReasonstring still mentions "wardens" but the warden role has been removed in this PR. This should be updated to reflect the new permission model.Proposed fix
- disabledReason="Only owners, admins, and wardens can post in decree channels" + disabledReason="Only owners and admins can post in decree channels"Note: The relevant code snippet from
apps/web/src/components/sidebar/channel-panel/create-channel-dialog.tsx(lines 36-37) also contains the text "Only admins and wardens can post" which should be updated separately.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/routes/_authenticated/`$guildSlug/$channelId.tsx at line 338, Update the stale "wardens" text to match the new permission model: change the disabledReason prop value currently set to "Only owners, admins, and wardens can post in decree channels" to remove "wardens" (e.g. "Only owners and admins can post in decree channels"), and also update the user-facing text inside the CreateChannelDialog component (the string "Only admins and wardens can post") to the corresponding new wording ("Only admins can post" or "Only owners and admins can post" as appropriate).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/api/src/routes/v1/guilds/schema.ts`:
- Around line 48-50: The schema updateGuildMemberRoleRequestSchema currently
hardcodes the allowed roles; instead import the authoritative
assignableGuildRoles (from packages/auth/src/lib/permissions.ts) and use it to
build the z.enum so the schema derives from a single source of truth (e.g.,
z.enum(assignableGuildRoles as const) or convert the imported array into the
required readonly tuple before passing to z.enum); update the import and replace
the hardcoded ["admin","member"] with the derived value so future changes to
assignableGuildRoles automatically flow to updateGuildMemberRoleRequestSchema.
In `@PIVOT.md`:
- Line 270: Update the UI to remove stale "Decree"/"wardens" terminology: remove
the "Decree" channel option in the CreateChannelDialog component
(apps/web/src/components/sidebar/channel-panel/create-channel-dialog.tsx) so it
no longer renders that option or its wardens-focused copy, and change the
disabledReason string in the authenticated guild route
(apps/web/src/routes/_authenticated/$guildSlug/$channelId.tsx) from "Only
owners, admins, and wardens can post in decree channels" to wording that matches
the new role model (e.g., "Only owners and admins can post in this channel" or
reference the dynamic guild_role model); ensure any UI labels/copy referencing
"wardens" or "Decree" are removed or replaced consistently.
---
Outside diff comments:
In `@apps/web/src/routes/_authenticated/`$guildSlug/$channelId.tsx:
- Line 338: Update the stale "wardens" text to match the new permission model:
change the disabledReason prop value currently set to "Only owners, admins, and
wardens can post in decree channels" to remove "wardens" (e.g. "Only owners and
admins can post in decree channels"), and also update the user-facing text
inside the CreateChannelDialog component (the string "Only admins and wardens
can post") to the corresponding new wording ("Only admins can post" or "Only
owners and admins can post" as appropriate).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 0f30ed17-21aa-4679-aec9-f93f39d5a807
📒 Files selected for processing (24)
PIVOT.mdapps/api/src/lib/permissions.tsapps/api/src/routes/v1/guilds/handlers.tsapps/api/src/routes/v1/guilds/index.tsapps/api/src/routes/v1/guilds/routes.tsapps/api/src/routes/v1/guilds/schema.tsapps/api/src/routes/v1/invites/handlers.tsapps/api/src/routes/v1/uploads/handlers.tsapps/realtime/src/services/channel-access.tsapps/realtime/src/services/messages.tsapps/realtime/src/services/rate-limit.tsapps/web/src/components/sidebar/channel-panel/channel-list.tsxapps/web/src/components/sidebar/channel-panel/guild-header.tsxapps/web/src/components/sidebar/right-panel/guild-members-panel.tsxapps/web/src/lib/permissions.tsapps/web/src/routes/_authenticated/$guildSlug/$channelId.tsxpackages/auth/src/lib/auth-client.tspackages/auth/src/lib/auth.tspackages/auth/src/lib/permissions.tspackages/db/src/schemas/guild-bans.tspackages/db/src/schemas/guild-members.tspackages/db/src/schemas/guilds.tspackages/db/src/schemas/index.tspackages/db/src/schemas/users.ts
💤 Files with no reviewable changes (8)
- packages/db/src/schemas/index.ts
- packages/db/src/schemas/guild-bans.ts
- apps/api/src/routes/v1/invites/handlers.ts
- apps/realtime/src/services/channel-access.ts
- apps/api/src/lib/permissions.ts
- packages/auth/src/lib/auth.ts
- apps/api/src/routes/v1/guilds/index.ts
- apps/api/src/routes/v1/guilds/handlers.ts
Strip ban / timeout features (Discord-style community moderation) and the warden tier from the granular better-auth permission system.
Keep the per-guild permission architecture intact —
assertGuildPermission,dynamic role grants via guild_role table, and the
createAccessControlmachinery all stay. The trims align the system with Lor's scope: workspace admin removes members (kick); no banishment, no timeouts, no moderator middle tier.Schema:
Permissions:
announcementresource from the statement map (no announcement channels in Lor).banandtimeoutactions from the guildMember statement.API:
Realtime:
Web:
authClient.organization.getActiveMember()return at the queryFn boundary in guild-header.tsx and channel-list.tsx — collapses the better-auth defensive index signature workaround down to clean{ userId: string; role: string } | null.PIVOT.md updated: granular perm system + dynamic roles stay (decision reversed mid-pass); only the feature-tied trims land.
Refs PIVOT.md "Delete aggressively" §banishment-and-timeouts.
This PR (phase 2 of the Lor pivot) removes Discord-style bans/timeouts and the warden moderator tier while preserving per-guild permissions. Changes touch schema, permissions, API routes, realtime services, web UI, and documentation.
Schema
Permissions
API routes & schemas
Realtime
Web UI
Docs
Files changed (representative)
Confidence Score: 2/5
Rationale: The refactor is broad and appears internally consistent across API, realtime, web, auth, and schema definitions. However, there is a critical deployment gap: no database migration files were found in the repo search to remove the guild_member communicationDisabled columns or drop the guild_bans table. Removing schema columns/tables requires explicit migrations; absent these, deploying will break or risk data loss. Addressing this missing migration (and adding tests or CI checks to catch lingering references) is required before merging. Other non-blocking items to consider: update any external tooling or scripts that relied on the removed fields, and add a short dev note documenting the owner-via-ownerId vs. role-based owner distinction to avoid future confusion.