Permissions (RBAC & FGAC)
The 64-bit BigInt permission architecture.
Waylog requires an organizational structure capable of supporting thousands of VTC members with granular control. We implemented a system heavily inspired by Discord, combining Role-Based Access Control (RBAC) with Fine-Grained Access Control (FGAC).
The Bitfield Architecture
Instead of utilizing rigid string enumerations (e.g., "ADMIN", "MODERATOR"), permissions in Waylog are mapped to the bits of a 64-bit integer (BigInt).
Currently, 27 of the 64 available bits are allocated across 8 logical categories:
- General (4 bits): Viewing, editing, and deleting the VTC.
- Members (4 bits): Kicking members, viewing audit logs.
- Roles (4 bits): Managing the role hierarchy.
- Applications (4 bits): Handling recruitment pipelines.
- Jobs/Dispatch (4 bits): Dispatching deliveries and viewing fleet telemetry.
- Convoys/Events (3 bits): Event organization.
- Announcements (3 bits): Internal communications.
- Admin (5 bits): High-level organizational control.
All bitwise constants are exported from the shared @waylog/permissions package.
export const VTC_GENERAL_VIEW = 1n << 0n;
export const VTC_MEMBERS_MANAGE = 1n << 5n;
export const VTC_JOBS_DISPATCH_CREATE = 1n << 17n;Role Templates & Assignment
VTC Owners can create infinite custom roles, establishing a hierarchy using the position integer. Waylog provides sensible defaults:
- OWNER: Automatically granted all 27 bits.
- EVERYONE: The baseline role, typically restricted to
VTC_GENERAL_VIEW. - DISPATCHER: Granted specialized bits within the Jobs/Dispatch category.
Members can be assigned multiple roles; their baseline permissions are the combined total (Bitwise OR) of all assigned roles.
Fine-Grained Access Control (FGAC)
Role templates are powerful, but sometimes a specific user needs a unique exception. The vtcMember record includes two dedicated fields:
permissionOverrides(BigInt): Explicitly grants specific permissions to a user, regardless of their roles.permissionDenials(BigInt): Explicitly revokes specific permissions from a user, overriding any roles that might grant them.
Computing Effective Permissions
To determine a user's actual capabilities, the server evaluates their "effective" permissions on the fly:
function computeEffectivePermissions(
rolePermissions: bigint[],
overrides: bigint,
denials: bigint,
isOwner: boolean
): bigint {
if (isOwner) return ALL_PERMISSIONS;
// Combine roles (OR)
const basePerms = rolePermissions.reduce((acc, curr) => acc | curr, 0n);
// Add overrides (OR), then remove denials (AND NOT)
return (basePerms | overrides) & ~denials;
}In the Fastify API, a requirePermission(VTC_MEMBERS_MANAGE) hook automatically performs this computation, rejecting unauthorized requests at the routing layer.