Summary
The service list uses offset pagination, which skips/duplicates rows when data changes mid-scan and degrades on large offsets. Replace it with opaque-cursor pagination with a stable total order.
Why this matters
Offset pagination is incorrect under concurrent writes and slow at scale. Cursors give stable, efficient, resumable iteration.
Requirements
- Add opaque-cursor pagination to the service list with a bounded page size.
- Order by a stable, unique key (e.g. created-at + id tiebreak).
- Return a
nextCursor (null at end); reject malformed/expired cursors with 400.
- Keep the response envelope stable and documented.
Technical guidance
- Encode the cursor opaquely (base64 of the sort key) — never leak internal offsets.
- Use a compound key so ties are deterministic.
Edge cases — each must have a test
Acceptance criteria
Out of scope
- Bidirectional (previous) paging
- Total-count on every page
Rewards
Part of the GrantFox OSS / Official Campaign (FWC26) — this task may be rewarded. PR quality is assessed by AI: depth, correctness under edge cases, meaningful tests, and clean design are what earn the reward. Shallow changes (typos, formatting, trivial docs) do not qualify.
Summary
The service list uses offset pagination, which skips/duplicates rows when data changes mid-scan and degrades on large offsets. Replace it with opaque-cursor pagination with a stable total order.
Why this matters
Offset pagination is incorrect under concurrent writes and slow at scale. Cursors give stable, efficient, resumable iteration.
Requirements
nextCursor(null at end); reject malformed/expired cursors with400.Technical guidance
Edge cases — each must have a test
Acceptance criteria
npm run lint,npm test, andnpm run buildall pass locallyCloses #<issue>Out of scope
Rewards
Part of the GrantFox OSS / Official Campaign (FWC26) — this task may be rewarded. PR quality is assessed by AI: depth, correctness under edge cases, meaningful tests, and clean design are what earn the reward. Shallow changes (typos, formatting, trivial docs) do not qualify.