fix(sprint-6/etapa-3): localStorage key en ProfileSheet + eliminar setTimeout(350) + specs E2E de auth
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:
51
TECH_DEBT.md
51
TECH_DEBT.md
@@ -47,15 +47,25 @@ en los 3 PDFs. Si hay truncamiento, evaluar:
|
||||
|
||||
## Deuda media — afecta DX o evolución del producto
|
||||
|
||||
### [INVESTIGATING] Clave de localStorage del auth E2E vs producción
|
||||
**Estado actual:** contradicción no resuelta entre dos hechos empíricos verificados:
|
||||
- En producción, `ProfileSheet.getAccessToken()` lee `supabase.auth.token` y funciona correctamente (Sprint 5 Etapa 4).
|
||||
- En E2E, `auth-setup.ts` escribe la sesión bajo `sb-${projectRef}-auth-token` y el smoke test "app header shows user avatar" pasa.
|
||||
**Hipótesis:** el cliente Supabase de la app (`src/lib/supabase.ts`) y el de `auth-setup.ts` podrían estar usando `storageKey` distinto. La documentación inline en `auth-setup.ts` explica el comportamiento observado pero no reconcilia la contradicción.
|
||||
**Impacto:** si el auth E2E no funciona realmente (sesión vacía), todos los specs con `storageState` serían inválidos — pasarían por ausencia de assertions fuertes, no porque el auth funcione.
|
||||
**Acción:** en Sprint 6, comparar el `localStorage` real en producción vs el `auth-state.json` del E2E. Ejecutar un spec que haga una query autenticada a Supabase y afirme que devuelve datos reales del usuario de test.
|
||||
**Archivos afectados:** `tests/e2e/setup/auth-setup.ts`, `src/lib/supabase.ts`.
|
||||
**Origen:** Sprint 5 Etapa 6 diagnóstico de auth-setup.
|
||||
### [RESOLVED] Clave de localStorage del auth E2E vs producción
|
||||
**Resultado:** la "contradicción" era un bug real, no solo una discrepancia de documentación.
|
||||
`tests/e2e/auth-localStorage-key.spec.ts` (Sprint 6 Etapa 3) confirmó empíricamente que la
|
||||
única clave presente en `localStorage` con sesión real es `sb-${projectRef}-auth-token`
|
||||
(`sb-xgqbkxcliyjzisoccsur-auth-token` en este proyecto) — `'supabase.auth.token'` (STORAGE_KEY
|
||||
default de `@supabase/auth-js`'s `GoTrueClient` en aislamiento) **no existe**, porque
|
||||
`@supabase/supabase-js`'s `createClient()` sobrescribe ese default calculando la clave
|
||||
`sb-`-prefijada desde la URL del proyecto.
|
||||
|
||||
`ProfileSheet.getAccessToken()` leía `'supabase.auth.token'` — la clave vieja, inexistente.
|
||||
Esto significaba que **el guardado de perfil (nombre, empresa) nunca llegaba a Supabase**:
|
||||
`getAccessToken()` retornaba `null`, el `if (!token) return` silenciaba el error, y el usuario
|
||||
veía el cambio solo en memoria (`updateUser()`) sin persistir. Bug real, no solo deuda de
|
||||
documentación.
|
||||
|
||||
**Fix:** `getAccessToken()` ahora calcula `sb-${projectRef}-auth-token` igual que
|
||||
`auth-setup.ts`. Verificado end-to-end: PATCH a `/rest/v1/users` devuelve 204, y tras un
|
||||
reload completo de página el valor guardado se relee correctamente desde la DB.
|
||||
**Sprint cerrado en:** Sprint 6 Etapa 3.
|
||||
|
||||
### [BACKLOG] `getCurrentUser()` en SupabaseAuthService — sin callers activos
|
||||
**Estado actual:** `SupabaseAuthService.getCurrentUser()` usa `getSession()` directamente (sin timeout, sin processLock workaround). Es la única excepción documentada a la regla — justificada porque necesita el objeto sesión completo, no solo una barrera. Sin callers activos hoy.
|
||||
@@ -64,11 +74,14 @@ en los 3 PDFs. Si hay truncamiento, evaluar:
|
||||
**Archivos afectados:** `src/auth/SupabaseAuthService.ts` (~línea 27, comentario explicativo presente).
|
||||
**Origen:** OBSERVATIONS Sprint 5 Etapa 1 — ítem prometido que faltaba registrar acá.
|
||||
|
||||
### [BACKLOG] `setTimeout(350)` en ProfileSheet — candidato a limpieza
|
||||
**Estado actual:** `ProfileSheet.handleSave()` difiere `updateUser` 350ms como mitigación de la race condition con Radix. El fix definitivo vive en `src/components/ui/sheet.tsx` (cleanup defensivo de `pointer-events`). El setTimeout es redundante pero inofensivo.
|
||||
**Solución propuesta:** eliminar el `setTimeout`, verificar que el fix en `sheet.tsx` sea suficiente por sí solo.
|
||||
**Archivos afectados:** `src/components/ProfileSheet.tsx`.
|
||||
**Origen:** Sprint 5 Etapa 4G (fix intermedio que quedó al resolverse la causa raíz en 4H).
|
||||
### [RESOLVED] `setTimeout(350)` en ProfileSheet — candidato a limpieza
|
||||
**Resultado:** `setTimeout` eliminado — `updateUser()` se llama directamente tras
|
||||
`onOpenChange(false)`. Verificado end-to-end (Sprint 6 Etapa 3): el fix definitivo en
|
||||
`src/components/ui/sheet.tsx` (`useEffect` sobre el prop `open`, limpieza defensiva de
|
||||
`pointer-events`) es suficiente por sí solo — `document.body.style.pointerEvents` queda
|
||||
vacío tras guardar, y la navegación posterior (click en "Importar BPMN") funciona sin
|
||||
bloqueos.
|
||||
**Sprint cerrado en:** Sprint 6 Etapa 3.
|
||||
|
||||
### [RESOLVED] E2E specs con Dexie directo — reescribir para Supabase
|
||||
**Resultado:** `export-pdf.spec.ts` (test "Heatmap con gradiente real") y `validate-dod-etapa4.spec.ts` reescritos para inyectar datos vía `@supabase/supabase-js` con `SUPABASE_SERVICE_ROLE_KEY` (bypasa RLS), en lugar de IndexedDB directo. `afterAll` borra el proceso creado por cada test (cascada en `activities`/`simulations`). Si `SUPABASE_SERVICE_ROLE_KEY` no está configurada en `.env.test`, ambos tests hacen `test.skip()` con mensaje descriptivo en vez de fallar — ver `.env.example`. Diagnóstico previo de `auth-setup.ts` confirmó que la storageKey (`sb-${projectRef}-auth-token`) ya era correcta (no era parte del problema): `@supabase/supabase-js`'s `createClient()` sobrescribe el `STORAGE_KEY` default de `auth-js` con esa clave calculada desde la URL.
|
||||
@@ -92,6 +105,16 @@ en los 3 PDFs. Si hay truncamiento, evaluar:
|
||||
**Costo:** bajo, mecánico — mismo cambio repetido 9 veces.
|
||||
**Origen:** Sprint 5 Etapa 6 — identificado durante el grep de diagnóstico, no aplicado por respeto al scope explícito del prompt.
|
||||
|
||||
### [BACKLOG] CumulativeSavingsChart — derivación de inversión base desde cumulativeSavingsHorizon
|
||||
**Estado actual:** cuando `roiBase` está presente (modo sensibilidad activo), el componente
|
||||
recupera la inversión original algebraicamente: `investment_base = roiBase.annualSavings * horizonYears - roiBase.cumulativeSavingsHorizon`.
|
||||
Es correcto mientras `horizonYears` del chart coincida con el usado en `calculateRoi` (hoy siempre es el mismo).
|
||||
**Riesgo:** si en el futuro el chart recibe un horizonte diferente al del cálculo de ROI, el valor
|
||||
de referencia del eje Y para la línea base será incorrecto, sin error visible.
|
||||
**Solución propuesta:** agregar prop `investmentBase?: number` a `CumulativeSavingsChartProps`
|
||||
y pasar `process.automationInvestment` directamente desde `ReportPage`.
|
||||
**Costo:** bajo. **Origen:** Sprint 6 Etapa 2 — detectado en auditoría post-implementación.
|
||||
|
||||
### [INVESTIGATING] Dexie live queries (sincronización store ↔ db)
|
||||
|
||||
**Estado actual:** la invalidación del resultado de simulación se garantiza vía ESLint rule (`no-restricted-imports`) + convención: todas las mutaciones pasan por `useProcessStore`.
|
||||
|
||||
Reference in New Issue
Block a user