Architectural pattern
The plugin architecture adopts the Hexagonal (Ports and Adapters) pattern combined with CQRS (Command Query Responsibility Segregation) and a Multi-Tenant design. Hexagonal architecture isolates business logic from infrastructure details such as APIs, databases, and external service clients. Communication between the core and the outside world occurs through ports (interfaces) and adapters (implementations). CQRS separates write operations (Commands) from read operations (Queries), allowing each side to be optimized independently.
Main components
| Component | Responsibility | Technology |
|---|---|---|
| Transfer Management | Orchestrates TED OUT, TED IN, and P2P flows | Go, Hexagonal + CQRS |
| Validation and Compliance | Applies schedule rules, limits, and duplicate prevention | Redis (atomic operations) |
| JD SPB Adapter | Communication with JD Consultores system via SOAP/XML | gowsdl, encoding/xml, crypto/rsa |
| Midaz Ledger Adapter | Balance operations: validation, provisioning, and settlement | midaz-sdk-golang/v2 (gRPC/HTTP) |
| CRM Adapter | Validates accounts and retrieves ledger information | HTTP REST client |
| Fees Adapter | Calculates transfer fees | HTTP REST client |
| Polling Worker | Detects new incoming transfers (TED IN) | Goroutine (30s interval) |
| Webhook Publisher | Notifies external systems about status changes | HTTP POST with retries and DLQ |
Two-step flow
The plugin implements a two-step flow for outgoing transfers, allowing the user to view the fee before confirming:
Step 1: Initiate
- Validates the source account in CRM
- Verifies operating hours
- Detects duplicates (60-second window)
- Calculates fee via plugin-fees
- Returns
initiationIdand calculated values
Step 2: Process
- Validates usage limits (daily/monthly)
- Verifies available balance
- Reserves funds in Midaz (hold)
- Sends message to SPB (TED OUT) or executes internal transfer (P2P)
- Returns
transferIdand confirmation number
Transfer states
Each transfer goes through well-defined states:
- TED OUT
- TED IN
- P2P
| State | Description |
|---|---|
CREATED | Transfer created, awaiting processing |
PENDING | Funds reserved, awaiting SPB submission |
PROCESSING | Message sent to SPB, awaiting confirmation |
COMPLETED | Transfer completed |
REJECTED | Rejected by SPB or recipient not found |
FAILED | Technical failure (timeout, unavailability) |
CANCELLED | Cancelled by user before processing |
RECEIVED | TED IN detected, awaiting credit |
Duplicate detection
The plugin detects duplicate transfers by comparing:
- Source account
- Recipient data (ISPB, branch, account)
- Amount
BTF-0012.
Mechanism:
- Idempotency key:
SHA256(organizationId + senderAccountId + recipient + amount) - Storage: Redis with configurable TTL
- Action: Reject duplicate requests with code
409 Conflict
Fees
The plugin integrates with plugin-fees for fee calculation in two directions:
| Operation | Fee type |
|---|---|
| TED OUT | Cashout (debit + send) |
| TED IN | Cashin (receive) |
| P2P | Configurable per organization |
Behavior in case of unavailability
| Configuration | Behavior |
|---|---|
| Fail-open (default) | Continues without fee if plugin-fees unavailable |
| Fail-closed | Rejects operation if fee cannot be calculated |
Multi-tenant support
The plugin was designed to operate in different deployment models, ensuring data isolation and configuration per client (tenant).
Tenant identification
ThetenantId is extracted from a JWT claim and validated against the HTTP header X-Organization-Id. This dual validation ensures the tenant context is correctly propagated throughout the execution stack.
Data isolation
All database queries are filtered byorganization_id, ensuring a tenant never accesses another’s data. Redis cache also uses per-tenant prefixes (tenant:{tenantId}:{key}), preventing collisions and information leakage.
Deployment models
| Model | Description | Use case | Overhead |
|---|---|---|---|
| SaaS Multi-Tenant | Multiple clients sharing the same infrastructure | Lerian clients in managed environment | ~5-10ms |
| BYOC Single-Tenant | Single client in dedicated infrastructure | Large clients with specific requirements | <1ms |
| BYOC Multi-Tenant | Main client managing subsidiaries | Clients operating as a platform | ~2-5ms |
Flexibility: A single codebase supports all three models through configuration, without the need for separate branches.
Per-organization configuration
Each organization has independent configuration:- JD SPB credentials (encrypted)
- Own ISPB
- Webhook URL and HMAC secret
- Fee settings
- Duplicate detection window
- Data isolation mode (DATABASE, SCHEMA, SINGLE)
Observability
The plugin exposes metrics, logs, and traces for complete monitoring.
Metrics (Prometheus)
Structured logs
All logs follow JSON format with contextual fields:tenantId: tenant identificationtransferId: transfer identificationcorrelationId: correlation between operations

