Same change, two presentations

.coveragerc+1 -1
src/api/pagination.py+24 -0
src/api/views.py+5 -2
tests/test_users.py+8 -0
Four files, alphabetical. No order, no story, no why. This is what the reviewer usually meets first.

Background

The users endpoint returns every user in one response. It sailed through review at 200 users; at 20,000 it started timing out.

Goal

Add cursor pagination so the endpoint streams results in pages instead of dumping the whole table.

The intuition

A cursor is an opaque bookmark into the result set. The client hands back the cursor it received to fetch the next page, so the server never re-scans from the start.

The change, in order

def list_users(request): qs = User.objects.all() return JsonResponse(paginate(qs, cursor=request.GET.get('page')), safe=False)
Worth a flag: paginate() is a new helper, but core/pagination.py already has paginate_queryset(). The raw dump buries this; the explainer surfaces it.