Cuando alguien guarda un punto en un mapa de pesca, lo normal es que quiera dos cosas a la vez, y en apariencia contradictorias: que la app recuerde el sitio exacto donde lanzó, y que ese sitio no quede expuesto si algún día decide compartir algo relacionado con ese punto. Resolver esa tensión no es una cuestión de interfaz, es una cuestión de modelo de datos. Este artículo no incluye coordenadas reales de ningún punto: todos los valores que aparecen aquí son ilustrativos.

La idea central es sencilla de enunciar y bastante más trabajosa de aplicar bien: la coordenada exacta y la coordenada que se muestra no pueden ser el mismo campo. Tienen que ser dos representaciones distintas del mismo hecho, con reglas propias sobre quién puede ver cada una.

Por qué no basta con "ocultar" el dato

La primera tentación es pensar que basta con un campo booleano tipo es_privado y, si es true, no mostrar el punto en el mapa general. Funciona mientras nadie necesite compartir nada relacionado con ese punto. En cuanto aparece cualquier función social —compartir con un amigo, publicar una captura, aportar a un grupo—, ese enfoque binario se queda corto: hay un término medio entre "nadie lo ve" y "se ve exacto", y ese término medio es donde vive casi todo el valor real de la función.

El modelo: coordenada base y coordenada de presentación

En la práctica separo dos conceptos en el modelo de datos:

  • Coordenada base: la posición real, guardada con la precisión que capturó el dispositivo. Esta nunca se expone directamente en ninguna respuesta pública de la API.
  • Coordenada de presentación: un valor derivado, calculado a partir de la base, que es el único que puede llegar a mostrarse fuera del ámbito privado del propietario.

La coordenada de presentación no es simplemente la base con menos decimales. Redondear una coordenada reduce la precisión aparente, pero si el punto cae cerca de un accidente geográfico único —una única laguna pequeña, un único recodo de un río— el redondeo no oculta gran cosa. Por eso la presentación se calcula como una zona (un centro más un radio mínimo) en lugar de un punto más impreciso, de forma que la incertidumbre real sea consistente independientemente del entorno.

Ejemplo práctico simplificado

Supongamos una coordenada base de ejemplo, puramente ilustrativa: 40.0000, -3.0000. Si un usuario decide compartir ese punto como "zona aproximada", el sistema no publica una versión con menos decimales de esos mismos números. En su lugar, genera un centro desplazado de forma controlada dentro de un radio mínimo definido (por ejemplo, unos cientos de metros, el valor exacto depende del contexto de uso) y publica ese centro junto con el radio, para que quien lo vea entienda que se trata de una zona y no de un punto exacto.

Ese desplazamiento no es aleatorio sin control: tiene que mantenerse dentro de un rango que siga siendo útil para el destinatario, pero no tan amplio que pierda todo el sentido de compartir la zona. Encontrar ese equilibrio es más un ajuste de producto que un problema puramente matemático.

Quién puede ver qué

La separación de datos no sirve de nada si los permisos no la respetan. La coordenada base solo se envía al dispositivo del propietario, autenticado, y nunca aparece en respuestas que puedan llegar a otros usuarios o a vistas públicas. La coordenada de presentación es la única candidata a exponerse, y solo cuando el propietario decide explícitamente compartir ese punto en algún nivel.

Esto obliga a revisar cada endpoint que toque puntos guardados y preguntarse, uno por uno: ¿esta respuesta puede llegar a un cliente que no sea el propietario? Si la respuesta es sí, la coordenada base no puede estar en ese payload, ni siquiera "por error" en un campo de depuración olvidado.

Qué implica esto para la base de datos

Separar ambos conceptos no es solo una cuestión de qué campo se envía en una respuesta: también afecta a cómo se guardan los datos. Mantengo la coordenada base y los parámetros de la coordenada de presentación —centro desplazado y radio— como columnas distintas, no como un único valor que se transforma sobre la marcha cada vez que se necesita. Esto tiene un coste de almacenamiento algo mayor, pero evita recalcular el desplazamiento en cada consulta y, sobre todo, evita que un cambio futuro en la fórmula de cálculo altere silenciosamente puntos que ya se habían compartido con una representación concreta.

Cuando migré los puntos que ya existían con el modelo anterior, tuve que generar la coordenada de presentación para cada uno como un paso explícito de migración, revisando antes que ningún punto quedara sin ese valor calculado. Un punto con coordenada de presentación vacía es, en la práctica, un punto que no debería poder compartirse todavía, y así lo trata el propio código: si ese campo no existe, la función de compartir se bloquea en lugar de recurrir por error a la coordenada base.

Límites y errores frecuentes

El error más fácil de cometer es calcular la coordenada de presentación en el cliente a partir de la base recibida del servidor, pensando que así se ahorra una llamada. Esto anula toda la protección: si la coordenada base llega al dispositivo en cualquier momento, ya no importa lo que se haga después con ella en pantalla. La derivación tiene que ocurrir en el servidor, antes de que el dato salga hacia una vista no privada.

Otro límite real: los metadatos. Una foto asociada a un punto puede llevar información de ubicación en el archivo, aunque la coordenada mostrada en el mapa esté bien protegida. Separar coordenadas no sustituye a revisar el resto del contenido asociado a un punto.

Conclusión

Separar la coordenada privada de su representación pública no es un capricho de arquitectura, es la pieza que permite que una app de pesca ofrezca funciones sociales sin traicionar la confianza de quien guardó el punto. El trabajo importante no está en el cálculo del desplazamiento, sino en garantizar que la coordenada exacta nunca sale del ámbito privado por ningún camino, ni directo ni indirecto. Sobre cómo compruebo esto antes de dar por buena cualquier función que toque datos sensibles, escribo más en qué pruebas hago antes de tocar datos sensibles.