A product page that fetches all reviews without a LIMIT clause will transfer every row in the reviews table on every page load. At 200 reviews averaging 500 bytes each, that's 100KB of JSON for a single product visit — multiplied across concurrent users, this becomes a cost and latency problem. ISO 25010 performance-efficiency requires that resource use be proportionate to demand. More concretely, a product that accumulates 10,000 reviews will eventually time out or OOM the serverless function handling the request, causing a user-visible 500 error at scale.
Low because the performance impact only manifests at high review volumes and does not expose data or allow unauthorized actions at typical early-stage scale.
Add a REVIEWS_PER_PAGE limit to the review query and render pagination controls in components/ReviewsList.tsx.
// components/ReviewsList.tsx
const REVIEWS_PER_PAGE = 10
export function ReviewsList({ productId }: { productId: string }) {
const [page, setPage] = useState(1)
const { data: reviews, total } = useReviews(productId, page, REVIEWS_PER_PAGE)
const totalPages = Math.ceil(total / REVIEWS_PER_PAGE)
return (
<section>
{reviews.map(r => <ReviewItem key={r.id} review={r} />)}
{totalPages > 1 && (
<nav aria-label="Review pages">
{Array.from({ length: totalPages }, (_, i) => (
<button key={i} onClick={() => setPage(i + 1)} aria-current={page === i + 1 ? 'page' : undefined}>
{i + 1}
</button>
))}
</nav>
)}
</section>
)
}
The corresponding API route at api/reviews must accept ?page= and ?limit= and apply LIMIT / OFFSET in the database query — CSS-hiding overflow is not a substitute.
ID: ecommerce-reviews.display-ux.pagination-lazy-load
Severity: low
What to look for: Count the maximum number of reviews loaded per page on initial render. Check for pagination controls (page buttons, "Page X of Y"), lazy-loading (IntersectionObserver, "Load More" button), or a limit parameter in the review query. Report the per-page limit if found.
Pass criteria: Review queries use a limit parameter of no more than 20 reviews per page, and the UI includes pagination controls (page numbers or "Load More" button) that fetch additional reviews on demand.
Fail criteria: All reviews load at once regardless of count (no limit in query), or the UI fetches all reviews and only hides overflow with CSS.
Skip (N/A) when: The project has no products with more than 20 reviews in the database or seed data.
Detail on fail: "Review query fetches all reviews with no LIMIT clause. A product with 200 reviews loads all 200 on initial render."
Remediation: Implement pagination in components/ReviewsList.tsx with a query limit:
// components/ReviewsList.tsx
const REVIEWS_PER_PAGE = 10
export function ReviewsList({ productId }) {
const [page, setPage] = useState(1)
const reviews = useReviews(productId, page, REVIEWS_PER_PAGE)
const totalPages = Math.ceil(reviews.total / REVIEWS_PER_PAGE)
return (
<>
{reviews.data.map(r => <ReviewItem key={r.id} review={r} />)}
<div className="pagination">
{Array.from({ length: totalPages }).map((_, i) => (
<button key={i + 1} onClick={() => setPage(i + 1)}>
{i + 1}
</button>
))}
</div>
</>
)
}