# 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 同步所有前端调用方
- [ ] 新增/改字段 → 已更新数据库脚本
- [ ] 无禁止清单中的违规项
