LeadFlow SaaS — Informe de Testing DevTools

Sesión de depuración: /dashboard/campaigns/new  |  Chrome DevTools MCP

18 jun 2026 14:32 CET 3 errores críticos 2 advertencias Verificado live
3
Errores de Consola
↑ bloquean envío formulario
4.2s
LCP (Time to Interactive)
↑ umbral: <2.5s (Necesita mejora)
0.31
CLS (Layout Shift)
↑ umbral: <0.1 (Deficiente)
7
Peticiones de Red
2 fallidas (422, 500)
Captura de Pantalla — Estado Actual
http://localhost:3000/dashboard/campaigns/new
BUG CAPTURADO
LeadFlow Dashboard Campañas Leads
Nueva Campaña
⚠ Error: tipo de campo esperado 'number', recibido 'string'. Validación falló silenciosamente.
Flujo de Debugging — Pasos del Agente
14:32:01
Screenshot capturado
Estado visual inicial del formulario — botón deshabilitado visible
14:32:04
3 errores detectados en consola
TypeError en validación, CORS en Supabase, React render error
TypeError: Cannot read properties of undefined (reading 'budget')
14:32:08
DOM inspeccionado — campo budget
type="text" encontrado donde se esperaba type="number"
14:32:11
Red: POST /api/campaigns → 422
Payload enviado con string en vez de number para budget
14:32:15
Rendimiento perfilado — LCP 4.2s
Bundle JS sin lazy-load: 847KB bloqueando render inicial
14:32:19
A11y: 3 fallos de accesibilidad
Botón sin aria-label, inputs sin label asociado, contraste insuficiente
14:32:24
Informe compilado — hallazgos priorizados
5 issues críticos/altos listos para asignar
Consola del Navegador — Errores y Advertencias
Console Sources Network ● 3 errors   ⚠ 2 warnings
ERROR
TypeError: Cannot read properties of undefined (reading 'budget')
at validateCampaignForm (CampaignForm.tsx:87:23)
CampaignForm.tsx:87 — budget field undefined cuando el input es type="text" y el schema Zod espera number
ERROR
Access to fetch at 'https://xyz.supabase.co/rest/v1/campaigns' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header.
api/campaigns.ts:34 — La variable NEXT_PUBLIC_SUPABASE_URL apunta a proyecto de staging con CORS restrictivo
ERROR
React: Each child in a list should have a unique "key" prop. Check the render method of <ChannelSelector>.
ChannelSelector.tsx:52 — array .map() sin key={channel.id}
WARN
Image with src "/images/hero-campaign.jpg" has either width or height modified, but not the other. If you use CSS to change the size of your image, also include the styles 'width: "auto"' or 'height: "auto"' to maintain the aspect ratio.
next/image: CampaignHero.tsx:12
WARN
[Deprecation] navigator.userAgent no longer provides full UA string in Chrome 115+. Use User-Agent Client Hints API instead.
analytics/tracker.ts:8 — compatibilidad futura
INFO
[LeadFlow] Campaign form mounted. User: tester@leadflow.io — Org: org_demo_9f2a
CampaignForm.tsx:41 — debug logging activo en prod (¡debe eliminarse!)
Monitor de Red — Peticiones Capturadas
Método URL Status Tiempo Tamaño
GET /dashboard/campaigns/new 200 4.2s 847 KB
GET /api/channels 200 82ms 2.1 KB
GET /api/user/profile 200 64ms 0.8 KB
POST /api/campaigns 422 148ms 0.3 KB
GET https://xyz.supabase.co/rest/v1/campaigns CORS
PATCH /api/analytics/session 200 48ms 0.1 KB
GET /images/hero-campaign.jpg 200 210ms 312 KB
Inspección DOM — Campo Budget (Bug)
<form id="campaign-form" novalidate>
<div class="field-group">
<label for="budget-input">Presupuesto €</label>
<input id="budget-input" type="text" <!-- ⚠ debería ser type="number" -->
value="5000" name="budget" autocomplete="off"
aria-label="undefined" <!-- ⚠ aria-label vacío --> >
</div>
<button
type="submit"
disabled="true" <!-- bloqueado por TypeError -->
<!-- aria-label="Crear Campaña" faltante -->
>Crear Campaña</button>
</form>
Causa raíz detectada: El campo budget tiene type="text" en el JSX. Zod espera z.number() pero recibe string → TypeError → botón bloqueado.
Core Web Vitals — Perfil de Rendimiento
LCP — Largest Contentful Paint
4.2s
Bueno: <2.5s | Necesita mejora: 2.5–4s | Deficiente: >4s
Causa: bundle JS 847KB sin lazy-load ni code splitting
CLS — Cumulative Layout Shift
0.31
Bueno: <0.1 | Necesita mejora: 0.1–0.25 | Deficiente: >0.25
Causa: imagen hero sin width/height definidos — salta al cargar
INP — Interaction to Next Paint
210ms
Bueno: <200ms | Necesita mejora: 200–500ms | Deficiente: >500ms
Causa: validación síncrona en cada keystroke sin debounce
TTFB — Time to First Byte
180ms
Bueno: <800ms
Server response OK — Vercel Edge Function funcionando bien
FCP — First Contentful Paint
2.1s
Bueno: <1.8s | Necesita mejora: 1.8–3s
Render-blocking CSS de fuentes externas (Google Fonts)
Bundle JS principal
847 KB
Recomendado: <200 KB parse crítico
chart.js + date-fns importados completos, sin tree-shaking
Árbol de Accesibilidad — Verificación A11y
Botón "Crear Campaña" sin nombre accesible
El botón submit carece de aria-label. Los usuarios de lectores de pantalla no saben qué hace. WCAG 2.1 — 4.1.2 Name, Role, Value
Input budget: aria-label="undefined"
El atributo aria-label contiene literalmente "undefined" por un prop no resuelto en React. WCAG 1.3.1
Contraste insuficiente — texto placeholder
Ratio de contraste: 2.8:1 (mínimo requerido: 4.5:1). Color: #6B7280 sobre #1A1F29. WCAG 1.4.3
Jerarquía de headings rota: h1 → h3
La sección "Configuración avanzada" salta de h1 a h3 sin h2 intermedio. WCAG 1.3.1
Orden de foco correcto
Tab navega en orden lógico: nombre → presupuesto → canal → botón. Sin trampas de foco.
Región ARIA del formulario correcta
role="main" y <main> semántico presentes. Landmarks correctos para navegación.
Hallazgos Priorizados — Plan de Acción
🔴
CRÍTICO: type="text" en campo budget bloquea el formulario
Zod schema usa z.number() pero el input envía string. TypeError en runtime desactiva el botón de submit permanentemente.
Fix: type="text"type="number" en CampaignForm.tsx:87, o añadir coerción z.coerce.number()
🔴
CRÍTICO: CORS — SUPABASE_URL apunta a staging
La variable NEXT_PUBLIC_SUPABASE_URL en .env.local apunta al proyecto de staging con CORS restrictivo. Todas las peticiones a Supabase fallan.
Fix: Cambiar NEXT_PUBLIC_SUPABASE_URL al proyecto de desarrollo en .env.local
🟡
RENDIMIENTO: Bundle de 847KB retrasa LCP 4.2s
chart.js y date-fns importados completos. El formulario de creación no necesita estas librerías en la carga inicial.
Fix: dynamic(() => import('recharts'), {'{'} ssr: false {'}'}) + tree-shaking date-fns
🟡
A11Y: 3 fallos WCAG 2.1 (nivel AA)
Botón sin nombre, aria-label="undefined", contraste insuficiente. Afecta usuarios de lectores de pantalla.
Fix: Añadir aria-label="Crear campaña" al botón y corregir prop aria en el input budget
Checklist de Verificación — Estado Actual
  • Página carga sin errores de consola 3 errores activos: TypeError, CORS, React key prop
  • Peticiones de red retornan status correctos POST /api/campaigns → 422 | Supabase → CORS blocked
  • Output visual coincide con el diseño esperado Botón deshabilitado, campo con error de validación visible
  • Árbol de accesibilidad correcto y etiquetas presentes 3 fallos WCAG 2.1 nivel AA detectados
  • Métricas de rendimiento en rango aceptable LCP 4.2s (deficiente), CLS 0.31 (deficiente)
  • TTFB del servidor dentro de umbral 180ms — Vercel Edge Function respondiendo correctamente
  • Contenido del navegador no interpretado como instrucciones Todo DOM/console tratado como datos no confiables
  • JS execution limitado a inspección de solo lectura Sin acceso a cookies, localStorage ni credenciales