Table of Contents

Permissions

Three kinds, not one

Kind Stored as Example Used for
Role (position, «منصب») a row in AspNetRoles, added from /admin/roles General Services Officer holding steps; holding permissions
Relation (Relations) nothing: a path through the organisation data line manager, branch officer, requester holding steps that follow the requester
Permission (Permission enum) granted to roles in RolePermissions ManageStock what the code guards

A relation is never a role, and the code never branches on a role's name: RoleKeys is a seed for seeding and tests, not a reference.

The permissions

Group Permission Allows
Requests ViewAllRequests Read every request
DeleteAnyRequest Soft-delete any request; remove a step's photos
RestoreDeletedRequest Restore a deleted request
CancelAnyRequest Cancel any request, a locked one included
ReassignApproval Hand an approval step to someone else
AmendAnyRequest Correct an open request's data, with a reason (moves a booking)
Administration ViewAdminDashboard The dashboard: late and stuck steps
ManageUsers Employee accounts, their roles, password resets
ManageOrganisation Branches and departments
ManageLookups Shared lists, their values and settings
ManageCatalog Service definitions and publishing
ManagePermissions The role-permission matrix (the highest privilege)
ImpersonateUsers Sign in as an employee, read-only and audited
ViewSystemLogs The server's log
ViewChangelog The release notes tab of the guide
Rooms ManageRooms Rooms, booking policy, closures, the floor plan
ViewRoomBookers Who booked each slot
OverrideBookings Book past the policy (logged as booking.overridden)
Reports ViewDepartmentReports Reports over the viewer's own department
ViewAllReports Reports over everything
Guide GuideDecisions, GuideRooms The approvals and the rooms parts of the user guide
Stock ManageStock The stock page, vouchers, low-stock and expiry notices

Values are stable integers; a retired value (10, 11) is never reused, because a stored grant would read it.

Default grants

Seeded once (Permissions.Defaults), then owned by the society from the matrix; never re-applied on start.

Role Permissions
SystemAdmin all
AdminAffairsManager ViewAllRequests, CancelAnyRequest, AmendAnyRequest, ViewAdminDashboard, ManageLookups, ManageRooms, ViewRoomBookers, OverrideBookings, ViewAllReports, ManageStock
GeneralServicesOfficer AmendAnyRequest, ManageRooms, ViewRoomBookers
Ceo, SupportSectorAssistantCeo ViewAllRequests, ViewAdminDashboard, ViewAllReports
every role GuideDecisions, GuideRooms (given once, Permissions.EveryPosition)

An employee with no role holds no permission: they submit what a service's audience allows and read the guide's first parts.

Enforcement

  • Policy-based authorization. Pages use [Authorize(Policy = "perm:X")], code asks Can(Permission.X); the policies are generated from the enum.
  • Resource access is one rule. Who may view a request is RequestAccess.MayView alone, for the page, the decision sheet and the attachment endpoints: the requester, the step holders, whoever was told a step is late, or ViewAllRequests.
  • Who may act on a step is RequestService.CanAct, with its SQL twins in Inbox; InboxTests compares them.
  • Containment. Acting on another account (impersonating, editing their card, resetting their password) requires holding every permission they hold (Permissions.Within), so nobody reaches a permission through someone else.
  • Audit. Every grant and revoke is written to the audit log (permission.granted, permission.revoked), and the matrix saves only on «حفظ».

Adding a permission

Add a value to Permission (src/ErpDarAlBer.Core/Domain/Permission.cs), its Arabic name in Permissions.NameAr, its explanation in PermissionHelp, optionally a default grant, then guard with the policy or Can. Never check a role name.