Files
Edu/docs/standards/git-workflow.md
SpecialX b39095cbdd docs: git-workflow v1.1 与 CODEOWNERS 规范
- git-workflow.md v1.1: scope-enum 对齐实际服务名(identity→iam 等)
- git-workflow.md: 新增 §4.7 模块 Owner 与 CODEOWNERS 章节
- git-workflow.md: husky hooks 与实际文件对齐,新增 pre-push 说明
- .github/CODEOWNERS: 定义各模块 owner team 与 PR 合并职责
- .github/pull_request_template.md: PR 模板
2026-07-08 12:53:18 +08:00

36 KiB
Raw Blame History

Edu Git 工作流规范

版本1.1 日期2026-07-08 状态基线发布v1.1scope-enum 对齐 + CODEOWNERS 适用范围Edu 多语言 monorepopnpm workspace + go.work + pyproject.toml 关联文档:


目录

  1. 分支策略
  2. Conventional Commits 规范
  3. commitlint + husky 配置
  4. PR 与 Code Review
  5. 文档同步规则
  6. 多语言 monorepo 提交规则
  7. 版本与发布
  8. 紧急回滚
  9. 附录CICD 与 Edu Git 工作流差异

一、分支策略

1.1 主干开发Trunk-Based Development

本项目采用主干开发模式,所有变更最终合并至 main 分支。

核心原则

  • main 分支始终保持可发布状态
  • 短生命周期特性分支(通常 ≤ 3 天)
  • 频繁集成,每天至少一次 rebase/merge 至最新 main
  • 通过特性开关Feature Flag控制未完成功能的暴露

1.2 分支模型

gitGraph
    commit id: "init"
    commit id: "P1-foundation"
    branch feat/identity-service
    checkout feat/identity-service
    commit id: "scaffold"
    commit id: "implement-login"
    commit id: "add-tests"
    checkout main
    merge feat/identity-service tag: "v0.2.0"
    branch fix/jwt-expiry
    checkout fix/jwt-expiry
    commit id: "fix-token-refresh"
    checkout main
    merge fix/jwt-expiry tag: "v0.2.1"
    branch release/v0.3
    checkout release/v0.3
    commit id: "freeze"
    commit id: "hotfix"
    checkout main
    merge release/v0.3 tag: "v0.3.0"

1.3 分支命名规范

分支类型 前缀 示例 生命周期
主干 main main 永久
特性 feat/ feat/identity-service ≤ 3 天
修复 fix/ fix/jwt-expiry ≤ 1 天
重构 refactor/ refactor/split-data-access ≤ 5 天
性能 perf/ perf/query-optimization ≤ 3 天
文档 docs/ docs/api-specification ≤ 2 天
发布 release/v release/v0.3.0 发布周期内
热修复 hotfix/ hotfix/v0.3.1 ≤ 1 天

规则

  • 分支名使用 kebab-case
  • 一个分支只做一件事,禁止在一个分支内混合多个无关变更
  • 特性分支命名包含服务/模块名(feat/identity-service 而非 feat/login

1.4 分支保护规则

main 分支保护

  • 禁止直接 push必须通过 PR
  • 至少 1 名 Reviewer 审批通过(核心模块需 2 名)
  • 所有 CI 检查通过lint + typecheck + test + build
  • 分支必须与 main 保持最新(无冲突或已 rebase
  • 禁止 force push

release/* 分支保护

  • 禁止直接 push仅接受 cherry-pick 或特定 hotfix PR
  • 至少 2 名 Reviewer 审批
  • 发布完成后打 tag 并归档

二、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.jsCommonJS

/** @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 与本节,并在 PR 中说明原因。

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/ 教学核心服务NestJSOutbox + 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/ 教师端 BFFNestJS
BFF 聚合层 student-bff services/student-bff/ 学生端 BFF待建立
BFF 聚合层 parent-bff services/parent-bff/ 家长端 BFF待建立
微前端 teacher-portal apps/teacher-portal/ 教师端 PortalNext.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: xxxci: 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 提示。Go go build 检查必须通过。

3.5 lint-staged 配置

实际生效配置文件:仓库根 lint-staged.config.jsCommonJS

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']


四、PR 与 Code Review

4.1 PR 流程

flowchart TD
    A[开发者创建特性分支] --> B[提交代码]
    B --> C[本地通过 lint + typecheck + test]
    C --> D[rebase 至最新 main]
    D --> E[推送至远程]
    E --> F[创建 PR]
    F --> G[CI 自动检查]
    G --> H{CI 通过?}
    H -->|否| I[修复问题]
    I --> B
    H -->|是| J[Reviewer 审查]
    J --> K{审查通过?}
    K -->|需修改| L[根据反馈修改]
    L --> B
    K -->|通过| M[Squash Merge]
    M --> N[删除特性分支]
    N --> O[CI 部署至 staging]

4.2 PR 标题

PR 标题必须符合 Conventional Commits 规范(与最终 squash merge 的 commit message 一致):

feat(identity): 实现用户注册接口

4.3 PR 模板

.github/pull_request_template.md(或 Gitea 等价路径):

## 变更说明

<!-- 简述本次变更的目的和实现方式 -->

## 变更类型

- [ ] feat: 新功能
- [ ] fix: Bug 修复
- [ ] perf: 性能优化
- [ ] refactor: 重构
- [ ] test: 测试
- [ ] docs: 文档
- [ ] build/ci: 构建/CI

## 影响范围

<!-- 列出受影响的服务/包 -->

- 服务:
- 包:
- 数据库迁移:是 / 否
- protobuf 契约变更:是 / 否
- Kafka topic 变更:是 / 否

## 测试情况

- [ ] 单元测试通过
- [ ] 集成测试通过
- [ ] 本地手动测试通过
- [ ] 新增测试覆盖新功能

## 文档同步

- [ ] 已更新服务 README如涉及服务结构变更
- [ ] 已更新架构文档(如涉及架构变更)
- [ ] 已运行 `pnpm run arch:scan` 更新 arch.db
- [ ] 已更新 known-issues.md如遇到新问题

## Breaking Change

- [ ]- [ ] 是(请在下方说明影响和迁移路径)

## 关联 Issue

Closes #

4.4 Reviewer 要求

变更类型 最少 Reviewer 备注
普通业务变更 1 默认
跨服务变更 2 涉及 ≥ 2 个服务
protobuf 契约变更 2 需包含架构组成员
数据库 schema 变更 2 需包含 DBA 或架构组
安全相关变更 2 需包含安全负责人
核心模块auth/identity 2 核心模块强制 2 人

4.5 Code Review 清单

通用检查

  • 代码是否符合 编码规范
  • 是否有明显的逻辑错误
  • 错误处理是否完整(不忽略 error/err/exception
  • 日志是否包含足够的上下文request_id、user_id 等)
  • 是否存在硬编码的密钥、token、连接字符串

架构检查

  • 是否违反限界上下文边界(跨服务直接查 DB
  • 是否违反依赖方向shared 反向依赖 services
  • protobuf 变更是否向后兼容
  • 事件 schema 变更是否向后兼容

性能检查

  • 是否有 N+1 查询
  • 是否有未加索引的查询
  • 是否有不必要的大对象拷贝
  • 是否有阻塞事件循环的同步操作Python/Node

安全检查

  • 所有入口是否经过权限校验
  • 用户输入是否经过验证
  • SQL 是否使用参数化查询
  • 是否有 SQL 注入、XSS、SSRF 风险

4.6 合并策略

默认使用 Squash Merge

  • 保留 PR 的完整变更作为一个 commit
  • commit message 使用 PR 标题
  • 删除特性分支

禁止使用 Merge Commit(除非是发布分支合并回 main

  • 避免历史中充斥 "Merge branch" 噪音
  • 保持线性历史

Rebase Merge

  • 仅用于需要保留多个有意义 commit 的特性分支
  • 需在 PR 中说明原因

4.7 模块 Owner 与 CODEOWNERS

实际生效文件:仓库根 .github/CODEOWNERSGitHub/Gitea 原生支持,自动为 PR 分配 reviewer

设计原则

  • 每个模块至少 1 名 owner核心模块 2 名
  • 跨模块变更(如 proto 契约、arch.db、project_rules由架构组 review
  • 基础设施变更K8s/Helm/backup由 SRE review
  • owner 名单变更需走 PR由架构组审批

模块 Owner 分配矩阵

模块分类 路径 Owner Team 最少 Reviewer 备注
架构与规则 .trae/rules/docs/architecture/docs/standards/ @edu-platform/arch 2 架构组强制 review
架构工具 scripts/arch-scan/ @edu-platform/arch 1
根配置 .commitlintrc.jslint-staged.config.jspackage.jsonpnpm-workspace.yamlgo.workpyproject.tomltsconfig.base.json @edu-platform/arch 2 影响全局
共享包 packages/shared-proto/ @edu-platform/arch 2 契约变更影响所有服务
网关层 services/api-gateway/services/push-gateway/ @edu-platform/gateway 1
IAM 服务 services/iam/ @edu-platform/iam 2 核心模块强制 2 人
教学核心 services/core-edu/services/classes/ @edu-platform/edu-core 1
内容资源 services/content/ @edu-platform/content 1
消息通知 services/msg/ @edu-platform/messaging 1
数据分析 services/data-ana/ @edu-platform/data 1
AI 服务 services/ai/ @edu-platform/ai 1
BFF 层 services/teacher-bff/services/student-bff/services/parent-bff/ @edu-platform/edu-core 1
微前端 apps/teacher-portal/apps/student-portal/apps/parent-portal/apps/admin-portal/ @edu-platform/frontend 1
基础设施 infra/k8s/infra/backup/infra/security/infra/monitoring/ @edu-platform/sre 2 生产环境变更强制 2 人
CI/CD .github/.husky/ @edu-platform/sre 1
文档 docs/troubleshooting/docs/standards/ @edu-platform/arch 1 known-issues 更新

Team handle 占位符:上表 @edu-platform/* 为 team handle 模板。实际团队 handle 需在 GitHub/Gitea Organization 中创建对应 team 后,同步更新 .github/CODEOWNERS

CODEOWNERS 文件维护规则

  1. 新增服务/包时,必须在同一 PR 中更新 .github/CODEOWNERS
  2. owner 变更(人员调动)需开独立 PR由架构组审批
  3. CODEOWNERS 与本节表格保持同步,单一事实源为 .github/CODEOWNERS 文件

五、文档同步规则

5.1 文档同步矩阵

代码变更类型 需同步的文档 同步时机
新增/删除服务 001_architecture_overview.md + 服务 README PR 内同步
新增/删除模块 服务 README + arch:scan PR 内同步
新增/删除导出函数 pnpm run arch:scan 提交前
修改函数签名 pnpm run arch:scan 提交前
修改权限点 project_rules.md + 权限文档 PR 内同步
新增/删除数据库表 架构文档 + 服务 README PR 内同步
新增/删除路由 服务 README + OpenAPI PR 内同步
修改模块间依赖 arch:scan + 架构文档 PR 内同步
新增 protobuf message proto/ README + arch:scan PR 内同步
新增 Kafka topic 架构文档 + 服务 README PR 内同步
遇到新问题/经验 known-issues.md PR 内同步

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 主题分区

| 场景     | 技术/规则          |
| -------- | ------------------ |
| 简述场景 | 正确做法(一句话) |

规则

  • 索引式:场景→技术/规则映射
  • 不写代码示例和错误示范
  • 同类问题在原条目补充,不重复创建
  • 在"工作经验日志"区按时间倒序追加记录

六、多语言 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按以下顺序拆分提交

  1. 契约先行feat(proto): ...
  2. 生成代码build(contracts): ...
  3. 后端服务feat(teaching): ...
  4. 网关层feat(gateway): ...
  5. 前端feat(teacher-shell): ...

6.4 依赖升级规则

规则

  • 依赖升级使用 build(deps): 类型
  • 必须说明升级原因(安全、功能、兼容性)
  • 安全漏洞修复必须包含 CVE 编号
  • 大版本升级需单独 PR 并完整测试

示例

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 事件"

七、版本与发布

7.1 版本号体系

本项目采用双层版本号

层级 格式 说明
平台版本 v{阶段}.{迭代}.{patch} v0.3.1P3 阶段第 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 镜像标签

格式{registry}/edu/{service}:{tag}

tag 类型 格式 示例 用途
版本号 v{version} v0.3.1 正式发布
服务版本 {service}-{semver} identity-1.2.0 服务独立版本
Git SHA sha-{short} sha-a1b2c3d 精确追溯
最新 latest latest 开发环境
阶段 {stage}-{sha} staging-a1b2c3d 阶段环境

7.4 发布流程

flowchart TD
    A[main 分支达到发布标准] --> B[创建 release/v0.3.x 分支]
    B --> C[运行完整测试套件]
    C --> D{测试通过?}
    D -->|否| E[修复问题]
    E --> C
    D -->|是| F[更新 CHANGELOG.md]
    F --> G[打 tag v0.3.0]
    G --> H[CI 自动构建镜像]
    H --> I[部署至 staging]
    I --> J[冒烟测试]
    J --> K{冒烟通过?}
    K -->|否| L[修复并重新发布]
    L --> C
    K -->|是| M[审批发布至 production]
    M --> N[monitoring 观察指标]
    N --> O{指标正常?}
    O -->|否| P[紧急回滚]
    O -->|是| Q[发布完成]
    Q --> R[合并 release 分支回 main]

7.5 CHANGELOG 格式

CHANGELOG.mdKeep a Changelog 格式维护:

## [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

版本号升级规则

  • MAJORBreaking Changeprotobuf 不兼容变更、API 破坏性修改)
  • MINOR:新增功能,向后兼容
  • PATCHBug 修复,向后兼容

八、紧急回滚

8.1 回滚策略

场景 回滚方式 耗时
代码缺陷 git revert + 重新部署 5-10 分钟
镜像问题 kubectl rollout undo 1-2 分钟
数据库迁移问题 执行迁移 down 脚本 5-30 分钟
配置错误 回滚 ConfigMap/Secret 1-2 分钟
全站故障 回滚至上一稳定 tag 10-30 分钟

8.2 代码回滚

# 1. 确认要回滚的 commit
git log --oneline -10

# 2. 创建回滚分支
git checkout -b hotfix/v0.3.1

# 3. 回滚指定 commit
git revert <commit-sha>

# 4. 推送并创建 PR
git push origin hotfix/v0.3.1

# 5. 紧急审批合并后部署

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 数据库迁移回滚

规则

  • 所有迁移必须提供 updown 脚本
  • down 脚本必须在 CI 中测试
  • 回滚前必须备份生产数据
# 回滚最近一次迁移
pnpm --filter identity run migrate:down

# 回滚至指定版本
pnpm --filter identity run migrate:down -- --to <version>

8.5 回滚原则

  1. 优先保证可用性:回滚决策应在 5 分钟内做出,无需 root cause
  2. 保留现场回滚前保存日志、metrics、错误堆栈
  3. 通知相关方:回滚后立即通知运维、产品、相关开发
  4. 复盘改进:回滚后 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 工作流差异

维度 CICDNext.js 单应用) Edu微服务 monorepo
仓库结构 单一 Next.js 应用 多语言 monorepopnpm + go.work + uv
分支策略 trunk-based trunk-based沿用
提交规范 Conventional Commits Conventional Commits沿用scope 扩展至服务/包)
scope 范围 模块名(如 examshomework 服务/包名(如 iamapi-gatewayshared-proto
commitlint scope-enum 35 个模块 26 个 scope含服务/包/工具/平台级,与 .commitlintrc.js 同步)
PR Reviewer 1 人 1-2 人(核心模块/跨服务 2 人)
合并策略 Squash Merge Squash Merge沿用
版本号 单一应用版本 双层(平台版本 + 服务独立版本)
发布粒度 整体发布 按服务独立发布
Docker 镜像 单一镜像 每服务一镜像
回滚粒度 整体回滚 按服务回滚
数据库迁移 Drizzle 单库 每服务独立库 + 独立迁移
文档同步 npm run arch:scan pnpm run arch:scan(多语言扫描)
CI 检查 lint + tsc + test lint + typecheck + test按语言分别执行
紧急回滚 git revert + 重新部署 git revert + kubectl rollout undo
事故复盘 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 与 CODEOWNERShusky hooks 与实际文件对齐;新增 pre-push hook 说明