Self-contained roadmap list surface that fetches roadmap data via `useSelfFetch`, applies URL-driven search/status filters, and renders the controlled `` with SSR hydration support. ## Key Components - **`RoadmapView`** — Primary export. Orchestrates data fetching, URL parameter reading, scroll-to-hash deep linking, and delegates rendering to ``. - **`RoadmapViewProps`** — Configuration interface for API routes, SSR hydration, voting, and URL parameter key overrides. - **`useSelfFetch`** — Shared hook providing `data`, `setData`, `isLoading`, `error`, and `reload`. The fetch URL acts as the cache key, so filter changes automatically trigger refetches. - **`useScrollToHash`** — Handles deep-link hash dispatch (e.g. `?search=#roadmap-` from chat cards), polling until the target item mounts. - **`RoadmapGridSkeleton`** — Shown only during the first in-flight fetch when no data exists yet. - **`LoadError`** — Rendered on fetch failure with a retry callback. ## Usage Example ```typescript import { RoadmapView } from './roadmap-view' // Minimal — uses all defaults (/api/roadmap, 'search', 'status' params) // With SSR hydration, custom endpoint, and voting `/api/v2/roadmap/${taskId}`} votingOptions={{ voteEndpoint: '/api/roadmap/vote', storageKey: 'roadmap-votes', }} searchParamKey="q" statusParamKey="status" /> ``` ## Notes - Filter params are folded into the fetch URL (`?search=&status=`), keeping the URL as the single cache key. This mirrors the `ProductReleasesView` pattern. - The `initialData` wrapper is memoized to maintain stable identity and prevent optimistic vote patches from being clobbered by re-sync effects. - After a vote, `onItemUpdate` patches the refreshed task directly into local state via `setData`, keeping vote counts live without a full list refetch. - `searchParamKey` and `statusParamKey` default to values from `DEV_SECTION_PARAM_KEYS` — the same registry used by the section chrome — preventing silent key divergence.