Skip to content

Composición de flows + matriz LoA

This content is not available in your language yet.

Una de las confusiones más comunes cuando alguien ve por primera vez el seed default de bmonkey es pensar que el flujo “consentimiento + documento

  • selfie + SARLAFT + OTP” es el onboarding que ofrece bjungle. No lo es. Es un ejemplo (el caso cashpaya). bmonkey está diseñado como un workflow engine de identidad: cada tenant define qué pasos quiere, en qué orden, y el nivel de aseguramiento (LoA) resultante se calcula a partir de la combinación.

Este ADR fija:

  1. El catálogo canónico de pasos.
  2. La matriz de cuánto LoA aporta cada combinación.
  3. Las verticales pre-seedeadas para acelerar setup.
  4. El modelo de pricing por step.

StepCatalog (en internal/domain/flow.go) es la fuente única de verdad. La portal lo lee vía GET /v1/flows/catalog y el step picker se renderiza dinámicamente. Agregar un step nuevo es agregar una entrada a este array + el handler en flow_engine.go. Cero migración.

StepQué haceAçaí costValid in
consentRegistra HABEAS DATA + biométrico en subject_consents0onboarding
document_uploadCaptura frente / dorso del documento (presign S3)0onboarding
ocrExtrae datos del documento con Bedrock0onboarding
face_matchCompara selfie vs foto del documento (Rekognition / ArcFace)0onboarding, login, step-up
face_enrollGuarda patrón facial para login posterior0onboarding
livenessAnti-spoofing (Rekognition Liveness o básico)0onboarding
sarlaftScreening sincrónico contra reglas bhawk (PEP, OFAC, etc.)screeningonboarding
email_otpCódigo por correo (SES)0onboarding, login, step-up
sms_otpCódigo por SMS (SNS)mfa_otp_smsonboarding, login, step-up
passwordContraseña tradicional (bmonkey como IdP)0onboarding, login

LoA = Level of Assurance, alineado con NIST 800-63-3 y eIDAS. bmonkey emite VCs con uno de tres niveles según qué pasos se completaron.

┌─────────┬─────────┬─────────┐
│ LoA 1 │ LoA 2 │ LoA 3 │
│ (bajo) │ (medio) │ (alto) │
─────────────────┼─────────┼─────────┼─────────┤
consent │ ✓ │ ✓ │ ✓ │
email_otp │ ✓ │ ✓ │ ✓ │
document_upload │ │ ✓ │ ✓ │
ocr │ │ ✓ │ ✓ │
face_enroll │ │ ✓ │ ✓ │
face_match │ │ ✓ │ ✓ │
liveness │ │ │ ✓ │
sarlaft │ │ │ ✓ │
sms_otp │ │ │ ✓ │
─────────────────┴─────────┴─────────┴─────────┘
Equivalencias
NIST 800-63-3 IAL1 IAL2 IAL3
eIDAS low substantial high

Reglas duras:

  • Sin consent → no se emite VC (es bloqueo legal, no técnico).
  • Sin document_upload + ocr + face_match → LoA queda en 1.
  • Sin liveness → LoA capped a 2.
  • Sin sarlaft → no se otorga LoA 3 a menos que el tenant haga su propio screening por fuera (raro, requiere acuerdo explícito).

Cuando un tenant pide presentación con required_loa: 2, el wallet solo aprueba si hay al menos una VC del usuario que llegó a ese nivel. Eso permite que la misma persona se onboardee LoA1 en una app de delivery y LoA3 en un banco, y cada tenant solo ve / paga lo que le corresponde.

Para acelerar el primer flow de un tenant, ofrecemos seeds por vertical. Cada seed inserta un flow publicado con steps + branding razonables.

[consent, email_otp]
UX: ~30 segundos
Açaí cost por onboarding: ~5
Casos típicos: apps de pedidos, fitness, contenido,
suscripciones bajo riesgo
[consent, document_upload, ocr, face_enroll, face_match, email_otp]
UX: ~3 minutos
Açaí cost por onboarding: ~30
Casos típicos: billeteras digitales sin custodia mayor,
marketplaces con pago integrado, neobancos lite
[consent, document_upload, ocr, face_enroll, face_match, liveness,
sarlaft, email_otp, sms_otp]
UX: ~6 minutos
Açaí cost por onboarding: ~120 (incluye screening + SMS)
Casos típicos: apertura de cuenta corriente, líneas de crédito,
corredoras bursátiles

crypto_strict (LoA 3 + re-attestation periódica)

Sección titulada «crypto_strict (LoA 3 + re-attestation periódica)»

Como banking_full, más:

  • Trust policy con require_freshness_days: 90 — fuerza re-presentación cada trimestre.
  • Step-up obligatorio en transferencias > X via flow step_up.
flow tipo onboarding:
[consent, document_upload, ocr, face_enroll, face_match, liveness,
sarlaft, email_otp, sms_otp]
flow tipo step_up:
[face_match, sms_otp]
  1. Tenant-portal :4401 → tab bmonkeyFlowsNuevo flow.
  2. Tipo (onboarding / login / step_up) + code (slug interno).
  3. Step picker: arrastra steps del catálogo.
  4. Por step: marcar required (si es opcional, se omite si el contexto no lo necesita) + editar config.
  5. Branding (logo, color accent, texto del header).
  6. Save as draft → testear con /embed/<token>Publish.
Ventana de terminal
curl -X POST http://localhost:8081/v1/flows \
-H "X-API-Key: dj_live_anafintech_XXX" \
-H "Content-Type: application/json" \
-d '{
"type": "onboarding",
"code": "delivery_lite",
"name": "Onboarding rapido para delivery",
"version": 1,
"steps": [
{"step_type": "consent", "required": true, "config": {}},
{"step_type": "email_otp", "required": true, "config": {"ttl_seconds": 300}}
],
"branding": {"accent": "#ff5722", "logo_url": "https://ana.co/logo.png"},
"trust_policy": {"required_loa": "LoA1"}
}'
# luego publicar:
curl -X POST http://localhost:8081/v1/flows/{flow_id}/publish \
-H "X-API-Key: dj_live_anafintech_XXX"

Los pasos pueden tener config.condition que los SALTA si el contexto no lo satisface. Ejemplo: SMS OTP solo si el usuario proveyó teléfono.

{
"step_type": "sms_otp",
"required": false,
"config": {
"condition": { "key": "phone", "op": "exists" }
}
}

Operadores soportados hoy: exists, absent, equals, not_equals.

Esto permite:

  • MFA opcional: SMS OTP solo si registraron celular.
  • Step-up por riesgo: face_match solo si el monto > 1M.
  • Geofencing: sarlaft extra solo si el doc es de país de alto riesgo.

El costo Açaí por onboarding completo se calcula sumando los acai_operation de cada step que ejecutó. Eso significa:

  • delivery_lite cuesta lo mínimo (algunos Açaí por la sesión + 0 por steps gratis).
  • banking_full cuesta significativamente más (screening + mfa_otp_sms
    • costos base).
  • Ana paga exactamente lo que usó por usuario onboardeado, no una cuota fija por nivel.

Esto está alineado con el modelo de cashpaya: cobramos por uso real, no por capacidad reservada.

  • ADR-001 separación de audiencias: cada tenant decide qué pasos son aceptables para SU end user. bjungle no impone política mínima excepto en regulación nacional dura (SARLAFT obligatorio si el tenant ofrece servicios financieros en Colombia bajo Decreto 1421 / SuperFinanciera).
  • Wallet Modelo C: la VC emitida lleva loa: "LoA1|2|3" y el proof con el did:web del issuer. La trust policy del tenant que pide la presentación es quien decide si ese LoA basta.
  • Trust policy: el required_loa en la trust policy del tenant solicitante se compara contra el LoA del VC en el wallet. Mismatch → consent rechaza con loa_insufficient.
  • Tenant que omite consent porque “queremos UX más rápido”. No, el step es no-negociable (HABEAS DATA). El flow delivery_lite ya lo tiene como mínimo.
  • Tenant que pone sarlaft en una app de fitness porque “más seguridad es mejor”. No: SARLAFT cuesta 40 Açaí, agrega 1-2 minutos de UX, y no tiene sentido fuera de servicios financieros. La vertical correcta es delivery_lite.
  • Tenant que pide required_loa: 3 para ver el full_name. Crea fricción innecesaria. required_loa: 2 (documento + cara) es suficiente para “verificar nombre real”. LoA3 es para movimientos financieros.
AspectoDecisión
StatusAccepted (2026-05-30)
Aplicable abmonkey-api · flow_engine · portal · embed
Catálogo de stepsopen vocabulary — agregar entrada al StepCatalog + handler
Verticales seedeadasdelivery_lite, fintech_medium, banking_full, crypto_strict
Re-evaluarcuando un regulador imponga LoA mínimo por vertical