Story-1673 pramaan-admin nuqs removal keystone

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.

Hook state

useReactTable is still the table engine with manualPagination, manualSorting, and manualFiltering. The hook return shape and consumer call shape are unchanged.

Clean URL mirror

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.

Plain parsers

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.