From 3044342ac137410da18ab9ab6675e397f50020d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20Ben=C3=ADtez?= Date: Tue, 7 Jul 2026 23:38:38 -0300 Subject: [PATCH] etapa 5 --- sprints/sprint-8/ETAPA_5_PROMPT.md | 343 +++++++++++++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100644 sprints/sprint-8/ETAPA_5_PROMPT.md diff --git a/sprints/sprint-8/ETAPA_5_PROMPT.md b/sprints/sprint-8/ETAPA_5_PROMPT.md new file mode 100644 index 0000000..eca3c87 --- /dev/null +++ b/sprints/sprint-8/ETAPA_5_PROMPT.md @@ -0,0 +1,343 @@ +# 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

+
+ {SAMPLE_PROCESSES.map(...)} +
+
+ +// Después: solo visible para InQuality (platform_admin y member) +{user?.platformRole !== 'client_editor' && ( +
+

O cargá un proceso de ejemplo con un click

+
+ {SAMPLE_PROCESSES.map(...)} +
+
+)} +``` + +### 2D — Corregir texto de marca en ImportPage + +El header tiene texto desactualizado que viola las reglas de marca del producto: + +```tsx +// Antes (incorrecto — nombre viejo del producto): +
+ + Process Cost Platform · MVP Fase 0 +
+ +// Después: +
+ + InQ ROI +
+``` + +El tagline del final de la página también está desactualizado: + +```tsx +// Antes: +

+ 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

+
+ ) +} + +// Después (diferenciado): +if (isClientRole) { + if (user?.platformRole === 'client_editor') { + return ( +
+ +

Tu biblioteca está vacía

+

+ Importá tu primer BPMN para empezar a cuantificar costos +

+ +
+ ) + } + // client_viewer: mantener mensaje existente + return ( +
+ +

No tenés procesos asignados aún

+

Contactá a tu administrador para que te asigne acceso

+
+ ) +} +``` + +`user` está disponible en el scope de `HomeView` como prop (o via `useAuth()` — verificar cuál aplica). + +--- + +## Lo que NO cambia en esta etapa + +- **`process-repo.ts`** — no tocar. `updateEditable()` no necesita `bpmn_xml` para este flujo. +- **`process-store.ts`** — no tocar. +- **`WorkspacePage.tsx`** — sin cambios. client_editor ya tiene acceso al workspace desde Sprint 7 (la RLS de `update_processes` ya lo cubre). +- **`GlobalSettingsPanel.tsx`** — sin cambios. El selector de área ya funciona para client_editor desde Etapa 4. +- **Rol `client_viewer`** — sigue sin acceso a importación en todo momento. + +--- + +## Criterios de validación + +### Técnicos +- [ ] Migración 018 creada y aplicada en Supabase +- [ ] `insert_processes` en la DB incluye la cláusula de client_editor (verificar con `pg_policies`) +- [ ] `npm run build` sin errores TypeScript +- [ ] `npm run test` sin regresiones (596 tests) + +### Funcionales (validación visual mandatoria del director) +- [ ] Loguear como `client_editor` → `/library` → botón "Importar BPMN" visible en el header +- [ ] Hacer click en "Importar BPMN" → lleva a `/import` (no redirige a `/`) +- [ ] `/import` muestra el drop zone; la sección de "procesos de ejemplo" NO aparece +- [ ] Subir un archivo BPMN real → proceso creado → workspace abre correctamente +- [ ] En Supabase: verificar que el proceso creado tiene `org_id` = org del client_editor (no null) +- [ ] Loguear como `client_viewer` → `/library` → botón "Importar BPMN" NO visible +- [ ] Si client_viewer navega manualmente a `/import` → redirige a `/` +- [ ] La biblioteca vacía de client_editor muestra botón de importar; la de client_viewer muestra "Contactá a tu administrador" + +--- + +## Restricciones explícitas + +- **NO** tocar políticas RLS de tablas distintas a `processes` (activities y gateways ya permiten client_editor) +- **NO** crear procesos de muestra en la DB para client_editor — el flujo es importar BPMNs reales +- **NO** modificar el workspace ni el reporte — client_editor ya puede usarlos +- **NO** agregar tests en esta etapa + +--- + +## Archivos autorizados a modificar/crear + +``` +supabase/migrations/ +└── 018_client_editor_insert.sql ← crear y aplicar + +src/features/ +├── import/ +│ └── ImportPage.tsx ← guards + orgId + ejemplos + texto marca +└── library/ + └── LibraryPage.tsx ← botón header + empty state diferenciado +``` + +--- + +## Commits esperados + +``` +feat(db): migración 018 — INSERT policy para client_editor en processes +feat(import): client_editor puede importar BPMN; orgId asignado automáticamente +feat(library): botón Importar BPMN visible para client_editor; empty state diferenciado +fix(import): corregir texto de marca — "Process Cost Platform" → "InQ ROI" +``` + +--- + +## Reporte esperado + +1. Contenido exacto de `018_client_editor_insert.sql` +2. Resultado de la query de verificación en `pg_policies` para `insert_processes` +3. Lista de cambios en `ImportPage.tsx` (resumen compacto) +4. Lista de cambios en `LibraryPage.tsx` (resumen compacto) +5. `npm run build` y `npm run test` (con conteo) +6. **Solicitar validación visual del director** — describir el estado de la UI para client_editor antes del OK formal