Arquitectura Funcional de Lana Bank
Tabla de Contenidos
- Descripción General
- Arquitectura de la Aplicación
- Flujos de Comunicación
- Integraciones con Sistemas Externos
- Flujos de Autenticación y Seguridad
- Segmentación de Red por Ambiente
- Zonas de Seguridad
- Auditoría
- Flujo de Préstamo Respaldado por Bitcoin
- Portabilidad y Dependencia de Proveedores
- Servidores / Instancias
- Sistemas Operativos
- Bases de Datos
- Middleware / Integración
- Servicios Externos
1. Descripción General
Este documento describe la arquitectura lógica de Lana Bank, incluyendo la arquitectura interna de la aplicación, integraciones con sistemas externos, flujos de autenticación y seguridad, segmentación de red por ambiente y zonas de seguridad.
1.1 Visión General
Lana Bank es una aplicación de core bancario especializada en préstamos respaldados por Bitcoin. La arquitectura sigue los principios de Domain-Driven Design (DDD) y Arquitectura Hexagonal, separando claramente las capas de dominio, aplicación e infraestructura.
El backend está desarrollado en Rust, usando PostgreSQL como base de datos principal y Cala Ledger como motor de contabilidad de partida doble con fuertes garantías de consistencia. Los frontends web están construidos con Next.js y TypeScript, consumiendo APIs GraphQL expuestas por el backend. Para reportes y analítica, existe un pipeline de datos basado en Meltano que extrae información a BigQuery, donde los datos se transforman con dbt.
2. Arquitectura de la Aplicación
2.1 Módulos del Core Bancario
Los módulos del core implementan la lógica de negocio del banco, siguiendo principios de Event Sourcing donde cada entidad mantiene su estado como una secuencia de eventos inmutables.
2.1.1 Crédito
El módulo de crédito es el corazón del sistema, gestionando el ciclo de vida completo de préstamos respaldados por Bitcoin. Una facilidad de crédito pasa por un ciclo de vida bien definido que comienza cuando un operador crea una CreditFacilityProposal para un cliente. Esta propuesta entra automáticamente en un proceso de aprobación gestionado por el módulo de gobernanza; los miembros del comité asignado deben votar para aprobarla.
Una vez aprobada, la propuesta se transforma en una PendingCreditFacility. En esta etapa, el cliente debe depositar el colateral Bitcoin requerido. Si la facilidad tiene un custodio asignado, los webhooks del custodio mantienen automáticamente el balance del colateral sincronizado. Si no hay custodio (modo manual), un operador puede actualizar el colateral directamente. El sistema monitorea continuamente la relación de colateralización (CVL - Collateral Value to Loan) comparándola con el precio actual de Bitcoin.
La facilidad se activa automáticamente cuando el CVL alcanza el umbral inicial configurado en los términos. TermValues definen todos los parámetros del préstamo: la tasa de interés anual, duración (clasificada como corto o largo plazo dependiendo de si excede 12 meses), intervalos de acumulación de interés (diario o mensual), la comisión inicial (cargo único), y tres umbrales críticos de CVL que deben mantener una jerarquía estricta: el CVL inicial debe ser mayor que el CVL de margin call, que a su vez debe ser mayor que el CVL de liquidación. También se configura la política de desembolso, que puede ser única o múltiple.
Con la CreditFacility activa, el cliente puede solicitar Disbursals. Cada desembolso pasa por su propio proceso de aprobación. Cuando se ejecuta, los fondos se acreditan a la cuenta de depósito del cliente y se crea una Obligation representando la deuda. Las obligaciones tienen un ciclo de estados: comienzan como "no vencidas", pasan a "vencidas" en la fecha de vencimiento, pueden convertirse en "morosas" si no se pagan a tiempo, entran en "liquidación" si la morosidad persiste, y finalmente ser marcadas como "incumplidas".
El sistema ejecuta jobs periódicos para la acumulación de intereses. Los InterestAccrualCycles calculan intereses según los intervalos configurados y generan nuevas obligaciones por intereses acumulados. Cuando el cliente realiza un Payment, el sistema automáticamente asigna fondos a las obligaciones pendientes en orden de prioridad a través de PaymentAllocation, típicamente priorizando las obligaciones más antiguas e intereses sobre el principal.
Si el CVL cae por debajo del umbral de margin call, la facilidad entra en estado de alerta. Si cae por debajo del umbral de liquidación, se inicia un LiquidationProcess donde el banco puede ejecutar el colateral para recuperar la deuda. El sistema implementa un buffer de histéresis para evitar oscilaciones frecuentes entre estados cuando el CVL está cerca de los umbrales.
2.1.2 Depósito
El módulo de depósitos gestiona las cuentas donde los clientes mantienen sus fondos en USD. Cuando se crea una DepositAccount para un cliente, el sistema genera automáticamente las cuentas contables correspondientes en el libro mayor. La categorización contable depende del tipo de cliente: las cuentas para individuos, entidades gubernamentales, empresas privadas, bancos, instituciones financieras y empresas no domiciliadas se agrupan bajo diferentes nodos del plan de cuentas.
Los Deposits representan entradas de fondos a la cuenta y se registran inmediatamente. Los Withdrawals siguen un flujo más controlado: cuando se inician, los fondos se reservan en contabilidad y se crea un proceso de aprobación. El comité asignado debe aprobar el retiro antes de que se ejecute. Si se aprueba, los fondos salen de la cuenta; si se rechaza o cancela, la reserva se revierte. También existe la posibilidad de revertir depósitos ya registrados cuando sea necesario.
Las cuentas pueden estar en diferentes estados que afectan las operaciones permitidas. Una cuenta activa permite todas las operaciones normales. Una cuenta congelada previene nuevas operaciones pero mantiene el balance visible; esto es útil para situaciones de cumplimiento donde los fondos necesitan ser bloqueados temporalmente. Una cuenta cerrada es permanente y solo se permite si el balance es cero. El módulo también soporta la actualización masiva del estado de todas las cuentas de un cliente, por ejemplo cuando cambia su verificación KYC.
El historial de la cuenta puede consultarse a través del libro mayor, mostrando todas las transacciones que han afectado el balance. El módulo calcula el balance disponible considerando los retiros pendientes de aprobación.
2.1.3 Cliente
Este módulo gestiona la información de los clientes del banco y es fundamental para el cumplimiento regulatorio. Cada cliente se crea con un tipo específico que determina su tratamiento contable y regulatorio: Individual para personas naturales, GovernmentEntity para entidades gubernamentales, PrivateCompany para empresas privadas, Bank para bancos, FinancialInstitution para otras instituciones financieras, ForeignAgencyOrSubsidiary para agencias extranjeras, y NonDomiciledCompany para empresas no domiciliadas.
El proceso de verificación KYC se integra con SumSub. Un cliente comienza en estado PendingVerification. Cuando SumSub notifica vía webhook que la verificación fue exitosa, el cliente pasa a Verified con un nivel KYC (Básico o Avanzado). Si la verificación falla, permanece en estado Rejected. El sistema puede configurarse para requerir verificación antes de permitir la creación de cuentas de depósito o facilidades de crédito.
El módulo gestiona documentos asociados al cliente, almacenándolos en la nube y permitiendo la generación de enlaces de descarga temporales. Los documentos pueden archivarse o eliminarse según sea necesario.
Para el cumplimiento de regulaciones de cuentas inactivas, el sistema rastrea la última actividad de cada cliente. Un job periódico clasifica automáticamente a los clientes según su actividad: Active si han tenido actividad reciente (menos de un año), Inactive si han estado entre uno y diez años sin actividad, y Suspended si exceden diez años. Esta clasificación puede afectar el estado de sus cuentas de depósito.
2.1.4 Custodia
El módulo de custodia proporciona una abstracción sobre múltiples proveedores de custodia de Bitcoin, permitiendo al banco trabajar con diferentes custodios según sus necesidades operativas y regulatorias. El sistema está diseñado con un patrón de plugins donde cada Custodian implementa una interfaz común. Actualmente están implementados BitGo y Komainu, pero la arquitectura permite agregar nuevos custodios sin modificar el resto del sistema.
En cada despliegue, múltiples custodios pueden configurarse y activarse simultáneamente. Cuando se crea una facilidad de crédito, se puede especificar qué custodio gestionará el colateral de esa facilidad particular. Esto permite, por ejemplo, usar diferentes custodios para diferentes segmentos de clientes o jurisdicciones.
Cada custodio gestiona Wallets que se asignan a facilidades de crédito para recibir colateral Bitcoin. Los custodios notifican al sistema sobre cambios en los balances de las billeteras a través de webhooks. Cuando llega una notificación, el sistema actualiza el Collateral asociado a la facilidad correspondiente y recalcula el CVL. Esta sincronización automática es crítica para mantener una visión precisa del riesgo en tiempo real.
Los webhooks de custodios se reciben en endpoints específicos por proveedor y se validan criptográficamente antes de procesarlos. La configuración de cada custodio incluye las credenciales API necesarias y claves para verificar la autenticidad del webhook. Las claves sensibles se almacenan cifradas.
2.1.5 Contabilidad
El módulo de contabilidad implementa un sistema completo de contabilidad de partida doble, fundamental para cualquier institución financiera regulada. Utiliza Cala Ledger como motor subyacente, un crate de Rust especializado que proporciona plantillas de transacciones predefinidas y garantías de consistencia ACID para todas las operaciones contables.
El ChartOfAccounts define la estructura jerárquica de cuentas del banco. Puede importarse desde archivos CSV y soporta una estructura de árbol con múltiples niveles. Cada nodo del árbol puede ser una cuenta individual o un grupo que agrega las cuentas de sus hijos. El plan de cuentas se integra con otros módulos: las cuentas de depósito de clientes, facilidades de crédito y cuentas de colateral se crean automáticamente como hijos de nodos apropiados según el tipo de cliente y producto.
Cada LedgerAccount tiene un tipo de balance normal (débito o crédito) y puede mantener balances en múltiples monedas (USD y BTC). Las LedgerTransactions representan movimientos contables que siempre mantienen balance: el total de débitos es igual al total de créditos. El sistema registra automáticamente transacciones para cada operación de negocio: depósitos, retiros, desembolsos, pagos de préstamos, acumulación de intereses y actualizaciones de colateral.
Para reportes financieros, el módulo genera el TrialBalance que lista todas las cuentas con sus balances de débito y crédito, útil para verificar que los libros cuadran. El BalanceSheet presenta la posición financiera del banco organizando activos, pasivos y patrimonio. El ProfitAndLoss muestra ingresos (principalmente intereses de préstamos) menos gastos para calcular el resultado del período.
El sistema soporta múltiples FiscalYears y permite consultar balances y reportes para rangos de fechas específicos. También permite ManualTransactions para ajustes contables que no se originan de operaciones automatizadas del sistema.
2.1.6 Gobernanza
El sistema de gobernanza proporciona un framework flexible para implementar flujos de aprobación multifirma en operaciones sensibles. Está diseñado para adaptarse a diferentes estructuras organizacionales y requisitos regulatorios.
Los Committees representan grupos de personas autorizadas para tomar decisiones sobre ciertos tipos de operaciones. Un comité puede tener cualquier número de miembros, típicamente usuarios del sistema con roles específicos. El mismo usuario puede pertenecer a múltiples comités.
Las Policies definen las reglas de aprobación para cada tipo de proceso. Una política especifica qué comité es responsable de aprobar ese tipo de operación y cuál es el umbral requerido: el número mínimo de votos afirmativos necesarios para aprobar. Por ejemplo, una política para aprobación de desembolsos podría requerir 2 de 3 miembros del comité de crédito.
Cuando se inicia una operación que requiere aprobación, el sistema crea automáticamente un ApprovalProcess vinculado a la política correspondiente. El proceso comienza en estado pendiente y registra los votos de los miembros del comité. Un miembro puede votar para aprobar o para denegar (con una razón obligatoria). Cuando se alcanza el umbral de aprobación, el proceso se marca como aprobado y se emite un evento ApprovalProcessConcluded. Si algún miembro deniega, el proceso termina inmediatamente como rechazado.
Los eventos de conclusión del proceso de aprobación son consumidos por jobs que ejecutan la operación aprobada o manejan el rechazo. Este diseño desacopla el flujo de aprobación de la ejecución, permitiendo que las aprobaciones se procesen de forma asíncrona.
2.1.7 Acceso
El módulo de acceso implementa control de acceso basado en roles (RBAC) para todos los operadores del sistema. Los Users representan a las personas que operan el banco a través del Panel de Administración. Cada usuario tiene un identificador único que se vincula con el sistema de autenticación externo.
Los Roles agrupan conjuntos de permisos y se asignan a usuarios. Un usuario puede tener múltiples roles, y sus permisos efectivos son la unión de permisos de todos sus roles. Los PermissionSets son colecciones nombradas de permisos específicos que facilitan la configuración de roles comunes.
El sistema de permisos es granular: cada operación en cada módulo tiene un permiso asociado. Por ejemplo, hay permisos separados para leer clientes, crear clientes, aprobar KYC, ver facilidades de crédito, iniciar desembolsos, etc. Antes de ejecutar cualquier operación, el sistema verifica que el usuario tenga el permiso correspondiente y registra la acción en el log de auditoría.
El sistema de autorización utiliza Casbin, un motor de control de acceso flexible, con políticas almacenadas en PostgreSQL para persistencia y sincronización entre instancias. El modelo RBAC sigue una estructura de tres niveles: Usuario → Rol → PermissionSet → Permisos (Objeto + Acción).
Cada módulo define sus propios conjuntos de permisos que agrupan acciones relacionadas. Los conjuntos de permisos típicos siguen un patrón viewer/writer. El sistema incluye roles predefinidos como Admin (acceso completo), Bank Manager (similar a admin pero sin acceso a gestión de acceso o custodia), y Accountant (enfocado en funciones de contabilidad y visualización).
Los permisos se gestionan dinámicamente a través de la API y los cambios persisten inmediatamente en la base de datos, recargándose en cada verificación de permisos, asegurando que las actualizaciones sean efectivas sin reiniciar el sistema.
2.1.8 Precio
Este módulo obtiene y gestiona precios de Bitcoin, una función crítica para un banco que ofrece préstamos colateralizados con BTC. El sistema se integra con Bitfinex para obtener precios en tiempo real a través de su API.
Cuando se obtiene un nuevo precio, el módulo publica un CorePriceEvent que otros módulos consumen. El módulo de crédito es el principal consumidor: usa el precio para calcular el CVL de todas las facilidades activas y determinar si alguna ha caído por debajo de los umbrales de margin call o liquidación. Los cambios de precio pueden disparar actualizaciones de estado en facilidades y potencialmente iniciar procesos de liquidación.
2.1.9 Reportes
El módulo de reportes coordina la generación de reportes regulatorios y operativos. Define tipos de Report que especifican qué datos incluir y en qué formato. Cada ejecución de reporte se registra como un ReportRun con su estado (pendiente, ejecutando, completado, fallido) y archivos generados.
La generación de reportes se integra con el pipeline de datos: los datos transformados en BigQuery alimentan los reportes finales. El sistema puede integrarse con sistemas de reportes externos según las necesidades regulatorias de cada jurisdicción donde opera el banco.
2.1.10 Módulos de Soporte
Además de los módulos principales, hay módulos de soporte: document-storage para almacenamiento de documentos en la nube, public-id para generar identificadores públicos legibles para entidades, y core-money que define primitivas monetarias (UsdCents, Satoshis) usadas en todo el sistema.
2.2 Capa de Aplicación
El directorio lana/ contiene la capa de aplicación que orquesta los módulos del core y expone funcionalidad externamente.
2.2.1 Servidores GraphQL
El sistema expone dos servidores GraphQL independientes. El admin-server sirve al panel de administración usado por operadores del banco, mientras que el customer-server sirve al portal de clientes. Ambos servidores incluyen playground integrado para desarrollo y reciben webhooks de servicios externos.
2.2.2 Servicios de Aplicación
El servicio principal lana-app orquesta la inicialización de todos los módulos y proporciona el punto de entrada unificado. lana-cli ofrece una interfaz de línea de comandos para operaciones administrativas.
Existen servicios especializados para diferentes funciones: notification maneja el envío de emails, contract-creation genera contratos PDF, customer-sync y deposit-sync sincronizan datos con sistemas externos, user-onboarding gestiona el registro de operadores, y dashboard calcula métricas agregadas. Para desarrollo y pruebas, sim-bootstrap permite inicializar datos de simulación.
2.2.3 Sistema de Eventos
El módulo lana-events define el enum unificado LanaEvent que agrupa todos los eventos de dominio del sistema, permitiendo que el sistema de outbox y los jobs procesen eventos de cualquier módulo de forma uniforme.
2.3 Frontends Web
2.3.1 Panel de Administración
El Panel de Administración es la interfaz principal para operadores y personal del banco. Permite gestionar clientes y sus procesos KYC, administrar facilidades de crédito en todas sus etapas, aprobar desembolsos y retiros, y gestionar cuentas de depósito. También proporciona acceso a visualización contable completa (balance, estado de resultados, balance de comprobación), configuración de comités y políticas de aprobación, gestión de usuarios y roles, y generación de reportes regulatorios.
2.3.2 Portal de Clientes
El Portal de Clientes está orientado a los clientes del banco. Actualmente ofrece funcionalidad de solo lectura, permitiendo visualización de facilidades de crédito, estado de desembolsos e historial de transacciones. La arquitectura permite extenderlo en el futuro para soportar operaciones del lado del cliente.
2.3.3 Shared Web
El módulo shared-web contiene componentes de UI compartidos entre ambos portales, asegurando consistencia visual y reduciendo duplicación de código.
3. Flujos de Comunicación
3.1 Event Sourcing y Eventos de Dominio
El sistema usa Event Sourcing como patrón arquitectónico central. Cada entidad recibe comandos que generan eventos, estos eventos se persisten en la base de datos como la única fuente de verdad, y el estado actual de la entidad se reconstruye aplicando la secuencia de eventos.
Este diseño proporciona auditabilidad completa (cada cambio se registra), la capacidad de reconstruir el estado en cualquier punto en el tiempo, y la posibilidad de agregar nuevas proyecciones sobre datos históricos.
La comunicación entre módulos ocurre a través de eventos públicos. Cada módulo define sus propios eventos en un enum específico (por ejemplo, CoreCreditEvent para el módulo de crédito). Un Publisher asociado a cada módulo transforma eventos internos de entidad en eventos públicos que otros módulos pueden consumir.
Los eventos públicos típicos incluyen: creación y aprobación de propuestas de crédito, activación y finalización de facilidades, cambios de colateralización, desembolsos liquidados, acumulación de intereses, creación y transición de obligaciones entre estados (vencida, morosa, incumplida), pagos registrados, y procesos de liquidación. Cada evento incluye timestamps de cuándo se registró y cuándo fue efectivo, permitiendo reconstrucciones precisas del estado en cualquier momento.
3.2 Patrón Outbox
Para integraciones con sistemas externos que requieren garantías de entrega, el sistema implementa el Patrón Outbox. Cuando un módulo necesita publicar un evento, lo persiste en una tabla outbox dentro de la misma transacción de base de datos que la operación de negocio. Esto garantiza atomicidad: o ambos (la operación y el evento) persisten, o ninguno.
PostgreSQL NOTIFY informa inmediatamente a los listeners cuando hay nuevos eventos, evitando la necesidad de polling.
El sistema soporta dos tipos de eventos en el outbox. Los eventos persistentes tienen un identificador único, un número de secuencia global monotónicamente creciente, el payload serializado como JSON, contexto de tracing para correlación distribuida, y timestamp de cuándo se registró. Los eventos efímeros no tienen secuencia y se usan para notificaciones en tiempo real que no necesitan durabilidad.
Este diseño garantiza entrega al menos una vez: un sistema externo puede consumir eventos con certeza de que no perderá ninguno, aunque podría recibir duplicados que debe manejar de forma idempotente.
3.3 Sistema de Jobs Asíncronos
Las operaciones que no deben bloquear el flujo principal se ejecutan a través de un sistema de jobs asíncronos. Los workers corren como procesos separados del servidor principal, permitiendo escalar el procesamiento independientemente de los servidores API.
Los jobs pueden programarse de varias formas: ejecutar inmediatamente, programar para una fecha/hora futura específica, o reprogramar al completar para ejecutar de nuevo. Esta flexibilidad es esencial para los flujos temporales del sistema bancario. Por ejemplo, cuando se crea una obligación, se programa un job para la fecha de vencimiento. Cuando ese job se ejecuta, si la obligación no está pagada, la marca como "vencida" y programa el siguiente job para la fecha de morosidad. La cadena continúa: vencida → morosa → liquidación → incumplida, cada transición programada precisamente según los términos de la facilidad.
Para la acumulación de intereses, un job procesa cada acumulación diaria y automáticamente se reprograma para el día siguiente. Cuando termina un período de acumulación (típicamente a fin de mes), programa un job de ciclo de acumulación que consolida intereses y crea la obligación correspondiente.
Otros jobs procesan streams de eventos del outbox continuamente, manteniendo su estado de ejecución (el último evento procesado) y reprogramándose inmediatamente cuando no hay nuevos eventos para continuar escuchando.
3.4 Webhooks Entrantes
Los servicios externos notifican al sistema a través de webhooks. SumSub envía notificaciones sobre el ciclo de vida de verificación KYC a /webhook/sumsub. Cuando un cliente completa su verificación, SumSub notifica el resultado (aprobado o rechazado). El sistema procesa esta notificación y actualiza el estado KYC del cliente, lo que puede desbloquear la creación de cuentas de depósito o facilidades de crédito según la configuración.
Los custodios de Bitcoin (BitGo, Komainu) notifican eventos de billetera a /webhook/custodian/[provider]. Cada proveedor tiene su propio formato de webhook que el sistema normaliza. Los eventos típicos incluyen depósitos de Bitcoin a billeteras de colateral. Cuando llega una notificación, el sistema verifica su autenticidad (típicamente vía HMAC), identifica la billetera afectada, actualiza el balance de colateral correspondiente, y recalcula el CVL de la facilidad de crédito asociada. Si el nuevo CVL cruza algún umbral configurado, se actualiza el estado de colateralización y se publican los eventos correspondientes.
Este flujo de webhooks es crítico para la gestión de riesgo en tiempo real. Sin él, el sistema dependería de polling periódico y podría tener visibilidad retrasada de cambios en el colateral, aumentando el riesgo durante caídas del precio de Bitcoin.
3.5 Flujo de API GraphQL
Las solicitudes de clientes web siguen este flujo: el cliente envía una solicitud GraphQL con un token JWT. El middleware extrae el subject del token y lo inyecta en el contexto. El resolver invoca el caso de uso correspondiente en lana-app, que primero verifica permisos RBAC y luego ejecuta la operación en el módulo core apropiado. Los eventos generados se publican, y la respuesta retorna al cliente.
4. Integraciones con Sistemas Externos
La aplicación está diseñada para integrarse con varios servicios externos que proporcionan funcionalidades especializadas. Estos servicios no son parte de la infraestructura desplegada pero son componentes críticos del ecosistema operativo.
Es importante enfatizar que estos servicios deben configurarse externamente por el cliente o equipo de operaciones. La aplicación simplemente espera recibir las credenciales, tokens, endpoints y otra información de configuración necesaria para integrarse con estos servicios. La aplicación no gestiona la creación, configuración o administración de cuentas en estos servicios externos; solo consume sus APIs y servicios una vez que están configurados y disponibles.
4.1 KYC/KYB y AML (Conozca a su Cliente / Conozca su Negocio / Anti-Lavado de Dinero)
4.1.1 Sumsub
Sumsub se usa para gestionar procesos y datos de KYC (Know Your Customer) y KYB (Know Your Business). Este servicio externo maneja la verificación de identidad de clientes y empresas, incluyendo:
- Validación de documentos de identidad
- Verificación biométrica
- Verificación de documentos corporativos
- Cumplimiento regulatorio
- Onboarding de clientes y empresas
- Verificación continua
Sumsub también satisface necesidades de AML (Anti-Money Laundering) además de proporcionar capacidades KYC/KYB. Sumsub incluye funcionalidades de detección y prevención de lavado de dinero, tales como:
- Verificación de listas de sanciones (OFAC, UN, etc.)
- Análisis de transacciones sospechosas
- Monitoreo de patrones de comportamiento
- Reportes regulatorios automáticos
- Integración con sistemas de cumplimiento
La aplicación se integra con Sumsub a través de su API REST. Para configurar la integración, es necesario configurar una cuenta en el servicio Sumsub, obtener credenciales API (API key, API secret), configurar los endpoints correspondientes (pueden variar por región), y proporcionar estas credenciales y endpoints como parte de la configuración del ambiente.
El flujo de integración funciona así: la aplicación envía solicitudes de verificación a Sumsub a través de su API. Sumsub procesa las solicitudes y realiza las verificaciones necesarias. Los resultados de los procesos de onboarding y verificación continua se reciben vía webhooks en el endpoint /webhook/sumsub. Cuando un cliente completa su verificación, SumSub notifica el resultado (aprobado o rechazado), y el sistema procesa esta notificación actualizando el estado KYC del cliente, lo que puede desbloquear la creación de cuentas de depósito o facilidades de crédito según la configuración.
La arquitectura también está preparada para integrar sistemas AML adicionales si es necesario. Las integraciones AML típicamente incluyen las funcionalidades mencionadas arriba. La aplicación puede integrarse con proveedores de servicios AML a través de APIs REST o a través de integración con sistemas de terceros. La configuración seguiría el mismo patrón que otras integraciones externas: las credenciales y endpoints se proporcionan como parte de la configuración del ambiente.
4.2 Pasarelas de Pago
Nota importante: Las integraciones con pasarelas de pago no están implementadas en la versión actual de Lana. Sin embargo, debido a que Lana es modular en diseño, la arquitectura anticipa que estos elementos eventualmente se agregarán según las necesidades del negocio.
La aplicación está dise ñada para integrarse con pasarelas de pago externas para procesar transacciones financieras. Aunque las pasarelas específicas pueden variar por cliente y región, la arquitectura soporta integración con múltiples proveedores.
La aplicación está diseñada para soportar varios tipos de integración:
- Procesamiento de pagos con tarjeta (débito/crédito)
- Transferencias bancarias (ACH, wire transfers, etc.)
- Procesamiento de pagos móviles
- Integración con sistemas de compensación y liquidación
Las pasarelas de pago se integrarían vía APIs REST o SOAP. Las credenciales API, endpoints y configuraciones específicas se proporcionarían como parte de la configuración del ambiente. La aplicación está diseñada para soportar múltiples pasarelas simultáneamente, permitiendo enrutamiento de transacciones según reglas de negocio.
Todas las comunicaciones con pasarelas de pago usarían TLS/SSL para cifrado en tránsito. Las credenciales sensibles se almacenarían como secrets en Kubernetes e inyectarían en contenedores de aplicación vía variables de ambiente o volúmenes montados.
4.3 BCR (Banco Central de Reserva)
Nota importante: La integración con el Banco Central de Reserva (BCR) no está implementada en la versión actual de Lana. Sin embargo, debido a que Lana es modular en diseño, la arquitectura anticipa que esta integración eventualmente se agregará según las necesidades del negocio.
La aplicación está diseñada para incluir soporte para operaciones con el Banco Central de Reserva (BCR), que es el banco central de El Salvador. Esta integración sería crítica para operaciones bancarias regulatorias.
El sistema está diseñado para soportar varios tipos de operaciones con el BCR:
- Depósitos en el BCR (moneda local y extranjera)
- Operaciones repo con el BCR
- Operaciones de financiamiento con el BCR
- Reportes regulatorios y cumplimiento
- Operaciones de liquidez
La integración con el BCR se haría a través de sistemas de comunicación bancaria estándar (típicamente SWIFT, sistemas de mensajería financiera, o APIs específicas del BCR). La configuración incluiría credenciales de acceso a sistemas del BCR, endpoints de comunicación, certificados digitales para autenticación, y configuración de formato de mensajes (ISO 20022, formatos propietarios, etc.).
Las operaciones del BCR se procesarían a través de workers dedicados que manejarían comunicación asíncrona y procesamiento de respuestas. Los datos de operaciones se registrarían en la base de datos principal e integrarían con el sistema contable.
4.4 Fuentes de Datos Regulatorios
Nota importante: Las integraciones con fuentes de datos regulatorios no están implementadas en la versión actual de Lana. Sin embargo, debido a que Lana es modular en diseño, la arquitectura anticipa que estos elementos eventualmente se agregarán según las necesidades del negocio.
La aplicación está diseñada para integrarse con múltiples fuentes de datos regulatorios para cumplimiento y reportes. Estas incluirían:
- Sistemas de reportes del banco central
- Sistemas de información crediticia
- Registros públicos (registro de empresas, registro de propiedad, etc.)
- Sistemas gubernamentales de verificación de identidad
- Sistemas de intercambio de información financiera
Las integraciones con fuentes de datos regulatorios se harían a través de:
- APIs REST o SOAP proporcionadas por organismos regulatorios
- Sistemas de mensajería financiera (SWIFT, sistemas propietarios)
- Archivos batch para intercambio de datos
- Portales web con autenticación y scraping automatizado (cuando sea necesario)
Los workers de la aplicación procesarían integraciones con sistemas regulatorios de forma asíncrona. Los datos recibidos se validarían, transformarían y almacenarían en la base de datos. Los reportes regulatorios se generarían automáticamente según los requisitos y se enviarían a través de los canales apropiados.
4.5 Observabilidad
4.5.1 Honeycomb
Honeycomb se usa para agregación y explotación de datos OpenTelemetry, así como para generar alertas que se integran con software de gestión de pager/on-call. El sistema usa el protocolo OpenTelemetry (OTEL) para enviar métricas, logs y trazas desde el OpenTelemetry Collector a Honeycomb.
El OpenTelemetry Collector se configura con la API key y dataset de Honeycomb. Los datos se envían automáticamente vía el protocolo OTEL. Aunque actualmente se usa Honeycomb, la aplicación usa el protocolo OTEL estándar, lo que permite migrar a otros proveedores compatibles (Datadog, New Relic, Grafana Cloud, etc.) sin modificaciones significativas.
El sistema está instrumentado para proporcionar visibilidad completa de su comportamiento en producción. OpenTelemetry captura trazas de todas las operaciones, desde recibir una solicitud HTTP hasta la respuesta final. Cada operación significativa crea un span con atributos relevantes. Los spans se propagan a través de llamadas asíncronas y entre servicios, permitiendo reconstruir el flujo completo de una operación.
Las trazas se exportan a Honeycomb, donde pueden analizarse para identificar cuellos de botella, errores y patrones de uso. La propagación del contexto de tracing a través del outbox permite correlacionar la operación original con su procesamiento asíncrono posterior.
El logging usa el crate tracing de Rust, que proporciona logs estructurados con niveles (error, warn, info, debug, trace) y campos tipados. Los logs se emiten en formato JSON en producción, facilitando su indexación y búsqueda. Cada entrada de log incluye automáticamente el contexto del span actual, conectándola con la traza distribuida.
4.6 Almacenamiento de Datos para Reportes
4.6.1 BigQuery
BigQuery se usa como almacenamiento de datos analíticos y de reportes. El sistema usa BigQuery para almacenar datos transformados de las bases de datos operativas PostgreSQL, permitiendo análisis y reportes sin impactar el rendimiento de la base de datos transaccional.
La aplicación usa BigQuery en conjunto con herramientas ETL (Meltano) y transformación de datos (dbt) para cargar y transformar datos desde PostgreSQL a BigQuery. Meltano extrae datos de múltiples fuentes: el extractor principal tap-postgres obtiene eventos y entidades del core bancario, y extractores adicionales obtienen precios históricos de Bitfinex y datos de verificación KYC de SumSub.
Los datos se cargan en BigQuery, donde dbt los transforma a través de capas: staging (limpieza de datos crudos), intermediate (lógica de negocio), y outputs (reportes finales). El sistema genera reportes regulatorios que pueden integrarse con sistemas externos según las necesidades de cada jurisdicción.
La configuración incluye JSON de service account, project ID y nombres de datasets. Es importante notar que, aunque actualmente se usa BigQuery, la aplicación puede refactorizarse para realizar el mismo trabajo en otras bases de datos analíticas. El código ETL y de transformación puede adaptarse para trabajar con alternativas como Amazon Redshift, Snowflake, Azure Synapse Analytics, o incluso bases de datos analíticas on-premise.
5. Flujos de Autenticación y Seguridad
5.1 IAM (Identity and Access Management)
5.1.1 Keycloak
Keycloak actúa como el servidor central de identidad y acceso (IAM) integrado con la aplicación. Proporciona:
- Gestión de usuarios y roles
- Autenticación a través de múltiples métodos (usuario/contraseña, OAuth2, OIDC)
- Autorización basada en roles (RBAC)
- Single Sign-On (SSO)
- Gestión de sesiones
- Integración con proveedores de identidad externos (Google, etc.)
Naturaleza Federada y Autenticación Externa de Empleados:
Debido a su naturaleza federada, Keycloak está diseñado para delegar la autenticación de usuarios internos (empleados) a sistemas de identidad externos. Se espera que el backend de autenticación de empleados venga externamente. Por ejemplo, si la institución usa Azure Active Directory (Azure AD), Keycloak debería integrarse con Azure AD para que Keycloak delegue la autenticación a Azure AD. Este es un detalle de despliegue que debe abordarse en cada caso según las necesidades de la institución y los sistemas de identidad existentes.
Configurabilidad:
Keycloak es altamente configurable y la configuración descrita a continuación es una sugerencia que puede adaptarse a las necesidades de cada despliegue. Realms, clientes, flujos de autenticación y proveedores de identidad pueden configurarse según los requisitos específicos de cada cliente.
Como sugerencia, se configuran tres realms:
- Internal Realm: Para usuarios internos y servicios de aplicación
- Customer Realm: Para clientes de la aplicación
- Data-Dagster Realm: Para acceso a herramientas de datos (Dagster)
Similarmente, se sugieren tres clientes de aplicación:
- internal-service-account: Para servicios internos de la aplicación
- customer-service-account: Para el portal de clientes
- oauth2-proxy: Para autenticación OAuth2 Proxy
El flujo de autenticación para usuarios internos funciona así: cuando un usuario accede al Panel de Administración (admin.{domain}), la aplicación redirige a Keycloak para autenticación. Keycloak puede delegar la autenticación a un proveedor de identidad externo (ej. Azure AD, LDAP, etc.) o validar credenciales directamente. Después de autenticación exitosa, Keycloak genera tokens JWT usados para autenticar solicitudes a la API GraphQL. Finalmente, Oathkeeper valida los tokens JWT antes de permitir acceso a recursos.
Para clientes, el flujo de autenticación es similar: cuando un cliente accede al Portal de Clientes (app.{domain}), la aplicación redirige a Keycloak (Customer Realm) para autenticación. Keycloak valida credenciales y genera tokens JWT, que se usan para autenticar solicitudes a la API pública. Oathkeeper valida los tokens JWT antes de permitir acceso a recursos.
Los flujos de autenticación descritos son ejemplos y pueden variar según la configuración específica de cada despliegue, especialmente respecto a la integración con proveedores de identidad externos para usuarios internos.
5.1.2 Oathkeeper
Oathkeeper actúa como proxy de autenticación y autorización, proporcionando:
- Validación de tokens JWT
- Enrutamiento de solicitudes autenticadas
- Mutación de tokens (transformación de claims)
- Reglas de acceso basadas en URL y método HTTP
- Alta disponibilidad (2 réplicas por defecto)
Se configuran varias reglas de acceso:
- admin-api: Protege el endpoint GraphQL del Panel de Administración, requiere autenticación JWT
- admin-ui: Protege la interfaz del Panel de Administración, permite acceso sin autenticación (autenticación manejada por la aplicación)
- customer-ui: Protege el Portal de Clientes, permite acceso sin autenticación (autenticación manejada por la aplicación)
- customer-api: Protege la API pública del Portal de Clientes, requiere autenticación JWT
El flujo de validación funciona así: cuando un cliente envía una solicitud con un token JWT en el header Authorization, Oathkeeper extrae y valida el token JWT contra el JWKS de Keycloak. Oathkeeper verifica que el token no haya expirado y que el issuer sea válido, luego aplica reglas de autorización según URL y método. Si la autorización es exitosa, Oathkeeper muta el token (opcional) y reenvía la solicitud al servicio upstream.
5.1.3 OAuth2 Proxy
OAuth2 Proxy proporciona autenticación OAuth2/OIDC para aplicaciones que no soportan autenticación nativa. Se usa principalmente para proteger acceso a Dagster.
El flujo de autenticación con OAuth2 Proxy funciona así: cuando un usuario accede a Dagster (dagster.{domain}), OAuth2 Proxy intercepta la solicitud y verifica si hay una sesión válida. Si no hay sesión, OAuth2 Proxy redirige a Keycloak para autenticación. El usuario se autentica en Keycloak (puede usar Google como proveedor de identidad), y Keycloak redirige de vuelta a OAuth2 Proxy con un código de autorización. OAuth2 Proxy intercambia el código por tokens y crea una sesión, finalmente permitiendo acceso a Dagster con headers de autenticación.
5.2 WAF (Web Application Firewall)
El sistema usa NGINX Ingress Controller como punto de entrada, que proporciona capacidades WAF a través de varias funcionalidades.
Geo-blocking: Permite bloquear países no soportados configurados vía GeoIP2. La base de datos GeoIP2 se actualiza automáticamente desde un bucket GCS, y las reglas de bloqueo se configuran vía mapas NGINX.
Rate Limiting: Incluye limitación de solicitudes por minuto por host, limitación de conexiones simultáneas, y configuración por host (portal de clientes, panel de administración, dagster).
Protección Adicional: Existe la posibilidad de configurar WAF vía anotaciones NGINX, integración con servicios WAF externos (Cloudflare, AWS WAF, Azure WAF, etc.), y protección contra ataques comunes (DDoS, SQL injection, XSS, etc.).
5.3 Firewalls
5.3.1 Reglas de Firewall en GCP
Las reglas de firewall en GCP incluyen:
- Intra-cluster Egress: Permite comunicación entre pods y con el master (protocolos TCP, UDP, ICMP, SCTP, ESP, AH) a Master CIDR, subred del Cluster, rango de Pods y rango de Services
- Webhook Ingress: Permite al master llamar webhooks en pods (puertos 8443, 443) desde Master CIDR
- DMZ to Nodes: Permite acceso desde bastion a nodos del cluster (todos los protocolos) desde subred DMZ
5.3.2 Network Security Groups en Azure
Los Network Security Groups (NSG) en Azure proporcionan reglas de firewall por subred:
- PostgreSQL NSG: Permite solo tráfico desde VirtualNetwork al puerto 5432
- Cluster NSG: Controla tráfico hacia y desde nodos de Kubernetes
- DMZ NSG: Controla acceso a hosts bastion
5.4 Cifrado en Tránsito
Para comunicaciones externas, todos los servicios expuestos públicamente usan HTTPS/TLS. Los certificados SSL/TLS se gestionan automáticamente por cert-manager, que puede usar Let's Encrypt (para certificados públicos) o una CA interna (para certificados privados). Los certificados se renuevan automáticamente antes de expirar.
Para comunicaciones internas, las bases de datos PostgreSQL requieren SSL/TLS para todas las conexiones (sslmode = "require" en Azure). Las comunicaciones entre servicios dentro del cluster pueden usar mTLS (mutual TLS) vía service mesh (opcional). Las comunicaciones con servicios externos (Sumsub, pasarelas de pago, etc.) usan HTTPS/TLS.
Se usan protocolos y versiones seguros: TLS 1.2 o superior para todas las conexiones, cipher suites seguros configurados en NGINX Ingress, y Perfect Forward Secrecy (PFS) habilitado.
5.5 Cifrado en Reposo
Las bases de datos gestionadas (Cloud SQL, Azure PostgreSQL) usan cifrado en reposo proporcionado por el proveedor cloud. En GCP, Cloud SQL usa cifrado automático de datos en reposo. En Azure, Azure PostgreSQL Flexible Server usa cifrado automático con claves gestionadas por Microsoft o claves gestionadas por el cliente (CMK). Los backups también están cifrados.
Los objetos almacenados en buckets GCS (documentos, reportes, etc.) usan cifrado en reposo. El cifrado puede ser gestionado por Google o vía claves gestionadas por el cliente (CMEK).
Los secrets de Kubernetes se almacenan cifrados en etcd. En GCP, etcd está cifrado vía claves gestionadas por Google. En Azure, etcd está cifrado vía claves gestionadas por Microsoft. Los secrets sensibles (contraseñas, API keys, etc.) se almacenan como Kubernetes Secrets y se inyectan en contenedores.
Los volúmenes persistentes usan cifrado proporcionado por el proveedor cloud. En GCP, los Persistent Volumes usan cifrado automático. En Azure, los Managed Disks usan cifrado automático.
5.6 VPN (Virtual Private Network)
Nota importante: La configuración de VPN es un detalle de despliegue, no parte de la aplicación Lana. Lo presentado a continuación son sugerencias y opciones arquitectónicas que pueden ser útiles para diferentes escenarios. Es responsabilidad del operador tomar las decisiones finales y diseños que se ajusten a las necesidades específicas de su despliegue, incluyendo requisitos de seguridad, cumplimiento y organizacionales.
El sistema puede soportar múltiples opciones de VPN para acceso administrativo y de empleados, dependiendo de la configuración elegida por el operador.
5.6.1 VPN Site-to-Site
Una opción es configurar VPN entre la red de oficina/corporativa y la VPC/VNet vía Cloud VPN o Partner VPN en GCP, o VPN Gateway (Site-to-Site) en Azure. Las ventajas incluyen acceso directo a recursos internos sin exponer servicios a Internet, no se requieren IPs públicas para servicios internos, y control de acceso centralizado. Los empleados conectados a la red corporativa accederían automáticamente.
5.6.2 VPN Client (Point-to-Site)
Otra opción es configuración de VPN cliente para acceso remoto, que presenta diferencias dependiendo del proveedor cloud: Cloud VPN no soporta P2S nativamente en GCP, requiriendo solución de terceros, mientras que en Azure se puede usar VPN Gateway (Point-to-Site) con OpenVPN o IKEv2. Las ventajas incluyen acceso desde cualquier ubicación, autenticación por certificado o usuario/contraseña, y no se requiere red corporativa. Los empleados remotos se conectarían vía cliente VPN.
5.6.3 Bastion Host con VPN
Una alternativa es configuración de VPN al host bastion con port forwarding, que funcionaría así: el empleado se conecta a VPN, VPN termina en el host bastion, y el empleado accede a servicios internos a través del bastion. Las ventajas incluyen control de acceso granular, auditoría centralizada, y no se requieren cambios a la infraestructura principal.
5.6.4 Acceso vía Bastion (SSH Tunneling)
Otra opción es configuración de túnel SSH a través del host bastion para acceso administrativo y debugging. Por ejemplo, tunneling a base de datos PostgreSQL vía ssh -L localhost:5432:db-internal-ip:5432 bastion-host. Las ventajas incluyen acceso seguro a recursos internos sin exponerlos a Internet.
El operador debe evaluar estas opciones y seleccionar o diseñar la solución de acceso remoto que mejor se ajuste a sus requisitos específicos de seguridad, cumplimiento y operacionales.
5.7 Certificados
cert-manager gestiona automáticamente certificados SSL/TLS. Los certificados se crean como recursos de Kubernetes (Certificates), cert-manager solicita certificados de Let's Encrypt o CA interna según configuración, los certificados se renuevan automáticamente antes de expirar, y se almacenan como Kubernetes Secrets.
Los certificados para comunicación con bases de datos y servicios internos pueden ser gestionados por cert-manager o proporcionados manualmente. Los certificados para autenticación con servicios externos (BCR, sistemas regulatorios) se proporcionan como parte de la configuración del ambiente.
6. Segmentación de Red por Ambiente
La arquitectura implementa aislamiento completo entre diferentes ambientes (DEV, QA, UAT, PROD). Los ambientes no comparten ningún recurso de infraestructura.
Cada ambiente tiene:
- Su propia VPC/VNet completamente aislada
- Su propio cluster de Kubernetes
- Sus propias instancias de base de datos
- Sus propios load balancers e IPs públicas
- Sus propias credenciales y secrets
- Sus propios dominios y certificados SSL/TLS
No hay conectividad de red directa entre ambientes. No hay VPC/VNet peering entre ambientes. No hay rutas de red que permitan comunicación entre ambientes. Cada ambiente es completamente independiente y aislado de los demás.
7. Zonas de Seguridad
La arquitectura implementa un modelo de zonas de seguridad que segmenta la infraestructura según nivel de exposición y requisitos de seguridad.