This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
TMS (Transportation Management System) is a full-stack application for managing transportation operations, built on the RuoYi framework.
tms for transportation management featuresmanage (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
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 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/.
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 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:
@PreAuthorize("@ss.hasPermi('tms:tmsDispatchOrder:list')")
@GetMapping("/list")
public TableDataInfo list(TmsDispatchOrder order) {
startPage();
List<TmsDispatchOrder> list = tmsDispatchOrderService.selectTmsDispatchOrderList(order);
return getDataTable(list);
}
Checking Permissions in Components:
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:
<!-- Show button only if user has permission -->
<el-button v-hasPermi="['tms:tmsDispatchOrder:add']" @click="handleAdd">
Add Order
</el-button>
<!-- Show element if user has role -->
<div v-hasRole="['admin']">Admin only content</div>
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<T, K> 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<TmsDispatchOrder, Long> {
List selectTmsDispatchOrderList(TmsDispatchOrder order);
}
// Implementation
@Service
public class TmsDispatchOrderServiceImpl extends BaseServiceImpl<TmsDispatchOrderMapper, TmsDispatchOrder>
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<TmsDispatchOrder> list = tmsDispatchOrderService.selectTmsDispatchOrderList(order);
return getDataTable(list);
}
}
```
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
<avue-crud
:option="option"
:data="tableData"
:page="page"
:permission="permissionList"
v-model="form"
v-model:search="queryParams"
@row-save="rowSave"
@row-update="rowUpdate"
@row-del="rowDel"
@search-change="searchChange"
/>
**Pinia Store Pattern** (`src/store/modules/user.ts`):
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;
},
},
});
```
tms_dispatch_order, tms_quote_detail)customer_id, created_time)id (bigint)create_by, create_time, update_by, update_time, remark, del_flagtms_dispatch_order - Main dispatch order entitytms_plan_order - Transportation plan orderstms_quote_detail - Quote details for routestms_customer_info - Customer informationtms_driver - Driver managementtms_vehicle - Vehicle/truck informationtms_service_provider - Third-party service providersadmin/src/main/resources/application.yml - Main application configurationadmin/src/main/resources/application-custom.yml - Custom configurations (API keys, Aliyun)admin/src/main/resources/application-{profile}.yml - Profile-specific configsui/admin-ui3/vite.config.ts - Vite build configurationui/admin-ui3/.env.development - Development environment variablesui/admin-ui3/src/settings.ts - App-wide settings (theme, layout)sql/ - Database initialization and migration scriptstms_202501101.sql)Backend:
java @PostMapping("/smartDispatch") @PreAuthorize("@ss.hasPermi('tms:tmsDispatchOrder:smartDispatch')") public AjaxResult smartDispatch(@RequestParam("file") MultipartFile file) { // Implementation return success(result); }
Permission Registration:
sys_menu table: INSERT INTO sys_menu VALUES(..., 'tms:tmsDispatchOrder:smartDispatch', ...)sys_role_menu tableFrontend API Service:
typescript export const smartDispatchExtract = (file: File): Promise<any> => { const formData = new FormData(); formData.append("file", file); return request.post("/tms/tmsDispatchOrder/smartDispatch", formData); };
Frontend Component:
vue <el-button v-hasPermi="['tms:tmsDispatchOrder:smartDispatch']" @click="handleSmartDispatch"> Smart Dispatch </el-button>
sql/ directory (e.g., tms_20260304.sql)mysql -u root -p database_name < sql/tms_20260304.sqltms/ moduleKey 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
<skipTests>true</skipTests> in pom.xml)mvn test -DskipTests=falsemvn clean package produces admin/target/admin.jarjava -jar admin.jar or use Spring Boot deploymentspring.profiles.active propertynpm run build:prod generates optimized assets in dist/ directorydist/ contents to web server (Nginx, Apache) or serve via Spring Boot static resources@PreAuthorize annotation with appropriate permissionmodule:action:operationsys_menu tablereactive() or ref() for local stateAjaxResult with code, msg, data fieldssrc/hooks/)src/utils/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