Add GPS nearby locations endpoint with Overpass API (OpenStreetMap) #10

Closed
opened 2026-03-16 19:03:44 +00:00 by forgejo_admin · 0 comments
Contributor

Lineage

plan-mcd-tracker → Phase 5 → Phase 5c: GPS Nearby Locations

Repo

forgejo_admin/mcd-tracker-api

User Story

  • auto-location: I want the app to know which McDonald's I'm at without typing

Architecture

  • arch-dataflow-mcd-tracker#flow-5-auto-detect-location — GPS coords → Overpass API → nearest McDonald's list

Context

Phase 5a shipped the Receipt model. The scan flow needs GPS auto-detection to pre-fill the location when a user scans a receipt. This endpoint queries OpenStreetMap's Overpass API to find nearby McDonald's — free, no API key, well-mapped for US chain restaurants.

File Targets

Files to create:

  • src/mcd_tracker_api/services/__init__.py — empty
  • src/mcd_tracker_api/services/overpass.py — Overpass API client using httpx. Query: [out:json]; node["brand"="McDonald's"](around:{radius},{lat},{lng}); out;. Parse response into location list.
  • src/mcd_tracker_api/services/geo.py — Haversine distance calculation (lat/lng → meters/miles)
  • src/mcd_tracker_api/routes/nearby.pyGET /locations/nearby endpoint
  • tests/test_nearby.py — tests with mocked Overpass responses

Files to modify:

  • src/mcd_tracker_api/main.py — register nearby router
  • src/mcd_tracker_api/schemas.py — add NearbyLocation response schema
  • src/mcd_tracker_api/config.py — add overpass_url setting (default: https://overpass-api.de/api/interpreter)

Files NOT to touch:

  • models.py — no schema changes
  • Existing routes — no changes
  • alembic/ — no migration needed

Acceptance Criteria

  • GET /locations/nearby?lat=39.74&lng=-104.99 returns list of nearby McDonald's
  • Each result: name, address (from OSM tags), lat, lng, distance_miles from query point
  • Results sorted by distance ascending
  • Default radius: 5000 meters (configurable via query param)
  • If a nearby McDonald's matches a user's saved location (within 100m), include saved_location_id and slot availability
  • Overpass API errors handled gracefully (timeout → 503, no results → empty list)
  • Auth required (get_current_user)
  • Tests use mocked Overpass responses (no real API calls in CI)
  • Haversine distance is accurate to within 1% for short distances (<50km)

Test Expectations

  • test_nearby.py: mock Overpass returning 3 McDonald's, verify sorted by distance
  • test_nearby.py: mock Overpass returning 0 results, verify empty list
  • test_nearby.py: mock Overpass timeout, verify 503 response
  • test_nearby.py: verify saved location matching (mock a saved location near one of the results)
  • test_nearby.py: verify Haversine calculation accuracy
  • Run: pytest tests/ -v

Constraints

  • Use httpx for Overpass API calls (already a dependency from auth.py JWKS fetch)
  • Overpass API rate limit: be respectful. Cache results for the same coordinates within a short TTL (optional, nice-to-have)
  • Overpass query must filter by brand=McDonald's specifically (not amenity=fast_food which returns all fast food)
  • OSM data quality: addr:street, addr:city tags may be missing on some nodes. Handle gracefully — return coords even if address is incomplete
  • The nearby endpoint is READ-ONLY — it doesn't create locations. Users save locations separately via POST /locations

Checklist

  • PR opened with Closes #9
  • Tests pass (mocked Overpass, real Postgres)
  • Ruff clean
  • No unrelated changes
  • phase-mcd-tracker-5c-gps-nearby — phase note
  • arch-dataflow-mcd-tracker#flow-5-auto-detect-location — data flow
  • plan-mcd-tracker — parent plan
### Lineage `plan-mcd-tracker` → Phase 5 → Phase 5c: GPS Nearby Locations ### Repo `forgejo_admin/mcd-tracker-api` ### User Story - `auto-location`: I want the app to know which McDonald's I'm at without typing ### Architecture - `arch-dataflow-mcd-tracker#flow-5-auto-detect-location` — GPS coords → Overpass API → nearest McDonald's list ### Context Phase 5a shipped the Receipt model. The scan flow needs GPS auto-detection to pre-fill the location when a user scans a receipt. This endpoint queries OpenStreetMap's Overpass API to find nearby McDonald's — free, no API key, well-mapped for US chain restaurants. ### File Targets Files to create: - `src/mcd_tracker_api/services/__init__.py` — empty - `src/mcd_tracker_api/services/overpass.py` — Overpass API client using httpx. Query: `[out:json]; node["brand"="McDonald's"](around:{radius},{lat},{lng}); out;`. Parse response into location list. - `src/mcd_tracker_api/services/geo.py` — Haversine distance calculation (lat/lng → meters/miles) - `src/mcd_tracker_api/routes/nearby.py` — `GET /locations/nearby` endpoint - `tests/test_nearby.py` — tests with mocked Overpass responses Files to modify: - `src/mcd_tracker_api/main.py` — register nearby router - `src/mcd_tracker_api/schemas.py` — add NearbyLocation response schema - `src/mcd_tracker_api/config.py` — add `overpass_url` setting (default: `https://overpass-api.de/api/interpreter`) Files NOT to touch: - models.py — no schema changes - Existing routes — no changes - alembic/ — no migration needed ### Acceptance Criteria - [ ] `GET /locations/nearby?lat=39.74&lng=-104.99` returns list of nearby McDonald's - [ ] Each result: name, address (from OSM tags), lat, lng, distance_miles from query point - [ ] Results sorted by distance ascending - [ ] Default radius: 5000 meters (configurable via query param) - [ ] If a nearby McDonald's matches a user's saved location (within 100m), include `saved_location_id` and slot availability - [ ] Overpass API errors handled gracefully (timeout → 503, no results → empty list) - [ ] Auth required (get_current_user) - [ ] Tests use mocked Overpass responses (no real API calls in CI) - [ ] Haversine distance is accurate to within 1% for short distances (<50km) ### Test Expectations - [ ] test_nearby.py: mock Overpass returning 3 McDonald's, verify sorted by distance - [ ] test_nearby.py: mock Overpass returning 0 results, verify empty list - [ ] test_nearby.py: mock Overpass timeout, verify 503 response - [ ] test_nearby.py: verify saved location matching (mock a saved location near one of the results) - [ ] test_nearby.py: verify Haversine calculation accuracy - Run: `pytest tests/ -v` ### Constraints - Use httpx for Overpass API calls (already a dependency from auth.py JWKS fetch) - Overpass API rate limit: be respectful. Cache results for the same coordinates within a short TTL (optional, nice-to-have) - Overpass query must filter by `brand=McDonald's` specifically (not `amenity=fast_food` which returns all fast food) - OSM data quality: `addr:street`, `addr:city` tags may be missing on some nodes. Handle gracefully — return coords even if address is incomplete - The nearby endpoint is READ-ONLY — it doesn't create locations. Users save locations separately via POST /locations ### Checklist - [ ] PR opened with `Closes #9` - [ ] Tests pass (mocked Overpass, real Postgres) - [ ] Ruff clean - [ ] No unrelated changes ### Related - `phase-mcd-tracker-5c-gps-nearby` — phase note - `arch-dataflow-mcd-tracker#flow-5-auto-detect-location` — data flow - `plan-mcd-tracker` — parent plan
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#10
No description provided.