ShelfWise implements a sophisticated role-based authorization system with 8 distinct roles, each with specific permissions and hierarchy levels. Authorization is enforced through Laravel Policies, ensuring consistent permission checks across the application.
Key Principle: Form Requests handle validation only. Controllers use Gate::authorize() before service calls. All authorization logic lives in Policies.
Role levels enable hierarchical comparisons like “only Store Manager and above can approve”. Use $user->role->level() >= UserRole::STORE_MANAGER->level() for such checks.
Platform administrator with full system access. Manages all tenants, subscriptions, platform settings, and has complete visibility across the entire platform.
'platform_admin','manage_all_tenants','manage_subscriptions','impersonate_users',// ... all tenant permissions
Owner (100)
Full system access within their tenant. Manages tenant settings, all stores, users, billing, and has complete visibility across the entire organization.
// On User model$user->role->hasPermission('manage_inventory');// In policiesif (! $user->role->hasPermission('manage_orders')) { return false;}// Get all permissions for a role$permissions = UserRole::STORE_MANAGER->permissions();
All authorization logic lives in Laravel Policies:
app/Policies/ProductPolicy.php
namespace App\Policies;use App\Enums\UserRole;use App\Models\Product;use App\Models\User;class ProductPolicy{ public function viewAny(User $user): bool { return $user->role->hasPermission('manage_inventory'); } public function view(User $user, Product $product): bool { // CRITICAL: Always check tenant isolation first if ($user->tenant_id !== $product->tenant_id) { return false; } // Owners and GMs can view all products in their tenant if (in_array($user->role->value, [UserRole::OWNER->value, UserRole::GENERAL_MANAGER->value])) { return true; } // Other roles can only view products in their assigned shops return $user->shops()->where('shops.id', $product->shop_id)->exists(); } public function create(User $user): bool { return $user->role->hasPermission('manage_inventory'); } public function update(User $user, Product $product): bool { if ($user->tenant_id !== $product->tenant_id) { return false; } if (in_array($user->role->value, [UserRole::OWNER->value, UserRole::GENERAL_MANAGER->value])) { return true; } return $user->shops()->where('shops.id', $product->shop_id)->exists(); } public function delete(User $user, Product $product): bool { if ($user->tenant_id !== $product->tenant_id) { return false; } // Only Owner and GM can delete return in_array($user->role->value, [UserRole::OWNER->value, UserRole::GENERAL_MANAGER->value]); }}
Here’s a complete example showing state-based authorization:
app/Policies/OrderPolicy.php
class OrderPolicy{ public function viewAny(User $user): bool { return $user->role->hasPermission('manage_orders'); } public function view(User $user, Order $order): bool { if ($user->tenant_id !== $order->tenant_id) { return false; } if (in_array($user->role->value, [UserRole::OWNER->value, UserRole::GENERAL_MANAGER->value])) { return true; } return $user->shops()->where('shops.id', $order->shop_id)->exists(); } public function update(User $user, Order $order): bool { if ($user->tenant_id !== $order->tenant_id) { return false; } // Can only edit pending/confirmed orders if (! in_array($order->status, ['pending', 'confirmed'])) { return false; } return $user->role->hasPermission('manage_orders'); } public function cancel(User $user, Order $order): bool { if ($user->tenant_id !== $order->tenant_id) { return false; } // Cannot cancel completed/cancelled orders if (in_array($order->status, ['completed', 'cancelled'])) { return false; } // Requires Store Manager or above if ($user->role->level() < UserRole::STORE_MANAGER->level()) { return false; } return $user->role->hasPermission('manage_orders'); } public function refund(User $user, Order $order): bool { if ($user->tenant_id !== $order->tenant_id) { return false; } // Only completed orders can be refunded if ($order->status !== 'completed') { return false; } // Requires General Manager or above if ($user->role->level() < UserRole::GENERAL_MANAGER->level()) { return false; } return $user->role->hasPermission('manage_orders'); }}
// User-Shop relationship (many-to-many)$user->shops()->attach($shop->id, ['tenant_id' => $tenant->id]);// Check if user has access to shop$hasAccess = $user->shops()->where('shops.id', $shopId)->exists();