Skip to content

Permissions

Who may do what, generated from the code: the global roles of app/modules/permissions and the per-object permissions the repositories build, each with every place checking it. See Permissions for how the two work and where a new check goes. Server checks throw a 403 (requireRole, requirePermission), client ones only decide what is shown (useHasRole, useHasPermission), and hasPermission / roles.includes outside .server files may run on either side.

Global roles

Granted to the logged in user by userRoles() of mapper.server.ts.

RoleGranted whenChecked in
ADMINisAdmin(user)
Either sideTrophies
STAFFisStaff(user) || isAdmin(user)
Either sideTrophies
PLUS_SERVER_MEMBERtypeof user.plusTier === "number"
ClientLFG
VIDEO_ADDERuser.isVideoAdder
ServerVods
ClientVods
ARTISTuser.isArtist
ServerArt
CALENDAR_EVENT_ADDERuserDiscordIdIsAged(user) || isSupporter(user)
ServerCalendar
ClientCalendar
TOURNAMENT_ADDERuser.isTournamentOrganizer || isSupporter(user)
API_ACCESSERuser.isTournamentOrganizer || user.isApiAccesser || isSupporter(user)
Either sideApi
QAisQa(user)
Either sideTrophies
DEVisDev(user)
ServerAuth ×2
Either sideTrophies
SUPPORTER

patrons of "Supporter" tier or higher

isSupporter(user)
Either sideImage export
MINOR_SUPPORT

patrons of "Support" tier or higher

typeof user.patronTier === "number"
Either sideapp ×4

By feature

Each feature's Permissions page lists the per-object permissions it grants, who each is granted to and every check of it (other features' included), and the roles its code checks.

FeatureGrantsChecks in its code
Admin17 checks
Api1 check
ArtEDIT, UNLINK5 checks
AssociationsREMOVE, MANAGE, MANAGE_INVITE_LINK4 checks
Auth4 checks
Availability2 checks
BadgesMANAGE6 checks
BuildsEDIT0 checks
CalendarEDIT, DELETE, REPORT_WINNERS13 checks
ChatVIEW, POST, OBSERVE3 checks
Events1 check
Image export1 check
Img upload2 checks
Leaderboards2 checks
LFGEDIT, DELETE8 checks
Plus suggestionsEDIT, DELETE4 checks
Plus voting0 checks
Scanner2 checks
ScrimsMANAGE_REQUESTS, DELETE_POST, CANCEL, MANAGE_TRACKING6 checks
SendouQ1 check
SendouQ match1 check
Settings1 check
TeamEDIT, MANAGE_ROSTER, DELETE9 checks
TournamentADMIN, ORGANIZE, MANAGE_MATCHES, EDIT_EVENT_INFO, EDIT_IN_GAME_NAMES1 check
Tournament bracket8 checks
Tournament organizationEDIT, BAN12 checks
TrophiesEDIT6 checks
User page10 checks
VodsEDIT6 checks
Voice0 checks

Outside the system

Best-effort flags, some of them deliberate: the permissions doc lists the boundaries.

Granted but never checked (1 permission): no check of that name matches the feature and nothing reads it directly.

  • chat: OBSERVE

Checked but never granted (0 checks): no feature, or no single one, grants a permission of that name.

Read directly (8 reads): x.permissions.NAME.includes(…) skips hasPermission and with it the admin bypass.

Checks of who the user is (17 calls): isAdmin, isStaff, isDev, isQa and isSupporter called outside app/modules/permissions. Authorizing an action on an object with one is a bug, a role or permission should decide it.