25 nov 2025·7 min de lectura

CI/CD para prototipos heredados: un plan de pipeline simple

CI/CD para código de prototipos heredados simplificado: un pipeline práctico con linting, tests, builds reproducibles, deploy previews y lanzamientos a producción más seguros.

CI/CD para prototipos heredados: un plan de pipeline simple

Por qué los prototipos heredados necesitan un enfoque distinto de CI/CD

El código de prototipos heredado suele ser una mezcla de experimentos rápidos, fragmentos copiados y funciones a medio terminar. A menudo tiene una estructura débil, propiedad poco clara y atajos “temporales” que se volvieron permanentes. Si herramientas de IA ayudaron a crearlo, también puedes ver patrones inconsistentes, manejo de errores faltante y lógica que parece funcionar hasta que usuarios reales encuentran casos límite.

Por eso puede funcionar en una laptop y venirse abajo en producción. La configuración original puede depender de archivos locales ocultos, una versión de runtime específica, una base de datos con datos precargados o variables de entorno que nadie documentó. Un compañero lo corre con cache caliente; otro instala todo desde cero y sólo ve pantalla en blanco. Producción añade seguridad más estricta, condiciones de red distintas y volumen real de datos, lo que expone problemas como autenticación rota, secretos expuestos y consultas a la base de datos frágiles.

Un mejor enfoque de CI/CD aquí no busca la ingeniería perfecta desde el día uno. Busca menos alarmas. Un pipeline simple detecta fallos comunes temprano, hace los lanzamientos repetibles y te da una forma más segura de cambiar cosas sin necesitar un gran refactor inmediatamente.

Este blueprint se centra en guardarraíles prácticos: linting básico, un pequeño conjunto de tests relevantes, builds fiables, deploy previews para revisión y lanzamientos a producción más seguros con ruta de rollback.

Si los cimientos están muy rotos (por ejemplo, autenticación enredada, patrones de consultas inseguras o huecos de seguridad como inyección SQL), te beneficiarás más de un diagnóstico corto y reparaciones enfocadas primero. Luego CI/CD ayuda a evitar que los mismos problemas vuelvan.

Define el objetivo: qué significa “suficientemente seguro para enviar”

Los prototipos heredados fallan de formas impredecibles. La meta de tu pipeline no es la perfección. Es feedback más rápido, menos deploys rotos y lanzamientos que puedas repetir sin contener la respiración.

Escribe lo que “suficientemente seguro” significa para tu app este mes, no tu versión soñada dentro de seis meses. Una promesa práctica de inicio es simple: cada cambio ejecuta los mismos checks, todas las veces. No más excepciones de “hotfix rápido”, porque las excepciones se convierten en la nueva normalidad.

Una definición que el equipo pueda repetir

Un cambio está “hecho” cuando se cumplen dos cosas:

  • El pipeline está en verde.
  • Produce algo que realmente puedes desplegar (un artefacto desplegable), no sólo código que compila en una laptop.

Si los checks pasan pero no puedes desplegar, el pipeline no está terminado.

Mantén la definición corta. Para la mayoría de equipos suele ser suficiente exigir: linting y un conjunto básico de tests, un build limpio en CI, un deploy de preview o staging para revisión y un release a producción que siga la misma ruta con un paso explícito de aprobación.

Qué posponer (a propósito)

Intentar arreglar todo el primer día es la vía más rápida para abandonar CI/CD. Está bien posponer cobertura completa de tests y grandes refactors mientras pones puertas de confianza confiables.

Si el login a veces falla, no empieces reescribiendo toda la autenticación. Empieza por hacer que “suficientemente seguro” signifique: el login tiene un test de humo automatizado, los secretos no están expuestos y el build produce un artefacto liberable. Cuando los lanzamientos dejen de fallar, podrás ampliar la cobertura y refactorizar con menos riesgo.

Prepara el repo: ramas, entornos y secretos

Antes de enchufar CI/CD, haz que el repo sea predecible. La mayor parte del dolor en prototipos viene de configuraciones misteriosas: ramas en las que nadie confía, variables de entorno dispersas en chats y secretos comprometidos por accidente.

Mantén las ramas aburridas

Normalmente sólo necesitas una rama de larga vida más ramas de trabajo de corta duración:

  • main siempre está desplegable.
  • Los cambios ocurren en ramas de feature cortas que se fusionan rápido.

Evita mega-ramas (como una dev que dura semanas) que se desvían. Etiqueta releases en main para poder volver a un punto conocido bueno.

Haz explícitos entornos y secretos

Elige una única fuente de la verdad para la configuración. Un patrón simple: local usa un archivo .env de ejemplo, CI usa el almacén de secretos del CI y producción usa las variables del proveedor de hosting. La clave es la consistencia: los mismos nombres de variables existen en todos lados.

Mínimo esencial:

  • Mantén una lista documentada de vars de entorno requeridas (qué hacen, valores por defecto seguros).
  • Conserva un .env.example solo con nombres, nunca valores reales.
  • Elimina secretos comprometidos y rota cualquier cosa expuesta.
  • Mantén claves y URLs fuera del código.

Una prueba útil: si un nuevo compañero no puede ejecutar la app sin pedir “el .env correcto”, tu pipeline también será frágil.

Añade además una nota corta en el README con comandos copy-paste para correr lint, tests y build localmente. Si es incómodo localmente, lo será peor en CI.

Puertas de calidad que atrapan la mayoría de problemas temprano

El código de prototipos tiende a romperse de formas previsibles: formato desordenado, suposiciones de runtime ocultas y “funciona en mi máquina” en las instalaciones. Las puertas de calidad son los checks que tu pipeline ejecuta en cada cambio para que los problemas aparezcan minutos después de un commit, no durante un deploy nocturno.

Empieza con un formateador y un linter, y hazlos no opcionales. La consistencia importa más que la perfección. Los checks automáticos paran debates sobre estilo y evitan que pequeños issues oculten bugs reales.

Añade chequeos de tipos ligeros donde encajen. No necesitas reescribir todo para obtener valor. Incluso un chequeo básico de tipos puede detectar argumentos incorrectos, campos faltantes y manejo nulo inseguro antes de que se conviertan en errores en producción.

Para tests, mantén la barra realista. Define un conjunto mínimo que siempre deba pasar, aunque el resto de la suite siga creciendo. Un mínimo práctico suele cubrir los flujos que más tiempo te cuestan:

  • Login y manejo de sesión (incluyendo logout)
  • Un “happy path” central para la característica principal
  • Un endpoint API crítico (o job en background) que haga una llamada real a la base de datos
  • Chequeos básicos de permisos (usuarios no pueden ver datos de otros usuarios)
  • Un test de humo que la app arranca sin errores

Finalmente, haz que los builds sean repetibles. Fija la versión de runtime (Node, Python, etc.), usa lockfiles y haz instalaciones limpias en CI. Así estarás probando lo que realmente vas a desplegar.

Blueprint paso a paso del pipeline (lint -> test -> build)

Devuelve el pipeline al verde
Convierte checks inestables en señales fiables sin reescribir toda la aplicación.

El objetivo del pipeline es fallar rápido y decirte qué arreglar.

Ejecutarlo en cada pull request, mantenerlo consistente y suficientemente rápido para que la gente no intente saltárselo.

Un orden simple que funciona

  1. Formatea y ejecuta el linter primero. El autoformateo reduce diffs ruidosos. El lint atrapa problemas fáciles temprano (variables no usadas, imports incorrectos, patrones inseguros) y ayuda a mantener el código legible mientras lo vas arreglando.

  2. Ejecuta tests con salida clara. Haz las fallas obvias: qué test falló, el mensaje de error y dónde pasó. Los revisores no deberían tener que escarbar en logs.

  3. Haz el build como en producción. Usa el mismo comando de build y la misma versión de runtime que esperas en producción. Usa la misma forma de variables de entorno (pero nunca secretos reales). Este paso atrapa assets faltantes, config equivocada y sorpresas de “funciona en mi máquina”.

  4. Añade un chequeo de seguridad rápido. Mantenlo ligero: escanea dependencias en busca de paquetes vulnerables conocidos y busca secretos comprometidos. El código asistido por IA es especialmente propenso a tokens hardcodeados o credenciales de ejemplo.

  5. Publica artefactos de build. Guarda la salida del build (y los reportes de test) para que los pasos de deploy los reutilicen en vez de rebuilds redundantes.

Deploy previews: revisar cambios sin arriesgar producción

Un deploy preview es una copia temporal de tu app que ejecuta exactamente el código de un pull request. Se comporta como el producto real, pero está aislada. Esto ayuda a revisores no técnicos porque pueden navegar el flujo real sin instalar nada.

Las previews son una de las formas más rápidas de detectar problemas de “funciona en mi máquina”. También muestran issues de UI, redirects rotos, variables de entorno faltantes y páginas lentas antes de que algo llegue a producción.

Crea previews para cada PR por defecto. Sáltalas solo cuando no aporten valor (por ejemplo, cambios solo de documentación). La consistencia importa: los revisores aprenden que cada cambio tiene un lugar seguro para probar.

Haz las previews realistas (sin copiar producción)

Si las previews arrancan con una base de datos vacía, muchas páginas parecerán rotas aun cuando el código esté bien. Planea datos seed simples desde el principio:

  • Crea un pequeño conjunto de usuarios falsos y registros de ejemplo en cada deploy.
  • Añade un banner claro de “modo demo”.
  • Proporciona una o dos cuentas de prueba predefinidas para revisión (nunca cuentas reales).

Mantén las previews seguras

Los entornos de preview nunca deberían usar datos reales de clientes ni secretos de producción. Trátalos como un sandbox público.

Buenos valores por defecto: claves y bases de datos separadas para previews, deshabilitar jobs destructivos (facturación, emails, webhooks) y expiración automática de previews después de un tiempo corto.

Lanzamientos seguros a producción: aprobaciones, rollbacks y monitoring

Un proceso de release seguro hace riesgos ocultos visibles y fáciles de deshacer.

Haz que cada release a producción sea trazable. Usa etiquetas de versión (por ejemplo, v1.8.0) para poder responder: ¿qué código está corriendo ahora, quién lo aprobó y qué cambió desde el último release?

Incluso en equipos pequeños, añade un paso de aprobación manual antes de producción. CI puede ejecutar checks, pero un humano debe confirmar que la preview luce bien, verificar las notas de release y asegurarse de que exista un plan de rollback. En codebases heredadas, un pequeño cambio puede romper un flujo crítico.

Los rollbacks deben ser rápidos y aburridos. Antes de necesitar uno, asegúrate de poder redeployar la etiqueta anterior con una sola acción, manejar cambios en la base de datos de forma segura (o evitar migraciones riesgosas durante releases), restaurar configuraciones de entorno sin conjeturas y confirmar el éxito con un chequeo de humo rápido.

Si quieres seguridad extra, usa un despliegue progresivo (canary o por porcentaje). Lanza a una porción pequeña del tráfico, vigila problemas y luego despliega al resto. Si los errores suben, para o haz rollback mientras la mayoría de usuarios no se ven afectados.

Después de un release, vigila las pocas señales que te dicen si la app es usable:

  • errores en servidor y frontend (picos, tipos nuevos de error)
  • tasa de éxito de login y registro
  • pagos o finalizaciones de checkout (si aplica)
  • rendimiento (páginas lentas, timeouts)
  • jobs background clave (emails, webhooks, colas)

Cuando faltan tests o son inestables: una ruta práctica

Obtén un plan de remediación práctico
Trae tu repo actual y te diremos la ruta más rápida hacia lanzamientos seguros.

Los prototipos heredados suelen no tener tests o tener tests que fallan “a veces”. Aún necesitas confianza, pero también progreso. La meta es señales predecibles en las que puedas confiar.

¿Test inestable o bug real?

Un test inestable suele fallar en distintos puntos sin cambios de código. Un bug real tiende a fallar de la misma forma hasta que lo arreglas.

Formas rápidas de averiguarlo:

  • Re-ejecuta el mismo commit 3-5 veces. Pasadas aleatorias apuntan a inestabilidad.
  • Mira el error. Timeouts, “element not found” y fallos de red a menudo significan inestabilidad.
  • Observa estado compartido: tests dependientes del orden, bases de datos reutilizadas, sesiones cacheadas.
  • Compara local vs CI. Fallos solo en CI suelen ser problemas de timing o configuración faltante.

No ignores la inestabilidad. Aísla el test (marcarlo como no bloqueante) y abre una tarea para arreglarlo para que el pipeline siga siendo útil.

¿No hay tests aún? Empieza con tests de humo

Si no tienes ningún test, comienza con un pequeño conjunto de humo que proteja los caminos más importantes:

  • La app arranca y la página principal carga
  • El login funciona (happy path)
  • Una acción crítica de crear/leer funciona
  • Usuarios no logueados no pueden acceder a una página privada
  • Un health check de la API devuelve 200

Mantén estos rápidos (unos pocos minutos) y hazlos bloqueantes.

Para estabilizar sin frenar a todos, divide tests en niveles: los tests de humo bloquean merges; tests E2E más largos corren por horario o antes de un release. Limita reintentos a uno y trata “retry pasó” como advertencia, no como éxito.

Para cobertura, fija una meta que crezca despacio: empieza con 10-20% en lógica core y súbela con el tiempo.

Errores comunes que hacen CI/CD doloroso

La forma más rápida de terminar con un pipeline en el que nadie confía es hacerlo “perfecto” el primer día. Con código heredado (especialmente generado por IA), apunta a progreso repetible, no a un muro de checks rojos que todos aprenden a ignorar.

Una trampa común es hacer puertas de calidad tan estrictas que cada ejecución falle por asuntos de estilo menores. El linting es útil, pero si bloquea todo el trabajo, la gente empezará a evitar CI o a mergear sin arreglar nada. Comienza con reglas que atrapen bugs reales y aprieta con el tiempo.

Otro error es auto-desplegar a producción en cada merge sin botón de pausa. Eso convierte un pequeño error en un incidente frente a clientes. Mantén producción aburrida: aprobación antes del release, opción clara de rollback y forma de detener un release si algo se ve mal.

Las deploy previews también pueden salir mal. Una preview que lee tu base de datos de producción o usa claves de producción no es “segura” — es producción con menos ojos. Usa credenciales separadas y una DB de preview (o servicios mockeados) para que las revisiones no arriesguen datos ni dinero.

Otros causantes de dolor frecuentes:

  • Construir de una forma en CI y de otra en producción (runtime, vars, flags diferentes).
  • Postergar actualizaciones de dependencias hasta que un issue de seguridad obligue a un upgrade apresurado.
  • Saltarse checks básicos porque “funcionó en mi máquina”.

Lista rápida: ¿está tu pipeline listo para confiar?

Recupera la autenticación
Si el inicio de sesión falla constantemente, diagnosticamos y arreglamos la autenticación para que los lanzamientos no fallen.

Un pipeline vale la pena cuando responde dos preguntas cada vez: “¿Rompimos algo?” y “¿Podemos hacer rollback rápido si lo hicimos?”.

Busca estas señales mínimas:

  • Linting y formateo se ejecutan automáticamente en cada cambio y fallan rápido.
  • Tests corren de forma fiable y terminan en un tiempo razonable.
  • El build es reproducible y produce un artefacto desplegable.
  • Deploy previews están aisladas (sin datos reales de clientes, sin secretos de producción).
  • Los releases a producción requieren aprobación explícita y tienen un plan de rollback escrito.

Si sólo puedes hacer una cosa esta semana, asegura las previews. Usa una base de datos de pruebas, claves de pago falsas y emails simulados para que los revisores puedan navegar sin enviar mensajes reales ni tocar registros reales.

Luego enfócate en la primera hora después del release:

  • Tracking de errores activo y sabes dónde mirar.
  • Alertas para picos de 500s, fallas de login y requests lentas.
  • Un health check rápido confirma flujos centrales (sign in, crear un registro, guardar, cerrar sesión).
  • Logs buscables que no incluyan secretos.
  • Alguien asignado para vigilar.

Ejemplo: convertir un prototipo inestable construido por IA en una app liberable

Heredas un prototipo construido en Lovable (or Bolt/v0) que funcionó en una demo y luego se rompe en cuanto intentas desplegar. Los logins fallan, variables de entorno están hardcodeadas y el build pasa en una laptop pero no en CI. Aquí es donde un pipeline simple quita las conjeturas y hace los cambios más seguros.

La primera semana debe ser pequeña y aburrida, por diseño. No buscas perfeccionar todo. Buscas que cada cambio sea visible, testeable y reversible.

Un plan práctico para la primera semana:

  • Día 1: Obtener una instalación limpia y un build de “un comando” en CI
  • Día 2: Añadir checks de linting/format y fallar en errores obvios
  • Día 3: Añadir 2-5 tests de humo para rutas críticas (login, una ruta API clave, una página principal)
  • Día 4: Habilitar deploy previews para cada pull request
  • Día 5: Añadir una puerta simple de release (aprobación manual) para producción

Las deploy previews cambian la conversación con stakeholders. En lugar de “creo que está arreglado”, envías una preview y la aprobación se vuelve un claro sí/no.

Si las previews revelan problemas más profundos como autenticación rota, secretos expuestos, consultas inseguras a la DB o una arquitectura que hace riesgosos los cambios, pausa el trabajo del pipeline y arregla los fundamentos primero.

Si heredaste una codebase generada por IA que es demasiado desordenada para estabilizar rápidamente, una auditoría y un pase de reparación enfocado ayudan. FixMyMess (fixmymess.ai) comienza con una auditoría de código gratuita, y luego maneja arreglos puntuales como reparación de lógica, hardening de seguridad, refactor y preparación para deployment para que tu pipeline tenga algo sólido que proteger.