# 开发规范
本文档规范 DarkM 项目的完整开发流程,包括 Git 工作流、代码审查、测试、版本管理、部署等所有开发相关事项。
# 📋 完整开发流程
# 标准开发流程
graph TD
A[需求分析] --> B[任务拆分]
B --> C[创建 Git 分支]
C --> D[本地开发]
D --> E[单元测试]
E --> F[提交代码]
F --> G[推送到远程]
G --> H[创建 Merge Request]
H --> I[CI 自动检查]
I --> J[代码审查]
J --> K{审查通过?}
K -->|否 | L[修改反馈]
L --> J
K -->|是 | M[合并到 develop]
M --> N[部署测试环境]
N --> O[功能测试]
O --> P[创建 Release 分支]
P --> Q[回归测试]
Q --> R[合并到 master]
R --> S[打版本标签]
S --> T[部署生产环境]
T --> U[监控验证]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 各阶段详细说明
# 1. 需求分析(1-2 天)
输入: 产品需求文档(PRD)
输出:
- 技术方案设计
- 任务拆分清单
- 工作量评估
参与人员: 产品经理、技术负责人、开发人员
检查清单:
- [ ] 需求理解一致
- [ ] 技术可行性确认
- [ ] 依赖关系明确
- [ ] 风险评估完成
# 2. 任务拆分(0.5 天)
用户故事格式:
作为 [角色]
我想要 [功能]
以便于 [价值]
验收标准:
1. [标准 1]
2. [标准 2]
3. [标准 3]
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
示例:
作为 系统管理员
我想要 批量导入用户功能
以便于 快速初始化用户数据
验收标准:
1. 支持 Excel 格式导入
2. 单次最多导入 1000 条
3. 导入失败显示详细错误信息
4. 导入完成发送通知
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
任务拆分原则:
- 每个任务不超过 3 天工作量
- 任务可独立测试
- 任务之间有明确依赖关系
# 3. 开发实现(根据任务复杂度)
每日工作流:
# 早上开始工作
git checkout develop
git pull origin develop
git checkout feature/your-feature
git rebase develop # 保持分支最新
# 开发过程中
git add .
git commit -m "feat: 完成 XXX 功能"
# 下班前
git push origin feature/your-feature
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 4. 代码审查(0.5-1 天)
审查要点:
- 代码质量
- 功能正确性
- 性能影响
- 安全性
- 测试覆盖
# 5. 测试验证(1-2 天)
测试类型:
- 单元测试(开发人员)
- 集成测试(开发人员)
- 功能测试(测试人员)
- 回归测试(测试人员)
# 6. 部署上线(0.5 天)
部署检查:
- 预发布环境验证
- 生产环境部署
- 线上功能验证
- 监控告警配置
# 🌿 Git 工作流详解
# 分支模型
采用 Git Flow 工作流,结合 DarkM 项目特点:
master (生产环境)
↑
release/v* (发布分支)
↑
develop (开发主线)
↑
├── feature/* (功能开发)
├── bugfix/* (Bug 修复)
└── hotfix/* (紧急修复)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 分支详细说明
# master 分支(生产分支)
| 属性 | 说明 |
|---|---|
| 用途 | 生产环境代码,随时可发布 |
| 来源 | 从 develop 分支合并 |
| 保护 | 禁止直接提交,必须通过 MR 合并 |
| 生命周期 | 永久 |
| 命名 | master |
操作示例:
# 查看 master 分支
git checkout master
git pull origin master
# 查看版本标签
git tag -l
1
2
3
4
5
6
2
3
4
5
6
# develop 分支(开发分支)
| 属性 | 说明 |
|---|---|
| 用途 | 日常开发集成分支 |
| 来源 | 从 master 分支创建(初始) |
| 保护 | 禁止直接提交,必须通过 MR 合并 |
| 生命周期 | 永久 |
| 命名 | develop |
操作示例:
# 基于 develop 创建功能分支
git checkout develop
git pull origin develop
git checkout -b feature/user-management
1
2
3
4
2
3
4
# feature 分支(功能分支)
| 属性 | 说明 |
|---|---|
| 用途 | 新功能开发 |
| 来源 | develop 分支 |
| 合并目标 | develop 分支 |
| 生命周期 | 功能完成后删除 |
| 命名 | feature/<功能描述> |
命名示例:
feature/user-management # 用户管理功能
feature/order-export # 订单导出功能
feature/payment-integration # 支付集成
1
2
3
2
3
完整操作流程:
# 1. 创建功能分支
git checkout develop
git pull origin develop
git checkout -b feature/user-management
# 2. 开发过程中提交
git add src/
git commit -m "feat(user): 添加用户列表查询"
git add src/
git commit -m "feat(user): 实现用户新增功能"
git add src/
git commit -m "feat(user): 实现用户编辑功能"
# 3. 推送到远程
git push -u origin feature/user-management
# 4. 功能开发完成,创建 MR 合并到 develop
# 在 GitLab/GitHub 上创建 Merge Request
# 5. 合并后删除分支
git checkout develop
git pull origin develop
git branch -d feature/user-management
git push origin --delete feature/user-management
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# bugfix 分支(Bug 修复分支)
| 属性 | 说明 |
|---|---|
| 用途 | 测试阶段发现的 Bug 修复 |
| 来源 | develop 分支 |
| 合并目标 | develop 分支 |
| 生命周期 | Bug 修复后删除 |
| 命名 | bugfix/<Bug 描述> |
操作示例:
# 创建 Bug 修复分支
git checkout -b bugfix/login-error develop
# 修复 Bug
# ... 修改代码 ...
git add .
git commit -m "fix(auth): 修复登录页面样式错误"
git push -u origin bugfix/login-error
# 创建 MR 合并到 develop
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# hotfix 分支(紧急修复分支)
| 属性 | 说明 |
|---|---|
| 用途 | 生产环境紧急 Bug 修复 |
| 来源 | master 分支 |
| 合并目标 | master 和 develop 分支 |
| 生命周期 | 修复后删除 |
| 命名 | hotfix/<修复描述> |
完整操作流程:
# 1. 基于 master 创建热修复分支
git checkout master
git pull origin master
git checkout -b hotfix/login-critical
# 2. 修复紧急 Bug
# ... 修改代码 ...
git add .
git commit -m "fix(auth): 修复登录崩溃问题(紧急)"
# 3. 合并到 master
git checkout master
git merge --no-ff hotfix/login-critical
git tag -a v1.2.1 -m "Hotfix: 修复登录崩溃问题"
# 4. 合并到 develop(保持同步)
git checkout develop
git merge --no-ff hotfix/login-critical
# 5. 推送
git push origin master --tags
git push origin develop
git push origin hotfix/login-critical
# 6. 删除热修复分支
git branch -d hotfix/login-critical
git push origin --delete hotfix/login-critical
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# release 分支(发布分支)
| 属性 | 说明 |
|---|---|
| 用途 | 版本发布准备和测试 |
| 来源 | develop 分支 |
| 合并目标 | master 和 develop 分支 |
| 生命周期 | 发布后删除 |
| 命名 | release/v<版本号> |
完整发布流程:
# 1. 创建发布分支
git checkout develop
git pull origin develop
git checkout -b release/v1.2.0
# 2. 版本号更新
# 修改 .csproj、package.json、AssemblyInfo.cs
# 3. 更新 CHANGELOG.md
# 记录本次发布的所有变更
# 4. 最终测试
npm test
dotnet test
npm run build
# 5. 提交发布准备
git add .
git commit -m "chore: 准备发布 v1.2.0"
git push origin release/v1.2.0
# 6. 创建 MR 合并到 master(发布审查)
# 在 GitLab/GitHub 上创建 Merge Request
# 7. 合并到 master
git checkout master
git pull origin master
git merge --no-ff release/v1.2.0
git tag -a v1.2.0 -m "Release version 1.2.0"
# 8. 合并回 develop(保持同步)
git checkout develop
git merge --no-ff release/v1.2.0
# 9. 删除发布分支
git branch -d release/v1.2.0
git push origin --delete release/v1.2.0
# 10. 推送所有变更
git push origin master --tags
git push origin develop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 📝 Commit Message 规范详解
# 完整格式
<type>(<scope>): <subject>
<body>
<footer>
1
2
3
4
5
2
3
4
5
# Type 类型详解
| 类型 | 说明 | 使用场景 | 示例 |
|---|---|---|---|
feat | 新功能 | 新增功能模块 | feat: 添加用户管理模块 |
fix | Bug 修复 | 修复功能缺陷 | fix: 修复登录失败问题 |
docs | 文档 | 文档增删改 | docs: 更新 API 文档 |
style | 格式 | 代码格式调整(不影响功能) | style: 格式化代码 |
refactor | 重构 | 代码重构(不新增功能、不修复 Bug) | refactor: 重构用户服务 |
perf | 性能 | 性能优化 | perf: 优化数据库查询 |
test | 测试 | 测试相关(新增/修改测试) | test: 添加单元测试 |
chore | 构建 | 构建过程或辅助工具变动 | chore: 更新依赖版本 |
ci | CI/CD | 持续集成配置 | ci: 添加 GitHub Actions |
revert | 回滚 | 回滚上一次提交 | revert: 回滚用户管理功能 |
build | 构建 | 影响构建系统或外部依赖 | build: 更新 webpack 配置 |
config | 配置 | 配置文件修改 | config: 更新数据库配置 |
# Scope 范围说明
| 范围 | 说明 | 示例 |
|---|---|---|
admin | 权限管理模块 | feat(admin): 添加角色管理 |
common | 通用模块 | fix(common): 修复字典查询 |
quartz | 任务调度 | feat(quartz): 新增定时任务 |
data | 数据访问层 | perf(data): 优化 ORM 查询 |
ui | 前端 UI | style(ui): 调整按钮样式 |
utils | 工具库 | feat(utils): 添加加密工具 |
docs | 文档 | docs: 更新快速上手 |
config | 配置 | config: 更新端口配置 |
deps | 依赖 | chore(deps): 升级依赖版本 |
# Subject 主题规范
规则:
- 使用祈使句:"add" 而不是 "added"
- 首字母小写
- 不以句号结尾
- 长度不超过 50 字符
- 清晰简洁描述变更内容
示例:
# ✅ 推荐
feat: 添加用户列表查询功能
fix: 修复登录 token 过期问题
docs: 更新 API 接口文档
# ❌ 不推荐
feat: 添加了用户列表查询功能 # 过去式
Fix: 修复登录问题 # 首字母大写
feat: 添加了一个新的用户管理功能,包括列表查询、新增、编辑、删除等 # 太长
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# Body 正文规范
何时需要 Body:
- 复杂的变更需要解释
- 说明修改原因
- 对比修改前后
- 记录技术决策
格式要求:
- 每行不超过 72 字符
- 使用第一人称现在时
- 详细说明"为什么"而不是"是什么"
示例:
feat(user): 添加批量导入用户功能
- 实现 Excel 文件解析
- 支持单次最多 1000 条导入
- 添加数据验证(重复检查、格式验证)
- 导入失败显示详细错误信息
- 导入完成发送站内通知
技术实现:
- 使用 EPPlus 解析 Excel
- 事务处理确保数据一致性
- 异步处理提高导入性能
性能对比:
- 导入 1000 条:从 30s 优化到 5s
- 内存占用:从 500MB 降低到 50MB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Footer 页脚规范
关联 Issue:
Closes #123
Fixes #456
Refs #789
1
2
3
2
3
破坏性变更:
BREAKING CHANGE: UserRepository 接口变更
- 移除 FindById 方法
- 新增 GetAsync 方法
- 所有实现类需要更新
迁移指南:
1. 替换 FindById 为 GetAsync
2. 添加 async/await 关键字
3. 更新返回值处理
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
完整示例:
feat(user): 重构用户服务层
- 提取公共方法到基类
- 优化异步实现
- 添加完整单元测试
BREAKING CHANGE: IUserService 接口变更
- RemoveUser 改为 DeleteUser
- 新增 BatchDelete 方法
Closes #123
Refs #456
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 🔍 代码审查(Code Review)详解
# 审查流程
graph TD
A[开发者完成开发] --> B[创建 Merge Request]
B --> C[填写 MR 描述]
C --> D[指定 Reviewer]
D --> E[CI 自动检查]
E --> F{CI 通过?}
F -->|否 | G[修复 CI 问题]
G --> E
F -->|是 | H[Reviewer 审查]
H --> I{审查通过?}
I -->|否 | J[提出修改意见]
J --> K[开发者修改]
K --> H
I -->|是 | L[批准合并]
L --> M[合并到目标分支]
M --> N[删除功能分支]
N --> O[触发 CI/CD]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Merge Request 模板
## 📋 变更说明
**需求链接:** [需求文档链接]
**任务编号:** [JIRA-123]
## 🎯 变更内容
### 功能新增
- [ ] 添加用户列表查询
- [ ] 实现用户新增功能
- [ ] 实现用户编辑功能
### Bug 修复
- [ ] 修复登录页面样式问题
### 性能优化
- [ ] 优化数据库查询性能
## 🧪 测试说明
### 单元测试
- [ ] 新增单元测试 10 个
- [ ] 测试覆盖率:85%
### 集成测试
- [ ] API 接口测试通过
- [ ] 数据库操作测试通过
### 手动测试
- [ ] 功能测试通过
- [ ] 边界条件测试通过
## 📸 截图/录屏
(如有 UI 变更,提供截图)
## ⚠️ 注意事项
- [ ] 数据库迁移脚本已准备
- [ ] 配置文件已更新
- [ ] 文档已更新
## 🔗 关联 Issue
Closes #123
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 审查清单(Checklist)
# 代码质量(30%)
- [ ] 遵循编码规范
- [ ] 命名清晰易懂
- [ ] 函数职责单一(不超过 50 行)
- [ ] 代码重复度低
- [ ] 注释适当且准确
- [ ] 无死代码和调试代码
# 功能正确(30%)
- [ ] 功能实现完整
- [ ] 边界条件处理
- [ ] 异常处理适当
- [ ] 日志记录完整
- [ ] 无安全隐患
- [ ] 符合业务需求
# 性能优化(15%)
- [ ] 无 N+1 查询
- [ ] 数据库索引合理
- [ ] 缓存使用适当
- [ ] 无内存泄漏
- [ ] 异步处理 I/O
- [ ] 大数据量测试通过
# 测试覆盖(15%)
- [ ] 单元测试通过
- [ ] 集成测试通过
- [ ] 测试覆盖率达标(>80%)
- [ ] 边界用例测试
- [ ] 回归测试通过
# 文档完整(10%)
- [ ] API 文档更新
- [ ] 代码注释完整
- [ ] README 更新
- [ ] CHANGELOG 更新
- [ ] 部署文档更新
# 审查意见规范
# ✅ 批准(LGTM)
LGTM! 👍
代码质量很好,功能实现完整,测试覆盖充分。
建议合并。
1
2
3
4
2
3
4
# 💬 建议(非必须修改)
代码整体不错,有几个小建议供参考:
1. 第 35 行:可以考虑使用 async/await 替代 Promise 链
2. 第 78 行:这个魔法数字可以提取为常量
3. 建议添加空状态处理
这些不是必须修改的,你可以斟酌处理。
1
2
3
4
5
6
7
2
3
4
5
6
7
# ❌ 需要修改(必须修复)
需要修改后才能合并:
### 严重问题
1. ❌ 缺少参数验证(第 25 行)
2. ❌ 异常处理不完整(第 50 行)
3. ❌ SQL 注入风险(第 80 行)
### 测试问题
4. ❌ 缺少单元测试
5. ❌ 边界条件未测试
### 文档问题
6. ❌ API 文档未更新
请修复后重新提交审查。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ⚠️ 询问(需要澄清)
有几个地方需要确认:
1. 第 45 行:为什么这里要加锁?
2. 第 67 行:这个超时时间设置为 30s 的原因?
3. 是否考虑过并发场景?
请澄清一下,谢谢。
1
2
3
4
5
6
7
2
3
4
5
6
7
# 审查工具
# GitLab MR
# 查看 MR 状态
glab mr list
# 查看 MR 详情
glab mr view <MR_ID>
# 批准 MR
glab mr approve <MR_ID>
# 合并 MR
glab mr merge <MR_ID>
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# GitHub PR
# 查看 PR 状态
gh pr list
# 查看 PR 详情
gh pr view <PR_NUMBER>
# 批准 PR
gh pr review <PR_NUMBER> --approve
# 合并 PR
gh pr merge <PR_NUMBER> --merge
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 🧪 测试规范详解
# 测试金字塔
/\
/ \
/ E2E \ 5% - 端到端测试
/--------\
/Integration\ 20% - 集成测试
/--------------\
/ Unit Tests \ 75% - 单元测试
/------------------\
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 单元测试规范
# 测试框架
后端(xUnit):
// UserService.Tests.cs
public class UserServiceTests : IDisposable
{
private readonly Mock<IUserRepository> _mockRepo;
private readonly Mock<ILogger> _mockLogger;
private readonly UserService _userService;
public UserServiceTests()
{
_mockRepo = new Mock<IUserRepository>();
_mockLogger = new Mock<ILogger>();
_userService = new UserService(_mockRepo.Object, _mockLogger.Object);
}
[Fact]
public async Task GetUserById_UserExists_ReturnsSuccess()
{
// Arrange(准备)
var userId = Guid.NewGuid();
var user = new UserEntity
{
Id = userId,
Name = "张三",
Email = "zhangsan@example.com"
};
_mockRepo.Setup(r => r.GetAsync(userId)).ReturnsAsync(user);
// Act(执行)
var result = await _userService.GetUserById(userId);
// Assert(断言)
Assert.True(result.Successful);
Assert.NotNull(result.Data);
Assert.Equal("张三", result.Data.Name);
Assert.Equal(userId, result.Data.Id);
_mockRepo.Verify(r => r.GetAsync(userId), Times.Once);
}
[Fact]
public async Task GetUserById_UserNotExists_ReturnsFailed()
{
// Arrange
var userId = Guid.NewGuid();
_mockRepo.Setup(r => r.GetAsync(userId)).ReturnsAsync((UserEntity)null);
// Act
var result = await _userService.GetUserById(userId);
// Assert
Assert.False(result.Successful);
Assert.Equal("用户不存在", result.Msg);
Assert.Null(result.Data);
}
[Fact]
public async Task CreateUser_NameIsNull_ReturnsFailed()
{
// Arrange
var model = new UserAddModel { Name = null };
// Act
var result = await _userService.CreateUser(model);
// Assert
Assert.False(result.Successful);
Assert.Contains("用户名", result.Msg);
}
public void Dispose()
{
_mockRepo.VerifyAll();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# 测试命名规范
[Fact]
public void 方法名_场景_预期结果()
{
// 示例
[Fact]
public void CreateUser_NameIsNull_ReturnsFailed()
[Fact]
public void GetUserById_UserExists_ReturnsSuccess()
[Fact]
public void DeleteUser_UserNotFound_ThrowsException()
[Theory]
[InlineData(0)]
[InlineData(-1)]
public void ValidateAge_InvalidAge_ReturnsFailed(int age)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 测试覆盖要求
| 模块类型 | 覆盖率要求 | 说明 |
|---|---|---|
| 核心业务 | > 90% | 关键业务逻辑 |
| 一般业务 | > 80% | 普通业务逻辑 |
| 工具类 | > 70% | 工具方法 |
| 简单 CRUD | > 60% | 简单增删改查 |
# 集成测试
// UserApi.Tests.cs
public class UserApiTests : IClassFixture<TestServerFixture>
{
private readonly HttpClient _client;
public UserApiTests(TestServerFixture fixture)
{
_client = fixture.CreateClient();
}
[Fact]
public async Task GetUsers_ReturnsSuccess()
{
// Act
var response = await _client.GetAsync("/api/user");
var content = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<ResultModel>(content);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.True(result.Successful);
}
[Fact]
public async Task CreateUser_InvalidData_ReturnsBadRequest()
{
// Arrange
var user = new { Name = "" };
var content = new StringContent(
JsonConvert.SerializeObject(user),
Encoding.UTF8,
"application/json"
);
// Act
var response = await _client.PostAsync("/api/user", content);
// Assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# E2E 测试
// cypress/e2e/user.cy.js
describe('用户管理', () => {
beforeEach(() => {
cy.login('admin', '******')
cy.visit('/user')
})
it('显示用户列表', () => {
cy.get('.user-table').should('be.visible')
cy.get('.user-row').should('have.length.greaterThan', 0)
})
it('新增用户', () => {
cy.get('.add-user-btn').click()
cy.get('#name').type('测试用户')
cy.get('#email').type('test@example.com')
cy.get('.submit-btn').click()
cy.get('.message-success').should('be.visible')
cy.contains('测试用户').should('be.visible')
})
it('搜索用户', () => {
cy.get('#search-input').type('张三')
cy.get('#search-btn').click()
cy.get('.user-row').each(($row) => {
cy.wrap($row).should('contain', '张三')
})
})
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 📦 版本管理详解
# Semantic Versioning 2.0.0
MAJOR.MINOR.PATCH
↑ ↑ ↑
│ │ └─ 向后兼容的 Bug 修复
│ └─ 向后兼容的功能新增
└─ 不向后兼容的 API 变更
1
2
3
4
5
2
3
4
5
# 版本号规则
| 变更类型 | 版本号变更 | 示例 |
|---|---|---|
| 破坏性变更 | MAJOR + 1 | 1.2.3 → 2.0.0 |
| 向后兼容新功能 | MINOR + 1 | 1.2.3 → 1.3.0 |
| 向后兼容 Bug 修复 | PATCH + 1 | 1.2.3 → 1.2.4 |
| 预发布版本 | 添加后缀 | 1.2.3-beta.1 |
| 构建元数据 | 添加 + 后缀 | 1.2.3+build.123 |
# 版本号示例
1.0.0 # 初始发布
1.0.1 # Bug 修复
1.1.0 # 新增功能
2.0.0 # 破坏性变更
2.0.0-beta.1 # 预发布版本
2.0.0+build.1 # 构建元数据
1
2
3
4
5
6
2
3
4
5
6
# 发布流程详解
# 1. 发布准备
# 创建发布分支
git checkout develop
git pull origin develop
git checkout -b release/v1.2.0
# 更新版本号
# 修改以下文件:
# - Directory.Build.props (后端)
# - package.json (前端)
# - CHANGELOG.md
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 2. 更新 CHANGELOG
# [1.2.0] - 2022-08-07
## ✨ 新增
- 添加用户管理模块 (#123)
- 支持批量导入导出用户 (#124)
- 新增数据字典功能 (#125)
## 🐛 修复
- 修复登录页面样式问题 (#126)
- 修复数据库连接池泄漏 (#127)
- 修复缓存更新不及时 (#128)
## ⚡ 优化
- 优化数据库查询性能(提升 50%)
- 减少前端打包体积(从 5MB 到 3MB)
- 优化图片加载速度
## 🔧 变更
- 升级 .NET 5.0 到 6.0
- 更新 Element-UI 到 2.15.0
- 重构日志模块
## ⚠️ 破坏性变更
- UserRepository 接口变更
- Remove `FindById` method
- Add `GetAsync` method
- API 路径调整
- `/api/user/list` → `/api/user`
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 3. 测试验证
# 运行所有测试
npm test
dotnet test
# 构建
npm run build
dotnet build -c Release
# 本地验证
dotnet run
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 4. 合并发布
# 合并到 master
git checkout master
git pull origin master
git merge --no-ff release/v1.2.0 -m "Release version 1.2.0"
# 打标签
git tag -a v1.2.0 -m "Release version 1.2.0"
# 合并回 develop
git checkout develop
git merge --no-ff release/v1.2.0 -m "Merge release/v1.2.0"
# 删除发布分支
git branch -d release/v1.2.0
# 推送
git push origin master --tags
git push origin develop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 🚀 部署规范详解
# 环境说明
| 环境 | 分支 | 域名 | 用途 | 部署方式 |
|---|---|---|---|---|
| 开发 | feature/* | localhost | 本地开发 | 手动 |
| 测试 | develop | test.example.com | 功能测试 | 自动 |
| 预发布 | release/* | staging.example.com | 上线前验证 | 自动 |
| 生产 | master | example.com | 线上环境 | 手动确认 |
# 部署检查清单
# 部署前检查
- [ ] 代码审查通过
- [ ] 所有测试通过(单元/集成/E2E)
- [ ] 版本号已更新
- [ ] CHANGELOG 已更新
- [ ] 数据库迁移脚本准备
- [ ] 配置文件检查(测试/生产)
- [ ] 回滚方案准备
- [ ] 相关人员通知
# 部署后验证
- [ ] 服务启动正常
- [ ] 健康检查通过(/health)
- [ ] 日志无异常
- [ ] 核心功能验证
- [ ] 性能指标正常
- [ ] 监控告警正常
- [ ] 用户反馈收集
# 部署脚本示例
#!/bin/bash
# deploy.sh
set -e
ENV=$1
VERSION=$2
if [ -z "$ENV" ] || [ -z "$VERSION" ]; then
echo "Usage: ./deploy.sh <env> <version>"
echo " env: test|staging|prod"
exit 1
fi
echo "开始部署到 $ENV 环境,版本:$VERSION"
# 1. 拉取代码
git fetch origin
git checkout $VERSION
# 2. 安装依赖
echo "安装依赖..."
npm install
dotnet restore
# 3. 构建
echo "构建项目..."
npm run build
dotnet publish -c Release -o ./publish
# 4. 备份旧版本
echo "备份旧版本..."
if [ -d "/var/www/app/current" ]; then
cp -r /var/www/app/current /var/www/app/backup-$(date +%Y%m%d-%H%M%S)
fi
# 5. 部署新版本
echo "部署新版本..."
systemctl stop darkm-app
rm -rf /var/www/app/current
cp -r ./publish/* /var/www/app/current/
systemctl start darkm-app
# 6. 健康检查
echo "健康检查..."
sleep 5
curl -f http://localhost:6220/health || exit 1
# 7. 清理
echo "清理..."
rm -rf ./publish
echo "部署完成!"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# 📊 项目管理
# 用户故事模板
# 用户故事
## 故事描述
作为 [角色]
我想要 [功能]
以便于 [价值]
## 验收标准
- [ ] 标准 1
- [ ] 标准 2
- [ ] 标准 3
## 技术备注
- 技术实现要点
- 依赖关系
- 风险评估
## 工作量评估
故事点:__
预计时间:__ 天
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 故事点估算
| 点数 | Fibonacci | 时间参考 | 复杂度 | 示例 |
|---|---|---|---|---|
| 1 | 1 | < 2 小时 | 非常简单 | 修改文案、调整样式 |
| 2 | 2 | 2-4 小时 | 简单 | 添加简单 API 接口 |
| 3 | 3 | 4-8 小时 | 中等 | 新增 CRUD 功能 |
| 5 | 5 | 1-2 天 | 较复杂 | 集成第三方服务 |
| 8 | 8 | 2-3 天 | 复杂 | 重构核心模块 |
| 13 | 13 | > 3 天 | 非常复杂 | 需要拆分 |
# 任务看板
┌─────────────┬─────────────┬─────────────┬─────────────┐
│ To Do │ In Progress│ Testing │ Done │
├─────────────┼─────────────┼─────────────┼─────────────┤
│ 用户列表 │ 用户新增 │ 用户编辑 │ 登录功能 │
│ 用户导出 │ 权限配置 │ │ 角色管理 │
│ │ │ │ 菜单管理 │
└─────────────┴─────────────┴─────────────┴─────────────┘
1
2
3
4
5
6
7
2
3
4
5
6
7
# 🔒 安全规范详解
# OWASP Top 10 防护
# 1. SQL 注入
// ✅ 推荐:参数化查询
var user = await _dbSet.QueryFirstOrDefaultAsync<UserEntity>(
"SELECT * FROM User WHERE UserName = @UserName",
new { UserName = userName }
);
// ❌ 不推荐:SQL 拼接
var sql = $"SELECT * FROM User WHERE UserName = '{userName}'";
var user = await _dbSet.QueryFirstOrDefaultAsync<UserEntity>(sql);
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 2. XSS 攻击
// ✅ 推荐:Vue 自动转义
<template>
<div>{{ userInput }}</div> <!-- 自动转义 -->
</template>
// ❌ 不推荐:直接渲染 HTML
<template>
<div v-html="userInput"></div> <!-- XSS 风险 -->
</template>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 3. CSRF 攻击
// ✅ 推荐:使用 AntiForgery
[ValidateAntiForgeryToken]
[HttpPost]
public async Task<IActionResult> Create(User model)
{
// ...
}
// 前端添加 token
<form method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 4. 敏感信息保护
// ✅ 推荐:使用配置
var apiKey = Configuration.GetValue<string>("ApiKey");
var connectionString = Configuration.GetConnectionString("Default");
// ❌ 不推荐:硬编码
var apiKey = "sk-1234567890abcdef";
var password = "admin123";
1
2
3
4
5
6
7
2
3
4
5
6
7
# 5. 密码安全
// ✅ 推荐:使用 BCrypt
var passwordHash = BCrypt.Net.BCrypt.HashPassword(password, 12);
var isValid = BCrypt.Net.BCrypt.Verify(password, passwordHash);
// ❌ 不推荐:明文或简单哈希
user.Password = password; // 明文
user.Password = MD5(password); // 不安全
1
2
3
4
5
6
7
2
3
4
5
6
7
# 📚 相关文档
最后更新: 2022-08-07