Problem
src/app/issues/page.tsx renders the bounty board — presumably the highest-traffic, most performance-sensitive route since it's the primary discovery surface for contributors per the README's feature map. fetchBounties in src/lib/api.ts has no pagination, filtering, or sorting parameters — it fetches the entire /bounties collection in one call every time the page renders. As the platform grows past a small demo dataset, this becomes a scaling problem on multiple axes simultaneously: unbounded server-side payload size and Server Component render time, no way for a contributor to filter by difficulty/asset/repo/reward-range without client-side filtering of an already-fully-loaded dataset (wasteful and eventually infeasible), and no URL-shareable filter/sort state (a contributor can't bookmark or share "beginner USDC bounties over $50" as a link).
Why this is hard
- This requires designing a pagination/filtering contract against a backend (
mergefi-backend) that, per the currently visible frontend code, has no evidence of supporting query params on /bounties at all — you need to either verify the backend already supports this (check the mergefi/backend repo) or explicitly scope this as a paired frontend+backend change and design the frontend to degrade sensibly if backend support lands later.
- Filter/sort state needs to live in the URL (Next.js
searchParams in the Server Component) for shareability and correct back/forward browser navigation, not in client-only React state — this affects whether /issues can remain a Server Component or needs restructuring, since reading searchParams in a Server Component and passing filtered/paginated results down is the correct App Router pattern but requires re-architecting how fetchBounties/adaptBounty are invoked (per-page-load with params, not once with a static fallback).
- The mock-data fallback path (
fetchWithFallback/fetchBounties's catch-and-return-fallback) needs to also respect the same filter/sort/pagination params against mock-data.ts so the "always demoable without a backend" property from the README isn't broken by this change — i.e. mock-data.ts needs in-memory filter/sort/paginate logic mirroring what the backend would do.
- Must design sensible defaults and limits (page size, max sortable fields) and handle edge cases: filters that produce zero results, invalid/out-of-range page numbers in the URL, combining multiple simultaneous filters.
Scope
- Design and document the pagination/filter/sort query contract (params, defaults, limits).
- Update
fetchBounties (and request) to accept and forward these params to the backend.
- Add equivalent in-memory filter/sort/pagination logic for the
mock-data.ts fallback path so demos remain fully functional offline.
- Restructure
src/app/issues/page.tsx to read searchParams, pass them through, and render filter/sort controls that update the URL (not just local state).
- Add an empty-state and invalid-page-number handling (e.g. clamp or redirect to a valid page).
- Coordinate/document the required backend contract as a note in the PR if backend support doesn't yet exist.
Acceptance criteria
- Filtering and sorting the bounty board produces a shareable, bookmarkable URL that reproduces the same filtered view on reload.
- The page works fully (with correct filtering/sorting/pagination) against mock data with no backend running.
- Invalid page/filter query params degrade gracefully rather than erroring the page.
Problem
src/app/issues/page.tsxrenders the bounty board — presumably the highest-traffic, most performance-sensitive route since it's the primary discovery surface for contributors per the README's feature map.fetchBountiesinsrc/lib/api.tshas no pagination, filtering, or sorting parameters — it fetches the entire/bountiescollection in one call every time the page renders. As the platform grows past a small demo dataset, this becomes a scaling problem on multiple axes simultaneously: unbounded server-side payload size and Server Component render time, no way for a contributor to filter by difficulty/asset/repo/reward-range without client-side filtering of an already-fully-loaded dataset (wasteful and eventually infeasible), and no URL-shareable filter/sort state (a contributor can't bookmark or share "beginner USDC bounties over $50" as a link).Why this is hard
mergefi-backend) that, per the currently visible frontend code, has no evidence of supporting query params on/bountiesat all — you need to either verify the backend already supports this (check themergefi/backendrepo) or explicitly scope this as a paired frontend+backend change and design the frontend to degrade sensibly if backend support lands later.searchParamsin the Server Component) for shareability and correct back/forward browser navigation, not in client-only React state — this affects whether/issuescan remain a Server Component or needs restructuring, since readingsearchParamsin a Server Component and passing filtered/paginated results down is the correct App Router pattern but requires re-architecting howfetchBounties/adaptBountyare invoked (per-page-load with params, not once with a static fallback).fetchWithFallback/fetchBounties's catch-and-return-fallback) needs to also respect the same filter/sort/pagination params againstmock-data.tsso the "always demoable without a backend" property from the README isn't broken by this change — i.e.mock-data.tsneeds in-memory filter/sort/paginate logic mirroring what the backend would do.Scope
fetchBounties(andrequest) to accept and forward these params to the backend.mock-data.tsfallback path so demos remain fully functional offline.src/app/issues/page.tsxto readsearchParams, pass them through, and render filter/sort controls that update the URL (not just local state).Acceptance criteria