User Story:
As a visitor, I want to browse, search, filter, and sort campaigns via the API so that I can find causes I want to support.
Acceptance Criteria:
GET /campaigns: page, limit, category, status, search (Postgres full-text search across title/description/story, min 3 characters, relevance-ordered), sortBy (newest/mostFunded/endingSoon); excludes DRAFT/SUSPENDED
- Response cached in Redis for 30s with all query params included in the cache key — test this specifically, since a partial key is a real bug that serves wrong results silently
GET /campaigns/categories: categories with live counts
User Story:
As a visitor, I want to browse, search, filter, and sort campaigns via the API so that I can find causes I want to support.
Acceptance Criteria:
GET /campaigns:page,limit,category,status,search(Postgres full-text search across title/description/story, min 3 characters, relevance-ordered),sortBy(newest/mostFunded/endingSoon); excludesDRAFT/SUSPENDEDGET /campaigns/categories: categories with live counts