# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview **TMS (Transportation Management System)** is a full-stack application for managing transportation operations, built on the RuoYi framework. - **Backend**: Java Spring Boot 2.5.15 (Java 8), Maven multi-module architecture - **Frontend**: Vue 3 + TypeScript + Vite with Element Plus UI library - **Database**: MySQL with MyBatis-Plus ORM - **Key Custom Module**: `tms` for transportation management features ## Architecture Overview ### Backend Architecture (Maven Multi-Module) ``` manage (parent pom) ├── admin # Spring Boot entry point & web server ├── framework # Core security, permissions, base classes ├── system # System management (users, roles, menus) ├── common # Shared utilities and constants ├── service # Business service layer ├── api # API contracts/interfaces ├── tms # Transportation Management System domain └── quartz # Scheduled task management ``` **Key Architectural Pattern**: - **Layered Architecture**: Controller → Service → Mapper (MyBatis) → Database - **Security**: Spring Security with custom `PermissionService` (@Service("ss")) for permission checking - **Permission Model**: `@PreAuthorize("@ss.hasPermi('module:action:operation')")` on controllers - **Async Processing**: `AsyncManager` for fire-and-forget async operations - **API Documentation**: Swagger 3.0 available at `/swagger-ui.html` ### Frontend Architecture (Vue 3 + Vite) ``` src/ ├── api/ # API service classes (axios calls) ├── router/ # Route definitions & navigation guards ├── store/ # Pinia stores (user, app state) ├── views/ # Page components (organized by module) ├── components/ # Reusable UI components ├── hooks/ # Composition API hooks ├── directive/ # Vue directives (permission checks, etc.) ├── layout/ # Layout templates ├── utils/ # Helper functions & utilities ├── assets/ # Static resources (images, styles) └── plugins/ # Vue plugin configuration ``` **Key Architectural Patterns**: - **CRUD Forms**: Built with Avue (`@smallwei/avue`) - declarative configuration-based CRUD - **State Management**: Pinia for user auth, permissions, global app state - **API Layer**: Axios instance with interceptors for auth/error handling - **Permission Control**: `v-hasPermi` directive and `hasPermission()` function - **Responsive**: Element Plus component library for UI ## Build & Development Commands ### Backend (Java/Maven) ```bash # Build all modules mvn clean package # Build specific module (e.g., admin) mvn clean package -pl admin -am # Run tests (currently disabled in pom.xml) mvn test -DskipTests=false # Build and skip tests mvn clean package -DskipTests # Start development with Spring Boot DevTools # Run from admin module's main class: com.ruoyi.RuoyiApplication # IDE: Right-click Application.java → Run ``` **Note**: The `admin` module is the web entry point. Start the application by running the `Application` class in `admin/src/main/java/com/ruoyi/`. ### Frontend (Vue 3/Vite) ```bash cd ui/admin-ui3 # Install dependencies npm install # or pnpm install # Development server (hot reload on port 5173) npm run dev # Production build npm run build:prod # Staging build (with staging config) npm run build:stage # Preview production build npm run preview ``` **Environment Configuration**: - `.env.development` - development environment variables - Check `vite.config.ts` for proxy settings and build configuration ## Permission System ### Backend Permission Structure **Permission String Format**: `module:action:operation` Examples: - `tms:tmsDispatchOrder:list` - List dispatch orders - `tms:tmsDispatchOrder:add` - Create dispatch order - `tms:tmsDispatchOrder:edit` - Edit dispatch order - `tms:tmsDispatchOrder:remove` - Delete dispatch order - `tms:tmsDispatchOrder:export` - Export dispatch orders **Usage in Controllers**: ```java @PreAuthorize("@ss.hasPermi('tms:tmsDispatchOrder:list')") @GetMapping("/list") public TableDataInfo list(TmsDispatchOrder order) { startPage(); List list = tmsDispatchOrderService.selectTmsDispatchOrderList(order); return getDataTable(list); } ``` ### Frontend Permission Control **Checking Permissions in Components**: ```typescript import { hasPermission } from "@/utils/permissionUtils"; import { computed } from "vue"; // In setup() or script setup const permissionList = computed(() => ({ addBtn: hasPermission(["tms:tmsDispatchOrder:add"]), editBtn: hasPermission(["tms:tmsDispatchOrder:edit"]), deleteBtn: hasPermission(["tms:tmsDispatchOrder:remove"]), })); ``` **Using Permission Directives**: ```vue Add Order
Admin only content
``` ## Code Patterns & Conventions ### Backend Patterns **Service Layer**: - Located in `tms/src/main/java/com/ruoyi/tms/service/` - Interface in `service/` directory, implementation in `service/impl/` - Inject mapper using `@Autowired` or constructor injection - Use `BaseServiceImpl` as base class for CRUD operations **Controller Layer**: - Located in `tms/src/main/java/com/ruoyi/tms/controller/` - Extend `BaseController` for standard pagination/response handling - Return `AjaxResult` for JSON responses - Return `TableDataInfo` for paginated data tables **Mapper (Data Access)**: - Located in `tms/src/main/resources/mapper/tms/` (XML files) - Interfaces in `tms/src/main/java/com/ruoyi/tms/mapper/` - Use MyBatis dynamic SQL for flexible queries **Domain Models**: - Located in `tms/src/main/java/com/ruoyi/tms/domain/` - Use Lombok `@Data`, `@Builder` for getters/setters - Use `@TableName` annotation for MyBatis mapping - VO (View Objects) for API responses in `domain/vo/` subdirectory **Example Service Structure**: ```java // Interface public interface TmsDispatchOrderService extends IBaseService { List selectTmsDispatchOrderList(TmsDispatchOrder order); } // Implementation @Service public class TmsDispatchOrderServiceImpl extends BaseServiceImpl implements TmsDispatchOrderService { @Override public List selectTmsDispatchOrderList(TmsDispatchOrder order) { return baseMapper.selectTmsDispatchOrderList(order); } } // Controller @RestController @RequestMapping("/tms/tmsDispatchOrder") public class TmsDispatchOrderController extends BaseController { @Autowired private TmsDispatchOrderService tmsDispatchOrderService; @PreAuthorize("@ss.hasPermi('tms:tmsDispatchOrder:list')") @GetMapping("/list") public TableDataInfo list(TmsDispatchOrder order) { startPage(); List list = tmsDispatchOrderService.selectTmsDispatchOrderList(order); return getDataTable(list); } } ``` ### Frontend Patterns **API Service Layer** (`src/api/tms/tmsDispatchOrder.ts`): ```typescript import request from "@/utils/request"; export interface TmsDispatchOrderI { id?: string; planCode?: string; customerName?: string; // ... other fields } export const listTmsDispatchOrder = ( data: TmsDispatchOrderI & any ): Promise => { return request.get("/tms/tmsDispatchOrder/list", { params: data }); }; export const getTmsDispatchOrder = (id: string): Promise => { return request.get("/tms/tmsDispatchOrder/" + id); }; export const addTmsDispatchOrder = (data: TmsDispatchOrderI): Promise => { return request.post("/tms/tmsDispatchOrder", data); }; export const updateTmsDispatchOrder = (data: TmsDispatchOrderI): Promise => { return request.put("/tms/tmsDispatchOrder", data); }; export const delTmsDispatchOrder = (id: string): Promise => { return request.delete("/tms/tmsDispatchOrder/" + id); }; ``` **Avue CRUD Component** (data-driven form configuration): ```vue ``` **Pinia Store Pattern** (`src/store/modules/user.ts`): ```typescript import { defineStore } from "pinia"; export interface UserState { token?: string; roles: string[]; permissions: string[]; user?: { userName: string; [key: string]: any }; } export const useUserStore = defineStore("user", { state: (): UserState => ({ token: undefined, roles: [], permissions: [], }), getters: { getToken(): string { return this.token || ""; }, }, actions: { // Get user info and set roles/permissions from backend async GetInfo() { const res = await getInfo(); this.roles = res.roles || []; this.permissions = res.permissions || []; return res; }, }, }); ``` ## Database Conventions ### Naming Patterns - **Tables**: Snake case, prefixed by module (e.g., `tms_dispatch_order`, `tms_quote_detail`) - **Columns**: Snake case (e.g., `customer_id`, `created_time`) - **Primary Key**: Usually `id` (bigint) - **Common Fields**: `create_by`, `create_time`, `update_by`, `update_time`, `remark`, `del_flag` ### Key Tables (TMS Module) - `tms_dispatch_order` - Main dispatch order entity - `tms_plan_order` - Transportation plan orders - `tms_quote_detail` - Quote details for routes - `tms_customer_info` - Customer information - `tms_driver` - Driver management - `tms_vehicle` - Vehicle/truck information - `tms_service_provider` - Third-party service providers ## Key Files & Locations ### Backend Configuration - `admin/src/main/resources/application.yml` - Main application configuration - `admin/src/main/resources/application-custom.yml` - Custom configurations (API keys, Aliyun) - `admin/src/main/resources/application-{profile}.yml` - Profile-specific configs ### Frontend Configuration - `ui/admin-ui3/vite.config.ts` - Vite build configuration - `ui/admin-ui3/.env.development` - Development environment variables - `ui/admin-ui3/src/settings.ts` - App-wide settings (theme, layout) ### Database & Migrations - `sql/` - Database initialization and migration scripts - Scripts are typically named by date (e.g., `tms_202501101.sql`) ## Common Development Tasks ### Adding a New API Endpoint 1. **Backend**: ```java @PostMapping("/smartDispatch") @PreAuthorize("@ss.hasPermi('tms:tmsDispatchOrder:smartDispatch')") public AjaxResult smartDispatch(@RequestParam("file") MultipartFile file) { // Implementation return success(result); } ``` 2. **Permission Registration**: - Add permission to `sys_menu` table: `INSERT INTO sys_menu VALUES(..., 'tms:tmsDispatchOrder:smartDispatch', ...)` - Assign to roles in `sys_role_menu` table 3. **Frontend API Service**: ```typescript export const smartDispatchExtract = (file: File): Promise => { const formData = new FormData(); formData.append("file", file); return request.post("/tms/tmsDispatchOrder/smartDispatch", formData); }; ``` 4. **Frontend Component**: ```vue Smart Dispatch ``` ### Modifying Database Schema 1. Create migration script in `sql/` directory (e.g., `tms_20260304.sql`) 2. Apply script to database: `mysql -u root -p database_name < sql/tms_20260304.sql` 3. Update corresponding domain models and mappers in `tms/` module 4. Regenerate MyBatis mappers if using generation tool ### Working with Avue CRUD Forms Key properties for column configuration: - `label` - Display label - `type` - Input type (input, select, textarea, date, table, etc.) - `addDisplay` - Show in add dialog - `editDisplay` - Show in edit dialog - `viewDisplay` - Show in view/detail page - `search` - Searchable in filter bar - `hide` - Hide from table display - `dicUrl` - URL for dropdown options (e.g., `/system/dict/data/type/order_type`) - `rules` - Validation rules - `children` - Nested table configuration for 1-to-many relationships ## Testing - Unit tests are currently skipped in Maven build (`true` in pom.xml) - To enable tests: `mvn test -DskipTests=false` - Frontend tests would require Jest/Vitest setup (currently not configured) ## Deployment ### Backend - **Build**: `mvn clean package` produces `admin/target/admin.jar` - **Run**: `java -jar admin.jar` or use Spring Boot deployment - **Configuration**: Set active profile via `spring.profiles.active` property ### Frontend - **Build**: `npm run build:prod` generates optimized assets in `dist/` directory - **Serve**: Copy `dist/` contents to web server (Nginx, Apache) or serve via Spring Boot static resources ## Important Notes ### Security & Permissions - All API endpoints must have `@PreAuthorize` annotation with appropriate permission - Permission strings follow pattern: `module:action:operation` - Database-driven permission system - add new permissions via `sys_menu` table - Never hardcode permissions in code ### Frontend State Management - Use Pinia stores for global state (user, app settings) - Use component-level `reactive()` or `ref()` for local state - Permissions are loaded from backend on login and stored in user store ### Error Handling - Backend returns `AjaxResult` with `code`, `msg`, `data` fields - HTTP 401: Unauthorized (redirect to login) - HTTP 403: Forbidden (no permission) - HTTP 500: Server error - Frontend interceptor handles errors globally ### Code Organization - Keep components focused and single-responsibility - Extract reusable logic into hooks (`src/hooks/`) - Put shared utilities in `src/utils/` - Organize views by feature module matching backend structure ## Troubleshooting **Backend Won't Start**: - Check MySQL connection in `application.yml` - Verify database exists and migrations are applied - Check port 8080 is not in use (or change in config) - Review logs in `logs/` directory **Frontend Dev Server Issues**: - Delete `node_modules/` and `package-lock.json`, then `npm install` - Clear `.vite/` cache directory - Check Vite port 5173 is not in use **Permission Denied on Frontend**: - Verify user has proper role assigned in `sys_user_role` table - Verify role is assigned permission in `sys_role_menu` table - Check permission string format is correct - Clear browser localStorage and re-login ## Related Documentation - **RuoYi Framework**: Based on popular RuoYi open-source framework - **Avue**: Data-driven CRUD form framework - key for table operations - **MyBatis**: ORM framework for database access - **Spring Security**: Authentication and authorization framework - **Vite**: Frontend build tool and dev server - **Pinia**: Vue 3 state management library