Volver a proyectos

2026 · En producción

Agenda de Ubicaciones

Aplicación móvil con geocercas para guardar lugares y recibir avisos al llegar

Rol: Desarrollo full stack (app móvil + API + ingesta de datos)

Contexto

Los lugares quedaban dispersos entre notas, fotos y mensajes. El proyecto resuelve tres problemas concretos: guardar ubicaciones propias de forma privada, compartir lugares públicos con otros usuarios, y no olvidar un recordatorio al llegar a un sitio.

De un vistazo

pantallas
19
pantallas
líneas TypeScript
5.600+
líneas TypeScript
migraciones de BD
14
migraciones de BD
endpoints REST
26
endpoints REST

Tecnologías

  • React Native
  • Expo SDK 57
  • TypeScript
  • Expo Router
  • Laravel 12
  • MySQL
  • Laravel Sanctum
  • Python
  • MapLibre
  • TanStack Query
  • OpenStreetMap

Lo más destacado

  • Geocercas nativas en segundo plano que notifican al entrar a un lugar y rearma la alarma al salir
  • Búsqueda de lugares cercanos con fórmula de Haversine ejecutada en SQL, con filtro por radio configurable
  • Registro con verificación por código de un solo uso: la cuenta solo se crea tras confirmar el correo
  • Compresión automática de fotografías en el dispositivo para no consumir datos del usuario
  • Eliminación de cuenta que conserva las ubicaciones públicas ya compartidas y borra las privadas
  • Ingesta masiva de lugares desde OpenStreetMap respetando la atribución de licencia
  • Actualizaciones over-the-air sin pasar por la tienda de aplicaciones

El problema técnico más interesante

Las geocercas parecían un requisito sencillo, pero el primer prototipo notificaba en bucle: el sistema disparaba el evento de entrada cada pocos segundos y el usuario recibía notificaciones constantes.

La solución fue un conjunto de identificadores ya disparados que se guarda en almacenamiento local. Al entrar a la geocerca se comprueba si ya se notificó y se omite; al salir, se borra el identificador y la alarma queda rearmada para la próxima visita.

  • La tarea se ejecuta fuera de React, así que no puede leer el estado de la aplicación. Por eso los metadatos del recordatorio se guardan antes de registrar la geocerca.
  • Si el sistema de geocercas no está disponible, el error queda registrado en consola en lugar de fallar en silencio.
  • La app detecta y avisa cuando falta el permiso de ubicación permanente en Android.

Cercanía calculada en la base de datos

En lugar de traer todos los lugares al dispositivo y calcular las distancias en JavaScript, la distancia se calcula en la consulta SQL con la fórmula de Haversine, y se filtra y ordena por ella en el mismo paso.

  • El resultado se acota con least() y greatest() para que un error de punto flotante no devuelva un valor fuera del dominio de la función acos().
  • La distancia mostrada se etiqueta como línea recta, para no confundirla con la distancia de ruta real.

Decisiones documentadas con su porqué

Cada decisión no obvia quedó escrita junto al código, junto al problema que resolvió. Por ejemplo: por qué la subida de archivos usa XMLHttpRequest y no fetch; por qué la llave de correo se lee desde config() y no desde env(); por qué el enlace de recuperación de contraseña necesita una página web intermedia.

Ese último caso es un buen ejemplo. Los bloqueadores de correo no permiten abrir enlaces con esquemas de aplicación, así que el enlace apunta a una página web que después redirige a la aplicación.

Ver aplicación