- 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 模板
985 lines
36 KiB
Markdown
985 lines
36 KiB
Markdown
# Edu Git 工作流规范
|
||
|
||
> 版本:1.1
|
||
> 日期:2026-07-08
|
||
> 状态:基线发布(v1.1:scope-enum 对齐 + CODEOWNERS)
|
||
> 适用范围: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. [PR 与 Code Review](#四pr-与-code-review)
|
||
5. [文档同步规则](#五文档同步规则)
|
||
6. [多语言 monorepo 提交规则](#六多语言-monorepo-提交规则)
|
||
7. [版本与发布](#七版本与发布)
|
||
8. [紧急回滚](#八紧急回滚)
|
||
9. [附录:CICD 与 Edu Git 工作流差异](#九附录cicd-与-edu-git-工作流差异)
|
||
|
||
---
|
||
|
||
## 一、分支策略
|
||
|
||
### 1.1 主干开发(Trunk-Based Development)
|
||
|
||
本项目采用**主干开发**模式,所有变更最终合并至 `main` 分支。
|
||
|
||
**核心原则**:
|
||
|
||
- `main` 分支始终保持可发布状态
|
||
- 短生命周期特性分支(通常 ≤ 3 天)
|
||
- 频繁集成,每天至少一次 rebase/merge 至最新 `main`
|
||
- 通过特性开关(Feature Flag)控制未完成功能的暴露
|
||
|
||
### 1.2 分支模型
|
||
|
||
```mermaid
|
||
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](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` 与本节,并在 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/` | 教学核心服务(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']`。
|
||
|
||
---
|
||
|
||
## 四、PR 与 Code Review
|
||
|
||
### 4.1 PR 流程
|
||
|
||
```mermaid
|
||
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 等价路径):
|
||
|
||
```markdown
|
||
## 变更说明
|
||
|
||
<!-- 简述本次变更的目的和实现方式 -->
|
||
|
||
## 变更类型
|
||
|
||
- [ ] 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 清单
|
||
|
||
**通用检查**:
|
||
|
||
- [ ] 代码是否符合 [编码规范](./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.6 合并策略
|
||
|
||
**默认使用 Squash Merge**:
|
||
|
||
- 保留 PR 的完整变更作为一个 commit
|
||
- commit message 使用 PR 标题
|
||
- 删除特性分支
|
||
|
||
**禁止使用 Merge Commit**(除非是发布分支合并回 main):
|
||
|
||
- 避免历史中充斥 "Merge branch" 噪音
|
||
- 保持线性历史
|
||
|
||
**Rebase Merge**:
|
||
|
||
- 仅用于需要保留多个有意义 commit 的特性分支
|
||
- 需在 PR 中说明原因
|
||
|
||
### 4.7 模块 Owner 与 CODEOWNERS
|
||
|
||
**实际生效文件**:仓库根 `.github/CODEOWNERS`(GitHub/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.js`、`lint-staged.config.js`、`package.json`、`pnpm-workspace.yaml`、`go.work`、`pyproject.toml`、`tsconfig.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。
|
||
|
||
```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 主题分区
|
||
|
||
| 场景 | 技术/规则 |
|
||
| -------- | ------------------ |
|
||
| 简述场景 | 正确做法(一句话) |
|
||
```
|
||
|
||
**规则**:
|
||
|
||
- 索引式:场景→技术/规则映射
|
||
- 不写代码示例和错误示范
|
||
- 同类问题在原条目补充,不重复创建
|
||
- 在"工作经验日志"区按时间倒序追加记录
|
||
|
||
---
|
||
|
||
## 六、多语言 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 编号
|
||
- 大版本升级需单独 PR 并完整测试
|
||
|
||
**示例**:
|
||
|
||
```
|
||
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 事件"
|
||
```
|
||
|
||
---
|
||
|
||
## 七、版本与发布
|
||
|
||
### 7.1 版本号体系
|
||
|
||
本项目采用**双层版本号**:
|
||
|
||
| 层级 | 格式 | 说明 |
|
||
| -------- | ------------------------ | ----------------------------------------- |
|
||
| 平台版本 | `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 镜像标签
|
||
|
||
**格式**:`{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 发布流程
|
||
|
||
```mermaid
|
||
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.md` 按 [Keep a Changelog](https://keepachangelog.com/zh-CN/) 格式维护:
|
||
|
||
```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 回滚策略
|
||
|
||
| 场景 | 回滚方式 | 耗时 |
|
||
| -------------- | ----------------------- | ---------- |
|
||
| 代码缺陷 | `git revert` + 重新部署 | 5-10 分钟 |
|
||
| 镜像问题 | `kubectl rollout undo` | 1-2 分钟 |
|
||
| 数据库迁移问题 | 执行迁移 down 脚本 | 5-30 分钟 |
|
||
| 配置错误 | 回滚 ConfigMap/Secret | 1-2 分钟 |
|
||
| 全站故障 | 回滚至上一稳定 tag | 10-30 分钟 |
|
||
|
||
### 8.2 代码回滚
|
||
|
||
```bash
|
||
# 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 部署回滚
|
||
|
||
```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 | trunk-based(沿用) |
|
||
| 提交规范 | Conventional Commits | Conventional Commits(沿用,scope 扩展至服务/包) |
|
||
| scope 范围 | 模块名(如 `exams`、`homework`) | 服务/包名(如 `iam`、`api-gateway`、`shared-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 与 CODEOWNERS;husky hooks 与实际文件对齐;新增 pre-push hook 说明 |
|