Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/EdgarJr30/proyecto-de-grado-cms/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The application uses React Router v6 with a centralized route registry defined in src/Routes/appRoutes.tsx. All routes are lazy-loaded for optimal performance.

Route Definition

Routes are defined using a strongly-typed AppRoute interface:
src/Routes/appRoutes.tsx
export type AppRoute = {
  path: string;                    // URL path
  element: JSX.Element;            // Lazy-loaded component
  allowPerms: string[];            // Required permissions
  name?: string;                   // Display name
  icon?: JSX.Element;              // Sidebar icon
  showInSidebar?: boolean;         // Sidebar visibility
};

Route Registry

All application routes are defined in the APP_ROUTES array:
src/Routes/appRoutes.tsx
export const APP_ROUTES: AppRoute[] = [
  {
    path: '/inicio',
    element: <DashboardPage />,
    allowPerms: ['home:read'],
    name: 'Inicio',
    icon: IconHome,
    showInSidebar: true,
  },
  {
    path: '/ordenes_trabajo',
    element: <WorkOrdersPage />,
    allowPerms: [
      'work_orders:read',
      'work_orders:full_access',
      'work_orders:cancel',
      'work_orders:delete',
    ],
    name: 'Órdenes de Trabajo',
    icon: IconWorkOrders,
    showInSidebar: true,
  },
  {
    path: '/tickets/:ticketId',
    element: <TicketDetailsPage />,
    allowPerms: [
      'home:read',
      'work_orders:read',
      'work_orders:read_own',
      'work_orders:full_access',
    ],
    showInSidebar: false,
  },
];

Lazy Loading

All page components are lazy-loaded to reduce initial bundle size:
src/Routes/appRoutes.tsx
import { lazy } from 'react';

const CreateTicketPage = lazy(() => import('../pages/CreateTicketPage'));
const WorkOrdersPage = lazy(() => import('../pages/WorkOrdersPage'));
const InventoryHomePage = lazy(() => import('../pages/inventory/InventoryHomePage'));
// ...
Lazy loading reduces the initial JavaScript bundle by loading page components only when they are accessed.

Access Control

Route access is controlled through a layered permission system:
1

ProtectedRoute Wrapper

Checks if the user is authenticated:
<ProtectedRoute>
  <RequirePerm allowPerms={route.allowPerms}>
    <Suspense fallback={<ScreenLoader />}>
      {route.element}
    </Suspense>
  </RequirePerm>
</ProtectedRoute>
2

RequirePerm Component

Validates user permissions against allowPerms:
// User must have at least ONE permission from allowPerms array
<RequirePerm allowPerms={['work_orders:read', 'work_orders:full_access']}>
  <WorkOrdersPage />
</RequirePerm>
3

Permission Check Logic

Uses the PermissionsContext to check user permissions:
const { has } = usePermissions();
const canAccess = allowPerms.some(perm => has(perm));

Permission Array Behavior

The allowPerms array uses OR logic: users need at least one of the listed permissions to access the route.
// User needs EITHER work_orders:read OR work_orders:full_access
allowPerms: ['work_orders:read', 'work_orders:full_access']

// User needs ONLY home:read
allowPerms: ['home:read']

Programmatic Navigation

import { useNavigate } from 'react-router-dom';

function MyComponent() {
  const navigate = useNavigate();
  
  const handleClick = () => {
    navigate('/ordenes_trabajo');
  };
  
  return <button onClick={handleClick}>Go to Work Orders</button>;
}
import { Link } from 'react-router-dom';

<Link to="/tickets/123">View Ticket</Link>

Dynamic Routes

import { useParams } from 'react-router-dom';

function TicketDetailsPage() {
  const { ticketId } = useParams<{ ticketId: string }>();
  
  // Use ticketId to fetch ticket data
}
Routes with showInSidebar: true appear in the application sidebar:
{
  path: '/inventario',
  element: <InventoryHomePage />,
  allowPerms: ['inventory:read'],
  name: 'Inventario',
  icon: IconInventory,
  showInSidebar: true,  // Shows in sidebar
}

Route Redirects

Legacy routes redirect to new locations:
src/Routes/appRoutes.tsx
{
  path: '/admin/assets',
  element: <Navigate to="/inventory/assets" replace />,
  allowPerms: ['assets:read'],
  showInSidebar: false,
}

Inventory Subroutes

The inventory module has nested routes:
/inventario                          # Inventory home
├── /inventory/uoms                  # Units of measure
├── /inventory/parts                 # Parts catalog
├── /inventory/warehouses            # Warehouses
│   └── /inventory/warehouses/:id/bins  # Warehouse bins
├── /inventory/availability          # Stock overview
├── /inventory/assets                # Assets
├── /inventory/docs                  # Documents
│   ├── /inventory/docs/crear        # Create document
│   └── /inventory/docs/:docId       # Document editor
├── /inventory/vendors               # Vendors
├── /inventory/reorder               # Reorder policies
└── /inventory/kardex                # Movement history

Admin Routes

Administration routes require elevated permissions:
{
  path: '/admin/settings',
  element: <AdminSettingsHubPage />,
  allowPerms: [
    'rbac:manage_roles',
    'rbac:manage_permissions',
    'society:read',
    'special_incidents:read',
    'assets:read',
  ],
  name: 'Configuración',
  icon: IconPermissions,
  showInSidebar: true,
}

Error Routes

403 Forbidden

Shown when user lacks permissions:
{ path: '/403', element: <ForbiddenPage /> }

Root Redirect

Root path redirects to dashboard:
{ path: '/', element: <Navigate to="/inicio" replace /> }

Route Icons

Icons are inline SVG elements:
src/Routes/appRoutes.tsx
const IconHome = (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    fill="none"
    viewBox="0 0 24 24"
    strokeWidth="1.5"
    stroke="currentColor"
    className="w-5 h-5 mr-2"
  >
    <path
      strokeLinecap="round"
      strokeLinejoin="round"
      d="m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12..."
    />
  </svg>
);
Always check that new routes have appropriate allowPerms values aligned with backend RLS policies.

Best Practices

Lazy loading keeps the initial bundle small and improves performance:
const MyPage = lazy(() => import('../pages/MyPage'));
Never rely solely on UI-level permission checks. Backend RLS policies are the source of truth:
allowPerms: ['feature:read', 'feature:full_access']
Only show primary navigation items in the sidebar. Detail pages and sub-routes should be hidden:
showInSidebar: false  // for detail pages

Next Steps

Services

Learn about the service layer

Components

Explore UI components

Build docs developers (and LLMs) love