Hands-On Lab & Phase Exit
Build, test, reason about, and transfer a production-style collection endpoint
Phase 15 - Filtering, Search, Sorting & Pagination
Volume 04 - Professional Backend
Architecture milestone
Implement
v
Smoke test
v
Explain trade-offs
v
Transfer skill
Phase 15 turns an unbounded collection endpoint into a validated, queryable, stable, paginated API contract.
Hands-on lab
The Phase 15 lab proves that your collection endpoint is bounded, validated, predictable, and useful to a real UI.
Lab A - Query contract
• Create tasks-query.schemas.ts.
• Add projectId, assigneeId, status, priority, search, sort, order, page, and pageSize.
• Use coercion for numeric query strings.
• Cap pageSize at 100.
• Reject unknown query parameters with a strict object.
Lab B - Prisma translation
• Build a Prisma.TaskWhereInput from only the validated public filters.
• Add case-insensitive title/description search.
• Map allow-listed sort fields explicitly.
• Add id as a stable secondary order.
• Implement skip/take offset pagination.
Lab C - Response contract
• Return data + meta instead of a raw array.
• Count using the same where filter.
• Calculate totalPages and previous/next flags.
• Verify an out-of-range page returns an empty data array with truthful metadata.
Lab D - PowerShell smoke matrix
Scenario Expected
GET /tasks Defaults applied, <=20 rows
?status=IN_PROGRESS&priority;=HIGH Both filters applied
?search=payroll Case-insensitive substring match
?sort=title■=asc Deterministic sorted page
?page=0 400 validation error
?pageSize=1000 400 validation error
?sort=dropTable 400 validation error
?page=999999 200 with empty data + truthful meta
Exercise levels
Level Challenge
1 - Follow Implement the reference query contract and pass the smoke tests.
2 - Modify Add dueBefore and dueAfter ISO datetime filters with clear inclusive/exclusive semantics.
3 - Implement Add an unassigned=true filter without allowing contradictory assigneeId + unassigned=true combinations.
Level Challenge
4 - Engineer Design the list endpoint for a payroll employee table with department, employment status, search, sortable
columns, and either offset or cursor pagination. Justify every query parameter and index candidate before coding.
Architecture oral exam
• Why should arbitrary query parameters never be forwarded directly into Prisma?
• Why does stable pagination require deterministic ordering?
• Why is pageSize capped by the backend?
• Why can offset pagination degrade on deep pages?
• When is cursor pagination a better product fit?
• Why can exact total counts be expensive?
• Why is an ordinary B-tree index not enough for arbitrary substring search?
• Why should filters and page often live in the URL?
• What evidence should exist before adding a new database index?
Phase exit checklist
• GET /tasks no longer returns an unbounded collection.
• query params are validated and normalized before TasksService.
• public filters translate explicitly to Prisma where input.
• search semantics are documented and intentionally simple.
• sorting is allow-listed and deterministic.
• offset pagination returns useful metadata.
• you can explain when cursor pagination is preferable.
• you understand the cost of count queries.
• index design is tied to observed workload rather than guesswork.
• Next.js can represent collection state with URL search parameters.
Figure 1 - Phase 15 complete architecture
URL collection state
v
NestJS query validation
v
TasksService query translation
v
Prisma where/orderBy/skip/take
v
PostgreSQL + measured indexes
v
data + pagination metadata
TaskFlow now has a bounded, queryable collection API suitable for real application screens.
Next volume
Phase 16 begins Volume 05 - Authentication & Security. The next problem is identity: TaskFlow can query data professionally,
but it still cannot prove who the caller is. We will first learn authentication concepts before integrating Supabase Auth.