Skip to main content

Overview

Trazea implements a comprehensive role-based access control (RBAC) system where permissions are stored as JSON objects in the roles table. Each role defines granular permissions across different areas of the application.

Role Structure

Role Interface

src/entities/user/model/useUserStore.ts:62-67
interface Role {
  id_rol: string;
  nombre: string;
  descripcion: string;
  permissions: AppPermissions;
}

Available Roles

src/entities/user/model/types.ts:6-10
export enum ROLES {
  ADMIN = 'admin',
  TECNICO = 'tecnico',
  SUPERVISOR = 'superuser',
}

Admin

Full AccessComplete system control including user management, configuration, and all operational features.

Técnico

Operational AccessTechnical staff access to inventory, spare parts, service requests, and assigned work.

Supervisor

Enhanced AccessElevated permissions for oversight, approvals, and cross-location visibility.

Permissions Structure

AppPermissions Interface

Permissions are organized into functional domains:
src/entities/user/model/useUserStore.ts:19-60
export interface AppPermissions {
  menu: {
    registros: MenuPermissions;
    repuestos: MenuPermissions;
    solicitudes: MenuPermissions;
    inventario: MenuPermissions;
    [key: string]: MenuPermissions;
  };
  dashboard?: {
    view_global_stats: boolean;
    view_financial_data: boolean;
  };
  inventory?: {
    edit_product: boolean;
    create_product: boolean;
    delete_product: boolean;
    view_cost_price: boolean;
    view_all_locations: boolean;
    adjust_stock_manual: boolean;
    view_assigned_location_only: boolean;
  };
  logistics?: {
    reject_transfer: boolean;
    view_all_orders: boolean;
    approve_transfer_in: boolean;
    approve_transfer_out: boolean;
    create_transfer_order: boolean;
  };
  technical_ops?: {
    assign_to_tech: boolean;
    create_tech_user: boolean;
    receive_from_tech: boolean;
    view_tech_history: boolean;
  };
  users_and_access?: {
    create_user: boolean;
    edit_user_roles: boolean;
    view_audit_logs: boolean;
    assign_locations: boolean;
  };
  [key: string]: unknown;
}

Permission Domains

Control access to main navigation sections:
src/entities/user/model/useUserStore.ts:7-17
export interface MenuPermissions {
  show_view: boolean;
  edit_register?: boolean;
  show_form_register?: boolean;
  get_action?: boolean;
  discontinue?: boolean;
  send_action?: boolean;
  button_actions?: boolean;
  create_register?: boolean;
  [key: string]: boolean | undefined;
}
show_view
boolean
required
Whether the menu item is visible and accessible
edit_register
boolean
Permission to edit existing records in this section
create_register
boolean
Permission to create new records in this section
show_form_register
boolean
Permission to view the registration form
button_actions
boolean
Access to action buttons within this section

Dashboard Permissions

view_global_stats
boolean
View statistics across all locations
view_financial_data
boolean
Access to financial reports and cost data

Inventory Permissions

Inventory permissions directly affect what users can do with stock levels and pricing information.
edit_product
boolean
Edit spare part details in the catalog
create_product
boolean
Add new spare parts to the catalog
delete_product
boolean
Remove spare parts from the catalog
view_cost_price
boolean
View cost prices and margins
view_all_locations
boolean
See inventory across all locations (overrides location assignment)
adjust_stock_manual
boolean
Manually adjust stock levels
view_assigned_location_only
boolean
Restrict view to only assigned locations

Logistics Permissions

create_transfer_order
boolean
Create transfer orders between locations
approve_transfer_in
boolean
Approve incoming transfers to location
approve_transfer_out
boolean
Approve outgoing transfers from location
reject_transfer
boolean
Reject transfer requests
view_all_orders
boolean
View transfer orders across all locations

Technical Operations Permissions

assign_to_tech
boolean
Assign work orders to technicians
receive_from_tech
boolean
Receive completed work from technicians
create_tech_user
boolean
Create new technician accounts
view_tech_history
boolean
View technician work history and performance

Users & Access Permissions

Critical Security Permissions: These permissions control who can manage users and access controls.
create_user
boolean
Create new user accounts
edit_user_roles
boolean
Assign and modify user roles
assign_locations
boolean
Assign users to locations via usuarios_localizacion table
view_audit_logs
boolean
Access system audit logs and user activity

Checking Permissions

Using the User Store

The user store provides helper methods for permission checks:
src/entities/user/model/useUserStore.ts:139-148
checkMenuPermission: (menu: string, permission: string) => {
  const state = get();
  const menuPermissions = state.sessionData?.user.role?.permissions?.menu;

  if (!menuPermissions || !menuPermissions[menu]) {
    return false;
  }

  return !!menuPermissions[menu][permission];
},

Route-Level Checks

src/entities/user/model/useUserStore.ts:150-160
canViewRoute: (routeKey: string) => {
  const state = get();
  const menuPermissions = state.sessionData?.user.role?.permissions?.menu;

  if (!menuPermissions) {
    return false;
  }

  const routePermission = menuPermissions[routeKey];
  return routePermission?.show_view === true;
},

Role Checks

src/entities/user/model/useUserStore.ts:132-137
hasRole: (roleName: string) => {
  const state = get();
  const userRole = state.sessionData?.user.role?.nombre;
  if (!userRole) return false;
  return userRole.toLowerCase().trim() === roleName.toLowerCase().trim();
},

Using Permissions in Components

Check Menu Permission

import { useUserStore } from '@/entities/user';

function InventoryActions() {
  const { checkMenuPermission } = useUserStore();
  
  const canEdit = checkMenuPermission('inventario', 'edit_register');
  const canCreate = checkMenuPermission('inventario', 'create_register');
  
  return (
    <div>
      {canCreate && (
        <Button onClick={handleCreate}>Add New Part</Button>
      )}
      {canEdit && (
        <Button onClick={handleEdit}>Edit Part</Button>
      )}
    </div>
  );
}

Check Domain Permission

import { useUserStore } from '@/entities/user';

function PricingDisplay({ cost }: { cost: number }) {
  const { sessionData } = useUserStore();
  const permissions = sessionData?.user.role?.permissions;
  
  const canViewCost = permissions?.inventory?.view_cost_price;
  
  return (
    <div>
      {canViewCost ? (
        <span>Cost: ${cost}</span>
      ) : (
        <span>Cost: Hidden</span>
      )}
    </div>
  );
}

Route Protection

import { useUserStore } from '@/entities/user';
import { Navigate } from 'react-router-dom';

function ProtectedRoute({ children, requiredRoute }: ProtectedRouteProps) {
  const { canViewRoute } = useUserStore();
  
  if (!canViewRoute(requiredRoute)) {
    return <Navigate to="/unauthorized" replace />;
  }
  
  return <>{children}</>;
}

// Usage
<ProtectedRoute requiredRoute="inventario">
  <InventoryPage />
</ProtectedRoute>

Configuring Role Permissions

Creating a Role

1

Define Role Details

Choose a unique nombre and write a clear descripcion.
2

Build Permissions Object

Create the JSON permissions structure with appropriate access levels.
3

Insert into Database

Add the role to the roles table with the permissions JSON.
4

Assign to Users

Update users’ id_rol field to assign the new role.

Example: Creating a Technician Role

{
  "menu": {
    "registros": {
      "show_view": true,
      "edit_register": false,
      "create_register": false
    },
    "repuestos": {
      "show_view": true,
      "edit_register": false,
      "create_register": false
    },
    "solicitudes": {
      "show_view": true,
      "edit_register": true,
      "create_register": true
    },
    "inventario": {
      "show_view": true,
      "edit_register": false,
      "create_register": false
    }
  },
  "dashboard": {
    "view_global_stats": false,
    "view_financial_data": false
  },
  "inventory": {
    "edit_product": false,
    "create_product": false,
    "delete_product": false,
    "view_cost_price": false,
    "view_all_locations": false,
    "adjust_stock_manual": false,
    "view_assigned_location_only": true
  },
  "technical_ops": {
    "assign_to_tech": false,
    "create_tech_user": false,
    "receive_from_tech": true,
    "view_tech_history": false
  },
  "users_and_access": {
    "create_user": false,
    "edit_user_roles": false,
    "view_audit_logs": false,
    "assign_locations": false
  }
}

Example: Creating an Admin Role

{
  "menu": {
    "registros": {
      "show_view": true,
      "edit_register": true,
      "create_register": true,
      "button_actions": true
    },
    "repuestos": {
      "show_view": true,
      "edit_register": true,
      "create_register": true,
      "discontinue": true
    },
    "solicitudes": {
      "show_view": true,
      "edit_register": true,
      "create_register": true,
      "button_actions": true
    },
    "inventario": {
      "show_view": true,
      "edit_register": true,
      "create_register": true,
      "button_actions": true
    }
  },
  "dashboard": {
    "view_global_stats": true,
    "view_financial_data": true
  },
  "inventory": {
    "edit_product": true,
    "create_product": true,
    "delete_product": true,
    "view_cost_price": true,
    "view_all_locations": true,
    "adjust_stock_manual": true,
    "view_assigned_location_only": false
  },
  "logistics": {
    "reject_transfer": true,
    "view_all_orders": true,
    "approve_transfer_in": true,
    "approve_transfer_out": true,
    "create_transfer_order": true
  },
  "technical_ops": {
    "assign_to_tech": true,
    "create_tech_user": true,
    "receive_from_tech": true,
    "view_tech_history": true
  },
  "users_and_access": {
    "create_user": true,
    "edit_user_roles": true,
    "view_audit_logs": true,
    "assign_locations": true
  }
}

Permissions JSON Storage

Permissions are stored as JSONB in PostgreSQL, allowing flexible querying and indexing.

Database Storage

The roles table structure:
CREATE TABLE roles (
  id_rol UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  nombre TEXT NOT NULL UNIQUE,
  descripcion TEXT,
  permissions JSONB NOT NULL,
  created_at TIMESTAMP DEFAULT NOW()
);

Updating Permissions

To update role permissions:
UPDATE roles
SET permissions = '{
  "menu": { ... },
  "inventory": { ... },
  ...
}'::jsonb
WHERE nombre = 'tecnico';
Critical Configuration Step: Always test permission changes in a development environment first. Users must log out and back in for permission changes to take effect.

Best Practices

Grant users only the permissions they need to perform their job:
  • Start with minimal permissions
  • Add permissions as needed
  • Regularly review and audit permissions
  • Remove unused permissions
Create roles based on job functions:
  • Define clear role boundaries
  • Avoid too many similar roles
  • Document what each role can do
  • Use descriptive role names
Always test permission changes:
  • Create test users for each role
  • Verify UI elements show/hide correctly
  • Test API access restrictions
  • Check cross-location permissions
Keep your permission structure documented:
  • List all available permissions
  • Document what each permission controls
  • Maintain a permission matrix
  • Update docs when adding new features

Session Management

Permissions are loaded when users log in:
src/shared/api/fetchUserSessionData.ts:20-24
const { data: rol } = await supabase
  .from('roles')
  .select('*')
  .eq('id_rol', user?.id_rol)
  .single();
The role object (including permissions) is stored in the user session and persisted to localStorage for quick access.

User Management

Learn about user creation, approval, and role assignment

Multi-Location Setup

Configure location-based access controls

Build docs developers (and LLMs) love