Files
vps-tracker/.cursor/rules/vite-tanstack-frontend.mdc
T
DenozordecandCursor 6fbd1a9113 refactor(repo): переход на pnpm monorepo с shadcn/ui и Fastify+Drizzle
Frontend:
- apps/web (Vite+TS, TanStack Router/Query, shadcn/ui @cfdm/ui base-nova)
- 10 страниц в routes/_auth/, Recharts через shadcn Chart, lucide-react
- формы на RHF + Zod (FormSheet/FormField)
- удалены Tabler, Chart.js, react-router-dom

Backend (параллельный трек):
- apps/api (Fastify 5 + Drizzle + better-sqlite3)
- packages/db: Drizzle-схема и repositories по сущностям
- packages/shared: Zod-контракты
- роуты с валидацией и единым форматом ошибок { error: { code, message } }
- sync/backup — заглушки 501 (billmanager-адаптеры переносятся отдельно)
- legacy Express оставлен как runtime по умолчанию (RUNTIME=express)

Infra:
- Dockerfile multi-stage под pnpm workspaces
- .dockerignore и docker-compose обновлены под monorepo

Rules:
- удалены нерелевантные правила (rust, cloudflare, server/frontend-conventions)
- project-structure.mdc и AGENTS.md переписаны под monorepo
- frontend-shadcn.mdc, shadcn-ui-production.mdc, sqlite.mdc обновлены

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-26 13:42:05 +07:00

121 lines
3.3 KiB
Plaintext

---
description: Vite + TanStack Router v1 + TanStack Query v5 — routing, loaders, queries, mutations
globs: apps/web/**/*.{tsx,ts}
alwaysApply: false
---
# Vite + TanStack Router + Query
Фронтенд: **Vite SPA**, не Next.js. Нет Server Components, App Router, `'use client'`.
## Структура
```
apps/web/src/
routes/ # file-based routes (__root.tsx, _auth/, ...)
queries/ # queryOptions factories + key factories
lib/ # api-client, queryClient, auth, schemas
components/ # domain + layout (UI primitives → @cfdm/ui)
main.tsx
```
## Архитектура
- **Router** — маршрутизация, URL state, navigation, loaders
- **Query** — server state, cache, mutations
- **Loader** — `queryClient.ensureQueryData()` до рендера → без спиннеров на route data
- **Компоненты** — UI; данные из Query cache
## QueryClient + Router
```ts
// lib/queryClient.ts
export const queryClient = new QueryClient({
defaultOptions: { queries: { staleTime: 60_000 } },
})
// lib/router.ts
export const router = createRouter({
routeTree,
context: { queryClient },
defaultPreload: 'intent',
})
declare module '@tanstack/react-router' {
interface Register { router: typeof router }
}
```
## Query definitions
- `queryOptions` factories в `queries/`, не inline в компонентах
- Key factories: `all` → `lists` / `details` → `list(filters)` / `detail(id)`
```ts
export const serviceKeys = {
all: ['services'] as const,
list: () => [...serviceKeys.all, 'list'] as const,
}
export const servicesQueryOptions = () =>
queryOptions({
queryKey: serviceKeys.list(),
queryFn: () => api.get('/api/v1/services'),
})
```
## Loader + component
```tsx
export const Route = createFileRoute('/_auth/services')({
loader: ({ context: { queryClient } }) =>
queryClient.ensureQueryData(servicesQueryOptions()),
component: ServicesPage,
})
function ServicesPage() {
const { data } = useQuery(servicesQueryOptions()) // из cache loader
return ...
}
```
## Search params
- Zod + `validateSearch`; доступ через `Route.useSearch()`
- Search params = source of truth для фильтров/пагинации
- Передавать в `queryOptions` для query key и fetcher
## Mutations
```ts
onSuccess: (newItem) => {
queryClient.setQueryData(keys.detail(newItem.id), newItem)
queryClient.invalidateQueries({ queryKey: keys.lists() })
}
```
- `setQueryData` + `invalidateQueries`, не только invalidate
- Навигация после create — когда cache уже тёплый
## Routing
- `createFileRoute` для file-based routes
- `<Link>` для внутренней навигации, не `<a href>`
- Pathless layouts: `_auth/` для protected routes
- Auth guard в `beforeLoad` pathless route
## Запреты
- `useEffect` для fetch данных — только loader / `useQuery`
- Inline `queryKey` в компонентах — только factories из `queries/`
- `useQuery` с позиционными аргументами (v5 — только options object)
- `window.location` для search params
## Prefetch
`onMouseEnter` на `<Link>` → `queryClient.prefetchQuery(detailOptions(id))`
## DevTools
Только в dev: `TanStackRouterDevtools`, `ReactQueryDevtools`