La arquitectura detrás de Entre Diagonales
React Native, Django, Railway e inteligencia artificial: así dividimos las responsabilidades de un producto que debía coordinar cámara, ubicación, progreso, mapas y reconocimiento visual.
Cuando empezamos a construir Entre Diagonales, la arquitectura parecía sencilla: una aplicación móvil consume una API, y la API guarda datos.
La idea duró poco.
La aplicación debía saber dónde estaba cada persona, capturar imágenes, mostrar mapas, calcular progreso, validar desafíos, procesar reconocimiento visual y mantener coherente un sistema de recompensas. Cada una de esas tareas tenía necesidades distintas y no podía resolverse bien desde un único lugar.
Por eso tomamos una decisión que terminó ordenando todo el proyecto: separar responsabilidades desde el comienzo.
Tres capas para un producto que ocurre en la ciudad
Pensamos Entre Diagonales en tres bloques principales:
- la aplicación móvil, donde sucede la experiencia de exploración;
- el backend, donde se validan las reglas y se conserva el estado del sistema;
- los servicios de reconocimiento visual y mapas, que aportan capacidades especializadas cuando hacen falta.
No es una arquitectura exótica. Esa era justamente una ventaja.
No buscábamos diseñar una infraestructura llamativa, sino una solución que pudiéramos entender, probar y evolucionar mientras el producto cambiaba.
La aplicación móvil: el lugar donde ocurre la experiencia
Para el cliente elegimos React Native con Expo. El tipo de producto hacía que la decisión fuera bastante natural: Entre Diagonales depende de capacidades nativas del teléfono, como la cámara, la geolocalización, las notificaciones, los efectos hápticos, los mapas y el almacenamiento local.
React Native nos permitió mantener una única base de código, mientras que Expo simplificó la integración con muchas de esas funciones del dispositivo.
Pero desde el principio intentamos que el cliente tuviera una responsabilidad muy clara: representar la experiencia, no decidir las reglas críticas del juego.
El teléfono puede solicitar completar una parada, pero no debería decidir por sí solo que esa parada fue completada. Puede enviar una fotografía, pero no debería asignarse una recompensa solo porque la interfaz considere correcta la captura.
Esa distinción nos llevó al backend.

Django como árbitro del sistema
El servidor fue desarrollado con Django y Django REST Framework. Necesitábamos un backend con mucha lógica relacional: usuarios, niveles, personajes, recorridos, paradas, trivias, respuestas, objetos secretos, logros, notificaciones y progreso.
Además, el componente de inteligencia artificial está construido dentro del ecosistema Python. Mantener ambos mundos cerca simplificó la integración.
El backend terminó funcionando como el árbitro central del sistema. Allí viven reglas como estas:
- si una persona puede completar una parada;
- si ya respondió una trivia;
- qué recompensa corresponde a una acción;
- si está lo suficientemente cerca de un punto;
- si una predicción visual supera el umbral de confianza requerido;
- cómo se actualiza la experiencia y el nivel.
La interfaz propone una acción. El servidor decide si esa acción es válida.
Esta decisión evita confiar en un cliente que, por definición, está bajo el control de quien usa el dispositivo.
El flujo que concentra la idea del proyecto
El reconocimiento de una parada es probablemente el mejor ejemplo de cómo se reparten las responsabilidades.
- La persona llega a un punto del recorrido y toma una fotografía.
- La app envía la imagen y la información necesaria a la API.
- Antes de ejecutar el modelo, el servidor verifica que la ubicación esté dentro del rango permitido.
- Si esa regla se cumple, el backend preprocesa la imagen y ejecuta el reconocimiento visual.
- Con la clasificación y su nivel de confianza, el servidor decide si valida la acción y actualiza el progreso.
La inteligencia artificial aparece relativamente tarde en el flujo, y es intencional. No tenía sentido consumir recursos ejecutando el modelo si la persona estaba lejos del lugar que intentaba validar.
Primero se comprueba la ubicación. Después, si corresponde, se infiere sobre la imagen.
Una regla de producto terminó convirtiéndose también en una optimización técnica.
Por qué la inteligencia artificial no vive en el teléfono
En la primera versión decidimos ejecutar el modelo del lado del servidor. La aplicación toma una imagen y la envía a la API; el backend la preprocesa, ejecuta el modelo correspondiente y recibe una clasificación junto con su nivel de confianza.
Durante el prototipado, este enfoque nos daba ventajas concretas:
- reduce la dependencia del hardware de cada dispositivo;
- permite actualizar modelos sin publicar una nueva versión de la app;
- centraliza la lógica de validación;
- deja trazabilidad sobre los reconocimientos;
- conecta directamente el resultado del modelo con las reglas del producto.
El costo también era claro: el flujo requiere conexión a Internet y suma una solicitud a la API. Para esta etapa del proyecto, ese intercambio tenía sentido.
Infraestructura simple, decisiones deliberadas
Para desplegar el backend utilizamos Railway. La elección fue pragmática: no necesitábamos una plataforma pensada para millones de usuarios; necesitábamos validar un producto funcional sin convertir la infraestructura en el centro del proyecto.
Railway nos permitió desplegar el servidor rápidamente y mantener un ciclo de desarrollo simple. La decisión expresa una idea que atravesó todo el trabajo:
La arquitectura debía resolver el problema que teníamos, no el problema que quizá tendríamos dentro de cinco años.
Es muy fácil sobrediseñar un prototipo. Resistir esa tentación suele ser más valioso.
Mapas: calcular localmente, pedir rutas cuando hacen falta
Los mapas y las rutas requerían otro tratamiento. Involucran servicios externos, ubicación en tiempo real y, potencialmente, muchas solicitudes.
En lugar de delegar todo a una API de mapas, combinamos cálculos locales de distancia mediante la fórmula de Haversine con servicios de ruteo para obtener trazados solo cuando son necesarios.
La aplicación no recalcula una ruta ante cada pequeño cambio de GPS. Reserva las actualizaciones para eventos relevantes, como un cambio de parada o un desplazamiento significativo. Así reducimos solicitudes y mejoramos el rendimiento.
Una vez más, la solución no fue agregar infraestructura: fue decidir mejor cuándo usarla.
La decisión más importante no fue una tecnología
Esta separación nos permitió evolucionar cada componente sin reescribir los demás. Podemos cambiar el modelo de inteligencia artificial sin modificar la navegación móvil; ajustar una regla de gamificación en Django sin publicar una nueva versión de la app; u optimizar imágenes y animaciones del cliente sin alterar el reconocimiento visual.
En un proyecto que mezcla ciudad, turismo, juego y visión por computadora, esa independencia resultó más valiosa que cualquier tecnología concreta.
React Native, Django, Railway o MobileNetV2 son decisiones reemplazables. La decisión de fondo fue otra:
definir con claridad quién es responsable de qué.
En el próximo artículo vamos a profundizar en la parte más experimental del proyecto: por qué elegimos reconocimiento visual en lugar de códigos QR y cómo llegamos a MobileNetV2, aun cuando no era el modelo con la métrica más alta.