Files
Edu/docs/standards/git-workflow.md

918 lines
38 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Edu Git 工作流规范
> 版本1.3
> 日期2026-07-10
> 状态v1.3恢复分支开发模式AI 不切换分支
> 适用范围Edu 多语言 monorepopnpm 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 模式
本项目采用**分支开发**模式:**人类决策者**为每个任务/模块创建分支并分配给 AIAI 只在当前分配的分支上工作,分支的创建、切换、合并均由人类决策者维护。
> **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+ CIproject_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/` | 教学核心服务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: 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 messageConventional 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 主题分区
| 场景 | 技术/规则 |
| -------- | ------------------ |
| 简述场景 | 正确做法(一句话) |
```
**规则**
- 索引式:场景→技术/规则映射
- 不写代码示例和错误示范
- 同类问题在原条目补充,不重复创建
- **不设"工作经验日志"区**:模块内经验沉淀在各自服务 READMEknown-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 Changeprotobuf 不兼容变更、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 mainCI 自动触发重新部署)
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 工作流差异
| 维度 | CICDNext.js 单应用) | Edu微服务 monorepo |
| --------------------- | -------------------------------- | --------------------------------------------------------------------------- |
| 仓库结构 | 单一 Next.js 应用 | 多语言 monorepopnpm + 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 与 CODEOWNERShusky 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 身份 |