test-backend/.claude/backend.md

218 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 02 — 后端规则
> **适用**:所有后端 AI 开发任务。
---
## 分层不变式
```
Controller → 参数校验 + 调 Service + 返回统一格式
禁止:写业务逻辑、直接调 Mapper、处理事务
Service → 业务逻辑 + 事务管理
禁止:处理 HTTP 请求/响应、直接操作 Request/Response
Mapper → 数据访问MyBatis-Plus BaseMapper
禁止:写业务逻辑、调用其他 Mapper
Entity → 数据映射(@TableName 对应表名)
禁止:写业务方法、放非持久化字段(放 DTO/VO
```
### 包结构
```
com.ghb.base/
├── system/ # 系统模块(不改)
│ ├── entity/ SysUser, SysRole, SysMenu...
│ ├── controller/
│ └── service/
└── business/ # 业务模块 ← 你的代码放这里
├── entity/ # 继承 JeecgBoot 的 BaseEntity
├── controller/ # 继承 JeecgController
├── service/ # impl/ 继承 ServiceImpl
├── mapper/ # 继承 BaseMapper
│ └── xml/ # MyBatis XML复杂查询才需要
└── vo/ # 请求/响应 DTO (*VO, *Request, *ImportRow)
```
---
## 命名规则
| 元素 | 规则 | 示例(正确 → 错误) |
|------|------|---------------------|
| **类名** | 大驼峰,名词 | `TaskController` `OrderService` `UserMapper` |
| **方法名** | 小驼峰,动词开头 | `getById()` `saveTask()` `listByStatus()` |
| **变量** | 小驼峰,有意义 | `taskList` `userId` → ❌ `list` `id` `data` |
| **包名** | 全小写,点分隔 | `com.xxx.server.controller` |
| **Entity** | 大驼峰,对应表名 | 表 `task_apply` → 类 `TaskApply` |
| **DTO** | 大驼峰,后缀 DTO/VO/Request | `TaskCreateRequest` `UserListVO` |
| **常量** | 全大写,下划线分隔 | `MAX_RETRY_COUNT` `DEFAULT_PAGE_SIZE` |
| **SQL 表名** | 小写,下划线分隔 | `task_apply` `user_profile` |
| **SQL 字段** | 小写,下划线分隔 | `create_time` `task_id` `del_flag` |
| **URL 路径** | 小写,短横线或斜杠 | `/app/task/list` → ❌ `/app/Task/GetList` |
| **配置文件** | kebab-case 或小写 | `application-prod.yml` |
### 长度控制
类名、方法名、表名不要过长。超过 3 个单词或 30 个字符时,用通用缩写。
**前缀也要缩**:模块前缀用一个单词,别堆多个词。
| 完整 | 缩写 | JeecgBoot 实际案例 |
|------|------|-------------------|
| Department | Dept | `SysDepartRolePermission``SysDeptRolePerm` |
| Permission | Perm | 同上 |
| Announcement | Notice | `SysAnnouncementSend``SysNoticeSend` |
| Enterprise | Ent | `WechatEnterprise``WxEnt` |
| Message | Msg | `SysMessageTemplate``SysMsgTemplate` |
```java
// ❌ JeecgBoot 原版 — 太长
SysDepartRolePermissionServiceImpl // 35 字符
SysAnnouncementSendServiceImpl // 30 字符
ThirdAppWechatEnterpriseServiceImpl // 35 字符
// ✅ 缩写后
SysDeptRolePermServiceImpl // 26 字符
SysNoticeSendServiceImpl // 25 字符
ThirdAppWxEntServiceImpl // 27 字符
```
**原则**:优先用全称,超长再缩写。缩写必须一眼能认出含义,不自造别人看不懂的缩写。
---
## 注释规则
| 位置 | 要求 | 示例 |
|------|------|------|
| **类/接口** | 必须有 Javadoc说明职责 | `/** 任务管理 Controller处理任务的增删改查 */` |
| **公共方法** | 必须有 Javadoc说明入参/返回/异常 | `/** @param taskId 任务ID @return 任务详情 @throws 无 */` |
| **复杂逻辑** | 行内注释说明"为什么这么做" | `// 先查缓存再查库,避免击穿` |
| **常量** | 必须有注释说明含义 | `/** 最大重试次数 */` |
| **TODO/FIXME** | 必须有负责人和日期 | `// TODO(yaoshuli 2026-06) 后续改为配置项` |
| **禁止** | ❌ 注释写"做了什么"(代码本身已说明) | `// 查询任务列表` ← 删掉 |
| **禁止** | ❌ 注释掉的旧代码 | 直接删Git 有历史 |
| **禁止** | ❌ 无意义注释 | `// 定义一个变量` `// 返回结果` |
| **禁止** | ❌ Controller 方法加 Javadoc 说"这是xxx接口" | 写业务含义,不写技术废话 |
### 注释示例
```java
/** 任务服务,负责任务的创建、分配、状态流转 */
@Service
public class TaskServiceImpl implements TaskService {
/** 单次批量操作上限 */
private static final int BATCH_LIMIT = 100;
/**
* 根据状态和截止时间查询待处理任务。
* 先查 Redis 缓存,未命中再查 MySQL。
*
* @param status 任务状态,不能为 null
* @param deadline 截止时间,只查此时间之前的任务
* @return 任务列表,可能为空
*/
@Override
public List<Task> listPending(String status, LocalDateTime deadline) {
// 缓存 key: pending:{status}
String cacheKey = "pending:" + status;
List<Task> cached = cacheService.get(cacheKey);
if (cached != null) return cached;
// 查库(这里用复合索引 idx_status_deadline
List<Task> tasks = taskMapper.selectByStatusBefore(status, deadline);
cacheService.set(cacheKey, tasks, 300);
return tasks;
}
}
```
## 新增功能标准步骤
```
1. 建表 SQL → [项目数据库脚本目录]
2. Entity → 表映射
3. Mapper → 继承 BaseMapper
4. Service 接口+实现 → 业务逻辑
5. Controller → 接口暴露
6. 编译验证 → 构建通过
```
---
## CRUD 模板(填空式)
```java
// ===== 分页列表 =====
@GetMapping("/list")
public Result<IPage<Xxx>> list(@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
Page<Xxx> p = new Page<>(page, size);
// [填空] 构建查询条件
return Result.ok(service.page(p, wrapper));
}
// ===== 详情 =====
@GetMapping("/{id}")
public Result<Xxx> detail(@PathVariable Long id) {
Xxx entity = service.getById(id);
if (entity == null) return Result.error("[资源]不存在");
return Result.ok(entity);
}
// ===== 新增 =====
@PostMapping
public Result<?> create(@RequestBody @Valid XxxDto dto) {
// [填空] DTO → Entity 转换
service.save(entity);
return Result.ok();
}
// ===== 更新 =====
@PutMapping("/{id}")
public Result<?> update(@PathVariable Long id, @RequestBody @Valid XxxDto dto) {
Xxx entity = service.getById(id);
if (entity == null) return Result.error("[资源]不存在");
// [填空] 字段更新
service.updateById(entity);
return Result.ok();
}
```
---
## 禁止清单
| 类别 | ❌ 禁止 |
|------|--------|
| **分层** | Controller 里写 if/else 业务判断 |
| **分层** | Controller 直接调 Mapper/Repository |
| **分层** | Entity 里写业务方法 |
| **数据** | SQL/查询条件字符串拼接 |
| **数据** | 查不到不判空,直接返回可能 NPE |
| **数据** | `selectOne` / `getOne` 不做唯一性约束 |
| **输入** | 入参不校验(该用 `@Valid` 的地方手撸 if |
| **输出** | 返回裸对象、裸字符串、自造格式 |
| **值** | 代码里硬编码魔法数字、魔法字符串 |
| **事务** | 该加事务的地方漏加 |
---
## 检查表
每完成一个后端任务,逐项自检:
- [ ] 编译通过(`mvn compile` / `go build` / 对应构建命令)
- [ ] 所有返回值是统一格式,无裸返回
- [ ] 分页接口格式正确(`list/total/pages/current/size`
- [ ] Controller 方法体不超过 20 行(超过说明写了业务逻辑)
- [ ] 查不到/null 路径有明确的 `fail` 返回
- [ ] 改了接口 → 已 grep 同步所有前端调用方
- [ ] 新增/改字段 → 已更新数据库脚本
- [ ] 无禁止清单中的违规项