# Sprint 8 — Etapa 5: client_editor puede importar BPMN > **Tipo:** DB + UI — habilitar flujo de importación para rol cliente editor > **Rama:** main > **Estimación:** 1.5 horas > **Dependencias:** Etapas 1–4 completadas ✅ > (tabla `areas` y columna `org_id` en processes ya existen, `isClientRole` ya implementado en workspace) --- ## Objetivo Habilitar que un usuario con rol `client_editor` pueda importar archivos BPMN propios. Actualmente la `ImportPage` redirige a todos los roles cliente a `/`. Con esta etapa, `client_editor` pasa a ser un ciudadano de primera clase del flujo de importación: puede subir un BPMN, el proceso se asigna automáticamente a su org, y puede trabajar desde el workspace como lo hace InQuality. `client_viewer` **no** obtiene acceso de importación — eso no cambia. --- ## Contexto del código actual Leer estos archivos antes de modificar: - `src/features/import/ImportPage.tsx` — tiene dos guards que bloquean a client_editor: 1. `useEffect` con `allowed = ['platform_admin', 'member']` → redirige a `/` 2. `if (isClientRole) return null` antes del return final → nunca llega al JSX Además, el proceso se crea con `orgId: null`, lo que rompe las RLS. - `src/features/library/LibraryPage.tsx` — el botón "Importar BPMN" del header está envuelto en `{!isClientRole && ...}` (líneas ~841-860). El empty state de la vista cliente muestra "Contactá a tu administrador" sin botón de importar para nadie. - `supabase/migrations/015_client_roles_and_rls.sql` — la política `insert_processes` permite solo `platform_admin` y `member`. La línea de comentario lo dice explícitamente: `-- client_editor y client_viewer NO pueden crear procesos nuevos`. --- ## Parte 1: Migration 018 Crear `supabase/migrations/018_client_editor_insert.sql`. El único cambio de esta migración: extender la política `insert_processes` para incluir a `client_editor` cuando inserta en su propia org. ```sql -- Permite que client_editor inserte procesos en su propia org -- Los demás roles mantienen sus permisos actuales DROP POLICY IF EXISTS "insert_processes" ON public.processes; CREATE POLICY "insert_processes" ON public.processes FOR INSERT WITH CHECK ( public.is_platform_admin() OR public.current_platform_role() = 'member' OR ( public.current_platform_role() = 'client_editor' AND org_id = public.current_org() ) -- client_viewer y guest siguen sin poder crear procesos ); ``` **Verificar que las políticas de actividades y gateways ya permiten a client_editor:** Buscar en `015_client_roles_and_rls.sql`: - `activities_insert`: usa `NOT IN ('client_viewer', 'guest')` → client_editor puede ✅ - `gateways_write`: usa `NOT IN ('client_viewer', 'guest')` → client_editor puede ✅ Si alguna de esas dos NO incluye a client_editor, corregir en esta misma migración. Verificar antes de cerrar el archivo. ### Aplicar la migración Aplicar en Supabase y verificar: ```sql -- Verificar que la nueva política existe SELECT policyname, cmd, qual FROM pg_policies WHERE schemaname = 'public' AND tablename = 'processes'; -- Esperado: ver "insert_processes" con la nueva definición que incluye client_editor ``` --- ## Parte 2: `ImportPage.tsx` ### 2A — Eliminar los dos guards que bloquean a client_editor **Guard 1 — cambiar la lista de roles permitidos en el `useEffect`:** ```typescript // Antes: const allowed = ['platform_admin', 'member'] if (!allowed.includes(user.platformRole)) { void navigate({ to: '/' }) } // Después: const allowed = ['platform_admin', 'member', 'client_editor'] if (!allowed.includes(user.platformRole)) { void navigate({ to: '/' }) } ``` **Guard 2 — reemplazar el bloqueo total por uno solo para client_viewer:** ```typescript // Antes (bloquea a todos los client roles): const isClientRole = user?.platformRole === 'client_editor' || user?.platformRole === 'client_viewer' if (isClientRole) return null // Después (solo bloquea client_viewer): if (user?.platformRole === 'client_viewer') return null ``` ### 2B — Asignar `orgId` del usuario en el proceso creado Al construir el objeto `process` dentro de `processFile`, el campo `orgId` actualmente es `null`. Para que la RLS de `insert_processes` valide `org_id = current_org()`, el proceso insertado debe tener el `org_id` del usuario. ```typescript // Antes: const process: Process = { // ... orgId: null, // ... } // Después: const process: Process = { // ... orgId: user!.orgId, // ← org_id del usuario autenticado; null solo si no tiene org (no debería pasar para client_editor) // ... } ``` Verificar que `user.orgId` está disponible en el tipo `User` del AuthContext (debería estar — se pobló en Sprint 7). ### 2C — Ocultar los procesos de ejemplo para client_editor Los "procesos de ejemplo" (`SAMPLE_PROCESSES`) son demostraciones internas de InQuality. Un client_editor no debería importar datos de prueba de InQuality en su propio espacio. En el JSX, la sección de ejemplos está bajo el drop zone. Envolverla en una condición: ```tsx // Antes: siempre visible
O cargá un proceso de ejemplo con un click
O cargá un proceso de ejemplo con un click
100% en tu navegador · Sin backend · Sin registro · Datos guardados localmente
// Después: eliminar este párrafo (el producto ya tiene backend y registro) ``` --- ## Parte 3: `LibraryPage.tsx` ### 3A — Botón "Importar BPMN" en el header visible para client_editor El botón en el header de LibraryPage (líneas ~841-860) está condicionado con `!isClientRole`, lo que lo oculta para todos los roles cliente. Cambiar para mostrarlo a `client_editor`: ```tsx // Antes: {!isClientRole && ( )} // Después: {user?.platformRole !== 'client_viewer' && ( )} ``` ### 3B — Empty state diferenciado para client_editor vs client_viewer En `HomeView`, el empty state para roles cliente (cuando `groups.length === 0 && processes.length === 0`) actualmente muestra "Contactá a tu administrador" para todos. Diferenciarlo: ```tsx // Antes (igual para todos los client roles): if (isClientRole) { return (No tenés procesos asignados aún
Contactá a tu administrador para que te asigne acceso
Tu biblioteca está vacía
Importá tu primer BPMN para empezar a cuantificar costos
No tenés procesos asignados aún
Contactá a tu administrador para que te asigne acceso