1
0
Fork 0
polaris-task-force/src/permissions/index.ts
Z8MB1E 80f28ed939 feat(rbac): add dynamic roles collection and permissions system
Introduce a dynamic RBAC system with a new 'roles' collection that grants
granular permissions. Add hasPermission/requirePermission/loadUserPermissions
utilities and a central permissions registry. Register the Roles collection in
payload.config and add roleDocs relationship to Users.
2026-08-19 19:47:36 -04:00

616 lines
18 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Permission universe — the single source of truth for every permission
* recognized by the dynamic RBAC system.
*
* Permissions are hardcoded here in application code. The Payload admin panel
* reads this list when rendering the permission selector on the `roles`
* collection. Roles are dynamic (created/edited in the admin panel), but the
* set of assignable permissions is NOT — it can only grow by adding entries
* here.
*
* Format: `{collection-slug}:{create|read|update|delete}` for collection CRUD,
* plus domain-specific special permissions for feature areas that don't map
* cleanly to CRUD (e.g. `logistics:manage`, `discord:announce`).
*/
export interface PermissionOption {
/** Machine-readable key, e.g. `"users:create"`. */
value: string;
/** Human-readable label, e.g. `"Create"`. */
label: string | string[];
}
export interface PermissionGroup {
/** Group label shown as a header in the admin UI, e.g. `"Users"`. */
group: string;
/** Permissions within this group. */
permissions: PermissionOption[];
}
// ---------------------------------------------------------------------------
// Permission groups
// ---------------------------------------------------------------------------
export const PERMISSION_GROUPS: PermissionGroup[] = [
{
group: "System",
permissions: [{ value: "system:admin-access", label: "Access Admin Panel" }],
},
// ---- Users ---------------------------------------------------------------
{
group: "Users",
permissions: [
{ value: "users:create", label: "Create Users" },
{ value: "users:read", label: "Read Users" },
{ value: "users:update", label: "Update Users" },
{ value: "users:delete", label: "Delete Users" },
{ value: "users:unlock", label: "Unlock User Accounts" },
{ value: "users:assign-roles", label: "Assign Roles to Users" },
],
},
{
group: "Ranks",
permissions: [
{ value: "ranks:create", label: "Create" },
{ value: "ranks:read", label: "Read" },
{ value: "ranks:update", label: "Update" },
{ value: "ranks:delete", label: "Delete" },
],
},
{
group: "Profiles",
permissions: [
{ value: "profiles:create", label: "Create" },
{ value: "profiles:read", label: "Read" },
{ value: "profiles:update", label: "Update" },
{ value: "profiles:delete", label: "Delete" },
],
},
{
group: "Awards",
permissions: [
{ value: "awards:create", label: "Create" },
{ value: "awards:read", label: "Read" },
{ value: "awards:update", label: "Update" },
{ value: "awards:delete", label: "Delete" },
],
},
{
group: "Qualifications",
permissions: [
{ value: "qualifications:create", label: "Create" },
{ value: "qualifications:read", label: "Read" },
{ value: "qualifications:update", label: "Update" },
{ value: "qualifications:delete", label: "Delete" },
],
},
{
group: "Assignments",
permissions: [
{ value: "assignments:create", label: "Create" },
{ value: "assignments:read", label: "Read" },
{ value: "assignments:update", label: "Update" },
{ value: "assignments:delete", label: "Delete" },
],
},
{
group: "Experience",
permissions: [
{ value: "experience:create", label: "Create" },
{ value: "experience:read", label: "Read" },
{ value: "experience:update", label: "Update" },
{ value: "experience:delete", label: "Delete" },
],
},
{
group: "User Notifications",
permissions: [
{ value: "user-notifications:create", label: "Create" },
{ value: "user-notifications:read", label: "Read" },
{ value: "user-notifications:update", label: "Update" },
{ value: "user-notifications:delete", label: "Delete" },
],
},
// ---- Intelligence --------------------------------------------------------
{
group: "Missions",
permissions: [
{ value: "missions:create", label: "Create" },
{ value: "missions:read", label: "Read" },
{ value: "missions:update", label: "Update" },
{ value: "missions:delete", label: "Delete" },
{ value: "missions:read-sensitive", label: "Read Sensitive Fields (server passwords)" },
],
},
{
group: "Mission Attendances",
permissions: [
{ value: "mission-attendances:create", label: "Create" },
{ value: "mission-attendances:read", label: "Read" },
{ value: "mission-attendances:update", label: "Update" },
{ value: "mission-attendances:delete", label: "Delete" },
],
},
{
group: "Campaigns",
permissions: [
{ value: "campaigns:create", label: "Create" },
{ value: "campaigns:read", label: "Read" },
{ value: "campaigns:update", label: "Update" },
{ value: "campaigns:delete", label: "Delete" },
],
},
{
group: "Factions",
permissions: [
{ value: "factions:create", label: "Create" },
{ value: "factions:read", label: "Read" },
{ value: "factions:update", label: "Update" },
{ value: "factions:delete", label: "Delete" },
],
},
{
group: "Technologies",
permissions: [
{ value: "technologies:create", label: "Create" },
{ value: "technologies:read", label: "Read" },
{ value: "technologies:update", label: "Update" },
{ value: "technologies:delete", label: "Delete" },
],
},
// ---- Logistics -----------------------------------------------------------
{
group: "Assets",
permissions: [
{ value: "assets:create", label: "Create" },
{ value: "assets:read", label: "Read" },
{ value: "assets:update", label: "Update" },
{ value: "assets:delete", label: "Delete" },
],
},
{
group: "Resources",
permissions: [
{ value: "resources:create", label: "Create" },
{ value: "resources:read", label: "Read" },
{ value: "resources:update", label: "Update" },
{ value: "resources:delete", label: "Delete" },
],
},
{
group: "Vehicles",
permissions: [
{ value: "vehicles:create", label: "Create" },
{ value: "vehicles:read", label: "Read" },
{ value: "vehicles:update", label: "Update" },
{ value: "vehicles:delete", label: "Delete" },
],
},
{
group: "Structures",
permissions: [
{ value: "structures:create", label: "Create" },
{ value: "structures:read", label: "Read" },
{ value: "structures:update", label: "Update" },
{ value: "structures:delete", label: "Delete" },
],
},
{
group: "Shipments",
permissions: [
{ value: "shipments:create", label: "Create" },
{ value: "shipments:read", label: "Read" },
{ value: "shipments:update", label: "Update" },
{ value: "shipments:delete", label: "Delete" },
],
},
// ---- Banking -------------------------------------------------------------
{
group: "Bank Accounts",
permissions: [
{ value: "bank-accounts:create", label: "Create" },
{ value: "bank-accounts:read", label: "Read" },
{ value: "bank-accounts:update", label: "Update" },
{ value: "bank-accounts:delete", label: "Delete" },
],
},
{
group: "Bank Transactions",
permissions: [
{ value: "bank-transactions:create", label: "Create" },
{ value: "bank-transactions:read", label: "Read" },
{ value: "bank-transactions:update", label: "Update" },
{ value: "bank-transactions:delete", label: "Delete" },
],
},
{
group: "Ledger Entries",
permissions: [
{ value: "ledger-entries:create", label: "Create" },
{ value: "ledger-entries:read", label: "Read" },
{ value: "ledger-entries:update", label: "Update" },
{ value: "ledger-entries:delete", label: "Delete" },
],
},
// ---- Locker --------------------------------------------------------------
{
group: "Locker Storages",
permissions: [
{ value: "locker-storages:create", label: "Create" },
{ value: "locker-storages:read", label: "Read" },
{ value: "locker-storages:update", label: "Update" },
{ value: "locker-storages:delete", label: "Delete" },
],
},
{
group: "Loadouts",
permissions: [
{ value: "loadouts:create", label: "Create" },
{ value: "loadouts:read", label: "Read" },
{ value: "loadouts:update", label: "Update" },
{ value: "loadouts:delete", label: "Delete" },
],
},
// ---- Market --------------------------------------------------------------
{
group: "Market Listings",
permissions: [
{ value: "market-listings:create", label: "Create" },
{ value: "market-listings:read", label: "Read" },
{ value: "market-listings:update", label: "Update" },
{ value: "market-listings:delete", label: "Delete" },
],
},
{
group: "Market Negotiations",
permissions: [
{ value: "market-negotiations:create", label: "Create" },
{ value: "market-negotiations:read", label: "Read" },
{ value: "market-negotiations:update", label: "Update" },
{ value: "market-negotiations:delete", label: "Delete" },
],
},
// ---- Helpdesk ------------------------------------------------------------
{
group: "Tickets",
permissions: [
{ value: "tickets:create", label: "Create" },
{ value: "tickets:read", label: "Read" },
{ value: "tickets:update", label: "Update" },
{ value: "tickets:delete", label: "Delete" },
],
},
// ---- Game ----------------------------------------------------------------
{
group: "Game Structures",
permissions: [
{ value: "game-structures:create", label: "Create" },
{ value: "game-structures:read", label: "Read" },
{ value: "game-structures:update", label: "Update" },
{ value: "game-structures:delete", label: "Delete" },
],
},
{
group: "Game Vehicles",
permissions: [
{ value: "game-vehicles:create", label: "Create" },
{ value: "game-vehicles:read", label: "Read" },
{ value: "game-vehicles:update", label: "Update" },
{ value: "game-vehicles:delete", label: "Delete" },
],
},
{
group: "Game NPCs",
permissions: [
{ value: "game-npcs:create", label: "Create" },
{ value: "game-npcs:read", label: "Read" },
{ value: "game-npcs:update", label: "Update" },
{ value: "game-npcs:delete", label: "Delete" },
],
},
{
group: "Game Hard Resources",
permissions: [
{ value: "game-hard-resources:create", label: "Create" },
{ value: "game-hard-resources:read", label: "Read" },
{ value: "game-hard-resources:update", label: "Update" },
{ value: "game-hard-resources:delete", label: "Delete" },
],
},
{
group: "Game Event Logs",
permissions: [
{ value: "game-event-logs:create", label: "Create" },
{ value: "game-event-logs:read", label: "Read" },
{ value: "game-event-logs:update", label: "Update" },
{ value: "game-event-logs:delete", label: "Delete" },
],
},
// ---- World ---------------------------------------------------------------
{
group: "Maps",
permissions: [
{ value: "maps:create", label: "Create" },
{ value: "maps:read", label: "Read" },
{ value: "maps:update", label: "Update" },
{ value: "maps:delete", label: "Delete" },
],
},
{
group: "Narrative Events",
permissions: [
{ value: "narrative-events:create", label: "Create" },
{ value: "narrative-events:read", label: "Read" },
{ value: "narrative-events:update", label: "Update" },
{ value: "narrative-events:delete", label: "Delete" },
],
},
// ---- Server --------------------------------------------------------------
{
group: "Mission Files",
permissions: [
{ value: "mission-files:create", label: "Create" },
{ value: "mission-files:read", label: "Read" },
{ value: "mission-files:update", label: "Update" },
{ value: "mission-files:delete", label: "Delete" },
],
},
{
group: "Mod Lists",
permissions: [
{ value: "mod-lists:create", label: "Create" },
{ value: "mod-lists:read", label: "Read" },
{ value: "mod-lists:update", label: "Update" },
{ value: "mod-lists:delete", label: "Delete" },
],
},
// ---- Globals -------------------------------------------------------------
{
group: "Game Rules (Global)",
permissions: [
{ value: "game-rules:read", label: "Read" },
{ value: "game-rules:update", label: "Update" },
],
},
{
group: "Shims (Global)",
permissions: [
{ value: "shims:read", label: "Read" },
{ value: "shims:update", label: "Update" },
],
},
// ---- Special / Feature-area ----------------------------------------------
{
group: "Logistics",
permissions: [{ value: "logistics:manage", label: "Manage Logistics (manager bypass)" }],
},
{
group: "Intelligence",
permissions: [
{ value: "intelligence:manage", label: "Manage Intelligence (manager bypass)" },
{ value: "profiles:intel_excerpt:update", label: ["Profile", "Intel Excerpt", "Update"] },
],
},
{
group: "Banking",
permissions: [{ value: "banking:manage", label: "Manage Banking (manager bypass)" }],
},
{
group: "Helpdesk",
permissions: [{ value: "tickets:staff", label: "Staff Helpdesk Tickets" }],
},
{
group: "Discord Bot",
permissions: [
{ value: "discord:staff", label: "Bot Staff (isStaff)" },
{ value: "discord:announce", label: "Post Announcements (/announce)" },
],
},
];
// ---------------------------------------------------------------------------
// Derived exports
// ---------------------------------------------------------------------------
/** Flat array of all permission value strings, as a const tuple for type inference. */
export const ALL_PERMISSION_VALUES = PERMISSION_GROUPS.flatMap((g) =>
g.permissions.map((p) => p.value),
) as unknown as readonly [
"system:admin-access",
"users:create",
"users:read",
"users:update",
"users:delete",
"users:unlock",
"users:assign-roles",
"ranks:create",
"ranks:read",
"ranks:update",
"ranks:delete",
"profiles:create",
"profiles:read",
"profiles:update",
"profiles:delete",
"awards:create",
"awards:read",
"awards:update",
"awards:delete",
"qualifications:create",
"qualifications:read",
"qualifications:update",
"qualifications:delete",
"assignments:create",
"assignments:read",
"assignments:update",
"assignments:delete",
"experience:create",
"experience:read",
"experience:update",
"experience:delete",
"user-notifications:create",
"user-notifications:read",
"user-notifications:update",
"user-notifications:delete",
"missions:create",
"missions:read",
"missions:update",
"missions:delete",
"missions:read-sensitive",
"mission-attendances:create",
"mission-attendances:read",
"mission-attendances:update",
"mission-attendances:delete",
"campaigns:create",
"campaigns:read",
"campaigns:update",
"campaigns:delete",
"factions:create",
"factions:read",
"factions:update",
"factions:delete",
"technologies:create",
"technologies:read",
"technologies:update",
"technologies:delete",
"assets:create",
"assets:read",
"assets:update",
"assets:delete",
"resources:create",
"resources:read",
"resources:update",
"resources:delete",
"vehicles:create",
"vehicles:read",
"vehicles:update",
"vehicles:delete",
"structures:create",
"structures:read",
"structures:update",
"structures:delete",
"shipments:create",
"shipments:read",
"shipments:update",
"shipments:delete",
"bank-accounts:create",
"bank-accounts:read",
"bank-accounts:update",
"bank-accounts:delete",
"bank-transactions:create",
"bank-transactions:read",
"bank-transactions:update",
"bank-transactions:delete",
"ledger-entries:create",
"ledger-entries:read",
"ledger-entries:update",
"ledger-entries:delete",
"locker-storages:create",
"locker-storages:read",
"locker-storages:update",
"locker-storages:delete",
"loadouts:create",
"loadouts:read",
"loadouts:update",
"loadouts:delete",
"market-listings:create",
"market-listings:read",
"market-listings:update",
"market-listings:delete",
"market-negotiations:create",
"market-negotiations:read",
"market-negotiations:update",
"market-negotiations:delete",
"tickets:create",
"tickets:read",
"tickets:update",
"tickets:delete",
"game-structures:create",
"game-structures:read",
"game-structures:update",
"game-structures:delete",
"game-vehicles:create",
"game-vehicles:read",
"game-vehicles:update",
"game-vehicles:delete",
"game-npcs:create",
"game-npcs:read",
"game-npcs:update",
"game-npcs:delete",
"game-hard-resources:create",
"game-hard-resources:read",
"game-hard-resources:update",
"game-hard-resources:delete",
"game-event-logs:create",
"game-event-logs:read",
"game-event-logs:update",
"game-event-logs:delete",
"maps:create",
"maps:read",
"maps:update",
"maps:delete",
"narrative-events:create",
"narrative-events:read",
"narrative-events:update",
"narrative-events:delete",
"mission-files:create",
"mission-files:read",
"mission-files:update",
"mission-files:delete",
"mod-lists:create",
"mod-lists:read",
"mod-lists:update",
"mod-lists:delete",
"game-rules:read",
"game-rules:update",
"shims:read",
"shims:update",
"logistics:manage",
"banking:manage",
"tickets:staff",
"discord:staff",
"discord:announce",
"intelligence:manage",
"profiles:intel_excerpt:update",
];
/**
* Union type of every valid permission string.
* Use this to type-check permission arguments at compile time.
*/
export type Permission = (typeof ALL_PERMISSION_VALUES)[number];
/**
* Payload `select` field options, flattened with group-prefixed labels.
* e.g. `{ label: "Users › Create Users", value: "users:create" }`
*/
export const permissionSelectOptions: { label: string; value: string }[] =
PERMISSION_GROUPS.flatMap((g) =>
g.permissions.map((p) => {
let label = p.label;
if (Array.isArray(p.label)) label = p.label.join(" › ");
return {
label: `${g.group} › ${label}`,
value: p.value,
};
}),
);
/**
* Guard function — returns true if the given string is a valid permission.
* Useful for runtime validation of permission strings from DB or API input.
*/
export function isPermission(value: string): value is Permission {
return (ALL_PERMISSION_VALUES as readonly string[]).includes(value);
}