Volver al blog

De un reto técnico a un SPA full-stack: Angular 19, Express y Firebase

25 ago 2026 6 min de lecturaAngular

Caso de estudio: cómo resolví un reto técnico full-stack —una app de tareas con login, CRUD y estado— con Angular 19, un API Express + TypeScript en Cloud Functions y Firestore, aplicando arquitectura hexagonal, SOLID y buenas prácticas.

De un reto técnico a un SPA full-stack: Angular 19, Express y Firebase

Una startup de mensajería en tiempo real me lanzó un reto técnico full-stack: construir una aplicación de tareas completa, con login, CRUD y estado, en pocos días. El detalle divertido es que el frontend pedía Angular, un framework que hasta ese momento nunca había tocado. Aun así, no bajé el listón: entregué un SPA con arquitectura limpia, un API desacoplado y buenas prácticas de punta a punta. Este es el detrás de escena —las decisiones técnicas, no solo el resultado— y lo que revela de cómo trabajo.

El reto

Sobre el papel sonaba a un «Todo app» más. En la práctica, el enunciado estaba diseñado para medir criterio de arquitectura, no para ver si sabías pintar una lista. Lo que pedían:

  • Dos páginas. Un inicio de sesión y un tablero principal con las tareas del usuario ordenadas por fecha de creación.
  • Login solo con correo. Si el usuario existe, entra directo; si no, aparece un diálogo que confirma su creación y luego pasa al tablero.
  • CRUD de tareas. Cada tarea con título, descripción, fecha de creación y estado; crear, editar, eliminar y marcar como completada o pendiente con una casilla.
  • Responsive y usable en cualquier dispositivo.
  • Un API propio con Express y TypeScript, desplegado en Cloud Functions, con Firestore como base de datos, y seis endpoints: listar, crear, actualizar y eliminar tareas, más buscar y crear usuario.

Cómo se evaluaba (el listón real)

El enunciado era explícito: se prioriza la calidad del código y las buenas prácticas por encima de la cantidad de funcionalidades. En concreto miraban arquitectura limpia o hexagonal, principios SOLID, patrones de diseño (repositorios, factories, singletons), observables y servicios bien estructurados en el frontend, trackBy en las listas, guards y lazy loading, seguridad con tokens y CORS, pruebas unitarias, y un README útil. En otras palabras: no querían ver qué construyes, sino cómo decides.

Esa última frase fue mi brújula. Preferí entregar menos superficie, pero cada pieza en su sitio.

Arquitectura de un vistazo

Antes de escribir una línea, dibujé el flujo completo: un cliente Angular que habla por HTTP con un API Express desplegado como función serverless, que a su vez persiste en Firestore. Cada petición viaja autenticada con un token; cada capa tiene una única responsabilidad.

Diagrama de arquitectura: el navegador ejecuta un SPA de Angular 19 con rutas lazy y guards; se comunica por HTTP con JWT contra un API Express + TypeScript desplegado en Firebase Cloud Functions, organizado en capas hexagonales (controllers, casos de uso, repositorios); los repositorios persisten en Cloud Firestore en las colecciones users y tasks

La idea de fondo es simple: el cliente no sabe nada de Firestore y el dominio no sabe nada de Express. Cada frontera está ahí para que una decisión de infraestructura (cambiar la base de datos, mover el hosting) no se filtre al resto.

Las decisiones técnicas

Aquí está el corazón del reto. Separé el trabajo en tres frentes y en cada uno tomé decisiones deliberadas.

Angular 19, aprendido sobre la marcha, pero con criterio.

  • Componentes standalone y funcionalidades cargadas con lazy loading, para que el navegador solo descargue lo que la ruta necesita.
  • Estado con Angular Signals —el enfoque moderno del framework— y RxJS para las llamadas al API, que la plantilla consume con el async pipe: nada de suscripciones colgadas que limpiar a mano.
  • Dos guards: uno de autenticación protege el tablero, y otro de habilidad (CASL) decide qué puede hacer cada rol antes de entrar a una ruta.
  • Un interceptor HTTP adjunta el token a cada petición de forma centralizada.
  • Formularios reactivos con validación tipada, y trackBy en la lista para que Angular no repinte el DOM entero en cada cambio.
  • Angular Material + TailwindCSS, con una arquitectura modular core / features / shared y una interfaz responsive y accesible.

Por qué la arquitectura hexagonal aquí

Para una lista de tareas puede sonar a sobreingeniería. No lo era: el reto medía justamente esto. Separar dominio, aplicación e infraestructura convierte «funciona» en «funciona y se puede mantener», y demuestra que sé dónde poner cada responsabilidad aunque el dominio sea pequeño.

El flujo de usuario, paso a paso

Con la arquitectura resuelta, la experiencia quedó exactamente como pedía el enunciado:

Inicia sesión con el correo

El usuario escribe solo su email. El frontend pregunta al API si ya existe.

Confirma la creación si es nuevo

Si el correo no está registrado, un diálogo pregunta si quiere crear la cuenta. Al aceptar, se da de alta y entra directo, sin fricción extra.

Gestiona sus tareas

En el tablero ve sus tareas ordenadas por fecha. Puede agregar una nueva desde un formulario, editarla o eliminarla.

Marca el progreso

Una casilla alterna cada tarea entre completada y pendiente, con la interfaz respondiendo al instante gracias a los observables.

Qué demuestra esto

El reto no era la lista de tareas; era la excusa. Lo que realmente entregué fue una forma de trabajar:

  • Aprendí Angular sobre la marcha sin sacrificar la calidad. Enfrentar un framework nuevo bajo presión y aun así aplicar lazy loading, guards y estado con signals como se debe dice más que cualquier certificación.
  • Fui más allá de lo pedido donde aportaba valor. El enunciado invitaba a sumar extras; añadí permisos por roles con CASL —con su guard de habilidad y su página de acceso denegado— para mostrar cómo modelo autorización de verdad, no solo un login.
  • Prioricé criterio sobre cantidad, tal como pedía la nota del enunciado: cada pieza con una arquitectura que puedo defender.
  • Pensé en el mantenimiento desde el día uno. Un dominio desacoplado de la infraestructura es lo que separa un prototipo de algo que un equipo puede hacer crecer.

Esa es, al final, la mentalidad senior: no solo resolver el problema de hoy, sino dejar el código listo para el de mañana.

¿Tienes un reto así?

Si necesitas a alguien que llegue a un stack nuevo y entregue arquitectura sólida —no solo código que compila—, hablemos. Puedes ver cómo trabajo en la página de servicios.

El código completo está en los repositorios del frontend en Angular y del API en Express.

Foto de Marco Torres

Escrito por

Marco Torres

Desarrollador Full-Stack senior con DevOps y arquitectura cloud, y Bachiller en Ingeniería de Sistemas. Escribo sobre arquitectura escalable y las lecciones de llevar sistemas a producción — desde la trinchera.