7.4 KiB
Etapa 5 — UX de roles de cliente y routing
Sprint: 7 Fecha: 2026-07-06 Alcance: guards de rol en router + ajustes de UI en LibraryPage, WorkspacePage y ReportPage. Sin cambios en migraciones, Edge Functions, o panel admin.
Contexto
Las Etapas 1-4 construyeron la infraestructura. Esta etapa cierra la experiencia de usuario para client_editor y client_viewer:
- El router impide que
client_viewerentre al workspace - La Library oculta elementos internos de InQuality (crear proceso, grupos)
- El workspace oculta "Importar BPMN" para
client_editor - El reporte arranca en la tab ROI para
client_viewer
La RLS ya filtra los datos (un client_editor de Banco Solar solo ve procesos de Banco Solar). Esta etapa solo ajusta la UI para que el comportamiento sea coherente con esa realidad de datos.
ANTES de empezar: leer el código actual de src/router.tsx, LibraryPage.tsx, WorkspacePage.tsx y ReportPage.tsx. Los nombres exactos de componentes y props pueden diferir del BRIEF.
5a — Guards de rol en el router
Workspace route (/workspace/$processId)
client_viewer no puede editar → redirigir al reporte:
beforeLoad: ({ context, params }) => {
const user = context.auth?.user
if (!user) throw redirect({ to: '/login' })
if (user.platformRole === 'client_viewer') {
throw redirect({ to: '/report/$processId', params: { processId: params.processId } })
}
}
Import BPMN route (si existe como ruta separada)
Si hay una ruta /import o similar: solo platform_admin y member pueden acceder. client_editor y client_viewer → redirect a /.
beforeLoad: ({ context }) => {
const user = context.auth?.user
const allowed = ['platform_admin', 'member']
if (!user || !allowed.includes(user.platformRole)) {
throw redirect({ to: '/' })
}
}
Rutas de admin (verificar que ya están protegidas)
Las rutas /admin/* ya tienen guard de Etapa 4. Solo verificar que siguen funcionando después de los cambios de esta etapa.
5b — WorkspacePage: ocultar "Importar BPMN" para roles de cliente
El botón o trigger de importación de BPMN solo debe aparecer para platform_admin y member.
const { user } = useAuth()
const canImport = user?.platformRole === 'platform_admin' || user?.platformRole === 'member'
// En el JSX:
{canImport && <ImportBpmnButton />} // o el componente/botón equivalente
No deshabilitar el botón — ocultarlo completamente. Un client_editor no necesita saber que esa función existe.
5c — LibraryPage: UI ajustada para roles de cliente
Ocultar "Nuevo proceso" para client_editor y client_viewer
const canCreateProcess = user?.platformRole === 'platform_admin' || user?.platformRole === 'member'
{canCreateProcess && <CreateProcessButton />}
Ocultar grupos/tags internos de InQuality para roles de cliente
Los process_groups y el sistema de grupos/tags son navegación interna de InQuality. Para client_editor y client_viewer, la Library debe mostrar directamente la lista de procesos sin el panel lateral de grupos.
const isClientRole = user?.platformRole === 'client_editor' || user?.platformRole === 'client_viewer'
// Ocultar completamente el panel de grupos si es rol cliente
{!isClientRole && <ProcessGroupsPanel />}
Si el layout actual tiene los grupos integrados de forma que no se pueden ocultar sin romper la estructura, simplificar: mostrar todos los procesos sin agrupación para roles de cliente (la RLS ya garantiza que solo ven los suyos).
Encabezado de bienvenida para roles de cliente
Opcional (versión wow): si isClientRole, mostrar el nombre de la organización como contexto:
{isClientRole && user?.orgId && (
<p className="text-sm text-muted-foreground mb-4">
Procesos de <span className="font-medium">{orgName}</span>
</p>
)}
Para obtener orgName: hacer una query a organizations con user.orgId. Si ya hay un hook que lo cargue, usarlo. Si no, una query simple al cargar el componente.
5d — ReportPage: tab ROI por defecto para client_viewer
En ReportPage, la tab activa inicial debe ser roi cuando el usuario es client_viewer:
const { user } = useAuth()
const defaultTab = user?.platformRole === 'client_viewer' ? 'roi' : 'actual'
const [activeTab, setActiveTab] = useState(defaultTab)
Las otras tabs (Actual, Automatizado) permanecen visibles — client_viewer puede verlas pero las actividades son de solo lectura (esto ya está garantizado por RLS: no puede hacer UPDATE/INSERT). No es necesario bloquear la UI explícitamente en esta etapa; la RLS rechazará cualquier intento de escritura.
Si el componente de tab activa ya es controlado desde el router (query param o similar), adaptar según el código real.
Tests nuevos
// tests/features/routing/role-guards.test.ts
// Con vitest + mocks del AuthContext:
// 1. client_viewer en /workspace/$id → redirect a /report/$id
// 2. client_editor en /workspace/$id → NO redirige (permanece)
// 3. client_editor en /import → redirect a /
// 4. platform_admin en /import → NO redirige
// tests/features/library/library-ui.test.ts
// 5. client_editor: "Nuevo proceso" no renderiza
// 6. client_editor: grupos panel no renderiza
// 7. platform_admin: "Nuevo proceso" renderiza
// 8. platform_admin: grupos panel renderiza
// tests/features/report/report-default-tab.test.ts
// 9. client_viewer: tab inicial = 'roi'
// 10. platform_admin: tab inicial = 'actual' (o cualquier otro default actual)
Criterios de validación
client_viewerque navega a/workspace/:id→ redirige a/report/:idclient_editorpuede entrar al workspace normalmente- Botón "Importar BPMN" no visible para
client_editorniclient_viewer - Botón "Nuevo proceso" no visible para
client_editorniclient_viewer - Panel de grupos no visible para
client_editorniclient_viewer ReportPageconclient_viewerabre en tab ROIReportPageconplatform_adminabre en la tab que ya abre actualmente (no cambiar comportamiento existente)npm run test→ 558+ tests verdes (más los nuevos ~10)npm run buildlimpio- Validación visual del director antes del OK formal (ver checklist abajo)
Checklist de validación visual (para el director)
Para validar esta etapa necesitás idealmente dos sesiones: una como platform_admin y una como client_editor. Si aún no hay usuario cliente invitado, la validación puede hacerse manualmente editando el platform_role en Supabase Studio:
-- Cambiar temporalmente para prueba (revertir después)
UPDATE public.users SET platform_role = 'client_editor' WHERE id = '<tu-id>';
-- Después de probar:
UPDATE public.users SET platform_role = 'platform_admin' WHERE id = '<tu-id>';
Con rol client_editor:
- Library: no aparece "Nuevo proceso", no aparece el panel de grupos
- Workspace: no aparece el botón/opción de importar BPMN
- Workspace: todo lo demás funciona (editar actividades, simular, ver reporte)
Con rol client_viewer (mismo mecanismo de UPDATE temporal):
- Intentar navegar a
/workspace/$id→ redirige al reporte - Reporte abre directo en tab ROI
NO modificar
- Panel de admin (
/admin/*) - Migraciones (001-015)
- Edge Functions
- Lógica de simulación, dominio, cálculo de ROI, PDF, CSV
AppHeadermás allá de lo estrictamente necesario