---
description: Role-based access control (RBAC) patterns and implementations for POS System
globs: **/components/**,**/api/**,**/routes/**
---

# Role-Based Access Control (RBAC) Patterns

## Role Definitions

### Available Roles
```typescript
type UserRole = 'admin' | 'manager' | 'server' | 'counter' | 'kitchen'
```

### Role Capabilities
- **admin**: Full system access, can switch to any interface
- **manager**: Business operations, reports, staff oversight
- **server**: Dine-in order creation only
- **counter**: All order types + payment processing
- **kitchen**: Order preparation and status updates

## Frontend Role Routing

### Main Router Pattern
```typescript
// RoleBasedLayout.tsx
export function RoleBasedLayout({ user }: { user: User }) {
  // Admin gets AdminLayout with all interfaces
  if (user.role === 'admin') {
    return <AdminLayout user={user} />
  }
  
  // Other roles get specific interfaces
  switch (user.role) {
    case 'server': return <ServerInterface />
    case 'counter': return <CounterInterface />
    case 'kitchen': return <KitchenLayout user={user} />
    default: return <POSLayout user={user} />
  }
}
```

### Navigation Access Control
```typescript
// AdminLayout.tsx - Admin can access all interfaces
const adminSections = [
  { id: 'dashboard', label: 'Dashboard' },
  { id: 'pos', label: 'General POS' },        // Full POS access
  { id: 'server', label: 'Server Interface' }, // Server view
  { id: 'counter', label: 'Counter/Checkout' }, // Counter view
  { id: 'kitchen', label: 'Kitchen Display' }   // Kitchen view
  // + admin-only sections
]
```

## Backend API Role Restrictions

### Route Groups by Role
```go
// routes.go pattern
func setupRoutes(router *gin.Engine) {
    api := router.Group("/api/v1")
    
    // Public routes
    api.POST("/auth/login", handlers.Login)
    
    // Protected routes
    protected := api.Group("", middleware.RequireAuth)
    
    // Admin only
    admin := protected.Group("/admin", middleware.RequireRole("admin"))
    admin.GET("/users", handlers.GetUsers)
    admin.POST("/users", handlers.CreateUser)
    
    // Server only
    server := protected.Group("/server", middleware.RequireRole("server"))
    server.POST("/orders", handlers.CreateDineInOrder) // Restricted to dine_in
    
    // Counter access
    counter := protected.Group("/counter", middleware.RequireRoles("counter", "admin"))
    counter.POST("/orders", handlers.CreateCounterOrder) // All order types
    counter.POST("/orders/:id/payments", handlers.ProcessPayment)
}
```

### Role-Specific Endpoints
```typescript
// API Client role-specific methods
class APIClient {
  // Admin-only endpoints
  async getUsers(): Promise<APIResponse<User[]>> {
    return this.request({ method: 'GET', url: '/admin/users' });
  }
  
  // Server-specific (dine-in only)
  async createServerOrder(order: CreateOrderRequest): Promise<APIResponse<Order>> {
    return this.request({ method: 'POST', url: '/server/orders', data: order });
  }
  
  // Counter-specific (all order types + payments)
  async createCounterOrder(order: CreateOrderRequest): Promise<APIResponse<Order>> {
    return this.request({ method: 'POST', url: '/counter/orders', data: order });
  }
  
  async processCounterPayment(orderId: string, payment: ProcessPaymentRequest): Promise<APIResponse<Payment>> {
    return this.request({ method: 'POST', url: `/counter/orders/${orderId}/payments`, data: payment });
  }
}
```

## Component-Level Access Control

### Conditional Rendering by Role
```typescript
// Show admin-only features
{user.role === 'admin' && (
  <Button onClick={() => navigate('/admin')}>
    Admin Dashboard
  </Button>
)}

// Show based on multiple roles
{['admin', 'manager'].includes(user.role) && (
  <ReportsSection />
)}
```

### Form Restrictions
```typescript
// ServerInterface.tsx - Only dine-in orders
const ServerInterface = () => {
  const createOrderMutation = useMutation({
    mutationFn: (order: CreateOrderRequest) => {
      // Force dine_in type for servers
      return apiClient.createServerOrder({
        ...order,
        order_type: 'dine_in'
      })
    }
  })
  
  // Hide takeout/delivery options in UI
  const availableOrderTypes = ['dine_in'] // Only option for servers
}
```

## Database Role Validation

### User Schema
```sql
-- users table with role enum
CREATE TYPE user_role AS ENUM ('admin', 'manager', 'server', 'counter', 'kitchen');

ALTER TABLE users ADD COLUMN role user_role NOT NULL DEFAULT 'server';
```

### Sample Role Data
```sql
-- Seed data with all roles
INSERT INTO users (username, email, password_hash, first_name, last_name, role) VALUES
('admin', 'admin@pos.com', '$2b$10$...', 'Admin', 'User', 'admin'),
('server1', 'server1@pos.com', '$2b$10$...', 'Sarah', 'Smith', 'server'),
('counter1', 'counter1@pos.com', '$2b$10$...', 'Lisa', 'Davis', 'counter'),
('kitchen1', 'kitchen@pos.com', '$2b$10$...', 'Chef', 'Williams', 'kitchen');
```

## Authentication Flow

### Login Process
```typescript
// login.tsx
const loginMutation = useMutation({
  mutationFn: async (credentials: LoginRequest) => {
    const response = await apiClient.login(credentials)
    return response
  },
  onSuccess: (data) => {
    if (data.success && data.data) {
      // Store user info with role
      apiClient.setAuthToken(data.data.token)
      localStorage.setItem('pos_user', JSON.stringify(data.data.user))
      router.navigate({ to: '/' })
    }
  }
})
```

### Route Protection
```typescript
// index.tsx
function HomePage() {
  const [user, setUser] = useState<User | null>(null)
  
  useEffect(() => {
    const storedUser = localStorage.getItem('pos_user')
    if (storedUser) {
      setUser(JSON.parse(storedUser))
    }
  }, [])
  
  // Redirect if not authenticated
  if (!apiClient.isAuthenticated() || !user) {
    return <Navigate to="/login" />
  }
  
  // Role-based routing
  return <RoleBasedLayout user={user} />
}
```

## Security Best Practices

### Frontend Security
- Never trust frontend role checks alone
- Always validate roles on backend
- Store minimal user data in localStorage
- Clear auth on logout

### Backend Security
- Use middleware for role validation
- Check roles on every protected endpoint
- Log access attempts for audit
- Implement proper session management

### Error Handling
```typescript
// Handle role access errors gracefully
onError: (error: any) => {
  if (error.status === 403) {
    alert('Access denied: Insufficient permissions')
  } else {
    alert(`Error: ${error.message}`)
  }
}
```