--- convoy: pricing-online-local brief_number: 11 depends_on: [10] recommended_model: composer-2.5 model_tier: standard files: - pages/api/stores/nearby.js - lib/rate-limit.js - test/api/stores-nearby.test.js --- # Brief 11: Stores nearby API ## Goal (1 sentence) Ship `GET /api/stores/nearby` with geocode + Overpass lookup, caching, and per-user refresh rate limit. ## Files in scope (do not edit anything else) - `pages/api/stores/nearby.js` - `lib/rate-limit.js` - `test/api/stores-nearby.test.js` ## Conventions to follow - **Auth required** (`getUserFromRequest` → 401). Zip from user's saved `home_zip` only — ignore arbitrary `zip` query param (security planning decision A). - Add `stores` limiter: 1/hour/user; IP backstop for burst abuse. - Respect `PRICING_LOCAL_ENABLED` — return 503 when `false`. - Overpass fixed-template query only (see Brief 10). ## Acceptance criteria - [ ] Endpoint returns store list for authenticated user with saved zip - [ ] 401 without Bearer token - [ ] Second call within 7 days serves from `geo_stores_cache` - [ ] Rate limit returns 429 with `Retry-After` - [ ] Tests pass - [ ] No scope expansion ## Rationale (≤3 sentences) Phase 2 API surface from convoy spec. Auth-gated zip prevents geocode relay abuse. Rate limiting protects Overpass.