Dragonchat
Trabajé en el desarrollo y evolución de un producto orientado al envío masivo de mensajes a través de WhatsApp, basado en una arquitectura de microservicios. Este sistema permitía a los usuarios automatizar campañas de mensajería, gestionar contenido dinámico y mantener control sobre los envíos en tiempo real. Mi rol estuvo principalmente enfocado en el backend, participando en el diseño de servicios, modelado de datos y optimización de flujos críticos para mejorar la escalabilidad, mantenibilidad y rendimiento del sistema.
Arquitectura general de microservicios
Uno de los aportes clave fue la creación de un sistema interno de feature flags implementado como un microservicio independiente. Me encargué del diseño del modelo de datos, así como de la construcción completa de su API, permitiendo habilitar o deshabilitar funcionalidades de forma dinámica sin necesidad de despliegues. Esto facilitó la experimentación controlada y el rollout progresivo de nuevas features dentro del ecosistema de servicios.
Feature Flags — flujo de habilitación
Otro de los desarrollos más relevantes fue la reconstrucción completa del sistema de mensajería. Diseñé una API dedicada para la gestión de mensajes, incluyendo su modelo de datos y endpoints, e integré RabbitMQ para manejar la comunicación asíncrona. Esto permitió que los envíos se procesaran en background, independientemente del estado del cliente, habilitando funcionalidades como pausa, reanudación y modificación de campañas en tiempo real, todo orquestado desde el backend.
Implementé una funcionalidad de "sequence library" que permitía a los usuarios crear, almacenar y reutilizar plantillas de mensajes. Estas secuencias podían incluir múltiples mensajes, variaciones de texto y archivos asociados, los cuales se almacenaban de forma persistente. Además, desarrollé la lógica para compartir secuencias entre usuarios y gestionar restricciones según el tipo de suscripción, integrando validaciones tanto a nivel de negocio como de API.
Sistema de archivos con Supabase + Redis
También diseñé e implementé un sistema de gestión de archivos completamente desde el backend, reemplazando una lógica previa que dependía del frontend. Integré almacenamiento con Supabase y optimicé el acceso mediante el uso de Redis, manejando los archivos a través de identificadores únicos y cacheando URLs firmadas para reducir la latencia y la carga de requests repetidos. Además, implementé un mecanismo automático de limpieza que eliminaba archivos temporales después de 24 horas, asegurando eficiencia en el uso de recursos.
A nivel de infraestructura, realicé la migración de los microservicios desde Express a Fastify dentro del framework NestJS, lo que implicó adaptar middlewares, manejo de requests/responses y subida de archivos. Esta migración permitió mejorar significativamente el rendimiento de las APIs y optimizar el consumo de recursos.
Refactorización del API Gateway — antes y después
Lideré la refactorización de la API Gateway, la cual inicialmente concentraba lógica de negocio que no le correspondía. Reorganicé la arquitectura extrayendo dicha lógica hacia un servicio intermedio (middleend), logrando una separación clara de responsabilidades. Esto permitió que el Gateway se enfocara exclusivamente en la orquestación y comunicación entre servicios, mejorando la escalabilidad y mantenibilidad del sistema.
En términos de seguridad, implementé configuraciones de CORS y Helmet en los servicios, definiendo políticas de acceso y agregando headers de seguridad para mitigar vulnerabilidades comunes como XSS y otros riesgos asociados a la exposición de APIs.
Adicionalmente, desarrollé una librería interna para NestJS que estandarizaba la realización de requests HTTP mediante Axios, incorporando logging configurable e integración con herramientas de observabilidad como Loki, Prometheus y Grafana. Esto permitió mejorar la trazabilidad y monitoreo de las comunicaciones entre microservicios.
Finalmente, optimicé el manejo de contexto de las requests mediante la implementación de AsyncLocalStorage, eliminando la necesidad de utilizar servicios con scope de request. Esto permitió mantener acceso a información contextual en toda la ejecución sin sacrificar rendimiento, logrando una arquitectura más eficiente basada en servicios singleton.