API desarrollada con NestJS para procesar y consultar datos de deudores del Banco Central de la República Argentina (BCRA) con procesamiento asíncrono con SQS y subida a S3 usando LocalStack.
- Procesamiento asíncrono con SQS para archivos grandes
- Subida optimizada a S3 con multipart upload para archivos pesados
- Procesamiento por lotes de 3000 registros para eficiencia optimizada
- API REST para consulta de deudores y entidades
- Base de datos MySQL con migraciones automáticas
- LocalStack para simular servicios AWS (S3, SQS)
- Docker Compose para orquestación completa de servicios
- Procesamiento eficiente de archivos grandes (>100MB usa multipart)
- Arquitectura modular con microservicios
- Seguimiento de progreso en tiempo real
- Notificaciones por email al inicio y finalización del procesamiento
- Docker & Docker Compose
- pnpm (gestor de paquetes)
- Git
-
Clonar el repositorio
git clone <repository-url> cd waynijs
-
Iniciar todos los servicios
# Iniciar MySQL, LocalStack y la aplicación docker-compose up -d -
Inicializar LocalStack
# Inicializar recursos S3 y SQS ./scripts/init-localstack.sh -
Verificar que todo funciona
# Ver estado de los contenedores docker-compose ps # Ver logs de la aplicación docker-compose logs -f app # Probar la API curl http://localhost:3001/api
-
Clonar el repositorio
git clone <repository-url> cd waynijs
-
Instalar dependencias
pnpm install
-
Configurar variables de entorno
# El archivo .env ya está configurado para desarrollo local # Solo necesitas tener MySQL ejecutándose localmente
-
Iniciar servicios de soporte
# Iniciar solo MySQL y LocalStack docker-compose up mysql localstack -d # Inicializar LocalStack ./scripts/init-localstack.sh
-
Ejecutar la aplicación
pnpm run start:dev
El proyecto incluye los siguientes servicios en Docker Compose:
-
MySQL 8.0: Base de datos principal
- Puerto:
3306 - Usuario:
root - Contraseña:
root123 - Base de datos:
wayni - Migraciones automáticas habilitadas
- Puerto:
-
LocalStack: Simulación de servicios AWS
- Puerto:
4566 - Servicios: S3, SQS
- Bucket S3:
wayni-files - Cola SQS:
wayni-notifications - Estrategia de endpoint:
standard
- Puerto:
-
MailHog: Servidor SMTP para desarrollo
- Puerto:
8025(UI web) - Puerto:
1025(SMTP) - Captura todos los emails enviados
- Puerto:
-
Aplicación NestJS: API principal
- Puerto:
3001 - Hot reload en desarrollo
- Procesamiento asíncrono con SQS
- Puerto:
id: ID único autoincrementalnro_identificacion: CUIT/CUIL (único)situacion_maxima: Máximo valor entre registros coincidentessuma_total_prestamos: Suma total de préstamoscreated_at,updated_at: Timestamps
id: ID único autoincrementalcodigo_entidad: Código de entidad financiera (único)suma_total_prestamos: Suma total agrupada por entidadcreated_at,updated_at: Timestamps
GET /- Mensaje de bienvenidaGET /api- Información completa de la API (incluye listado de endpoints)
POST /import/upload- Procesar archivo de deudores (asíncrono con SQS)GET /import/jobs/{jobId}- Obtener estado de un trabajo específico
GET /deudores/{cuit}- Buscar deudor por CUIT/CUILGET /deudores/top/{n}- Top N deudores con mayor suma de préstamosGET /deudores?situacion={n}- Filtrar deudores por situaciónGET /deudores/stats/overview- Estadísticas generales de deudores
GET /entidades/{codigo}- Buscar entidad por códigoGET /entidades- Listar todas las entidadesGET /entidades/stats/overview- Estadísticas generales de entidades
- Host:
localhost - Puerto:
3306 - Usuario:
root - Contraseña:
root123 - Base de datos:
wayni
mysql -h localhost -P 3306 -u root -p
# Contraseña: root123docker exec -it wayni-mysql mysql -u root -p
# Contraseña: root123src/
├── config/
│ └── database.config.ts # Configuración de base de datos
├── modules/
│ ├── aws/ # Módulo de servicios AWS
│ │ ├── aws.module.ts
│ │ ├── s3.service.ts # Servicio S3
│ │ └── sqs.service.ts # Servicio SQS
│ ├── deudores/ # Módulo de deudores
│ │ ├── entities/
│ │ │ └── deudor.entity.ts
│ │ ├── deudores.controller.ts
│ │ ├── deudores.service.ts
│ │ └── deudores.module.ts
│ ├── entidades/ # Módulo de entidades
│ │ ├── entities/
│ │ │ └── entidad.entity.ts
│ │ ├── entidades.controller.ts
│ │ ├── entidades.service.ts
│ │ └── entidades.module.ts
│ ├── import/ # Módulo de importación
│ │ ├── import.controller.ts
│ │ ├── import.service.ts
│ │ └── import.module.ts
│ ├── email/ # Módulo de email
│ │ ├── email.service.ts # Servicio de envío de emails
│ │ └── email.module.ts
│ ├── notification/ # Módulo de notificaciones
│ │ ├── notification.service.ts
│ │ └── notification.module.ts
│ └── queue/ # Módulo de colas
│ ├── queue.service.ts # Servicio de colas
│ ├── queue-worker.service.ts # Worker de procesamiento
│ └── queue.module.ts
├── shared/
│ ├── interfaces/ # Interfaces TypeScript
│ │ └── bcra-record.interface.ts
│ └── services/ # Servicios compartidos
│ └── file-parser.service.ts
└── main.ts # Punto de entrada
# Iniciar procesamiento asíncrono indicando la ruta del archivo
curl -X POST http://localhost:3001/import/upload \
-H "Content-Type: application/json" \
-d '{"filePath":"./deudores/deudores.txt"}'
# Ver estado de un trabajo específico
curl http://localhost:3001/import/jobs/{jobId}# Procesar archivo específico
curl -X POST http://localhost:3001/import/upload \
-H "Content-Type: application/json" \
-d '{"filePath": "/ruta/al/archivo.txt"}'curl http://localhost:3001/deudores/20123456789curl http://localhost:3001/deudores/top/10curl http://localhost:3001/deudores?situacion=5curl http://localhost:3001/entidades/001curl http://localhost:3001/deudores/stats/overview
curl http://localhost:3001/entidades/stats/overview# Ejecutar pruebas e2e de integración (requiere Docker corriendo)
pnpm run test:e2e -- --testNamePattern="SQS.*S3.*Integration"# 1) Ver que LocalStack tenga el bucket y la cola
docker compose exec localstack awslocal s3 ls | grep wayni-files
docker compose exec localstack awslocal sqs list-queues | grep wayni-notifications
# 2) Disparar el procesamiento (usa ./deudores/deudores.txt por defecto)
JOB_ID=$(curl -s -X POST http://localhost:3001/import/upload | jq -r .jobId)
echo "Job: $JOB_ID"
# 3) Monitorear el estado y progreso
watch -n 5 "curl -s http://localhost:3001/import/jobs/$JOB_ID | jq"
# 4) Ver logs del worker y eventos SQS/S3
docker compose logs -f app | grep -E "submitJob|SQS|QueueWorker|S3|s3Url"# Acceder a la interfaz web de MailHog
open http://localhost:8025
# O verificar via API
curl http://localhost:8025/api/v1/messages# Ver estado de todos los servicios
docker-compose ps
# Iniciar todos los servicios
docker-compose up -d
# Detener todos los servicios
docker-compose down
# Reiniciar un servicio específico
docker-compose restart app
# Ver logs de un servicio
docker-compose logs -f app
docker-compose logs -f mysql
docker-compose logs -f localstack
docker-compose logs -f mailhog# Conectar a MySQL
docker exec -it wayni-mysql mysql -u root -p
# Hacer backup de la base de datos
docker exec wayni-mysql mysqldump -u root -proot123 wayni > backup.sql
# Restaurar backup
docker exec -i wayni-mysql mysql -u root -proot123 wayni < backup.sql
# Limpiar volúmenes (¡CUIDADO! Borra todos los datos)
docker-compose down -v# Reconstruir la aplicación
docker-compose up --build -d
# Ejecutar comandos en el contenedor de la app
docker exec -it waynijs-app-1 sh
# Ver logs en tiempo real
docker-compose logs -f --tail=100 app- Agrupación por CUIT/CUIL: Los registros se agrupan por número de identificación
- Situación Máxima: Se toma el valor máximo del campo 6 entre registros coincidentes
- Suma Total: Se suman todos los préstamos (campo 7) del mismo deudor
- Agrupación por Código: Se agrupa por código de entidad (campo 1)
- Suma Total: Se suman todos los préstamos agrupados por entidad
El sistema utiliza un flujo asíncrono completo que incluye:
- Envío a SQS: El archivo se envía a la cola SQS para procesamiento asíncrono
- Email de inicio: Se envía notificación por email al iniciar el procesamiento
- Subida a S3: El archivo se sube a S3 con multipart upload para archivos grandes
- Procesamiento por lotes: QueueWorker procesa el archivo en lotes de 3000 registros via SQS
- Monitoreo: Seguimiento del progreso en tiempo real
- Email de finalización: Se envía notificación por email al completar el procesamiento
Variables de entorno clave:
AWS_ENDPOINT_URL=http://localstack:4566
AWS_ACCESS_KEY_ID=test
AWS_SECRET_ACCESS_KEY=test
S3_BUCKET_NAME=wayni-files
SQS_QUEUE_URL=http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/wayni-notifications
SMTP_HOST=mailhog
SMTP_PORT=1025- Carga del archivo: Se lee el archivo TXT del BCRA desde
/data/ - Parsing: Se procesa línea por línea usando streams para eficiencia
- Transformación: Se agrupan y transforman los datos según las reglas de negocio
- Almacenamiento: Se guardan en MySQL con TypeORM
- Backup S3: Se almacena el archivo original en LocalStack S3
- Notificación: Se envía notificación de finalización a SQS
graph TD
A[Archivo TXT] --> B[NestJS API]
B --> C[MySQL DB]
B --> D[S3 - LocalStack]
B --> E[SQS - LocalStack]
E --> F[Queue Worker]
F --> C
F --> D
B --> G[MailHog UI]
F --> H[SMTP MailHog]
classDef svc fill:#eef,stroke:#88a,stroke-width:1px;
class B,C,D,E,F,G,H svc;
- Archivo: Procesa en lotes de 3000 registros (optimizado)
- Base de datos: Guarda en lotes de 3000 registros
- Memoria: Uso eficiente con streams
- Concurrencia: Permite procesamiento de múltiples archivos
- SQS: Cola de mensajes para trabajos
- Worker: Procesamiento en background
- Progreso: Seguimiento en tiempo real
- Escalabilidad: Fácil escalado horizontal
# Ejecutar tests unitarios
pnpm run test
# Ejecutar tests con cobertura
pnpm run test:cov
# Ejecutar tests e2e
pnpm run test:e2eLa aplicación genera logs estructurados que incluyen:
- Progreso del procesamiento de archivos (cada 10,000 líneas)
- Estadísticas de importación por lotes
- Notificaciones de finalización vía SQS
- Errores y advertencias detallados
- Estado de trabajos asíncronos
- Archivos grandes: El sistema está optimizado para procesar archivos >200MB
- Memoria: Usa streams y procesamiento por lotes para eficiencia
- Concurrencia: Maneja múltiples solicitudes simultáneas
- Validación: Valida formato de CUIT/CUIL y códigos de entidad
- Docker: Requiere al menos 4GB de RAM disponible para todos los servicios
- Puertos: Asegúrate de que los puertos 3001, 3306, 4566, 8025 y 1025 estén disponibles
- SQS: Requiere inicialización de LocalStack para funcionar correctamente
- Email: Los emails se capturan en MailHog para desarrollo (puerto 8025)
- Rendimiento: Lotes de 3000 registros optimizados para procesamiento rápido
# Modo desarrollo con hot reload
pnpm run start:dev
# Compilar para producción
pnpm run build
# Ejecutar en producción
pnpm run start:prod
# Linting
pnpm run lint# Iniciar solo servicios de soporte
docker-compose up mysql localstack -d
# Ejecutar la app localmente
pnpm run start:dev
# Reconstruir y reiniciar todo
docker-compose down && docker-compose up --build -d# Ver qué proceso usa el puerto 3001
lsof -ti:3001
# Matar el proceso
kill -9 $(lsof -ti:3001)# Verificar que MySQL esté ejecutándose
docker-compose ps mysql
# Ver logs de MySQL
docker-compose logs mysql
# Reiniciar MySQL
docker-compose restart mysql# Verificar estado de LocalStack
curl http://localhost:4566/_localstack/health
# Reiniciar LocalStack
docker-compose restart localstack
# Inicializar recursos nuevamente
./scripts/init-localstack-curl-sqs.sh# Verificar que la cola existe
curl -X POST "http://localhost:4566/" \
-H "Content-Type: application/x-amz-json-1.0" \
-H "X-Amz-Target: AWSSimpleQueueService.ListQueues" \
-d '{}'
# Crear la cola manualmente si es necesario
curl -X POST "http://localhost:4566/" \
-H "Content-Type: application/x-amz-json-1.0" \
-H "X-Amz-Target: AWSSimpleQueueService.CreateQueue" \
-d '{"QueueName": "wayni-notifications"}'# Detener y eliminar contenedores y volúmenes
docker-compose down -v
# Eliminar imágenes
docker-compose down --rmi all
# Iniciar desde cero
docker-compose up --build -d# Ver todos los trabajos
curl http://localhost:3001/import/jobs
# Ver estado de un trabajo específico
curl http://localhost:3001/import/jobs/{jobId}# Ver logs de la aplicación
docker-compose logs -f app
# Ver logs de un servicio específico
docker-compose logs -f mysql
docker-compose logs -f localstack
docker-compose logs -f mailhog# Acceder a la interfaz web de MailHog
open http://localhost:8025
# Ver todos los emails enviados
curl -s http://localhost:8025/api/v1/messages | jq '.[0].Content.Headers.Subject[0]'
# Contar emails enviados
curl -s http://localhost:8025/api/v1/messages | jq 'length'Este proyecto es parte de una prueba técnica para Wayni Móvil.
Desarrollado con ❤️ usando NestJS, TypeORM, MySQL, SQS y LocalStack