后端: - 为 copy_trading 表添加 max_market_end_date 字段(毫秒时间戳) - 为 markets 表添加 end_date 字段,迁移时清空已有数据 - 实现市场截止时间过滤逻辑(仅跟单截止时间小于设置时间的订单) - 更新 CopyTradingService 支持 maxMarketEndDate 的创建和更新 - 更新 FilterResult 添加 FAILED_MARKET_END_DATE 状态 - 更新 CopyOrderTrackingService 传递 marketEndDate 参数 前端: - 添加市场截止时间筛选 UI(支持小时和天两种单位) - 输入限制:仅支持整数输入(precision=0) - 更新 AddModal 和 EditModal 支持市场截止时间配置 - 更新过滤类型显示映射(MARKET_END_DATE) - 添加多语言支持(中文、英文、繁体中文) 数据库迁移: - V22: 合并添加 max_market_end_date 和 end_date 字段 - 迁移时清空 markets 表数据,确保所有数据都包含 end_date
182 lines
4.6 KiB
Plaintext
182 lines
4.6 KiB
Plaintext
---
|
||
alwaysApply: true
|
||
path: backend/**
|
||
---
|
||
|
||
# 后端开发规范
|
||
|
||
## 核心原则
|
||
- **禁止**在代码中添加 TODO/FIXME/XXX 注释
|
||
- **禁止**返回 mock 数据或硬编码的假数据
|
||
- **禁止**在 API 调用失败时返回默认值作为 fallback
|
||
- 所有功能必须完整实现,确保代码可以正常运行
|
||
|
||
## 项目范围
|
||
- **平台**: 仅支持 Polymarket
|
||
- **分类**: 仅支持 `sports` 和 `crypto`
|
||
- **包名**: `com.wrbug.polymarketbot`
|
||
|
||
## 实体类规范
|
||
```kotlin
|
||
@Entity
|
||
@Table(name = "example_table")
|
||
data class ExampleEntity(
|
||
@Id
|
||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||
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
|
||
)
|
||
```
|
||
|
||
**规则**:
|
||
- ID 字段必须使用 `Long? = null`
|
||
- 时间字段使用 `Long` 时间戳(毫秒)
|
||
- 数值字段使用 `BigDecimal`
|
||
- **禁止**使用 `LocalDateTime` 或 `Double`
|
||
|
||
## 配置文件规范
|
||
- **必须**使用 `application.properties` 格式(禁止 `application.yml`)
|
||
- 使用 `${ENV_VAR:default}` 引用环境变量
|
||
|
||
## 代码规范
|
||
|
||
### Controller
|
||
- **禁止**使用 `suspend`
|
||
- 使用 `runBlocking` 调用 suspend 方法
|
||
- 统一使用 `@PostMapping`
|
||
|
||
### Service
|
||
- 可以使用 `suspend` 方法
|
||
- 使用 `@Transactional` 管理事务
|
||
- 使用构造函数注入依赖
|
||
|
||
### Repository
|
||
- 继承 `JpaRepository<Entity, Long>`
|
||
- 使用 Spring Data JPA 方法命名规范
|
||
|
||
## API 接口规范
|
||
|
||
### 统一响应格式
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {},
|
||
"msg": ""
|
||
}
|
||
```
|
||
|
||
### 错误码范围
|
||
- `0`: 成功
|
||
- `1001-1999`: 参数错误
|
||
- `2001-2999`: 认证/权限错误
|
||
- `3001-3999`: 资源不存在
|
||
- `4001-4999`: 业务逻辑错误
|
||
- `5001-5999`: 服务器内部错误
|
||
|
||
### Controller 示例
|
||
```kotlin
|
||
@RestController
|
||
@RequestMapping("/api/example")
|
||
class ExampleController(
|
||
private val exampleService: ExampleService,
|
||
private val messageSource: MessageSource
|
||
) {
|
||
@PostMapping("/list")
|
||
fun getList(@RequestBody request: ExampleListRequest): ResponseEntity<ApiResponse<ExampleListResponse>> {
|
||
return try {
|
||
val data = runBlocking { exampleService.getList(request) }
|
||
ResponseEntity.ok(ApiResponse.success(data))
|
||
} catch (e: Exception) {
|
||
logger.error("Failed to get list", e)
|
||
ResponseEntity.ok(ApiResponse.error(ErrorCode.SERVER_ERROR, messageSource))
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 数值计算
|
||
```kotlin
|
||
val amount = "0.5".toSafeBigDecimal()
|
||
val total = amount.add("0.4".toSafeBigDecimal())
|
||
|
||
if (total.lt(BigDecimal.ONE)) {
|
||
// 业务逻辑
|
||
}
|
||
```
|
||
|
||
## Side 判断规范
|
||
**禁止**使用 "YES"/"NO" 字符串判断 side
|
||
|
||
```kotlin
|
||
// ❌ 错误
|
||
if (side != null && side.uppercase() == "NO") { }
|
||
|
||
// ✅ 正确
|
||
if (outcomeIndex != null && outcomeIndex == 1) { }
|
||
```
|
||
|
||
## 多语言规范
|
||
- **禁止**硬编码中文或英文错误消息
|
||
- **必须**使用 `ErrorCode` 枚举和 `MessageSource`
|
||
|
||
```kotlin
|
||
// ❌ 错误
|
||
return ResponseEntity.ok(ApiResponse.paramError("配置ID不能为空"))
|
||
|
||
// ✅ 正确
|
||
return ResponseEntity.ok(ApiResponse.error(ErrorCode.PARAM_EMPTY, messageSource))
|
||
```
|
||
|
||
### 多语言支持范围
|
||
1. **API 响应消息**: 使用 `ErrorCode` + `MessageSource`
|
||
2. **日志消息**: 可使用中文或英文
|
||
3. **代码注释**: 建议使用中文
|
||
4. **数据库字段**: 使用英文(snake_case)
|
||
|
||
## HTTP 客户端
|
||
- 使用 Retrofit + OkHttp
|
||
- 使用拦截器处理认证
|
||
|
||
## 跟单系统需求
|
||
参考文档: `docs/copy-trading-requirements.md`
|
||
|
||
核心功能:
|
||
- 账户管理(私钥导入,多账户)
|
||
- Leader 管理
|
||
- 订单同步与执行
|
||
- 跟单配置管理
|
||
- 风险控制
|
||
- 跟单记录与统计
|
||
|
||
## 禁止事项
|
||
|
||
### 代码质量
|
||
- ❌ 禁止使用 `!!` 除非有明确原因
|
||
- ❌ 禁止忽略异常
|
||
- ❌ 禁止硬编码配置值
|
||
- ❌ 禁止提交敏感信息到 Git
|
||
|
||
### 类型
|
||
- ❌ 禁止使用 `Double` 进行数值计算
|
||
- ❌ 禁止使用 `LocalDateTime` 存储时间
|
||
- ❌ 禁止实体类 ID 使用非空默认值
|
||
|
||
### API 接口
|
||
- ❌ 禁止使用 GET/PUT/DELETE(统一使用 POST)
|
||
- ❌ 禁止返回不符合统一格式的响应
|
||
- ❌ 禁止在响应中直接返回 Map 类型
|
||
|
||
### Side 判断
|
||
- ❌ 禁止使用 "YES"/"NO" 字符串判断 side
|
||
- ✅ 必须使用 `outcomeIndex` 判断
|
||
|
||
### 数据源
|
||
- ❌ 禁止直接返回 mock 数据
|
||
- ❌ 禁止在 API 调用失败时返回 mock 数据
|
||
- ✅ 所有数据必须来自真实 API 或数据库查询
|