Plataforma de rifas y sorteos Fajo Group
Sistema integral para gestionar rifas, notificaciones por WhatsApp (Meta), incluye tienda pública, panel de administración y API REST con arquitectura por capas.
El Problema
Situación que debíamos resolver
Se presentaba una operación manual y poco escalable, la gestión de rifas, números por serie, reservas, pagos y ganadores se llevaba a cabo con hojas de cálculo y procesos dispersos, lo que generaba errores y limitaba el crecimiento.
Además, existía el problema de las reservas sin pago, donde los números quedaban bloqueados indefinidamente si el comprador no completaba la transacción. Era necesario implementar un sistema que liberara automáticamente esos números y notificara al cliente por WhatsApp.
Otro reto era la trazabilidad y legalidad, se debía garantizar que cada sorteo quedara registrado de manera transparente (número ganador, persona ganadora, premio) y que las boletas fueran verificables mediante un código único o QR.
La comunicación postventa y post-sorteotambién resultaba ineficiente, ya que dependía de envíos manuales. Se requería un canal unificado que centralizara confirmaciones de compra, entrega de boletas, avisos de liberación de números y notificación de ganadores, preferiblemente a través de WhatsApp.
Finalmente, se necesitaba soportar múltiples canales de venta: tanto la tienda web como la posible integración con WhatsApp (Kapso), manteniendo una sola fuente de verdad para órdenes y números.
Requerimientos Clave
Lo que el proyecto necesitaba
Gestión de rifas con estados
Borrador, activa (venta web), solo visible (contacto WhatsApp), cerrada, finalizada.
Números por serie con estados
Disponible, reservado (con reserved_until), vendido, ganador.
Reservas con tiempo límite
Liberación automática (cron cada minuto) sin bloquear números indefinidamente.
Pagos asociados a órdenes.
Motor de boletas
Plantillas configurables, generación de imágenes (Sharp + QR), almacenamiento (S3) y envío por WhatsApp (tamaño/formatos válidos).
Contenido editable para la tienda (CMS)
Hero, marketing (barra, promo), “cómo funciona” (site content/CMS en backend).
Notificaciones WhatsApp
Confirmación, boleta, número liberado, ganador, etc., con plantillas y sanitización de parámetros (límites de Meta).
La Solución
Cómo abordamos el problema
El proyecto se construyó sobre un backend en NestJS, diseñado como una API REST versionada y organizada en módulos por dominio (rifas, sorteos, ganadores, órdenes, pagos, webhooks, flujos, motor de boletas, reportes, contenido del sitio, clientes, usuarios, permisos y auditoría). La lógica de negocio se orquesta en servicios de aplicación, mientras que el dominio define entidades clave como Raffle, Draw, Winner, Usery Permission. La infraestructura se apoya en PostgreSQLpara persistencia y S3para almacenamiento de archivos. En cuanto a las reservas, al crear una orden en estado PENDING se bloquean números con estado RESERVED y un tiempo límite (reserved_until). Un proceso programado (cron cada minuto) detecta reservas vencidas sin pago, elimina ítems de la orden, cancela órdenes vacías, libera los números a AVAILABLE y envía una notificación automática por WhatsApp informando que el número fue liberado. Los sorteos se gestionan mediante el DrawExecutionService, que determina el número ganador según formato y serie, valida que pertenezca a la rifa y comprueba si está vendido (orden CONFIRMED). Luego inserta el resultado en la tabla de ganadores, actualiza el estado del número a WINNER y envía notificaciones al ganador. En caso de que el número no esté vendido, se contempla la opción de un reroll.
El motor de boletas se implemento con TicketGeneratorService, que genera imágenes mediante Sharp, con zonas configurables y códigos QR.
Decisiones Técnicas
Por qué elegimos este enfoque
El backend se diseñó siguiendo una arquitectura por capas, que favorece la evolución y las pruebas en cada nivel:
- Domain: entidades y reglas de negocio.
- Application: servicios y jobs que orquestan la lógica.
- Infrastructure: base de datos PostgreSQL, almacenamiento en S3 e integración con Kapso.
- Interfaces: controladores HTTP que exponen la API.
Las operaciones críticas —como reclamar números, liberar reservas o ejecutar sorteos— se ejecutan dentro de transacciones PostgreSQL, garantizando consistencia y atomicidad en la gestión de órdenes y números.
El frontend, desarrollado en Next.js con App Router, utiliza Server Components por defecto para cargar datos de hero, rifas y marketing directamente desde el servidor. Además, se emplea Suspense para ofrecer una carga progresiva en la página principal, mejorando la experiencia del usuario.
Resultados
Impacto medible del proyecto
Stack Tecnológico
Herramientas y por qué las elegimos