Blog·7 min de lectura·11 de agosto de 2026

Devlog: cómo construimos el registro, el KYC y el login de Movo (y los 3 bugs que encontramos en el camino)

Un repaso técnico de un sprint de desarrollo: registro con verificación de teléfono por Twilio, KYC biométrico con Didit.me, login con tokens seguros y un API Gateway que protege toda la plataforma. Con números y los bugs reales que aparecieron.

Trabajamos en sprints de dos semanas, con una demo al final de cada uno. Este es el resumen del sprint que le dedicamos a la parte que sostiene todo lo demás en una plataforma P2P: que dos desconocidos puedan confiar el uno en el otro para que uno le entregue un paquete al otro.

Lo hicimos todo contra infraestructura real desde el primer día: base de datos, el proveedor de verificación de identidad y el envío de SMS de verdad, nada de mocks. Nos tomó más tiempo que simular esas piezas, pero fue justamente eso lo que nos hizo encontrar bugs que un entorno de pruebas simulado no iba a mostrarnos nunca.

El objetivo del sprint

Cerramos el módulo de Identidad y Confianza: una persona nueva se puede registrar, verificar su número de teléfono con un código por SMS (usamos Twilio), validar su identidad con documento y reconocimiento facial (eso lo tercerizamos con Didit.me, un proveedor especializado en KYC), iniciar sesión de forma segura y consultar o editar su perfil.

No es la parte más vistosa del producto, pero es la que habilita todo lo demás. Sin identidad verificada no hay reputación, y sin reputación un modelo P2P de logística no cierra: nadie le da un paquete a un desconocido sin ninguna garantía de que existe y de que es quien dice ser.

249

tests automatizados en verde

37

archivos de test

0

servicios simulados (mocks) en la demo

1

sprint para todo el módulo

Qué puede hacer un usuario hoy

  • Registrarse con nombre, documento, dirección y teléfono
  • Verificar el teléfono con un código SMS real (con reintento y cooldown anti-spam)
  • Validar su identidad con documento + reconocimiento facial en vivo
  • Iniciar sesión y mantener la sesión activa de forma segura
  • Cerrar sesión revocando el acceso al instante
  • Ver su perfil público y el de otros usuarios, con la información justa en cada caso

El gateway, o quién cuida la puerta

Toda la plataforma corre sobre microservicios: usuarios, envíos, precios y pagos viven cada uno en su propio servicio, aislado de los demás. Eso da flexibilidad para tocar uno sin romper otro, pero deja una pregunta abierta: ¿quién se fija que un pedido venga autenticado antes de que llegue a cualquiera de esos servicios?

La resolvimos con un único punto de entrada, un API Gateway, que valida identidad, rol y un límite de pedidos por minuto por usuario antes de dejar pasar nada. Así ningún servicio interno tiene que reimplementar esa lógica, y no queda ningún endpoint expuesto sin protección por un descuido.

Los 3 bugs reales que encontramos (y arreglamos en el mismo sprint)

Probar contra proveedores externos reales, y no solo contra su documentación, cuesta más tiempo pero tiene un beneficio directo: aparecieron tres problemas que un mock jamás hubiera mostrado. El límite de pedidos por minuto del gateway se compartía por error entre /kyc/session y /auth/login, así que un usuario podía gastar su cupo autenticándose y quedarse sin margen para arrancar el KYC. Twilio dejó de aceptar nuestro método de autenticación (Account SID + Auth Token) y tuvimos que migrar en caliente a API Key + Secret. Y un número argentino con el prefijo +549 no lo reconocía como el mismo destinatario que +54, así que algunos SMS no llegaban. Los tres aparecieron probando contra el entorno real y se corrigieron en el mismo sprint.

Por qué no alcanza con leer la documentación del proveedor

Didit.me documenta tres resultados posibles para una verificación de identidad: aprobado, rechazado o revisión manual. Cuando empezamos a integrar el flujo contra su sandbox real, los estados que efectivamente llegaban por webhook eran Approved, Declined e In Review —nombres distintos a los que habíamos usado para diseñar nuestra propia máquina de estados.

Paramos, revisamos el comportamiento real del proveedor y ajustamos el modelo para reflejarlo: agregamos el estado manual_review, que se resuelve solo cuando llega el webhook con el resultado final, o que se puede consultar activamente contra la API de Didit si esa notificación nunca llega. Fue medio día de trabajo extra, pero mejor eso que lanzar con un caso sin contemplar.

Lo que aprendimos

Cuando algo depende del comportamiento de un tercero, conviene validarlo contra el entorno real del proveedor antes de darlo por cerrado. La documentación es un punto de partida, no la última palabra.

Y cuando en el camino encontramos una decisión de seguridad que había quedado abierta —en este caso, dos rutas de verificación de identidad que no exigían estar autenticado y aceptaban un id de usuario adivinable en la URL— la cerramos en el mismo sprint, en vez de anotarla como deuda técnica para después.

Qué sigue

Con la identidad resuelta pasamos al módulo de Ejecución del Envío: que un emisor pueda publicar un envío y que quien lo recibe pueda confirmarlo.

Siguiente devlog

Devlog: ya se puede crear y gestionar un envío en Movo (transportarlo es otra historia)

Movo llega pronto

La app está en desarrollo. Seguinos en Instagram para enterarte cuando esté disponible.

Seguir en Instagram