Skip to content

feat(api): geocode member city/region to lat/long on save #1972

@cdcore09

Description

@cdcore09

Summary

profiles already has city, region, countryId, latitude, longitude, and showOnMap columns, but latitude/longitude are never populated automatically — they exist only because someone manually wrote to them. A geocoding pipeline should run on profile address changes so map placement just works.

Requirements

  • On PATCH /me/profile (packages/api/src/routes/me.ts): when city, region, or countryId changes, enqueue or inline-call a geocoder
  • On PATCH /admin/users/:id (packages/api/src/routes/admin/users/byId.ts): same trigger when an admin edits the address fields
  • Geocoded values write to profiles.latitude / profiles.longitude; if the geocode fails (no result, rate-limited, network error) the existing lat/long stays put and we log the failure
  • A nullable profiles.geocoded_at timestamp records the last successful geocode — distinguishes "never tried" from "tried, no result"
  • Backfill script packages/api/scripts/geocode-profiles.ts for the existing roster: iterate over profiles with city + country and no lat/long
  • Geocoder choice (Nominatim vs Mapbox) decided in coordination with feat(admin): add addresses + geocoding to organizations #1969 — orgs and members should use the same one

Context

profiles.{city, region, countryId, latitude, longitude} already exist (packages/api/src/db/schema/users.ts:103-115). The map plumbing on the web app reads these — populating them is the missing link.

Pairs with #1969 (org-side addresses + geocoding) — same pipeline serves both.

Implementation Notes

Nominatim has a 1 req/sec public rate limit + a User-Agent header requirement; that's plenty for an admin PATCH but means the backfill script needs a setTimeout delay between calls. Mapbox is faster but needs an API key + budget. Decide once for both #1969 and this issue and reuse the same lib/geocode.ts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions