Files
inq-roi-simulador-web/OBSERVATIONS.md

118 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OBSERVATIONS — Sprint 5
> 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.
>
> **Sprint 4 cerrado el 2026-06-18.** Observaciones archivadas — ítems migrados a BACKLOG.md y TECH_DEBT.md.
---
## Convención de etiquetas
- `[CURRENT-SPRINT]` — Se resuelve en este sprint
- `[DEFERRED-TECH-DEBT]` — Se va a TECH_DEBT.md al cerrar el sprint
- `[DEFERRED-BACKLOG]` — Se va a BACKLOG.md al cerrar el sprint
- `[RESOLVED]` — Resuelto durante el sprint, archivar al cierre
---
## Hallazgos activos
### [RESOLVED] Etapa 1 — Workspace loading fix + carry-over skeleton
**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
### [RESOLVED] Etapas 3 + 3B — Heatmap gradiente + toggle + persistencia
**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.1x4x), 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()`
---
## Hallazgos diferidos (promocionar al cerrar sprint)
*(vacío)*
---
## Notas operativas
- Los hallazgos resueltos quedan acá hasta el cierre del sprint. Al cerrar, se archiva o purga.
- Los hallazgos sin resolver se promocionan a `TECH_DEBT.md` o `BACKLOG.md` según corresponda.
- Este archivo NO contiene roadmap futuro ni deuda histórica — solo hallazgos del sprint en curso.
---
## Cierre del sprint (checklist)
Cuando el sprint cierre, ejecutar:
```
[ ] Verificar que todos los items [CURRENT-SPRINT] están RESOLVED
[ ] Mover items [DEFERRED-TECH-DEBT] a TECH_DEBT.md (si no están ya)
[ ] Mover items [DEFERRED-BACKLOG] a BACKLOG.md (si no están ya)
[ ] Archivar o purgar este archivo
[ ] Crear OBSERVATIONS.md vacío para el sprint siguiente
```