38 KiB
Edu Git 工作流规范
版本:1.3 日期:2026-07-10 状态:v1.3:恢复分支开发模式,AI 不切换分支 适用范围:Edu 多语言 monorepo(pnpm workspace + go.work + pyproject.toml) 关联文档:
目录
- 分支开发
- Conventional Commits 规范
- commitlint + husky 配置
- 事后 Code Review
- 文档同步规则
- 多语言 monorepo 提交规则
- 版本管理
- 紧急回滚
- 附录:CICD 与 Edu Git 工作流差异
一、分支开发
1.1 模式
本项目采用分支开发模式:人类决策者为每个任务/模块创建分支并分配给 AI,AI 只在当前分配的分支上工作,分支的创建、切换、合并均由人类决策者维护。
AI 不允许自行切换/创建/合并分支。AI 禁止执行以下命令:
git checkout -b、git switch(创建/切换分支)git branch(创建分支)git merge(合并分支)git push origin main(推送主干)
核心原则:
main分支始终保持可发布状态,只有人类决策者能向 main 合并- 人类决策者为每个任务/模块创建分支并分配给对应 AI
- AI 只在当前分配的分支上工作,不切换、不创建、不合并分支
- AI 完成提交后通知人类决策者合并,不自行 push main
- 提交前本地通过 lint + typecheck + test + build(见 §3.4 pre-push hook)
- 通过特性开关(Feature Flag)控制未完成功能的暴露
- 代码审查改为事后追溯(见 §4),不在合并前阻塞
- 默认多 AI 协作,每个模块单一负责制
1.2 AI 提交流程
AI 只在当前分配的分支上执行 git add → git commit,完成后通知人类决策者合并,不推送 main。
# 1. 本地校验(强制)
pnpm run lint # TS 服务
pnpm run typecheck # TS 服务
cd services/api-gateway && go vet ./... && go build ./... # Go 服务
ruff check src/ # Python 服务
# 2. 提交(遵循 Conventional Commits,见 §2)
git add <files>
git commit -m "feat(<scope>): <subject>"
# 3. 通知人类决策者合并
# AI 不执行 git push origin main,不创建/切换/合并分支
AI 可执行:
git add、git commit、git status、git log、git diff、git pull(仅同步当前分支)。AI 禁止执行:
git checkout -b、git switch、git branch、git merge、git push origin main、git push --force。
1.3 人类合并流程
人类决策者负责将分支合并到 main,合并时机与策略由人类决策者判断。
# 人类决策者操作(AI 不执行)
# 1. 同步最新 main
git checkout main
git pull origin main
# 2. 合并分支(由人类决策者选择策略)
git merge <branch-name> # 或 git merge --no-ff <branch-name>
# 3. 推送 main(触发 CI 部署)
git push origin main
# 4. (可选)删除已合并分支
git branch -d <branch-name>
合并策略建议:
- 一般任务:
git merge --no-ff(保留分支拓扑,便于追溯) - 紧急修复:
git merge --ff-only(线性历史) - 大特性分支:
git merge --squash(压缩为单 commit)
1.4 冲突处理
- 分支合并冲突:由人类决策者在合并分支到 main 时解决,AI 不参与合并操作
- 架构冲突:由协调 AI 仲裁,通知人类决策者保留方案后合并,通过后续 commit 修正
- 禁止
git push --force到 main:仅协调 AI 在事故时可git push --force-with-lease origin main,需人类决策者确认
1.5 main 分支保护
- 禁止 force push(仅协调 AI 在事故时操作,需人类决策者确认)
- pre-commit / commit-msg / pre-push hook 强制校验(见 §3.4)
- 不要求 PR review,代码质量由本地校验 + 事后 review(§4)+ CI(project_rules §15)保证
- AI 无权直接 push main,所有 main 变更须经人类决策者合并
二、Conventional Commits 规范
2.1 提交信息格式
所有提交信息必须遵循 Conventional Commits 1.0.0:
<type>(<scope>): <subject>
<body>
<footer>
2.2 类型(type)
| 类型 | 含义 | 是否触发发布 |
|---|---|---|
feat |
新功能 | 是(MINOR) |
fix |
Bug 修复 | 是(PATCH) |
perf |
性能优化 | 是(PATCH) |
refactor |
重构(不改变行为) | 否 |
style |
代码风格(格式化、空白) | 否 |
test |
新增/修改测试 | 否 |
docs |
文档变更 | 否 |
build |
构建系统或依赖变更 | 否 |
ci |
CI 配置变更 | 否 |
chore |
杂项(不修改 src 或 test) | 否 |
revert |
回滚某次提交 | 是 |
2.3 范围(scope)
scope 必须是服务名或包名,详见 §3.3 scope-enum。
示例:
feat(identity): 实现用户注册接口fix(gateway): 修复路由匹配优先级perf(teaching): 优化课表查询 N+1 问题docs(contracts): 补充 identity.proto 字段说明
2.4 主题(subject)
规则:
- 使用中文简短描述
- 不超过 50 个字符
- 不以句号结尾
- 使用祈使句("实现用户注册"而非"实现了用户注册")
- 不包含 type/scope(已在前面体现)
2.5 正文(body)
规则:
- 解释"为什么"而非"做了什么"(代码已说明做了什么)
- 每行不超过 72 个字符
- 使用无序列表列出关键变更点
- 涉及 breaking change 必须在正文开头说明
示例:
feat(teaching): 作业提交支持附件上传
- 新增 Attachment 聚合根,支持多文件关联
- Outbox 事件 HomeworkSubmitted 新增 attachments 字段
- BFF 接口新增 multipart/form-data 支持
BREAKING CHANGE: HomeworkSubmitted 事件 schema 变更,
消费方需升级 proto 至 v2 才能消费新事件
2.6 脚注(footer)
用于关联 Issue、PR、Jira 卡片:
fix(content): 修复题库导入时重复题目标题去重逻辑
Closes #123
Refs EDU-456
Reviewed-by: @reviewer-name
三、commitlint + husky 配置
3.1 安装与初始化
# 在 monorepo 根目录
pnpm add -Dw @commitlint/cli @commitlint/config-conventional husky lint-staged
# 初始化 husky
pnpm exec husky init
3.2 commitlint 配置
实际生效配置文件:仓库根 .commitlintrc.js(CommonJS)。
/** @type {import('@commitlint/types').UserConfig} */
module.exports = {
extends: ["@commitlint/config-conventional"],
rules: {
// type 枚举
"type-enum": [
2,
"always",
[
"feat",
"fix",
"perf",
"refactor",
"style",
"test",
"docs",
"build",
"ci",
"chore",
"revert",
],
],
// type 小写
"type-case": [2, "always", "lower-case"],
// type 不能为空
"type-empty": [2, "never"],
// scope 枚举(见 3.3,与 .commitlintrc.js 保持同步)
"scope-enum": [
2,
"always",
[
// 网关层(Go)
"api-gateway",
"push-gateway",
// 业务微服务(NestJS / FastAPI)
"iam",
"core-edu",
"classes",
"content",
"data-ana",
"msg",
"ai",
// BFF 聚合层(NestJS)
"teacher-bff",
"student-bff",
"parent-bff",
// 微前端(Next.js)
"teacher-portal",
"student-portal",
"parent-portal",
"admin-portal",
// 共享包(packages/)
"shared-proto",
"shared-ts",
"shared-go",
"shared-py",
"shared-tokens",
// 工具与平台级
"arch-scan",
"infra",
"docs",
"deps",
"release",
],
],
// scope 小写
"scope-case": [2, "always", "lower-case"],
// subject 不能为空
"subject-empty": [2, "never"],
// subject 不超过 50 字符
"subject-max-length": [2, "always", 72],
// subject 不以句号结尾
"subject-full-stop": [2, "never", "."],
// body 每行不超过 100 字符
"body-max-line-length": [1, "always", 100],
// footer 每行不超过 100 字符
"footer-max-line-length": [1, "always", 100],
// header 不超过 100 字符
"header-max-length": [2, "always", 100],
},
};
单一事实源:实际生效的配置在仓库根
.commitlintrc.js,本节示例仅作说明。修改 scope 必须同步更新.commitlintrc.js与本节,并在提交时说明原因。
3.3 scope-enum 完整清单
与仓库根
.commitlintrc.js保持同步;修改 scope 必须同时更新此处与.commitlintrc.js。
| 分类 | scope | 对应目录 | 说明 |
|---|---|---|---|
| 网关层 | api-gateway |
services/api-gateway/ |
API 网关(Go + Gin) |
| 网关层 | push-gateway |
services/push-gateway/ |
WebSocket 推送网关(Go) |
| 业务微服务 | iam |
services/iam/ |
身份与访问管理(NestJS) |
| 业务微服务 | core-edu |
services/core-edu/ |
教学核心服务(NestJS,Outbox + Kafka) |
| 业务微服务 | classes |
services/classes/ |
班级服务(P1 黄金模板,P3 并入 core-edu) |
| 业务微服务 | content |
services/content/ |
内容资源服务(NestJS + Neo4j) |
| 业务微服务 | data-ana |
services/data-ana/ |
数据分析服务(Python + FastAPI + ClickHouse) |
| 业务微服务 | msg |
services/msg/ |
消息通知服务(NestJS + ES) |
| 业务微服务 | ai |
services/ai/ |
AI 网关服务(Python + FastAPI + LLM) |
| BFF 聚合层 | teacher-bff |
services/teacher-bff/ |
教师端 BFF(NestJS) |
| BFF 聚合层 | student-bff |
services/student-bff/ |
学生端 BFF(待建立) |
| BFF 聚合层 | parent-bff |
services/parent-bff/ |
家长端 BFF(待建立) |
| 微前端 | teacher-portal |
apps/teacher-portal/ |
教师端 Portal(Next.js) |
| 微前端 | student-portal |
apps/student-portal/ |
学生端 Portal(待建立) |
| 微前端 | parent-portal |
apps/parent-portal/ |
家长端 Portal(待建立) |
| 微前端 | admin-portal |
apps/admin-portal/ |
管理端 Portal(待建立) |
| 共享包 | shared-proto |
packages/shared-proto/ |
protobuf 契约定义 |
| 共享包 | shared-ts |
packages/shared-ts/ |
TS 共享类型与工具(待建立) |
| 共享包 | shared-go |
packages/shared-go/ |
Go 共享工具(待建立) |
| 共享包 | shared-py |
packages/shared-py/ |
Python 共享工具(待建立) |
| 共享包 | shared-tokens |
packages/shared-tokens/ |
设计令牌(待建立) |
| 工具 | arch-scan |
scripts/arch-scan/ |
架构元数据库扫描器 |
| 平台级 | infra |
infra/ |
基础设施(K8s / docker-compose / backup / monitoring) |
| 平台级 | docs |
docs/ |
平台级文档(跨多模块) |
| 平台级 | deps |
- | 依赖升级 |
| 平台级 | release |
- | 发布相关 |
chore/ci/build等 Conventional Commits 标准 type 不需要 scope,可直接使用chore: xxx、ci: xxx。
3.4 husky hooks
实际生效的 hook 文件在仓库根 .husky/ 目录。使用 npx --no-install 确保使用本地依赖。
.husky/commit-msg:
npx --no-install commitlint --edit $1
.husky/pre-commit:
npx --no-install lint-staged
.husky/pre-push(推送前类型检查,TS 服务 typecheck 通过后才允许推送):
#!/usr/bin/env sh
# 推送前运行类型检查(TS 服务)
pnpm -r run typecheck 2>/dev/null || echo "[pre-push] typecheck 跳过或不可用"
# Go 服务编译检查
for d in services/api-gateway services/push-gateway; do
if [ -d "$d" ]; then (cd "$d" && go build ./... ) || exit 1; fi
done
注意:
pre-push中的 typecheck 在 TS 服务 ESLint 9 flat config 迁移完成前为可选(当前pnpm -r run typecheck缺失脚本,会 fallback 到 echo 提示)。Gogo build检查必须通过。
3.5 lint-staged 配置
实际生效配置文件:仓库根 lint-staged.config.js(CommonJS)。
module.exports = {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{go,mod,sum}": ["gofmt -w", "golangci-lint run --fix"],
"*.{py}": ["ruff check --fix", "ruff format"],
"*.proto": ["buf format --write"],
"*.md": ["prettier --write"],
};
JSON / YAML 文件由 prettier 在
*.md规则外按全局配置处理,如需显式规则可在lint-staged.config.js追加'*.{json,yaml,yml}': ['prettier --write']。
四、事后 Code Review
不再使用 PR 流程,代码审查改为事后追溯:AI 在分支上提交后通知人类决策者合并,人类决策者合并到 main 后由模块 owner 或协调 AI 通过分支 commit history 进行 review。问题通过后续 commit 修正或
git revert回滚。
4.1 事后 Review 流程
flowchart TD
A[开发 AI 本地校验] --> B[分支上 git add + git commit]
B --> C[通知人类决策者合并]
C --> D[人类决策者合并到 main]
D --> E[CI 自动检查]
E --> F{CI 通过?}
F -->|否| G[人类 git revert + 修复后重新合并]
F -->|是| H[模块 owner 事后审查分支 commit]
H --> I{审查通过?}
I -->|有问题| J[后续 commit 修正或 revert]
I -->|通过| K[review 完成]
review 依据:
- commit message(Conventional Commits 格式,见 §2)
- 分支 commit history(通过
git log或平台分支/合并视图追溯) - commit diff(通过
git log -p或平台 commit 视图)
4.2 Code Review 清单
事后 review 时检查:
通用检查:
- 代码是否符合 编码规范
- 是否有明显的逻辑错误
- 错误处理是否完整(不忽略 error/err/exception)
- 日志是否包含足够的上下文(request_id、user_id 等)
- 是否存在硬编码的密钥、token、连接字符串
架构检查:
- 是否违反限界上下文边界(跨服务直接查 DB)
- 是否违反依赖方向(shared 反向依赖 services)
- protobuf 变更是否向后兼容
- 事件 schema 变更是否向后兼容
性能检查:
- 是否有 N+1 查询
- 是否有未加索引的查询
- 是否有不必要的大对象拷贝
- 是否有阻塞事件循环的同步操作(Python/Node)
安全检查:
- 所有入口是否经过权限校验
- 用户输入是否经过验证
- SQL 是否使用参数化查询
- 是否有 SQL 注入、XSS、SSRF 风险
4.3 模块 Owner 与 CODEOWNERS
实际生效文件:仓库根 .github/CODEOWNERS。
不再用于自动分配 PR reviewer(无 PR 流程),CODEOWNERS 保留作为模块归属追溯依据:分支合并涉及某路径时,对应 owner 负责事后 review。
设计原则:
- 每个模块至少 1 名 owner,核心模块 2 名
- 跨模块变更(如 proto 契约、arch.db、project_rules)由架构组事后 review
- 基础设施变更(K8s/Helm/backup)由 SRE 事后 review
- owner 名单变更通过分支提交更新,由架构组确认后人类决策者合并
模块 Owner 分配矩阵:
| 模块分类 | 路径 | Owner Team | 备注 |
|---|---|---|---|
| 架构与规则 | .trae/rules/、docs/architecture/、docs/standards/ |
@edu-platform/arch |
架构组强制 review |
| 架构工具 | scripts/arch-scan/ |
@edu-platform/arch |
|
| 根配置 | .commitlintrc.js、lint-staged.config.js、package.json、pnpm-workspace.yaml、go.work、pyproject.toml、tsconfig.base.json |
@edu-platform/arch |
影响全局 |
| 共享包 | packages/shared-proto/ |
@edu-platform/arch |
契约变更影响所有服务 |
| 网关层 | services/api-gateway/、services/push-gateway/ |
@edu-platform/gateway |
|
| IAM 服务 | services/iam/ |
@edu-platform/iam |
核心模块 |
| 教学核心 | services/core-edu/、services/classes/ |
@edu-platform/edu-core |
|
| 内容资源 | services/content/ |
@edu-platform/content |
|
| 消息通知 | services/msg/ |
@edu-platform/messaging |
|
| 数据分析 | services/data-ana/ |
@edu-platform/data |
|
| AI 服务 | services/ai/ |
@edu-platform/ai |
|
| BFF 层 | services/teacher-bff/、services/student-bff/、services/parent-bff/ |
@edu-platform/edu-core |
|
| 微前端 | apps/teacher-portal/、apps/student-portal/、apps/parent-portal/、apps/admin-portal/ |
@edu-platform/frontend |
|
| 基础设施 | infra/k8s/、infra/backup/、infra/security/、infra/monitoring/ |
@edu-platform/sre |
生产环境变更 |
| CI/CD | .github/、.husky/ |
@edu-platform/sre |
|
| 文档 | docs/troubleshooting/、docs/standards/ |
@edu-platform/arch |
known-issues 更新 |
Team handle 占位符:上表
@edu-platform/*为 team handle 模板。实际团队 handle 需在 GitHub/Gitea Organization 中创建对应 team 后,同步更新.github/CODEOWNERS。
CODEOWNERS 文件维护规则:
- 新增服务/包时,必须同步更新
.github/CODEOWNERS - owner 变更(人员调动)由架构组确认后通过分支提交更新
- CODEOWNERS 与本节表格保持同步,单一事实源为
.github/CODEOWNERS文件
五、文档同步规则
5.1 文档同步矩阵
| 代码变更类型 | 需同步的文档 | 同步时机 |
|---|---|---|
| 新增/删除服务 | 001_architecture_overview.md + 服务 README |
分支内同步 |
| 新增/删除模块 | 服务 README + arch:scan |
分支内同步 |
| 新增/删除导出函数 | pnpm run arch:scan |
提交前 |
| 修改函数签名 | pnpm run arch:scan |
提交前 |
| 修改权限点 | project_rules.md + 权限文档 |
分支内同步 |
| 新增/删除数据库表 | 架构文档 + 服务 README | 分支内同步 |
| 新增/删除路由 | 服务 README + OpenAPI | 分支内同步 |
| 修改模块间依赖 | arch:scan + 架构文档 |
分支内同步 |
| 新增 protobuf message | proto/ README + arch:scan |
分支内同步 |
| 新增 Kafka topic | 架构文档 + 服务 README | 分支内同步 |
| 遇到新问题/经验 | known-issues.md |
分支内同步 |
5.2 arch.db 同步规则
强制规则:任何代码变更提交前必须运行 pnpm run arch:scan 更新 arch.db。
# 提交前流程
pnpm run arch:scan # 更新 arch.db
pnpm run arch:query -- violations # 检查是否有违规
git add arch.db # 将 arch.db 纳入提交
git commit -m "feat(identity): 实现用户注册接口"
违规检查:
- 长文件(> 1000 行)
- 未校验权限的 Handler
- 循环依赖
- 跨限界上下文直接 DB 访问
5.3 服务 README 要求
每个服务必须包含 README.md,结构如下:
# [服务名] 服务
> 版本:1.0
> 限界上下文:[上下文名]
> 技术栈:[语言 + 框架]
## 职责
[一段话描述]
## 架构
[mermaid 架构图]
## 核心流程
[mermaid 时序图]
## 目录结构
[树形结构 + 说明]
## 依赖
- 上游服务:[列表]
- 下游服务:[列表]
- 共享包:[列表]
## 约束
[业务规则、技术约束]
## 架构决策
[关键设计决策记录]
5.4 known-issues.md 格式
docs/troubleshooting/known-issues.md 采用索引式速查手册格式:
### X.X 主题分区
| 场景 | 技术/规则 |
| -------- | ------------------ |
| 简述场景 | 正确做法(一句话) |
规则:
- 索引式:场景→技术/规则映射
- 不写代码示例和错误示范
- 同类问题在原条目补充,不重复创建
- 不设"工作经验日志"区:模块内经验沉淀在各自服务 README,known-issues 只保留索引式场景→技术映射(见 project_rules §9)
- 经验沉淀不标注 AI 身份:AI 只做经验沉淀(场景→技术映射),不记录工作日志,不标注 AI 身份
六、多语言 monorepo 提交规则
6.1 单服务单提交原则
规则:一个 commit 只涉及一个服务或一个包的变更。
原因:
- 便于回滚(按服务粒度回滚)
- 便于追踪(changelog 清晰)
- 便于 review(聚焦单一职责)
例外:跨服务重构或契约变更可在同一 commit 中涉及多个服务,但需在 body 中说明。
6.2 生成代码单独提交
规则:protobuf 生成的代码必须与手写代码分开提交。
# 正确流程
# 1. 修改 proto 定义
git commit -m "feat(proto): 新增 UserRegistered 事件 schema"
# 2. 生成代码
pnpm run proto:generate
# 3. 单独提交生成代码
git commit -m "build(contracts): 重新生成 proto 代码"
6.3 跨语言变更拆分
当一个功能涉及多个语言(如 TS 服务 + Go 网关 + Python AI),按以下顺序拆分提交:
- 契约先行:
feat(proto): ... - 生成代码:
build(contracts): ... - 后端服务:
feat(teaching): ... - 网关层:
feat(gateway): ... - 前端:
feat(teacher-shell): ...
6.4 依赖升级规则
规则:
- 依赖升级使用
build(deps):类型 - 必须说明升级原因(安全、功能、兼容性)
- 安全漏洞修复必须包含 CVE 编号
- 大版本升级需单独分支并完整测试
示例:
build(deps): 升级 nestjs 至 10.3.0
- 修复 CVE-2024-1234 漏洞
- 升级至最新 patch 版本
- 全部测试通过
6.5 跨服务依赖更新
当一个服务的 protobuf 变更影响其他服务:
# 1. 提交 proto 变更
git commit -m "feat(proto): UserRegistered 事件新增 attachments 字段"
# 2. 生成新契约
pnpm run proto:generate
git commit -m "build(contracts): 生成 UserRegistered v2"
# 3. 更新消费方服务
git commit -m "feat(notification): 适配 UserRegistered v2 事件"
七、版本管理
不使用 tag 发布与 release 分支(见 project_rules §15.3 no-push 模式)。版本通过 commit SHA 追溯,发布由人类决策者合并分支到 main 后触发 CI 自动部署。
7.1 版本号体系
本项目采用双层版本号(仅作记录与沟通用,不通过 git tag 标记):
| 层级 | 格式 | 说明 |
|---|---|---|
| 平台版本 | v{阶段}.{迭代}.{patch} |
如 v0.3.1(P3 阶段第 1 次迭代 patch 1) |
| 服务版本 | {service}:{semver} |
如 identity:1.2.0 |
7.2 阶段版本范围
| 阶段 | 平台版本范围 | 说明 |
|---|---|---|
| P1 地基 | v0.1.x |
monorepo 初始化、CI/CD、arch.db |
| P2 身份 | v0.2.x |
identity + auth + notification |
| P3 核心教学 | v0.3.x |
org + teaching + content |
| P4 内容分析 | v0.4.x |
insight + CQRS 读模型 |
| P5 沟通AI | v0.5.x |
comm + AI 增强 |
| P6 硬化 | v1.0.x |
正式发布版 |
7.3 Docker 镜像标签
no-push 模式下镜像不推 registry,本地构建本地使用(见 project_rules §15.4)。下表标签格式仅用于本地镜像管理。
格式:{registry}/edu/{service}:{tag}
| tag 类型 | 格式 | 示例 | 用途 |
|---|---|---|---|
| Git SHA | sha-{short} |
sha-a1b2c3d |
精确追溯 |
| 最新 | latest |
latest |
开发环境 |
| 服务版本 | {service}-{semver} |
identity-1.2.0 |
服务独立版本 |
7.4 发布流程
flowchart TD
A[开发 AI 本地校验通过] --> B[分支上 git add + git commit]
B --> C[通知人类决策者合并]
C --> D[人类决策者合并到 main]
D --> E[CI 自动触发 quality + deploy]
E --> F{CI 通过?}
F -->|否| G[人类 git revert + 修复后重新合并]
G --> D
F -->|是| H[部署至目标环境]
H --> I[健康检查轮询 /healthz]
I --> J{健康?}
J -->|否| K[输出容器日志 + 紧急回滚 §8]
J -->|是| L[发布完成]
L --> M[更新 CHANGELOG.md]
不创建 release 分支、不打 git tag。发布点通过 commit SHA 追溯,回滚通过
git revert或workflow_dispatch指定commit_sha(见 project_rules §15.4)。
7.5 CHANGELOG 格式
CHANGELOG.md 按 Keep a Changelog 格式维护,版本号对应阶段迭代(不绑定 git tag):
## [v0.3.0] - 2026-08-15
### Added
- 教学核心服务新增作业管理功能
- 内容服务支持题库导入
- 教师端 Shell 新增作业批改界面
### Changed
- identity 服务升级至 NestJS 10.3
- gateway 路由匹配算法优化
### Fixed
- 修复 JWT 刷新 token 过期判断错误
- 修复课表查询时区问题
### Breaking Changes
- UserRegistered 事件 schema 变更至 v2,消费方需升级
7.6 服务独立版本
每个服务维护独立的 VERSION 文件,内容为 semver:
# services/identity/VERSION
1.2.0
版本号升级规则:
- MAJOR:Breaking Change(protobuf 不兼容变更、API 破坏性修改)
- MINOR:新增功能,向后兼容
- PATCH:Bug 修复,向后兼容
八、紧急回滚
8.1 回滚策略
| 场景 | 回滚方式 | 耗时 |
|---|---|---|
| 代码缺陷 | 人类在 main 上 git revert + push 触发 CI 重新部署 |
5-10 分钟 |
| 镜像问题 | kubectl rollout undo |
1-2 分钟 |
| 数据库迁移问题 | 执行迁移 down 脚本 | 5-30 分钟 |
| 配置错误 | 回滚 ConfigMap/Secret | 1-2 分钟 |
| 全站故障 | workflow_dispatch 指定稳定 commit_sha |
10-30 分钟 |
8.2 代码回滚
不创建 hotfix 分支。由人类决策者在 main 上
git revert后 push,CI 自动重新部署。AI 不参与 main 上的回滚推送操作。
# 人类决策者操作(AI 不执行 push main)
# 1. 确认要回滚的 commit
git log --oneline -10
# 2. 切换到 main 并拉取最新
git checkout main
git pull origin main
# 3. 回滚指定 commit(生成反向 commit)
git revert <commit-sha>
# 4. push main(CI 自动触发重新部署)
git push origin main
修复型回滚也可通过新分支提交修复后由人类决策者合并,具体方式由人类决策者判断。
8.3 K8s 部署回滚
# 查看部署历史
kubectl rollout history deployment/identity -n edu-prod
# 回滚至上一版本
kubectl rollout undo deployment/identity -n edu-prod
# 回滚至指定版本
kubectl rollout undo deployment/identity -n edu-prod --to-revision=3
# 监控回滚状态
kubectl rollout status deployment/identity -n edu-prod
8.4 数据库迁移回滚
规则:
- 所有迁移必须提供
up和down脚本 down脚本必须在 CI 中测试- 回滚前必须备份生产数据
# 回滚最近一次迁移
pnpm --filter identity run migrate:down
# 回滚至指定版本
pnpm --filter identity run migrate:down -- --to <version>
8.5 回滚原则
- 优先保证可用性:回滚决策应在 5 分钟内做出,无需 root cause
- 保留现场:回滚前保存日志、metrics、错误堆栈
- 通知相关方:回滚后立即通知运维、产品、相关开发
- 复盘改进:回滚后 24 小时内完成事故复盘,记录至
docs/troubleshooting/incidents/
8.6 回滚记录格式
docs/troubleshooting/incidents/YYYY-MM-DD-incident.md:
# 事故记录:[简述]
> 日期:YYYY-MM-DD
> 影响范围:[服务/用户]
> 持续时间:[开始-结束]
> 严重等级:P0/P1/P2/P3
## 时间线
- HH:MM 告警触发
- HH:MM 确认问题
- HH:MM 决定回滚
- HH:MM 回滚完成
- HH:MM 服务恢复
## 影响分析
[受影响的功能、用户数、业务损失]
## 根本原因
[技术原因 + 流程原因]
## 回滚过程
[执行的操作]
## 改进措施
- [ ] 短期:[立即修复项]
- [ ] 中期:[流程改进项]
- [ ] 长期:[架构改进项]
九、附录:CICD 与 Edu Git 工作流差异
| 维度 | CICD(Next.js 单应用) | Edu(微服务 monorepo) |
|---|---|---|
| 仓库结构 | 单一 Next.js 应用 | 多语言 monorepo(pnpm + go.work + uv) |
| 分支策略 | trunk-based | 分支开发,AI 不切换分支,人类维护 |
| 提交规范 | Conventional Commits | Conventional Commits(沿用,scope 扩展至服务/包) |
| scope 范围 | 模块名(如 exams、homework) |
服务/包名(如 iam、api-gateway、shared-proto) |
| commitlint scope-enum | 35 个模块 | 26 个 scope(含服务/包/工具/平台级,与 .commitlintrc.js 同步) |
| 代码审查 | PR Reviewer 1 人 | 事后 review(无 PR,通过分支 commit history 追溯) |
| 合并策略 | Squash Merge | 人类决策者手动合并分支到 main(AI 不合并) |
| 版本号 | 单一应用版本 | 双层(平台版本 + 服务独立版本,仅记录不打 tag) |
| 发布粒度 | 整体发布 | 按服务独立发布 |
| Docker 镜像 | 单一镜像 | 每服务一镜像(no-push 本地构建,见 project_rules §15) |
| 回滚粒度 | 整体回滚 | 按服务回滚 |
| 数据库迁移 | Drizzle 单库 | 每服务独立库 + 独立迁移 |
| 文档同步 | npm run arch:scan |
pnpm run arch:scan(多语言扫描) |
| CI 检查 | lint + tsc + test | lint + typecheck + test(按语言分别执行) |
| 紧急回滚 | git revert + 重新部署 |
人类在 main 上 git revert + push 触发 CI,或 workflow_dispatch 指定 SHA |
| 事故复盘 | known-issues.md | incidents/ 目录独立记录 |
变更记录
| 版本 | 日期 | 变更内容 |
|---|---|---|
| 1.0 | 2026-07-07 | 基线发布,从 CICD 单应用规范迁移至微服务多语言 monorepo |
| 1.1 | 2026-07-08 | scope-enum 对齐实际服务名(identity→iam、teaching→core-edu 等);新增 §4.7 模块 Owner 与 CODEOWNERS;husky hooks 与实际文件对齐;新增 pre-push hook 说明 |
| 1.2 | 2026-07-10 | 因 Gitea 问题移除分支/PR 流程:§1 改为直接 push main(移除特性/发布/hotfix 分支命名与保护);§4 改为事后 Code Review(移除 PR 流程/标题/模板/合并策略,保留 Code Review 清单与 CODEOWNERS 追溯);§7 改为版本管理(移除 release 分支与 tag 发布,用 commit SHA 追溯);§8 移除 hotfix 分支回滚,改为直接 git revert + push main;§9 更新差异表 |
| 1.3 | 2026-07-10 | 恢复分支开发模式(AI 不切换分支):§1 改为分支开发(人类决策者维护分支,AI 禁止 git checkout -b/git switch/git branch/git merge/git push origin main,AI 只做 git add→git commit→通知人类合并);§4 review 依据改为分支 commit history,移除 AI 身份标注;§8 回滚由人类在 main 上 git revert,不使用 hotfix 分支;§9 分支策略改为"分支开发,AI 不切换分支,人类维护";§5.4 经验沉淀不标注 AI 身份 |