Files
sase.tr/.agents/skills/tanstack-router/rules/tanstack-router.md
Sase Dev 996d614d50 feat: admin user creation, Vite migration, dialog fix, pl24 integration
- Add POST /admin/users endpoint with password hashing and role support
- Add user creation dialog to admin users page
- Migrate web from Next.js to Vite + TanStack Router
- Fix Dialog component positioning for Tailwind CSS v4
- Add @source directive for @sase/ui package scanning
- Add pl24 integration parsers and vehicle decode flow
- Backup old Next.js app to apps/web-nj

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 14:24:58 +00:00

3.0 KiB

paths: "/*.ts", "/.tsx", "**/route.ts", "**/router*.ts"

TanStack Router v1 Corrections

Claude's training may have limited TanStack Router knowledge. This project uses TanStack Router v1.

/* ❌ Manual route definitions (verbose) */
const router = createRouter({
  routeTree: rootRoute.addChildren([
    indexRoute,
    aboutRoute,
  ]),
})

/* ✅ File-based routing with routeTree.gen.ts */
// routes/__root.tsx, routes/index.tsx, routes/about.tsx
// Then import generated tree:
import { routeTree } from './routeTree.gen'
const router = createRouter({ routeTree })

Route File Structure

/* ❌ Wrong file naming */
// routes/About.tsx - capitalized won't work
// routes/about/page.tsx - Next.js convention

/* ✅ TanStack Router conventions */
// routes/__root.tsx - root layout
// routes/index.tsx - home page (/)
// routes/about.tsx - /about
// routes/posts/$postId.tsx - /posts/:postId (dynamic)
// routes/posts/index.tsx - /posts

createFileRoute vs createRoute

/* ❌ Using createRoute in file-based routing */
import { createRoute } from '@tanstack/react-router'
const Route = createRoute({...})

/* ✅ Use createFileRoute for file-based */
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/about')({
  component: AboutPage,
})

Loader Pattern

/* ❌ React Router style loader */
export async function loader({ params }) {
  return fetch(`/api/posts/${params.id}`)
}

/* ✅ TanStack Router loader */
export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params }) => {
    return fetchPost(params.postId)
  },
  component: PostPage,
})

function PostPage() {
  const post = Route.useLoaderData()
  return <div>{post.title}</div>
}

Search Params

/* ❌ Manual URLSearchParams */
const params = new URLSearchParams(window.location.search)

/* ✅ Type-safe search params */
export const Route = createFileRoute('/search')({
  validateSearch: (search) => ({
    q: search.q as string || '',
    page: Number(search.page) || 1,
  }),
})

function SearchPage() {
  const { q, page } = Route.useSearch()
}

Navigation

/* ❌ useNavigate like React Router */
import { useNavigate } from 'react-router-dom'
const navigate = useNavigate()
navigate('/about')

/* ✅ TanStack Router navigation */
import { useNavigate, Link } from '@tanstack/react-router'
const navigate = useNavigate()
navigate({ to: '/about' })

// Or type-safe Link
<Link to="/posts/$postId" params={{ postId: '123' }}>
  View Post
</Link>

Quick Fixes

If Claude suggests... Use instead...
createRoute in file-based createFileRoute
routes/About.tsx routes/about.tsx (lowercase)
loader({ params }) export loader inside createFileRoute
useParams() Route.useParams()
useSearchParams() Route.useSearch() with validateSearch
navigate('/path') navigate({ to: '/path' })