Problema
La mayoría del acceso a internet en Cuba pasa por el servicio Nauta de Etecsa: te autenticas contra un portal cautivo para conectarte, y gestionas tu plan, saldo y horas de bonificación desde un portal de usuario aparte. Durante años eso significó dos flujos de navegador de escritorio que no compartían estado. Los abonados necesitaban una sola superficie móvil donde pudieran iniciar sesión en el portal cautivo, ver cuánto les quedaba, y manejar su cuenta — sin malabarear navegadores, copiar y pegar credenciales, ni interpretar respuestas HTML crudas.
En paralelo, las plataformas operativas detrás de esas superficies — que sirven a aproximadamente 7 millones de abonados — estaban siendo reconstruidas desde un stack heredado de Javax a Spring Boot. La app tenía que aterrizar sobre un backend que se movía activamente debajo.
La superficie móvil
Construí la app móvil Nauta de punta a punta en Flutter, como único desarrollador móvil. Cuatro flujos principales:
- Selector de app — entrada única que se bifurca en los dos portales distintos (cuenta de usuario vs. navegación por portal cautivo) para que el abonado vea un modelo mental claro antes de elegir.
- Login al portal cautivo — el flujo diario: abres la app, te autenticas contra el Wi-Fi de Nauta, te conectas.
- Login al portal de usuario — acceso con credenciales a la cuenta personal, incluyendo el captcha por imagen que el portal sigue exigiendo del lado del servidor.
- Dashboard de cuenta — tipo de plan, estado, fecha de venta, fecha de bloqueo, horas de bonificación, moneda y saldo — traídos del portal de usuario y renderizados como datos estructurados, no como el HTML crudo que devuelve el portal heredado.
Decisiones que vale la pena mencionar:
- Una sola app, dos portales. El portal cautivo y el portal de usuario son sistemas distintos con vidas de sesión y semánticas de error distintas. Los mantuve visualmente unificados pero con sus máquinas de estado separadas, para que una sesión en uno no se filtrara accidentalmente al otro.
- Honesto con el captcha. El portal de usuario exige un captcha por imagen emitido por el servidor. No traté de saltarlo — la app refresca el desafío a demanda y trata al captcha como parte de primer nivel del formulario, no como un workaround.
- Datos estructurados en vez de HTML crudo. El portal de usuario devuelve su vista de cuenta como una página, no como una API limpia. La app la normaliza a un modelo tipado para que el dashboard se lea como un producto, no como un screen scrape.
El backend con el que habla
El equipo de Etecsa — yo incluido — migró los módulos Javax heredados detrás de esos portales a Spring Boot, módulo por módulo, detrás de un contrato de API compartido. La decisión no obvia: el Javax heredado y los nuevos servicios Spring Boot corrieron lado a lado en la misma red operativa, ruteados por feature flag en vez de por endpoint, para mover un solo equipo, validar, y solo después expandir.
No hubo fin de semana de migración. Hubo una secuencia de martes seguros.
Resultado
La app móvil le dio a los abonados un único lugar para todo lo que antes hacían entre dos flujos de navegador — las tareas diarias (iniciar sesión, ver saldo, ver horas de bonificación) se convirtieron en operaciones de una pantalla y un tap. Detrás, los módulos ya migrados a Spring Boot mostraron una mejora de throughput de 3× contra el baseline heredado. El personal operativo notó tiempos de respuesta más rápidos sin que nadie les contara por qué. Cero caídas durante la ventana de migración para los módulos que enviamos.
El patrón de “sin fin de semana de migración grande” ahora es el default del equipo para cualquier trabajo de modernización — y la app sigue evolucionando contra el backend al que el flag la rutea.


