diff --git a/src/Meezi.Core/Authorization/Permission.cs b/src/Meezi.Core/Authorization/Permission.cs index 4cd2b7e..37ac527 100644 --- a/src/Meezi.Core/Authorization/Permission.cs +++ b/src/Meezi.Core/Authorization/Permission.cs @@ -5,37 +5,135 @@ namespace Meezi.Core.Authorization; /// truth for authorization — controllers check a rather /// than hard-coding role names, so the role→capability mapping lives in exactly /// one place (). +/// +/// Granularity is "full CRUD per module + distinct sensitive actions": each page +/// has a View capability, record modules split Create/Edit/Delete, and high-risk +/// operations (void, refund, discount, comp, cash drawer, export) are their own +/// permissions so an owner can grant day-to-day work without the dangerous bits. +/// +/// Names are persisted (custom roles store them by name in JSON, and they ride in +/// the JWT). Renaming or removing a value is a breaking change — add, don't rename. /// public enum Permission { - // Café-level administration (Owner only) + // ── Café administration (owner tier) ────────────────────────────────────── + ViewCafeSettings, ManageCafeSettings, + ManageDiscoverProfile, + ViewBilling, ManageBilling, - ManageBranches, - - // Management (Owner + Manager) - ManageStaff, - ManageMenu, - ManageInventory, - ManageExpenses, - ManageTaxes, - ManageCoupons, - ManageReservations, - ManageTables, - ViewReports, - ReviewLeave, - ManageSalaries, + ViewBranches, + CreateBranch, + EditBranch, + DeleteBranch, + ManageRoles, + ViewPrintSettings, ManagePrintSettings, - // Front-of-house operations + // ── Taxes ───────────────────────────────────────────────────────────────── + ViewTaxes, + CreateTax, + EditTax, + DeleteTax, + + // ── Staff & HR ────────────────────────────────────────────────────────────── + ViewStaff, + CreateStaff, + EditStaff, + DeleteStaff, + /// Assign per-branch roles / org structure (distinct from editing a record). + ManageStaff, + ManageStaffCredentials, + ViewAttendance, + ManageAttendance, + ViewSchedules, + ManageSchedules, + ViewLeave, + ReviewLeave, + ViewSalaries, + ManageSalaries, + + // ── Menu ────────────────────────────────────────────────────────────────── + ViewMenu, + CreateMenuItem, + EditMenuItem, + DeleteMenuItem, + + // ── Inventory ─────────────────────────────────────────────────────────────── + ViewInventory, + CreateInventory, + EditInventory, + DeleteInventory, + + // ── Tables ────────────────────────────────────────────────────────────────── + ViewTables, + ManageTables, + + // ── Reservations ────────────────────────────────────────────────────────── + ViewReservations, + CreateReservation, + EditReservation, + DeleteReservation, + + // ── Orders & POS ────────────────────────────────────────────────────────── + ViewOrders, ProcessOrders, + EditOrder, + VoidOrder, + RefundOrder, + ApplyDiscount, + CompOrder, HandlePayments, + UpdateOrderStatus, + + // ── Register / cash ────────────────────────────────────────────────────── OperateRegister, + OpenCashDrawer, + + // ── Queue ───────────────────────────────────────────────────────────────── + ViewQueue, ManageQueue, - // Kitchen + // ── Kitchen ─────────────────────────────────────────────────────────────── ViewKitchen, + ManageKitchenStations, - // Delivery + // ── Delivery ────────────────────────────────────────────────────────────── + ViewDelivery, HandleDelivery, + AssignDelivery, + + // ── Customers / CRM ─────────────────────────────────────────────────────── + ViewCustomers, + CreateCustomer, + EditCustomer, + DeleteCustomer, + + // ── Coupons ─────────────────────────────────────────────────────────────── + ViewCoupons, + CreateCoupon, + EditCoupon, + DeleteCoupon, + + // ── SMS / marketing ────────────────────────────────────────────────────── + ViewSms, + SendSms, + ManageSmsSettings, + + // ── Reviews ─────────────────────────────────────────────────────────────── + ViewReviews, + ManageReviews, + + // ── Reports & finance ───────────────────────────────────────────────────── + ViewReports, + ExportReports, + ViewAuditLog, + ViewFinancials, + ManageFinancials, + + // ── Expenses ────────────────────────────────────────────────────────────── + ViewExpenses, + CreateExpense, + EditExpense, + DeleteExpense, } diff --git a/src/Meezi.Core/Authorization/RolePermissions.cs b/src/Meezi.Core/Authorization/RolePermissions.cs index 9fc516d..dd98ed2 100644 --- a/src/Meezi.Core/Authorization/RolePermissions.cs +++ b/src/Meezi.Core/Authorization/RolePermissions.cs @@ -1,64 +1,66 @@ using Meezi.Core.Enums; +using static Meezi.Core.Authorization.Permission; namespace Meezi.Core.Authorization; /// -/// The authoritative role→capability matrix. Change what a role can do here and -/// every controller that calls EnsurePermission updates automatically. +/// The authoritative role→capability matrix. Change what a base role can do here +/// and every controller that calls EnsurePermission updates automatically. +/// Owners customise further with custom roles (which override this matrix entirely). /// public static class RolePermissions { + /// Capabilities reserved to the Owner — the rest is the Manager baseline. + private static readonly HashSet OwnerOnly = new() + { + ManageCafeSettings, + ManageDiscoverProfile, + ViewBilling, + ManageBilling, + CreateBranch, + EditBranch, + DeleteBranch, + ManageRoles, + }; + private static readonly IReadOnlyDictionary> Matrix = new Dictionary> { [EmployeeRole.Owner] = AllPermissions(), - [EmployeeRole.Manager] = new() - { - Permission.ManageStaff, - Permission.ManageMenu, - Permission.ManageInventory, - Permission.ManageExpenses, - Permission.ManageTaxes, - Permission.ManageCoupons, - Permission.ManageReservations, - Permission.ManageTables, - Permission.ViewReports, - Permission.ReviewLeave, - Permission.ManageSalaries, - Permission.ManagePrintSettings, - Permission.ProcessOrders, - Permission.HandlePayments, - Permission.OperateRegister, - Permission.ManageQueue, - Permission.ViewKitchen, - Permission.HandleDelivery, - }, + // Manager runs the café day to day: everything except the owner-only + // governance (billing, branches, café identity, role definitions). + [EmployeeRole.Manager] = AllExcept(OwnerOnly), [EmployeeRole.Cashier] = new() { - Permission.ProcessOrders, - Permission.HandlePayments, - Permission.OperateRegister, - Permission.ManageQueue, - Permission.ManageReservations, + ViewOrders, ProcessOrders, EditOrder, HandlePayments, UpdateOrderStatus, + OperateRegister, OpenCashDrawer, + ViewQueue, ManageQueue, + ViewTables, + ViewReservations, CreateReservation, EditReservation, + ViewMenu, + ViewCustomers, CreateCustomer, + ViewCoupons, }, [EmployeeRole.Waiter] = new() { - Permission.ProcessOrders, - Permission.ManageReservations, - Permission.ManageQueue, + ViewOrders, ProcessOrders, EditOrder, UpdateOrderStatus, + ViewTables, + ViewMenu, + ViewReservations, CreateReservation, EditReservation, + ViewQueue, ManageQueue, }, [EmployeeRole.Chef] = new() { - Permission.ViewKitchen, + ViewKitchen, UpdateOrderStatus, ViewOrders, ViewMenu, }, [EmployeeRole.Delivery] = new() { - Permission.HandleDelivery, + ViewDelivery, HandleDelivery, ViewOrders, }, }; @@ -73,4 +75,7 @@ public static class RolePermissions private static HashSet AllPermissions() => new(Enum.GetValues()); + + private static HashSet AllExcept(HashSet excluded) => + new(Enum.GetValues().Where(p => !excluded.Contains(p))); }