530 lines
29 KiB
Markdown
530 lines
29 KiB
Markdown
# Edu 项目规则(微服务版)
|
||
|
||
> 版本:1.0
|
||
> 日期:2026-07-08
|
||
> 适用范围:Edu 微服务架构(DDD + EDA + CQRS,多语言 monorepo)
|
||
> 关联文档:
|
||
>
|
||
> - [004 架构影响地图](../../docs/architecture/004_architecture_impact_map.md)
|
||
> - [理想蓝图 0010](../../docs/architecture/0010_architecture.md)
|
||
> - [迁移指南](../../MIGRATION_GUIDE.md)
|
||
> - [known-issues 速查](../../docs/troubleshooting/known-issues.md)
|
||
|
||
---
|
||
|
||
## 1. 架构图优先规则
|
||
|
||
**任何任务开始前,必须先查阅架构影响地图,通过图定位代码和模块。**
|
||
|
||
1. **先图后码**:执行任何分析、修改、搜索任务时,首先运行 `pnpm run arch:scan` 更新 arch.db,再通过 `pnpm run arch:query` 查询目标模块、函数、依赖关系,结合阅读 `docs/architecture/004_architecture_impact_map.md` 定位架构设计意图,最后按图索骥读取源码
|
||
2. **图未覆盖则先补图**:如果发现项目中存在 arch.db 未记录的模块、函数、表、路由、proto 等结构,**必须先运行 `pnpm run arch:scan` 重新扫描**(多语言扫描器:TS + Go + Python + Proto),然后检查 004 是否需要补充
|
||
3. **改码必同步图**:对源码的任何修改完成后,必须运行 `pnpm run arch:scan` 更新 arch.db;若架构设计意图有变化,同步更新 004
|
||
|
||
### 架构文档清单
|
||
|
||
| 文档 | 用途 |
|
||
| -------------------------------------------------- | -------------------------------------------------------- |
|
||
| `docs/architecture/004_architecture_impact_map.md` | 架构设计意图唯一源(人类可读) |
|
||
| `docs/architecture/0010_architecture.md` | 理想蓝图(目标态) |
|
||
| `docs/architecture/roadmap/` | 长远规划(tech-debt / pending-features) |
|
||
| `docs/architecture/runbooks/` | 运维手册(P6 硬化、post-p6-followup、incident-response) |
|
||
| `docs/troubleshooting/known-issues.md` | 已知问题速查(场景→技术映射,索引式,不写工作日志) |
|
||
|
||
### 需要同步图的场景
|
||
|
||
- 新增/删除/重命名导出函数、组件、Hook、类型
|
||
- 修改函数签名(参数、返回类型)
|
||
- 修改权限点(Permissions 常量)或角色-权限映射
|
||
- 新增/删除数据库表
|
||
- 新增/删除路由页面、API 路由、gRPC 服务、proto message
|
||
- 修改模块间依赖关系或服务间调用关系
|
||
- 新增服务、新增模块、新增 proto 定义
|
||
- 修改 Kafka topic、Outbox 事件命名
|
||
|
||
### 同步方式
|
||
|
||
- 修改源码后运行 `pnpm run arch:scan` 更新 arch.db(强制)
|
||
- 若架构设计意图变化,同步更新 `docs/architecture/004_architecture_impact_map.md`
|
||
- 若发现新的"场景→技术"映射或工作经验,更新 `docs/troubleshooting/known-issues.md`
|
||
|
||
---
|
||
|
||
## 2. 架构元数据库规则(arch.db)
|
||
|
||
**arch.db 是代码结构唯一源,AI 工作前必须运行 `pnpm run arch:scan` 更新。**
|
||
|
||
1. **多语言扫描**:arch.db 覆盖 TypeScript(ts-morph)、Go(tree-sitter-go)、Python(tree-sitter-python)、Proto(buf AST)四类语言
|
||
2. **查询命令**:
|
||
- `pnpm run arch:query -- sql "<SQL>"` 自定义 SQL 查询
|
||
- `pnpm run arch:query -- module-deps` 查模块依赖
|
||
- `pnpm run arch:query -- module-reverse-deps <module>` 查反向依赖
|
||
- `pnpm run arch:query -- symbol-refs <symbol>` 查符号引用链
|
||
- `pnpm run arch:query -- tech-usage <tag>` 查技术使用
|
||
- `pnpm run arch:query -- violations` 查架构违规
|
||
- `pnpm run arch:query -- stats` 查总体统计
|
||
- `pnpm run arch:query -- modules` 查模块列表
|
||
3. **arch.db 不替代 004**:arch.db 是"代码现状",004 是"设计意图",两者互补
|
||
4. **预期规模**:模块数 ≥ 10(api-gateway、push-gateway、teacher-bff、iam、classes、core-edu、content、msg、data-ana、ai),符号数 ≥ 100
|
||
|
||
---
|
||
|
||
## 3. 编码规范
|
||
|
||
详细规范见 `docs/standards/coding-standards.md`,以下为核心强制规则。
|
||
|
||
### 3.1 代码质量规则
|
||
|
||
- 每次修改后运行 `pnpm run lint` 和 `pnpm run typecheck` 确保零错误
|
||
- TypeScript 服务必须用 `@RequirePermission()` 装饰器进行权限校验
|
||
- 前端组件禁止使用 `role === "xxx"` 硬编码,统一使用 `usePermission().hasPermission()`
|
||
- 单文件行数遵循企业级规范:
|
||
- 配置文件、常量文件、类型定义文件、proto:无限制
|
||
- Controller / Service:建议 ≤ 500 行
|
||
- Repository / data-access:建议 ≤ 800 行
|
||
- 工具函数:建议 ≤ 40 行
|
||
- 自定义 Hook:建议 ≤ 80 行
|
||
- 硬性上限:任何文件不超过 1000 行,超过必须拆分
|
||
|
||
### 3.2 架构分层规则(微服务)
|
||
|
||
- **四层分层**:Gateway → BFF → Services → Data
|
||
- **依赖方向单向**:Gateway → BFF → Services → Data,禁止反向依赖
|
||
- **服务间通信**:通过 protobuf gRPC 或 Kafka 事件,**禁止直接访问对方 DB**
|
||
- **Gateway 职责**:JWT 校验、限流、熔断、CORS、请求 ID 注入
|
||
- **BFF 职责**:聚合多个 Service 的数据,为前端提供场景化 API
|
||
- **Service 职责**:业务逻辑,每服务独占 DB(DDD 限界上下文)
|
||
|
||
### 3.3 模块标准结构(DDD)
|
||
|
||
```
|
||
services/[service]/src/
|
||
├─ [domain]/ # 限界上下文
|
||
│ ├─ *.controller.ts # Controller(HTTP/gRPC 入口)
|
||
│ ├─ *.service.ts # Application Service(编排层)
|
||
│ ├─ *.repository.ts # Repository(数据访问)
|
||
│ ├─ *.schema.ts # Zod 验证
|
||
│ └─ *.dto.ts # DTO
|
||
├─ config/ # 配置(database / env / kafka / neo4j / elasticsearch)
|
||
├─ middleware/ # 中间件(auth.middleware / permission.guard)
|
||
├─ shared/ # 共享
|
||
│ ├─ errors/ # 错误(application-error / global-error.filter)
|
||
│ ├─ health/ # 健康检查
|
||
│ ├─ lifecycle/ # 生命周期
|
||
│ ├─ observability/ # 可观测性(logger / metrics / tracer)
|
||
│ └─ outbox/ # Outbox(仅事件驱动服务)
|
||
├─ app.module.ts # 根模块
|
||
└─ main.ts # 入口
|
||
```
|
||
|
||
### 3.4 TypeScript 规则
|
||
|
||
- **禁止 `any`**:未知类型用 `unknown` 并做类型守卫
|
||
- **禁止 `as` 断言**(除非从 `unknown` 转换或测试中,需注释原因)
|
||
- **函数返回值必须显式标注**,特别是 `Promise<T>`
|
||
- **仅用于类型的导入必须使用 `import type`**
|
||
- **可选链后禁止跟非空断言 `!`**
|
||
- **ESM 模式**:NestJS ESM 模式下,相对 import 的 `.js` 后缀(构建产物)
|
||
|
||
### 3.5 Go 规则
|
||
|
||
- 包名小写单词,不使用下划线或驼峰
|
||
- 导出函数必须有 doc comment(`// FuncName ...`)
|
||
- 错误处理:`if err != nil { return err }`,禁止 `_ = err`
|
||
- 不使用 `interface{}`,用 `any`(Go 1.18+)
|
||
- 包内文件命名 lowercase,不使用下划线(除 `_test.go`)
|
||
- 中间件位于 `internal/middleware/`,路由位于 `internal/routing/`
|
||
|
||
### 3.6 Python 规则
|
||
|
||
- 类型注解强制(所有函数签名、变量声明)
|
||
- FastAPI 路由用 `APIRouter`
|
||
- 异步优先:`async def`,IO 密集场景禁止同步阻塞调用
|
||
- 模块名 snake_case,类名 PascalCase
|
||
- 配置统一通过 `pydantic-settings` 管理(`config.py`)
|
||
|
||
### 3.7 命名规范(多语言)
|
||
|
||
| 对象 | 规范 | 示例 |
|
||
| ----------- | -------------------------------------------------- | ------------------------------------------------ |
|
||
| 目录 | kebab-case | `api-gateway/`、`core-edu/` |
|
||
| TS 组件 | PascalCase | `UserController.ts` |
|
||
| TS Hook | camelCase | `useAuth.ts` |
|
||
| Go 文件 | lowercase | `circuitbreaker.go` |
|
||
| Python 文件 | snake_case | `clickhouse_client.py` |
|
||
| Proto 文件 | snake_case | `core_edu.proto` |
|
||
| 变量/函数 | camelCase(TS)/ lowercase(Go)/ snake_case(Py) | `getUserById` / `getUserById` / `get_user_by_id` |
|
||
| 常量 | UPPER_SNAKE_CASE | `MAX_RETRY_COUNT` |
|
||
| 类/接口 | PascalCase,接口不加 `I` 前缀 | `UserService` |
|
||
| 布尔值 | `is/has/can/should` 前缀 | `isActive`、`hasPermission` |
|
||
|
||
### 3.8 Controller / Server Action 规范
|
||
|
||
- 每个 Controller 方法必须用 `@RequirePermission()` 装饰器声明权限
|
||
- 输入用 Zod / class-validator 验证,验证失败返回结构化错误
|
||
- 返回 protobuf message 或 DTO(结构同 ActionState)
|
||
- 错误统一走 `GlobalErrorFilter`
|
||
- BFF Controller 聚合多个 Service 调用,禁止直接访问 DB
|
||
|
||
### 3.9 Tailwind 规范
|
||
|
||
- 使用 `cn()` 工具函数管理条件类名
|
||
- **禁止**字符串拼接动态类名(`bg-${color}-500`)
|
||
- **禁止**使用任意值(`w-[137px]`),除非有充分理由并注释
|
||
- 设计令牌在 `packages/shared-tokens/`(待建立)或 `apps/teacher-portal/src/app/styles/tokens/`
|
||
|
||
### 3.10 设计令牌规范(强制)
|
||
|
||
- **禁止硬编码颜色**:TSX/TS/CSS 中不得出现 `#hex` 颜色字面量,统一使用 `hsl(var(--*))` 或 Tailwind 类 `bg-*`
|
||
- **禁止硬编码字体**:不得出现 `'Inter'`/`'Fraunces'`/`'JetBrains Mono'` 字面量,使用 `var(--font-family-sans/serif/mono)`
|
||
- **禁止硬编码字号**:不得出现 `font-size: Npx`,使用 `var(--font-size-1~9)`
|
||
- **禁止 Tailwind 任意值**:不得使用 `w-[Npx]`/`h-[Npx]`/`p-[Npx]` 等,映射到 `--space-*` 或 Tailwind 默认阶梯
|
||
- **三层令牌**:
|
||
- Layer 1 Primitive:原始色板/字号/间距/阴影,业务代码不直接引用
|
||
- Layer 2 Semantic:语义令牌(light/dark),业务代码唯一引用入口
|
||
- Layer 3 Tailwind Theme:`@theme inline` 将 Semantic 令牌暴露为 `bg-*`/`text-*`/`font-*` 类
|
||
- **改令牌必同步图**:修改令牌定义后,同步更新 004 与 arch.db
|
||
- **ESLint 强制约束**:
|
||
- `no-restricted-syntax`:禁止 `#hex` 字面量
|
||
- `design-tokens/no-hardcoded-fonts`:禁止 `'Inter'`/`'Fraunces'` 字面量
|
||
- 白名单:`primitive.css`、`email-channel`、`manifest.ts`
|
||
|
||
---
|
||
|
||
## 4. 安全规范
|
||
|
||
- **JWT RS256**:IAM 签发,Gateway 公钥校验(不共享密钥)
|
||
- **Cookie**:`httpOnly + Secure + SameSite=Strict`
|
||
- **环境变量**:服务端变量不加 `NEXT_PUBLIC_` 前缀;前端变量必须加
|
||
- **环境校验**:用 `@t3-oss/env-nextjs` + Zod 或 `pydantic-settings` 校验
|
||
- **禁止 `dangerouslySetInnerHTML`**(如必须使用,先用 DOMPurify 清洗)
|
||
- **密码哈希**:bcrypt(cost ≥ 12),禁止 MD5/SHA1
|
||
- **限流**:Gateway 层 IP 级令牌桶,登录接口额外加用户级限流
|
||
- **CORS**:白名单域名,禁止 `*`
|
||
- **WAF**:见 `infra/security/waf-rules.conf`
|
||
|
||
---
|
||
|
||
## 5. 契约规范
|
||
|
||
- **契约先行**:服务间通信先定 `.proto`,再写实现
|
||
- **工具链**:protobuf + buf v2
|
||
- **buf lint**:`STANDARD` 规则集
|
||
- **buf breaking**:`FILE` 级别检查(CI 强制)
|
||
- **proto 文件位置**:`packages/shared-proto/proto/`
|
||
- **包名规范**:`edu.<domain>.v1`(如 `edu.iam.v1`、`edu.core_edu.v1`)
|
||
- **生成代码**:`buf generate`(TS 走 `buf.gen.yaml`,Go/Python 各自配置)
|
||
- **gRPC 服务端口**:每服务独立端口,见 004 服务清单
|
||
|
||
---
|
||
|
||
## 6. 事件驱动规范
|
||
|
||
- **Outbox 模式**:事务内写业务表 + outbox 表,独立 publisher 投递到 Kafka(保证 at-least-once)
|
||
- **事件命名**:`<Aggregate>.<Action>`(如 `ExamCreated`、`HomeworkSubmitted`、`GradeReleased`)
|
||
- **TOPIC_MAP 路由**:每个服务维护 `事件 → topic` 映射(见 `shared/outbox/`)
|
||
- **幂等性**:
|
||
- Kafka producer:`idempotent=true` + `transactionalId`
|
||
- Consumer:基于 `event_id` 去重(Redis SETNX 或 DB 唯一索引)
|
||
- **CDC**:MySQL → Debezium → Kafka(可选,用于读模型同步)
|
||
- **事件版本**:schema 演化用 `v1`/`v2` 后缀,禁止破坏性变更
|
||
|
||
---
|
||
|
||
## 7. 提交规范
|
||
|
||
- 使用 Conventional Commits 格式:`feat(scope): description`
|
||
- **类型**:`feat`、`fix`、`chore`、`docs`、`style`、`refactor`、`test`、`perf`、`ci`
|
||
- **scope**(服务名或包名):
|
||
- 服务:`iam`、`classes`、`core-edu`、`content`、`msg`、`ai`、`data-ana`、`api-gateway`、`push-gateway`、`teacher-bff`
|
||
- 包:`shared-proto`、`shared-ts`、`shared-go`、`shared-py`、`shared-tokens`
|
||
- 基础设施:`infra`、`k8s`、`helm`、`ci`
|
||
- 文档:`docs`
|
||
- **提交前必须运行**:`pnpm run lint` + `pnpm run typecheck`(TS);`go vet ./...`(Go);`ruff check src/`(Python)
|
||
- **commitlint + husky**:强制校验(见 `.commitlintrc.js`、`.husky/commit-msg`)
|
||
|
||
---
|
||
|
||
## 8. Git 工作流
|
||
|
||
- **分支策略**:分支开发。**人类决策者手动维护分支**(创建分支、合并到 main),AI 不得自行切换/创建/合并分支
|
||
- **AI 分支约束(强制)**:
|
||
- AI 只在人类分配的当前分支上工作
|
||
- **禁止** `git checkout -b`、`git switch`、`git branch` 创建或切换分支
|
||
- **禁止** `git merge`、`git push origin main`(合并与推送 main 由人类负责)
|
||
- AI 完成工作后 `git add` + `git commit` 提交到当前分支,通知人类合并
|
||
- **提交前校验**:commit 前必须本地通过 `pnpm run lint` + `pnpm run typecheck`(TS)/ `go vet ./...`(Go)/ `ruff check src/`(Python)
|
||
- **pre-commit hook**:`lint-staged` 自动修复 + 校验(见 `lint-staged.config.js`)
|
||
- **commit-msg hook**:commitlint 校验格式
|
||
- **回滚**:由人类在 main 上 `git revert <commit>`,不使用分支回滚
|
||
- **默认多 AI 协作**:所有工作默认按多 AI 合作模式进行(见 §14),每个 AI 在各自分支独立工作
|
||
|
||
---
|
||
|
||
## 9. 问题记录规则
|
||
|
||
**所有工作完成后,必须将遇到的问题记录到 `docs/troubleshooting/known-issues.md`(索引式速查手册)。**
|
||
|
||
### 必须记录的场景
|
||
|
||
| 场景 | 记录要求 |
|
||
| -------------------------------------------------- | --------------------------------- |
|
||
| 构建报错(dev/build/lint/tsc/go vet/ruff) | 记录到"全局经验"对应主题分区 |
|
||
| 运行时异常(白屏/API 报错/数据加载失败/gRPC 错误) | 记录到"模块经验"对应模块分区 |
|
||
| 框架/库版本兼容问题 | 记录到"全局经验: 框架与运行时" |
|
||
| 依赖配置问题(go mod / uv / pnpm workspace) | 记录到"全局经验: 依赖管理" |
|
||
| 架构约束违规(跨服务访问 DB / 缺契约) | 记录到"全局经验: 架构约束" |
|
||
| 多语言 monorepo 问题(共享包链接失败等) | 记录到"全局经验: 多语言 monorepo" |
|
||
|
||
### 记录格式
|
||
|
||
索引式表格,指明"场景→技术/规则"映射,不写多行代码示例:
|
||
|
||
```markdown
|
||
### X.X 主题分区
|
||
|
||
| 场景 | 技术/规则 |
|
||
| -------- | ------------------ |
|
||
| 简述场景 | 正确做法(一句话) |
|
||
```
|
||
|
||
### 记录要求
|
||
|
||
- **索引式**:场景→技术/规则映射,不写代码示例和错误示范列
|
||
- **去重**:同类问题在原条目补充,不重复创建
|
||
- **引用架构规则**:架构分层、模块结构等规则引用 004 和本规则文件,不重复
|
||
- **只读自己模块分区**:AI 查阅 known-issues 时只读自己负责模块的分区,禁止读其他 AI 模块的分区(避免被历史记录误导)
|
||
- **禁止工作日志**:known-issues 不设"工作经验日志"区,不写流水账、不写"做了什么/学到什么"
|
||
- **经验沉淀不标注 AI 身份**:所有经验记录只写"场景→技术/规则"映射,**不得出现 AI 标识(如 ai01/ai02/coord 等)**,避免新同名 AI 将前任记录误认为当前事实
|
||
- **模块内经验**:模块内的经验沉淀在各自模块的 README/文档中,同样不标注 AI 身份
|
||
|
||
---
|
||
|
||
## 10. AI 工作强制流程
|
||
|
||
**所有 AI 工作必须遵循此流程,违反即违规。**
|
||
|
||
### 阶段 1:上下文加载(按需阅读,严格模块边界)
|
||
|
||
> **架构文档按需阅读**:模块开发只读自己模块的架构与服务 README;项目整体相关工作(跨模块契约、基础设施、文档体系、shared-proto)才读全局架构文档。功能开发/文档书写等强依赖场景必须读对应架构。
|
||
>
|
||
> **严格模块边界**:AI 只读自己负责模块的文档与源码,不越界阅读其他模块的内部实现细节(避免被历史记录或他人方案误导)。仅在需要确认跨模块契约时,才读对方的对外接口(proto/API/事件)。
|
||
|
||
1. `pnpm run arch:scan` 更新 arch.db
|
||
2. `pnpm run arch:query -- module-deps` 查目标模块依赖
|
||
3. `pnpm run arch:query -- symbol-refs <目标函数>` 查调用链
|
||
4. 阅读 `services/[service]/README.md` 读**自己模块**的工作流程
|
||
5. 查 `docs/troubleshooting/known-issues.md` **仅读自己模块的分区**,禁止读其他 AI 模块分区
|
||
6. 模块开发:查 `docs/architecture/004_architecture_impact_map.md` **对应模块章节**;全局工作:查 004 全文
|
||
|
||
### 阶段 2:执行工作
|
||
|
||
1. 按规划执行(契约先行:先 proto,再实现)
|
||
2. 修改代码后立即运行 `pnpm run arch:scan` 更新 arch.db
|
||
3. 运行质量校验确保零错误:
|
||
- TS:`pnpm run lint` + `pnpm run typecheck`
|
||
- Go:`go vet ./...` + `go build ./...`
|
||
- Python:`ruff check src/`
|
||
|
||
### 阶段 3:经验沉淀(强制,不可跳过)
|
||
|
||
1. 若发现新的"场景→技术"映射 → 提炼到 `docs/troubleshooting/known-issues.md` 对应**模块分区**(索引式一行,不写流水日志,**不标注 AI 身份**)
|
||
2. 若发现新的架构决策 → 更新 004
|
||
3. 若代码结构变化 → `pnpm run arch:scan` 确认 arch.db 已更新
|
||
4. 模块内的经验沉淀到**自己模块的 README/文档**,不污染全局 known-issues,同样不标注 AI 身份
|
||
|
||
> **禁止**在 known-issues.md 写"工作经验日志/流水账"。known-issues 是索引式速查手册,只保留场景→技术映射,**不出现任何 AI 标识**。
|
||
|
||
---
|
||
|
||
## 11. 多语言 monorepo 规则
|
||
|
||
- **包管理器分工**:
|
||
- TypeScript:pnpm workspace(`pnpm-workspace.yaml`)
|
||
- Go:go.work(`go.work`)
|
||
- Python:uv workspace(根 `pyproject.toml` 的 `[tool.uv.workspace]`)
|
||
- **共享包**(`packages/`):
|
||
- `shared-proto`:protobuf 契约定义(跨语言共享)
|
||
- `shared-ts`:TypeScript 共享类型与工具(待建立)
|
||
- `shared-go`:Go 共享工具(待建立)
|
||
- `shared-py`:Python 共享工具(待建立)
|
||
- `shared-tokens`:设计令牌(待建立)
|
||
- **跨语言契约**:通过 protobuf,禁止 JSON Schema 或 OpenAPI 作为内部契约
|
||
- **依赖版本对齐**:共享依赖(如 uuid、jwt)在多语言版本号保持一致
|
||
|
||
---
|
||
|
||
## 12. 可观测性规范
|
||
|
||
- **三支柱必须同时启用**(所有服务):
|
||
- **日志**:pino(TS)/ zap(Go)/ structlog(Python)—— 结构化 JSON
|
||
- **指标**:prom-client(TS)/ prometheus(Go)/ prometheus-client(Python)—— `/metrics` 端点
|
||
- **链路**:OpenTelemetry SDK + OTLP exporter —— 统一 traceparent
|
||
- **健康检查**:`/health`(liveness)+ `/ready`(readiness),见各服务 `shared/health/`
|
||
- **请求 ID**:Gateway 注入 `X-Request-Id`,全链路传递(日志、metrics、trace)
|
||
- **指标命名**:`<service>_<module>_<operation>_<unit>`(如 `iam_login_duration_seconds`)
|
||
- **告警规则**:见 `infra/prometheus/rules.yml` + `infra/alertmanager/alertmanager.yml`
|
||
- **Grafana 面板**:见 `infra/grafana/dashboards/`
|
||
|
||
---
|
||
|
||
## 13. 部署与基础设施规范
|
||
|
||
- **容器化**:每服务独立 Dockerfile(见 `services/[service]/Dockerfile`)
|
||
- **K8s**:基础设施 manifest 位于 `infra/k8s/`,演化目标为 Helm chart(见 `infra/k8s/helm/`)
|
||
- **命名空间**:`edu-system`、`edu-monitoring`、`edu-chaos`、`edu-backup`
|
||
- **配置分离**:
|
||
- ConfigMap:非敏感配置(环境变量、特性开关)
|
||
- Secret:敏感配置(DB 密码、JWT 密钥、API key)—— 见 `infra/security/secrets.example.env`
|
||
- **备份**:见 `infra/backup/backup-mysql.sh`,每服务独立备份,保留 7 天
|
||
- **监控栈**:Prometheus + Grafana + Alertmanager(见 `infra/docker-compose.monitoring.yml`)
|
||
- **混沌工程**:见 `infra/chaos/experiments.yaml`
|
||
|
||
---
|
||
|
||
## 14. 多 AI 协作规范
|
||
|
||
> **默认多 AI 协作**:所有 AI 工作默认按多 AI 合作模式进行。详细流程见 [多 AI 协作指南](../../docs/standards/multi-ai-collaboration.md),本节为强制约束摘要。
|
||
|
||
### 14.1 角色与权限
|
||
|
||
| 角色 | 职责 | 在分支提交 | 合并到 main | force push main |
|
||
| -------------------------- | -------------------------------------------------------- | ----------- | ------------------------- | --------------- |
|
||
| **协调 AI(Coordinator)** | 契约管理、交叉审查、冲突仲裁、发布 | ✅ | ❌(由人类合并) | ⚠️(仅事故) |
|
||
| **开发 AI(Dev)** | 按模块分工写代码、在分支提交 | ✅ | ❌ | ❌ |
|
||
| **SRE AI** | `infra/` 维护、部署 | ✅(infra) | ❌(由人类合并) | ⚠️(仅事故) |
|
||
| **人类决策者** | 架构决策、分支管理、合并、Breaking Change 审批、发布确认 | — | ✅(手动合并分支到 main) | ⚠️(仅事故) |
|
||
|
||
> AI 在分配的分支上提交,**不自行合并到 main**。合并由人类决策者负责。
|
||
|
||
### 14.2 模块单一负责制与模块边界(强制)
|
||
|
||
- **每个模块(限界上下文)只有一个 AI 负责,禁止并行修改同一模块**
|
||
- **严格模块边界**:AI 只修改自己负责的目录(`services/<my-service>/` 或 `apps/<my-app>/`),禁止越界修改他人模块的源码
|
||
- **只读自己模块文档**:AI 阅读文档时只读自己模块的 README/设计文档/known-issues 分区,**禁止阅读其他 AI 模块的内部文档和历史记录**(避免被前任同名 AI 的过时方案/审计结果误导)
|
||
- **跨模块契约只读接口**:需要确认跨模块协同时,只读对方的对外接口(proto message / API 端点 / Kafka 事件 schema),不读对方内部实现
|
||
- `shared-proto`、`shared-tokens`、`docs/` 由协调 AI 维护,开发 AI 只读引用
|
||
- `infra/` 由 SRE AI 专门负责,业务 AI 不直接修改
|
||
|
||
### 14.3 分支开发规则(强制)
|
||
|
||
1. **分支由人类创建**:人类决策者为每个任务/模块创建分支并分配给 AI,AI 不得自行创建分支
|
||
2. **AI 禁止切换分支**:AI 不得执行 `git checkout -b`、`git switch`、`git branch` 等分支创建/切换命令
|
||
3. **AI 禁止合并/推送 main**:`git merge`、`git push origin main` 由人类决策者执行,AI 只提交到当前分支
|
||
4. **AI 提交流程**:`git add <files>` → `git commit -m "<type>(<scope>): <subject>"` → 通知人类合并
|
||
5. **提交前校验**:commit 前必须本地通过 `pnpm run lint` + `pnpm run typecheck`(TS)/ `go vet ./...`(Go)/ `ruff check src/`(Python)
|
||
6. **提交信息规范**:遵循 Conventional Commits(见 §7)
|
||
|
||
### 14.4 跨模块变更顺序(强制)
|
||
|
||
修改涉及多模块时,按依赖顺序依次在各模块分支完成,由人类决策者按顺序合并到 main:
|
||
|
||
1. `shared-proto`(proto 契约)
|
||
2. 业务服务(classes / iam / core-edu 等)
|
||
3. `api-gateway`(路由)
|
||
4. BFF(teacher-bff 等)
|
||
5. 微前端(teacher-portal 等)
|
||
|
||
> 每合并一层到 main 后,再合并下一层。协调 AI 负责监督顺序,避免越级合并导致下游构建失败。
|
||
|
||
### 14.5 冲突处理规则
|
||
|
||
- **分支冲突**:由人类决策者在合并时解决,或通知 AI 在分支上 `git rebase` 最新 main 后重新提交
|
||
- **架构冲突**:由协调 AI 仲裁保留方案,通过新 commit 修正
|
||
- **禁止 `git push --force` 到 main**:仅协调 AI 在事故时可 `--force-with-lease`
|
||
|
||
### 14.6 经验沉淀规则(强制)
|
||
|
||
- **不记录工作日志**:AI 不在 known-issues.md 或任何文档中写"工作经验日志/流水账"
|
||
- **只做经验沉淀**:遇到新的"场景→技术"映射,以索引式一行记录到 known-issues 对应模块分区
|
||
- **不标注 AI 身份**:经验沉淀记录**不得出现 AI 标识**(如 ai01/ai02/coord 等),避免新同名 AI 误读
|
||
- **模块内经验**:模块内的经验沉淀到各自服务 README/文档,同样不标注 AI 身份
|
||
|
||
### 14.7 敏感文件保护
|
||
|
||
以下文件修改需人类决策者额外审批:
|
||
|
||
- `.env`、`.env.example`、`infra/security/secrets.example.env`
|
||
- `infra/k8s/`(生产部署)
|
||
- `.github/workflows/`(CI 配置)
|
||
- `.trae/rules/project_rules.md`(项目规则)
|
||
|
||
---
|
||
|
||
## 15. CI/CD 规范
|
||
|
||
> 详细配置见 `.github/workflows/ci.yml`,使用手册见 [cicd-runbook](../../docs/standards/cicd-runbook.md),设计文档见 [no-push-local-build-design](../../docs/superpowers/specs/2026-07-08-cicd-no-push-local-build-design.md)。
|
||
|
||
### 15.1 核心模式:no-push 本地构建
|
||
|
||
- **不推送镜像到 registry**:构建即部署,镜像只存在于构建机本地
|
||
- **不依赖自建镜像**:全部使用官方镜像(node:22-alpine / golang:1.22-alpine / bufbuild/buf / docker:25-git)
|
||
- **DooD 模式**:deploy job 容器挂载 `/var/run/docker.sock`,容器内 docker 命令作用于宿主机
|
||
- **单文件管理**:一个 `.github/workflows/ci.yml` 管全部 CI/CD
|
||
|
||
### 15.2 流水线阶段
|
||
|
||
| 阶段 | 并行 | 内容 | 失败策略 |
|
||
| ----------------- | ---- | ------------------------------------ | -------- |
|
||
| **quality-ts** | ✅ | pnpm lint + typecheck + test + build | 失败阻断 |
|
||
| **quality-go** | ✅ | go vet + build + test | 失败阻断 |
|
||
| **quality-proto** | ✅ | buf lint + buf breaking | 失败阻断 |
|
||
| **deploy** | 串行 | docker compose up --build + 健康检查 | 失败阻断 |
|
||
|
||
> 质量检查在分支推送时触发,部署仅在合并到 main 时触发。
|
||
|
||
### 15.3 触发条件
|
||
|
||
| 事件 | 触发阶段 | 触发条件 |
|
||
| ----------------- | ----------------------------------------------- | -------------------------------- |
|
||
| 分支 push / PR | quality-ts + quality-go + quality-proto(并行) | 分支推送自动 |
|
||
| push 到 main | 上述全部 + deploy | 合并后自动 |
|
||
| workflow_dispatch | 上述全部 + deploy | 手动触发,支持 `commit_sha` 回滚 |
|
||
|
||
> **不再支持 tag 发布**:no-push 模式下不用 `git tag v*` 触发。版本管理通过 commit SHA 追溯。
|
||
|
||
### 15.4 镜像规范
|
||
|
||
- **不推送到 registry**,本地构建本地使用
|
||
- **不保留历史镜像**:layer cache 在宿主机本地,未变更的层秒过
|
||
- **回滚**:`git revert` 重跑 CI,或 `workflow_dispatch` 指定 `commit_sha`
|
||
|
||
### 15.5 部署策略
|
||
|
||
- **目标环境**:服务器 Docker Compose(P1-P2 阶段),K8s(P3+ 阶段)
|
||
- **部署方式**:`docker compose up -d --build --remove-orphans`(在 `/opt/edu/` 目录)
|
||
- **部署目录**:`/opt/edu/`(compose 文件)+ `/opt/edu/repo/`(CI 同步的源码,供 build.context 使用)
|
||
- **健康检查**:部署后轮询 `/healthz` 端点(10 次 × 6 秒),失败输出容器日志
|
||
- **回滚**:`git revert + push` 或 `workflow_dispatch` 指定 `commit_sha`
|
||
|
||
### 15.6 必需的 CI 文件
|
||
|
||
| 文件 | 用途 |
|
||
| --------------------------------- | ------------------------------------- |
|
||
| `.github/workflows/ci.yml` | 唯一 CI/CD 流水线(quality + deploy) |
|
||
| `infra/docker-compose.deploy.yml` | 部署用 compose(build: 替代 image:) |
|
||
| `infra/docker-compose.tools.yml` | 一次性预拉所有 CI 镜像 |
|
||
| `infra/deploy.env.example` | 部署环境变量模板 |
|
||
|
||
### 15.7 actrunner 配置
|
||
|
||
```toml
|
||
# /etc/gitea/act_runner/config.yaml
|
||
container:
|
||
valid_volumes:
|
||
- /var/run/docker.sock
|
||
```
|
||
|
||
### 15.8 镜像预拉(一次性)
|
||
|
||
部署前在服务器执行:
|
||
|
||
```bash
|
||
docker compose -f infra/docker-compose.tools.yml pull
|
||
```
|
||
|
||
拉取清单:node:22-alpine、golang:1.22-alpine、bufbuild/buf:latest、docker:25-git、node:20-alpine、alpine:3.20、mysql:8.0(开发测试)、redis:7-alpine(开发测试)。
|
||
|
||
---
|
||
|
||
**本规则文件是项目的强制约束,所有 contributor(含 AI)必须遵守。规则变更需同步更新 004 与 arch.db。**
|