Permission catalogue

The vocabulary is src/app/shared/users/user-permissions.enum.ts — 40 codes. Mechanics (the two deny filters, the four gating mechanisms, supplier-scoped grants and sub-permissions) are in authorisation.

Client-side gating is advisory. The backend enforces every protected operation. A code with no front-end enforcement listed below is still meaningful server-side.

The two deny filters

These are restrictions, not grants — holding one removes access.

Code Enforced in

REST_UW_ACCESS

Route clauses in suppliers/, crm-tools/tasks-routing, emails/, manage/, marketplaces/, processes/, reports/, underwriting/; sidenav-menu.component.html; a restricted-access body class from src/app/app.component.ts; search-overlay.component.ts; the supplier box headers (both generations); additional-business-owners, kyc-documentation, supplier-general, supplier-underwriting, supplier-information, supplier-business-address, underwriting-daily, underwriting-initial, ucc-list; and the KYC guardrail audit trail in shared/monitor.service.ts.

ADVANCE_AUDITORS

The same route tables and sidebar clauses, plus suppliers/store/supplier/supplier.effects.ts (funding, balance and contract calls are replaced with of(null)), crm-tools/store/crm.effects.ts, spinner-button.component.html, supplier.component.html, and ~12 underwriting card templates (agreement-review, amazon-information, credit-check, international-supplier, personal-background-check, underwriting-files, underwriting-initial-header, background-report-card-header, uw-review, …). Also the KYC guardrail trail.

The three reusable route spreads that combine them are defined in suppliers/suppliers-routing.routes.ts — RESTRICTED_UW_ACCESS_CONFIG, RESTRICTED_AUDITORS_ACCESS_CONFIG, RESTRICTED_REST_UW_ACCESS_ONLY_CONFIG. See the route catalogue.

Login and session

Code Governs / enforced in

AUTH_TOKEN

Token issuance. No front-end check.

SUP_LOGIN

Supplier-side login. No front-end check.

INT_LOGIN

Internal login. Used as a filter in UsersService.getUsers() — ?permCode=INT_LOGIN selects internal users.

DELETED

Soft-deleted account marker. No front-end check.

Broad roles

Code Governs / enforced in

INT_SUPER_USER

Broad administrative access. No explicit front-end check — it is a backend role.

VIEW_ONLY

Read-only access. No explicit front-end check.

FINANCE

Allow-list on /suppliers/:key/underwriting/background-reports ({ only: FINANCE }). Also checked imperatively in supplier-marketplace-edit.component.ts (hasPermission), marketplace-access-details.component.ts (checkPermission), edit-marketplace-statement.component.ts, supplier-underwriting.component.ts, ucc-create.component.ts, and supplier-general.component.html.

MARKETING

No explicit front-end check.

CUST_SERVICE

supplier-underwriting/supplier-information/supplier-information.component.ts.

Sales

No explicit front-end check. Note the non-uppercase enum value.

UNDERWRITING

No explicit front-end check.

PROD_MGR

No explicit front-end check.

US (value 'us')

suppliers/supplier/cancel-supplier/cancel-supplier.component.ts. Lowercase value.

DEV

Allow-list on /admin ({ only: DEV, redirectTo: '/' }) and the DEV Admin sidebar item (*ngxPermissionsOnly). Also checked in documentation-card-header.component.ts, uw-personal-checks-card.component.ts and advance-offer-summary.component.ts.

dev_support

edit-marketplace-statement.component.ts. Lowercase value. Does not grant /admin.

Administration

Code Governs / enforced in

INT_UPDATE

General update rights. No explicit front-end check.

INT_PERMS_ADM

Users and permission groups (/manage/users, /manage/perm-groups). Enforced by the backend; no route clause.

INT_GLOBAL_SETTINGS

Global settings. Checked in manage/onboarding/onboarding-list.component.ts and onboarding-mp-list.component.ts.

INT_EMAIL_SETTINGS

Email settings. Checked in manage/email-settings/email-settings-list/email-settings-list.component.ts.

INT_RULES_UPDATE

Event rules. No explicit front-end check (rules-list.component.ts checks CRM_ADMIN instead).

INT_REP_ADMIN

Report administration. Checked in reports/report-list/report-list.component.ts.

CRM_ADMIN

The broadest imperative permission in the front end: manage/event-rules-2, manage/event-rules/rules-list, manage/global-settings, manage/month-end-close, manage/onboarding/onboarding-list and onboarding-mp-list, manage/email-settings/email-settings-list, shared/sidenav/sidenav-menu/sidenav-menu.component.ts, and UserModel.isSuperUser() — which is a CRM_ADMIN check despite its name.

Money operations

Code Governs

INT_MP_PMTS

Marketplace payments (Add MP Payment, Add Zero MP Payment).

INT_RCV

Receivables (Add receivable).

INT_XACT_CNCL

Transaction cancellation.

INT_FEE_UPD

Fee updates (Adjust Payability Fee, the fees tab).

INT_PMT_ADMIN

Payment administration (batches).

INT_PMT_REVIEW

Payment review (batch approval).

MANAGE_PMT

Payment management.

MANAGE_BAD_DEBT

Write-offs and bad-debt recovery.

None of these carry an explicit front-end check in the current code — they are enforced by the backend, and the corresponding UI is reached through the Actions menu. See lifecycle actions and transactions.

Supplier data

Code Governs

INT_SUP_CRED

Supplier credentials (password reset, login-as-supplier).

MANAGE_LINKING_PAYMENT_GATEWAYS

Linking payment gateways to a marketplace record. See marketplaces.

Sub-permissions

The only codes checked through SubPermissionsGuard and UsersService.checkPermission:

Code Enforced in

MP_LOANS_MODIFY

Route data.requireOneOfSubPermissions on /suppliers/:key/amazon-lending/add-loan and …/loan/:loanKey; supplier-amazon-lending-list.component.ts and supplier-amazon-lending-loan.component.ts (checkPermission).

MP_LOANS_DELETE

Route data on …/loan/:loanKey; supplier-amazon-lending-loan.component.ts.

MP_STATEMENTS_MODIFY

supplier-marketplace-statements.component.ts.

MP_STATEMENTS_DELETE

supplier-marketplace-statements.component.ts.

Sub-permissions are resolved via GET perms/:permCode/sub-perms, and are also what EvaComponent forwards to EVA as EvaPermissions. Note the cache in UsersService.getPermissionSubPerms ignores permCode — see authorisation.

Allow-list clauses (the only two)

Route Clause

/admin

{ only: DEV, redirectTo: '/' }

/suppliers/:key/underwriting/background-reports

{ only: FINANCE }

An only clause is an allow-list: it blocks everyone without that exact code, including super users. FINANCE on background reports and DEV on /admin behave that way deliberately.

Permission models

Model Fields

UserPermModel

permCode, permDesc, supplierKey (non-null = supplier-scoped grant), loginPermKey (the grant id, needed to revoke).

PermissionBaseModel

generalPerm, permCode, permDesc.

PermissionModel (extends the above)

assignable (may be granted in the UI), specSupPerm (may be supplier-scoped), type = 'group', plus id/key/name getters.

ngx-permissions is loaded with perms.map(p ⇒ p.permCode) — the supplierKey scope is discarded. Route and template gating are therefore scope-blind. Only UsersService.checkPermission (and the backend) can honour a supplier-scoped grant.

Checking permissions in code

Call Returns

NgxPermissionsService.getPermission(code)

Synchronous — the object or undefined.

NgxPermissionsService.hasPermission(code)

Promise<boolean>.

UsersService.checkPermission(code, user?)

Observable<boolean>.

UsersService.checkPermissions(codes, user)

Observable<boolean> — all codes.

UsersService.checkGeneralPermission(s)

Observable<boolean> — checks the generalPerm flag.

All five are in live use. Match the local convention of the file you are editing.

Administering grants

Operation Endpoint

List permissions/groups

GET perms

A user’s grants

GET logins/:loginKey/perms

Sub-permissions of a permission

GET perms/:permCode/sub-perms

Grant

addPermissionToLogin(loginKey, { permCode, supplierKey })

Revoke

removePermissionFromLogin(loginKey, loginPermKey) — by grant id, not code

See manage.

Adding a permission

  1. Add the code to USER_PERMISSION — matching the backend’s exact string, including any non-uppercase casing.

  2. Gate the route (data.permissions) and/or the template (*ngxPermissionsOnly / *ngxPermissionsExcept), and update the sidebar entry to match.

  3. For a sub-permission, use data.requireOneOfSubPermissions with SubPermissionsGuard.

  4. Add a row to this page and, if it changes a route, to the route catalogue.