chore(sprint-6): abrir sprint — BRIEF + OBSERVATIONS reset
Some checks failed
/ Deploy to Cloudflare Pages (push) Has been cancelled
Some checks failed
/ Deploy to Cloudflare Pages (push) Has been cancelled
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
# OBSERVATIONS — Sprint 5
|
# OBSERVATIONS — Sprint 6
|
||||||
|
|
||||||
> Hallazgos descubiertos durante el sprint actual.
|
> Hallazgos descubiertos durante el sprint actual.
|
||||||
> Este archivo se vacía al cerrar el sprint: los hallazgos se promocionan a TECH_DEBT.md o BACKLOG.md, o quedan resueltos.
|
> Este archivo se vacía al cerrar el sprint: los hallazgos se promocionan a TECH_DEBT.md o BACKLOG.md, o quedan resueltos.
|
||||||
>
|
>
|
||||||
> **Sprint 4 cerrado el 2026-06-18.** Observaciones archivadas — ítems migrados a BACKLOG.md y TECH_DEBT.md.
|
> **Sprint 5 cerrado el 2026-06-23.** Observaciones archivadas — ítems migrados a BACKLOG.md y TECH_DEBT.md.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -18,92 +18,13 @@
|
|||||||
|
|
||||||
## Hallazgos activos
|
## Hallazgos activos
|
||||||
|
|
||||||
### [RESOLVED] Etapa 1 — Workspace loading fix + carry-over skeleton
|
*(vacío)*
|
||||||
|
|
||||||
**Estado:** OK formal del director — 2026-06-19.
|
|
||||||
**Fix principal:** `process-store.ts` y `useReportData.ts` usaban `getSession()` sin timeout; reemplazados inicialmente por `getSessionSafe()`. Error Boundary + estado `error` inline con retry button agregados.
|
|
||||||
**⚠️ Corrección histórica (Etapa 4E):** `getSessionSafe()` fue identificado como contraproducente y eliminado completamente. Usaba `Promise.race` con un timeout que abandonaba la Promise interna de `getSession()`, dejando operaciones huérfanas ocupando el `processLock` indefinidamente. El fix correcto fue `lockAcquireTimeout: 30000` en `supabase.ts` + eliminación de `getSessionSafe()` en todos los archivos. El código actual NO usa `getSessionSafe()`.
|
|
||||||
**Carry-over a Etapa 2:** `WorkspaceSkeleton.tsx` fue creado pero el spinner del router-level guard (TanStack Router) intercepta antes de que el componente monte. El skeleton no aparece en la práctica. Corregir en Etapa 2 como Fix 0 (bajo esfuerzo).
|
|
||||||
**SupabaseAuthService.ts:** su `getSession()` directo documentado como excepción intencional (necesita el objeto sesión real, no es barrera descartable). Sin callers activos. Ver TECH_DEBT.md para el ítem pendiente.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hallazgos resueltos durante el sprint
|
## Hallazgos resueltos durante el sprint
|
||||||
|
|
||||||
### [RESOLVED] Etapas 3 + 3B — Heatmap gradiente + toggle + persistencia
|
*(vacío)*
|
||||||
|
|
||||||
**Estado:** OK formal del director — 2026-06-19.
|
|
||||||
**Entregado:** gradiente 4 stops (#10b981→#f59e0b→#f97316→#ef4444), modos percentile/minmax, `useHeatmapMode` hook con localStorage, HeatmapModeToggle, leyenda PDF 4 stops, zoom controls movidos a bottom-left.
|
|
||||||
**Lección operativa:** Dokploy con Autodeploy desactivado requiere `git push origin main` explícito antes de validar en producción. Los commits `a65bec4` y `e8a4a1b` estaban locales sin pushear — Dokploy desplegaba Etapa 2 mientras se validaba Etapa 3. La validación fallida fue contra código desactualizado, no contra bugs reales.
|
|
||||||
|
|
||||||
### [RESOLVED] Etapa 2 — Zoom BPMN fix + controles + skeleton
|
|
||||||
|
|
||||||
**Estado:** OK formal del director — 2026-06-19.
|
|
||||||
**Fixes:** fit-viewport `'auto'` agregado (una línea), zoom-in/zoom-out en esquina inferior derecha (Lucide icons, 1.2x factor, límites 0.1x–4x), skeleton wired correctamente en WorkspacePage (guard `isLoading` simple sin `!currentProcess`).
|
|
||||||
**Carry-over a Etapa 3:** controles de zoom solapan el logo bpmn.io (esquina inferior derecha). Fix: mover a esquina inferior izquierda (`left: 12` en lugar de `right: 12`). Una línea CSS.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### [RESOLVED] Etapa 3 — Heatmap gradiente 4 stops + persistencia de modo + zoom position
|
|
||||||
|
|
||||||
**Estado:** pendiente OK formal del director.
|
|
||||||
**Fixes Etapa 3:**
|
|
||||||
- `colors.ts`: gradiente continuo verde→amarillo→naranja→rojo (interpolación genérica N-stops), modos `'percentile'`/`'minmax'` reemplazan `'relative'`/`'absolute'`
|
|
||||||
- `useHeatmapMode.ts` (hook nuevo): persiste preferencia en `localStorage` con lazy initializer en `useState`
|
|
||||||
- `ReportPage.tsx`: reemplaza `useState<HeatmapMode>('relative')` por `useHeatmapMode()`
|
|
||||||
- `BpmnCanvas.tsx`: zoom-in/zoom-out movidos de `right:12` a `left:12` (evita solapar logo bpmn.io)
|
|
||||||
- PDF: leyenda de 4 stops con interpolación. Tests: 528 Vitest verdes. E2E recalibrados con distancia euclidiana.
|
|
||||||
|
|
||||||
**Fixes Etapa 3B verificados (incluidos en Etapa 3):**
|
|
||||||
- Fix 1 (repintado de canvas al cambiar toggle): `mode` ya estaba como dependencia del `useEffect` en `HeatmapCanvas.tsx` desde el MVP. El bug fue observado durante implementación intermedia; resuelto con los renombres de Etapa 3.
|
|
||||||
- Fix 2 (persistencia localStorage): `useHeatmapMode()` con lazy initializer correcto; `ReportPage` usa el hook.
|
|
||||||
- Fix 3 (zoom position): `left: 12` en `BpmnCanvas.tsx`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### [RESOLVED] Etapa 4 — Recursos por proceso + perfil empresa + fix freeze ProfileSheet
|
|
||||||
|
|
||||||
**Estado:** OK formal del director — 2026-06-23.
|
|
||||||
|
|
||||||
**Entregado:**
|
|
||||||
- `ResourceCatalogPage`: columna "Procesos" con conteo de procesos que usan cada recurso. `resource-repo.ts` expone `getProcessCountsByResourceId()` y `getProcessesByResourceId()` para carga on-demand.
|
|
||||||
- Perfil de usuario: campo `company` en tabla `users` (Supabase), campo en `ProfileSheet`, visible en dropdown `AppHeader`.
|
|
||||||
- Fix `||` vs `??` en cadena de propagación de `name`: `buildAuthUser`, `getUserFromStorage`, `syncProfileFromDB`, `AuthContext useEffect` — evita que Google OAuth con `full_name: ""` deje el botón Guardar deshabilitado.
|
|
||||||
|
|
||||||
**Bug crítico resuelto — freeze de UI al guardar perfil (12 commits, 2026-06-23):**
|
|
||||||
|
|
||||||
Dos causas independientes bajo el mismo síntoma ("la app se congela"):
|
|
||||||
|
|
||||||
1. **Contención de `processLock`:** `supabase.from().update()` en `ProfileSheet` adquiría el lock vía `getSession()` interno, bloqueando otras queries de la página. Fix: reemplazo por `fetch()` nativo con token leído de `localStorage` (`supabase.auth.token`), sin pasar por el cliente Supabase.
|
|
||||||
|
|
||||||
2. **`@radix-ui/react-remove-scroll` no limpiaba `pointer-events:none` del body:** al cerrar el Sheet, el cleanup de Radix no corría porque el re-render de `AuthContext` (disparado por `updateUser`) interrumpía la animación de cierre. `document.body.style.pointerEvents = 'none'` quedaba permanente, bloqueando toda la UI excepto el canvas BPMN (que fija `pointer-events: all` en su propio SVG). Fix: wrapper `Sheet` en `src/components/ui/sheet.tsx` con `useEffect` que observa el prop `open` y limpia el body 400ms después del cierre si no hay otro dialog abierto.
|
|
||||||
|
|
||||||
**Lección operativa (cosechada a `methodology/`):** ante un bug de UI que persiste tras 2+ fixes teóricos basados en lectura de código, pedir evidencia observable directa (DOM, Network, consola) antes de continuar. El diagnóstico definitivo llegó de un dato: `document.body.style.pointerEvents = 'none'`. Ver `INFORME_ETAPA_4_FREEZE_PERFIL.md` para cronología completa.
|
|
||||||
|
|
||||||
**Archivos modificados:**
|
|
||||||
- `src/auth/SupabaseAuthService.ts` — `||` en `buildAuthUser` y `syncProfileFromDB`
|
|
||||||
- `src/auth/AuthContext.tsx` — `||` en `getUserFromStorage` y `useEffect` de sync
|
|
||||||
- `src/components/ProfileSheet.tsx` — fetch nativo, optimistic close, defer `updateUser` 350ms
|
|
||||||
- `src/components/ui/sheet.tsx` — wrapper defensivo con cleanup de `pointer-events`
|
|
||||||
- `src/lib/supabase.ts` — `lockAcquireTimeout: 30000`, eliminación de `getSessionSafe()`
|
|
||||||
- `src/store/library-store.ts`, `src/store/process-store.ts`, `src/features/report/useReportData.ts` — eliminación de `getSessionSafe()`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### [RESOLVED] Etapa 5 — Columna "Eficiencia de automatización" en ComparisonTable
|
|
||||||
|
|
||||||
**Estado:** implementado, tests verdes (542 Vitest). Pendiente OK formal del director.
|
|
||||||
**Entregado:** dos columnas A/B para focus group — "Ahorro esperado" (`ahorro$ × executionProbability`) y "Eficiencia" (`ahorro$ × executionProbability / executionTimeMinutes`, formato `valor currency/min`). Sort multi-columna con headers clickeables, tooltips explicativos, barras de progreso proporcionales (`MetricCell`). PDF explícitamente fuera de scope (6ª columna no entra en 138mm de ancho).
|
|
||||||
**Desviación de scope necesaria:** cambiar el sort por defecto a `efficiency` rompía un test existente en `roi-components.test.tsx` que asumía que un solo click invertía el orden. Ajustado a doble-click (activar columna → invertir) para ejercitar el comportamiento real sin dejar la suite roja — el propio prompt exigía `npm run test` verde.
|
|
||||||
**Carry-over a BACKLOG:** celda de Eficiencia corta el valor+unidad en dos líneas por ancho — falta `whitespace-nowrap` en el `<span>` de `MetricCell`.
|
|
||||||
|
|
||||||
### [RESOLVED] Etapa 6 — Limpieza técnica: E2E Supabase + flakiness + documentación
|
|
||||||
|
|
||||||
**Estado:** implementado, 542 Vitest + 9 smoke E2E + 6 specs de payback/ROI (3 corridas) verdes. Pendiente OK formal del director.
|
|
||||||
**Diagnóstico 6a-extra (auth-setup.ts):** bug NO confirmado. `auth-js` define `STORAGE_KEY='supabase.auth.token'` como default de `GoTrueClient`, pero `@supabase/supabase-js`'s `createClient()` lo sobrescribe calculando `sb-${projectRef}-auth-token` desde la URL — exactamente la clave que ya usaba `auth-setup.ts`. Confirmado empíricamente: smoke test "app header shows user avatar" (aserción no-vacía, requiere sesión real) pasa; `auth-state.json` generado contiene la clave esperada. Documentado inline en `auth-setup.ts`.
|
|
||||||
**6b — data-testid + fix flakiness:** `data-testid="save-activity-btn"` en `ActivityPanel.tsx`. `payback-etapa-2.spec.ts` y `export-roi.spec.ts` reemplazan click directo por `waitForSelector(':not([disabled])')` → click → `waitForSelector('[disabled]')`. Confirmado estable 3/3 corridas tras rebuild (el `webServer` de Playwright sirve `dist/` sin rebuildear — hay que `npm run build` antes de cada corrida E2E tras tocar `src/`).
|
|
||||||
**6a — E2E Dexie→Supabase:** `export-pdf.spec.ts` (test "Heatmap con gradiente real") y `validate-dod-etapa4.spec.ts` reescritos con `service_role_key`. Sin la key en `.env.test`, ambos hacen `test.skip()` con mensaje descriptivo — confirmado (2 skipped, 0 failed). `afterAll` limpia el proceso creado.
|
|
||||||
**Desviación de scope explícita:** se encontraron 9 specs adicionales + `GlobalSettingsPanel.tsx` con el mismo patrón flaky de "Guardar" sin `data-testid`. No tocados — el prompt listaba solo 2 specs y 1 archivo de producción. Documentado en TECH_DEBT.md como ítems nuevos.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
188
sprints/sprint-6/BRIEF.md
Normal file
188
sprints/sprint-6/BRIEF.md
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
# Sprint 6 — BRIEF
|
||||||
|
|
||||||
|
> InQ ROI — Client-readiness polish + análisis de sensibilidad
|
||||||
|
> Inicio: 2026-06-23
|
||||||
|
> Foco: primer uso real con cliente externo como norte operativo
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contexto
|
||||||
|
|
||||||
|
Sprint 5 cerró con el producto estable, en uso interno y con el reporte de ROI funcional. La pregunta que orientó la apertura de Sprint 6 fue: **¿qué le falta a InQ ROI para correrlo en vivo frente a un cliente y producir un informe de ROI creíble hoy?**
|
||||||
|
|
||||||
|
Diagnóstico al cierre de Sprint 5:
|
||||||
|
|
||||||
|
- El motor de simulación, el heatmap, la ComparisonTable y los 3 PDFs están listos.
|
||||||
|
- El consultor puede preparar el proceso con anticipación y correr la simulación en reunión.
|
||||||
|
- Dos gaps concretos antes de la primera sesión con cliente externo:
|
||||||
|
1. **Sin logo en el header de los PDFs** — el entregable parece borrador sin marca visual.
|
||||||
|
2. **Sin análisis de sensibilidad** — el ROI es un número puntual; cualquier cliente sofisticado pregunta "¿y si el volumen cae 20%?" y no hay respuesta dentro de la herramienta.
|
||||||
|
|
||||||
|
Sprint 6 cierra esos dos gaps.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Etapas
|
||||||
|
|
||||||
|
### Etapa 1 — Logo InQuality en header de PDFs + whitespace-nowrap
|
||||||
|
|
||||||
|
**Prioridad:** bloqueante para entregable a cliente externo.
|
||||||
|
|
||||||
|
**Logo en PDF header:**
|
||||||
|
|
||||||
|
Los assets ya existen en `assets/`. Cuatro PNGs disponibles — usar el horizontal color para fondos claros:
|
||||||
|
- `MARCA FINAL 2023 AREA DE SEGURIDAD 1 COLOR.png` — candidato principal (header blanco)
|
||||||
|
- `MARCA FINAL 2023 AREA DE SEGURIDAD 1 BCO.png` — alternativa para headers con fondo oscuro (si aplica)
|
||||||
|
|
||||||
|
El logo va en el header compartido de los 3 PDFs (Actual, Automatizado, ROI). La función `drawSharedHeader` en `src/lib/export/pdf-sections-shared.ts` es el punto de inserción.
|
||||||
|
|
||||||
|
**Implementación:**
|
||||||
|
|
||||||
|
Convertir el PNG a base64 en tiempo de ejecución usando `fetch` + `arrayBuffer` → `btoa`, o pre-convertirlo como asset importado con `?url` de Vite. Insertar con `doc.addImage(base64, 'PNG', x, y, width, height)`. El logo reemplaza o complementa el texto "InQuality" que pueda existir actualmente en el header.
|
||||||
|
|
||||||
|
Restricciones:
|
||||||
|
- Ancho máximo: ~35mm (no puede dominar el header, el título del proceso sigue siendo protagonista)
|
||||||
|
- Alineación: derecha del header (o izquierda — validar visualmente con el director antes del OK formal)
|
||||||
|
- Mantener "Powered by InQuality" en el footer — no reemplaza, complementa
|
||||||
|
|
||||||
|
**Fold-in — whitespace-nowrap en celda de Eficiencia:**
|
||||||
|
|
||||||
|
En `src/features/report/ComparisonTable.tsx`, en el `<span>` del número dentro de `MetricCell` para la columna Eficiencia, agregar `whitespace-nowrap` para que "1.02 USD/min" no se corte en dos líneas.
|
||||||
|
|
||||||
|
Una línea de cambio. Sin tests que actualizar.
|
||||||
|
|
||||||
|
**Criterios:**
|
||||||
|
- [ ] Logo visible en el header de los 3 PDFs exportados
|
||||||
|
- [ ] Tamaño y posición validados visualmente por el director
|
||||||
|
- [ ] "Powered by InQuality" sigue en el footer de todas las páginas
|
||||||
|
- [ ] "1.02 USD/min" aparece en una sola línea en ComparisonTable
|
||||||
|
- [ ] `npm run lint` sin errores
|
||||||
|
- [ ] `npm run build` limpio
|
||||||
|
- [ ] Tests Vitest verdes (sin regresiones)
|
||||||
|
- [ ] Validación visual del director sobre el PDF antes del OK formal
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Etapa 2 — Panel de análisis de sensibilidad
|
||||||
|
|
||||||
|
**Contexto del problema:**
|
||||||
|
|
||||||
|
El ROI que calcula InQ ROI hoy es nominal y puntual: dadas estas condiciones exactas, el retorno es X. Pero las condiciones de un proceso real tienen incertidumbre — el volumen puede variar, la inversión puede dispararse, las estimaciones de tiempo pueden estar erradas. Un consultor que presente un ROI de USD 1.2M sin poder responder "¿y si el volumen cae 30%?" pierde credibilidad frente a cualquier CFO.
|
||||||
|
|
||||||
|
**Qué NO hacer:** re-simulación completa (implica cargar el BPMN, recorrer gateways, recalcular recursos — es lento y no necesario). Los costos por instancia del proceso ya están calculados y son estables. Solo cambian los agregados anuales.
|
||||||
|
|
||||||
|
**Qué SÍ hacer:** un panel que recalcula únicamente las fórmulas de ROI (`domain/roi.ts`) con inputs modificados por sliders — sin tocar el motor de simulación. El cálculo es instantáneo.
|
||||||
|
|
||||||
|
**Variables de sensibilidad (dos sliders):**
|
||||||
|
|
||||||
|
1. **Volumen (frecuencia anual):** rango -50% a +100%, paso 10%, default 0% (= valor configurado en el proceso). Afecta: ahorro anual, ROI, payback, trayectoria acumulada.
|
||||||
|
|
||||||
|
2. **Inversión en automatización:** rango -50% a +100%, paso 10%, default 0% (= valor configurado). Afecta: ROI, payback, trayectoria acumulada. No afecta el ahorro por ejecución.
|
||||||
|
|
||||||
|
**UX — versión mínima:**
|
||||||
|
|
||||||
|
- Panel colapsable "Análisis de sensibilidad" debajo de los KPIs de ROI en la pestaña "Comparación + ROI"
|
||||||
|
- Dos sliders con label, valor actual y delta en porcentaje (ej: "Volumen: 12.000 ejecuciones/año (+20%)")
|
||||||
|
- Los 4 KPIs de ROI (Ahorro por ejecución, Ahorro anual, Payback, ROI anual) se actualizan en tiempo real al mover los sliders
|
||||||
|
- Badge o indicador visual que muestra que los valores están en modo "análisis" (no son los valores base)
|
||||||
|
- Botón "Restablecer" que vuelve a los valores originales del proceso
|
||||||
|
|
||||||
|
**UX — versión wow (+criterio de wow):**
|
||||||
|
|
||||||
|
Además de la versión mínima, agregar una visualización de rango: para la variable más sensible (volumen), mostrar una banda de incertidumbre en el `CumulativeSavingsChart` existente — la línea actual se convierte en el caso base, y se agrega un área sombreada que muestra el rango [-30%, +30%] en el mismo gráfico. Misma paleta naranja, opacidad reducida para el rango. Esto convierte el gráfico de trayectoria de "certeza" a "escenario con rango", que es la forma en que un consultor financiero presenta proyecciones.
|
||||||
|
|
||||||
|
Implementar versión wow si el costo extra es < 40% del tiempo de la versión mínima.
|
||||||
|
|
||||||
|
**Implementación técnica:**
|
||||||
|
|
||||||
|
- El estado de los sliders vive en un `useState` local en `ReportPage.tsx` o en un componente `SensitivityPanel` nuevo — no persiste (se resetea al recargar, es análisis exploratorio)
|
||||||
|
- El recálculo de KPIs se hace importando las funciones de `domain/roi.ts` directamente, pasando los inputs modificados
|
||||||
|
- `CumulativeSavingsChart` recibe los datos recalculados vía props — no requiere cambios internos si ya acepta `roi: RoiResult` como prop
|
||||||
|
- El panel NO se exporta al PDF en esta etapa (es una feature interactiva del reporte web)
|
||||||
|
|
||||||
|
**Restricciones:**
|
||||||
|
- NO re-simular (no llamar al motor BPMN ni a `simulation.ts`)
|
||||||
|
- NO persistir en Supabase (es exploración, no configuración)
|
||||||
|
- NO tocar `domain/roi.ts` (solo consumirlo)
|
||||||
|
- El valor base del proceso (frecuencia, inversión) NO cambia en base de datos
|
||||||
|
|
||||||
|
**Criterios:**
|
||||||
|
- [ ] Panel visible en la pestaña "Comparación + ROI", colapsado por defecto
|
||||||
|
- [ ] Slider de volumen: -50% a +100%, los KPIs se actualizan en tiempo real
|
||||||
|
- [ ] Slider de inversión: -50% a +100%, los KPIs se actualizan en tiempo real
|
||||||
|
- [ ] Los valores base (sin ajuste de sliders) son idénticos a los KPIs actuales
|
||||||
|
- [ ] Botón "Restablecer" vuelve los sliders a 0%
|
||||||
|
- [ ] Indicador visual de "modo análisis" activo
|
||||||
|
- [ ] (Wow) Banda de rango visible en CumulativeSavingsChart si se implementa
|
||||||
|
- [ ] Tests unitarios del recálculo de sensibilidad en Vitest
|
||||||
|
- [ ] `npm run lint` sin errores
|
||||||
|
- [ ] `npm run build` limpio
|
||||||
|
- [ ] Validación visual del director antes del OK formal
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Etapa 3 — Quick wins y limpieza técnica
|
||||||
|
|
||||||
|
**3a — Investigación auth E2E localStorage (TECH_DEBT `[INVESTIGATING]`):**
|
||||||
|
|
||||||
|
Contradicción documentada en TECH_DEBT.md: en producción, `ProfileSheet` lee `supabase.auth.token`; en E2E, `auth-setup.ts` escribe `sb-${projectRef}-auth-token` y los smoke tests pasan. Determinar definitivamente qué clave usa el cliente Supabase de la app en producción comparando el localStorage real vs el `auth-state.json`.
|
||||||
|
|
||||||
|
Acción concreta: agregar un spec E2E que haga una query autenticada a Supabase y afirme que devuelve el `email` real del usuario de test (no vacío). Si el test pasa, el auth E2E funciona realmente. Si falla, el bug está confirmado.
|
||||||
|
|
||||||
|
**3b — Cleanup `setTimeout(350)` en ProfileSheet:**
|
||||||
|
|
||||||
|
`src/components/ProfileSheet.tsx` tiene un `setTimeout(350)` que difiere `updateUser` como mitigación de la race condition con Radix. El fix definitivo vive en `sheet.tsx` (useEffect sobre prop `open`). El setTimeout es redundante pero inofensivo.
|
||||||
|
|
||||||
|
Eliminar el setTimeout, verificar que el fix de `sheet.tsx` sea suficiente. Un test manual de guardar perfil confirma que funciona.
|
||||||
|
|
||||||
|
**3c — Animación de expansión sección "Automatización" en ActivityPanel:**
|
||||||
|
|
||||||
|
La sección usa el truco de `max-height` para la animación de expand/collapse. La aceleración no es lineal en los últimos píxeles (se nota el "freno" al final).
|
||||||
|
|
||||||
|
Fix: usar `useRef + scrollHeight` para animar a la altura real del contenido con una transición CSS. Impacto: micro-pulido visual, moderado esfuerzo.
|
||||||
|
|
||||||
|
Solo implementar si 3a y 3b no consumen el slot completo de la etapa.
|
||||||
|
|
||||||
|
**Criterios:**
|
||||||
|
- [ ] Spec E2E de auth: verde si el auth funciona, o diagnóstico definitivo + fix si no funciona
|
||||||
|
- [ ] `setTimeout(350)` eliminado de ProfileSheet, funcionalidad verificada manualmente
|
||||||
|
- [ ] TECH_DEBT.md actualizado: marcar RESOLVED los ítems cerrados
|
||||||
|
- [ ] (Opcional) Animación de expansión más fluida en ActivityPanel
|
||||||
|
- [ ] `npm run test` → mantener o superar 542 tests verdes
|
||||||
|
- [ ] Validación del director sobre el estado de la documentación
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Distribución del sprint
|
||||||
|
|
||||||
|
| Área | Etapas | % estimado |
|
||||||
|
|---|---|---|
|
||||||
|
| PDF (logo) | 1 parcial | ~15% |
|
||||||
|
| Web app features (sensibilidad) | 2 | ~65% |
|
||||||
|
| Infraestructura / deuda técnica | 3 | ~20% |
|
||||||
|
|
||||||
|
Dentro del rango de rebalanceo comprometido (60-70% web, 15-25% PDF, 10-15% infra).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Qué NO entra en Sprint 6
|
||||||
|
|
||||||
|
- Historial de simulaciones / múltiples simulaciones por proceso
|
||||||
|
- Modelo B (dos BPMNs AS-IS / TO-BE)
|
||||||
|
- Export Excel
|
||||||
|
- Modo offline / PWA
|
||||||
|
- i18n
|
||||||
|
- Compartir procesos con usuarios externos (`setShared()`)
|
||||||
|
- Keycloak / migración de auth
|
||||||
|
- Análisis de sensibilidad en PDF (es feature interactiva, PDF es estático)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Definition of Done del sprint
|
||||||
|
|
||||||
|
- [ ] 3 etapas con OK formal del director (validación visual de Etapas 1 y 2; validación documental de Etapa 3)
|
||||||
|
- [ ] `npm run build` limpio
|
||||||
|
- [ ] `npm run lint` sin warnings nuevos
|
||||||
|
- [ ] Tests Vitest: mantener o superar 542
|
||||||
|
- [ ] OBSERVATIONS.md con hallazgos del sprint
|
||||||
|
- [ ] STRATEGIC_DIRECTION.md actualizado al cerrar el sprint
|
||||||
Reference in New Issue
Block a user