Abrí la página de respaldos. Tenía pestañas para Historial y Programaciones. Un botón "Disparar respaldo" con un degradado azul. Un botón "Crear programación." Un componente CronBuilder con 17 presets y un editor de campos de 5 columnas. Configuración de proveedores de almacenamiento con 13 backends soportados. Asistentes de tres pasos para disparar y programar. Un estado vacío con una linda ilustración. Notificaciones toast. Paginación.
Hice clic en "Disparar respaldo." Seleccioné mi instancia PostgreSQL. Hice clic en "Respaldar ahora." El toast dijo "Respaldo disparado." Una tarjeta apareció en la lista del historial: insignia amarilla, "pending."
Esperé. Refresqué. Seguía pendiente. Revisé los logs. Nada.
La UI era perfecta. El backend era un callejón sin salida.
Todo lo que el usuario podía ver
Siete funcionalidades. Dos funcionaban (eliminar y alternar programación). Cinco estaban rotas o faltantes.
Lo que entregamos en una sesión
- Modal de confirmación de eliminación -- Reemplazamos el
confirm()nativo del navegador con un modal adecuado. - Tarjetas de programación en lugar de tabla -- Diseño basado en tarjetas que coincide con las tarjetas del historial de respaldos.
- Botón de programación en la pestaña Historial -- El momento más natural para crear una programación es justo después de disparar un respaldo manual.
- Descarga de respaldo -- Backend con
Content-Disposition: attachmenty frontend con blob +<a>programático. - Confirmación de Ejecutar ahora -- Modal de confirmación mostrando nombre de fuente y tipo antes de ejecutar.
- Modal de editar programación -- El endpoint API ya soportaba actualizaciones; faltaba solo la UI.
- Limpieza del CronBuilder -- Eliminamos los inputs de texto redundantes, mantuvimos solo los selects.
La brecha de confianza
Lo peligroso de una UI que parece completa es que crea confianza. Cuando vi la página de respaldos con sus modales y CronBuilder y asistentes de 3 pasos, asumí que funcionaba. La UI era la evidencia.
La brecha estaba en el cableado. El manejador no llamaba al motor. El programador no estaba generado. El respaldo de volumen usaba la API equivocada. El nombre de base de datos era incorrecto. Cada uno es una sola línea faltante o una variable equivocada -- invisible en revisión de código, obvio en pruebas.
La corrección no es más revisión de código. Es testing de integración. Un test que:
- Dispara un respaldo vía la API
- Espera a que el estado cambie de "pending" a "completed"
- Descarga el archivo de respaldo
- Verifica que el archivo sea un archivo gzip válido
- Para respaldos de base de datos: verifica que el contenido SQL contenga las tablas esperadas
Este test habría detectado cada bug en este artículo. No lo teníamos. Ahora sí.