feat!(web): migrate UI from SvelteKit to React + shadcn/ui + ReUI
CI / changes (push) Successful in 17s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 26s
CI / web (push) Successful in 46s
CI / go (push) Successful in 1m1s
CI / bird2 (push) Successful in 17s
CI / release (push) Failing after 2m22s
CI / changes (push) Successful in 17s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 26s
CI / web (push) Successful in 46s
CI / go (push) Successful in 1m1s
CI / bird2 (push) Successful in 17s
CI / release (push) Failing after 2m22s
Web UI полностью переведён с SvelteKit на новый стек: React 19, TanStack Router/Query/Table/Virtual, shadcn/ui (base-nova) и ReUI enterprise-компоненты (data-grid, filters, autocomplete). Новый код разложен по слоям: packages/ui (shadcn-примитивы), apps/web (роуты, shared-обёртки, ReUI-адаптации). BREAKING CHANGE: меняется структура и инструментинг фронтенда. - apps/web/ — новый Vite + React-проект (@evobgp/web), file-based роуты TanStack Router; экраны dashboard, modules, monitoring, network, operations, schedule, settings, tenant-settings, access, directories. - packages/ui/ — shadcn/ui-примитивы (@evobgp/ui) с общими стилями globals.css и cn-утилитой; CLI shadcn запускается из apps/web. - apps/web/src/components/reui/ — enterprise-паттерны ReUI. - pnpm workspace (pnpm-workspace.yaml, pnpm-lock.yaml, tsconfig.base.json) заменяет npm-проект в web/. - web/ переименован в web-legacy-svelte/ (архив-референс для миграции); импорты оттуда запрещены правилом WEB-22. - CI (.gitea/workflows/ci.yaml): job web переведён на Node 22 + pnpm 10 (typecheck/lint/build через pnpm --filter @evobgp/web); пути триггеров обновлены под apps/web|packages/ui. - deploy/docker/evobgp-web/Dockerfile: сборка из корня репозитория, pnpm install --frozen-lockfile, выход dist из apps/web/dist. - .cursor/rules/web-shadcn.mdc, context7-stack.mdc, engineering.mdc, AGENTS.md — обновлены под React-стек (WEB-01..WEB-22, DOC-SYNC-06/07). Проверки WEB-19 локально: typecheck, lint, build — exit 0. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -0,0 +1,345 @@
|
||||
---
|
||||
name: EvoBGP → React+shadcn/ui+ReUI
|
||||
overview: "Big-bang миграция web UI EvoBGP с SvelteKit+Svelte5 на React 19 + Vite + TanStack Router/Query + shadcn/ui (Base UI, base-nova) + ReUI registry, идентично эталону vps-tracker. Структура — pnpm workspaces monorepo (apps/web + packages/ui как @evobgp/ui). Скоуп: только фронтенд; Go-бэкенд, OpenAPI, nginx, compose и bake-конфиги сохраняются с минимальной правкой путей сборки. Старый web/ заменяется полностью; перенос доменных экранов идёт по одному роуту через MCP-shadcn с проверкой по docs."
|
||||
todos:
|
||||
- id: "1"
|
||||
content: "Этап 0: Установить MCP в workspace EvoBGP (plugin-shadcn-shadcn с @reui, plugin-context7, cursor-ide-browser) — скопировать .cursor/mcp.json из vps-tracker"
|
||||
status: pending
|
||||
- id: "2"
|
||||
content: "Этап 1: Архивировать web/ → web-legacy-svelte/, зафиксировать инвентарь 13 роутов и компонентов"
|
||||
status: pending
|
||||
- id: "3"
|
||||
content: "Этап 2: Создать pnpm workspaces монорепо — pnpm-workspace.yaml, корневой package.json, tsconfig.base.json, .npmrc, .nvmrc"
|
||||
status: pending
|
||||
- id: "4"
|
||||
content: "Этап 3: Создать packages/ui (@evobgp/ui) — package.json, components.json (base-nova + @reui), src/styles/globals.css (копия vps-tracker), lib/utils.ts, hooks/use-mobile.ts"
|
||||
status: pending
|
||||
- id: "5"
|
||||
content: "Этап 4: Добавить shadcn-примитивы в packages/ui через MCP+CLI (33 компонента идентично vps-tracker)"
|
||||
status: pending
|
||||
- id: "6"
|
||||
content: "Этап 5: Создать apps/web каркас — package.json (@evobgp/web), components.json, tsconfig, vite.config.ts (TanStackRouterPlugin+react+tailwindcss, alias @ и @evobgp/ui/*, proxy /v1)"
|
||||
status: pending
|
||||
- id: "7"
|
||||
content: "Этап 6: React-инициализация — main.tsx (StrictMode→ThemeProvider→QC→Router+Toaster), lib/queryClient.ts, lib/router.ts (Register augmentation), routes/__root.tsx, theme-provider.tsx, index.html"
|
||||
status: pending
|
||||
- id: "8"
|
||||
content: "Этап 7: Перенос app-shell (sidebar-07) и shared-обёрток (PageShell, PageHeader, EmptyState, QueryState, ConfirmDialog, StatusBadge, DataGridCard, FormSheet, FormField, LoadingButton, skeletons) из vps-tracker с адаптацией брендинга"
|
||||
status: pending
|
||||
- id: "9"
|
||||
content: "Этап 8: Перенос API-клиента и типов из legacy — api-client.ts (Bearer localStorage, Idempotency-Key, RFC 9457 Problem, waitForJob, apiPageAll), types/api.ts, queries/* по доменам"
|
||||
status: pending
|
||||
- id: "10"
|
||||
content: "Этап 9: Добавить ReUI enterprise через MCP+CLI — @reui/data-grid, filters, autocomplete, date-selector, number-field, color-picker, badge"
|
||||
status: pending
|
||||
- id: "11"
|
||||
content: "Этап 10.1: Роуты _auth layout + settings (token+theme) + access (session+api-keys) — простые экраны"
|
||||
status: pending
|
||||
- id: "12"
|
||||
content: "Этап 10.2: Роуты index (dashboard KPI+recent) + modules/index (DataGridCard) + modules/$moduleId (детали с cards)"
|
||||
status: pending
|
||||
- id: "13"
|
||||
content: "Этап 10.3: Роуты network (peers/speakers/BIRD tabs, live refetchInterval) + operations (jobs/revisions/diff, waitForJob) + schedule"
|
||||
status: pending
|
||||
- id: "14"
|
||||
content: "Этап 10.4: Роуты directories (communities/DoH) + monitoring (bird/postgres/runtime) + tenant-settings + редиректы peers→network, revisions→operations"
|
||||
status: pending
|
||||
- id: "15"
|
||||
content: "Этап 11: Обновить deploy/docker/evobgp-web/Dockerfile (pnpm+corepack, COPY apps/web + packages, dist вместо build); nginx.conf НЕ трогать; проверить bake"
|
||||
status: pending
|
||||
- id: "16"
|
||||
content: "Этап 12: Обновить .gitea/workflows/ci.yaml web job (pnpm, tsc --noEmit, eslint, build) + path-filter apps/web/** + packages/ui/**"
|
||||
status: pending
|
||||
- id: "17"
|
||||
content: "Этап 13: Cursor rules — удалить web-shadcn.mdc; скопировать shadcn-mcp/reui-mcp/frontend-* из vps-tracker; обновить engineering.mdc (DEP-04, TEST-04, DOC-SYNC) и context7-stack.mdc; создать .agents/skills/{shadcn,reui}"
|
||||
status: pending
|
||||
- id: "18"
|
||||
content: "Этап 14: Финал — pnpm build без ошибок, MCP get_audit_checklist, cursor-ide-browser smoke 13 роутов, удалить web-legacy-svelte/, коммит feat(frontend)"
|
||||
status: pending
|
||||
isProject: false
|
||||
---
|
||||
|
||||
# Plan: Миграция EvoBGP web UI на React + shadcn/ui + ReUI
|
||||
|
||||
## Контекст
|
||||
|
||||
**Цель:** Перевести `web/` EvoBGP с SvelteKit 2.50 + Svelte 5.54 + shadcn-svelte на стек идентичный `vps-tracker/apps/web`:
|
||||
- **Стек:** React 19 + Vite 7 + TanStack Router/Query v5 + shadcn/ui (Base UI, `style: base-nova`) + ReUI registry `@reui` + Tailwind v4 monorepo + lucide-react + react-hook-form + Zod + recharts + sonner + next-themes
|
||||
- **Структура:** pnpm workspaces monorepo — `apps/web` (SPA) + `packages/ui` (`@evobgp/ui` barrel)
|
||||
- **Скоуп:** только frontend. Go-бэкенд (`internal/*`), OpenAPI (`docs/openapi.yaml`), compose/bake/nginx — не трогаются (минимальная правка только путей сборки в Dockerfile)
|
||||
- **Стратегия:** big-bang. Старый `web/` архивируется в `web-legacy-svelte/` и удаляется в финале. Рабочий UI создаётся с нуля
|
||||
- **Эталон:** `c:\Users\shats\Dev\vps-tracker\apps\web\` + `c:\Users\shats\Dev\vps-tracker\packages\ui\`
|
||||
|
||||
**Инвентарь существующего EvoBGP web** (из исследования):
|
||||
- 13 роутов SvelteKit: `/`, `/modules`, `/modules/[id]`, `/network` (+редирект `/peers`), `/operations` (+редирект `/revisions`), `/monitoring`, `/schedule`, `/directories`, `/access`, `/tenant-settings`, `/settings`
|
||||
- ~130 доменных `.svelte`-компонентов в `web/src/lib/components/{modules,network,operations,monitoring,tenant-settings,access,...}`
|
||||
- API-клиент `web/src/lib/api/client.ts` + типы `web/src/lib/api/types.ts` (4301 строка OpenAPI, 76 эндпоинтов)
|
||||
- Токен в localStorage (`evobgp_api_token`), Bearer, RFC 9457 errors, cursor-пагинация, Idempotency-Key, polling jobs
|
||||
- Тема `neutral` в `web/src/routes/layout.css` с semantic tokens `--success/--warning/--info`
|
||||
- nginx.conf — SPA fallback `try_files $uri $uri/ /index.html` (нейтрален к фреймворку, не меняется)
|
||||
- Сейчас npm (НЕ pnpm), корневого `pnpm-workspace.yaml` нет
|
||||
|
||||
**Архитектура после миграции**:
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph EvoBGP[EvoBGP repo root]
|
||||
PWS[pnpm-workspace.yaml]
|
||||
RP[package.json + pnpm-lock.yaml]
|
||||
TSB[tsconfig.base.json]
|
||||
NVM[.nvmrc Node 22]
|
||||
MCP[.cursor/mcp.json]
|
||||
subgraph Apps
|
||||
AW[apps/web — React SPA]
|
||||
end
|
||||
subgraph Packages
|
||||
UI[packages/ui — @evobgp/ui]
|
||||
end
|
||||
Deploy[deploy/ nginx+compose+bake]
|
||||
GoAPI[internal/httpapi — Go API]
|
||||
end
|
||||
AW -->|imports| UI
|
||||
AW -->|/v1 proxy dev| GoAPI
|
||||
Deploy -->|Dockerfile build| AW
|
||||
Deploy -->|nginx /v1 proxy| GoAPI
|
||||
UI -->|globals.css @source| AW
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Этапы (последовательность, safe-by-design)
|
||||
|
||||
### Этап 0 — MCP environment (предварительный)
|
||||
|
||||
Установить MCP-серверы в workspace EvoBGP. Источник: `c:\Users\shats\.cursor\projects\c-Users-shats-Dev-vps-tracker\mcps\` — там работают:
|
||||
- `plugin-shadcn-shadcn` (serverName `shadcn`) — даёт инструменты `get_project_registries`, `search_items_in_registries` (с поддержкой `registries: ["@reui"]`), `get_item_examples_from_registries`, `get_add_command_for_items`, `view_items_in_registries`, `list_items_in_registries`, `get_audit_checklist`
|
||||
- `plugin-context7-plugin-context7` — docs-lookup React/TanStack/Recharts
|
||||
- `cursor-ide-browser` — визуальная проверка UI
|
||||
|
||||
Скопировать `.cursor/mcp.json` из vps-tracker → `c:\Users\shats\Dev\EvoBGP\.cursor\mcp.json`. Enable серверы в Cursor Settings. ReUI MCP и codegraph — **не существуют как отдельные MCP** (исследовано); ReUI доступен **через** `plugin-shadcn-shadcn` с `registries: ["@reui"]`.
|
||||
|
||||
### Этап 1 — Подготовка
|
||||
|
||||
1. **Зафиксировать инвентарь**: список 13 роутов + ~130 компонентов + API-клиент + типы. Не удалять пока ничего.
|
||||
2. **Архивировать старый стек**: `web/` → `web-legacy-svelte/`. Оставить до финала как референс при переносе экранов.
|
||||
|
||||
### Этап 2 — Монорепо-каркас
|
||||
|
||||
Корневые файлы:
|
||||
|
||||
- `pnpm-workspace.yaml`: `packages: ['apps/*', 'packages/*']`
|
||||
- Корневой `package.json`: `{"private": true, "scripts": {"dev": "pnpm --filter @evobgp/web dev", "build": "pnpm --filter @evobgp/web build", "lint": "pnpm -r lint"}}`. Существующий корневой `package.json` (semantic-release/commitlint) — слить в один или оставить как `package.release.json` (решить по ходу).
|
||||
- `tsconfig.base.json`: `strict: true`, `target: ES2022`, `moduleResolution: bundler`, `jsx: react-jsx`, `paths: {"@/*": ["./apps/web/src/*"], "@evobgp/ui/components/*": ["./packages/ui/src/components/*"], "@evobgp/ui/hooks/*": ["./packages/ui/src/hooks/*"], "@evobgp/ui/lib/utils": ["./packages/ui/src/lib/utils.ts"]}`
|
||||
- `.npmrc`: `engine-strict=true`
|
||||
- `.nvmrc`: `22` (приводим к единой версии с Dockerfile)
|
||||
- `.gitignore`: добавить `node_modules/`, `dist/`, `routeTree.gen.ts` (опц.)
|
||||
|
||||
### Этап 3 — `packages/ui` (@evobgp/ui)
|
||||
|
||||
Структура полностью повторяет `c:\Users\shats\Dev\vps-tracker\packages\ui\`:
|
||||
|
||||
- `packages/ui/package.json`:
|
||||
- `name: "@evobgp/ui"`
|
||||
- `exports`: `./components/*`, `./hooks/*`, `./lib/utils`, `./globals.css`
|
||||
- `dependencies`: `@base-ui/react`, `class-variance-authority`, `clsx`, `cmdk`, `date-fns`, `lucide-react`, `next-themes`, `react-day-picker`, `recharts`, `sonner`, `tailwind-merge`
|
||||
- `peerDependencies`: `react`, `react-dom` (19)
|
||||
- `packages/ui/components.json` (точная копия vps-tracker с заменой `@cfdm` → `@evobgp`):
|
||||
```json
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "base-nova",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {"config": "", "css": "src/styles/globals.css", "baseColor": "neutral", "cssVariables": true},
|
||||
"iconLibrary": "lucide",
|
||||
"registries": {"@reui": "https://reui.io/r/{style}/{name}.json"},
|
||||
"aliases": {"components": "@evobgp/ui/components", "utils": "@evobgp/ui/lib/utils", "hooks": "@evobgp/ui/hooks", "lib": "@evobgp/ui/lib", "ui": "@evobgp/ui/components"}
|
||||
}
|
||||
```
|
||||
- `packages/ui/src/styles/globals.css`: **точная копия** `c:\Users\shats\Dev\vps-tracker\packages\ui\src\styles\globals.css` (Tailwind v4 + `tw-animate-css` + `@source "../"` + `@source "../../../apps/web/src"` + `:root`/`.dark` со всеми oklch-токенами + ReUI semantic tokens `--success/--info/--warning/--destructive-foreground/--invert/--focus` + chart-1..5 + sidebar-* + `@theme inline` + `@layer base`)
|
||||
- `packages/ui/src/lib/utils.ts`: `cn()` через `clsx` + `tailwind-merge`
|
||||
- `packages/ui/src/hooks/use-mobile.ts`
|
||||
|
||||
### Этап 4 — shadcn-примитивы через MCP
|
||||
|
||||
Перед каждым `add` — обязательно через MCP:
|
||||
1. `search_items_in_registries` → `get_item_examples_from_registries` → `get_add_command_for_items`
|
||||
2. CLI `pnpm dlx shadcn@latest docs <component>` сверка с [ui.shadcn.com/docs/components](https://ui.shadcn.com/docs/components)
|
||||
|
||||
Компоненты (идентично набору `vps-tracker/packages/ui/src/components/`):
|
||||
```
|
||||
button button-group card input textarea label select checkbox field
|
||||
separator scroll-area table badge tabs dialog alert-dialog sheet popover
|
||||
dropdown-menu tooltip breadcrumb sidebar skeleton sonner spinner alert
|
||||
command kbd calendar slider chart input-group input-otp toggle
|
||||
```
|
||||
Команда: `cd apps/web && pnpm dlx shadcn@latest add button card input ...` (CLI пишет в `packages/ui/src/components/` через aliases).
|
||||
|
||||
Применение темы: `pnpm dlx shadcn@latest apply b2fA --only theme -y` (обновит `:root`/`.dark` в `globals.css`).
|
||||
|
||||
### Этап 5 — `apps/web` каркас
|
||||
|
||||
- `apps/web/package.json` (`@evobgp/web`): deps из `vps-tracker/apps/web/package.json` с заменой `@cfdm/*` → `@evobgp/*`:
|
||||
- `react`, `react-dom` 19
|
||||
- `@tanstack/react-router`, `@tanstack/react-router-devtools`, `@tanstack/react-query`, `@tanstack/react-query-devtools`, `@tanstack/react-table`, `@tanstack/react-virtual`
|
||||
- `@hookform/resolvers`, `react-hook-form`, `zod` (v3 для совместимости с RHF-resolvers — как в vps-tracker)
|
||||
- `class-variance-authority`, `cmdk`, `date-fns`, `lucide-react`, `next-themes`, `react-day-picker`, `recharts`, `sonner`
|
||||
- `@dnd-kit/core`, `@dnd-kit/modifiers`, `@dnd-kit/sortable`, `@dnd-kit/utilities`
|
||||
- devDeps: `@tailwindcss/vite`, `@tanstack/router-plugin`, `@types/react`, `@types/react-dom`, `@vitejs/plugin-react`, `happy-dom`, `tailwindcss`, `tw-animate-css`, `typescript`, `vite`, `vitest`
|
||||
- `apps/web/components.json` (алиасы web-side: `@/components`, `@/hooks`, `@/lib`, `utils: @evobgp/ui/lib/utils`, `ui: @evobgp/ui/components`; registries `@reui`; css `../../packages/ui/src/styles/globals.css`)
|
||||
- `apps/web/vite.config.ts` (точная копия vps-tracker с заменой `@cfdm` → `@evobgp`): плагины `TanStackRouterPlugin({ target: 'react', autoCodeSplitting: true })` → `react()` → `tailwindcss()`; alias `@`, `@evobgp/ui/*`; server port 5173, proxy `/v1` и `/metrics` → `http://127.0.0.1:8080`
|
||||
- `apps/web/tsconfig.json` extends `../../tsconfig.base.json`
|
||||
- `apps/web/index.html` (#root, anti-FOUC тема-скрипт `evobgp-theme`)
|
||||
|
||||
### Этап 6 — React-инициализация
|
||||
|
||||
Точная копия vps-tracker с заменой путей:
|
||||
|
||||
- `apps/web/src/main.tsx`: `StrictMode → ThemeProvider → QueryClientProvider → RouterProvider + <Toaster richColors position="top-right" />`, единственный `import '@evobgp/ui/globals.css'`
|
||||
- `apps/web/src/lib/queryClient.ts`: `staleTime: 60_000, retry: 1, refetchOnWindowFocus: false`
|
||||
- `apps/web/src/lib/router.ts`: `createRouter({ routeTree, context, defaultPreload: 'intent', scrollRestoration: true })` + `declare module '@tanstack/react-router'` Register
|
||||
- `apps/web/src/components/theme-provider.tsx`: next-themes `attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange`
|
||||
- `apps/web/src/routes/__root.tsx`: `createRootRouteWithContext<{ queryClient }>` + `<AppShell><Outlet /></AppShell>`
|
||||
|
||||
### Этап 7 — Перенос app-shell и shared-обёрток
|
||||
|
||||
Перенести из `vps-tracker/apps/web/src/components/` с адаптацией брендинга/навигации:
|
||||
- `layout/app-shell.tsx` (block sidebar-07, `SidebarProvider → Sidebar collapsible="icon" → SidebarHeader/SidebarContent(navGroups)/SidebarFooter + SidebarInset(header sticky h-16 backdrop-blur + SidebarTrigger + Breadcrumb + actions + main)`). `render={<Link to={item.to} />}` — **Base UI render-prop, не Radix asChild**. Навигация подставляется под EvoBGP-экраны.
|
||||
- `mode-toggle.tsx`, `page-shell.tsx`, `page-header.tsx`, `empty-state.tsx`, `query-state.tsx`, `confirm-dialog.tsx`, `status-badge.tsx`, `section-cards.tsx`, `form-sheet.tsx`, `form-field.tsx`, `loading-button.tsx`, `skeletons.tsx`
|
||||
- `data-grid-card.tsx` (обёртка над `@reui/data-grid`) — полная копия с типизированным `DataGridCardProps<TData>`
|
||||
|
||||
### Этап 8 — API-клиент и типы (перенос из legacy)
|
||||
|
||||
- `apps/web/src/lib/api-client.ts`: перенос логики из `web-legacy-svelte/src/lib/api/client.ts`:
|
||||
- `TOKEN_STORAGE_KEY = 'evobgp_api_token'`
|
||||
- `mergeHeaders`: Accept JSON + Bearer из localStorage
|
||||
- `apiFetch`, `apiJSON<T>`, `apiMutate<T>` с auto-Idempotency-Key
|
||||
- `parseResponse<T>`: 204/205→undefined, ошибки → `ApiError` с RFC 9457 Problem
|
||||
- `waitForJob(jobId, opts?)`: poll `GET /v1/jobs/{id}` каждые 400ms
|
||||
- `apiPageAll<T>`: cursor-пагинация (`items`/`next_cursor`/`has_more`)
|
||||
- `apps/web/src/types/api.ts`: перенос всех типов из `web-legacy-svelte/src/lib/api/types.ts` (`ModuleRow`, `BgpPeer`, `SpeakerRow`, `RevisionRow`, `JobRow`, `AuthSession`, `ApiKey`, `PostgresOverview`, etc.)
|
||||
- `apps/web/src/queries/` — по доменам: `auth.ts`, `modules.ts`, `network.ts`, `operations.ts`, `monitoring.ts`, `directories.ts`, `access.ts`, `settings.ts` (queryOptions + key factories)
|
||||
|
||||
### Этап 9 — ReUI enterprise-компоненты
|
||||
|
||||
Через MCP `search_items_in_registries` с `registries: ["@reui"]` → `get_item_examples` → `get_add_command`:
|
||||
```bash
|
||||
cd apps/web
|
||||
pnpm dlx shadcn@latest add @reui/data-grid
|
||||
pnpm dlx shadcn@latest add @reui/filters
|
||||
pnpm dlx shadcn@latest add @reui/autocomplete
|
||||
pnpm dlx shadcn@latest add @reui/date-selector
|
||||
pnpm dlx shadcn@latest add @reui/number-field
|
||||
pnpm dlx shadcn@latest add @reui/color-picker
|
||||
pnpm dlx shadcn@latest add @reui/badge
|
||||
```
|
||||
Документация для `@reui/*`: [reui.io/docs/components/base/](https://reui.io/docs/components/base) + [llms.txt](https://reui.io/llms.txt) — **не** ui.shadcn.com для ReUI.
|
||||
|
||||
Ложатся в `apps/web/src/components/reui/` (НЕ в packages/ui). Post-add: импорты shadcn-примитивов внутри ReUI → `@evobgp/ui/components/*`. Проверить что `@tanstack/react-table`, `@tanstack/react-virtual`, `@dnd-kit/*`, `date-fns`, `react-day-picker` попали в `apps/web/package.json`.
|
||||
|
||||
### Этап 10 — Реализация 13 роутов (поэтапно)
|
||||
|
||||
Каждый роут — отдельная подзадача. Порядок от простого к сложному (позволяет рано верифицировать стек):
|
||||
|
||||
| # | Файл (TanStack file-based) | Что делает | Источник (legacy) |
|
||||
|---|---|---|---|
|
||||
| 1 | `routes/_auth.tsx` + `_auth.tsx` layout | auth guard (токен в localStorage) | `routes/+layout.ts` |
|
||||
| 2 | `routes/_auth/settings.tsx` | API-токен + тема (свет/тёмн/сист) | `routes/settings/+page.svelte` |
|
||||
| 3 | `routes/_auth/access.tsx` | `GET /v1/auth/session` + список API-ключей | `routes/access/+page.svelte` |
|
||||
| 4 | `routes/index.tsx` | dashboard: KPI + recent jobs/revisions + network status | `routes/+page.svelte` |
|
||||
| 5 | `routes/_auth/modules/index.tsx` | список модулей (DataGridCard) | `routes/modules/+page.svelte` |
|
||||
| 6 | `routes/_auth/modules/$moduleId.tsx` | детали модуля (cards: AS/Cdn/Domain/IpRange) | `routes/modules/[moduleId]/+page.svelte` |
|
||||
| 7 | `routes/_auth/network.tsx` | peers + speakers + BIRD settings (tabs) | `routes/network/+page.svelte` |
|
||||
| 8 | `routes/_auth/operations.tsx` | jobs + revisions + diff (tabs, waitForJob) | `routes/operations/+page.svelte` |
|
||||
| 9 | `routes/_auth/schedule.tsx` | refresh jobs (tabs all/refresh/failed) | `routes/schedule/+page.svelte` |
|
||||
| 10 | `routes/_auth/directories.tsx` | BGP communities + DoH profiles (tabs) | `routes/directories/+page.svelte` |
|
||||
| 11 | `routes/_auth/monitoring.tsx` | bird status + version + postgres + runtime logs | `routes/monitoring/+page.svelte` |
|
||||
| 12 | `routes/_auth/tenant-settings.tsx` | настройки BIRD/ревизий/runtime (tabs) | `routes/tenant-settings/+page.svelte` |
|
||||
| 13 | редиректы | `/peers`→`/network`, `/revisions`→`/operations?tab=revisions` | `routes/peers`, `routes/revisions` |
|
||||
|
||||
Для каждого роута: MCP-shadcn search+examples → `pnpm dlx shadcn@latest docs <name>` сверка с [ui.shadcn.com/docs/components](https://ui.shadcn.com/docs/components) → ReUI для data-grid/filters → композиция @evobgp/ui + DataGridCard; логика переносится из соответствующего `+page.svelte` (но на TanStack Query вместо инлайн fetch). Live-данные (network, monitoring) — `refetchInterval` вместо кастомного `setInterval`.
|
||||
|
||||
### Этап 11 — Инфраструктура деплоя
|
||||
|
||||
**Минимальные правки (compose/bake не трогать):**
|
||||
|
||||
`deploy/docker/evobgp-web/Dockerfile` (3 стадии → 3 стадии):
|
||||
- `deps`: установить pnpm (corepack), `COPY pnpm-workspace.yaml package.json apps/web/package.json packages/ui/package.json ./` + `COPY apps/web/ apps/web/` + `COPY packages/ packages/` → `pnpm install --frozen-lockfile`
|
||||
- `build`: `COPY . .` → `pnpm --filter @evobgp/web build`
|
||||
- `web`: `COPY --from=web-artifacts /app/apps/web/dist /usr/share/nginx/html` (вместо `/web/build`)
|
||||
|
||||
`deploy/docker/evobgp-web/nginx.conf` — **не меняется** (SPA fallback совместим).
|
||||
|
||||
`deploy/docker/docker-bake.hcl` — проверить что target `web-build` корректно прокидывает контекст.
|
||||
|
||||
### Этап 12 — CI/CD
|
||||
|
||||
`.gitea/workflows/ci.yaml`, job `web` (строки 164-181):
|
||||
- `actions/setup-node@v4` → `node-version: "22"`, `cache: pnpm`, `cache-dependency-path: pnpm-lock.yaml`
|
||||
- Добавить `pnpm install` (через corepack)
|
||||
- Заменить `npm run check` → `pnpm --filter @evobgp/web exec tsc --noEmit`
|
||||
- Заменить `npm run lint` → `pnpm --filter @evobgp/web lint` (eslint)
|
||||
- Добавить `pnpm --filter @evobgp/web build` (раньше проверялось только в Docker)
|
||||
|
||||
Job `changes` — path-filter `web/*` → `apps/web/**` + `packages/ui/**` (расширить globs).
|
||||
|
||||
### Этап 13 — Cursor rules + skills
|
||||
|
||||
**Удалить** (Svelte-специфика):
|
||||
- `.cursor/rules/web-shadcn.mdc` (WEB-01..WEB-19 — всё про shadcn-svelte)
|
||||
|
||||
**Скопировать из vps-tracker `.cursor/rules/`** (с заменой `@cfdm` → `@evobgp`, `Vps*` → `EvoBgp*`):
|
||||
- `shadcn-mcp.mdc`, `reui-mcp.mdc`, `shadcn-ui-production.mdc`, `frontend-shadcn.mdc`, `frontend-monorepo.mdc`, `frontend-ui-patterns.mdc`, `vite-tanstack-frontend.mdc`
|
||||
|
||||
**Обновить** `engineering.mdc`:
|
||||
- `DEP-04`: «shadcn-svelte/bits-ui» → «shadcn/ui React (Base UI) + ReUI registry»
|
||||
- `TEST-04`: `npm run check` → `pnpm --filter @evobgp/web exec tsc --noEmit`; `npm run lint` → eslint
|
||||
- `DOC-SYNC-06/07`: `shadcn-svelte.com` → `ui.shadcn.com/docs` + `reui.io/docs`
|
||||
|
||||
**Обновить** `context7-stack.mdc` Web UI таблица: убрать svelte/sveltekit/bits-ui/formsnap/`@lucide/svelte`; добавить React 19, TanStack Router/Query/Table/Virtual, ReUI llms.txt, `lucide-react`.
|
||||
|
||||
**Создать** `c:\Users\shats\Dev\EvoBGP\.agents\skills\` (сейчас не существует):
|
||||
- `shadcn/SKILL.md` — скопировать из cloudflare-domain-manager
|
||||
- `reui/SKILL.md` — скопировать из cloudflare-domain-manager, заменить обёртки под EvoBGP (`DataGridCard`, `NetworkFiltersToolbar`)
|
||||
|
||||
### Этап 14 — Финальная проверка и очистка
|
||||
|
||||
1. `pnpm install && pnpm --filter @evobgp/web build` без ошибок
|
||||
2. MCP `get_audit_checklist` — пройти по чек-листу
|
||||
3. `cursor-ide-browser` smoke-тест всех 13 роутов (login через dev-токен, навигация, CRUD, dark/light toggle)
|
||||
4. Удалить `web-legacy-svelte/`
|
||||
5. Проверить что compose поднимается (`docker compose --profile reference up`)
|
||||
6. Коммит на main (gitflow по `.cursor/rules/conventional-commits.mdc`): `feat(frontend): миграция web UI на React + shadcn/ui + ReUI`
|
||||
|
||||
---
|
||||
|
||||
## Цитаты ключевых файлов эталона
|
||||
|
||||
- Конфиги: [apps/web/components.json](c:\Users\shats\Dev\vps-tracker\apps\web\components.json), [packages/ui/components.json](c:\Users\shats\Dev\vps-tracker\packages\ui\components.json)
|
||||
- Стили: [packages/ui/src/styles/globals.css](c:\Users\shats\Dev\vps-tracker\packages\ui\src\styles\globals.css)
|
||||
- Инициализация: [apps/web/src/main.tsx](c:\Users\shats\Dev\vps-tracker\apps\web\src\main.tsx), [lib/queryClient.ts](c:\Users\shats\Dev\vps-tracker\apps\web\src\lib\queryClient.ts), [lib/router.ts](c:\Users\shats\Dev\vps-tracker\apps\web\src\lib\router.ts)
|
||||
- Layout: [components/layout/app-shell.tsx](c:\Users\shats\Dev\vps-tracker\apps\web\src\components\layout\app-shell.tsx)
|
||||
- Vite: [apps/web/vite.config.ts](c:\Users\shats\Dev\vps-tracker\apps\web\vite.config.ts)
|
||||
- ReUI обёртка: [components/data-grid-card.tsx](c:\Users\shats\Dev\vps-tracker\apps\web\src\components\data-grid-card.tsx)
|
||||
- API-клиент legacy: [web/src/lib/api/client.ts](c:\Users\shats\Dev\EvoBGP\web\src\lib\api\client.ts), [web/src/lib/api/types.ts](c:\Users\shats\Dev\EvoBGP\web\src\lib\api\types.ts)
|
||||
|
||||
## Документация
|
||||
|
||||
- [shadcn/ui Installation](https://ui.shadcn.com/docs/installation)
|
||||
- [shadcn/ui Components](https://ui.shadcn.com/docs/components)
|
||||
- [shadcn/ui Monorepo](https://ui.shadcn.com/docs/monorepo)
|
||||
- [shadcn/ui MCP Server](https://ui.shadcn.com/docs/mcp)
|
||||
- [ReUI Get Started](https://reui.io/docs/get-started)
|
||||
- [ReUI Styling](https://reui.io/docs/styling)
|
||||
- [ReUI MCP](https://reui.io/docs/mcp)
|
||||
- [ReUI llms.txt](https://reui.io/llms.txt)
|
||||
|
||||
## Риски и митигация
|
||||
|
||||
| Риск | Митигация |
|
||||
|---|---|
|
||||
| Big-bang = длинное окно неработающего UI в dev | Этапы 3-9 делаются параллельно с рабочим `web-legacy-svelte/`; переключение атомарно в финале |
|
||||
| ReUI на React 19 / Base UI может иметь breaking changes | MCP `get_item_examples` + dry-run `--dry-run` перед add |
|
||||
| OpenAPI drift (типы в legacy vs контракт) | Типы переносятся как есть (frontend-only scope); Zod-схемы по желанию позже |
|
||||
| npm → pnpm меняет lock-файлы и CI | Пункт 12 явно покрывает CI; corepack в Dockerfile |
|
||||
| 13 роутов = большой объём работы | Этап 10 разбит по сложности; можно остановиться после базовых и продолжить инкрементально |
|
||||
@@ -32,23 +32,28 @@ alwaysApply: true
|
||||
|
||||
---
|
||||
|
||||
## Web UI (`web/`)
|
||||
## Web UI (`apps/web/` + `packages/ui/`)
|
||||
|
||||
| Библиотека | Context7 ID | Версия в проекте | Когда |
|
||||
|------------|-------------|------------------|-------|
|
||||
| Svelte | `/websites/svelte_dev` | ^5.54 | runes, компоненты, реактивность |
|
||||
| SvelteKit | `/sveltejs/kit` | ^2.50 | routing, `load`, adapters, SSR |
|
||||
| React | `/facebook/react` | ^19.2 | hooks, components, JSX |
|
||||
| TanStack Router | `/tanstack/router` | ^1.130 | file-based routes, `createFileRoute`, `useSearch`, `Link` |
|
||||
| TanStack Query | `/tanstack/query` | ^5.90 | `useQuery`, `useMutation`, `queryOptions`, invalidation |
|
||||
| TanStack Table | `/websites/tanstack_table` | ^8.21 | data-grid колонки, сортировка (ReUI) |
|
||||
| TanStack Virtual | `/tanstack/virtual` | ^3.14 | виртуализация списков (ReUI data-grid) |
|
||||
| Vite | `/vitejs/vite/v7.3.1` | ^7.3.1 | dev server, build, plugins |
|
||||
| TypeScript | `/microsoft/typescript/v5.9.3` | ^5.9.3 | типы, strict, tsconfig |
|
||||
| Tailwind CSS | `/tailwindlabs/tailwindcss.com` | ^4.1 | v4, `@tailwindcss/vite`, утилиты |
|
||||
| shadcn-svelte | `/websites/shadcn-svelte` | CLI | примитивы `ui/core`, theming |
|
||||
| Bits UI | `/llmstxt/bits-ui_llms_txt` | ^2.17 | headless-примитивы под shadcn |
|
||||
| sveltekit-superforms | `/ciscoheat/sveltekit-superforms` | ^2.30 | формы, server actions |
|
||||
| Formsnap | `/svecosystem/formsnap` | ^2.0 | доступные поля форм |
|
||||
| Zod | `/websites/zod_dev_v4` | ^4.4 | схемы валидации |
|
||||
| TanStack Table | `/websites/tanstack_table` | table-core ^8.21 | `AppDataTable`, колонки, сортировка |
|
||||
| shadcn/ui (React) | MCP `plugin-shadcn-shadcn` + https://ui.shadcn.com/docs | base-nova | примитивы `@evobgp/ui/components/*` |
|
||||
| ReUI | https://reui.io/llms.txt + MCP с `registries: ["@reui"]` | registry | enterprise: data-grid, filters, autocomplete |
|
||||
| react-hook-form | `/react-hook-form` | ^7.60 | формы, controller |
|
||||
| Zod | `/websites/zod_dev_v4` | ^3.25 / ^4 (apps/web) | схемы валидации |
|
||||
| recharts | `/recharts/recharts` | 3.8.0 | графики через shadcn `Chart` |
|
||||
| next-themes | `/pacocoursey/next-themes` | ^0.4 | dark/light theme provider |
|
||||
| sonner | `/emilkowalski/sonner` | ^1.7 | toast notifications |
|
||||
| lucide-react | `/lucide-icons/lucide` | ^0.468 | иконки |
|
||||
|
||||
UI-правила репозитория: `.cursor/rules/web-shadcn.mdc` (shadcn-svelte docs — первичный источник для компонентов).
|
||||
UI-правила репозитория: `.cursor/rules/web-shadcn.mdc` (MCP + shadcn/ui React docs — первичный источник для компонентов).
|
||||
|
||||
---
|
||||
|
||||
@@ -82,7 +87,9 @@ UI-правила репозитория: `.cursor/rules/web-shadcn.mdc` (shadcn
|
||||
## Примеры запросов
|
||||
|
||||
```
|
||||
/docs /websites/svelte_dev runes $state $derived
|
||||
/docs /facebook/react hooks useState useEffect
|
||||
/docs /tanstack/router createFileRoute useSearch Link
|
||||
/docs /tanstack/query useQuery useMutation queryOptions
|
||||
/docs /golang/go/go1_24_6 net/http ServeMux pattern matching
|
||||
/docs /websites/pkg_go_dev_github_com_jackc_pgx_v5 pool acquire rows
|
||||
/docs /llmstxt/bird_xmsl_dev_llms_txt filter bgp import
|
||||
|
||||
@@ -94,8 +94,8 @@ alwaysApply: true
|
||||
**DEP-03** | MUST | Миграции схемы — пары `.up.sql`/`.down.sql` для **postgres** и **sqlite**, синхронная нумерация.
|
||||
*Проверка:* `migrations/postgres/`, `migrations/sqlite/`.
|
||||
|
||||
**DEP-04** | MUST | Web UI-библиотеки — только экосистема shadcn-svelte/bits-ui (см. `web-shadcn.mdc`).
|
||||
*Проверка:* `web/package.json` review.
|
||||
**DEP-04** | MUST | Web UI-библиотеки — только экосистема shadcn/ui (React) + ReUI (см. `web-shadcn.mdc`).
|
||||
*Проверка:* `apps/web/package.json`, `packages/ui/package.json` review.
|
||||
|
||||
---
|
||||
|
||||
@@ -123,7 +123,7 @@ alwaysApply: true
|
||||
**TEST-03** | MUST | Новые BIRD-сценарии в `internal/birdfmt/testdata/scenarios/*/bird.conf` + `bird -p`.
|
||||
*Проверка:* CI job `bird2`.
|
||||
|
||||
**TEST-04** | MUST | Изменения `web/` — локально **`npm run check` и `npm run lint`** (обе команды, exit 0); CI job `web` в `.gitea/workflows/ci.yaml`. Агент: при fail lint — `npx prettier --write` затем повтор. Только `check` не заменяет `lint`.
|
||||
**TEST-04** | MUST | Изменения `apps/web/**` или `packages/ui/**` — локально **`pnpm --filter @evobgp/web run typecheck`, `lint`, `build`** (все три команды, exit 0); CI job `web` в `.gitea/workflows/ci.yaml`.
|
||||
*Проверка:* CI job `web`; `.cursor/rules/web-shadcn.mdc` WEB-19.
|
||||
|
||||
**TEST-05** | MUST | Изменения OpenAPI — `npx @redocly/cli lint docs/openapi.yaml`.
|
||||
@@ -213,7 +213,7 @@ alwaysApply: true
|
||||
**DOC-SYNC-01** | MUST | Новый API библиотеки — сверка версии в `go.mod`/`package.json` с официальной документацией.
|
||||
**DOC-SYNC-02** | NEVER | Устаревшие примеры (Svelte 4 `export let`, deprecated pgx).
|
||||
**DOC-SYNC-03** | MUST | Конфликт docs: **OpenAPI (HTTP)** → **код** → обзорные `docs/`; `.cursor/plans/` не контракт.
|
||||
**DOC-SYNC-04** | MUST | Сомнения по Svelte — Svelte MCP / `npm run check`.
|
||||
**DOC-SYNC-04** | MUST | Сомнения по React/shadcn/ReUI — MCP `plugin-shadcn-shadcn` + `pnpm --filter @evobgp/web run typecheck`.
|
||||
**DOC-SYNC-05** | MUST | BIRD — официальная документация BIRD2 + `networking-bird.mdc` + `go test ./internal/birdfmt/...`.
|
||||
|
||||
Приоритет при сомнениях — **официальные источники**, не блоги и не «память модели».
|
||||
@@ -230,7 +230,7 @@ alwaysApply: true
|
||||
go vet ./...
|
||||
go test ./... -race -count=1
|
||||
npx @redocly/cli lint docs/openapi.yaml
|
||||
# web: cd web; npm run check; npm run lint (или scripts/lint-web.ps1)
|
||||
# web: pnpm --filter @evobgp/web run typecheck; pnpm --filter @evobgp/web run lint; pnpm --filter @evobgp/web run build
|
||||
# go fmt/lint: gofmt -w <files>; scripts/lint-go.ps1 (gofmt + vet + golangci-lint)
|
||||
# birdfmt: go test ./internal/birdfmt/... -count=1
|
||||
```
|
||||
|
||||
@@ -1,126 +1,131 @@
|
||||
---
|
||||
description: EvoBGP WebUI — shadcn-svelte, Svelte 5, слои ui/core|patterns|app
|
||||
description: EvoBGP WebUI — React 19, shadcn/ui (base-nova), ReUI, TanStack Router/Query
|
||||
globs:
|
||||
- web/**
|
||||
- apps/web/**
|
||||
- packages/ui/**
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Web UI — shadcn-svelte
|
||||
# Web UI — React + shadcn/ui + ReUI
|
||||
|
||||
**Источник правды:** https://shadcn-svelte.com/docs (не React shadcn/ui, не Legacy Docs).
|
||||
**Источники правды:**
|
||||
- shadcn/ui React: https://ui.shadcn.com/docs/components
|
||||
- ReUI Base UI: https://reui.io/docs/components/base/<name>
|
||||
- ReUI llms.txt: https://reui.io/llms.txt
|
||||
- MCP `plugin-shadcn-shadcn` (registries: `@shadcn`, `@reui`) — перед любой UI-задачей
|
||||
|
||||
Общие правила Go/API: `.cursor/rules/engineering.mdc`. Локальная карта: `web/README.md`.
|
||||
Общие правила Go/API: `.cursor/rules/engineering.mdc`. Стек ID: `.cursor/rules/context7-stack.mdc`.
|
||||
|
||||
## Слои UI
|
||||
|
||||
| Слой | Путь | Назначение |
|
||||
|------|------|------------|
|
||||
| Примитивы | `src/lib/ui/core/` | shadcn-svelte (только CLI `add`) |
|
||||
| Паттерны | `src/lib/ui/patterns/` | FormField, AppDataTable, ConfirmDialog, EmptyState |
|
||||
| App chrome | `src/lib/ui/app/` | Layout, PageHeader, `notify` |
|
||||
| Legacy | `src/lib/components/ui/` | Re-export; **не добавлять новые файлы** |
|
||||
| shadcn-примитивы | `packages/ui/src/components/` | output `shadcn add` (не трогать под кейс) |
|
||||
| ReUI enterprise | `apps/web/src/components/reui/` | output `shadcn add @reui/*` |
|
||||
| Shared обёртки | `apps/web/src/components/` | PageHeader, QueryState, ConfirmDialog, StatusBadge, SectionCards, LoadingButton |
|
||||
| Роуты | `apps/web/src/routes/` | TanStack Router (file-based) |
|
||||
|
||||
Тема: `src/routes/layout.css`, `src/lib/ui/app/tokens.md`. CLI из `web/`: `npx shadcn-svelte@latest add <component> -y -o`.
|
||||
|
||||
---
|
||||
Тема: `packages/ui/src/styles/globals.css`. CLI из `apps/web`: `pnpm dlx shadcn@latest add <component>`.
|
||||
|
||||
## Правила
|
||||
|
||||
**WEB-01** | MUST | Перед новым UI — проверить https://shadcn-svelte.com/docs/components; использовать компонент, не HTML+CSS с нуля.
|
||||
*Rationale:* Open Code + единый дизайн.
|
||||
*Проверка:* review; нет голых `<button class=…>`.
|
||||
**WEB-01** | MUST | Перед новым UI — MCP `plugin-shadcn-shadcn`: `search_items_in_registries` → `get_item_examples_from_registries` → `get_add_command_for_items`. Только после — JSX.
|
||||
*Rationale:* единый источник правды и API.
|
||||
*Проверка:* review; нет самописных примитивов, если есть registry item.
|
||||
|
||||
**WEB-02** | MUST | Отсутствующий примитив — `npx shadcn-svelte@latest add <component> -y -o` → `src/lib/ui/core/`.
|
||||
*Rationale:* Distribution через CLI и `components.json`.
|
||||
*Проверка:* файлы только в `ui/core`.
|
||||
**WEB-02** | MUST | Отсутствующий shadcn-примитив — `pnpm dlx shadcn@latest add <component>` (из `apps/web`). ReUI — `pnpm dlx shadcn@latest add @reui/<name>`.
|
||||
*Проверка:* файлы в `packages/ui/src/components/` (для shadcn) или `apps/web/src/components/reui/` (для ReUI).
|
||||
|
||||
**WEB-03** | NEVER | Альтернативные UI-kit'ы (Material, Vuetify, DaisyUI-only без shadcn-примитива).
|
||||
*Проверка:* `package.json` review.
|
||||
**WEB-03** | NEVER | Альтернативные UI-kit'ы (Material, Vuetify, Tabler, Bootstrap утилиты).
|
||||
*Проверка:* `apps/web/package.json` review.
|
||||
|
||||
**WEB-04** | MUST | Комозиция по docs: все sub-компоненты (`DialogHeader`, `TableRow`, `Field`, …).
|
||||
*Проверка:* сверка со страницей компонента в docs.
|
||||
**WEB-04** | MUST | Композиция по docs: использовать под-компоненты (`CardHeader`, `TableRow`, `TabsList`, …).
|
||||
*Проверка:* сверка с shadcn/ReUI docs.
|
||||
|
||||
**WEB-05** | MUST | Формы — Formsnap + `sveltekit-superforms`; UI в `ui/patterns/form`, не ad-hoc валидация на странице.
|
||||
*Проверка:* https://shadcn-svelte.com/docs/components/form
|
||||
**WEB-05** | MUST | Формы — `react-hook-form` + Zod; через `FormField`/`Form` обёртки.
|
||||
*Проверка:* https://ui.shadcn.com/docs/components/form
|
||||
|
||||
**WEB-06** | MUST | Таблицы — Data Table + `@tanstack/table-core`; на страницах — `AppDataTable` из patterns.
|
||||
*Проверка:* https://shadcn-svelte.com/docs/components/data-table
|
||||
**WEB-06** | MUST | Сложные data-списки — ReUI `DataGridCard` (ReUI data-grid, не shadcn Data Table). Простые списки — shadcn `Table`.
|
||||
*Проверка:* `@/components/reui/data-grid` или `@evobgp/ui/components/table`.
|
||||
|
||||
**WEB-07** | MUST | Toast — Sonner через `notify` из `ui/app/toast.js`.
|
||||
*Проверка:* https://shadcn-svelte.com/docs/components/sonner
|
||||
**WEB-07** | MUST | Toast — `sonner` (`Toaster` в `main.tsx`); `toast.success/error/message` из `sonner`.
|
||||
*Проверка:* https://ui.shadcn.com/docs/components/sonner
|
||||
|
||||
**WEB-08** | MUST | Иконки — `@lucide/svelte` (`components.json` → `iconLibrary: lucide`).
|
||||
*Проверка:* imports.
|
||||
**WEB-08** | MUST | Иконки — `lucide-react` (`components.json` → `iconLibrary: lucide`).
|
||||
*Проверка:* imports; нет `@tabler/icons-react`, `@lucide/svelte`.
|
||||
|
||||
**WEB-09** | MUST | Цвета — CSS-переменные `layout.css` и токены `tokens.md`; не hex/rgb на страницах.
|
||||
*Проверка:* grep `#[0-9a-f]{3,6}` в `routes/`.
|
||||
**WEB-09** | MUST | Цвета — CSS-переменные `globals.css` и ReUI semantic токены (`variant="success"/"info"/"warning"`); не hex/rgb на страницах.
|
||||
*Проверка:* grep `#[0-9a-f]{3,6}` в `apps/web/src/routes/`.
|
||||
|
||||
**WEB-10** | SHOULD | Кастомизация — правка `ui/core` (Open Code), не `!important` поверх API.
|
||||
**WEB-10** | SHOULD | Кастомизация — правка `packages/ui`/`reui` (Open Code), не `!important` поверх API.
|
||||
|
||||
**WEB-11** | MUST | `apps/web/src/routes/**` — композиция `@evobgp/ui/components/*` + `@/components/*` + `@/components/reui/*`; не копировать целые примитивы в route.
|
||||
*Проверка:* review.
|
||||
|
||||
**WEB-11** | MUST | `routes/**` — композиция `ui/core` + `ui/patterns` + `ui/app`; не копировать целые примитивы shadcn в route.
|
||||
**WEB-12** | NEVER | Примеры Svelte/SvelteKit, Tabler, Bootstrap — без адаптации под текущий React-стек.
|
||||
*Проверка:* `pnpm --filter @evobgp/web run typecheck`.
|
||||
|
||||
**WEB-13** | MUST | Реактивность — React 19 (`useState`, `useEffect`, TanStack Query/Router хуки); не Svelte runes, не `export let`.
|
||||
*Проверка:* `pnpm --filter @evobgp/web run typecheck`.
|
||||
|
||||
**WEB-14** | SHOULD | Нетривиальный UI — прочитать страницу компонента shadcn/ReUI (props, a11y).
|
||||
|
||||
**WEB-15** | MUST | Сомнения — MCP `plugin-shadcn-shadcn` + shadcn CLI docs + `pnpm --filter @evobgp/web run typecheck`.
|
||||
|
||||
**WEB-16** | MUST | Подтверждение удаления — `ConfirmDialog` из `@/components/confirm-dialog`, не `window.confirm`.
|
||||
|
||||
**WEB-17** | MUST | Пустые списки — `EmptyState` или через `QueryState` с `emptyTitle`.
|
||||
*Проверка:* review.
|
||||
|
||||
**WEB-12** | NEVER | Примеры React shadcn/ui или Svelte 4 Legacy без адаптации под https://shadcn-svelte.com/docs/migration/svelte-5
|
||||
*Проверка:* `npm run check`.
|
||||
**WEB-18** | SHOULD | Повторяемая комбинация core (≥2 раза) — вынести в `apps/web/src/components/`.
|
||||
|
||||
**WEB-13** | MUST | Реактивность — Svelte 5 runes (`$state`, `$derived`, `$effect`); не `export let` для локального state страниц.
|
||||
*Проверка:* `npm run check`; Svelte MCP.
|
||||
|
||||
**WEB-14** | SHOULD | Нетривиальный UI — прочитать страницу компонента (props, a11y).
|
||||
*Проверка:* PR description.
|
||||
|
||||
**WEB-15** | MUST | Сомнения — https://shadcn-svelte.com/llms.txt , Svelte MCP, `npm run check`.
|
||||
*Проверка:* локально.
|
||||
|
||||
**WEB-19** | MUST | **После любого изменения `web/**`** — перед завершением задачи агент **обязан** выполнить в `web/`:
|
||||
**WEB-19** | MUST | **После любого изменения `apps/web/**` или `packages/ui/**`** — перед завершением задачи агент **обязан**:
|
||||
```powershell
|
||||
npm run check
|
||||
npm run lint
|
||||
pnpm --filter @evobgp/web run typecheck
|
||||
pnpm --filter @evobgp/web run lint
|
||||
pnpm --filter @evobgp/web run build
|
||||
```
|
||||
Если `npm run lint` падает (Prettier) — **сначала** `npx prettier --write <изменённые файлы>` или `npx prettier --write .`, затем снова `npm run check` и `npm run lint`. Не сдавать PR/ответ, пока обе команды не exit 0.
|
||||
*Rationale:* CI job `web` = `check` + `prettier --check`; `svelte-check` не ловит форматирование.
|
||||
*Проверка:* CI job `web`; pre-commit hook `prettier-web`.
|
||||
Все три команды должны exit 0. Не сдавать PR/ответ, пока все три не пройдут.
|
||||
*Rationale:* CI job `web` = typecheck + lint + build.
|
||||
*Проверка:* CI job `web`.
|
||||
|
||||
**WEB-16** | MUST | Подтверждение удаления — `ConfirmDialog` из patterns, не `window.confirm`.
|
||||
*Проверка:* review.
|
||||
**WEB-20** | MUST | Роутинг — TanStack Router (file-based `apps/web/src/routes/`); типобезопасные `createFileRoute`, `useSearch`, `Link`. Не `react-router-dom`.
|
||||
*Проверка:* `tsr generate` в `build`/`typecheck` скриптах.
|
||||
|
||||
**WEB-17** | MUST | Пустые списки — `EmptyState` из patterns.
|
||||
*Проверка:* review.
|
||||
**WEB-21** | MUST | Data fetching — TanStack Query (`useQuery`, `useMutation`, `queryOptions`); query-key factories в `apps/web/src/queries/`. Mutations invalidate keys, не refetch вручную.
|
||||
*Проверка:* review `queries/*.ts`.
|
||||
|
||||
**WEB-18** | SHOULD | Повторяемая комбинация core (≥2 раза) — вынести в `ui/patterns/`.
|
||||
*Проверка:* review.
|
||||
**WEB-22** | MUST | Legacy Svelte — в `web-legacy-svelte/` (archive). Не использовать импорты оттуда в новом коде; только как референс при миграции роутов.
|
||||
|
||||
---
|
||||
|
||||
## Documentation Sync (Web)
|
||||
|
||||
**DOC-SYNC-06** | MUST | UI — первично https://shadcn-svelte.com/docs; при конфликте с блогами/Stack Overflow побеждает официальная страница компонента.
|
||||
**DOC-SYNC-07** | MUST | Перед `add` — сверить Installation/Theming с `web/components.json` и `src/routes/layout.css`.
|
||||
**DOC-SYNC-06** | MUST | UI — первично MCP + shadcn/ui docs (React) + ReUI docs (Base UI); при конфликте с блогами/Stack Overflow побеждает официальная страница.
|
||||
**DOC-SYNC-07** | MUST | Перед `add` — сверить Installation/Theming с `apps/web/components.json`, `packages/ui/components.json` и `packages/ui/src/styles/globals.css`.
|
||||
|
||||
Tailwind v4: https://shadcn-svelte.com/docs/migration/tailwind-v4
|
||||
Tailwind v4 + base-nova: https://ui.shadcn.com/docs/migration/tailwind-v4
|
||||
ReUI semantic tokens: https://reui.io/docs/styling
|
||||
|
||||
---
|
||||
|
||||
## Enforcement
|
||||
|
||||
**Обязательный финальный шаг агента при правках `web/**`:** `npm run check` **и** `npm run lint` (см. **WEB-19**). Только `check` недостаточно.
|
||||
**Обязательный финальный шаг агента при правках `apps/web/**` или `packages/ui/**`** (см. **WEB-19**):
|
||||
|
||||
```powershell
|
||||
cd web
|
||||
npm run check
|
||||
npm run lint
|
||||
# при warn/fail lint:
|
||||
npx prettier --write .
|
||||
npm run check
|
||||
npm run lint
|
||||
pnpm --filter @evobgp/web run typecheck
|
||||
pnpm --filter @evobgp/web run lint
|
||||
pnpm --filter @evobgp/web run build
|
||||
```
|
||||
|
||||
**PR checklist `web/**`:**
|
||||
- [ ] `npm run check` — exit 0
|
||||
- [ ] `npm run lint` (prettier --check) — exit 0
|
||||
- [ ] `ui/core` / `ui/patterns`, не дубли примитивов
|
||||
- [ ] Новые примитивы через shadcn CLI
|
||||
**PR checklist `apps/web/**` / `packages/ui/**`:**
|
||||
- [ ] `pnpm --filter @evobgp/web run typecheck` — exit 0
|
||||
- [ ] `pnpm --filter @evobgp/web run lint` — exit 0
|
||||
- [ ] `pnpm --filter @evobgp/web run build` — exit 0
|
||||
- [ ] shadcn-примитивы в `packages/ui/src/components/`, ReUI в `apps/web/src/components/reui/`
|
||||
- [ ] Новые примитивы через shadcn CLI (`@shadcn` или `@reui`)
|
||||
- [ ] Импорты: `@evobgp/ui/components/*` для shadcn, `@/components/reui/*` для ReUI
|
||||
- [ ] Ссылка на docs компонента (если новый паттерн)
|
||||
|
||||
**CI:** job `web` — `npm run check` + `npm run lint`.
|
||||
**CI:** job `web` — `typecheck` + `lint` + `build`.
|
||||
|
||||
+10
-1
@@ -1,10 +1,19 @@
|
||||
{
|
||||
"plugins": {
|
||||
"svelte": {
|
||||
"shadcn": {
|
||||
"enabled": true
|
||||
},
|
||||
"context7-plugin": {
|
||||
"enabled": true
|
||||
},
|
||||
"claude-plugins-official/gopls-lsp": {
|
||||
"enabled": true
|
||||
},
|
||||
"claude-plugins-official/typescript-lsp": {
|
||||
"enabled": true
|
||||
},
|
||||
"svelte": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ description: Context7 lookup для стека EvoBGP — использоват
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Определи область: `internal/` (Go), `web/` (Svelte), `docs/openapi.yaml`, `birdfmt`/`pipeline` (BIRD), `deploy/compose` (Docker).
|
||||
1. Определи область: `internal/` (Go), `apps/web/` + `packages/ui/` (React + shadcn/ui + ReUI), `docs/openapi.yaml`, `birdfmt`/`pipeline` (BIRD), `deploy/compose` (Docker).
|
||||
2. Найди строку в таблице `context7-stack.mdc`.
|
||||
3. Вызови `query-docs` с `libraryId` из таблицы и полным вопросом пользователя.
|
||||
4. `resolve-library-id` — только если библиотеки нет в таблице или нужна другая major-версия.
|
||||
@@ -18,14 +18,17 @@ description: Context7 lookup для стека EvoBGP — использоват
|
||||
|
||||
| Задача | libraryId |
|
||||
|--------|-----------|
|
||||
| Svelte 5 runes | `/websites/svelte_dev` |
|
||||
| SvelteKit load/forms | `/sveltejs/kit` |
|
||||
| shadcn-svelte компонент | `/websites/shadcn-svelte` |
|
||||
| React 19 hooks | `/facebook/react` |
|
||||
| TanStack Router | `/tanstack/router` |
|
||||
| TanStack Query | `/tanstack/query` |
|
||||
| shadcn/ui (React) | MCP `plugin-shadcn-shadcn` + https://ui.shadcn.com/docs |
|
||||
| ReUI Base UI | https://reui.io/llms.txt + MCP с `registries: ["@reui"]` |
|
||||
| pgx pool/query | `/websites/pkg_go_dev_github_com_jackc_pgx_v5` |
|
||||
| Go net/http | `/golang/go/go1_24_6` |
|
||||
| OpenAPI lint | `/redocly/redocly-cli` |
|
||||
| BIRD config | `/llmstxt/bird_xmsl_dev_llms_txt` |
|
||||
| Tailwind v4 | `/tailwindlabs/tailwindcss.com` |
|
||||
| Zod 4 schema | `/websites/zod_dev_v4` |
|
||||
| Zod schema | `/websites/zod_dev_v4` |
|
||||
| recharts | `/recharts/recharts` |
|
||||
|
||||
Полный список и версии — в `context7-stack.mdc`.
|
||||
|
||||
Reference in New Issue
Block a user