DataTable keeps TanStack and drops hook-owned nuqs state
The shared useDataTable hook now owns page, page size, sorting, and column filters in React state, then mirrors clean URLs with shallow window.history.replaceState. TanStack Table remains the controlled engine.
What changed
src/hooks/use-data-table.ts no longer imports nuqs. Pagination, sorting, and column filters are initialized from server-passed initialState, controlled with useState, and mirrored to the browser URL without a Next navigation or server re-render.
useReactTable is still the table engine with manualPagination, manualSorting, and manualFiltering. The hook return shape and consumer call shape are unchanged.
Page, page size, sort, and filters write through window.history.replaceState. Filter URL writes remain debounced through useDebouncedCallback, and filter changes reset page to 1 by omitting the default page param.
src/lib/parsers.ts now exposes JSON and CSV parse/serialize helpers without nuqs/server. FilterItemSchema remains available for the shared data-table types.
Deep-link bridge
Because nuqs no longer reads the URL on mount for the shared hook, each live server-backed list now threads its already server-parsed request filters into initialState.columnFilters.
Firms maps search, status, onboardingStage, and plan into the search, status, onboardingStage, and plan table columns. Archived scope stays a direct nuqs side-param and is not migrated in this story.
Staff maps search, role, status, and hasActiveGrants into q, role, status, and hasActiveGrants. Support access maps q, firmId, and staffUserId. The support before cursor and expiringWithin side-param stay on nuqs for the follow-up story.
Scope guardrails
This story deliberately does not remove NuqsAdapter, NuqsTestingAdapter, BrowserNuqsAdapter, or the nuqs dependency. Direct side-params remain for #1674, and adapter/dependency removal remains for #1676.
No generated contracts, OpenAPI files, backend code, matter-type files, filing-type files, or customer app files were changed. This is a client-side state mechanism only, so the pramaan-docs ADR-124 observability note is instrumentation-exempt.
Verification proof
New hook-level tests prove initial controlled state, manual* flags, query-key meta, page/sort/filter replaceState writes, and no pushState navigation.
Firms, staff, and support-access unit tests prove deep-link hydration through initialState, generated request params derived from table.getState(), debounced filter URL mirroring, and no router navigation on filter changes.
Local verification: pnpm lint, pnpm exec tsc --noEmit, pnpm test, NEXT_PUBLIC_ENV=local pnpm build, pnpm build-storybook, and git diff --check.