Pre-seed McDonald's locations + smart proximity endpoint #20

Closed
opened 2026-03-18 06:52:56 +00:00 by forgejo_admin · 0 comments
Contributor

Lineage

todo-mcd-preseed-locations + todo-mcd-smart-proximity (lightweight work, no plan phase)

Repo

forgejo_admin/mcd-tracker-api

User Story

As a user tapping "Near Me"
I want to see nearby McDonald's instantly
So that I don't wait for a flaky external API that times out

Context

The /locations/nearby endpoint currently calls the Overpass API (OpenStreetMap) in real-time for every request. Overpass is a free public service that rate-limits and times out frequently — we're seeing 504s on 25km radius queries, which surface as 503s to the user.

McDonald's locations are essentially static (~13k in the US, change rate: a few dozen per year). Querying a live external API for static data on every request is architecturally wrong.

Decision: pre-seed McDonald's locations into Postgres and query locally. Overpass becomes a seed/refresh tool, never called at runtime.

The haversine_distance function already exists in services/geo.py. The _find_saved_match logic in routes/nearby.py already cross-references OSM results with user's saved locations — this stays, just reads from Postgres instead of Overpass.

File Targets

Files to create:

  • src/mcd_tracker_api/models.py — add McDonaldsLocation model (osm_id, name, address, city, state, lat, lng)
  • alembic/versions/xxx_add_mcdonalds_locations.py — migration for the new table
  • src/mcd_tracker_api/scripts/seed_locations.py — one-time batch Overpass query, upsert into Postgres

Files to modify:

  • src/mcd_tracker_api/routes/nearby.py — refactor to query mcdonalds_locations table instead of calling Overpass at runtime. Keep NearbyResponse schema unchanged so frontend doesn't break.
  • src/mcd_tracker_api/services/overpass.py — keep as-is (used by seed script only, no longer imported by routes)

Files NOT to touch:

  • src/mcd_tracker_api/routes/locations.py — saved locations logic is separate
  • src/mcd_tracker_api/routes/codes.py — unrelated
  • Frontend repos — response shape stays the same

Acceptance Criteria

  • mcdonalds_locations table exists with osm_id unique index and lat/lng columns
  • Seed script successfully populates table from Overpass (Denver metro or wider)
  • Seed script is idempotent (upsert on osm_id — safe to re-run)
  • GET /locations/nearby?lat=X&lng=Y&radius=N returns locations from Postgres, sorted by distance
  • Response schema is unchanged (NearbyResponse with NearbyLocation items)
  • Saved location matching still works (cross-reference with user's saved locations)
  • No Overpass API call happens at runtime (only during seed)
  • Existing 144 tests still pass

Test Expectations

  • Unit test: seed script parses Overpass response and inserts rows correctly
  • Integration test: /locations/nearby returns locations sorted by distance from seeded data
  • Integration test: saved location matching works against seeded data
  • Integration test: empty table returns empty list (graceful degradation)
  • Integration test: radius filtering works correctly
  • Run command: pytest tests/ -v

Constraints

  • Match existing route style in routes/nearby.py
  • Use existing haversine_distance from services/geo.py — don't add PostGIS
  • Seed script should use the existing Overpass client in services/overpass.py (may need a wider-radius query function)
  • Keep NearbyResponse and NearbyLocation schemas unchanged
  • The seed radius should be configurable (default: Denver metro ~50km, but allow full-US ~nationwide)
  • Alembic migration must be reversible (downgrade drops the table)

Checklist

  • PR opened
  • Tests pass
  • No unrelated changes
  • project-mcd-tracker — project this affects
  • todo-mcd-preseed-locations — pal-e-docs TODO
  • todo-mcd-smart-proximity — pal-e-docs TODO
  • services/geo.py — existing haversine function
  • services/overpass.py — existing Overpass client (becomes seed-only)
### Lineage `todo-mcd-preseed-locations` + `todo-mcd-smart-proximity` (lightweight work, no plan phase) ### Repo `forgejo_admin/mcd-tracker-api` ### User Story As a user tapping "Near Me" I want to see nearby McDonald's instantly So that I don't wait for a flaky external API that times out ### Context The `/locations/nearby` endpoint currently calls the Overpass API (OpenStreetMap) in real-time for every request. Overpass is a free public service that rate-limits and times out frequently — we're seeing 504s on 25km radius queries, which surface as 503s to the user. McDonald's locations are essentially static (~13k in the US, change rate: a few dozen per year). Querying a live external API for static data on every request is architecturally wrong. Decision: pre-seed McDonald's locations into Postgres and query locally. Overpass becomes a seed/refresh tool, never called at runtime. The `haversine_distance` function already exists in `services/geo.py`. The `_find_saved_match` logic in `routes/nearby.py` already cross-references OSM results with user's saved locations — this stays, just reads from Postgres instead of Overpass. ### File Targets Files to create: - `src/mcd_tracker_api/models.py` — add `McDonaldsLocation` model (osm_id, name, address, city, state, lat, lng) - `alembic/versions/xxx_add_mcdonalds_locations.py` — migration for the new table - `src/mcd_tracker_api/scripts/seed_locations.py` — one-time batch Overpass query, upsert into Postgres Files to modify: - `src/mcd_tracker_api/routes/nearby.py` — refactor to query `mcdonalds_locations` table instead of calling Overpass at runtime. Keep `NearbyResponse` schema unchanged so frontend doesn't break. - `src/mcd_tracker_api/services/overpass.py` — keep as-is (used by seed script only, no longer imported by routes) Files NOT to touch: - `src/mcd_tracker_api/routes/locations.py` — saved locations logic is separate - `src/mcd_tracker_api/routes/codes.py` — unrelated - Frontend repos — response shape stays the same ### Acceptance Criteria - [ ] `mcdonalds_locations` table exists with osm_id unique index and lat/lng columns - [ ] Seed script successfully populates table from Overpass (Denver metro or wider) - [ ] Seed script is idempotent (upsert on osm_id — safe to re-run) - [ ] `GET /locations/nearby?lat=X&lng=Y&radius=N` returns locations from Postgres, sorted by distance - [ ] Response schema is unchanged (`NearbyResponse` with `NearbyLocation` items) - [ ] Saved location matching still works (cross-reference with user's saved locations) - [ ] No Overpass API call happens at runtime (only during seed) - [ ] Existing 144 tests still pass ### Test Expectations - [ ] Unit test: seed script parses Overpass response and inserts rows correctly - [ ] Integration test: `/locations/nearby` returns locations sorted by distance from seeded data - [ ] Integration test: saved location matching works against seeded data - [ ] Integration test: empty table returns empty list (graceful degradation) - [ ] Integration test: radius filtering works correctly - Run command: `pytest tests/ -v` ### Constraints - Match existing route style in `routes/nearby.py` - Use existing `haversine_distance` from `services/geo.py` — don't add PostGIS - Seed script should use the existing Overpass client in `services/overpass.py` (may need a wider-radius query function) - Keep `NearbyResponse` and `NearbyLocation` schemas unchanged - The seed radius should be configurable (default: Denver metro ~50km, but allow full-US ~nationwide) - Alembic migration must be reversible (downgrade drops the table) ### Checklist - [ ] PR opened - [ ] Tests pass - [ ] No unrelated changes ### Related - `project-mcd-tracker` — project this affects - `todo-mcd-preseed-locations` — pal-e-docs TODO - `todo-mcd-smart-proximity` — pal-e-docs TODO - `services/geo.py` — existing haversine function - `services/overpass.py` — existing Overpass client (becomes seed-only)
Commenting is not possible because the repository is archived.
No labels
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ldraney/mcd-tracker-api#20
No description provided.