# Edu Git 工作流规范

> 版本：1.3
> 日期：2026-07-10
> 状态：v1.3：恢复分支开发模式，AI 不切换分支
> 适用范围：Edu 多语言 monorepo（pnpm workspace + go.work + pyproject.toml）
> 关联文档：
>
> - [项目规则](../../.trae/rules/project_rules.md)
> - [编码规范](./coding-standards.md)
> - [迁移指南](../../MIGRATION_GUIDE.md)
> - [架构总览](../architecture/001_architecture_overview.md)

---

## 目录

1. [分支开发](#一分支开发)
2. [Conventional Commits 规范](#二conventional-commits-规范)
3. [commitlint + husky 配置](#三commitlint--husky-配置)
4. [事后 Code Review](#四事后-code-review)
5. [文档同步规则](#五文档同步规则)
6. [多语言 monorepo 提交规则](#六多语言-monorepo-提交规则)
7. [版本管理](#七版本管理)
8. [紧急回滚](#八紧急回滚)
9. [附录：CICD 与 Edu Git 工作流差异](#九附录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。

```bash
# 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`，合并时机与策略由人类决策者判断。

```bash
# 人类决策者操作（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](https://www.conventionalcommits.org/zh-hans/)：

```
<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](#33-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 安装与初始化

```bash
# 在 monorepo 根目录
pnpm add -Dw @commitlint/cli @commitlint/config-conventional husky lint-staged

# 初始化 husky
pnpm exec husky init
```

### 3.2 commitlint 配置

实际生效配置文件：仓库根 `.commitlintrc.js`（CommonJS）。

```javascript
/** @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`：

```bash
npx --no-install commitlint --edit $1
```

`.husky/pre-commit`：

```bash
npx --no-install lint-staged
```

`.husky/pre-push`（推送前类型检查，TS 服务 typecheck 通过后才允许推送）：

```bash
#!/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.js`（CommonJS）。

```javascript
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 流程

```mermaid
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 时检查：

**通用检查**：

- [ ] 代码是否符合 [编码规范](./coding-standards.md)
- [ ] 是否有明显的逻辑错误
- [ ] 错误处理是否完整（不忽略 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 文件维护规则**：

1. 新增服务/包时，必须同步更新 `.github/CODEOWNERS`
2. owner 变更（人员调动）由架构组确认后通过分支提交更新
3. 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。

```bash
# 提交前流程
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`，结构如下：

```markdown
# [服务名] 服务

> 版本：1.0
> 限界上下文：[上下文名]
> 技术栈：[语言 + 框架]

## 职责

[一段话描述]

## 架构

[mermaid 架构图]

## 核心流程

[mermaid 时序图]

## 目录结构

[树形结构 + 说明]

## 依赖

- 上游服务：[列表]
- 下游服务：[列表]
- 共享包：[列表]

## 约束

[业务规则、技术约束]

## 架构决策

[关键设计决策记录]
```

### 5.4 known-issues.md 格式

`docs/troubleshooting/known-issues.md` 采用索引式速查手册格式：

```markdown
### X.X 主题分区

| 场景     | 技术/规则          |
| -------- | ------------------ |
| 简述场景 | 正确做法（一句话） |
```

**规则**：

- 索引式：场景→技术/规则映射
- 不写代码示例和错误示范
- 同类问题在原条目补充，不重复创建
- **不设"工作经验日志"区**：模块内经验沉淀在各自服务 README，known-issues 只保留索引式场景→技术映射（见 project_rules §9）
- **经验沉淀不标注 AI 身份**：AI 只做经验沉淀（场景→技术映射），不记录工作日志，不标注 AI 身份

---

## 六、多语言 monorepo 提交规则

### 6.1 单服务单提交原则

**规则**：一个 commit 只涉及一个服务或一个包的变更。

**原因**：

- 便于回滚（按服务粒度回滚）
- 便于追踪（changelog 清晰）
- 便于 review（聚焦单一职责）

**例外**：跨服务重构或契约变更可在同一 commit 中涉及多个服务，但需在 body 中说明。

### 6.2 生成代码单独提交

**规则**：protobuf 生成的代码必须与手写代码分开提交。

```bash
# 正确流程
# 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 编号
- 大版本升级需单独分支并完整测试

**示例**：

```
build(deps): 升级 nestjs 至 10.3.0

- 修复 CVE-2024-1234 漏洞
- 升级至最新 patch 版本
- 全部测试通过
```

### 6.5 跨服务依赖更新

当一个服务的 protobuf 变更影响其他服务：

```bash
# 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 发布流程

```mermaid
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](https://keepachangelog.com/zh-CN/) 格式维护，版本号对应阶段迭代（不绑定 git tag）：

```markdown
## [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 上的回滚推送操作。

```bash
# 人类决策者操作（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 部署回滚

```bash
# 查看部署历史
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 中测试
- 回滚前必须备份生产数据

```bash
# 回滚最近一次迁移
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`：

```markdown
# 事故记录：[简述]

> 日期：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 身份 |
