Skip to content

🔍 Auditoría Exhaustiva del Portfolio — 72 Hallazgos (Visual, Rendimiento, SEO, Accesibilidad, Seguridad, Código) #13

Description

@juankaspain

🔍 Auditoría Exhaustiva del Portfolio — 72 Hallazgos

Fecha: 2026-03-22
Tech Stack: Next.js 15.5.9, React 19, TypeScript, Tailwind CSS 3.4, Framer Motion

Resumen Ejecutivo

Categoría 🔴 Crítico 🟠 Alto 🟡 Medio 🔵 Bajo Total
A. Visual/UX 1 3 5 3 12
B. Rendimiento 0 4 5 3 12
C. SEO 1 3 4 2 10
D. Accesibilidad 1 4 4 2 11
E. Seguridad 1 2 3 2 8
F. Calidad de Código 1 3 4 3 11
G. Mejores Prácticas 1 2 3 2 8
TOTAL 6 21 28 17 72

🔴 Problemas Críticos (6)

A.1 — favicon.ico está vacío (0 bytes)

  • Archivo: public/favicon.ico
  • El archivo favicon.ico tiene 0 bytes. Navegadores sin soporte SVG no mostrarán icono.
  • Fix: Generar favicon.ico real a partir del favicon.svg (16x16, 32x32, 48x48).

C.1 — URLs externas en sitemap.xml

  • Archivo: public/sitemap.xml:95-116
  • El sitemap incluye URLs de dominios externos (imdb.com, filmaffinity.com, wikipedia.org). Google puede penalizar el sitemap completo.
  • Fix: Eliminar todas las URLs externas del sitemap.

D.1 — Sin link "Skip to content"

  • Archivo: src/app/layout.tsx, src/app/page.tsx
  • No existe enlace "Saltar al contenido principal". WCAG 2.4.1 (Bypass Blocks) - Nivel A.
  • Fix: Añadir <a href="#main-content">Saltar al contenido</a> y id="main-content" al <main>.

E.1 — API de contacto sin validación Zod ni rate limiting

  • Archivo: src/app/api/contact/route.ts:10-29
  • Validación manual básica en lugar del schema Zod existente. Sin rate limiting, permite abuso (spam, DoS).
  • Fix: Usar contactFormSchema.parse(body) y añadir rate limiting.

F.1 — Directorio anidado erróneo: src/lib/src/lib/

  • Archivo: src/lib/src/lib/analytics.ts
  • Directorio duplicado creado por error de copia.
  • Fix: Eliminar src/lib/src/ completo.

G.1 — Faltan assets PWA referenciados en manifests

  • Archivos: public/manifest.json, public/site.webmanifest
  • Múltiples archivos referenciados que no existen: android-chrome-192x192.png, android-chrome-512x512.png, apple-touch-icon.png, screenshots/, og-image.jpg, twitter-image.jpg, profile-image.jpg, etc.
  • Fix: Generar todos los assets referenciados o actualizar las referencias.

🟠 Problemas de Alta Importancia (21)

A. Visual/UX (3)

A.2 — Menú móvil sin AnimatePresence funcional

  • Archivo: src/components/Navbar.tsx:108-177
  • Animaciones de salida nunca se ejecutan. Menú desaparece abruptamente.
  • Fix: Envolver en <AnimatePresence>.

A.3 — Scroll no bloqueado al abrir menú móvil

  • Archivo: src/components/Navbar.tsx
  • Usuario puede hacer scroll en el fondo con el menú abierto.
  • Fix: document.body.style.overflow = 'hidden' al abrir.

A.4 — 12 links de navegación sin scroll visible en desktop

  • Archivo: src/components/Navbar.tsx:9-22
  • En pantallas 1024-1280px, los 12 enlaces probablemente no caben.
  • Fix: Implementar submenú dropdown o reducir ítems visibles.
B. Rendimiento (4)

B.1 — Imágenes servidas desde GitHub user-attachments

  • GitHub no es CDN optimizado. Sin redimensionado dinámico, caché impredecible.
  • Fix: Migrar a CDN dedicado (Vercel Blob, Cloudinary).

B.2 — 29 componentes de secciones, 9 sin usar (~110KB código muerto)

  • Collaborators.tsx, Events.tsx, FAQ.tsx, FeaturedRoles.tsx, News.tsx, Portfolio.tsx, SkillsGraph.tsx, SkillsVisual.tsx, Stats.tsx
  • Fix: Eliminar componentes no utilizados.

B.3 — Framer Motion importado en prácticamente todos los componentes

  • ~140KB minificado usado para animaciones simples que podrían ser CSS.
  • Fix: Usar CSS para animaciones simples, Framer Motion solo para complejas.

B.4 — Skills sin Suspense wrapper

  • dynamic() sin <Suspense> → sin fallback visual mientras carga.
  • Fix: Envolver en <Suspense fallback={<SectionSkeleton />}>.
C. SEO (3)

C.2 — Anchor links (#) en sitemap.xml

  • Motores de búsqueda ignoran fragmentos hash. Entradas inútiles.
  • Fix: Eliminar URLs con fragmentos.

C.3 — Conflicto entre robots.txt estático y robots.ts dinámico

  • Archivo estático tiene prioridad y bloquea *.json$ y *.xml$.
  • Fix: Eliminar public/robots.txt, usar solo src/app/robots.ts.

C.4 — Google verification placeholder no real

  • Valores placeholder 'pending-verification'. Google Search Console no verificado.
  • Fix: Completar verificación con código real o eliminar placeholder.
D. Accesibilidad (4)

D.2 — Navbar links sin aria-current para lectores de pantalla

  • Sección activa solo indicada visualmente. WCAG 4.1.2.
  • Fix: Añadir aria-current={isActive ? 'true' : undefined}.

D.3 — Botón menú móvil sin aria-expanded

  • Sin aria-expanded ni aria-controls. WCAG 4.1.2.
  • Fix: Añadir atributos ARIA al botón hamburguesa.

D.4 — Select de contacto sin contraste adecuado

  • Opciones del dropdown con problemas de contraste sobre bg-neutral-900. WCAG 1.4.3.

D.5 — Social links sin aria-label descriptivos

  • Solo muestran icono sin indicar que son enlaces externos. WCAG 2.4.4.
  • Fix: Añadir aria-label descriptivos.
E. Seguridad (2)

E.2 — CSP permite unsafe-eval y unsafe-inline

  • Archivo: next.config.js:95
  • Anula protección CSP contra XSS.
  • Fix: Eliminar 'unsafe-eval', usar nonces.

E.3 — Formspree endpoint hardcoded y expuesto

  • Archivo: src/components/sections/Contact.tsx:25
  • Cualquiera puede enviar formularios directamente.
  • Fix: Proxiar a través de API route con rate limiting.
F. Calidad de Código (3)

F.2 — Dos archivos Prettier config

  • .prettierrc y .prettierrc.json en la raíz.
  • Fix: Eliminar uno.

F.3 — Dos archivos Lighthouse config

  • lighthouserc.js y lighthouserc.json.
  • Fix: Mantener solo uno.

F.4 — Contact.tsx no usa Zod de validators.ts

  • Validación HTML nativa en lugar de Zod + react-hook-form (ambos instalados).
  • Fix: Integrar react-hook-form con @hookform/resolvers/zod.
G. Mejores Prácticas (2)

G.2 — No hay página 404 personalizada

  • Next.js muestra 404 genérica. No coincide con el diseño del sitio.
  • Fix: Crear src/app/not-found.tsx.

G.3 — Dos manifests PWA

  • manifest.json y site.webmanifest con contenido diferente.
  • Fix: Mantener solo uno.

🟡 Problemas de Prioridad Media (28)

Ver todos los problemas medios
# Categoría Descripción Archivo
A.5 Visual Partículas con posición absoluta basada en window size Contact.tsx
A.6 Visual Hero extremadamente largo en móvil Hero.tsx
A.7 Visual Texto "Professional Headshots" mezclando idiomas Hero.tsx:444
A.8 Visual Fan counter en Footer con localStorage sin backend Footer.tsx
A.9 Visual Doble Footer component (uno no usado) layouts/Footer.tsx
B.5 Rendimiento Service Worker sin versionado de cache sw.js
B.6 Rendimiento Múltiples implementaciones de Analytics analytics.ts (x3)
B.7 Rendimiento 21+ archivos markdown en raíz del proyecto ./
B.8 Rendimiento Preconnect a dominios no utilizados layout.tsx
B.9 Rendimiento Prefetch de anchor links sin efecto layout.tsx
C.5 SEO og-image.jpg y twitter-image.jpg no existen layout.tsx
C.6 SEO Metadatos duplicados layout.tsx vs metadata.ts metadata.ts
C.7 SEO hreflang apunta a /en inexistente layout.tsx
C.8 SEO SearchAction en schema sin búsqueda real layout.tsx
D.6 Accesibilidad Mínimo uso de aria-labels (17 en 52 archivos) Múltiples
D.7 Accesibilidad Animaciones sin prefers-reduced-motion Múltiples
D.8 Accesibilidad Menú móvil sin focus trap Navbar.tsx
D.9 Accesibilidad Heading hierarchy inconsistente Múltiples
E.4 Seguridad Google Analytics ID placeholder Analytics.tsx
E.5 Seguridad Sentry tracesSampleRate al 100% sentry.client.config.ts
E.6 Seguridad Email expuesto en múltiples ubicaciones Múltiples
F.5 Código Componentes layouts/ no usados layouts/
F.6 Código Constants.ts NAVIGATION_ITEMS no coincide con Navbar constants.ts
F.7 Código trackEvent con dos firmas incompatibles analytics.ts
F.8 Código suppressHydrationWarning en html y body layout.tsx
G.4 Prácticas No hay package-lock.json ./
G.5 Prácticas Falta error.tsx para errores de runtime src/app/
G.6 Prácticas No hay estilos de impresión (@media print) globals.css

🔵 Problemas de Baja Prioridad (17)

Ver todos los problemas bajos
# Categoría Descripción Archivo
A.10 Visual styled-jsx repetido múltiples veces en Hero Hero.tsx
A.11 Visual Color de acento inconsistente manifest vs theme-color manifest.json, layout.tsx
A.12 Visual About con loading="eager" innecesario below-the-fold About.tsx
B.10 Rendimiento critical.css no se usa ni se inyecta critical.css
B.11 Rendimiento console.log en Service Worker producción sw.js
B.12 Rendimiento Bundle analyzer importado incondicionalmente next.config.js
C.9 SEO Sitemap estático en lugar de dinámico sitemap.xml
C.10 SEO Schema.org image apunta a archivo inexistente layout.tsx
D.10 Accesibilidad Color contrast text-slate-400 sobre fondos oscuros Múltiples
D.11 Accesibilidad Imágenes decorativas sin aria-hidden Múltiples
E.7 Seguridad Fecha de nacimiento expuesta en schema layout.tsx
E.8 Seguridad security.txt sin GPG key security.txt
F.9 Código index como key en varios componentes Múltiples
F.10 Código react-hook-form y resolvers instalados sin usar package.json
F.11 Código Variable --font-serif sin fuente Playfair cargada globals.css
G.7 Prácticas IMAGES_TODO.md servido públicamente public/
G.8 Prácticas Falta loading.tsx para transiciones src/app/

Plan de Corrección

La rama feature/audit-fixes abordará todos los problemas en el siguiente orden:

  1. 🔴 Críticos — Fixes inmediatos
  2. 🟠 Altos — Mejoras prioritarias
  3. 🟡 Medios — Refinamiento
  4. 🔵 Bajos — Pulido final

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions