Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.laportenard.com/llms.txt

Use this file to discover all available pages before exploring further.

User roles

RoleOdoo groupAccess level
Managergroup_pos_managerFull access, price overrides, void authority
Cashiergroup_pos_userStandard POS, payments, split checks
Waiter(fallback)Order-taking only

Permission resolution

Permissions resolve through three layers, in order:
1

Factory defaults

Defined in permission_registry.py (PERMISSION_DEFAULTS) and mirrored in permissions.ts on the frontend.
2

Per-config role overrides

The nu.pos.permission.config model allows overriding defaults per POS configuration and role.
3

Per-user grant/deny

The nu.pos.permission.user.override model allows granting or denying specific permissions to individual users.
The bootstrap endpoint resolves permissions server-side and sends a flat permissions: Record<string, boolean> map per user.

Frontend permission check

// Primary: check resolved permissions map
hasPermission(user.permissions, 'void_item')

// Fallback: legacy FeatureGuards (when permissions is null)
canPerformAction('voidItem', user)
The canPerformAction() function bridges the legacy FeatureGuards system to the new permission system via an ACTION_TO_PERMISSION mapping.

Adding a new permission

1

Add the backend default

Add the key and default value to PERMISSION_DEFAULTS in nu_restaurant_pos/models/permission_registry.py.
2

Mirror on the frontend

Add the same key and default to PERMISSION_DEFAULTS in src/domain/users/permissions.ts.
3

Use in code

Check the permission with hasPermission() on the frontend or resolve_user_permissions() on the backend.
Both Python and TypeScript PERMISSION_DEFAULTS must stay in sync. A missing key on either side causes silent failures.

Security notes

  • Permission configuration models are writable only by base.group_system (admin) — managers cannot self-grant privileges
  • Role resolution uses user.has_group(), never config.read() group ID extraction (the read() output format is fragile)
  • The frontend rejects non-string role values to guard against Python False → JSON false propagation