Skip to content

User Roles & Permissions

Complete guide to user roles, permissions, and access control in Lager Guru.

Overview

Lager Guru uses a role-based access control (RBAC) system with a canonical set of user roles defined in the app_role PostgreSQL enum. All roles are stored in the user_roles table and enforced through Row-Level Security (RLS) policies.

Canonical Role List

The following roles are defined in the app_role enum:

Core Roles

  1. admin - System Administrator

    • Full system access
    • Can manage all tenants, users, and settings
    • Bypasses RLS via is_admin() function
    • Use case: System administrators
  2. driver - Delivery Driver

    • Transport operations
    • View and update assigned shipments
    • Limited safety reporting
    • Use case: Delivery drivers
  3. worker - Warehouse Worker

    • Warehouse operations
    • Pick & pack operations
    • Inventory movements
    • Safety incident reporting
    • Use case: Warehouse workers

Safety Pro Roles

  1. safety_officer - Safety Officer (Sicherheitsbeauftragter)

    • Full control over Safety module
    • Create and manage checklists
    • Manage incidents and actions
    • Create and manage trainings
    • View compliance dashboard
    • Access AI features
    • Generate reports
    • Create and manage workflows (visual editor)
    • Use case: Primary safety manager
  2. hse_manager - HSE Manager (Health, Safety, Environment)

    • All Safety Officer permissions
    • Access to all tenant safety data
    • Compliance reporting
    • Strategic analytics
    • Cross-tenant insights (if applicable)
    • Use case: Senior safety management
  3. auditor - Auditor

    • Read-only access to all safety data
    • View compliance metrics
    • Export reports
    • Access audit logs
    • Cannot modify data
    • Use case: External/internal auditors
  4. training_supervisor - Training Supervisor

    • Create and manage trainings
    • View training completions
    • Generate certificates
    • Access training analytics
    • Cannot manage incidents
    • Use case: Training department

Inventory Roles

  1. inventory - Inventory Manager
    • Read access to inventory intelligence
    • View inventory metrics and analytics
    • Access inventory snapshots
    • Use case: Inventory management staff

Role Assignment

Roles are assigned via:

  1. User Management UI (/admin → Users)

    • Admin can assign any role to any user
    • All roles are visible in the dropdown
  2. Database (user_roles table)

    sql
    INSERT INTO public.user_roles (user_id, role)
    VALUES ('user-uuid', 'safety_officer');
  3. Tenant-specific assignments (tenant_users table)

    • Tenant admins can assign tenant-level roles
    • Works in conjunction with user_roles

Role Validation

Database Validation

The system includes built-in validation to prevent undefined roles:

  1. Enum Type Constraint: The app_role enum type enforces that only valid enum values can be stored
  2. Validation Function: public.is_valid_app_role(TEXT) checks if a role string is valid
  3. Trigger: validate_user_role_trigger validates role assignments on insert/update
sql
-- Check if a role is valid
SELECT public.is_valid_app_role('safety_officer'); -- Returns true
SELECT public.is_valid_app_role('invalid_role'); -- Returns false

-- Get all valid roles
SELECT public.get_all_app_roles(); -- Returns array of all roles

Frontend Validation

TypeScript types ensure type safety:

typescript
import { AppRole } from '@/lib/queries';

const role: AppRole = 'safety_officer'; // Type-safe
// const invalid: AppRole = 'invalid'; // TypeScript error

Permission Matrix

FeatureAdminDriverWorkerSafety OfficerHSE ManagerAuditorTraining SupervisorInventory
System Management
Manage Tenants
Manage Users
System Settings
Operations
View Shipments✅ (own)
Create Shipments
Update Shipments✅ (own)
Pick & Pack
Inventory
View Inventory
Manage Inventory
Inventory Intelligence
Safety
Report Incident
Manage Incidents
Create Checklists
Manage Trainings
View Compliance
Manage Workflows
Safety Analytics

Role Helper Functions

Database Functions

  • public.is_admin() - Returns true if current user has admin role
  • public.is_safety_officer() - Returns true if current user has safety_officer role
  • public.is_worker() - Returns true if current user has worker role
  • public.is_driver() - Returns true if current user has driver role
  • public.is_auditor() - Returns true if current user has auditor role
  • public.has_role(_user_id UUID, _role app_role) - Check if a user has a specific role
  • public.is_valid_app_role(TEXT) - Validate if a role string is valid
  • public.get_all_app_roles() - Get array of all valid roles

Frontend Usage

typescript
import { useAuth } from '@/contexts/AuthContext';
import { AppRole } from '@/lib/queries';

const { userRole } = useAuth();

// Check role
if (userRole === 'safety_officer') {
  // Show safety management UI
}

// Type-safe role assignment
const assignRole = async (userId: string, role: AppRole) => {
  // ...
};

RLS Policy Patterns

Roles are enforced through Row-Level Security (RLS) policies:

sql
-- Example: Safety Officer can access all safety incidents
CREATE POLICY safety_incidents_safety_officer_all ON public.safety_incidents
  FOR ALL
  USING (
    EXISTS (
      SELECT 1 FROM public.user_roles ur
      WHERE ur.user_id = auth.uid()
      AND ur.role::text = 'safety_officer'
    )
  );

Adding New Roles

To add a new role:

  1. Add to enum (separate migration):

    sql
    ALTER TYPE public.app_role ADD VALUE 'new_role';
  2. Update TypeScript types:

    typescript
    export type AppRole = ... | 'new_role';
  3. Add RLS policies for the new role

  4. Update UI (UserManagement component)

  5. Add translations (i18n files)

  6. Update documentation

Safety Officer Specifics

The safety_officer role is critical for Safety Pro module access:

  • Defined: ✅ In app_role enum (migration 20250118000001_add_safety_officer_role.sql)
  • Function: ✅ public.is_safety_officer() exists
  • RLS Policies: ✅ Used in all Safety Pro tables
  • UI Visibility: ✅ Now visible in User Management
  • TypeScript Types: ✅ Included in AppRole type

Safety Officer Permissions

  • Full CRUD on safety_incidents
  • Full CRUD on safety_actions
  • Full CRUD on safety_checklists
  • Full CRUD on safety_trainings
  • Access to safety_insights
  • Access to workflow editor
  • Can moderate safety feed
  • Can manage recognitions

Best Practices

  1. Always use enum values: Never hardcode role strings
  2. Validate roles: Use is_valid_app_role() before assignment
  3. Type safety: Use AppRole type in TypeScript
  4. RLS first: Always enforce permissions via RLS, not just UI
  5. Document changes: Update this doc when adding roles
  6. Test permissions: Verify RLS policies work correctly

Released under Commercial License