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

9.6 KiB
Raw Blame History

TECH_DEBT — InQ ROI

Deuda técnica, refactors postergados y decisiones arquitectónicas pendientes. Requiere consulta entre director y técnico para resolver. No incluye features de producto (ver BACKLOG.md) ni hallazgos de sprint actual (ver OBSERVATIONS.md).


Convención de etiquetas

  • [SPRINT-2] — Comprometido para resolución en el próximo sprint
  • [BACKLOG] — Disponible para asignar
  • [DEFERRED] — Pospuesto, requiere decisión arquitectónica
  • [INVESTIGATING] — Necesita análisis técnico antes de planear

Cada ítem incluye:

  • Estado actual del problema
  • Causa raíz hipotetizada
  • Impacto si no se resuelve
  • Solución propuesta
  • Archivos afectados (cuando aplica)

Deuda crítica — afecta calidad del entregable

[RESOLVED] Truncamiento de líneas largas en notas metodológicas

Estado actual: los caracteres Unicode rotos (Σ → £, → ") fueron resueltos en Etapa 8 mediante reescritura a ASCII puro (SUM, x, -). Decisión arquitectónica: la notación ASCII se mantiene como solución permanente porque alinea con terminología financiera/Excel.

Pendiente: verificar si todavía hay líneas largas que se truncan en margen derecho cuando una fórmula excede el ancho de página portrait.

Acción: test E2E que valide ancho de cada línea de notas metodológicas en los 3 PDFs. Si hay truncamiento, evaluar:

  • Opción A: usar doc.splitTextToSize() para wrap automático
  • Opción B: reformular fórmulas problemáticas en múltiples líneas en el texto fuente

Resultado: auditado en Sprint 2 Etapa 5-6. Dos líneas variables corregidas con splitTextToSize (topResource.resourceName en drawAnalysisSection y top3 en análisis ROI). Resto sin riesgo confirmado. 7 tests nuevos cubren el comportamiento. Sprint cerrado en: Sprint 2 Etapas 5-6.


Deuda media — afecta DX o evolución del producto

[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. Impacto si no se resuelve: ninguno mientras no tenga callers. Si en el futuro algún flujo llama getCurrentUser(), podría colgar el processLock si el servidor no responde. Solución propuesta: cuando adquiera callers reales, evaluar si supabase.auth.getUser() (token de localStorage, sin lock) es suficiente para ese caso. 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).

[BACKLOG] E2E specs con Dexie directo — reescribir para Supabase

Estado actual: export-pdf.spec.ts y validate-dod-etapa4.spec.ts inyectan datos vía Dexie/IndexedDB directamente. Dexie fue eliminado en Sprint 4 Etapa 4 — estos specs fallan en cualquier entorno donde no exista la DB local del sprint anterior. Impacto: 2 specs permanentemente rojos. No bloquean build ni deploy, pero degradan la señal de la suite E2E. Solución propuesta: reescribir los fixtures de datos para insertar vía Supabase (usando el test user martin.bernal@inquality.com.py y el service_role_key en el setup de Playwright). Limpiar datos de test después de cada corrida. Costo: medio. Requiere diseño cuidadoso de fixtures para no interferir con datos de producción.

[BACKLOG] E2E flakiness — "Guardar cambios" button timing en ActivityPanel

Estado actual: 3 specs de PDF fallan intermitentemente porque Playwright no encuentra el botón "Guardar cambios" en estado habilitado. Validación manual confirma que el botón SÍ funciona correctamente — es un issue de timing en el test, no un bug real. Causa probable: el test hace click en la actividad y espera el botón sin suficiente guard sobre el estado inicial de isDirty. Solución propuesta: agregar await page.waitForSelector('[data-testid="save-btn"]:not([disabled])') o un data-testid explícito que permita espera determinística. Costo: bajo. Una línea por spec afectado.

[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.

Riesgo a futuro: si en Sprint 2 la grilla de edición masiva requiere escrituras de alta frecuencia directas a IndexedDB (por performance), la convención actual no escala.

Solución a evaluar: migración a live queries de Dexie que invaliden el store automáticamente.

Acción pendiente: análisis técnico de costo/beneficio cuando se planee la grilla de edición masiva.

Origen: auditoría de Mayo 2026.

[BACKLOG] Indicador visual en reporte de actividades automatable

Estado: Sprint 1 usa solo leyenda de texto para diferenciar actividades automatables. Acción: evaluar si el cliente necesita más claridad visual (borde punteado o ícono diferenciador) cuando compara Actual vs Automatizado en reuniones. Decidir con feedback de uso real.

[BACKLOG] Paleta del heatmap — saturado vs pastel

Estado: los colores saturados actuales (#10B981, #F59E0B, #EF4444) funcionan bien en pantallas grandes de talleres InQuality. El brief de Sprint 1.5 propuso pasteles "más consultivos" (#BBF7D0, #FED7AA, #FECACA).

Decisión actual: mantener saturados (Sprint 1.5 Etapa 1).

Impacto del cambio futuro: requiere recalibrar tests E2E de análisis de píxeles (umbrales de verde/ámbar/rojo).

Acción: decidir con feedback real de uso en talleres InQuality. Sprint 3-4.


Refinamientos UX

[BACKLOG] Mejorar animación de expansión de sección "Automatización" en ActivityPanel

Estado: actualmente usa max-h trick (funciona, pero la aceleración no es lineal en los últimos píxeles).

Solución sofisticada: useRef + scrollHeight para animar a la altura real del contenido.

Costo: medio. Beneficio: micro-pulido visual.

[RESOLVED] Label "Payback" superpuesto con eje Y en CumulativeSavingsChart (web)

Resultado: offset ajustado con padding: [0,0,0,8] y offset: [4,0]. Sin colisión con eje Y. Sprint cerrado en: Sprint 2 Etapa 3.

[RESOLVED] CumulativeSavingsChart — empezar en -inversión, no en 0 (web)

Resultado: verificado en Sprint 2 Etapa 3 — la línea ya arrancaba en -investment (roi.annualSavings * y - investment, y=0 → -investment). Ítem cerrado sin cambio de código. Sprint cerrado en: Sprint 2 Etapa 3.


Decisiones arquitectónicas tomadas en Sprint 1.5 (cerradas, archivadas)

Sección informativa. Estas decisiones ya están aplicadas en el código. Se mantienen acá como referencia.

Subtítulo "Análisis de retorno de inversión" solo en página 1 ROI

Decidido: página 1 tiene subtítulo descriptivo, páginas 2-4 no. Patrón estándar de reportes financieros (página 1 con título extendido).

KPI cards en página 1 de PDFs Actual/Automatizado — color naranja

Decidido: el KPI "Costo total" se migró a naranja durante refactor de Sprint 1.5. Antes era azul. Decisión retroactiva del audit.

ComparisonTable — actividades no automatizables muestran em dash

Decidido: en filas donde isAutomatable === false, mostrar "—" (em dash) en columnas Ahorro y % Ahorro en lugar de "USD 0,00" y "0,0%". Aplicado en Sprint 1.5.

Decidido: la versión es útil para usuarios internos en web. En PDFs entregados a clientes genera dudas de estabilidad. Aplicado en Sprint 1.5.


Anotaciones rápidas antes de pasar a Etapa 10

[RESOLVED] Tamaño del badge — evaluar aumentar

Resultado: evaluado en Sprint 2 Etapa 3 (16px) y ajustado a 20×20px en fix post-validación visual. Sin colisión en nodos de evento. Director aprobó visualmente. Sprint cerrado en: Sprint 2 Etapa 3 + fix.

[INVESTIGATING] Toggle automatable + Guardar requerido para badge

Estado: comportamiento intencional. Switch del ActivityPanel cambia visualmente, pero el badge en BpmnCanvas solo aparece después de "Guardar". Decisión actual (Sprint 1.5): mantener como está. Es UX deliberada. Acción: revisar en Sprint 2 con feedback real de uso en talleres. Si genera confusión recurrente, evaluar Opción B (indicador visual de "pendiente de guardar") o Opción C (auto-save).

[RESOLVED] Badge naranja en BpmnCanvas — Etapa 9

Resultado: badge rediseñado con identidad InQ, hex hardcodeados eliminados, 526 tests verdes. Sprint cerrado en: Sprint 1.5 Etapa 9.

[RESOLVED] Refinamientos página 1 PDF ROI — Etapa 11

Resultado: KPI Hero 26pt, banner con bold naranja oscuro, grid 2×2 uniforme 9/18/9pt, Top 3 con título 11pt. Esquinas redondeadas via canvas clip con fondo blanco opaco. Sprint cerrado en: Sprint 1.5 Etapa 11.