SensitivityPanel y CumulativeSavingsChart deben ser adyacentes: el slider afecta
el gráfico (doble línea) y el usuario no debe scrollear a través de la tabla de
comparación para ver el efecto. Reordenamiento de JSX puro, sin cambios de lógica.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
loadImageBase64 ahora retorna { base64, pixelWidth, pixelHeight } (320×210px tras el resize) en vez de solo el string.
PdfHeaderOptions agrega logoPixelWidth/logoPixelHeight.
drawSharedHeader: logo a 15mm de ancho con alto calculado proporcionalmente desde las dimensiones reales (≈9.8mm, ratio real ~1.53:1, no el 3.56:1 hardcodeado anterior). El logo se posiciona arriba (MARGIN - 1), y processName + fecha bajan a la línea siguiente sin superponerse. clientName baja una línea adicional cuando hay logo (para no chocar con la fecha), ajustando y antes del border-bottom.
Fallback a texto "InQ ROI" intacto cuando no hay logo.
getSessionSafe() tenía un problema de diseño: Promise.race([getSession(), timeout])
abandona la Promise de getSession() cuando gana el timeout. La Promise abandonada
deja una operación en PROCESS_LOCKS[name] que bloquea el chain. Con lockAcquireTimeout=5s
(default), un token refresh lento dispara ProcessLockAcquireTimeoutError cuyo handler
hace await previousOperation (colgada) → freeze permanente.
Fix: lockAcquireTimeout: 30000 (margen para redes lentas) + eliminar getSessionSafe()
de supabase.ts, library-store, process-store y useReportData. Las queries Supabase
llaman getSession() internamente vía _getAccessToken() que espera initializePromise
automáticamente — la barrera era redundante.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Feature A — Ver procesos asociados a un recurso:
- resource-repo.ts: getProcessCountsPerResource() (una query, N+1 evitado)
- resource-repo.ts: getProcessesForResource() (on-demand al expandir)
- ResourceCatalogPage: carga conteos en paralelo, columna "Procesos" con
badge naranja clicable, fila expandida con links a /workspace/:id
Feature B — Campo empresa en perfil:
- 013_add_company_to_users.sql: ALTER TABLE users ADD COLUMN IF NOT EXISTS company text
- AuthUser: agrega company? opcional
- SupabaseAuthService: lee company y name de tabla users en onAuthStateChange
- AuthContext: agrega updateUser() para reflejar cambios sin recargar
- ProfileSheet.tsx: Sheet con nombre/empresa editables, email read-only
- AppHeader: muestra empresa en dropdown + item "Editar perfil"
528 tests Vitest verdes. Build limpio.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix 0 (skeleton carry-over): el guard de Etapa 1 era isLoading && !currentProcess — fallaba al navegar directo entre dos workspaces distintos, porque el proceso anterior seguía en el store mientras el nuevo cargaba. Cambié a if (isLoading) return <WorkspaceSkeleton /> sin condición adicional, exactamente como pedía el brief.
Fix 1 (fit-viewport): una línea — el botón llamaba canvas.zoom('fit-viewport') sin 'auto' (la carga inicial sí lo tenía). Agregado.
Fix 2 (controles de zoom): agregué ZoomIn/ZoomOut de Lucide (no Tabler — ya está en el stack del proyecto, son visualmente equivalentes) en la esquina inferior derecha, apilados verticalmente, mismo estilo que el botón de encuadre (32×32px, fondo blanco semitransparente). Factor 1.2x, límites 0.1x–4x tal como especificaba el brief.
Verificación:
Build limpio
Lint: 2 warnings any nuevos en BpmnCanvas.tsx, consistentes con las 9 que ya existían en ese mismo archivo (el propio snippet del brief los prescribe así; bpmn-js tipa débilmente viewer.get()) — no es una categoría nueva de problema, lo marco para que quede explícito
Vitest: 521/521 verdes
E2E smoke: 9/9 verdes
Falta tu validación visual — en particular probar con Slow 3G que aparece el skeleton (no el spinner), y confirmar que el encuadre centra el diagrama y los botones de zoom no tapan nada.
Tier 1 — Automatizado
Build: ✅ limpio
Lint: ✅ limpio en archivos nuevos de Sprint 4 (separé resource-types.ts de resource-display.tsx para sacar 2 warnings de Fast Refresh; quedan 0 errores/warnings nuevos). Quedó 1 error preexistente en ReportPage.tsx (no tocado desde Sprint 3, fuera de scope) y ~102 warnings no-explicit-any preexistentes en tests viejos.
Tests unitarios: ✅ 521/521 verdes
Tests E2E: ⚠️ 43-44/48 verdes (varía levemente entre corridas) — detalle abajo
Auditoría inicial vs. estado final
Antes: 39/39 specs (100%) fallaban — ROJO-AUTH puro, todos por #bpmn-file-input nunca apareciendo (esperaban el flujo pre-Sprint-4 directamente en /).
Decisión tomada (con tu input): Opción A — sesión real. Creaste el usuario martin.bernal@inquality.com.py; yo verifiqué que no tenía fila en public.users y se la inserté con platform_role='platform_admin'. Implementé tests/e2e/setup/auth-setup.ts como globalSetup de Playwright: hace signInWithPassword, inyecta la sesión real en localStorage con el formato exacto que usa supabase-js v2, y genera tests/e2e/setup/auth-state.json (gitignored) en cada corrida.
Fix adicional necesario: todos los specs navegaban a / esperando el input de archivo ahí — ahora vive en /import. Corregí los 18 page.goto('/') → /import, incluyendo reescribir el flujo obsoleto de prod-smoke.spec.ts (esperaba una landing pre-auth que ya no existe).
Resultado: 33→43-44 specs pasan. Quedan 5-6 ROJO-OTRO, con dos causas raíz identificadas (no relacionadas con auth, fuera del mandato de esta etapa que pide no reescribir lógica de tests):
Botón "Guardar" en ActivityPanel queda deshabilitado (3 specs de PDF) — encontré algo extraño: el texto del botón dice "Guardar cambios" (que solo se renderiza si isDirty=true) pero Playwright lo sigue viendo disabled. Esto contradice la lógica simple de disabled={!isDirty} en el componente — sospecho un bug real de re-render en producción, pero diagnosticarlo a fondo requiere debugging en vivo. Recomiendo abrir esto como bug dedicado en un sprint futuro.
2 specs usan IndexedDB/Dexie directamente (export-pdf.spec.ts, validate-dod-etapa4.spec.ts) — Dexie se eliminó completamente en Etapa 4. Estos tests necesitan reescritura para inyectar datos vía Supabase en vez de IndexedDB — eso sí es "reescribir lógica de tests", explícitamente fuera de este alcance.
Los resultados varían levemente entre corridas porque Playwright corre specs en paralelo bajo la misma cuenta de test compartida — puede haber interferencia de datos entre specs concurrentes. Sugiero como mejora futura (no implementada ahora): --workers=1 para diagnóstico determinístico.
Entregables nuevos
tests/e2e/setup/auth-setup.ts — global setup con sesión real
tests/e2e/sprint-4-smoke.spec.ts — 9 tests (4 sin auth: login, redirects de /, /workspace, /recursos; 5 con auth: biblioteca sin 500, sin 406 en simulations, catálogo carga, avatar visible, import navega a workspace)
docs/CHECKLIST_ENTREGA.md — las 4 tiers completas
.env.test (gitignored) + .env.example documentado
.gitignore actualizado (.env.test, auth-state.json)
Polish
Textos de OwnershipBadge y "Compartir con equipo" ya estaban en español — sin cambios.
Tooltip "Disponible próximamente" para "Compartir con equipo": no lo agregué, tal como pedía el propio brief, consultarte antes. ¿Lo querés?
Tipos: Resource.processId? eliminado (vestigial); ResourceType ya tenía los 5 valores correctos, sin cambios.
resource-repo.ts: agregado getAllWithCreator() con JOIN a users!created_by (mismo patrón que Etapa 6) y tipo ResourceWithCreator. delete() ahora valida que no haya asignaciones activas en activity_resource_assignments antes de borrar — lanza error explicativo si las hay. Verifiqué ambos contra Supabase real: el JOIN funciona (FK reconocida por PostgREST) y el conteo de guarda también.
Nuevo — src/features/resources/:
resource-display.tsx — labels, colores/íconos por tipo (Lucide: User/Briefcase/Server/Wrench/Package) y ResourceTypeAvatar compartido
ResourceFormSheet.tsx — Sheet reutilizable para crear/editar, usado tanto en el catálogo como en el panel del workspace
ResourceCatalogPage.tsx — página /recursos: búsqueda, filtro por tipo, tabla con badge de tipo, costo, "creado por", editar/eliminar con confirmación
Nuevo — src/components/ui/sheet.tsx: componente shadcn Sheet (no existía), construido sobre @radix-ui/react-dialog que ya estaba instalado — no agregué dependencias nuevas.
ResourcesPanel.tsx rediseñado: ahora solo muestra recursos usados en el proceso actual (derivado de assignedResources), con conteo de actividades por recurso. CRUD completo se mudó a /recursos; el panel solo permite "Nuevo" (catálogo global) y tiene el link "Ver catálogo completo".
Router: ruta /recursos registrada.
ActivityPanel no se tocó, como indicaba el scope.
- SQL 010: tablas user_groups y group_memberships con RLS
- SQL 011: tabla process_access para acceso explícito a procesos
- SQL 012: función is_platform_admin() + políticas granulares (select/insert/update/delete) en processes
- types.ts: Process.ownerId (requerido)
- process-repo: fromRow mapea owner_id→ownerId; toRow preserva ownerId en updates; setShared() no-op documentado
- ImportPage: asigna ownerId: user.id al crear proceso
- LibraryPage: toggle Todos/Míos, OwnershipBadge (🔒/👤) en cada tarjeta, opción "Compartir con equipo" en menú de proceso propio con toast de confirmación
- Tests: ownerId: 'test-user' agregado a todos los fixtures de Process
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Scripts SQL 002-004: process_groups, processes, app_settings con RLS
- supabaseProcessRepo: save/getById/getAll/delete con mapeo camelCase↔snake_case
y limpieza Dexie en delete (actividades/gateways/resources/simulations)
- supabaseGroupRepo: save/getAll/getById/delete; FK ON DELETE SET NULL en processes
- supabaseSettingsRepo: get/update sobre fila singleton
- Stores actualizados: library-store y process-store usan repos Supabase para procesos
(actividades/gateways/recursos siguen en Dexie hasta Etapa 3-4)
- ImportPage y useReportData actualizados a supabaseProcessRepo
- userId inyectado internamente en repos via supabase.auth.getSession() — no se
threadea por la call stack; stores mantienen interfaces sin cambios
- 561/561 tests verdes, build limpio
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sprint 3 completo — 7 etapas:
- Etapa 1-2: biblioteca de procesos con agrupación por cliente (Dexie v4,
LibraryPage, library-store, groupId/tags en Process)
- Etapa 3: modal de configuración global por proceso (horizonte, frecuencia,
inversión, moneda) con validación y persistencia
- Etapa 4: panel de recursos rediseñado con soporte de unidades y minutos
de utilización (utilizationMinutes + units)
- Etapa 5: recursos en escenario automatizado — motor de simulación,
UI de edición en ActivityPanel, comparación AS-IS/TO-BE en reporte
- Etapa 6: PDF recursos automatizados, automatedAssignedResources requerido,
561 tests pasando
- Etapa 7: identidad de marca — AppHeader gradiente naranja/magenta con logo
InQuality en 5 páginas, favicon con logo real, logo/marca navegan a home
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Etapas 3-6 del Sprint 2. Resumen de cambios:
**Reporte web (Etapa 3)**
- ActivitiesTable: filas expandibles con desglose fijo + recursos por actividad
- CumulativeSavingsChart: fix payback label superpuesto con eje Y
- BpmnCanvas: badge ⚡ 14→20px
- TECH_DEBT cerrado: chart -inversión (ya estaba), payback label, badge
**Workspace (Etapa 4)**
- WorkspacePage: edición inline de nombre de proceso y cliente
(click → input → Enter/blur guarda en IndexedDB, checkmark naranja 1.5s)
**PDF (Etapas 5-6)**
- pdf-sections: drawResourcesSection — tabla condicional de recursos por actividad
con chips de tipo (rol/persona/sistema/equipamiento/insumo)
- pdf-export: página de recursos (pág. 4 cuando hay datos, metodología pasa a pág. 5)
- Fix truncamiento: splitTextToSize en resourceName y top3 ROI
- Fix texto: "ejecución" con tilde, header "Esp. (USD)" sin truncar
- TECH_DEBT cerrado: truncamiento notas metodológicas
**Tests**
- 7 tests nuevos: drawResourcesSection (4) + comportamiento condicional PDF (3)
- Total: 541 → 548 tests verdes
BREAKING: exportScenarioPdf ahora recibe activities[] como parámetro adicional.
Plataforma completa de análisis de costos operativos basada en BPMN 2.0.
Funcionalidades incluidas:
- Import de archivos BPMN 2.0 por drag & drop + 3 procesos de ejemplo
- Visualización read-only del diagrama (bpmn-js)
- Configuración de actividades (costo, tiempo, recursos asignados)
- CRUD de recursos (rol, persona, sistema, equipo, insumo)
- Configuración global (moneda, overhead %, nombre, cliente)
- Motor de simulación determinístico agregado con propagación de gateways XOR/AND
- Reporte visual con mapa de calor en dos modos (relativo/absoluto)
- Gráficos: KPIs, top actividades, composición, costo por recurso
- Export PDF (jsPDF + html2canvas) y CSV (papaparse)
- Persistencia en IndexedDB (Dexie)
- 268 tests unitarios/integración + 6 E2E con Playwright
- Deploy: https://process-cost-platform.pages.dev
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>