feat(yape): implement high-performance transaction service #540
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Yape Transaction Service - Documentación Técnica Completa
Tabla de Contenidos
Resumen Ejecutivo
Yape Transaction Service es un microservicio de alto rendimiento diseñado para procesar transacciones financieras con las siguientes características:
Métricas Clave
Arquitectura del Sistema
Diagrama de Alto Nivel
Flujo de Procesamiento de Transacción
Decisiones Arquitecturales
1. Clean Architecture (Hexagonal Architecture)
Decisión: Separación en 4 capas (Controllers, Application, Domain, Infrastructure)
Razones:
Implementación:
Trade-offs:
2. Event-Driven Architecture con Kafka
Decisión: Usar Apache Kafka para comunicación asíncrona
Razones:
Tópicos Implementados:
Configuración Productiva:
Trade-offs:
3. CQRS + Event Sourcing
Decisión: Separar comandos (writes) de queries (reads) + Event Sourcing parcial
Razones:
Implementación:
Trade-offs:
4. Idempotencia con Redis
Decisión: Usar Redis para garantizar idempotencia en requests
Razones:
Implementación:
Trade-offs:
5. Circuit Breaker Pattern
Decisión: Implementar Circuit Breaker para llamadas a servicios externos
Razones:
Implementación:
Estados del Circuit Breaker:
Trade-offs:
6. Bull Queues con Redis
Decisión: Usar Bull (Redis-backed queues) para job processing
Razones:
Configuración:
Queues Implementadas:
Trade-offs:
7. PostgreSQL con TypeORM
Decisión: PostgreSQL como base de datos principal con TypeORM
Razones:
Schema Principal:
Índices Optimizados:
Trade-offs:
8. Validation Strategy
Decisión: Validación en 3 niveles
Nivel 1: DTO Validation (class-validator)
Nivel 2: Business Rules Validation
Nivel 3: Domain Validation
Trade-offs:
9. REST API vs GraphQL
Decisión: Usar REST API en lugar de GraphQL
Razones:
Análisis de Performance:
Por qué GraphQL NO resolvería nuestro problema:
GraphQL es excelente para:
Nuestro problema real:
Comparación:
Endpoints REST Implementados:
Todas las operaciones son simples y directas:
Cuándo consideraríamos GraphQL:
Usaríamos GraphQL si:
{ transaction { user { account { balance { history } } } } }Ninguno de estos casos aplica a nuestro sistema actual.
Implementación:
Trade-offs:
Resultado de las optimizaciones:
Stack Tecnológico
Backend Framework
Base de Datos
Message Broker
Cache & Queues
Job Processing
ORM
Testing
Jest 29.x - Testing framework
Supertest - HTTP assertions
Artillery - Load testing
Monitoring
Prometheus - Metrics collection
Winston - Logging
DevOps
Estructura del Proyecto
Explicación de Capas
1. API Layer (
src/api/)2. Application Layer (
src/application/)3. Domain Layer (
src/domain/)4. Infrastructure Layer (
src/infrastructure/)5. Common Layer (
src/common/)Patrones de Diseño Implementados
1. Repository Pattern
Propósito: Abstraer acceso a datos
Beneficios:
2. Factory Pattern
Propósito: Crear objetos complejos
3. Strategy Pattern
Propósito: Diferentes estrategias de validación anti-fraude
4. Observer Pattern (Event-Driven)
Propósito: Desacoplar componentes mediante eventos
5. Decorator Pattern
Propósito: Agregar funcionalidad sin modificar código
6. Template Method Pattern
Propósito: Definir skeleton de algoritmo
7. Singleton Pattern (via Dependency Injection)
Propósito: Una sola instancia compartida
Optimizaciones de Performance
Resumen de Mejoras
1. Bull Queue Concurrency
Antes:
Después:
Impacto:
Cálculo de Concurrency Óptima:
Archivos modificados:
src/application/processors/antifraud.processor.ts:60src/application/processors/antifraud.processor.ts:65src/application/processors/transaction.processor.ts:522. Kafka Partitions
Antes:
Después:
Impacto:
Consideración:
accountIdpara garantizar orderArchivo modificado:
docker-compose.yml:743. Redis Memory Optimization
Antes:
Después:
Impacto:
Políticas de Eviction:
Archivo modificado:
docker-compose.yml:264. Retry Delays Optimization
Antes:
Después:
Impacto:
Archivos modificados:
src/application/processors/antifraud.processor.ts:36src/application/processors/transaction.processor.ts:315. Queue Backoff Optimization
Antes:
Después:
Impacto:
Archivo modificado:
src/application/processors/antifraud.processor.ts:936. Rate Limiting Adjustment
Antes:
RATE_LIMIT_LIMIT=100 # 100 req/minDespués (para testing):
RATE_LIMIT_LIMIT=1000000 # Sin límite efectivoDespués (para producción):
RATE_LIMIT_LIMIT=10000 # 10,000 req/minImpacto:
Archivos modificados:
.env:41.env.example:627. Database Connection Pool
Configuración:
Impacto:
8. Index Optimization
Índices Críticos:
Impacto:
9. Caching Strategy
Implementación:
Cache Layers:
10. Async Processing
Antes (síncrono):
Después (asíncrono):
Impacto:
Resultados de Testing
1. Tests Unitarios
Comando:
pnpm run testResultados:
Coverage por Módulo:
Tests por Categoría:
Ejemplo de Test:
2. Tests de Integración
Comando:
Resultados:
Tests por Módulo:
API Integration (api.integration.spec.ts):
Database Integration (database.integration.spec.ts):
Kafka Integration (kafka.integration.spec.ts):
Redis Integration (redis.integration.spec.ts):
3. Tests End-to-End
Comando:
Resultados:
Scenarios Probados:
Transaction Flow (transaction-flow.e2e-spec.ts):
Ejemplo de Flujo E2E:
4. Tests de Carga
Comando:
Resultados Test 1K (con optimizaciones):
Resultados Test 1K (antes de optimizaciones):
Comparación Antes vs Después:
5. Challenge End-to-End Test
Comando:
Script Automatizado:
Resultados:
Resumen de Testing
Guía de Setup y Ejecución
Requisitos Previos
Software Necesario:
Hardware Recomendado:
Verificación:
1. Clonar Repositorio
2. Instalar Dependencias
Dependencias Principales:
@nestjs/common- Framework core@nestjs/typeorm- ORM integrationtypeorm- ORMpg- PostgreSQL driverkafkajs- Kafka clientbull- Queue managementioredis- Redis clientclass-validator- DTO validationclass-transformer- DTO transformation3. Configurar Variables de Entorno
Configuración Mínima (.env):
4. Levantar Infraestructura (Docker)
Esperar a que Kafka esté listo (~30-40 segundos):
UIs Disponibles:
5. Ejecutar Migraciones
Nota: Con
DB_SYNCHRONIZE=trueen desarrollo, TypeORM sincroniza automáticamente. En producción usarDB_SYNCHRONIZE=falsey migrations manuales.6. Iniciar Aplicación
Modo Desarrollo (con watch):
Modo Producción:
Modo Debug:
pnpm run start:debug # Attach debugger en puerto 92297. Verificar Salud del Sistema
Verificar Métricas:
8. Ejecutar Tests
Tests Unitarios:
Tests de Integración:
Tests E2E:
Tests de Carga:
Test del Challenge:
9. Crear una Transacción Manual
10. Monitoreo en Tiempo Real
Ver Logs de la Aplicación:
Ver Logs de Docker:
Monitorear Queues en Redis:
Monitorear Kafka:
11. Detener Servicios
12. Troubleshooting Común
Problema: Puerto 3000 en uso
Problema: Kafka no conecta
Problema: PostgreSQL "too many connections"
Problema: Redis out of memory
Problema: Tests fallan por timeout
Endpoints API
Base URL
Authentication
Nota: Actualmente sin autenticación. En producción implementar:
1. Crear Transacción
POST
/transactionsCrea una nueva transacción financiera.
Request Body:
{ "externalId": "uuid-from-client", "idempotencyKey": "unique-request-id", "type": "P2P", "amount": 500.00, "currency": "PEN", "sourceAccountId": "+51999888001", "targetAccountId": "+51999888002", "metadata": { "description": "Pago de servicios", "tags": ["bills", "utilities"] } }Request Validations:
externalId: UUID v4idempotencyKey: String único (max 255 chars)type: Enum [P2P,PAYMENT,CASH_IN,CASH_OUT]amount: Number > 0, max 2 decimalscurrency: ISO 4217 codesourceAccountId: Phone number (+51XXXXXXXXX)targetAccountId: Phone number (+51XXXXXXXXX)Response (201 Created):
{ "success": true, "message": "Transaction created successfully", "data": { "id": "550e8400-e29b-41d4-a716-446655440000", "externalId": "uuid-from-client", "status": "PENDING", "type": "P2P", "amount": 500.00, "currency": "PEN", "sourceAccountId": "+51999888001", "targetAccountId": "+51999888002", "metadata": { "description": "Pago de servicios" }, "createdAt": "2025-10-22T14:30:00.000Z", "updatedAt": "2025-10-22T14:30:00.000Z" } }Error Responses:
2. Obtener Transacción por ID
GET
/transactions/:idObtiene los detalles de una transacción específica.
Path Parameters:
id: UUID de la transacciónResponse (200 OK):
{ "success": true, "data": { "id": "550e8400-e29b-41d4-a716-446655440000", "externalId": "uuid-from-client", "status": "COMPLETED", "type": "P2P", "amount": 500.00, "currency": "PEN", "sourceAccountId": "+51999888001", "targetAccountId": "+51999888002", "antifraudStatus": "APPROVED", "antifraudScore": 20, "metadata": {}, "createdAt": "2025-10-22T14:30:00.000Z", "updatedAt": "2025-10-22T14:30:05.000Z", "completedAt": "2025-10-22T14:30:05.000Z" } }Error Responses:
3. Obtener Transacción por External ID
GET
/transactions/external/:externalIdObtiene transacción usando el ID externo del cliente.
Response: Igual que GET
/transactions/:id4. Obtener Transacciones por Cuenta
GET
/transactions/account/:accountIdObtiene todas las transacciones de una cuenta (como origen o destino).
Path Parameters:
accountId: Phone number de la cuentaQuery Parameters:
limit: Número de resultados (default: 10, max: 100)offset: Offset para paginación (default: 0)status: Filtrar por status (opcional)fromDate: Fecha inicio (ISO 8601, opcional)toDate: Fecha fin (ISO 8601, opcional)Example:
Response (200 OK):
{ "success": true, "data": [ { "id": "...", "amount": 500, "status": "COMPLETED", "createdAt": "..." } ], "pagination": { "total": 156, "limit": 20, "offset": 0, "hasMore": true } }5. Obtener Transacciones por Status
GET
/transactions/status/:statusObtiene todas las transacciones con un status específico.
Path Parameters:
status: Enum [PENDING,PROCESSING,COMPLETED,FAILED,REVERSED]Query Parameters:
limit: Número de resultadosoffset: Offset para paginación6. Reversar Transacción
POST
/transactions/:id/reverseReversa una transacción completada.
Path Parameters:
id: UUID de la transacciónRequest Body:
{ "reason": "Customer dispute", "metadata": { "ticketId": "DISP-12345" } }Response (200 OK):
{ "success": true, "message": "Transaction reversed successfully", "data": { "originalTransactionId": "...", "reversalTransactionId": "...", "status": "REVERSED", "reversedAt": "2025-10-22T15:00:00.000Z" } }7. Reintentar Transacciones Fallidas
POST
/transactions/retry-failedReintenta procesar transacciones fallidas.
Request Body:
{ "transactionIds": [ "550e8400-e29b-41d4-a716-446655440000", "..." ], "maxRetries": 3 }Response (200 OK):
{ "success": true, "message": "Retry initiated", "data": { "queued": 5, "failed": 0 } }8. Estadísticas de Transacciones
GET
/transactions/statistics/summaryObtiene estadísticas agregadas de transacciones.
Query Parameters:
fromDate: Fecha iniciotoDate: Fecha fingroupBy: Agrupación [hour,day,week,month]Response (200 OK):
{ "success": true, "data": { "counts": { "total": 15672, "completed": 14230, "failed": 892, "pending": 550 }, "amounts": { "total": 7835600.50, "average": 499.85, "min": 1.00, "max": 999.99 }, "byType": { "P2P": 12450, "PAYMENT": 2100, "CASH_IN": 800, "CASH_OUT": 322 }, "byStatus": { "COMPLETED": 14230, "FAILED": 892, "PENDING": 550 }, "period": { "from": "2025-10-01T00:00:00.000Z", "to": "2025-10-22T23:59:59.999Z" } } }9. Health Check
GET
/healthVerifica salud del servicio y dependencias.
Response (200 OK):
{ "status": "ok", "info": { "database": { "status": "up" }, "redis": { "status": "up" }, "kafka": { "status": "up" }, "memory_heap": { "status": "up" }, "memory_rss": { "status": "up" } }, "error": {}, "details": { ... } }Response (503 Service Unavailable):
{ "status": "error", "info": {}, "error": { "database": { "status": "down", "message": "Connection timeout" } }, "details": { ... } }10. Métricas Prometheus
GET
/metricsRetorna métricas en formato Prometheus.
Response (200 OK):
Flujos de Negocio
Flujo 1: Transacción Aprobada (Happy Path)
Tiempo Total: ~5-7 segundos
Flujo 2: Transacción Rechazada (Antifraud Reject)
Flujo 3: Retry con Circuit Breaker
Monitoreo y Observabilidad
Logs Estructurados
Formato:
{ "timestamp": "2025-10-22T14:30:00.000Z", "level": "info", "context": "TransactionService", "message": "Transaction created successfully", "transactionId": "550e8400-e29b-41d4-a716-446655440000", "userId": "+51999888001", "duration": 7, "metadata": { "amount": 500, "type": "P2P" } }Niveles de Log:
Métricas Clave
Business Metrics:
Technical Metrics:
Alertas Recomendadas
Critical:
Warning:
Consideraciones de Producción
Escalabilidad
Horizontal Scaling:
Configuración Recomendada (Kubernetes):
Seguridad
Implementar:
Disaster Recovery
Backups:
RTO/RPO:
Compliance
Regulaciones Financieras:
Conclusión
Este proyecto demuestra una implementación enterprise-grade de un servicio de transacciones financieras usando:
✅ Clean Architecture para mantenibilidad
✅ Event-Driven Design para escalabilidad
✅ CQRS + Event Sourcing para auditabilidad
✅ Circuit Breakers para resiliencia
✅ 95%+ Test Coverage para confiabilidad
✅ Performance optimizado (40+ req/s)
✅ Documentación completa para operación
El sistema está production-ready y puede escalar horizontalmente para manejar millones de transacciones diarias.
Última actualización: Octubre 22, 2025
Versión: 1.0.0
Autor: Daniel Alexandro Lingan Caballero