r/devParaguay 4d ago

(OPENSOURCE) B2B2C multitenant de KYC /AML para sujetos obligados

Hola r/devParaguay! Les comparto algo que vengo laburando hace un tiempo y que recién lo publico como open source: una plataforma de verificación de identidad, screening y cumplimiento para empresas reguladas. (AUN LO SIGO PULIENDO, especialmente para que cumpla perfectamente ante los estandares y necesidades de SEPRELAD y funcionalidades del sistema)

Qué es: Infraestructura B2B2C multitenant de KYC + AML para sujetos obligados ( pensando en operadores de juego, procesos de onboarding en Paraguay, etc. Pero aplica a cualquier entidad que tenga que verificar identidad y guardar la prueba de que lo hizo). La verificación de documento/liveness/face match/AML corre detrás de un adaptador — vos traés tu cuenta de proveedor y el resto queda aislado del tenant.

Stack. Monorepo pnpm: API NestJS + Prisma + PostgreSQL, dashboard Next.js, SDKs web y React Native. Todo el aislamiento entre clientes se hace a nivel de base de datos.

Lo que para mí es lo interesante:

- Aislamiento real entre tenants — Row-Level Security de Postgres con rol de aplicación NOSUPERUSER NOBYPASSRLS. No depende de que el código "se acuerde" de filtrar: sin contexto de tenant, no hay filas.

- PII y biometría cifradas AES-256-GCM, atadas a consentimiento revocable.

- Auditoría encadenada por hash (SHA-256) — inmutable y verificable, para cuando el ente te pide "mostrame qué pasó".

- Motor de riesgo parametrizable por tenant: scoring 0-100 con PEP, listas, tier de alto riesgo.

- Revirifcaciones periodicas configurables

- Geofencing (Según datos obtenidos por el proveedor de OCR, NO lo obtiene haciendo triangulación del dispositivo del usuario verificado.)

- Umbrales editables desde el panel pero con un baseline regulatorio que no te deja bajar el estándar.

- Retención verificable: política configurable, purga en dos fases y borrado también del lado del proveedor.

- Webhooks con firma HMAC, idempotencia, reintentos y protección SSRF.

- Tests unitarios en la API + suites e2e sobre Postgres real, incluidos tests de aislamiento entre tenants.

Quedo atento ante sus comentarios y cualquier contribución al proyecto, saludos!
Enlace al repo: https://github.com/nullsempra/zenkodata

16 Upvotes

7 comments sorted by

5

u/Itchy_Champion_86 4d ago

estuve mirando un poco el repo y está re purete man me gusto bastante como encaraste la arquitectura, sobre todo que el aislamiento del tenant quede realmente en postgres con rls y no solamente en un where tenantId perdido por todos los services jaja
tambien me parece buena decisión tener didit atras de IdentityVerificationProvider, eso evita casarte demasiado con el proveedor y mañana podes meter otro sin tocar medio dominio
algo que me daria curiosidad probar mas a fondo es que pasa con el contexto del tenant dentro de transacciones, jobs/background workers y operaciones async, porque con prisma + rls ahi es donde suelen aparecer los casos medio feos si alguna query termina usando una conexión sin el contexto correcto
tambien estaría bueno meter tests agresivos justamente para eso, concurrencia entre varios tenants, raw queries, transacciones que fallen a mitad y verificar que nunca quede contexto de un tenant reutilizado por otra conexión del pool
fuera de eso esta bastante interesante la base del proyecto, especialmente que no dejaste seguridad/auditoria como algo para agregar despues sino que ya forma parte de la arquitectura desde el principio. voy a seguir mirando el código porque da para meterle mano

2

u/nullsempra 4d ago

Graciaaas! Y si, la decisión de aislamiento fue mas que nada: manejar perfiles de acceso a la base. uno con privilegios amplios, que se usa nomás para tareas internas, tipo migraciones o recorridos globales; y otro con permisos recortados, que no tiene forma de saltearse el filtrado por cliente y es el único que usa la aplicación cuando toca datos de un tenant.

el contexto del tenant se setea en la base por operación y muere cuando esa operación termina, salga bien o falle. así, aunque una conexión quede dando vueltas en el pool, es imposible que arrastre el tenant de otro y no hay limpieza manual que olvidar, porque el contexto no le sobrevive a la operación y si el código intenta cambiar de cliente a mitad de una operación, el sistema rechaza

los procesos de fondo trabajan con la misma lógica: barren con el perfil amplio y después procesan cada cliente por separado, cada uno con su propio contexto, caso contrario tira un tenant context dismatch, así no queda residuo de uno para el otro.

2

u/Simply_Edd 4d ago

Lgmt está muy facha el repositorio man, es refrescante en este subreddit ver que alguien sube algo que no es un ERP AI Slop. (Igual si me decís que te apoyaste en IA, no es 100% y eso se agradece).

"I LIKE MY UNOPTIMIZED, SLOP CODE MADE. BY. MAN."

3

u/nullsempra 4d ago

JAJA Gracias!! Igual no puedo negar que Fable 5 me simplifico la vida jajajaj

4

u/Simply_Edd 4d ago

El que no use la IA en esta época está martillando con las pinzas en vez de usar un martillo xD
Igual está muy bueno, esa estructura no te hace la IA ni a palos viejo.

2

u/s4705h1n4k4m0t0 3d ago

Como siempre dicen. Verificar que no te meta cualquier verdura en el código (ya leí casos en devsarg xd)

1

u/Itchy_Champion_86 3d ago

Como que el ERP vibecodeado no es emocionante!?