Patrón arquitectónico
La arquitectura del plugin adopta el patrón Hexagonal (Puertos y Adaptadores) combinado con CQRS (Command Query Responsibility Segregation) y un diseño Multi-Tenant. La arquitectura hexagonal aísla la lógica de negocio de los detalles de infraestructura, como APIs, bases de datos y clientes de servicios externos. La comunicación entre el core y el mundo exterior ocurre a través de puertos (interfaces) y adaptadores (implementaciones). CQRS separa las operaciones de escritura (Commands) de las operaciones de lectura (Queries), permitiendo optimizar cada lado de forma independiente.
Componentes principales
| Componente | Responsabilidad | Tecnología |
|---|---|---|
| Gestión de Transferencias | Orquesta los flujos de TED OUT, TED IN y P2P | Go, Hexagonal + CQRS |
| Validación y Cumplimiento | Aplica reglas de horario, límites y prevención de duplicados | Redis (operaciones atómicas) |
| Adaptador JD SPB | Comunicación con el sistema de JD Consultores via SOAP/XML | gowsdl, encoding/xml, crypto/rsa |
| Adaptador Midaz Ledger | Operaciones de saldo: validación, aprovisionamiento y liquidación | midaz-sdk-golang/v2 (gRPC/HTTP) |
| Adaptador CRM | Valida cuentas y recupera información del Ledger | HTTP REST client |
| Adaptador de Tarifas | Calcula tarifas de transferencia | HTTP REST client |
| Worker de Polling | Detecta nuevas transferencias de entrada (TED IN) | Goroutine (intervalo de 30s) |
| Publicador de Webhooks | Notifica sistemas externos sobre cambios de estado | HTTP POST con reintentos y DLQ |
Flujo en dos etapas
El plugin implementa un flujo de dos etapas para transferencias de salida, permitiendo que el usuario visualice la tarifa antes de confirmar:
Etapa 1: Iniciar (Initiate)
Endpoint: POST /v1/transfers/initiate Calcula la tarifa y crea una intención de transferencia válida por 24 horas. Qué sucede:- Valida la cuenta de origen en el CRM
- Verifica horario de funcionamiento
- Detecta duplicados (ventana de 60 segundos)
- Calcula tarifa via plugin-fees
- Retorna
initiationIdy valores calculados
Etapa 2: Procesar (Process)
Endpoint: POST /v1/transfers/process Confirma la transferencia e inicia el procesamiento. Qué sucede:- Valida límites de uso (diario/mensual)
- Verifica saldo disponible
- Reserva fondos en Midaz (hold)
- Envía mensaje al SPB (TED OUT) o ejecuta transferencia interna (P2P)
- Retorna
transferIdy número de confirmación
Estados de la transferencia
Cada transferencia pasa por estados bien definidos:
- TED OUT
- TED IN
- P2P
| Estado | Descripción |
|---|---|
CREATED | Transferencia creada, esperando procesamiento |
PENDING | Fondos reservados, esperando envío al SPB |
PROCESSING | Mensaje enviado al SPB, esperando confirmación |
COMPLETED | Transferencia completada |
REJECTED | Rechazada por SPB o destinatario no encontrado |
FAILED | Falla técnica (timeout, indisponibilidad) |
CANCELLED | Cancelada por el usuario antes del procesamiento |
RECEIVED | TED IN detectado, esperando crédito |
Detección de duplicados
El plugin detecta transferencias duplicadas comparando:
- Cuenta de origen
- Datos del destinatario (ISPB, agencia, cuenta)
- Valor
BTF-0012.
Mecanismo:
- Clave de idempotencia:
SHA256(organizationId + senderAccountId + recipient + amount) - Almacenamiento: Redis con TTL configurable
- Acción: Rechazar solicitudes duplicadas con código
409 Conflict
Tarifas
El plugin se integra con plugin-fees para cálculo de tarifas en dos direcciones:
| Operación | Tipo de tarifa |
|---|---|
| TED OUT | Cashout (débito + envío) |
| TED IN | Cashin (recepción) |
| P2P | Configurable por organización |
Comportamiento en caso de indisponibilidad
| Configuración | Comportamiento |
|---|---|
| Fail-open (por defecto) | Continúa sin tarifa si plugin-fees no está disponible |
| Fail-closed | Rechaza la operación si la tarifa no puede ser calculada |
Soporte multi-tenant
El plugin fue diseñado para operar en diferentes modelos de implementación, garantizando aislamiento de datos y configuración por cliente (tenant).
Identificación del tenant
EltenantId es extraído de un claim JWT y validado contra el encabezado HTTP X-Organization-Id. Esta doble validación garantiza que el contexto del tenant sea propagado correctamente por toda la pila de ejecución.
Aislamiento de datos
Todas las consultas a la base de datos son filtradas pororganization_id, garantizando que un tenant nunca acceda a datos de otro. El cache en Redis también utiliza prefijos por tenant (tenant:{tenantId}:{key}), previniendo colisiones y fuga de información.
Modelos de implementación
| Modelo | Descripción | Caso de uso | Overhead |
|---|---|---|---|
| SaaS Multi-Tenant | Múltiples clientes compartiendo la misma infraestructura | Clientes Lerian en ambiente gestionado | ~5-10ms |
| BYOC Single-Tenant | Un único cliente en infraestructura dedicada | Grandes clientes con requisitos específicos | <1ms |
| BYOC Multi-Tenant | Cliente principal gestionando subsidiarias | Clientes que operan como plataforma | ~2-5ms |
Flexibilidad: Un único código base soporta los tres modelos a través de configuración, sin necesidad de branches separados.
Configuración por organización
Cada organización posee configuración independiente:- Credenciales JD SPB (encriptadas)
- ISPB propio
- URL de webhook y secreto HMAC
- Configuraciones de tarifa
- Ventana de detección de duplicados
- Modo de aislamiento de datos (DATABASE, SCHEMA, SINGLE)
Observabilidad
El plugin expone métricas, logs y traces para monitoreo completo.
Métricas (Prometheus)
Logs estructurados
Todos los logs siguen formato JSON con campos contextuales:tenantId: identificación del tenanttransferId: identificación de la transferenciacorrelationId: correlación entre operaciones

