# 🔍 维护者 PR 审核指南
**语言:** [English](PR_REVIEW_GUIDE.md) | [中文](PR_REVIEW_GUIDE.zh-CN.md)
本指南适用于审核 pull request 的 NOFX 维护者。
---
## 📋 审核清单
### 1. 初步分类(24小时内)
- [ ] **检查 PR 与路线图的一致性**
- 是否符合我们当前的优先级?
- 是否在[路线图](../roadmap/README.zh-CN.md)中?
- 如果不在,我们是否应该接受它?
- [ ] **验证 PR 完整性**
- PR 模板的所有部分都已填写?
- 变更描述清晰?
- 相关 issue 已链接?
- UI 变更有截图/演示?
- [ ] **应用适当的标签**
- 优先级:critical/high/medium/low
- 类型:bug/feature/enhancement/docs
- 区域:frontend/backend/exchange/ai/security
- 状态:needs review/needs changes
- [ ] **分配审核者**
- 根据专业领域分配
- 至少需要 1 个维护者审核
### 2. 代码审核
#### A. 功能审核
```markdown
✅ **要问的问题:**
- 是否解决了所述问题?
- 边界情况是否处理?
- 是否会破坏现有功能?
- 方法是否适合我们的架构?
- 是否有更好的替代方案?
```
**测试:**
- [ ] 所有 CI 检查都通过?
- [ ] 贡献者进行了手动测试?
- [ ] 测试覆盖率足够?
- [ ] 测试有意义(不只是为了覆盖率)?
#### B. 代码质量审核
**Go 后端代码:**
```go
// ❌ 差 - 拒绝
func GetData(a, b string) interface{} {
d := doSomething(a, b)
return d
}
// ✅ 好 - 批准
func GetAccountBalance(apiKey, secretKey string) (*Balance, error) {
if apiKey == "" || secretKey == "" {
return nil, fmt.Errorf("API credentials required")
}
balance, err := client.FetchBalance(apiKey, secretKey)
if err != nil {
return nil, fmt.Errorf("failed to fetch balance: %w", err)
}
return balance, nil
}
```
**检查项:**
- [ ] 有意义的变量/函数名
- [ ] 正确的错误处理(没有忽略错误)
- [ ] 复杂逻辑有注释
- [ ] 没有硬编码值(使用常量/配置)
- [ ] 遵循 Go 习惯用法和约定
- [ ] 没有不必要的复杂性
**TypeScript/React 前端代码:**
```typescript
// ❌ 差 - 拒绝
const getData = (data: any) => {
return data.map(d =>
{d.name}
)
}
// ✅ 好 - 批准
interface Trader {
id: string;
name: string;
status: 'running' | 'stopped';
}
const TraderList: React.FC<{ traders: Trader[] }> = ({ traders }) => {
return (
{traders.map(trader => (
))}
);
};
```
**检查项:**
- [ ] 类型安全(除非绝对必要,否则不使用 `any`)
- [ ] 正确的 React 模式(hooks、函数式组件)
- [ ] 组件可重用性
- [ ] 可访问性(a11y)考虑
- [ ] 性能优化(需要时使用 memoization)
#### C. 安全审核
**关键检查:**
```go
// 🚨 拒绝 - 安全问题
func Login(username, password string) {
query := "SELECT * FROM users WHERE username='" + username + "'" // SQL 注入!
db.Query(query)
}
// ✅ 批准 - 安全
func Login(username, password string) error {
query := "SELECT * FROM users WHERE username = ?"
row := db.QueryRow(query, username) // 参数化查询
// ... 使用 bcrypt 进行正确的密码验证
}
```
- [ ] 没有 SQL 注入漏洞
- [ ] 前端没有 XSS 漏洞
- [ ] API 密钥/密码没有硬编码
- [ ] 用户输入已正确验证
- [ ] 认证/授权正确处理
- [ ] 日志中没有敏感数据
- [ ] 依赖项没有已知漏洞
#### D. 性能审核
- [ ] 没有明显的性能问题
- [ ] 数据库查询已优化(索引、没有 N+1 查询)
- [ ] 没有不必要的 API 调用
- [ ] 适当的缓存
- [ ] 没有内存泄漏
### 3. 文档审核
- [ ] 复杂逻辑有代码注释
- [ ] 如果需要,README 已更新
- [ ] API 文档已更新(如有 API 变更)
- [ ] 破坏性变更有迁移指南
- [ ] Changelog 条目(对于重大变更)
### 4. 测试审核
- [ ] 新函数有单元测试
- [ ] 新功能有集成测试
- [ ] 测试确实测试了功能(不只是覆盖率)
- [ ] 测试名称具有描述性
- [ ] 模拟数据真实
---
## 🏷️ 标签管理
### 优先级分配
使用这些标准来分配优先级:
**Critical(严重):**
- 安全漏洞
- 生产环境破坏性 bug
- 数据丢失问题
**High(高):**
- 影响许多用户的重大 bug
- 高优先级路线图功能
- 性能问题
**Medium(中):**
- 常规 bug 修复
- 标准功能请求
- 重构
**Low(低):**
- 次要改进
- 代码风格变更
- 非紧急文档
### 状态工作流
```
needs review → in review → needs changes → needs review → approved → merged
↓
on hold
```
**状态标签:**
- `status: needs review` - 准备初次审核
- `status: in progress` - 正在积极审核
- `status: needs changes` - 审核者请求更改
- `status: on hold` - 等待讨论/决定
- `status: blocked` - 被另一个 PR/issue 阻塞
---
## 💬 提供反馈
### 编写好的审核评论
**❌ 差的评论:**
```
这是错的。
改这个。
你为什么这样做?
```
**✅ 好的评论:**
```
这种方法可能会导致并发请求的问题。
考虑在这里使用互斥锁或原子操作。
建议:将此逻辑提取到单独的函数中以提高可测试性:
```go
func validateTraderConfig(config *TraderConfig) error {
// 验证逻辑
}
```
问题:你是否考虑过使用现有的 `ExchangeClient` 接口
而不是创建新接口?这将与代码库的其余部分保持一致。
```
### 评论类型
**🔴 阻塞性(必须解决):**
```markdown
**阻塞性:** 这引入了 SQL 注入漏洞。
请改用参数化查询。
```
**🟡 非阻塞性(建议):**
```markdown
**建议:** 考虑在这里使用 `strings.Builder` 以提高
连接多个字符串时的性能。
```
**🟢 赞扬(鼓励好的做法):**
```markdown
**很好!** 很好地使用 context 进行超时处理。这正是
我们想看到的。
```
### 问题 vs 指令
**❌ 指令(可能感觉强硬):**
```
改用工厂模式。
为这个函数添加测试。
```
**✅ 问题(更协作):**
```
工厂模式在这里会更合适吗?它可能会使测试更容易。
你能为错误路径添加一个测试用例吗?我想确保我们
优雅地处理失败。
```
---
## ⏱️ 响应时间指南
| PR 类型 | 初次审核 | 后续审核 | 合并决定 |
|---------|----------|----------|----------|
| **严重 Bug** | 4 小时 | 2 小时 | 当天 |
| **悬赏 PR** | 24 小时 | 12 小时 | 2-3 天 |
| **功能** | 2-3 天 | 1-2 天 | 3-5 天 |
| **文档** | 2-3 天 | 1-2 天 | 3-5 天 |
| **大型 PR** | 3-5 天 | 2-3 天 | 5-7 天 |
---
## ✅ 批准标准
PR 应在以下情况下批准:
1. **功能性**
- ✅ 解决了所述问题
- ✅ 现有功能没有退化
- ✅ 边界情况已处理
2. **质量**
- ✅ 遵循代码标准
- ✅ 结构良好且可读
- ✅ 测试覆盖率足够
3. **安全性**
- ✅ 没有安全漏洞
- ✅ 输入已验证
- ✅ 密钥管理正确
4. **文档**
- ✅ 需要的地方有代码注释
- ✅ 文档已更新(如适用)
5. **流程**
- ✅ 所有 CI 检查通过
- ✅ 所有审核评论已处理
- ✅ 已基于最新 dev 分支 rebase
---
## 🚫 拒绝标准
在以下情况下拒绝 PR:
**立即拒绝:**
- 🔴 引入安全漏洞
- 🔴 包含恶意代码
- 🔴 违反行为准则
- 🔴 包含抄袭代码
- 🔴 硬编码 API 密钥或密码
**请求更改:**
- 🟡 代码质量差(反馈被忽略后)
- 🟡 新功能没有测试
- 🟡 没有迁移路径的破坏性变更
- 🟡 与路线图不一致(未经事先讨论)
- 🟡 不完整(缺少关键部分)
**关闭并说明:**
- 🟠 重复功能
- 🟠 超出项目范围
- 🟠 已存在更好的替代方案
- 🟠 贡献者 >2 周无响应
---
## 🎯 特殊情况审核
### 悬赏 PR
需要额外注意:
- [ ] 所有验收标准都满足?
- [ ] 提供了演示视频/截图?
- [ ] 按悬赏 issue 中的规定工作?
- [ ] 私下讨论了付款信息?
- [ ] 优先审核(24小时周转)
### 破坏性变更
- [ ] 提供了迁移指南?
- [ ] 添加了弃用警告?
- [ ] 计划了版本升级?
- [ ] 考虑了向后兼容性?
- [ ] 为重大变更创建了 RFC?
### 安全 PR
- [ ] 由专注于安全的审核者验证?
- [ ] 没有公开披露漏洞?
- [ ] 如需要,协调披露?
- [ ] 准备了安全公告?
- [ ] 计划了补丁发布?
---
## 🔄 合并指南
### 何时合并
满足以下条件时合并:
- ✅ 至少 1 个维护者批准
- ✅ 所有 CI 检查通过
- ✅ 所有对话已解决
- ✅ 没有待处理的请求更改
- ✅ 已基于最新目标分支 rebase
### 合并策略
**Squash Merge**(大多数 PR 的默认策略):
- 小型 bug 修复
- 单功能 PR
- 文档更新
- 保持 git 历史清洁
**Merge Commit**(复杂 PR):
- 具有逻辑提交的多提交功能
- 保留提交历史
- 具有原子提交的大型重构
**Rebase and Merge**(很少使用):
- 线性历史很重要时
- 提交已经结构良好
### 合并提交信息
格式:
```
(): (#123)
变更的简要描述。
- 关键变更 1
- 关键变更 2
Co-authored-by: 贡献者姓名
```
---
## 📊 要跟踪的审核指标
每月监控这些指标:
- 平均首次审核时间
- 平均合并时间
- PR 接受率
- 按类型分类的 PR 数量(bug/feature/docs)
- 按区域分类的 PR 数量(frontend/backend/exchange)
- 贡献者留存率
---
## 🙋 问题?
如果对 PR 不确定:
1. **询问其他维护者**在私人频道
2. **向贡献者请求更多上下文**
3. **标记为"on hold"**并添加到下次维护者同步
4. **如有疑问,保守一点** - 问比批准有风险的东西更好
---
## 🔗 相关资源
- [贡献指南](../../CONTRIBUTING.md)
- [行为准则](../../CODE_OF_CONDUCT.md)
- [安全政策](../../SECURITY.md)
- [项目路线图](../roadmap/README.zh-CN.md)
---
**记住:** 审核应该是**尊重的**、**建设性的**和**教育性的**。
我们在构建社区,而不仅仅是代码。🚀