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)));
}