Files
PolyHermes/.cursor/rules/backend.mdc
T

234 lines
6.2 KiB
Plaintext
Raw Normal View History

2025-11-21 04:32:08 +08:00
---
alwaysApply: true
path: backend/**
---
# 后端开发规范
2026-01-09 08:35:05 +08:00
## 核心原则
- **禁止**在代码中添加 TODO/FIXME/XXX 注释
- **禁止**返回 mock 数据或硬编码的假数据
- **禁止**在 API 调用失败时返回默认值作为 fallback
- 所有功能必须完整实现,确保代码可以正常运行
2025-11-21 04:32:08 +08:00
## 项目范围
2026-01-09 08:35:05 +08:00
- **平台**: 仅支持 Polymarket
2025-11-21 04:32:08 +08:00
- **包名**: `com.wrbug.polymarketbot`
## 实体类规范
```kotlin
@Entity
@Table(name = "example_table")
data class ExampleEntity(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
2026-01-09 08:35:05 +08:00
val id: Long? = null, // ✅ 正确:使用可空类型
@Column(name = "created_at", nullable = false)
val createdAt: Long = System.currentTimeMillis(), // ✅ 使用 Long 时间戳
@Column(name = "amount", nullable = false, precision = 20, scale = 8)
val amount: BigDecimal = BigDecimal.ZERO // ✅ 使用 BigDecimal
2025-11-21 04:32:08 +08:00
)
```
2026-01-09 08:35:05 +08:00
**规则**:
- ID 字段必须使用 `Long? = null`
- 时间字段使用 `Long` 时间戳(毫秒)
- 数值字段使用 `BigDecimal`
- **禁止**使用 `LocalDateTime` 或 `Double`
2025-11-21 04:32:08 +08:00
2026-01-09 08:35:05 +08:00
## 配置文件规范
- **必须**使用 `application.properties` 格式(禁止 `application.yml`
- 使用 `${ENV_VAR:default}` 引用环境变量
2025-11-21 04:32:08 +08:00
## 代码规范
2026-01-09 08:35:05 +08:00
### Controller
- **禁止**使用 `suspend`
- 使用 `runBlocking` 调用 suspend 方法
- 统一使用 `@PostMapping`
2025-11-21 04:32:08 +08:00
2026-01-09 08:35:05 +08:00
### Service
- 可以使用 `suspend` 方法
2025-11-21 04:32:08 +08:00
- 使用 `@Transactional` 管理事务
- 使用构造函数注入依赖
2026-01-09 08:35:05 +08:00
### Repository
- 继承 `JpaRepository<Entity, Long>`
2025-11-21 04:32:08 +08:00
- 使用 Spring Data JPA 方法命名规范
2026-01-09 08:35:05 +08:00
## API 接口规范
2025-11-21 04:32:08 +08:00
2026-01-09 08:35:05 +08:00
### 统一响应格式
2025-11-21 04:32:08 +08:00
```json
{
"code": 0,
"data": {},
"msg": ""
}
```
2026-01-09 08:35:05 +08:00
### 错误码范围
- `0`: 成功
- `1001-1999`: 参数错误
- `2001-2999`: 认证/权限错误
- `3001-3999`: 资源不存在
- `4001-4999`: 业务逻辑错误
- `5001-5999`: 服务器内部错误
2025-11-21 04:32:08 +08:00
2026-01-09 08:35:05 +08:00
### Controller 示例
2025-11-21 04:32:08 +08:00
```kotlin
@RestController
@RequestMapping("/api/example")
class ExampleController(
2026-01-09 08:35:05 +08:00
private val exampleService: ExampleService,
private val messageSource: MessageSource
2025-11-21 04:32:08 +08:00
) {
@PostMapping("/list")
fun getList(@RequestBody request: ExampleListRequest): ResponseEntity<ApiResponse<ExampleListResponse>> {
return try {
val data = runBlocking { exampleService.getList(request) }
2026-01-09 08:35:05 +08:00
ResponseEntity.ok(ApiResponse.success(data))
2025-11-21 04:32:08 +08:00
} catch (e: Exception) {
logger.error("Failed to get list", e)
2026-01-09 08:35:05 +08:00
ResponseEntity.ok(ApiResponse.error(ErrorCode.SERVER_ERROR, messageSource))
2025-11-21 04:32:08 +08:00
}
}
}
```
2026-01-09 08:35:05 +08:00
## 数值计算
```kotlin
val amount = "0.5".toSafeBigDecimal()
val total = amount.add("0.4".toSafeBigDecimal())
2025-11-21 04:32:08 +08:00
2026-01-09 08:35:05 +08:00
if (total.lt(BigDecimal.ONE)) {
// 业务逻辑
}
```
2025-11-21 04:32:08 +08:00
## JSON 解析规范
### 使用扩展函数(推荐)
- **优先**使用扩展函数 `fromJson<T>()` 和 `toJson()`,禁止直接使用 `Gson`
- 扩展函数提供了类型安全的解析,使用方便
```kotlin
// ✅ 正确:使用扩展函数(推荐)
val json = "{\"name\":\"test\"}"
val obj = json.fromJson<MyDataClass>()
val jsonStr = obj.toJson()
// ✅ 也可以:使用 JsonUtils 类(兼容旧代码)
val obj = jsonUtils.fromJson<MyDataClass>(json)
// ❌ 错误:直接使用 Gson
val obj = gson.fromJson(json, MyDataClass::class.java)
```
### 扩展函数列表
- `String?.fromJson<T>()` - 解析 JSON 字符串为对象(支持泛型)
- `JsonElement?.fromJson<T>()` - 解析 JsonElement 为对象(支持泛型)
- `Any?.toJson()` - 将对象转换为 JSON 字符串
- `String?.parseStringArray()` - 解析 JSON 字符串数组
### JsonUtils 类
- `JsonUtils` 主要用于初始化全局 Gson 实例,供扩展函数使用
- 保留 `parseStringArray()` 方法用于兼容旧代码
- 不推荐直接使用 `JsonUtils` 的方法,优先使用扩展函数
### Data Class 规范
- **所有 data class 字段必须提供默认值**
- 可空字段使用 `? = null`
- 非空字段提供合适的默认值(空字符串、空集合、默认数值等)
```kotlin
// ✅ 正确:所有字段都有默认值
data class MyDto(
val name: String = "",
val age: Int = 0,
val tags: List<String> = emptyList(),
val optional: String? = null
)
// ❌ 错误:缺少默认值
data class MyDto(
val name: String, // 缺少默认值
val age: Int = 0
)
```
2026-01-09 08:35:05 +08:00
## Side 判断规范
**禁止**使用 "YES"/"NO" 字符串判断 side
2025-11-21 04:32:08 +08:00
2026-01-09 08:35:05 +08:00
```kotlin
// ❌ 错误
if (side != null && side.uppercase() == "NO") { }
2025-11-21 04:32:08 +08:00
2026-01-09 08:35:05 +08:00
// ✅ 正确
if (outcomeIndex != null && outcomeIndex == 1) { }
```
2026-01-09 08:35:05 +08:00
## 多语言规范
- **禁止**硬编码中文或英文错误消息
- **必须**使用 `ErrorCode` 枚举和 `MessageSource`
```kotlin
2026-01-09 08:35:05 +08:00
// ❌ 错误
return ResponseEntity.ok(ApiResponse.paramError("配置ID不能为空"))
2026-01-09 08:35:05 +08:00
// ✅ 正确
return ResponseEntity.ok(ApiResponse.error(ErrorCode.PARAM_EMPTY, messageSource))
```
2026-01-09 08:35:05 +08:00
### 多语言支持范围
1. **API 响应消息**: 使用 `ErrorCode` + `MessageSource`
2. **日志消息**: 可使用中文或英文
3. **代码注释**: 建议使用中文
4. **数据库字段**: 使用英文(snake_case
2026-01-09 08:35:05 +08:00
## HTTP 客户端
- 使用 Retrofit + OkHttp
- 使用拦截器处理认证
2025-12-05 02:20:46 +08:00
2026-01-09 08:35:05 +08:00
## 跟单系统需求
参考文档: `docs/copy-trading-requirements.md`
2025-12-05 02:20:46 +08:00
2026-01-09 08:35:05 +08:00
核心功能:
- 账户管理(私钥导入,多账户)
- Leader 管理
- 订单同步与执行
- 跟单配置管理
- 风险控制
- 跟单记录与统计
2025-12-05 02:20:46 +08:00
2026-01-09 08:35:05 +08:00
## 禁止事项
2025-12-05 02:20:46 +08:00
2026-01-09 08:35:05 +08:00
### 代码质量
- ❌ 禁止使用 `!!` 除非有明确原因
- ❌ 禁止忽略异常
- ❌ 禁止硬编码配置值
- ❌ 禁止提交敏感信息到 Git
2025-12-05 02:20:46 +08:00
2026-01-09 08:35:05 +08:00
### 类型
- ❌ 禁止使用 `Double` 进行数值计算
- ❌ 禁止使用 `LocalDateTime` 存储时间
- ❌ 禁止实体类 ID 使用非空默认值
- ❌ 禁止直接使用 `Gson`(必须使用 `JsonUtils`
- ❌ 禁止 data class 字段缺少默认值
2025-12-05 02:20:46 +08:00
2026-01-09 08:35:05 +08:00
### API 接口
- ❌ 禁止使用 GET/PUT/DELETE(统一使用 POST
- ❌ 禁止返回不符合统一格式的响应
- ❌ 禁止在响应中直接返回 Map 类型
2025-12-05 02:20:46 +08:00
2026-01-09 08:35:05 +08:00
### Side 判断
- ❌ 禁止使用 "YES"/"NO" 字符串判断 side
- ✅ 必须使用 `outcomeIndex` 判断
2025-12-05 02:20:46 +08:00
2026-01-09 08:35:05 +08:00
### 数据源
- ❌ 禁止直接返回 mock 数据
- ❌ 禁止在 API 调用失败时返回 mock 数据
- ✅ 所有数据必须来自真实 API 或数据库查询