### Goal Replace the **"Load more"** button on the Elements page with **pagination** (Previous / Next), where only the current page is shown. ### Why Sustainability. "Load more" adds every page to one list, so after scrolling far down the browser holds (and renders) hundreds or thousands of rows. With pagination the browser holds one page at a time, no matter how large the catalog grows. The assignment accepts either paging or dynamic loading. ### Does the backend need to change? **Not for Previous / Next.** The backend stays cursor-based (keyset), which is also what keeps deep pages as cheap as the first. - `searchCatalog` already takes `first` and `after` and returns `pageInfo { hasNextPage, endCursor }` and an opaque `cursor` per edge. There is no `before`, `last` or `hasPreviousPage`. - Going **back** needs no API change: the cursor that started a page is the `endCursor` of the page before it, so the frontend keeps a small stack of cursors (text only, no rows) and re-requests the earlier page. **Yes, if we want more than that.** Jumping to page N, a numbered page list, or "last page" cannot be done with keyset cursors without either offset paging (slower the deeper you go, which we rejected) or a `before`/`last` extension of the API. `totalCount` is also capped at 1001, so "page X of Y" is only exact for small results. Decide, and write the reason down: - [ ] **Recommended:** Previous / Next plus "Page N" (the number of the current page). No backend change. - [ ] Only if needed: numbered pages / last page, with the backend change and the effect on scalability documented in `docs/API.md`. ### What to do - [ ] Pagination control below the results: Previous and Next buttons (disabled when there is no such page), the current page number, as a `<nav aria-label="Pagination">`. - [ ] Keep the stack of cursors per search. A new search, filter or sort starts at page 1 and clears it. - [ ] **Do not keep old pages in memory.** `src/lib/apollo/cache.ts` now merges every page into one list (the `merge` function for `searchCatalog`). Change it so a page replaces the previous one (include `after` in the cache key or drop the merge), and check that old pages do not pile up in the Apollo cache. Measure that the number of rows held stays at one page after paging through ten pages. - [ ] Remove the `fetchMore` / "Load more" code and its error state; show errors for a failed page with a retry. - [ ] The page number in the address (`?page=`) cannot restore a cursor after a reload; decide the behaviour (for example reload goes to page 1) and write it down. - [ ] Accessibility: after changing page, move focus to the results heading (or the top of the table) and announce "Page N, showing X results" in a `role="status"` region; buttons have clear names; works with the keyboard only. - [ ] Update the tests: the Elements page component tests and `e2e/elements-flow.e2e.ts` (which clicks "Load more"). ### Documentation (required) - [ ] **Update `docs/SUSTAINABILITY.md`** with this change: why pagination, what is held in the browser, and the measured numbers before and after (rows in the DOM, memory or cache size after paging through many pages). - [ ] Update the README sections that describe "Load more" (the Elements page and the catalog search) and `docs/API.md` if it mentions it. - [ ] Add an entry to `docs/AI_USAGE.md`. ### Done when - [ ] Paging forward and back works, and only one page of rows is rendered and cached. - [ ] Lint, type check, component tests, e2e tests and build pass. - [ ] The sustainability document is updated with the measurement. _Text written with Claude Code in discussion with Ronja_