# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview This is the **RuoYi-Vue-Plus** frontend — a multi-tenant enterprise management system (Vue 3 + TypeScript + Element Plus + Vite). It is the UI for a Java Spring Boot backend and follows a standard admin panel architecture with RBAC, dynamic routing, and multi-tenant support. ## Commands ```bash # Development (uses pnpm) pnpm dev # Start dev server (port from VITE_APP_PORT, default 80) pnpm build:prod # Production build pnpm build:dev # Development build pnpm preview # Preview production build locally # Code quality pnpm lint:eslint # Run ESLint pnpm lint:eslint:fix # Auto-fix ESLint issues pnpm prettier # Format all files with Prettier # No test runner configured yet (vitest is installed but no vitest.config.ts exists) ``` ## Architecture ### Entry & Bootstrap (`src/main.ts`) - Creates Vue app → mounts Pinia → Vue Router → vue-i18n → plugins → custom directives → VXE Table - Loads UnoCSS, Element Plus styles, Highlight.js, SVG icons - Imports `src/permission.ts` for route guards ### Routing (`src/router/index.ts`) Two-tier route system: 1. **`constantRoutes`** — always loaded (login, register, 401, 404, index, redirect, profile) 2. **`dynamicRoutes`** — initially empty array; populated by frontend-defined routes checked against user permissions Actual menus come from the **backend API** (`/getRouters`). `permission.ts` store fetches these, converts backend route configs to Vue Router routes via `filterAsyncRouter()`, and dynamically adds them. Component strings from backend (e.g., `"system/user/index"`) are resolved against `import.meta.glob('./../../views/**/*.vue')`. ### Permission Guard (`src/permission.ts`) Router `beforeEach`: - No token → redirect to `/login` (unless whitelisted) - Has token + no roles loaded → fetch user info (`useUserStore().getInfo()`) then generate routes (`usePermissionStore().generateRoutes()`) → dynamically add routes → redirect to target - Has token + roles loaded → allow navigation ### State Management (Pinia) | Store | File | Purpose | |-------|------|---------| | `user` | `src/store/modules/user.ts` | Auth token, user info, roles, permissions | | `permission` | `src/store/modules/permission.ts` | Dynamic routes generation, sidebar/topbar route trees | | `app` | `src/store/modules/app.ts` | Sidebar state, device type, language, size | | `settings` | `src/store/modules/settings.ts` | Layout config (theme, navType, tagsView, etc.) persisted to localStorage | | `dict` | `src/store/modules/dict.ts` | Dictionary data cache | | `tagsView` | `src/store/modules/tagsView.ts` | Multi-tab page management | | `notice` | `src/store/modules/notice.ts` | Notification/announcement state | ### HTTP Layer (`src/utils/request.ts`) Axios instance with: - **Request interceptor**: injects Bearer token + `Content-Language` header, GET params serialization, duplicate submit detection (500ms window via sessionStorage), optional AES body encryption (ECB mode, key encrypted with RSA public key) - **Response interceptor**: AES decryption, 401 → re-login prompt, 500 → error message, 601 → warning - **`download()`** helper for file downloads with loading state Encryption is toggleable via `VITE_APP_ENCRYPT` env var — must match backend config. ### Permission System (`src/plugins/auth.ts`) - `hasPermi(permission)` — exact permission match (admin `*:*:*` wildcard supported) - `hasPermiOr(permissions)` — any match - `hasPermiAnd(permissions)` — all match - `hasRole(role)` / `hasRoleOr(roles)` / `hasRoleAnd(roles)` — role-based equivalents - Used in route filtering and button-level UI control via custom directives ### Layout (`src/layout/index.vue`) Classic admin layout: Sidebar + Navbar + TagsView + AppMain + Settings drawer. Supports: - `NavTypeEnum.LEFT` — left sidebar - `NavTypeEnum.TOP` — top navigation - `NavTypeEnum.MIX` — mixed mode - Responsive: mobile detection at 992px breakpoint ### API Layer (`src/api/`) Organized by backend module: - `src/api/login.ts` — auth (login, logout, register, tenant list) - `src/api/menu.ts` — menu/routing - `src/api/system/` — user, role, menu, dept, post, dict, config, notice, tenant, oss, client, social - `src/api/monitor/` — online users, operlog, loginInfo, cache - `src/api/tool/gen/` — code generation - `src/api/workflow/` — workflow (category, definition, instance, task, leave) - `src/api/demo/` — demo/demo, demo/tree ### Directory Quick Reference | Directory | Purpose | |-----------|---------| | `src/views/` | Page components, mirrors `src/api/` module structure | | `src/components/` | Shared components (Breadcrumb, DictTag, FileUpload, ImageUpload, Editor, Pagination, etc.) | | `src/plugins/` | Global Vue plugins installed via `app.use()` — auth, cache, modal, tab, download, svgicon | | `src/directive/` | Custom directives (permission checks, common utilities) | | `src/utils/` | Utilities — request, auth (token storage), crypto (AES+RSA), validate, websocket, sse, ruoyi (helper fns), dict, theme, scroll-to | | `src/lang/` | vue-i18n language packs (zh_CN, en_US) | | `src/enums/` | TypeScript enums (HttpStatus, NavTypeEnum, LanguageEnum, SideThemeEnum, MenuTypeEnum) | | `src/types/` | Global type declarations (env.d.ts, router.d.ts, global.d.ts, etc.) | | `vite/plugins/` | Vite plugin configs — auto-import, auto-components, UnoCSS, SVG icons, compression, setup-extend | ### Key Conventions - Auto-imported: `vue`, `vue-router`, `@vueuse/core`, `pinia` (via `unplugin-auto-import`) - Auto-registered: Element Plus components + `icon-park` icons (via `unplugin-vue-components`) - Path alias: `@/` → `src/` - Uses UnoCSS with `presetAttributify` (attribute-based utilities) and `presetIcons` - SCSS variables in `src/assets/styles/variables.module.scss` - Backend API prefix: `/dev-api` (dev), configurable via `VITE_APP_BASE_API` - Token stored in localStorage under key `Admin-Token`, managed via `@vueuse/core`'s `useStorage` - SSR/SSE: `src/utils/sse.ts` for Server-Sent Events, `src/utils/websocket.ts` for WebSocket ### Important: Backend-Driven Nature Many UI aspects are controlled by backend API responses: - **Menus/routes** come from backend (not frontend route definitions) - **Dictionaries** (`dict` store) provide dynamic dropdown options throughout the app - **Tenant info** is fetched on auth and drives data isolation - Always check the backend API contract when modifying UI modules