Saltar al contenido principal

Ubicación y Cercanía — Referencia técnica

← Volver a Ubicación y Cercanía

Dónde vive esto

Backend

Frontend

Bugs reales corregidos al construir esto

user-location.manager.js llamaba a cuatro métodos de user-location.access-service.jsfindByUserId, getAll, getByCity, getByCountry — que no existían en esa clase (solo tenía findById/findByUser/create/update/updateByUser/delete). Cualquier método del manager que tocara datos de ubicación (getLocation, updateLocation, deleteLocation, getNearbyUsers, searchByLocation, getPopularLocations) habría lanzado TypeError: ...is not a function en su primera llamada real. Se agregaron los cuatro métodos faltantes como envoltorios simples.

getNearbyUsers devolvía las coordenadas exactas de todos los usuarios sin ningún filtro de privacidad, aunque UserLocation.isPublic viene en false por defecto precisamente para que la ubicación de un usuario no se comparta hasta que decida activarlo — una fuga de privacidad real si esto se hubiera publicado tal cual estaba escrito. Se corrigió para filtrar por isPublic === true.

canSeeLocation() y setLocationPrivacy() están sin terminar — canSeeLocation son tres comentarios // TODO que siempre return true, y setLocationPrivacy escribe en una columna privacy_level que no existe en el modelo UserLocation (Sequelize descarta silenciosamente los atributos desconocidos en .update(), así que era un no-op silencioso). Ninguno de los dos se expone en esta capa de GraphQL — isPublic (un booleano simple) es el único control de privacidad de ubicación que el modelo realmente persiste y aplica. Un sistema de tres niveles público/amigos/privado, si se quiere más adelante, necesita primero una columna real y una aplicación real en canSeeLocation.

updateLocation antes nunca tocaba isPublic en absoluto (siempre lo dejaba en el valor por defecto false del modelo al crearse, nunca lo actualizaba) y escribía en una columna accuracy que no existe. Se corrigió para aceptar y persistir isPublic.

Checklist de implementación técnica

  • myLocation / updateMyLocation / deleteMyLocation — conectado; LocationSharingPage.tsx
  • nearbyUsers — conectado, filtrado solo a quienes activaron isPublic: true; usado por la lista "People nearby" de LocationSharingPage.tsx y por la sección "Cerca de ti" de DiscoverPeoplePage.tsx (RecommendationsSection.tsx también tiene una pestaña de cercanos, pero su barra de pestañas está actualmente oculta, por lo que esa ruta no es accesible desde la interfaz)
  • Feed local por radio (getLocalFeed en el manager) — no expuesto en GraphQL
  • Búsqueda por ciudad/país o coordenadas (searchByLocation en el manager) — no expuesto en GraphQL
  • Ubicaciones populares y estadísticas (getPopularLocations/getLocationStats en el manager) — no expuesto en GraphQL
  • Privacidad de ubicación por niveles (público/amigos/privado) — setLocationPrivacy/canSeeLocation son stubs sin terminar; hoy solo existe un interruptor binario isPublic real
  • El envío de ubicación estática dentro de los mensajes de chat (shareLocation) es una función aparte que ya está conectada — la acción rápida "share location" del compositor en ChatView.tsx (handleShareLocation) la invoca, y MessageBubble.tsx renderiza el mensaje de ubicación resultante. Los resolvers de transmisión de ubicación en vivo (updateLiveLocation/stopLiveLocation) también existen en message.resolver.js, pero nada en el frontend los invoca todavía y LocationInput sigue sin tener un campo locationType para marcar un mensaje como en vivo; ver Mensajes y Conversaciones

Modelo UserLocation

CampoDescripción
latitude / longitudeCoordenadas (WGS84), DECIMAL(10,8)/DECIMAL(11,8)
city / countryUbicación legible (opcional, no se geocodifica en reversa del lado del servidor — el frontend no los envía hoy)
isPublicBooleano, false por defecto. El único control de privacidad que realmente se aplica.

Compartir y actualizar ubicación

mutation UpdateMyLocation($input: UpdateLocationInput!) {
updateMyLocation(input: $input) { id city country latitude longitude isPublic updatedAt }
}

query MyLocation { myLocation { id city country latitude longitude isPublic updatedAt } }

mutation DeleteMyLocation { deleteMyLocation }

UpdateLocationInput: latitude: Float!, longitude: Float!, city: String, country: String, isPublic: Boolean (por defecto false/privado en el primer envío si se omite). Llama a updateMyLocation de nuevo con las mismas coordenadas para simplemente alternar isPublic sin volver a pedir el permiso de geolocalización del navegador.

Usuarios cercanos

query NearbyUsers($radiusKm: Float, $limit: Int) {
nearbyUsers(radiusKm: $radiusKm, limit: $limit) {
user { id username profilePicture isVerified }
distanceKm
city
}
}

Requiere que quien llama ya haya compartido su propia ubicación (myLocation debe ser distinto de null) — si no, nearbyUsers devuelve []. Solo devuelve a otros usuarios con isPublic: true, ordenados por distancia, calculada con la fórmula de Haversine en user-location.manager.js#calculateDistance.