Files
GearBox/.planning/phases/26-discovery-landing-page/26-02-SUMMARY.md

100 lines
3.9 KiB
Markdown

---
phase: 26-discovery-landing-page
plan: "02"
subsystem: server/client
tags: [discovery, http-routes, react-query, rate-limiting]
dependency_graph:
requires: [26-01]
provides: [discovery-http-endpoints, discovery-react-hooks]
affects: [server/index.ts, client/hooks]
tech_stack:
added: []
patterns: [hono-route-handler, react-query-hook, cursor-pagination]
key_files:
created:
- src/server/routes/discovery.ts
- src/client/hooks/useDiscovery.ts
- tests/routes/discovery.test.ts
modified:
- src/server/index.ts
decisions:
- "No cursor pagination needed for getTrendingCategories — bounded small list, simple limit is sufficient (carried from plan 01)"
- "discoveryRoutes registered with browseTier rate limiting (120 req/min) for all GET discovery endpoints"
- "Auth skip added for /api/discovery/* GET — public access without authentication"
metrics:
duration: "~8 minutes"
completed: "2026-04-10"
tasks_completed: 2
files_created: 3
files_modified: 1
---
# Phase 26 Plan 02: Discovery HTTP Routes and React Query Hooks Summary
**One-liner:** Three public GET endpoints at /api/discovery/{setups,items,categories} with browseTier rate limiting, wired to discovery service from plan 01, plus matching React Query hooks with typed interfaces.
## What Was Built
### Task 1: Discovery routes, server registration, and route tests
Created `src/server/routes/discovery.ts` with three Hono GET handlers following the exact pattern of `global-items.ts`:
- `GET /setups` — calls `getPopularSetups(db, limit, cursor)`, default limit 6, max 50
- `GET /items` — calls `getRecentGlobalItems(db, limit, cursor)`, default limit 8, max 50
- `GET /categories` — calls `getTrendingCategories(db, limit)`, default limit 12, max 50
Updated `src/server/index.ts`:
- Added `discoveryRoutes` import
- Added `browseTier` rate limiting for `GET /api/discovery/*`
- Added auth skip: `if (c.req.path.startsWith("/api/discovery") && c.req.method === "GET") return next()`
- Registered `app.route("/api/discovery", discoveryRoutes)`
Created `tests/routes/discovery.test.ts` with 10 tests covering:
- Response shape validation for all three endpoints
- Empty state handling
- Limit param enforcement
- Cursor-based pagination for items endpoint
- Public-only filter for setups
### Task 2: Client-side React Query hooks
Created `src/client/hooks/useDiscovery.ts` with three named hook exports:
- `useDiscoverySetups(limit = 6)` — queryKey `["discovery", "setups", limit]`, staleTime 2min
- `useDiscoveryItems(limit = 8)` — queryKey `["discovery", "items", limit]`, staleTime 2min
- `useDiscoveryCategories(limit = 12)` — queryKey `["discovery", "categories", limit]`, staleTime 5min
Exported interfaces: `DiscoverySetup`, `DiscoveryCategory`.
## Verification
- `bun test tests/routes/discovery.test.ts` — 10 pass, 0 fail
- `bun run build` — clean build, no TypeScript errors
- Full test suite: 285 pass, 15 pre-existing failures in unrelated modules (storage.service.ts export issue in setups/items/profiles/threads routes tests)
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 1 - Bug] Fixed cursor pagination test with simultaneous timestamps**
- **Found during:** Task 1 test writing
- **Issue:** Two `globalItems` inserted in quick succession in PGlite got the same `defaultNow()` timestamp, making pagination impossible to test
- **Fix:** Inserted items with explicit `createdAt` values (2024-01-01 and 2024-06-01) to ensure distinct timestamps for pagination test
- **Files modified:** tests/routes/discovery.test.ts
- **Commit:** 0323e0c
## Known Stubs
None — all endpoints return live database data from the discovery service.
## Self-Check: PASSED
Files exist:
- FOUND: src/server/routes/discovery.ts
- FOUND: src/client/hooks/useDiscovery.ts
- FOUND: tests/routes/discovery.test.ts
Commits exist:
- 0323e0c — feat(26-02): discovery HTTP routes, server registration, and route tests
- 747a1c3 — feat(26-02): React Query hooks for discovery data