Init
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
---
|
||||
description: Concise AI assistant — clean code, token efficiency, codebase alignment
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# AI Coding Assistant
|
||||
|
||||
You work inside a real codebase. Be precise, concise, and aligned with existing patterns.
|
||||
|
||||
## Clean Code
|
||||
|
||||
- Minimal, readable, maintainable code; simple over clever
|
||||
- Meaningful names; DRY; small single-responsibility functions
|
||||
- Follow existing project style and patterns
|
||||
|
||||
## Token Efficiency
|
||||
|
||||
- Do not explain obvious things
|
||||
- No step-by-step reasoning unless explicitly asked
|
||||
- Output only what is necessary: code, brief comments when needed
|
||||
- No long prose, summaries, or repetition
|
||||
- If unsure — ask a short clarifying question instead of guessing
|
||||
|
||||
## Work With Existing Codebase
|
||||
|
||||
- Analyze surrounding code before generating new code
|
||||
- Reuse existing utilities, helpers, and patterns
|
||||
- Do not reinvent functionality already in the project
|
||||
- Respect project architecture
|
||||
|
||||
## Documentation Awareness
|
||||
|
||||
- Check project docs, README, comments, and types before implementing
|
||||
- If behavior is unclear: infer from types/tests/examples, or ask
|
||||
- Prefer documented approaches over assumptions
|
||||
|
||||
## Output Format
|
||||
|
||||
- Default: only code
|
||||
- If explanation is required — keep it under 3–5 lines
|
||||
- Highlight only important decisions
|
||||
|
||||
## Refactoring
|
||||
|
||||
- Preserve behavior unless told otherwise
|
||||
- Improve readability and structure; reduce complexity and duplication
|
||||
|
||||
## Debugging
|
||||
|
||||
- Identify root cause, not symptoms
|
||||
- Suggest minimal fix; avoid rewriting large parts unless necessary
|
||||
|
||||
## Missing Context
|
||||
|
||||
- Ask concise, targeted questions
|
||||
- Do not hallucinate APIs or project structure
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
description: Conventional commits на русском языке
|
||||
globs: "**/*"
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Commit messages (русский)
|
||||
|
||||
Формат: `<type>[optional scope]: <описание>`
|
||||
|
||||
## Типы
|
||||
|
||||
- `feat` — только новая UX-фича для пользователя
|
||||
- `fix` — исправление бага
|
||||
- `chore` — конфиг, зависимости, правила, CI
|
||||
- `refactor` — рефакторинг без изменения поведения
|
||||
- `docs` — документация
|
||||
- `test` — тесты
|
||||
- `perf` — производительность
|
||||
|
||||
## Правила
|
||||
|
||||
- Subject в **императиве**, без точки в конце
|
||||
- Subject и body — **на русском**
|
||||
- Body (опционально) — что и зачем, не как
|
||||
- Scope в скобках при необходимости: `feat(domains): добавить фильтр по статусу`
|
||||
|
||||
## Примеры
|
||||
|
||||
```
|
||||
fix(frontend): заменить raw table на shadcn Table на странице доменов
|
||||
|
||||
feat(certificates): добавить предупреждение об истечении срока
|
||||
|
||||
chore(rules): консолидировать правила shadcn/ui для Cursor
|
||||
```
|
||||
@@ -0,0 +1,122 @@
|
||||
---
|
||||
description: shadcn/ui Monorepo — структура apps/web + packages/ui, CLI workflow, импорты @telemt/ui
|
||||
globs: apps/web/**/*,packages/ui/**/*
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Frontend Monorepo (shadcn/ui + ReUI)
|
||||
|
||||
**Обязательный стандарт структуры** — [Monorepo docs](https://ui.shadcn.com/docs/monorepo), ReUI — [Get Started](https://reui.io/docs/get-started).
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
apps/web/ # Vite SPA (routes, queries, domain components)
|
||||
apps/api/ # Fastify API + static SPA in prod
|
||||
packages/ui/ # @telemt/ui — shadcn primitives
|
||||
packages/shared/ # @telemt/shared — Zod schemas, parse-fqdn
|
||||
packages/db/ # @telemt/db — Drizzle schema, repositories
|
||||
```
|
||||
|
||||
## Два components.json
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|------------|
|
||||
| [`apps/web/components.json`](apps/web/components.json) | App aliases; `ui` → `@telemt/ui/components` |
|
||||
| [`packages/ui/components.json`](packages/ui/components.json) | UI package aliases |
|
||||
|
||||
**Синхронизировать:** `style`, `iconLibrary`, `baseColor`, `registries` в обоих файлах.
|
||||
|
||||
```json
|
||||
"registries": {
|
||||
"@reui": "https://reui.io/r/{style}/{name}.json"
|
||||
}
|
||||
```
|
||||
|
||||
## CLI — только из apps/web
|
||||
|
||||
```bash
|
||||
cd apps/web
|
||||
pnpm dlx shadcn@latest docs button
|
||||
pnpm dlx shadcn@latest add button
|
||||
pnpm dlx shadcn@latest add sidebar-07
|
||||
pnpm dlx shadcn@latest add login-03
|
||||
pnpm dlx shadcn@latest add @reui/data-grid
|
||||
pnpm dlx shadcn@latest add @reui/filters
|
||||
pnpm dlx shadcn@latest apply b2fA --only theme -y
|
||||
```
|
||||
|
||||
Перед обновлением существующих компонентов:
|
||||
|
||||
```bash
|
||||
pnpm dlx shadcn@latest add button --dry-run
|
||||
pnpm dlx shadcn@latest add button --diff
|
||||
pnpm dlx shadcn@latest info --json
|
||||
```
|
||||
|
||||
## Куда CLI кладёт файлы
|
||||
|
||||
| Команда | Куда |
|
||||
|---------|------|
|
||||
| `add button` | `packages/ui/src/components/button.tsx` |
|
||||
| `add login-03` | примитивы → `packages/ui`, block → `apps/web/src/components/` |
|
||||
| `add @reui/data-grid` | `apps/web/src/components/reui/data-grid/` |
|
||||
| `add @reui/filters` | `apps/web/src/components/reui/filters.tsx` |
|
||||
|
||||
## Импорты
|
||||
|
||||
```tsx
|
||||
import { Button } from '@telemt/ui/components/button'
|
||||
import { cn } from '@telemt/ui/lib/utils'
|
||||
import { useIsMobile } from '@telemt/ui/hooks/use-mobile'
|
||||
import '@telemt/ui/globals.css' // только в main.tsx
|
||||
```
|
||||
|
||||
| Запрещено | Разрешено |
|
||||
|-----------|-----------|
|
||||
| `@/components/ui/*` | `@telemt/ui/components/*` |
|
||||
| `@/components/reui/*` в `packages/ui` | `apps/web/src/components/reui/` |
|
||||
| `apps/web/src/components/ui/` | `packages/ui/src/components/` |
|
||||
| Ручное редактирование `globals.css` | `pnpm dlx shadcn@latest apply b2fA --only theme` |
|
||||
|
||||
**Registry imports после add:**
|
||||
- shadcn community → переписывать на `@telemt/ui/...`
|
||||
- ReUI `@reui/*` → остаётся `@/components/reui/...`; shadcn-примитивы внутри ReUI → `@telemt/ui/...`
|
||||
|
||||
**Post-add checklist ReUI:**
|
||||
- [ ] Импорты `@/components/ui/*` → `@telemt/ui/components/*`
|
||||
- [ ] Зависимости в `apps/web/package.json` (не в `packages/ui`)
|
||||
- [ ] `pnpm --filter web build`
|
||||
|
||||
## Разделение ответственности
|
||||
|
||||
- **`packages/ui`** — только output `shadcn add` (примитивы, registry hooks, `cn`)
|
||||
- **`apps/web/src/components/reui`** — только output `shadcn add @reui/*` (см. [`reui-mcp.mdc`](reui-mcp.mdc))
|
||||
- **`apps/web/src/components`** — blocks, layout, domain (`login-form`, `app-shell`, `reui-kit/*`)
|
||||
|
||||
## Стили (Tailwind v4 monorepo)
|
||||
|
||||
`packages/ui/src/styles/globals.css` — единственный CSS-файл. **Обязательно** `@source` для обоих workspace:
|
||||
|
||||
```css
|
||||
@source "../"; /* packages/ui/src */
|
||||
@source "../../../apps/web/src"; /* apps/web/src */
|
||||
```
|
||||
|
||||
Без `@source` Tailwind не видит классы из `packages/ui` и `apps/web` — UI ломается (нет sidebar, card, и т.д.).
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm --filter web dev
|
||||
pnpm --filter web build
|
||||
```
|
||||
|
||||
## Чеклист
|
||||
|
||||
- [ ] Два `components.json` согласованы (включая `@reui` registry)
|
||||
- [ ] `shadcn add` из `apps/web`
|
||||
- [ ] shadcn → `@telemt/ui`; ReUI → `@/components/reui`
|
||||
- [ ] Нет `apps/web/src/components/ui/`
|
||||
- [ ] `pnpm --filter web build` без ошибок
|
||||
|
||||
См. также: [`frontend-shadcn.mdc`](frontend-shadcn.mdc), [`reui-mcp.mdc`](reui-mcp.mdc), [`vite-tanstack-frontend.mdc`](vite-tanstack-frontend.mdc).
|
||||
@@ -0,0 +1,104 @@
|
||||
---
|
||||
description: Frontend — shadcn primitives + ReUI PRO blocks; CLI-first; kit patterns
|
||||
globs: apps/web/**/*,packages/ui/**/*
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Frontend — shadcn/ui + ReUI PRO
|
||||
|
||||
**Иерархия:** ReUI PRO > kit > shadcn primitives. См. [`reui-pro-priority.mdc`](reui-pro-priority.mdc).
|
||||
|
||||
**Источник истины:** MCP **`user-reui`** (pages/blocks/KPI/settings) + MCP `plugin-shadcn-shadcn` (только primitives) + docs. Не выдумывать UI. Не поднимать ui.shadcn.com/blocks выше `@reui`.
|
||||
|
||||
Monorepo — [`frontend-monorepo.mdc`](frontend-monorepo.mdc). ReUI — [`reui-mcp.mdc`](reui-mcp.mdc). Patterns — [`frontend-ui-patterns.mdc`](frontend-ui-patterns.mdc).
|
||||
|
||||
| Документ | URL |
|
||||
|----------|-----|
|
||||
| **shadcn Components** | https://ui.shadcn.com/docs/components |
|
||||
| **ReUI Blocks** | https://reui.io/blocks |
|
||||
| **ReUI llms.txt** | https://reui.io/llms.txt |
|
||||
| **ReUI Settings** | https://reui.io/blocks/application/settings |
|
||||
| **Installation** | https://ui.shadcn.com/docs/installation |
|
||||
| **Monorepo** | https://ui.shadcn.com/docs/monorepo |
|
||||
| **Forms (RHF)** | https://ui.shadcn.com/docs/forms/react-hook-form |
|
||||
|
||||
## Шаг 0 — перед любым UI-кодом
|
||||
|
||||
0. Найти существующие `reui-kit/*` / shared
|
||||
1. **Pages / KPI / settings / enterprise** → MCP `user-reui` (`search` → `get_block` / `compose_page`) + cite `previewUrl`
|
||||
2. **Primitives** → MCP `plugin-shadcn-shadcn` + `pnpm dlx shadcn@latest docs <component>`
|
||||
3. CLI add из `apps/web` → adapt
|
||||
|
||||
**Новая страница** → сначала ReUI PRO `compose_page` / blocks ([reui.io/blocks](https://reui.io/blocks)), не ui.shadcn.com/blocks как primary.
|
||||
|
||||
## Shared / kit (обязательно)
|
||||
|
||||
| Component | Файл |
|
||||
|-----------|------|
|
||||
| `PageShell` | `page-shell.tsx` |
|
||||
| `ResourcePage` | `reui-kit/resource-page.tsx` |
|
||||
| `OpsDashboard` / `KpiStatGrid` / `QuickActionGrid` | `reui-kit/ops-dashboard.tsx`, `kpi-stat-grid.tsx`, `quick-action-grid.tsx` |
|
||||
| `KanbanBoard` | `reui-kit/kanban-board.tsx` |
|
||||
| `DetailPanel` | `reui-kit/detail-panel.tsx` |
|
||||
| `SettingsShell` | `reui-kit/settings-shell.tsx` |
|
||||
| `EmptyState` | `empty-state.tsx` |
|
||||
| `QueryState` | `query-state.tsx` |
|
||||
| `ConfirmDialog` | `confirm-dialog.tsx` |
|
||||
| `StatusBadge` | `status-badge.tsx` |
|
||||
| `FormSheet` | `form-sheet.tsx` |
|
||||
| `FormField` | `form-field.tsx` |
|
||||
| `LoadingButton` | `loading-button.tsx` |
|
||||
| `SettingRow` | `setting-row.tsx` |
|
||||
|
||||
**Не использовать как эталон:** устаревшие `PageHeader` / `SectionCards` / `DataGridCard` / `TableCard` (если удалены или мёртвы).
|
||||
|
||||
**Overlay:** Sheet — forms; AlertDialog — destructive confirm.
|
||||
|
||||
## Шаг 1 — CLI
|
||||
|
||||
```bash
|
||||
cd apps/web
|
||||
pnpm dlx shadcn@latest add button field input ...
|
||||
pnpm dlx shadcn@latest add @reui/frame @reui/data-grid @reui/filters
|
||||
pnpm dlx shadcn@latest add @reui/stats-12 @reui/card-35 @reui/settings-16 @reui/auth-13
|
||||
pnpm dlx shadcn@latest apply b2fA --only theme -y
|
||||
```
|
||||
|
||||
## Приоритет композиции
|
||||
|
||||
1. `@telemt/ui/components/*` (primitives)
|
||||
2. ReUI PRO block → adapt (`blocks/` reference + kit)
|
||||
3. `reui-kit/*` + shared
|
||||
4. Domain-обёртка
|
||||
|
||||
## Запрещено
|
||||
|
||||
| ❌ | ✅ |
|
||||
|----|-----|
|
||||
| `<table>`, raw select | DataGrid / `Select` |
|
||||
| `bg-emerald-*` | semantic / ReUI `variant` |
|
||||
| Card как ops-shell | ReUI `Frame` |
|
||||
| Hand-roll KPI | `KpiStatGrid` / [stats-12](https://reui.io/preview/base/stats-12) |
|
||||
| `space-y-*` | `flex` + `gap-*` |
|
||||
| `@/components/ui/*` | `@telemt/ui/components/*` |
|
||||
|
||||
## Эталоны проекта
|
||||
|
||||
| Зона | Файл | Preview |
|
||||
|------|------|---------|
|
||||
| Shell | `layout/app-shell.tsx` | [app-shell-12](https://reui.io/preview/base/app-shell-12) |
|
||||
| Login | `routes/login.tsx` | [auth-13](https://reui.io/preview/base/auth-13) |
|
||||
| Dashboard | `routes/_auth/index.tsx` | [stats-12](https://reui.io/preview/base/stats-12) / dashboard-1 |
|
||||
| Lists | `ResourcePage` | [data-grid-filtering-2](https://reui.io/preview/base/data-grid-filtering-2) |
|
||||
| Settings | `settings/integrations.tsx` | [settings-16](https://reui.io/preview/base/settings-16) |
|
||||
|
||||
## Чеклист
|
||||
|
||||
- [ ] `user-reui` + preview/docs для зоны
|
||||
- [ ] Frame surface
|
||||
- [ ] CLI add при новых items
|
||||
- [ ] `pnpm --filter web build`
|
||||
|
||||
## Язык
|
||||
|
||||
Ответы — русский. Commits — [`commit-messages-ru.mdc`](commit-messages-ru.mdc).
|
||||
@@ -0,0 +1,194 @@
|
||||
---
|
||||
description: Единые UI-паттерны web — shared components, docs workflow, матрица стандартизации
|
||||
globs: apps/web/**/*
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Frontend UI Patterns
|
||||
|
||||
См. также: [`frontend-shadcn.mdc`](frontend-shadcn.mdc), [`shadcn-mcp.mdc`](shadcn-mcp.mdc), [`reui-mcp.mdc`](reui-mcp.mdc), [Components](https://ui.shadcn.com/docs/components), [ReUI llms.txt](https://reui.io/llms.txt).
|
||||
|
||||
## Docs workflow (обязательно)
|
||||
|
||||
0. Codegraph / поиск существующих shared/domain / `reui-kit`
|
||||
1. Skill ReUI + shadcn — component selection
|
||||
2. **Primary:** MCP `user-reui` — search → `get_block` / `compose_page` (`surface: "frame"`) — **всегда cite `previewUrl` + `docsUrl`**
|
||||
3. Primitives: MCP `plugin-shadcn-shadcn` + `pnpm dlx shadcn@latest docs <component>`
|
||||
4. CLI: `cd apps/web && pnpm dlx shadcn@latest add @reui/...` → сверить API
|
||||
5. Код по examples + docs (только после MCP ↔ docs)
|
||||
6. Context7 — **только** TanStack Router/Query, Recharts
|
||||
7. MCP `validate_usage` / `get_audit_checklist` — перед merge
|
||||
|
||||
## Surface
|
||||
|
||||
Проект использует **ReUI Frame** (`surface: frame`), не shadcn Card как оболочку list/ops-экранов. Эталон списка: [data-grid-filtering-2](https://reui.io/preview/base/data-grid-filtering-2).
|
||||
|
||||
## Обязательные референсы по зонам
|
||||
|
||||
| Зона | Preview |
|
||||
|------|---------|
|
||||
| KPI | [stats-12](https://reui.io/preview/base/stats-12) — EvoBGP hybrid SoT |
|
||||
| Quick Actions | [stats-12](https://reui.io/preview/base/stats-12) · [card-12](https://reui.io/preview/base/card-12) → `QuickActionGrid` |
|
||||
| List | [data-grid-filtering-2](https://reui.io/preview/base/data-grid-filtering-2) |
|
||||
| Settings | [settings-16](https://reui.io/preview/base/settings-16), [Application Settings](https://reui.io/blocks/application/settings) |
|
||||
| Settings rows / Health-check | [settings-2](https://reui.io/preview/base/settings-2), [settings-3](https://reui.io/preview/base/settings-3) |
|
||||
| Auth | [auth-13](https://reui.io/preview/base/auth-13) |
|
||||
| Empty | [empty-state-12](https://reui.io/preview/base/empty-state-12) |
|
||||
| Forms | [form-7](https://reui.io/preview/base/form-7) |
|
||||
| Shell | [app-shell-12](https://reui.io/preview/base/app-shell-12) |
|
||||
|
||||
**SettingRow:** `FieldSeparator` opt-in (`separated`); не между toggle-row и nested fields (Health-check). Settings-секции — отдельные Frame + `gap`, без hairline под PageHeader.
|
||||
|
||||
## Иерархия компонентов
|
||||
|
||||
```
|
||||
@telemt/ui/components/* ← shadcn CLI (packages/ui)
|
||||
@/components/reui/* ← ReUI CLI @reui/* (apps/web)
|
||||
apps/web/src/components/ ← shared + domain + layout
|
||||
page-shell.tsx
|
||||
reui-kit/
|
||||
resource-page.tsx ← list: Frame + line Tabs + Filters + DataGrid
|
||||
kanban-board.tsx ← kanban + KanbanBoardSkeleton
|
||||
detail-panel.tsx ← detail: Frame header/metrics
|
||||
settings-shell.tsx
|
||||
ops-dashboard.tsx ← KPI stats-12 + charts
|
||||
catalog-board-toggle.tsx
|
||||
empty-state.tsx
|
||||
query-state.tsx
|
||||
confirm-dialog.tsx
|
||||
status-badge.tsx
|
||||
form-sheet.tsx
|
||||
form-field.tsx
|
||||
loading-button.tsx
|
||||
layout/ ← app-shell, site-header, app-sidebar
|
||||
domain-* ← бизнес-компоненты
|
||||
```
|
||||
|
||||
## Матрица стандартизации
|
||||
|
||||
| Элемент | Shared | Primitive |
|
||||
|---------|--------|-----------|
|
||||
| Page wrapper | `PageShell` | — |
|
||||
| List page | `ResourcePage` | ReUI `Frame` + `data-grid` + `filters` + shadcn `Tabs` `variant="line"` |
|
||||
| Catalog / Board | `CatalogBoardToggle` + `ResourcePage` / `KanbanBoard` | `?view=board` на `/groups`, `/services` |
|
||||
| Kanban | `KanbanBoard` / `KanbanBoardSkeleton` | ReUI `kanban` + `Frame` |
|
||||
| Detail | `DetailPanel` | ReUI `Frame` |
|
||||
| Settings | `SettingsShell` | — |
|
||||
| Dashboard KPI | `OpsDashboard` / `KpiStatGrid` | ReUI Frame [stats-12](https://reui.io/preview/base/stats-12) hybrid |
|
||||
| Quick Actions | `QuickActionGrid` | Frame tiles + Badge «Перейти» |
|
||||
| Empty | `EmptyState` | `Empty` |
|
||||
| Loading / Error | `QueryState` / kit skeletons | `Skeleton`, `Alert` |
|
||||
| Status | `StatusBadge` | ReUI `Badge` (`success`/`info`/`warning`) |
|
||||
| Create/Edit | `FormSheet` + `*-edit-sheet.tsx` | `Sheet`, `Field` |
|
||||
| Form field | `FormField` | `Field`, `Input`, `Select` |
|
||||
| Submit button | `LoadingButton` | `Button`, `Spinner` |
|
||||
| Delete confirm | `ConfirmDialog` | `AlertDialog` |
|
||||
| Nav | `AppSidebar` (`isActive` обязателен) | `Sidebar` |
|
||||
| Breadcrumbs | `SiteHeader` | `Breadcrumb` |
|
||||
| Dates | `lib/format.ts` | — |
|
||||
|
||||
## Header actions
|
||||
|
||||
Независимые CTA в header → `flex shrink-0 flex-wrap items-center justify-end gap-2`.
|
||||
|
||||
**Не** оборачивать в `ButtonGroup` (он склеивает кнопки). `ButtonGroup` — только для связанных контролок (filter chips и т.п.).
|
||||
|
||||
Max 1 primary (`default`) на экран; остальные `outline` / `ghost`.
|
||||
|
||||
Toggle «Доска» / «К каталогу» — всегда `outline` в `primaryAction` / `KanbanBoard.toolbarActions` (не отдельный Frame-shell).
|
||||
|
||||
## Line tabs (project standard)
|
||||
|
||||
Эталон: [c-tabs-2](https://reui.io/preview/base/components/c-tabs-2) + counted [filtering-2](https://reui.io/preview/base/data-grid-filtering-2).
|
||||
|
||||
```tsx
|
||||
<TabsList variant="line" className="gap-5">
|
||||
<TabsTrigger value="…" className="text-muted-foreground hover:text-foreground h-auto gap-2 px-0 pb-3">
|
||||
<span>Label</span>
|
||||
<span className="bg-muted text-muted-foreground … tabular-nums rounded-md">{count}</span>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
```
|
||||
|
||||
- Примитив: [`packages/ui/.../tabs.tsx`](../../packages/ui/src/components/tabs.tsx) — line = `h-auto`, без `flex-1`, без `dark:data-active:bg-input/30`, underline `after:bottom-0`
|
||||
- Active = яркий текст + **foreground underline**, без фона
|
||||
- Count pill всегда `bg-muted`
|
||||
- Active state — Base UI `data-active`, не Radix `data-[state=active]`
|
||||
- Не трогать internals `reui/date-selector`
|
||||
|
||||
## Catalog / Board (`/groups`, `/services`)
|
||||
|
||||
| Режим | UI | Search |
|
||||
|-------|-----|--------|
|
||||
| Catalog (default) | `ResourcePage` + primary create | omit / `view=catalog` |
|
||||
| Board | `KanbanBoard` DnD | `?view=board` |
|
||||
|
||||
- Groups tabs: Все / С доменами / Пустые
|
||||
- Services tabs: Все / Включены / Выключены / Без группы
|
||||
- DnD только на board; kanban hooks/cards не удалять
|
||||
|
||||
## Dashboard KPI
|
||||
|
||||
Эталон: [stats-12](https://reui.io/preview/base/stats-12) — icon tile + value + label + optional badge/footer; клик через `to` (`Link`) / `onSelect`. Compact strip: [card-35](https://reui.io/preview/base/card-35).
|
||||
|
||||
## Sidebar
|
||||
|
||||
- Каждый `SidebarMenuButton` получает `isActive` от pathname (`useRouterState`)
|
||||
- `--sidebar-accent` в `AppShell` — заметный mix primary (~14%), не 5%
|
||||
|
||||
## Overlay selection
|
||||
|
||||
| Сценарий | Компонент |
|
||||
|----------|-----------|
|
||||
| Create/edit форма | `Sheet` |
|
||||
| Destructive confirm | `AlertDialog` via `ConfirmDialog` |
|
||||
| Modal preview | `Dialog` |
|
||||
|
||||
## Block registry
|
||||
|
||||
| Зона | Block / эталон |
|
||||
|------|----------------|
|
||||
| Shell | [app-shell-12](https://reui.io/preview/base/app-shell-12) |
|
||||
| List + tabs + filters | [data-grid-filtering-2](https://reui.io/preview/base/data-grid-filtering-2) |
|
||||
| Line tabs | [c-tabs-2](https://reui.io/preview/base/components/c-tabs-2) |
|
||||
| KPI | [stats-12](https://reui.io/preview/base/stats-12) — на dashboard, certificates, domains, groups, services |
|
||||
| Login | [auth-13](https://reui.io/preview/base/auth-13) |
|
||||
| Settings | [settings-16](https://reui.io/preview/base/settings-16) / [settings-6](https://reui.io/preview/base/settings-6) |
|
||||
| Empty | [empty-state-12](https://reui.io/preview/base/empty-state-12) |
|
||||
|
||||
## Spacing
|
||||
|
||||
```
|
||||
AppShell main: gap-4 md:gap-6, px-4 md:px-6, py-4 md:py-5
|
||||
(--sidebar-width: 240px; header h-12; AppSwitcher + AppsMenu — Shared App Shell chrome)
|
||||
PageShell: gap-4 md:gap-6
|
||||
Title/desc: gap-px
|
||||
Card/Frame grid: gap-4 (dashboard denser: gap-2 md:gap-3)
|
||||
FieldGroup: gap-4
|
||||
Item list: gap-2
|
||||
Toolbar / header actions: gap-2
|
||||
Tabs list (line): gap-5
|
||||
```
|
||||
|
||||
Shared chrome (telemt-panel / CFDM / EvoBGP): см. [`docs/ui-design-contract.md`](../../docs/ui-design-contract.md) — секция **Shared App Shell chrome**. Preview: [app-shell-12](https://reui.io/preview/base/app-shell-12).
|
||||
|
||||
**Запрещено:** `space-y-*`, raw colors (`bg-emerald-*`), custom empty divs, page-level Spinner / plain «Загрузка…» без Skeleton.
|
||||
|
||||
## UX/UI (состояния данных)
|
||||
|
||||
Каждый блок: **default, hover, focus, disabled, empty, loading, error**.
|
||||
|
||||
- **Loading** — `Skeleton` / `ResourcePage` skeleton / `KanbanBoardSkeleton` / `OpsDashboard` skeleton, не Spinner на странице
|
||||
- **Empty** — `EmptyState` с CTA
|
||||
- **Zero-results** — message внутри DataGrid (+ «Сбросить»)
|
||||
- **Error** — `QueryState` / `Alert` + `onRetry`
|
||||
- **Overflow** — `truncate`, `max-w-*`, `Tooltip`; `tabular-nums` для чисел
|
||||
- **Density** — operational (`dense` Frame/DataGrid); max 1 primary CTA
|
||||
- **A11y** — `aria-invalid`, `aria-label`/`sr-only` на icon-only, `aria-current="page"` на active nav/settings
|
||||
|
||||
## Button hierarchy (max 1 primary per screen)
|
||||
|
||||
1. `default` — главный CTA
|
||||
2. `outline` — вторичные действия
|
||||
3. `ghost` / `link` — навигация, cancel
|
||||
4. `destructive` — только с `ConfirmDialog`
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
description: Только hybrid KPI — KpiStatGrid / row tile DNA (stats-12). Запрет SectionCards и hand-roll.
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# KPI hybrid — только kit (stats-12 DNA)
|
||||
|
||||
Preview: [stats-12](https://reui.io/preview/base/stats-12). SoT DNA = EvoBGP. Markup в проекте: `apps/web/src/components/reui-kit/kpi-stat-grid.tsx`.
|
||||
|
||||
Связанные: [`reui-mcp.mdc`](reui-mcp.mdc), [`frontend-ui-patterns.mdc`](frontend-ui-patterns.mdc).
|
||||
|
||||
## MUST
|
||||
|
||||
| Зона | Компонент / DNA |
|
||||
|------|-----------------|
|
||||
| KPI-полосы / dashboard metrics | только `reui-kit/KpiStatGrid` (через `OpsDashboard` / `DetailPanel.Metrics` при наличии) |
|
||||
| Markup | horizontal compact hybrid: icon left `Item` `size-10.5` `bg-muted` + `border-background` + shadow + `ItemMedia` + label/Badge + value ± `variant` |
|
||||
| Row icon tiles (data-grid) | та же DNA — semantic `text-*` на `bg-muted` |
|
||||
| Quick Actions | только `reui-kit/QuickActionGrid` (sibling hybrid DNA) |
|
||||
|
||||
Импорты UI: `@telemt/ui/components/*`.
|
||||
|
||||
## NEVER
|
||||
|
||||
- SectionCards / vertical-only KPI / hand-roll Frame/Card KPI
|
||||
- Другой size / radius / solid brand fill вместо `bg-muted`
|
||||
- `card-35` как замена stats-12 hybrid KPI
|
||||
- Копипаст ReUI block в route — adapt через `reui-kit/`
|
||||
- Голый lucide `size-4` в name-cell без hybrid tile
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
description: Структура telemt-panel — pnpm monorepo (apps/web, apps/api, packages/ui, packages/shared, packages/db)
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Структура проекта telemt-panel
|
||||
|
||||
pnpm workspaces monorepo. Frontend — shadcn/ui + ReUI (`@reui`) + TanStack Router/Query + TS. Backend — Fastify + Drizzle + better-sqlite3 + TS.
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
telemt-panel/
|
||||
├── apps/
|
||||
│ ├── web/ # Vite SPA (TSX) — TanStack Router + Query, shadcn/ui + ReUI
|
||||
│ └── api/ # Fastify 5 API (TS) — @fastify/* + Drizzle
|
||||
├── packages/
|
||||
│ ├── ui/ # @telemt/ui — shadcn primitives (output `shadcn add`)
|
||||
│ ├── shared/ # @telemt/shared — Zod-схемы контрактов, общие типы
|
||||
│ └── db/ # @telemt/db — Drizzle schema, repositories, миграции
|
||||
├── data/ # SQLite база (том Docker, gitignored)
|
||||
├── pnpm-workspace.yaml
|
||||
├── package.json
|
||||
└── tsconfig.base.json
|
||||
```
|
||||
|
||||
## apps/web
|
||||
|
||||
```
|
||||
apps/web/
|
||||
├── components.json # ui alias → @telemt/ui/components
|
||||
├── vite.config.ts # React + TanStack Router plugin, proxy /api → apps/api
|
||||
├── tsconfig.json
|
||||
└── src/
|
||||
├── main.tsx # QueryClientProvider, createRouter, import '@telemt/ui/globals.css'
|
||||
├── routes/ # file-based routes (__root.tsx, _auth/...)
|
||||
├── queries/ # queryOptions + key factories по сущностям
|
||||
├── components/ # shared + layout + domain (blocks)
|
||||
└── lib/ # api-client, queryClient, router, schemas
|
||||
```
|
||||
|
||||
## apps/api
|
||||
|
||||
```
|
||||
apps/api/
|
||||
└── src/
|
||||
├── index.ts # buildApp()
|
||||
├── config.ts # env через Zod
|
||||
├── routes/ # тонкие Fastify plugins
|
||||
├── services/ # бизнес-логика + адаптеры (billmanager/*)
|
||||
└── plugins/ # @fastify/* registration
|
||||
```
|
||||
|
||||
## packages/db
|
||||
|
||||
```
|
||||
packages/db/src/
|
||||
├── schema/ # Drizzle tables по сущностям
|
||||
├── repositories/ # typed queries (inArray, JOIN, transaction)
|
||||
└── migrations/ # drizzle-kit generate/migrate
|
||||
```
|
||||
|
||||
## Именование
|
||||
|
||||
- Файлы: kebab-case (`provider-accounts.ts`, `row-mappers.ts`)
|
||||
- Компоненты: PascalCase (`PageHeader.tsx`)
|
||||
- Роуты API: `/api/vps`, `/api/provider-accounts`, `/api/sync/:accountId`
|
||||
- ID записей: `vps-bm-{accountId}-{externalId}`, `pay-bm-{accountId}-{externalId}`
|
||||
|
||||
## Barrel exports
|
||||
|
||||
- `packages/ui` — `@telemt/ui/components/*`, `@telemt/ui/lib/utils`, `@telemt/ui/hooks/*`, `@telemt/ui/globals.css`
|
||||
- `packages/shared` — `@telemt/shared/contracts/*` (Zod), `@telemt/shared/types/*`
|
||||
- `packages/db` — `@telemt/db/schema`, `@telemt/db/repositories/*`
|
||||
- `apps/api/src/services/billmanager/index.ts` — `testConnection`, `syncFromBillmanager`, `fetchDashboardInfo`
|
||||
|
||||
## Скоупы правил
|
||||
|
||||
- Frontend (`apps/web`, `packages/ui`) — [`frontend-monorepo.mdc`](frontend-monorepo.mdc), [`frontend-shadcn.mdc`](frontend-shadcn.mdc), [`frontend-ui-patterns.mdc`](frontend-ui-patterns.mdc), [`vite-tanstack-frontend.mdc`](vite-tanstack-frontend.mdc), [`shadcn-mcp.mdc`](shadcn-mcp.mdc), [`reui-mcp.mdc`](reui-mcp.mdc), [`shadcn-ui-production.mdc`](shadcn-ui-production.mdc)
|
||||
- Backend (`apps/api`, `packages/db`, `packages/shared`) — [`backend-fastify.mdc`](backend-fastify.mdc), [`backend-drizzle.mdc`](backend-drizzle.mdc), [`backend-mcp.mdc`](backend-mcp.mdc), [`backend-testing.mdc`](backend-testing.mdc), [`backend-api-ui.mdc`](backend-api-ui.mdc), [`sqlite.mdc`](sqlite.mdc)
|
||||
- API + UI-связка — [`backend-api-ui.mdc`](backend-api-ui.mdc)
|
||||
@@ -0,0 +1,114 @@
|
||||
---
|
||||
description: ReUI PRO (@reui) — MCP user-reui, Frame surface, kit, license, матрица выбора
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# ReUI MCP — обязательно (PRO + free)
|
||||
|
||||
**Приоритет:** ReUI PRO **выше** голого shadcn. См. [`reui-pro-priority.mdc`](reui-pro-priority.mdc).
|
||||
|
||||
Проект: **Base UI** (`style: base-nova`), surface lock **`frame`**.
|
||||
|
||||
Связанные: [`reui-pro-priority.mdc`](reui-pro-priority.mdc), [`shadcn-mcp.mdc`](shadcn-mcp.mdc), [`frontend-monorepo.mdc`](frontend-monorepo.mdc), [`frontend-shadcn.mdc`](frontend-shadcn.mdc), [`frontend-ui-patterns.mdc`](frontend-ui-patterns.mdc).
|
||||
|
||||
| Документ | URL |
|
||||
|----------|-----|
|
||||
| **llms.txt** | https://reui.io/llms.txt |
|
||||
| **Get Started** | https://reui.io/docs/get-started |
|
||||
| **Styling** | https://reui.io/docs/styling |
|
||||
| **MCP** | https://reui.io/docs/mcp |
|
||||
| **Blocks** | https://reui.io/blocks |
|
||||
| **Settings blocks** | https://reui.io/blocks/application/settings |
|
||||
| **License** | https://reui.io/docs/license-setup |
|
||||
| **Base UI components** | https://reui.io/docs/components/base/<name> |
|
||||
|
||||
## Primary MCP
|
||||
|
||||
1. **`user-reui`** — `search` / `compose_page` / `get_block` / `get_component` / `get_install_command` / `validate_usage` / `get_audit_checklist`
|
||||
2. **`plugin-shadcn-shadcn`** — primitives `@shadcn`; для `@reui` — вторично
|
||||
|
||||
**Обязательно** цитировать `previewUrl` + `docsUrl` для каждой UI-зоны.
|
||||
|
||||
## Когда ReUI vs shadcn
|
||||
|
||||
| Задача | Registry | Импорт |
|
||||
|--------|----------|--------|
|
||||
| Button, Sheet, Field, Sidebar, Tabs | `@shadcn` | `@telemt/ui/components/*` |
|
||||
| PRO pages/sections (settings, stats, auth, dashboard) | `@reui` blocks | adapt → `apps/web/src/components/` / `reui-kit/` |
|
||||
| Data Grid | `@reui` | `@/components/reui/data-grid/*` → `ResourcePage` |
|
||||
| Filters | `@reui` | `@/components/reui/filters` |
|
||||
| Frame surface | `@reui` | `@/components/reui/frame` |
|
||||
| KPI | block [stats-12](https://reui.io/preview/base/stats-12) | `reui-kit/KpiStatGrid` — см. [`kpi-hybrid.mdc`](kpi-hybrid.mdc) |
|
||||
| Quick Actions | Frame tiles sibling KPI | `reui-kit/QuickActionGrid` |
|
||||
| Semantic badge / alert | `@reui` | `@/components/reui/badge`, `@/components/reui/alert` |
|
||||
| Number / date / autocomplete / color / kanban | `@reui` | `@/components/reui/*` |
|
||||
|
||||
**Сложные списки** — `ResourcePage` (с Filters) или `FrameDataGrid` (простой CRUD Frame+DataGrid); не raw `<table>`, не Card shell.
|
||||
**Quick Actions** — только `QuickActionGrid` (не Card / Button grid).
|
||||
**KPI** — только `KpiStatGrid` (EvoBGP hybrid); не SectionCards.
|
||||
|
||||
## MCP workflow
|
||||
|
||||
0. Codegraph / поиск существующих `reui-kit/*`, `@/components/reui/*`
|
||||
1. `user-reui` `search` (`surface: "frame"`, `category` при известном)
|
||||
2. Страница целиком → `compose_page`; секция → `get_block`
|
||||
3. `get_component` для API primitives из `componentsUsed`
|
||||
4. CLI из `apps/web`: `pnpm dlx shadcn@latest add @reui/<name> --yes`
|
||||
5. Post-add: shadcn imports → `@telemt/ui/components/*`
|
||||
6. Adapt by reuse → kit / route
|
||||
7. `validate_usage` + `get_audit_checklist`
|
||||
|
||||
## Размещение
|
||||
|
||||
| Слой | Путь | Импорт |
|
||||
|------|------|--------|
|
||||
| shadcn | `packages/ui/src/components/` | `@telemt/ui/components/*` |
|
||||
| ReUI CLI | `apps/web/src/components/reui/` | `@/components/reui/*` |
|
||||
| PRO blocks (reference) | `apps/web/src/components/blocks/` | adapt into kit, не копипаст в routes |
|
||||
| Kit | `apps/web/src/components/reui-kit/` | `@/components/reui-kit/*` |
|
||||
|
||||
## Установленные ReUI (apps/web)
|
||||
|
||||
**Components:** `frame`, `data-grid/*`, `filters`, `kanban`, `badge`, `alert`, `autocomplete`, `number-field`, `date-selector`, `color-picker`, `timeline`, `rating`, `phone-input`, `icon-stack`
|
||||
|
||||
**Kit:** `ResourcePage`, `KpiStatGrid`, `QuickActionGrid`, `OpsDashboard`, `KanbanBoard`, `DetailPanel`, `SettingsShell`
|
||||
|
||||
**Blocks (reference):** `stats-12`, `card-35`, `auth-13`, `app-shell-12`, `settings-16`, `settings-8`, `empty-state-12`, `form-7`, `data-grid-filtering-2`, `dashboard-1`, …
|
||||
|
||||
## License
|
||||
|
||||
```env
|
||||
# .env.local (gitignored)
|
||||
REUI_LICENSE_KEY=
|
||||
```
|
||||
|
||||
`apps/web/components.json` → `@reui` с `Authorization: Bearer ${REUI_LICENSE_KEY}`.
|
||||
|
||||
## Эталоны preview
|
||||
|
||||
| Зона | Preview |
|
||||
|------|---------|
|
||||
| KPI / Quick Actions | https://reui.io/preview/base/stats-12 · https://reui.io/preview/base/card-12 |
|
||||
| List | https://reui.io/preview/base/data-grid-filtering-2 |
|
||||
| Settings | https://reui.io/preview/base/settings-16 |
|
||||
| Auth | https://reui.io/preview/base/auth-13 |
|
||||
| Shell | https://reui.io/preview/base/app-shell-12 |
|
||||
| Empty | https://reui.io/preview/base/empty-state-12 |
|
||||
|
||||
## Запрещено
|
||||
|
||||
- Копипаст с reui.io без CLI
|
||||
- ReUI в `packages/ui` / импорт как `@telemt/ui`
|
||||
- Radix-варианты docs — только Base UI
|
||||
- Raw `bg-emerald-*` вместо ReUI `variant`
|
||||
- Hand-roll data-grid/filters/KPI/Quick Actions/settings rows при наличии `@reui` / kit
|
||||
- Смешивать Card и Frame на ops-экране
|
||||
- Ставить shadcn/ui blocks выше ReUI PRO
|
||||
|
||||
## Чеклист
|
||||
|
||||
- [ ] `user-reui` search/get_block + previewUrl
|
||||
- [ ] `surface: frame`
|
||||
- [ ] CLI add из `apps/web` при новом item
|
||||
- [ ] Kit / `@/components/reui` / `@telemt/ui` — правильный слой
|
||||
- [ ] `pnpm --filter web build`
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
description: ReUI PRO приоритетнее голого shadcn — иерархия UI для telemtPanel
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# ReUI PRO > голый shadcn
|
||||
|
||||
В **telemtPanel** UI строится **reuse-first** из ReUI PRO. Голый shadcn/ui — только primitives и токены, никогда как источник страниц/blocks.
|
||||
|
||||
## Иерархия (жёстко)
|
||||
|
||||
1. **ReUI PRO** — MCP `user-reui` + registry `@reui` + kit `reui-kit/`
|
||||
pages, KPI, lists, settings, shell, empty, forms-as-blocks, Quick Actions, auth
|
||||
2. **shadcn primitives** — MCP `plugin-shadcn-shadcn` + `@telemt/ui`
|
||||
только Button / Field / Sidebar / Dialog / Sheet / Input / … и design tokens
|
||||
3. **Kit** (`apps/web/src/components/reui-kit/`) — adapt ReUI, не redesign
|
||||
4. **Domain** — wiring данных Telemt / fleet
|
||||
|
||||
## Primary MCP
|
||||
|
||||
1. **`user-reui`** — `search` → `compose_page` / `get_block` / `get_component` → `get_install_command` → CLI → `validate_usage`
|
||||
2. **`plugin-shadcn-shadcn`** — только free shadcn primitives / registry sync, **не** вместо PRO blocks
|
||||
|
||||
Skill: `.cursor/skills/reui/SKILL.md` · docs: [Cursor](https://reui.io/docs/cursor) · [License](https://reui.io/docs/license-setup) · [Blocks](https://reui.io/blocks)
|
||||
|
||||
## Surface
|
||||
|
||||
Ops / dashboard / list / detail / settings: **`surface: frame`** (`apps/web/src/lib/ui-surface.ts`).
|
||||
Не смешивать Card и Frame на одном ops-экране.
|
||||
|
||||
## Запрещено
|
||||
|
||||
- Поднимать **ui.shadcn.com/blocks** / shadcn MCP выше ReUI PRO для ops-экранов
|
||||
- Hand-roll data-grid / KPI / Quick Actions / settings rows / empty / auth page при наличии `@reui` / kit
|
||||
- Ставить SectionCards / DataGridCard / raw `<table>` как эталон
|
||||
- `space-y-*` / `space-x-*` — только `flex` + `gap-*`
|
||||
- Raw `bg-emerald-*` вместо semantic / ReUI `variant`
|
||||
- Копипаст markup с сайта без `pnpm dlx shadcn@latest add @reui/...`
|
||||
|
||||
## Обязательные ссылки в ответах по UI
|
||||
|
||||
Для затронутой зоны всегда: `previewUrl` + `docsUrl` (например [stats-12](https://reui.io/preview/base/stats-12), [app-shell-12](https://reui.io/preview/base/app-shell-12)).
|
||||
|
||||
Детали: [`reui-mcp.mdc`](reui-mcp.mdc), [`kpi-hybrid.mdc`](kpi-hybrid.mdc), `docs/ui-design-contract.md`, `AGENTS.md`.
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
description: ReUI skill pointer — workflow в .cursor/skills/reui; PRO выше голого shadcn
|
||||
globs: ["**/*.tsx","**/*.ts"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# ReUI (skill + PRO priority)
|
||||
|
||||
Полный workflow skill: [`.cursor/skills/reui/SKILL.md`](../skills/reui/SKILL.md).
|
||||
|
||||
**Приоритет UI:** ReUI PRO (`@reui` + MCP `user-reui`) → kit `reui-kit/` → shadcn primitives `@telemt/ui`.
|
||||
Голый shadcn/ui blocks **не** primary. См. [`reui-pro-priority.mdc`](reui-pro-priority.mdc), [`reui-mcp.mdc`](reui-mcp.mdc).
|
||||
|
||||
Краткий loop:
|
||||
|
||||
1. `user-reui` `search` (`surface: "frame"`) — cite `previewUrl` + `docsUrl`
|
||||
2. `get_install_command` → `pnpm dlx shadcn@latest add @reui/<name> --yes` из `apps/web`
|
||||
3. `get_component` / examples — реальный API
|
||||
4. Adapt into kit / route — не redesign
|
||||
5. `validate_usage` / `get_audit_checklist`
|
||||
|
||||
License: `REUI_LICENSE_KEY` в `.env.local` · [license-setup](https://reui.io/docs/license-setup).
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
description: shadcn MCP — primitives secondary; pages/blocks → user-reui first
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# shadcn MCP — primitives (secondary)
|
||||
|
||||
**Не primary.** Иерархия: ReUI PRO → kit → shadcn primitives. См. [`reui-pro-priority.mdc`](reui-pro-priority.mdc).
|
||||
|
||||
Перед UI-задачей: **сначала** MCP `user-reui` для pages / KPI / lists / settings / Frame / auth / empty ([`reui-mcp.mdc`](reui-mcp.mdc)).
|
||||
MCP `plugin-shadcn-shadcn` — **только** primitives `@shadcn` / `@telemt/ui` и registry sync. **Запрещено** брать ui.shadcn.com/blocks вместо `@reui` PRO.
|
||||
|
||||
CLI и docs — **после** MCP, по команде из `get_add_command_for_items`.
|
||||
|
||||
## Порядок (primitives)
|
||||
|
||||
0. Поиск существующих shared / `reui-kit`
|
||||
1. **`get_project_registries`**
|
||||
2. **`search_items_in_registries`** — primitive / example
|
||||
3. **`get_item_examples_from_registries`**
|
||||
4. **`get_add_command_for_items`** → CLI из `apps/web`
|
||||
5. `pnpm dlx shadcn@latest docs <component>` — сверить API
|
||||
6. Адаптировать под TanStack → `apps/web/src/`
|
||||
7. Context7 — только TanStack / Recharts / не-shadcn
|
||||
8. **`get_audit_checklist`** — перед merge
|
||||
|
||||
## Когда
|
||||
|
||||
| Задача | MCP |
|
||||
|--------|-----|
|
||||
| Новая страница / KPI / list / settings | **`user-reui`** ([`reui-mcp.mdc`](reui-mcp.mdc)) |
|
||||
| Нет примитива в `@telemt/ui` | `plugin-shadcn-shadcn` → add |
|
||||
| Сомнение в props примитива | examples + docs CLI |
|
||||
|
||||
## Запрещено
|
||||
|
||||
- Писать UI по памяти
|
||||
- Ставить ui.shadcn.com/blocks выше ReUI PRO
|
||||
- Самописные примитивы при наличии registry item
|
||||
|
||||
## Сервер
|
||||
|
||||
- **MCP:** `plugin-shadcn-shadcn` (+ `user-reui` primary)
|
||||
- Schema: `mcps/plugin-shadcn-shadcn/tools/`
|
||||
|
||||
Связанные: [`shadcn-ui-production.mdc`](shadcn-ui-production.mdc), [`reui-mcp.mdc`](reui-mcp.mdc), [`frontend-shadcn.mdc`](frontend-shadcn.mdc).
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
description: shadcn/ui + ReUI PRO — глобальные UI-принципы; ReUI PRO выше shadcn
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# shadcn/ui + ReUI PRO — правила проекта
|
||||
|
||||
UI строится по [shadcn/ui](https://ui.shadcn.com/docs/installation) + **ReUI PRO** (`@reui`): [Components](https://ui.shadcn.com/docs/components), [Blocks](https://ui.shadcn.com/blocks), [ReUI Get Started](https://reui.io/docs/get-started), [llms.txt](https://reui.io/llms.txt).
|
||||
|
||||
**Иерархия:** ReUI PRO (`user-reui`) **выше** базового shadcn. Pages / KPI / lists / settings / shell → ReUI; shadcn — primitives.
|
||||
|
||||
**Первый шаг UI-задачи:**
|
||||
1. MCP **`user-reui`** для pages / KPI / data-grid / settings / Frame / Quick Actions (`surface: frame`)
|
||||
2. MCP **`plugin-shadcn-shadcn`** для primitives `@shadcn`
|
||||
|
||||
См. [`shadcn-mcp.mdc`](shadcn-mcp.mdc), [`reui-mcp.mdc`](reui-mcp.mdc). Contract: [`docs/ui-design-contract.md`](../../docs/ui-design-contract.md).
|
||||
|
||||
## Frontend
|
||||
|
||||
Детали: [`frontend-shadcn.mdc`](frontend-shadcn.mdc), [`frontend-ui-patterns.mdc`](frontend-ui-patterns.mdc), [`frontend-monorepo.mdc`](frontend-monorepo.mdc).
|
||||
|
||||
Кратко: MCP → CLI из `apps/web` → Block → kit → `pnpm --filter web build`. Кастомный CSS и самописные примитивы **запрещены**.
|
||||
|
||||
## Стек
|
||||
|
||||
- Monorepo: `apps/web` + `packages/ui` (`@telemt/ui`), pnpm workspaces
|
||||
- Vite + TanStack Router/Query + shadcn **base-nova** + ReUI **@reui**
|
||||
- Конфиг: [`apps/web/components.json`](apps/web/components.json), [`packages/ui/components.json`](packages/ui/components.json)
|
||||
- Тема: `pnpm dlx shadcn@latest apply b2fA --only theme -y`; ReUI tokens — [Styling](https://reui.io/docs/styling)
|
||||
- License: `REUI_LICENSE_KEY` в `apps/web/.env.local`
|
||||
|
||||
## Backend → UI
|
||||
|
||||
При правках API с экранами: [`backend-api-ui.mdc`](backend-api-ui.mdc). Backend: `apps/api` (Fastify + Drizzle).
|
||||
|
||||
## Язык
|
||||
|
||||
Русский. Commits: [`commit-messages-ru.mdc`](commit-messages-ru.mdc).
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
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 → @telemt/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`
|
||||
Reference in New Issue
Block a user