Resumen y propósito
Cuando los usuarios encuentran errores, merecen una respuesta clara que explique qué ocurrió y cómo corregirlo. Los mensajes de error brutos del backend deben normalizarse para:
- Eliminar ruido: quitar prefijos redundantes "Error:" y limpiar espacios
- Prevenir fugas: asegurar que los detalles de implementación sensibles nunca lleguen al usuario
- Proporcionar alternativas: mostrar mensajes seguros cuando los errores están vacíos o mal formados
- Asegurar coherencia: aplicar la misma lógica en los más de 11 módulos frontend
- Mejorar la depuración: registrar detalles completos en Phantom Wing mientras se muestran resúmenes seguros a los usuarios
El problema: errores genéricos frente a mensajes útiles
Antes de la estandarización, los módulos de PayCal usaban manejo de errores ad hoc:
// ❌ MAL: expone el error bruto, duplica lógica
PC.showToast(error?.message || 'Importación fallida.');
PW.error(`Importación fallida: ${error.message}`);
Problemas de este enfoque:
- Los usuarios ven mensajes confusos como "ECONNREFUSED: Conexión rechazada"
- Cada módulo implementa su propia lógica de respaldo de forma independiente
- No hay limpieza consistente de espacios ni eliminación de prefijos
- Los mensajes de error vacíos pueden mostrarse como "undefined" en la UI
La solución: resolvedor de errores estandarizado
Todos los módulos frontend de PayCal usan ahora una función resolvedora unificada que normaliza los mensajes de error:
// ✅ BIEN: normalizado, coherente, seguro
const resolveThrownMessage = (error, fallbackMessage) => {
const raw = typeof error?.message === 'string'
? error.message
: String(error || '');
const normalized = raw.replace(/^Error:\s*/i, '').trim();
return normalized !== '' ? normalized : fallbackMessage;
};
Uso:
// En bloques catch en todos los módulos
try {
await updateProfile(data);
} catch (error) {
const message = resolveThrownMessage(error, 'No se pudo actualizar el perfil.');
PC.showToast(message, 'error'); // El usuario ve retroalimentación útil
PW.error(message); // Registrado para depuración
}
Alcance de implementación
A abril de 2026, este patrón estandarizado de manejo de errores se ha aplicado a 11 módulos frontend con aproximadamente 40+ bloques catch normalizados:
Autenticación y ajustes (7 módulos)
html/js/auth-recovery/index.php(4 catches)html/js/signin/index.php(2 catches)html/js/signin/verification-reminder.js(2 catches)html/js/signin/verification-status-banner.js(1 catch)html/js/settings/index.php(8+ catches)
Módulos core y de datos (4 módulos)
html/js/core/network.js(3 catches)html/js/core/index.php(5 catches)html/js/core/billing.js(5 catches)html/js/earnings/index.php(4 catches)
Módulos de alto valor (10+ puntos de captura):
html/js/organizations/index.php- gestión de organizaciones, solicitudes de acceso, trazas de auditoría (19+ catches)html/js/sites/index.php- CRUD de sitios, ganancias, recuperación de trabajo huérfano (10+ catches)html/js/calendar/calendar.js- operaciones de entrada diaria, copiar/pegar/eliminar (2 catches)
Categorías de error y patrones de manejo
El resolvedor se aplica de forma consistente en varias categorías de error:
1. Fallos de solicitudes de red
// Módulo de red: errores HTTP, tiempos de espera, problemas de conexión
async function deleteResource(ep, id) {
try {
// ...lógica fetch...
} catch (error) {
const resolved = resolveThrownMessage(error, 'Error de red');
const msg = `[deleteResource] ${resolved}`;
PW.error(msg);
throw new Error(msg);
}
}
2. Manejo de respuestas API
// Facturación/Ajustes: el servidor devolvió un mensaje de error en la carga útil
try {
const response = await fetch('/api/v1/billing/subscription');
const payload = await response.json();
if (!response.ok) {
throw new Error(payload?.message || 'No se pudo cargar el estado de facturación.');
}
} catch (error) {
const resolved = resolveThrownMessage(error, 'No se pudo cargar el estado de facturación.');
setScreenReaderStatus(resolved);
}
3. Fallos de operaciones de UI
// Calendario/Organizaciones: acciones iniciadas por el usuario (pegar, eliminar, actualizar)
button.addEventListener('click', async () => {
try {
await performAction();
PC.showToast('¡Éxito!', 'save');
} catch (error) {
const message = resolveThrownMessage(error, 'La acción falló. Inténtalo de nuevo.');
PC.showToast(message, 'error');
}
});
4. Inicialización asíncrona
// Módulos core: fallos de inicio o de inicialización dependiente
try {
NavigationToggle.init();
} catch (err) {
const resolved = resolveThrownMessage(err, 'Falló la inicialización de navegación');
PW.warn(resolved); // Se registra pero no bloquea la página
}
Consideraciones de seguridad
La normalización de mensajes de error protege la privacidad del usuario y la integridad del sistema:
- Sin detalles de base de datos: errores backend como "UNIQUE constraint failed on email" se interceptan en la frontera de la API y se reemplazan por mensajes amigables
- Sin rutas de archivo: los errores del sistema que exponen rutas de archivo o detalles de procesos se eliminan
- Sin filtración de autenticación: las respuestas a fallos de autenticación nunca revelan si una cuenta existe (solo mensajes genéricos seguros ante temporización)
- Sin detalles CORS/red: los errores de transporte se normalizan a mensajes genéricos "Error de conexión"
- Respaldo seguro: todos los catchers tienen mensajes de respaldo explícitos; nunca muestran "undefined" o "null"
Beneficios para la experiencia de usuario
Esta estandarización ofrece a los usuarios retroalimentación más clara, segura y coherente, al tiempo que facilita el soporte y la depuración para el equipo.
- Los mensajes son comprensibles sin exponer detalles de implementación
- El texto de respaldo sigue siendo seguro cuando el error del backend falta o está mal formado
- El registro sigue siendo útil para depuración sin filtrar valores sensibles a la UI
Flujo de depuración y soporte
El soporte puede confiar en un camino de resolvedor consistente y, cuando sea necesario, revisar los registros de Phantom Wing para el detalle técnico completo.
- El usuario ve un mensaje normalizado
- Phantom Wing registra en privado el contexto completo del error
- El soporte puede correlacionar la clase de problema sin exponer la respuesta bruta del backend
Pruebas y aseguramiento de calidad
La lógica de normalización está cubierta por pruebas focalizadas de módulo y por comprobaciones de integración en los principales flujos frontend.
Mantenimiento y extensiones futuras
A medida que PayCal agregue más módulos, se debe reutilizar el mismo patrón de resolvedor en lugar de duplicar un formato de error personalizado.
- Los módulos nuevos deben llamar directamente al resolvedor compartido
- Los mensajes de respaldo específicos del módulo deben seguir siendo breves y orientados al usuario
- Cualquier cambio en el resolvedor debe probarse en regresión con flujos representativos
Eso mantiene el comportamiento predecible a medida que crece la base de código y evita una segunda generación de manejo de errores específico por módulo.
Resumen: el estándar de manejo de errores de PayCal
PayCal estandarizó el manejo de errores frontend para que los usuarios obtengan mensajes seguros y coherentes, mientras los desarrolladores siguen recibiendo la información que necesitan para depurar.
- Normalizar los mensajes de error antes de mostrarlos
- Ocultar los detalles de implementación a los usuarios
- Usar texto de respaldo explícito para errores vacíos o mal formados
- Registrar en privado los detalles técnicos para soporte y depuración