1. Summary
Implement the user-facing search functionality across the application. This involves wiring up the desktop and mobile search inputs in the Navbar to redirect users to a dedicated /search page. The page will reactively fetch and display matching articles using TanStack Query, and allow users to refine results by category and sort options.
2. Blocker
- Schema Validation: Extend
articleSearchQuerySchema in src/features/article/types/index.ts with optional category (positive integer) and sort ('newest' | 'oldest' | 'popular', default 'newest') parameters.
- API Endpoint: Update
GET /api/articles/search in src/app/api/articles/search/route.ts to parse, validate, and forward category and sort query parameters.
- Database Service: Update
searchArticles in src/features/article/services/service.ts to pass query.category and query.sort to listArticlesWithCount, filtering results by category and applying the specified sort order.
3. Scope
- Shared Query Hook:
src/features/article/queries/useSearchArticles.ts — extend to accept category and sort options
- Navigation & Layout Components:
src/components/organisms/Navbar.tsx — desktop and mobile search inputs
- New Search Feature & Page:
src/app/search/page.tsx — new App Router page wrapper (with <Suspense> boundary)
src/features/search/ — new feature directory for search-specific UI
- Existing Shared Components (reused, not modified):
ArticleList component for rendering results
- Pagination component
- Category list hook (
useCategoryList)
4. Deliverables
- Navbar Search Integration: Controlled search inputs that navigate to
/search?q=<query> on submission (Enter or click). Mobile input in slide-out nav auto-closes the sheet on route change.
- Search Results Page (
/search):
- Dynamic page wrapped in a
<Suspense> boundary for useSearchParams() compliance
- Skeleton loaders for fetching state
- "No results found for '{query}'" empty state layout
- Filter & Sort Controls:
- Category filter selector (horizontal scrollable pills using
useCategoryList)
- Sort dropdown (Newest / Oldest / Popular)
- Changes immediately update URL params and reset page to 1
- Search Header: Displays query phrase and matched results count
- Pagination: Standard pagination controls tied to
&page=X URL param
- Input Validation: Client-side enforcement of
q.trim().length >= 3 with user feedback
5. Implementation Notes
- State & URL Sync: Treat browser URL search params (
q, category, sort, page) as the single source of truth. Enables shareable URLs and native browser navigation.
- Architectural Pattern: Container/Presentational. Keep params and data-fetching in
SearchContainer.tsx, delegate visual layout to presentational components (e.g. ArticleList).
- Hook Extension: Update
useSearchArticles to accept category and sort options and include them in the queryKey array for proper cache invalidation.
- Schema Alignment: Ensure client param names match the backend schema exactly (
category as number, sort as enum).
6. Acceptance Criteria
- Typing a search query in desktop or mobile navbar and pressing Enter navigates to
/search?q={query}.
- Mobile search in the slide-out nav sheet auto-closes the sheet on route change.
/search extracts q, category, sort, page from URL params and fetches matching articles.
- Submitting a query <3 characters shows a warning and prevents submission.
- Selecting category filters or changing sort immediately updates URL params and triggers a loading skeleton.
- Empty results display "No results found for '{query}'".
- Pagination controls are visible and functional when multiple pages exist.
- Code compiles without TypeScript errors (
npm run build).
- No ESLint or Prettier violations (
npm run lint / npm run format).
7. Tasks
Phase 1: Navbar Search Inputs
Phase 2: Hook & Page Scaffold
Phase 3: Filters, Sort & Pagination
Phase 4: Validation & Quality
1. Summary
Implement the user-facing search functionality across the application. This involves wiring up the desktop and mobile search inputs in the Navbar to redirect users to a dedicated
/searchpage. The page will reactively fetch and display matching articles using TanStack Query, and allow users to refine results by category and sort options.2. Blocker
articleSearchQuerySchemainsrc/features/article/types/index.tswith optionalcategory(positive integer) andsort('newest' | 'oldest' | 'popular', default'newest') parameters.GET /api/articles/searchinsrc/app/api/articles/search/route.tsto parse, validate, and forwardcategoryandsortquery parameters.searchArticlesinsrc/features/article/services/service.tsto passquery.categoryandquery.sorttolistArticlesWithCount, filtering results by category and applying the specified sort order.3. Scope
src/features/article/queries/useSearchArticles.ts— extend to acceptcategoryandsortoptionssrc/components/organisms/Navbar.tsx— desktop and mobile search inputssrc/app/search/page.tsx— new App Router page wrapper (with<Suspense>boundary)src/features/search/— new feature directory for search-specific UIArticleListcomponent for rendering resultsuseCategoryList)4. Deliverables
/search?q=<query>on submission (Enter or click). Mobile input in slide-out nav auto-closes the sheet on route change./search):<Suspense>boundary foruseSearchParams()complianceuseCategoryList)&page=XURL paramq.trim().length >= 3with user feedback5. Implementation Notes
q,category,sort,page) as the single source of truth. Enables shareable URLs and native browser navigation.SearchContainer.tsx, delegate visual layout to presentational components (e.g.ArticleList).useSearchArticlesto acceptcategoryandsortoptions and include them in thequeryKeyarray for proper cache invalidation.categoryas number,sortas enum).6. Acceptance Criteria
/search?q={query}./searchextractsq,category,sort,pagefrom URL params and fetches matching articles.npm run build).npm run lint/npm run format).7. Tasks
Phase 1: Navbar Search Inputs
/search?q=<query>.q.trim().length < 3, show inline warning.Phase 2: Hook & Page Scaffold
useSearchArticles.tsto acceptcategoryandsortoptions; add them toqueryKey.src/app/search/page.tsxwith<Suspense>boundary.SearchContainer.tsxinsrc/features/search/containers/.useSearchParamsand invokeuseSearchArticles(q, { category, sort, page }).ArticleListcomponent.Phase 3: Filters, Sort & Pagination
SearchContainerforisLoadingstate.useCategoryList) to the top of the search page.category,sort, resetpageto 1).SearchHeadershowing query string and results count.&page=XURL param.Phase 4: Validation & Quality
npm run formatandnpm run lint.npm run buildto confirm the build typechecks successfully.