Préstamos de Renta Particular
Diagnóstico del problema (AS-IS) y propuesta de arquitectura (TO-BE)
1. El problema
El cliente solicita un desembolso desde la Zona Segura. La solicitud viaja de forma síncrona a través del backend Node hasta admwr-api, un sistema legado (.NET Forms) dentro de la red privada IS-VCE, detrás del proxy de INARI.
Síntoma observado
- El proxy de INARI responde
502 Bad Gatewaycuando detecta lentitud o timeout. - admwr-api sigue procesando en segundo plano y muchas veces termina ejecutando el desembolso con éxito, aunque el cliente ya recibió un error.
- El cliente, al ver el error, reintenta manualmente → se genera un segundo desembolso para el mismo préstamo.
flowchart TB
Cliente["Cliente de Renta Particular"]
Proxy["Proxy"]
FE["zona-segura-frontend
(Cloud Run)"]
BE["zona-segura-backend
(Node, Cloud Run)"]
PortalDB[("portal-db
Compute Engine")]
INARI_PROXY["Proxy INARI
(VMWARE INARI)"]
ADMWR_API["admwr-api
.NET Forms"]
ADMWR_DB[("admwr
SQL Server")]
ULTIMUS["ultimus-api"]
SFTP["SFTP
tramas ASBANC"]
Bancos["Bancos
BBVA / BCP / IBK / Scotia"]
Cliente -->|"1 . Solicita prestamo"| Proxy
Proxy --> FE
FE -->|"2 . Registrar prestamo sincrono"| BE
BE -->|"3 . Guardar evento / cronograma"| PortalDB
BE -->|"4 . Enviar cronograma, espera respuesta"| INARI_PROXY
INARI_PROXY -->|"5 . Forward"| ADMWR_API
ADMWR_API --> ADMWR_DB
ADMWR_API --> ULTIMUS
ULTIMUS --> SFTP
SFTP --> Bancos
ADMWR_API -. "6 . sigue ejecutando aunque haya timeout" .-> ADMWR_DB
INARI_PROXY -. "X 502 Bad Gateway timeout" .-> BE
BE -. "X cliente ve error" .-> FE
FE -. "X reintento manual = nuevo desembolso" .-> BE
classDef fail stroke:#c0392b,stroke-width:2px,stroke-dasharray: 4 3,color:#c0392b;
class ADMWR_API,INARI_PROXY fail;
Causa raíz
El 502 es el síntoma, no la causa. El problema real combina tres cosas:
| # | Causa | Efecto |
|---|---|---|
| 1 | El timeout del proxy no está alineado con la duración real del proceso en admwr |
El proxy corta la conexión, pero el backend no se entera y sigue ejecutando (fire-and-forget accidental) |
| 2 | No existe idempotencia en la solicitud de desembolso | No hay forma de reconocer "esta ya es la segunda vez que me piden lo mismo" |
| 3 | El cliente usa un error de transporte como señal de negocio | Reintenta manualmente sin control de concurrencia → desembolso duplicado |
2. La solución
La idea central: el cliente nunca espera a INARI. Se introduce una capa de orquestación asíncrona con idempotencia y control de concurrencia entre la Zona Segura y el sistema legado.
Qué resuelve cada pieza nueva
- 202 inmediato + polling/estado: rompe el acoplamiento síncrono cliente-INARI.
- Idempotency-Key: un reintento del cliente no genera una segunda operación real.
- Lock por póliza: impide que dos mensajes para la misma póliza se procesen en paralelo.
- Cola con reintentos controlados: solo reintenta si la operación sigue pendiente, nunca a ciegas.
- Job de reconciliación: detecta operaciones "huérfanas" (admwr ejecutó, pero la confirmación no volvió) sin que el cliente lo note.
flowchart TB
Cliente["Cliente de Renta Particular"]
subgraph ZS["Zona Segura (Interseguro Zona Privada)"]
FE["zona-segura-frontend
(Cloud Run)"]
BE["zona-segura-backend
(Node, Cloud Run)"]
PDB[("portal-db
solicitudes + estado")]
end
subgraph NEW["GCP-MVP - Capa nueva de orquestacion"]
Q["Cola
Pub/Sub o Cloud Tasks"]
WRK["Worker orquestador
idempotencia + estado"]
LOCK[("Lock por poliza
Memorystore/Redis")]
RECON["Job de reconciliacion
detecta huerfanas"]
end
subgraph VCE["IS-VCE (red privada, legado)"]
ADMWR_API["admwr-api
.NET Forms (INARI)"]
ADMWR_DB[("admwr
SQL Server")]
ULTIMUS["ultimus-api"]
SFTP["SFTP tramas ASBANC"]
end
Bancos["Bancos
BBVA / BCP / IBK / Scotia"]
Cliente -->|"1 . Solicita prestamo"| FE
FE -->|"2 . POST + Idempotency-Key"| BE
BE -->|"3 . Persiste PENDIENTE"| PDB
BE -->|"4 . 202 Accepted + trackingId"| FE
FE -->|"5 . Polling / WS estado"| BE
BE -->|"6 . Encola mensaje"| Q
Q --> WRK
WRK -->|"7 . Adquiere lock por poliza"| LOCK
WRK -->|"8 . Verifica estado previo"| PDB
WRK -->|"9 . Invoca desembolso si no hay duplicado"| ADMWR_API
ADMWR_API --> ADMWR_DB
ADMWR_API --> ULTIMUS
ULTIMUS --> SFTP
SFTP --> Bancos
ADMWR_API -->|"10 . Resultado"| WRK
WRK -->|"11 . Actualiza estado final"| PDB
WRK -->|"12 . Libera lock"| LOCK
RECON -. "revisa PENDIENTE mayor a umbral" .-> PDB
RECON -. "consulta estado real" .-> ADMWR_API
classDef newc stroke:#2e7d32,stroke-width:2px,color:#2e7d32;
class Q,WRK,LOCK,RECON newc;
3. Cómo se mapea contra los criterios del reto
| Criterio | Cómo lo cubre el diseño |
|---|---|
| Escalabilidad | Cola + worker stateless en Cloud Run, escalan independiente del legado |
| Resiliencia y reintentos | Reintentos con backoff solo mientras la operación siga pendiente, nunca a ciegas |
| Control de concurrencia | Idempotency-Key + lock por póliza + estado persistido antes de invocar admwr |
| Seguridad | Mismo perímetro ya existente (Zona Segura, red privada IS-VCE) + JWT/mTLS en componentes nuevos |
| Costo | Servicios managed de bajo costo (Pub/Sub o Cloud Tasks, Memorystore) sobre infraestructura GCP ya existente |