feat: Add staff permissions#698
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive, plugin-based staff permission system for moderators and administrators in VitNode, adding database support for granular permissions, backend route-guarding middleware, and frontend components to conditionally render UI elements and sidebar navigation. The review feedback highlights several critical security vulnerabilities where handlers in the new staff administration routes lack authentication checks to verify if the current user has an active admin session. Additionally, several code improvements are suggested, including type definitions for nested navigation items, robust error handling in search callbacks and server actions, query simplification in Drizzle ORM, and reordering permission checks to validate user existence before asserting resource-specific permissions.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Pull request overview
This PR introduces a plugin-based staff permission system (admins + moderators) and integrates it across the VitNode core and the blog plugin, including backend route guards, admin-session permission resolution, admin sidebar filtering, and new admin UI for managing staff permission entries.
Changes:
- Add backend permission primitives (catalog types, permission resolution,
adminStaffPermissionroute middleware) and expose effective permissions on admin sessions. - Add admin UI for listing/creating/editing/removing staff entries and editing permissions (restricted vs unrestricted), plus permission-gated UI controls in existing admin areas.
- Add docs + i18n labels for permission catalog entries, and wire blog/core plugins to declare staff permissions.
Reviewed changes
Copilot reviewed 154 out of 160 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| plugins/blog/src/views/admin/categories/table/actions/edit-action.tsx | Hide edit action unless categories.can_edit |
| plugins/blog/src/views/admin/categories/table/actions/delete/delete-action.tsx | Hide delete action unless categories.can_delete |
| plugins/blog/src/routes/admin/blog/categories/page.tsx | Gate categories page + create action by permission |
| plugins/blog/src/locales/en.json | Add blog permission labels |
| plugins/blog/src/config.tsx | Gate blog admin nav item with permission |
| plugins/blog/src/config.api.ts | Declare blog staff permission catalog defaults |
| plugins/blog/src/api/modules/admin/categories/routes/edit.route.ts | Add adminStaffPermission guard for edit route |
| plugins/blog/src/api/modules/admin/categories/routes/delete.route.ts | Add adminStaffPermission guard for delete route |
| plugins/blog/src/api/modules/admin/categories/routes/create.route.ts | Add adminStaffPermission guard for create route |
| packages/vitnode/src/views/admin/views/core/users/show/show-user-admin-view.tsx | Hide user edit controls based on permissions + admin target |
| packages/vitnode/src/views/admin/views/core/users/show/roles/roles.tsx | Allow disabling role edit UI via canEdit |
| packages/vitnode/src/views/admin/views/core/users/show/roles/edit-roles.tsx | React import style update |
| packages/vitnode/src/views/admin/views/core/users/show/edit-field.tsx | Add canEdit flag for inline field editing |
| packages/vitnode/src/views/admin/views/core/users/actions.tsx | Hide user list row actions unless users.can_edit |
| packages/vitnode/src/views/admin/views/core/staff/views/moderators/moderators-staff-view.tsx | New moderators staff view with header + create button |
| packages/vitnode/src/views/admin/views/core/staff/views/admins/admins-staff-view.tsx | New admins staff view with header + create button |
| packages/vitnode/src/views/admin/views/core/staff/table/staff-user-format.tsx | New formatter for staff “user” entries |
| packages/vitnode/src/views/admin/views/core/staff/table/staff-table.tsx | Add permission badges + row actions column |
| packages/vitnode/src/views/admin/views/core/staff/table/actions/staff-row-actions.tsx | New per-row edit/delete controls with protected/self handling |
| packages/vitnode/src/views/admin/views/core/staff/table/actions/delete-action.ts | New server action to delete staff entries |
| packages/vitnode/src/views/admin/views/core/staff/staff-tabs.tsx | Remove old staff tabs component |
| packages/vitnode/src/views/admin/views/core/staff/moderators/moderators-staff-view.tsx | Remove old thin moderators wrapper |
| packages/vitnode/src/views/admin/views/core/staff/layout.tsx | Remove old staff layout wrapper |
| packages/vitnode/src/views/admin/views/core/staff/edit/mutation-api.ts | New server action to update staff permissions |
| packages/vitnode/src/views/admin/views/core/staff/edit/form.tsx | New client form to edit restricted/unrestricted permissions |
| packages/vitnode/src/views/admin/views/core/staff/edit/edit-staff-permissions-view.tsx | New server view composing catalog + entry into form props |
| packages/vitnode/src/views/admin/views/core/staff/create/search.action.ts | New server action to search users for staff assignment |
| packages/vitnode/src/views/admin/views/core/staff/create/mutation-api.ts | New server action to create staff entries |
| packages/vitnode/src/views/admin/views/core/staff/create/form.tsx | New client form to create staff entries (role/user) |
| packages/vitnode/src/views/admin/views/core/staff/create/create-staff-permissions-view.tsx | New server view wrapper for create form |
| packages/vitnode/src/views/admin/views/core/staff/admins/admins-staff-view.tsx | Remove old thin admins wrapper |
| packages/vitnode/src/views/admin/layouts/sidebar/nav/get-admin-nav.tsx | Filter admin nav by staff permissions + add Staff section |
| packages/vitnode/src/views/admin/layouts/breadcrumb/resolve-breadcrumb.ts | Improve breadcrumb label coverage for group roots |
| packages/vitnode/src/views/admin/layouts/breadcrumb/breadcrumb-staff-edit-admin.tsx | New breadcrumb helper for staff edit routes |
| packages/vitnode/src/views/admin/layouts/breadcrumb/breadcrumb-staff-create-admin.tsx | New breadcrumb helper for staff create routes |
| packages/vitnode/src/views/admin/layouts/breadcrumb/breadcrumb-staff-admin.tsx | Update staff breadcrumb paths after route move |
| packages/vitnode/src/views/admin/layouts/admin-layout.tsx | Provide admin permissions via context provider |
| packages/vitnode/src/routes/breadcrumb/admin/core/staff/moderators/page.tsx | New breadcrumb slot for staff moderators |
| packages/vitnode/src/routes/breadcrumb/admin/core/staff/moderators/edit/[id]/page.tsx | New breadcrumb slot for staff moderators edit |
| packages/vitnode/src/routes/breadcrumb/admin/core/staff/moderators/create/page.tsx | New breadcrumb slot for staff moderators create |
| packages/vitnode/src/routes/breadcrumb/admin/core/staff/admins/page.tsx | New breadcrumb slot for staff admins |
| packages/vitnode/src/routes/breadcrumb/admin/core/staff/admins/edit/[id]/page.tsx | New breadcrumb slot for staff admins edit |
| packages/vitnode/src/routes/breadcrumb/admin/core/staff/admins/create/page.tsx | New breadcrumb slot for staff admins create |
| packages/vitnode/src/routes/admin/core/users/staff/layout.tsx | Remove old staff layout route (moved) |
| packages/vitnode/src/routes/admin/core/users/page.tsx | Gate users page + create action by permission |
| packages/vitnode/src/routes/admin/core/staff/moderators/page.tsx | Update staff moderators route to new view + i18n provider |
| packages/vitnode/src/routes/admin/core/staff/moderators/edit/[id]/page.tsx | New staff moderators edit route |
| packages/vitnode/src/routes/admin/core/staff/moderators/create/page.tsx | New staff moderators create route |
| packages/vitnode/src/routes/admin/core/staff/admins/page.tsx | Update staff admins route to new view + i18n provider |
| packages/vitnode/src/routes/admin/core/staff/admins/edit/[id]/page.tsx | New staff admins edit route |
| packages/vitnode/src/routes/admin/core/staff/admins/create/page.tsx | New staff admins create route |
| packages/vitnode/src/locales/en.json | Add core permission labels + staff UI strings |
| packages/vitnode/src/lib/plugin.ts | Add permission to admin nav item typing |
| packages/vitnode/src/lib/api/get-session-admin-api.ts | Add checkAdminPermissionApi helper |
| packages/vitnode/src/lib/api/get-moderator-permissions-api.ts | Add moderator permission fetch + check helper |
| packages/vitnode/src/hooks/use-mobile.ts | React import style update |
| packages/vitnode/src/database/moderators.ts | Add data jsonb to moderators permissions table model |
| packages/vitnode/src/database/admins.ts | Add data jsonb to admins permissions table model |
| packages/vitnode/src/components/ui/tooltip.tsx | React import style update |
| packages/vitnode/src/components/ui/toggle-group.tsx | React import style update |
| packages/vitnode/src/components/ui/textarea.tsx | React import style update |
| packages/vitnode/src/components/ui/tabs.tsx | React import style update |
| packages/vitnode/src/components/ui/table.tsx | React import style update |
| packages/vitnode/src/components/ui/switch.tsx | React import style update |
| packages/vitnode/src/components/ui/slider.tsx | React import style update |
| packages/vitnode/src/components/ui/sidebar.tsx | React import style update |
| packages/vitnode/src/components/ui/sheet.tsx | React import style update |
| packages/vitnode/src/components/ui/separator.tsx | React import style update |
| packages/vitnode/src/components/ui/select.tsx | React import style update |
| packages/vitnode/src/components/ui/scroll-area.tsx | React import style update |
| packages/vitnode/src/components/ui/radio-group.tsx | React import style update |
| packages/vitnode/src/components/ui/progress.tsx | React import style update |
| packages/vitnode/src/components/ui/popover.tsx | React import style update |
| packages/vitnode/src/components/ui/pagination.tsx | React import style update |
| packages/vitnode/src/components/ui/navigation-menu.tsx | React import style update |
| packages/vitnode/src/components/ui/native-select.tsx | React import style update |
| packages/vitnode/src/components/ui/menubar.tsx | React import style update |
| packages/vitnode/src/components/ui/label.tsx | React import style update |
| packages/vitnode/src/components/ui/item.tsx | React import style update |
| packages/vitnode/src/components/ui/input.tsx | React import style update |
| packages/vitnode/src/components/ui/input-otp.tsx | React import style update |
| packages/vitnode/src/components/ui/input-group.tsx | React import style update |
| packages/vitnode/src/components/ui/hover-card.tsx | React import style update |
| packages/vitnode/src/components/ui/dropdown-menu.tsx | React import style update |
| packages/vitnode/src/components/ui/drawer.tsx | React import style update |
| packages/vitnode/src/components/ui/direction.tsx | React import style update |
| packages/vitnode/src/components/ui/dialog.tsx | Update dialog transitions + React import style |
| packages/vitnode/src/components/ui/context-menu.tsx | React import style update |
| packages/vitnode/src/components/ui/command.tsx | React import style update |
| packages/vitnode/src/components/ui/combobox.tsx | React import style update |
| packages/vitnode/src/components/ui/collapsible.tsx | React import style update |
| packages/vitnode/src/components/ui/checkbox.tsx | React import style update |
| packages/vitnode/src/components/ui/chart.tsx | React import style update |
| packages/vitnode/src/components/ui/carousel.tsx | React import style update |
| packages/vitnode/src/components/ui/card.tsx | React import style update |
| packages/vitnode/src/components/ui/breadcrumb.tsx | React import style update |
| packages/vitnode/src/components/ui/avatar.tsx | React import style update |
| packages/vitnode/src/components/ui/aspect-ratio.tsx | React import style update |
| packages/vitnode/src/components/ui/alert.tsx | React import style update |
| packages/vitnode/src/components/ui/alert-dialog.tsx | Update alert-dialog transitions |
| packages/vitnode/src/components/ui/accordion.tsx | React import style update |
| packages/vitnode/src/components/theme-provider.tsx | React import style update |
| packages/vitnode/src/components/staff-permission/provider.tsx | New admin permission context + hooks + gate component |
| packages/vitnode/src/api/plugin.ts | Declare core staff permission catalog defaults |
| packages/vitnode/src/api/modules/users/users.module.ts | Add permissions route to users module |
| packages/vitnode/src/api/modules/users/routes/permissions.route.ts | New endpoint exposing moderator permissions |
| packages/vitnode/src/api/modules/admin/users/routes/verify-email.route.ts | Add adminStaffPermission + extra admin-target edit assertion |
| packages/vitnode/src/api/modules/admin/users/routes/update.route.ts | Add adminStaffPermission + extra admin-target edit assertion |
| packages/vitnode/src/api/modules/admin/users/routes/show.route.ts | Add adminStaffPermission + expose isAdmin flag |
| packages/vitnode/src/api/modules/admin/users/routes/list.route.ts | Add adminStaffPermission guard |
| packages/vitnode/src/api/modules/admin/users/routes/create.route.ts | Add adminStaffPermission guard |
| packages/vitnode/src/api/modules/admin/users/lib/assert-edit-user-permission.ts | New helper enforcing can_edit_admin when needed |
| packages/vitnode/src/api/modules/admin/staff/staff.admin.module.ts | Expand staff admin module routes |
| packages/vitnode/src/api/modules/admin/staff/routes/update-permissions.route.ts | New route to update staff entry permissions |
| packages/vitnode/src/api/modules/admin/staff/routes/show-permissions.route.ts | New route to show staff entry permissions |
| packages/vitnode/src/api/modules/admin/staff/routes/permission-catalog.route.ts | New route to return permission catalog |
| packages/vitnode/src/api/modules/admin/staff/routes/moderators.route.ts | Include data + protected in moderators listing |
| packages/vitnode/src/api/modules/admin/staff/routes/delete.route.ts | New route to delete staff entries |
| packages/vitnode/src/api/modules/admin/staff/routes/create.route.ts | New route to create staff entries |
| packages/vitnode/src/api/modules/admin/staff/routes/admins.route.ts | Include data + protected in admins listing |
| packages/vitnode/src/api/modules/admin/staff/lib/schema.ts | Refactor staff schemas + add permissions schemas |
| packages/vitnode/src/api/modules/admin/staff/lib/resolve-staff-edges.ts | Add unrestricted/protected/self fields to resolved edges |
| packages/vitnode/src/api/modules/admin/routes/session.route.ts | Return effective admin permissions in session response |
| packages/vitnode/src/api/middlewares/global.middleware.ts | Aggregate permissionStaff catalog into request core metadata |
| packages/vitnode/src/api/lib/staff-permission.ts | New helpers for permission checks + key generation |
| packages/vitnode/src/api/lib/route.ts | Add adminStaffPermission route guard support |
| packages/vitnode/src/api/lib/plugin.ts | Allow plugins to declare staff permission catalog |
| packages/vitnode/src/api/lib/permission-staff.ts | New types for staff permission catalog + grants |
| packages/vitnode/src/api/lib/check-staff-permission.ts | New permission resolution + assert/check helpers |
| packages/vitnode/scripts/prepare-database.ts | Seed protected staff entries with unrestricted data |
| apps/docs/src/locales/@vitnode/core/en.json | Mirror new core permission + staff UI strings |
| apps/docs/src/locales/@vitnode/blog/en.json | Mirror new blog permission labels |
| apps/docs/src/examples/hover-card.tsx | Docs copy tweak |
| apps/docs/src/app/[locale]/admin/(auth)/@breadcrumb/core/staff/moderators/page.tsx | Docs app breadcrumb slot for staff moderators |
| apps/docs/src/app/[locale]/admin/(auth)/@breadcrumb/core/staff/moderators/edit/[id]/page.tsx | Docs app breadcrumb slot for staff moderators edit |
| apps/docs/src/app/[locale]/admin/(auth)/@breadcrumb/core/staff/moderators/create/page.tsx | Docs app breadcrumb slot for staff moderators create |
| apps/docs/src/app/[locale]/admin/(auth)/@breadcrumb/core/staff/admins/page.tsx | Docs app breadcrumb slot for staff admins |
| apps/docs/src/app/[locale]/admin/(auth)/@breadcrumb/core/staff/admins/edit/[id]/page.tsx | Docs app breadcrumb slot for staff admins edit |
| apps/docs/src/app/[locale]/admin/(auth)/@breadcrumb/core/staff/admins/create/page.tsx | Docs app breadcrumb slot for staff admins create |
| apps/docs/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/users/staff/layout.tsx | Remove old docs app staff layout route |
| apps/docs/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/users/page.tsx | Gate docs app users page by permission |
| apps/docs/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/staff/moderators/page.tsx | Update docs app staff moderators page |
| apps/docs/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/staff/moderators/edit/[id]/page.tsx | New docs app staff moderators edit page |
| apps/docs/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/staff/moderators/create/page.tsx | New docs app staff moderators create page |
| apps/docs/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/staff/admins/page.tsx | Update docs app staff admins page |
| apps/docs/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/staff/admins/edit/[id]/page.tsx | New docs app staff admins edit page |
| apps/docs/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/staff/admins/create/page.tsx | New docs app staff admins create page |
| apps/docs/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/categories/page.tsx | Gate docs app blog categories page by permission |
| apps/docs/src/app/[locale]/(main)/(home)/page.tsx | Homepage copy tweak |
| apps/docs/migrations/meta/0004_snapshot.json | Add staff permissions column snapshot metadata |
| apps/docs/migrations/meta/_journal.json | Register new migrations |
| apps/docs/migrations/0005_stale_firebird.sql | Update JSON default for new staff permissions shape |
| apps/docs/migrations/0004_dark_iron_lad.sql | Add JSON column for staff permissions |
| apps/docs/content/docs/dev/working-with-users/staff-permissions.mdx | New staff permissions documentation |
| apps/docs/content/docs/dev/working-with-users/meta.json | Add new docs page to sidebar |
| apps/docs/content/docs/dev/plugins/admin-page.mdx | Document nav gating with staff permissions |
| apps/api/src/locales/@vitnode/core/en.json | Mirror new core permission + staff UI strings |
| apps/api/src/locales/@vitnode/blog/en.json | Mirror new blog permission labels |
| .gitignore | Ignore docs build output folder |
| { | ||
| title: t("admin.global.nav.users.roles"), | ||
| href: "/admin/core/users/roles", | ||
| }, |
| permissionStaff: { | ||
| moderator: { | ||
| users: ["can_edit"], | ||
| }, | ||
| admin: { | ||
| users: ["can_view", "can_create", "can_edit", "can_edit_admin"], | ||
| roles: ["can_manage"], | ||
| }, | ||
| }, |
Improving Documentation
pnpm lint:fixto fix formatting issues before opening the PR.Description
What?
Why?