Saltar al contenido
Documento de Arquitectura · v1.1

BCFlow Background Checker · by Zetgo Flow · powered by DigitALL Pro

Plataforma colombiana de consulta de antecedentes — diseñada como un sistema distribuido de control central + flota de workers residenciales, con monitoreo, autocuración y entrega activa de eventos.

01 · Resumen ejecutivo

17 fuentes, un reporte, sin pelearle a las IPs.

BCFlow es una plataforma SaaS multi-tenant que consulta 17 fuentes de antecedentes en paralelo. Tres pilares: un plano de control en la nube, una flota distribuida de workers en máquinas residenciales colombianas, y una capa de monitoreo activo que avisa cuando algo se rompe antes de que el cliente lo note.

17
Fuentes de datos
11+6
Colombianas + sanciones
~60s
P95 de una consulta
N
Workers residenciales
5 min
Auto-actualización
4
Eventos en webhooks

La narrativa de este documento es simple: la plataforma se diseñó para que cada nueva máquina que se enchufa en una casa colombiana añada capacidad real al sistema, sin ceremonias, sin Kubernetes, sin proxies caros. Cada componente que verás aquí existe porque resuelve un problema concreto que enfrentamos en producción.

¿Cuántos workers necesitas para tu volumen?Usa la calculadora — volumen mensual, fuentes por consulta, retención. Salen workers, almacenamiento y costo total a N años.
02 · El problema

Tres barreras estructurales que matan cualquier solución ingenua.

Resolverlas las tres a la vez es lo que justifica todo el resto del sistema.

1

Bloqueo por IP

Los portales .gov.co rechazan IPs de centros de datos extranjeros y limitan agresivamente cualquier IP que haga >5 consultas por minuto.

2

CAPTCHAs y JavaScript

Cuatro fuentes (Policía, Contraloría, Procuraduría, Registraduría) requieren un navegador real con JavaScript, cookies y resolución de reCAPTCHA v2 o CAPTCHAs de imagen.

3

Volumen

El target del negocio son 4 mil a 500 mil consultas/mes por cliente con SLA de minutos. Un solo proceso, un solo navegador, una sola IP — colapsa antes del primer cliente serio.

Insight clave. Si necesitamos IPs residenciales colombianas, lo más barato a largo plazo es poner mini-PCs en casas colombianas. Cada máquina que se enchufa en una nueva conexión ISP aporta una IP residencial real y gratis al sistema.
03 · La solución en 60 segundos

Dos planos. Un solo trabajo cada uno.

Un plano de control en la nube (estable, una sola IP fija) y un plano de ejecución (flota de mini-PCs en casas residenciales). Se hablan por una cola de mensajes.

Plano de control y plano de ejecución
Plano de control (azul) y plano de ejecución (ámbar). El control tiene una IP fija y holds toda la lógica; los workers tienen IPs residenciales y solo ejecutan trabajo.

La promesa: cada nueva mini-PC enchufada en una casa colombiana es N veces más capacidad real, en minutos, sin tocar el plano de control. La IP residencial nueva queda automáticamente en rotación porque la cola distribuye el trabajo de forma equitativa.

04 · Arquitectura general

La vista detallada — todo lo que existe físicamente en producción.

Arquitectura completa
Los workers nunca exponen puertos al exterior — todas las conexiones son salientes. Eso permite operarlos detrás de NAT/CGNAT residencial sin abrir puertos.

Las dos reglas inviolables

Regla #1 — El VPS NUNCA corre un worker.

El VPS tiene IP de datacenter en EE.UU. Si ejecuta un adapter contra .gov.co, contamina la reputación de la IP del plano de control entero. Una sola consulta puede gatillar bloqueos que tumban toda la plataforma.

Regla #2 — Las sanciones NO van por la cola.

Watchman está atado a 127.0.0.1. Las consultas de sanciones se ejecutan in-process en la API — 100× más rápidas (<1s vs ~30s).

05 · Las cuatro capas

Una responsabilidad por capa. Un contrato entre cada par.

Cuatro capas del sistema
P

Presentación

Lo que el usuario toca: portal web, dashboard de salud, formularios, línea de progreso en tiempo real. SPA Nuxt. Recibe eventos SSE.

A

API Gateway

El portero. Verifica JWT, valida rate-limits por cuenta, traduce alias en español, aplica CORS y headers de seguridad.

O

Orquestación

Decide tier de la consulta (sanctions in-process; browser/api a la cola). Resuelve nombre completo, agrupa resultados, dispara eventos SSE.

E

Ejecución

17 adapters, cada uno habla su dialecto. BrowserManager, CaptchaSolver, EvidenceCollector compartidos.

06 · Componentes en detalle

Cada componente resuelve un problema concreto.

Plano de control

Express API. Lógica de negocio que NO requiere browser residencial. Stateless — escala horizontalmente.
Nuxt 3 (este SPA). Frontend hybrid SSR/SPA. Auth via httpOnly cookies + Nitro proxy. Charts en Chart.js.
Caddy. Reverse-proxy + TLS automático. Sirve estáticos y scripts de instalación.
PostgreSQL 18. DO Managed con backup diario. Drizzle ORM tipado. Verdad del sistema.
Redis 7 + BullMQ. Cola durable de jobs + pub/sub para SSE y heartbeats. Auth por ACL.
Watchman. Screening de sanciones in-memory. Sub-segundo. Atado a loopback.
Registry Docker. Privado v2 detrás de Caddy. digitall/worker + watchtower.
Cron Manager. 6 jobs gestionados con enable flag persistido en platform_config.

Inteligencia y monitoreo

Source Health Detector. Máquina de estados in-process por fuente. 3 fallos en 10 min → source.unhealthy.
Error Fingerprinting. SHA-256 del error normalizado. Mismo hash en N workers = upstream caído. En 1 = worker enfermo.
Webhook Deliverer. HMAC-SHA256. Reintentos 30s → 5min → 30min. Auto-disable a 10 fallos.
Sanctions Mirror. systemd timer 6h refresca CSVs locales. Sobrevive caídas del upstream europeo.

Plano de ejecución (workers)

Worker (Docker). Imagen multi-stage ~3 GB con Playwright. Conexiones SOLO de salida. No persiste nada localmente.
Watchtower. Auto-actualizador self-hosted. Cada 5 min poll del registry. Cero downtime, jobs activos vuelven a la cola.
BrowserManager. Playwright con stealth custom. Contexto fresco por consulta. Sin reuso entre requests.
RemoteCaptchaSolver. Cliente HTTP que reemplaza la llamada directa a 2captcha. Una sola IP a whitelistear.
07 · Ciclo de vida de una consulta

Diez pasos, dos planos.

Desde que el cliente hace clic en "Buscar" hasta que el reporte aparece pintado en pantalla.

Ciclo de vida de una consulta
Cada flecha es un evento real. La consulta retorna inmediatamente con un queryId; los resultados llegan vía SSE conforme cada fuente termina. No hay polling.
1·2·3

Recepción

POST → JWT + rate-limit + zod → fila en queries202 con queryId.

4

Decisión por tier

Sanctions → in-process. Browser/API → cola.

5·6

Worker recibe

Primer worker libre toma el job (BLPOP), corre el adapter en su IP residencial.

7·8

Persistencia + evento

Escribe en query_results con worker_id y publica en el canal SSE.

9·10

UI live

El navegador suscrito al SSE dibuja cada resultado conforme llega. Último evento: agregado final.

08 · Tipos de fuentes (tiers)

Tres tiers. Cada uno con su perfil de costo y forma de escalar.

SANCTIONS

6 fuentes — OFAC, US Non-SDN, US CSL, EU CSL, UK CSL, UN CSL

Watchman in-memory. Latencia <1s. In-process en la API — nunca tocan la cola. Costo cero después del seed.

BROWSER

4 fuentes — Policía, Contraloría, Procuraduría, Registro Civil

Playwright + reCAPTCHA + JSF. Latencia 20-100s. IP residencial CO obligatoria. CAPTCHA ~$0.005 por intento.

API

7 fuentes — PEPs, Defunción, ADRES, SIMIT, Rama Judicial, INTERPOL, INPEC

HTTP plano (ASP.NET, ICEfaces, JSF). Latencia 0.1-15s. IP residencial preferida.

Capacidad efectiva del fleet

Cada fuente tiene un rate-limit upstream — típicamente 5 consultas/min/IP. Con N workers, la capacidad total es N × 5 consultas/minuto. Lineal.

🟧 Proxies residenciales pagos

  • $50–100/mes por IP
  • 8 IPs ≈ $400–800/mes para siempre
  • Restricciones del proveedor (puerto 7005 bloqueado, .gov bloqueado)
  • Cero control sobre rotación o calidad

🟩 Mini-PCs en casas residenciales

  • ~$200 por máquina, una sola vez
  • Energía: ~$1.20/mes por nodo
  • IP residencial real, sin restricciones de puerto
  • Plug & play: instalación ~10 minutos
  • Break-even en 4 meses
09 · Vida de un worker

Operacionalmente trivial — ningún paso requiere expertise.

Vida de un worker

Geo-distribución y resiliencia de IPs

Cada worker está en una conexión ISP distinta. Con 8 workers en distintos ISPs, una caída masiva de un ISP (rara pero real) afecta a 1/8 del fleet. La cola redistribuye sin intervención.

Auto-actualización

Push nueva imagen → Watchtower detecta digest en ≤5 min → recreate del container manteniendo env y volumen. ≤10 min al fleet entero. Cero downtime.

10 · CAPTCHA proxy — caso de estudio

Centralizar lo que es delicado de operar.

Antes vs después del CAPTCHA proxy
  • Seguridad. Si una mini-PC se compromete, el atacante no obtiene la API key de 2captcha.
  • Operación. Añadir un worker pasa de "whitelistea su IP y reza que no cambie" a "enchúfalo y olvídalo".
  • Costo. Balance se monitorea desde un solo lugar. Atribución por worker_id sigue siendo posible.
  • Latencia. ~50 ms de hop adicional sobre un solve que tarda 20-60s. Invisible.
11 · Almacenamiento de evidencias

Workers solo trabajan — nunca almacenan datos históricos.

Almacenamiento de evidencias
Las mini-PCs son hardware desechable: pueden morirse de viejas, perder energía, sufrir un corte ISP largo, o simplemente decommissionarse. Si un worker dejara evidencia en su SSD, decommissionar = perder. Por eso la regla es absoluta: todo lo durable vive en el plano de control.
1. Captura en RAM. Playwright devuelve Buffer en memoria — sin tocar disco. Igual con PDFs y traces.
2. Subida HTTPS al VPS. Worker hace POST /internal/evidence/file con bytes en body.
3. Persistencia en VPS. API escribe a /var/lib/digitall/evidence/. Path traversal validado.
4. DB upsert. UPSERT en evidence_bundles. Single source of truth.
12 · Escalabilidad

Para cada eje: el cuello, la palanca, el costo.

Throughput browser

Cuello: rate-limit por IP (~5/min/IP).
Palanca: añadir workers en nuevas ISPs.
Capacidad: N × 5/min lineal. 8 workers ⇒ 1.7 M consultas/mes.
Costo: ~$200 por worker, una vez.

Throughput sanciones

Cuello: CPU + RAM de Watchman.
Palanca: escalar vertical el VPS.
Capacidad: >1000/seg en VPS pequeño.
Costo: $6-25/mes por instancia adicional.

Concurrencia HTTP

Cuello: conexiones a Postgres (max 25 inicial).
Palanca: habilitar PgBouncer transaction-pool.
Capacidad post-PgBouncer: ~1000 conexiones lógicas sobre 25 físicas.

CAPTCHA

Cuello: presupuesto en 2captcha.
Palanca: filtrar CAPTCHA-bound sources client-side o auto-recargar al umbral.
Costo: ~$2-4 K/mes para 500K consultas. Se traslada al cliente.

13 · Calculadora de dimensionamiento

Cinco variables — workers, almacenamiento y TCO al instante.

Cada fuente gubernamental tiene ~5 consultas/min/IP. Con N workers, capacidad = N × 5. Sin proxies, sin Kubernetes, sin gymnastics.

Escenarios de referencia

Cliente pequeño — 4 000 consultas/mes

PyME o startup haciendo onboarding

Promedio sostenido
~0.09 c/min
Pico (×5)
~0.46 c/min
Workers necesarios
1 (margen de sobra)
Almacenamiento 4a
~940 GB
Costo recurrente
~$98/mes
TCO 4 años
~$4 900

Enterprise — 1 000 000 consultas/mes

Plataforma BPO / RR.HH. nacional

Promedio sostenido
~23 c/min
Pico (×5)
~116 c/min
Workers necesarios
~30 mini-PCs en 30 ISPs
Almacenamiento 4a
~229 TB
Costo recurrente
~$25 000/mes
TCO 4 años
~$1.2 M

Calculadora interactiva

Variables de entrada

Volumen total esperado.

Total 1–17.

Con CAPTCHA, 0–5.

5× cubre concentración en horario laboral.

Dimensionamiento

Carga

Promedio sostenido2.3 consultas/min
Pico estimado12 consultas/min
Pico jobs browser/min46

Workers

Recomendados (con margen 30%)4 mini-PCs
Sin margen de seguridad2.3
CAPEX hardware (una sola vez)$800

Almacenamiento

Crecimiento mensual488 GB
Total al final de retención22.9 TB

Costo mensual recurrente

CAPTCHA (2captcha)$2000
Almacenamiento$469
Infraestructura (bundle)$140
Energía workers$4.80
Total mensual$2614

TCO a 4 años

$126,250

CAPEX + recurrente × 48 meses

Supuestos. Rate-limit gobierno: 5 c/min/IP/fuente. Margen workers: +30%. CAPTCHA: $0.005/solve. Mini-PC: $200 una vez. Energía: $1.20/PC/mes. Object-storage: $0.02/GB·mes. Infraestructura bundled por escalón.

14 · Robustez y fallas

Las fallas son la norma — no la excepción.

17 portales gubernamentales. La pregunta no es si fallan, es cómo nos enteramos y cuánto duele.

FallaDetecciónRespuesta automática
Una fuente fallaAdapter throwOtras siguen. Status: partial
3 fallas seguidasHealth detectorWebhook source.unhealthy
Worker mid-jobBullMQ stalled (30s)Reasigna a otro worker
Worker offline (90s)SweeperStatus flipea + webhook worker.offline
EU CSL caídoMirror timerSirve desde réplica local
Webhook receiver muerto10 fallos seguidosAuto-disable
Consulta atascadaCron 30 minMarca failed si >10 min

El truco de la fingerprint

Cada error se normaliza (timestamps, UUIDs, IPs, números → placeholder) y se hashea. El dashboard agrupa por hash y cuenta cuántos workers distintos lo vieron.

Mismo hash en N workers.
El upstream está roto. Nada que un worker individual pueda hacer.
Mismo hash en 1 worker.
Ese worker está enfermo. Pausar hasta que rote DHCP.
15 · Monitoreo y observabilidad

Tres dashboards y un detector — sin SSH a nada.

Dashboard de Salud

Per-source: runs, success rate, p50/p95, fingerprints top-3, breakdown por worker. Pestañas para fuentes, workers, Watchman y webhooks.

Métricas (Chart.js)

Consultas por hora, success rate por fuente, costo CAPTCHA por día, latencia p95 a lo largo del tiempo.

Logs estructurados (pino)

Cada componente loggea JSON en stdout. systemd persiste. Workers via Docker daemon.

16 · Webhooks salientes

Tú decides la URL. Nosotros firmamos, entregamos y registramos.

Webhook delivery

Eventos disponibles

source.unhealthy

3 fallos seguidos en 10 min. Adjunta fingerprint del último error y workers involucrados.

source.recovered

Primer éxito tras un período unhealthy. Cierra incidentes automáticamente.

worker.offline

Sweeper marcó worker offline tras 90s sin heartbeat. Útil para alertar a quien tenga la mini-PC en su casa.

query.failed

Toda fuente retornó error. Útil para reembolso automático en planes pay-per-query.

Cada POST incluye X-DigitALL-Event, X-DigitALL-Delivery (UUID único) y X-DigitALL-Signature: sha256=<hex>. Verifica con HMAC-SHA256 sobre el body crudo y la clave secreta (entregada UNA VEZ al crear el webhook).

17 · Lo que hemos conseguido

Estado actual — honesto.

✓ 17 de 17 fuentes 11 colombianas + 6 sanciones internacionales, todas en producción.
✓ Plano de control en producción VPS + TLS automático + multi-tenant JWT + dashboards Chart.js + evidencias.
✓ Provisión en una sola línea curl bco.zetgo.io/install | sudo bash + install.ps1 en Windows.
✓ Watchtower self-hosted Upstream archivado en 2025. Forkeamos y construimos nuestra imagen.
✓ Detector + webhooks HMAC Detección de fuentes degradadas. Dashboard distingue "upstream caído" de "worker enfermo".
✓ CAPTCHA centralizado Una sola IP a whitelistear. API key fuera de los workers.
✓ Réplica de listas de sanciones Watchman sobrevive caídas del upstream europeo.
✓ Live progress sin polling SSE entrega cada resultado conforme termina.
✓ Evidencia centralizada Workers no persisten en su SSD. Decommissionar ya no pierde nada.
✓ Cron manager centralizado 6 jobs gestionados, enable flag persistido, Run-now desde admin UI.
18 · Cierre

Cada decisión arquitectural defendible en una conversación con un cliente.

BCFlow se diseñó para que cada decisión arquitectural sea defendible en una conversación con un cliente que pregunta por qué. No hay tecnología por moda: cada componente resuelve un problema concreto que vimos en producción y cada componente se puede reemplazar sin tumbar el resto.