From 3fbb97791d308687f299c50851434d12834f69a1 Mon Sep 17 00:00:00 2001 From: SpecialX <47072643+wangxiner55@users.noreply.github.com> Date: Wed, 8 Jul 2026 12:50:00 +0800 Subject: [PATCH] =?UTF-8?q?fix(docs):=20=E4=BF=AE=E5=A4=8D=20project=5Frul?= =?UTF-8?q?es.md=20P0=20=E6=8D=9F=E5=9D=8F=E5=B9=B6=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E6=89=80=E6=9C=89=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 根目录 project_rules.md 损坏(72 字节乱码),已删除 - 从 CICD 项目迁移完整版至 .trae/rules/project_rules.md(17881 字节) - 更新 MIGRATION_GUIDE/README/coding-standards 引用至 .trae/rules/ - P0 紧急修复,影响所有 AI 工作流程 --- .trae/rules/project_rules.md | 372 +++++++++++++++++++++++++++++ MIGRATION_GUIDE.md | 341 +++++++++++++------------- README.md | 2 +- docs/standards/coding-standards.md | 170 +++++++------ project_rules.md | 1 - 5 files changed, 644 insertions(+), 242 deletions(-) create mode 100644 .trae/rules/project_rules.md delete mode 100644 project_rules.md diff --git a/.trae/rules/project_rules.md b/.trae/rules/project_rules.md new file mode 100644 index 0000000..877369d --- /dev/null +++ b/.trae/rules/project_rules.md @@ -0,0 +1,372 @@ +# 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 查询 + - `pnpm run arch:query -- module-deps` 查模块依赖 + - `pnpm run arch:query -- module-reverse-deps ` 查反向依赖 + - `pnpm run arch:query -- symbol-refs ` 查符号引用链 + - `pnpm run arch:query -- tech-usage ` 查技术使用 + - `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` +- **仅用于类型的导入必须使用 `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..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) +- **事件命名**:`.`(如 `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 工作流 + +- **分支策略**:trunk-based(直接提交 main 分支,小项目) +- **大型团队**:feature branch + PR,PR 至少 1 人 review +- **pre-commit hook**:`lint-staged` 自动修复 + 校验(见 `lint-staged.config.js`) +- **commit-msg hook**:commitlint 校验格式 +- **禁止 force push**:除非显式要求并通知团队 + +--- + +## 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 和本规则文件,不重复 +- **工作经验日志**:在"工作经验日志"区按时间倒序追加(50 条上限),记录"做了什么/学到什么/下次注意" + +--- + +## 10. AI 工作强制流程 + +**所有 AI 工作必须遵循此流程,违反即违规。** + +### 阶段 1:上下文加载 + +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` "模块经验"分区读相关经验 +6. 查 `docs/architecture/004_architecture_impact_map.md` 对应章节 + +### 阶段 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` "工作经验日志"区追加一条记录: + - 日期 + 时间 + - 模块 + - 做了什么 + 学到什么 +2. 若发现新的"场景→技术"映射 → 提炼到对应模块分区 +3. 若发现新的架构决策 → 更新 004 +4. 若代码结构变化 → `pnpm run arch:scan` 确认 arch.db 已更新 + +--- + +## 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) +- **指标命名**:`___`(如 `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` + +--- + +**本规则文件是项目的强制约束,所有 contributor(含 AI)必须遵守。规则变更需同步更新 004 与 arch.db。** diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 605551c..9d20f05 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -5,7 +5,8 @@ > 状态:基线发布 > 维护者:架构组 > 关联文档: -> - [项目规则](./project_rules.md) +> +> - [项目规则](./.trae/rules/project_rules.md) > - [编码规范](./docs/standards/coding-standards.md) > - [Git 工作流](./docs/standards/git-workflow.md) @@ -30,13 +31,13 @@ 原始项目 CICD 是基于 Next.js 16 的单应用架构,承载 K12 智慧教务系统 35 个业务模块。随着业务规模扩张与团队增长,单应用架构在以下方面暴露瓶颈: -| 维度 | 单应用瓶颈 | 微服务目标 | -|------|-----------|-----------| -| 团队协作 | 35 模块挤在同一仓库,合并冲突频繁 | 按领域拆分,6 领域团队独立迭代 | -| 部署节奏 | 全量构建发布,单模块变更牵动全站 | 服务粒度独立部署,故障爆炸半径缩小 | +| 维度 | 单应用瓶颈 | 微服务目标 | +| -------- | ---------------------------------- | ------------------------------------------------- | +| 团队协作 | 35 模块挤在同一仓库,合并冲突频繁 | 按领域拆分,6 领域团队独立迭代 | +| 部署节奏 | 全量构建发布,单模块变更牵动全站 | 服务粒度独立部署,故障爆炸半径缩小 | | 技术选型 | TypeScript 单语言,AI/分析场景受限 | TS(业务)+ Go(网关)+ Python(AI/分析)各取所长 | -| 数据规模 | 单 MySQL,跨模块联表与读放大 | 读写分离 + CQRS,ClickHouse 承载分析负载 | -| 可演进性 | 模块间隐式耦合,重构成本高 | DDD 限界上下文显式契约,演化可控 | +| 数据规模 | 单 MySQL,跨模块联表与读放大 | 读写分离 + CQRS,ClickHouse 承载分析负载 | +| 可演进性 | 模块间隐式耦合,重构成本高 | DDD 限界上下文显式契约,演化可控 | ### 1.2 迁移原则 @@ -52,29 +53,29 @@ ### 2.1 基本概况 -| 属性 | 值 | -|------|-----| -| 仓库路径 | `e:\Desktop\CICD` | -| 技术栈 | Next.js 16 + React 19 + Tailwind v4 + Drizzle ORM | -| 语言 | TypeScript(全栈) | -| 架构 | 单应用 + 严格模块化(app → modules → shared 三层) | -| 业务模块数 | 35 个 | -| 数据库 | MySQL(单库) | -| 认证 | NextAuth.js | -| 部署 | Gitea Actions + Docker standalone | +| 属性 | 值 | +| ---------- | -------------------------------------------------- | +| 仓库路径 | `e:\Desktop\CICD` | +| 技术栈 | Next.js 16 + React 19 + Tailwind v4 + Drizzle ORM | +| 语言 | TypeScript(全栈) | +| 架构 | 单应用 + 严格模块化(app → modules → shared 三层) | +| 业务模块数 | 35 个 | +| 数据库 | MySQL(单库) | +| 认证 | NextAuth.js | +| 部署 | Gitea Actions + Docker standalone | ### 2.2 模块清单(按领域归类) -| 领域 | 模块 | -|------|------| -| 身份与权限 | auth、users、onboarding、settings、permissions | -| 教学组织 | classes、teachers、students、parents、subjects | -| 教学核心 | courses、lessons、schedule、attendance、leave-requests | -| 考试评价 | exams、questions、grading、scores、analytics | -| 作业内容 | homework、textbooks、resources | -| 沟通通知 | messaging、notifications、announcements | -| 智能辅助 | ai(备课/出题/分析)、search | -| 系统支撑 | audit-logs、reports、dashboard、layout | +| 领域 | 模块 | +| ---------- | ------------------------------------------------------ | +| 身份与权限 | auth、users、onboarding、settings、permissions | +| 教学组织 | classes、teachers、students、parents、subjects | +| 教学核心 | courses、lessons、schedule、attendance、leave-requests | +| 考试评价 | exams、questions、grading、scores、analytics | +| 作业内容 | homework、textbooks、resources | +| 沟通通知 | messaging、notifications、announcements | +| 智能辅助 | ai(备课/出题/分析)、search | +| 系统支撑 | audit-logs、reports、dashboard、layout | ### 2.3 已沉淀的工程资产 @@ -94,17 +95,17 @@ ### 3.1 基本概况 -| 属性 | 值 | -|------|-----| -| 仓库路径 | `e:\Desktop\Edu` | -| 远程仓库 | https://git.eazygame.cn/xiner/Edu.git | -| 架构范式 | DDD + EDA + CQRS 微服务 | -| 语言 | TypeScript(NestJS 10)+ Go(Gin 网关)+ Python(FastAPI 分析/AI) | -| 前端 | React + Next.js + Module Federation(4 微前端) | -| monorepo 策略 | pnpm workspace + go.work + pyproject.toml (uv) | -| 事件总线 | Kafka + Debezium CDC | -| 契约 | protobuf + buf | -| 存储 | MySQL / Redis / ClickHouse / Neo4j / Elasticsearch | +| 属性 | 值 | +| ------------- | ------------------------------------------------------------------ | +| 仓库路径 | `e:\Desktop\Edu` | +| 远程仓库 | https://git.eazygame.cn/xiner/Edu.git | +| 架构范式 | DDD + EDA + CQRS 微服务 | +| 语言 | TypeScript(NestJS 10)+ Go(Gin 网关)+ Python(FastAPI 分析/AI) | +| 前端 | React + Next.js + Module Federation(4 微前端) | +| monorepo 策略 | pnpm workspace + go.work + pyproject.toml (uv) | +| 事件总线 | Kafka + Debezium CDC | +| 契约 | protobuf + buf | +| 存储 | MySQL / Redis / ClickHouse / Neo4j / Elasticsearch | ### 3.2 整体架构 @@ -164,23 +165,23 @@ flowchart TB ### 3.3 微前端与领域服务映射 -| 微前端 | 路由前缀 | 对接 BFF | 主要消费的服务 | -|--------|---------|---------|---------------| -| Admin Shell | `/admin` | Admin BFF | identity、org、insight | -| Teacher Shell | `/teacher` | Teacher BFF | teaching、content、comm | -| Student Shell | `/student` | Student/Parent BFF | teaching、content | -| Parent Shell | `/parent` | Student/Parent BFF | teaching、comm | +| 微前端 | 路由前缀 | 对接 BFF | 主要消费的服务 | +| ------------- | ---------- | ------------------ | ----------------------- | +| Admin Shell | `/admin` | Admin BFF | identity、org、insight | +| Teacher Shell | `/teacher` | Teacher BFF | teaching、content、comm | +| Student Shell | `/student` | Student/Parent BFF | teaching、content | +| Parent Shell | `/parent` | Student/Parent BFF | teaching、comm | -| 微服务 | 原始模块映射 | 主存储 | 对外契约 | -|--------|------------|--------|---------| -| identity | auth、users、onboarding、settings、permissions | MySQL + Redis | identity.proto | -| org | classes、teachers、students、parents、subjects | MySQL | org.proto | -| teaching | courses、lessons、schedule、attendance、leave-requests、exams、homework | MySQL | teaching.proto | -| content | textbooks、resources、questions、grading | MySQL + Elasticsearch | content.proto | -| comm | messaging、notifications、announcements | MySQL + Redis | comm.proto | -| insight | scores、analytics、ai、search、reports、dashboard | ClickHouse + Neo4j | insight.proto | -| auth(基础设施) | NextAuth 逻辑下沉 | MySQL + Redis | auth.proto | -| notification(基础设施) | notifications channel 抽离 | MySQL + Redis | notification.proto | +| 微服务 | 原始模块映射 | 主存储 | 对外契约 | +| ------------------------ | ----------------------------------------------------------------------- | --------------------- | ------------------ | +| identity | auth、users、onboarding、settings、permissions | MySQL + Redis | identity.proto | +| org | classes、teachers、students、parents、subjects | MySQL | org.proto | +| teaching | courses、lessons、schedule、attendance、leave-requests、exams、homework | MySQL | teaching.proto | +| content | textbooks、resources、questions、grading | MySQL + Elasticsearch | content.proto | +| comm | messaging、notifications、announcements | MySQL + Redis | comm.proto | +| insight | scores、analytics、ai、search、reports、dashboard | ClickHouse + Neo4j | insight.proto | +| auth(基础设施) | NextAuth 逻辑下沉 | MySQL + Redis | auth.proto | +| notification(基础设施) | notifications channel 抽离 | MySQL + Redis | notification.proto | --- @@ -190,65 +191,65 @@ flowchart TB ### 4.1 规范类资产 -| 资产 | 策略 | 说明 | -|------|------|------| -| 项目规则(project_rules) | 调整 | 架构图优先保留,分层规则从三层改为微服务分层,新增 DDD/契约/事件驱动规则 | -| 编码规范(coding-standards) | 调整 | TS 部分保留并补充 NestJS 装饰器/DI 规则,新增 Go、Python、protobuf 章节 | -| Git 工作流 | 调整 | trunk-based 替代分支策略,scope 改为服务/包名,新增多语言 monorepo 提交规则 | -| 提交规范(Conventional Commits) | 直接迁移 | 类型与格式完全沿用 | -| 设计令牌规范 | 调整 | 分层模型保留,分布位置从 `src/app/styles/tokens/` 改为微前端共享包 | -| 安全规范 | 直接迁移 | Cookie 策略、env 校验、XSS 防护、权限校验规则全部沿用 | -| 问题记录规则 | 直接迁移 | known-issues.md 索引式速查手册模式沿用 | -| A11y 规范 | 直接迁移 | WCAG 2.2 AA 目标与工具集沿用 | +| 资产 | 策略 | 说明 | +| -------------------------------- | -------- | --------------------------------------------------------------------------- | +| 项目规则(project_rules) | 调整 | 架构图优先保留,分层规则从三层改为微服务分层,新增 DDD/契约/事件驱动规则 | +| 编码规范(coding-standards) | 调整 | TS 部分保留并补充 NestJS 装饰器/DI 规则,新增 Go、Python、protobuf 章节 | +| Git 工作流 | 调整 | trunk-based 替代分支策略,scope 改为服务/包名,新增多语言 monorepo 提交规则 | +| 提交规范(Conventional Commits) | 直接迁移 | 类型与格式完全沿用 | +| 设计令牌规范 | 调整 | 分层模型保留,分布位置从 `src/app/styles/tokens/` 改为微前端共享包 | +| 安全规范 | 直接迁移 | Cookie 策略、env 校验、XSS 防护、权限校验规则全部沿用 | +| 问题记录规则 | 直接迁移 | known-issues.md 索引式速查手册模式沿用 | +| A11y 规范 | 直接迁移 | WCAG 2.2 AA 目标与工具集沿用 | ### 4.2 代码类资产 -| 资产 | 策略 | 说明 | -|------|------|------| -| Zod schema 定义 | 直接迁移 | 各模块 schema.ts 平移至对应微服务,复用验证规则 | -| 权限点常量(Permissions) | 直接迁移 | 集中迁入 identity 服务共享包 | -| Drizzle schema(表结构) | 调整 | 按领域拆分到各微服务独占库,关系型字段保持不变 | -| ActionState 类型 | 直接迁移 | 升级为 protobuf message,结构不变 | -| Server Actions | 重写 | 改写为 NestJS Controller + Service + Application Service 三层 | -| data-access 层 | 重写 | 改写为 NestJS Repository + Domain Entity | -| UI 组件(shared/components) | 直接迁移 | 平移至微前端共享包,保持 PascalCase 命名 | -| Hook(useAuth、usePermission) | 调整 | 改为通过 BFF/gRPC client 获取,接口签名保持不变 | -| 缓存层(cacheFn) | 重写 | 改为 NestJS Cache 模块 + Redis,去除 React cache() | -| arch:scan 工具 | 调整 | 扫描器扩展为多语言(TS+Go+Python),数据库结构保持 | -| 审计日志三件套 | 直接迁移 | 平移至 notification 服务,日志结构保持 | -| CI/CD 流水线 | 重写 | Gitea Actions 改为多服务并行流水线,新增契约校验阶段 | +| 资产 | 策略 | 说明 | +| ------------------------------ | -------- | ------------------------------------------------------------- | +| Zod schema 定义 | 直接迁移 | 各模块 schema.ts 平移至对应微服务,复用验证规则 | +| 权限点常量(Permissions) | 直接迁移 | 集中迁入 identity 服务共享包 | +| Drizzle schema(表结构) | 调整 | 按领域拆分到各微服务独占库,关系型字段保持不变 | +| ActionState 类型 | 直接迁移 | 升级为 protobuf message,结构不变 | +| Server Actions | 重写 | 改写为 NestJS Controller + Service + Application Service 三层 | +| data-access 层 | 重写 | 改写为 NestJS Repository + Domain Entity | +| UI 组件(shared/components) | 直接迁移 | 平移至微前端共享包,保持 PascalCase 命名 | +| Hook(useAuth、usePermission) | 调整 | 改为通过 BFF/gRPC client 获取,接口签名保持不变 | +| 缓存层(cacheFn) | 重写 | 改为 NestJS Cache 模块 + Redis,去除 React cache() | +| arch:scan 工具 | 调整 | 扫描器扩展为多语言(TS+Go+Python),数据库结构保持 | +| 审计日志三件套 | 直接迁移 | 平移至 notification 服务,日志结构保持 | +| CI/CD 流水线 | 重写 | Gitea Actions 改为多服务并行流水线,新增契约校验阶段 | ### 4.3 文档类资产 -| 资产 | 策略 | 说明 | -|------|------|------| -| 架构影响地图(004) | 重写 | 从单应用模块图改为微服务限界上下文图 | -| K12 功能清单(006) | 直接迁移 | 功能清单与架构无关,直接平移 | -| 差距审计报告(007) | 调整 | 重新审计各微服务的功能完成度 | -| 模块角色映射(008) | 直接迁移 | 角色权限矩阵不变 | -| 路线图(roadmap/) | 重写 | 6 阶段微服务路线图 | -| known-issues.md | 直接迁移 | 经验日志平移,新增"微服务"分区 | -| 各模块 README | 重写 | 改为各微服务 README,按 DDD 上下文描述 | +| 资产 | 策略 | 说明 | +| ------------------- | -------- | -------------------------------------- | +| 架构影响地图(004) | 重写 | 从单应用模块图改为微服务限界上下文图 | +| K12 功能清单(006) | 直接迁移 | 功能清单与架构无关,直接平移 | +| 差距审计报告(007) | 调整 | 重新审计各微服务的功能完成度 | +| 模块角色映射(008) | 直接迁移 | 角色权限矩阵不变 | +| 路线图(roadmap/) | 重写 | 6 阶段微服务路线图 | +| known-issues.md | 直接迁移 | 经验日志平移,新增"微服务"分区 | +| 各模块 README | 重写 | 改为各微服务 README,按 DDD 上下文描述 | --- ## 五、文档体系映射表 -| CICD 文档 | Edu 对应文档 | 关系 | -|-----------|------------|------| -| `.trae/rules/project_rules.md` | `project_rules.md` | 调整(微服务版) | -| `docs/standards/coding-standards.md` | `docs/standards/coding-standards.md` | 调整(多语言版) | -| —(散落在 project_rules) | `docs/standards/git-workflow.md` | 新建 | -| `docs/architecture/004_architecture_impact_map.md` | `docs/architecture/001_architecture_overview.md` | 重写 | -| `docs/architecture/006_k12_feature_checklist.md` | `docs/architecture/feature_checklist.md` | 直接迁移 | -| `docs/architecture/007_gap_audit_report.md` | `docs/architecture/gap_audit.md` | 调整 | -| `docs/architecture/008_module_role_mapping.md` | `docs/architecture/role_mapping.md` | 直接迁移 | -| `docs/architecture/roadmap/README.md` | `docs/architecture/roadmap/README.md` | 重写 | -| `docs/architecture/roadmap/tech-debt.md` | `docs/architecture/roadmap/tech-debt.md` | 重写 | -| `docs/architecture/roadmap/decoupling.md` | `docs/architecture/roadmap/migration_phases.md` | 重写(迁移阶段化) | -| `docs/troubleshooting/known-issues.md` | `docs/troubleshooting/known-issues.md` | 直接迁移 + 新分区 | -| `src/modules/[module]/README.md` | `services/[service]/README.md` | 重写 | -| `docs/standards/coding-standards.md` §A11y | `docs/standards/accessibility.md` | 拆分独立 | +| CICD 文档 | Edu 对应文档 | 关系 | +| -------------------------------------------------- | ------------------------------------------------ | ------------------ | +| `.trae/rules/project_rules.md` | `project_rules.md` | 调整(微服务版) | +| `docs/standards/coding-standards.md` | `docs/standards/coding-standards.md` | 调整(多语言版) | +| —(散落在 project_rules) | `docs/standards/git-workflow.md` | 新建 | +| `docs/architecture/004_architecture_impact_map.md` | `docs/architecture/001_architecture_overview.md` | 重写 | +| `docs/architecture/006_k12_feature_checklist.md` | `docs/architecture/feature_checklist.md` | 直接迁移 | +| `docs/architecture/007_gap_audit_report.md` | `docs/architecture/gap_audit.md` | 调整 | +| `docs/architecture/008_module_role_mapping.md` | `docs/architecture/role_mapping.md` | 直接迁移 | +| `docs/architecture/roadmap/README.md` | `docs/architecture/roadmap/README.md` | 重写 | +| `docs/architecture/roadmap/tech-debt.md` | `docs/architecture/roadmap/tech-debt.md` | 重写 | +| `docs/architecture/roadmap/decoupling.md` | `docs/architecture/roadmap/migration_phases.md` | 重写(迁移阶段化) | +| `docs/troubleshooting/known-issues.md` | `docs/troubleshooting/known-issues.md` | 直接迁移 + 新分区 | +| `src/modules/[module]/README.md` | `services/[service]/README.md` | 重写 | +| `docs/standards/coding-standards.md` §A11y | `docs/standards/accessibility.md` | 拆分独立 | --- @@ -283,14 +284,14 @@ gantt ### 6.2 各阶段目标 -| 阶段 | 名称 | 目标 | 关键交付物 | 验收信号 | -|------|------|------|-----------|---------| -| P1 | 地基 | 仓库骨架、契约工具链、CI、可观测平台 | monorepo 结构、buf 配置、Kafka 集群、OpenTelemetry | 契约生成 + 一次端到端 trace | -| P2 | 身份 | identity + auth + notification 三服务打通 | JWT 颁发、RBAC、邮件/短信/站内通知 | 用户注册→登录→收到通知 | -| P3 | 核心教学 | org + teaching + content | 班级/课表/作业/题库/考试 | 教师创建作业→学生提交→批改闭环 | -| P4 | 内容分析 | insight + CQRS 读模型 + ES 全文检索 | ClickHouse 报表、ES 搜索、Neo4j 知识图谱 | 多维分析报表 + 全文搜索可用 | -| P5 | 沟通AI | comm + AI 辅助 | 站内信/通知中心、AI 备课/出题/答疑 | 教师用 AI 出题并发布到班级 | -| P6 | 硬化 | 安全加固、灾备、性能、混沌工程 | WAF、定期备份、压测报告、混沌演练 | RPO≤15min、RTO≤30min、P99≤500ms | +| 阶段 | 名称 | 目标 | 关键交付物 | 验收信号 | +| ---- | -------- | ----------------------------------------- | -------------------------------------------------- | ------------------------------- | +| P1 | 地基 | 仓库骨架、契约工具链、CI、可观测平台 | monorepo 结构、buf 配置、Kafka 集群、OpenTelemetry | 契约生成 + 一次端到端 trace | +| P2 | 身份 | identity + auth + notification 三服务打通 | JWT 颁发、RBAC、邮件/短信/站内通知 | 用户注册→登录→收到通知 | +| P3 | 核心教学 | org + teaching + content | 班级/课表/作业/题库/考试 | 教师创建作业→学生提交→批改闭环 | +| P4 | 内容分析 | insight + CQRS 读模型 + ES 全文检索 | ClickHouse 报表、ES 搜索、Neo4j 知识图谱 | 多维分析报表 + 全文搜索可用 | +| P5 | 沟通AI | comm + AI 辅助 | 站内信/通知中心、AI 备课/出题/答疑 | 教师用 AI 出题并发布到班级 | +| P6 | 硬化 | 安全加固、灾备、性能、混沌工程 | WAF、定期备份、压测报告、混沌演练 | RPO≤15min、RTO≤30min、P99≤500ms | ### 6.3 阶段交付门槛 @@ -310,15 +311,16 @@ gantt **复用方式**:将 CICD 的 `src/app/styles/tokens/` 五层分层模型平移至微前端共享包。 -| CICD 位置 | Edu 位置 | 调整 | -|-----------|---------|------| -| `src/app/styles/tokens/primitive.css` | `packages/ui-tokens/primitive.css` | 直接平移 | -| `src/app/styles/tokens/semantic-light.css` | `packages/ui-tokens/semantic-light.css` | 直接平移 | -| `src/app/styles/tokens/semantic-dark.css` | `packages/ui-tokens/semantic-dark.css` | 直接平移 | +| CICD 位置 | Edu 位置 | 调整 | +| ---------------------------------------------- | ------------------------------------------- | -------- | +| `src/app/styles/tokens/primitive.css` | `packages/ui-tokens/primitive.css` | 直接平移 | +| `src/app/styles/tokens/semantic-light.css` | `packages/ui-tokens/semantic-light.css` | 直接平移 | +| `src/app/styles/tokens/semantic-dark.css` | `packages/ui-tokens/semantic-dark.css` | 直接平移 | | `src/app/styles/tokens/lesson-preparation.css` | `packages/ui-tokens/lesson-preparation.css` | 直接平移 | -| `src/app/styles/tokens/tailwind-theme.css` | `packages/ui-tokens/tailwind-theme.css` | 直接平移 | +| `src/app/styles/tokens/tailwind-theme.css` | `packages/ui-tokens/tailwind-theme.css` | 直接平移 | **强制规则保持不变**: + - 禁止硬编码颜色(`#hex`) - 禁止硬编码字体(`'Inter'`/`'Fraunces'`/`'JetBrains Mono'`) - 禁止硬编码字号(`font-size: Npx`) @@ -329,14 +331,15 @@ gantt **复用方式**:将 CICD 的 `src/shared/components/ui/` 平移至 `packages/ui-components/`,作为 Module Federation 共享依赖。 -| 组件类别 | CICD 路径 | Edu 路径 | 复用要点 | -|---------|----------|---------|---------| -| 基础组件(Button/Input/Dialog) | `shared/components/ui/` | `packages/ui-components/` | 全部平移,保持 PascalCase 命名 | -| A11y 组件 | `shared/components/a11y/` | `packages/ui-components/a11y/` | skip-link、visually-hidden、focus-trap、aria-status 全部平移 | -| 图表组件 | 各模块内 | `packages/ui-components/charts/` | 收集 recharts 封装,统一暴露 | -| 表单组件 | react-hook-form 封装 | `packages/ui-components/form/` | 与 zod resolver 一同平移 | +| 组件类别 | CICD 路径 | Edu 路径 | 复用要点 | +| ------------------------------- | ------------------------- | -------------------------------- | ------------------------------------------------------------ | +| 基础组件(Button/Input/Dialog) | `shared/components/ui/` | `packages/ui-components/` | 全部平移,保持 PascalCase 命名 | +| A11y 组件 | `shared/components/a11y/` | `packages/ui-components/a11y/` | skip-link、visually-hidden、focus-trap、aria-status 全部平移 | +| 图表组件 | 各模块内 | `packages/ui-components/charts/` | 收集 recharts 封装,统一暴露 | +| 表单组件 | react-hook-form 封装 | `packages/ui-components/form/` | 与 zod resolver 一同平移 | **复用规则**: + - 组件必须为纯函数,使用 `function` 声明 - 不使用 `React.FC`,直接用函数声明 + 显式标注 props 类型 - 默认服务端组件(微前端 host),需要交互时才添加 `"use client"` @@ -346,14 +349,15 @@ gantt **复用方式**:将 CICD 的 `requirePermission()` + `usePermission().hasPermission()` 模式平移至 identity 服务 + auth 基础设施服务。 -| CICD 资产 | Edu 位置 | 调整 | -|-----------|---------|------| -| `shared/lib/auth-guard.ts`(requirePermission) | `services/auth/src/guards/permission.guard.ts`(NestJS Guard) | 改为 NestJS Guard 装饰器 | -| `shared/types/permissions.ts`(权限点常量) | `packages/contracts/src/permissions.ts` | 集中到 contracts 包,多服务共享 | -| `usePermission` Hook | `packages/ui-components/hooks/use-permission.ts` | 通过 BFF 拉取权限,Hook 接口不变 | -| 角色权限矩阵(008) | `docs/architecture/role_mapping.md` | 直接平移 | +| CICD 资产 | Edu 位置 | 调整 | +| ----------------------------------------------- | -------------------------------------------------------------- | -------------------------------- | +| `shared/lib/auth-guard.ts`(requirePermission) | `services/auth/src/guards/permission.guard.ts`(NestJS Guard) | 改为 NestJS Guard 装饰器 | +| `shared/types/permissions.ts`(权限点常量) | `packages/contracts/src/permissions.ts` | 集中到 contracts 包,多服务共享 | +| `usePermission` Hook | `packages/ui-components/hooks/use-permission.ts` | 通过 BFF 拉取权限,Hook 接口不变 | +| 角色权限矩阵(008) | `docs/architecture/role_mapping.md` | 直接平移 | **强制规则保持不变**: + - 每个 Controller/Action 必须调用 `requirePermission()` 等价物 - 前端组件禁止使用 `role === "xxx"` 硬编码,统一使用 `usePermission().hasPermission()` @@ -361,36 +365,36 @@ gantt **复用方式**:CICD 的 `cacheFn`(React `cache()` + 自定义缓存层)改为 NestJS Cache 模块 + Redis,**权限数据不跨请求缓存**的规则沿用。 -| CICD 模式 | Edu 模式 | 备注 | -|-----------|---------|------| +| CICD 模式 | Edu 模式 | 备注 | +| ------------------------ | --------------------------------------------------- | ------------------------------------- | | `cacheFn`(React cache) | NestJS `@UseInterceptors(CacheInterceptor)` + Redis | 单请求内缓存改为 NestJS REQUEST scope | -| `unstable_cache` | 禁用 | CICD 已禁用,Edu 沿用禁用决策 | -| 权限数据缓存 | 仅在 auth 服务内部缓存,TTL ≤ 60s | 跨服务不缓存权限 | -| 静态资源缓存 | CDN + 短缓存 | 配置不变 | +| `unstable_cache` | 禁用 | CICD 已禁用,Edu 沿用禁用决策 | +| 权限数据缓存 | 仅在 auth 服务内部缓存,TTL ≤ 60s | 跨服务不缓存权限 | +| 静态资源缓存 | CDN + 短缓存 | 配置不变 | ### 7.5 Server Action 模式 → Application Service 模式 **复用方式**:CICD 的 Server Action 编排模式(权限 + Zod 验证 + 调用 data-access + revalidate)平移为 NestJS Application Service 编排模式。 -| CICD Server Action 步骤 | NestJS Application Service 对应 | -|------------------------|-------------------------------| -| `requirePermission(perm)` | `@RequirePermission(perm)` 装饰器 + Guard | -| Zod `safeParse` | `ValidationPipe` + DTO class-validator | -| 调用 `data-access` | 调用 Domain Service / Repository | -| `revalidatePath` | 发布领域事件触发读模型更新 | -| 返回 `ActionState` | 返回 protobuf message(结构同 ActionState) | +| CICD Server Action 步骤 | NestJS Application Service 对应 | +| ------------------------- | ------------------------------------------- | +| `requirePermission(perm)` | `@RequirePermission(perm)` 装饰器 + Guard | +| Zod `safeParse` | `ValidationPipe` + DTO class-validator | +| 调用 `data-access` | 调用 Domain Service / Repository | +| `revalidatePath` | 发布领域事件触发读模型更新 | +| 返回 `ActionState` | 返回 protobuf message(结构同 ActionState) | ### 7.6 状态管理 5 层模型 **复用方式**:CICD 的 5 层状态模型平移至微前端 host 应用。 -| 层级 | CICD 方案 | Edu 方案 | 备注 | -|------|----------|---------|------| -| L1 URL | nuqs | nuqs | 直接平移 | -| L2 Server | TanStack Query | TanStack Query | 直接平移 | -| L3 Client Business | Zustand slice | Zustand slice | 直接平移 | -| L4 Global UI | Zustand ui-store + ModalRoot | Zustand ui-store + ModalRoot | 直接平移 | -| L5 Form | react-hook-form + zodResolver | react-hook-form + zodResolver | 直接平移 | +| 层级 | CICD 方案 | Edu 方案 | 备注 | +| ------------------ | ----------------------------- | ----------------------------- | -------- | +| L1 URL | nuqs | nuqs | 直接平移 | +| L2 Server | TanStack Query | TanStack Query | 直接平移 | +| L3 Client Business | Zustand slice | Zustand slice | 直接平移 | +| L4 Global UI | Zustand ui-store + ModalRoot | Zustand ui-store + ModalRoot | 直接平移 | +| L5 Form | react-hook-form + zodResolver | react-hook-form + zodResolver | 直接平移 | ### 7.7 A11y 工具集 @@ -409,23 +413,24 @@ gantt **复用方式**:平移至 notification 服务,日志结构保持。 -| CICD 资产 | Edu 位置 | 备注 | -|-----------|---------|------| -| `shared/lib/login-logger.ts` | `services/notification/src/loggers/login-logger.ts` | 登录尝试日志 | +| CICD 资产 | Edu 位置 | 备注 | +| ----------------------------- | ---------------------------------------------------- | ---------------------------- | +| `shared/lib/login-logger.ts` | `services/notification/src/loggers/login-logger.ts` | 登录尝试日志 | | `shared/lib/change-logger.ts` | `services/notification/src/loggers/change-logger.ts` | 数据变更日志(监听领域事件) | -| `shared/lib/audit-logger.ts` | `services/notification/src/loggers/audit-logger.ts` | 关键业务操作日志 | +| `shared/lib/audit-logger.ts` | `services/notification/src/loggers/audit-logger.ts` | 关键业务操作日志 | ### 7.9 CI/CD 流水线模式 **复用方式**:三套工作流模式沿用(CI + 安全扫描 + 灾备演练),但执行方式改为多服务并行。 -| CICD 工作流 | Edu 工作流 | 调整 | -|------------|-----------|------| -| `ci.yml` | `.gitea/workflows/ci.yml` | 单体改为矩阵并行(每个服务一个 job) | -| `security.yml` | `.gitea/workflows/security.yml` | 新增 Trivy 扫描 Docker 镜像 | -| `dr-drill.yml` | `.gitea/workflows/dr-drill.yml` | 灾备演练改为多服务恢复顺序演练 | +| CICD 工作流 | Edu 工作流 | 调整 | +| -------------- | ------------------------------- | ------------------------------------ | +| `ci.yml` | `.gitea/workflows/ci.yml` | 单体改为矩阵并行(每个服务一个 job) | +| `security.yml` | `.gitea/workflows/security.yml` | 新增 Trivy 扫描 Docker 镜像 | +| `dr-drill.yml` | `.gitea/workflows/dr-drill.yml` | 灾备演练改为多服务恢复顺序演练 | **CI 必须包含**(沿用 CICD 规则): + 1. 安装依赖(多语言:pnpm install / go mod download / uv sync) 2. Lint 检查(ESLint + golangci-lint + ruff) 3. 类型检查(tsc --noEmit + go vet + mypy) @@ -478,15 +483,15 @@ gantt ## 附录:迁移过程中的关键决策点 -| 决策点 | 选择 | 理由 | -|--------|------|------| -| 服务拆分粒度 | 6 业务 + 2 基础设施 | 平衡团队规模与拆分收益,避免过细导致 RPC 开销 | -| 通信协议 | gRPC(内部)+ REST(BFF 对外) | 内部高性能,外部兼容性 | -| 事件总线 | Kafka + Debezium CDC | CDC 减少业务代码侵入,Outbox 模式保证一致性 | -| 契约工具 | protobuf + buf | 多语言代码生成,breaking change 检测 | -| 前端架构 | Module Federation | 微前端独立部署,运行时共享依赖 | -| 状态管理 | 沿用 5 层模型 | 团队熟悉度高,迁移成本低 | -| 数据库拆分 | 每服务独占库 | 杜绝跨服务联表,强制契约化通信 | -| 缓存策略 | NestJS Cache + Redis | 替代 React cache(),规则(权限不跨请求缓存)沿用 | -| 迁移方式 | strangler fig | 风险可控,渐进式切换 | -| arch.db | 多语言扫描扩展 | 复用 CICD 元数据库思路,扩展 Go/Python 扫描器 | +| 决策点 | 选择 | 理由 | +| ------------ | ------------------------------ | ------------------------------------------------ | +| 服务拆分粒度 | 6 业务 + 2 基础设施 | 平衡团队规模与拆分收益,避免过细导致 RPC 开销 | +| 通信协议 | gRPC(内部)+ REST(BFF 对外) | 内部高性能,外部兼容性 | +| 事件总线 | Kafka + Debezium CDC | CDC 减少业务代码侵入,Outbox 模式保证一致性 | +| 契约工具 | protobuf + buf | 多语言代码生成,breaking change 检测 | +| 前端架构 | Module Federation | 微前端独立部署,运行时共享依赖 | +| 状态管理 | 沿用 5 层模型 | 团队熟悉度高,迁移成本低 | +| 数据库拆分 | 每服务独占库 | 杜绝跨服务联表,强制契约化通信 | +| 缓存策略 | NestJS Cache + Redis | 替代 React cache(),规则(权限不跨请求缓存)沿用 | +| 迁移方式 | strangler fig | 风险可控,渐进式切换 | +| arch.db | 多语言扫描扩展 | 复用 CICD 元数据库思路,扩展 Go/Python 扫描器 | diff --git a/README.md b/README.md index 76c477c..ea42a93 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ pnpm dev - [UI 设计系统](docs/standards/ui-design-system.md) - [Git 工作流](docs/standards/git-workflow.md) - [已知问题](docs/troubleshooting/known-issues.md) -- [项目规则](project_rules.md) +- [项目规则](.trae/rules/project_rules.md) - [迁移指南](MIGRATION_GUIDE.md) ## 开发阶段 diff --git a/docs/standards/coding-standards.md b/docs/standards/coding-standards.md index 840ad53..71a5687 100644 --- a/docs/standards/coding-standards.md +++ b/docs/standards/coding-standards.md @@ -5,7 +5,8 @@ > 状态:基线发布 > 适用范围:Edu 微服务架构(TS + Go + Python + protobuf) > 关联文档: -> - [项目规则](../../project_rules.md) +> +> - [项目规则](../../.trae/rules/project_rules.md) > - [迁移指南](../../MIGRATION_GUIDE.md) > - [Git 工作流](./git-workflow.md) > - [架构总览](../architecture/001_architecture_overview.md) @@ -85,7 +86,7 @@ import type { UserEntity } from "@/modules/user/domain/user.entity"; #### 2.4.1 模块组织 -每个 NestJS 模块对应一个 DDD 聚合,结构见 [project_rules.md §4.1](../../project_rules.md#41-nestjs-业务微服务标准结构)。 +每个 NestJS 模块对应一个 DDD 聚合,结构见 [project_rules.md §3.3](../../.trae/rules/project_rules.md#33-模块标准结构ddd)。 #### 2.4.2 装饰器规则 @@ -111,6 +112,7 @@ export class UserController { ``` **规则**: + - Controller 必须使用 `@Controller(path)` 装饰器,path 使用 kebab-case 复数 - Controller 类必须使用 `@RequirePermission()` 装饰器(类级默认权限) - 每个 Handler 可选覆盖类级权限(更细粒度) @@ -131,6 +133,7 @@ export class UserService { ``` **规则**: + - 依赖通过构造函数注入,使用 `readonly` 修饰符 - 接口绑定在 Module 的 `providers` 中:`{ provide: "UserRepository", useClass: UserRepoImpl }` - 禁止使用属性注入(`@Inject()` 属性装饰器) @@ -152,6 +155,7 @@ export class UserModule {} ``` **规则**: + - Module 类名 PascalCase + `Module` 后缀 - `exports` 仅暴露 Application Service,不暴露 Repository - 跨 Module 通信通过 exports 的 Service,不直接访问对方 Repository @@ -190,6 +194,7 @@ export class GetUserByIdHandler implements IQueryHandler { ``` **规则**: + - Command 走写路径:Command → Handler → Domain → Repository → MySQL + Outbox - Query 走读路径:Query → Handler → Read Model(禁止查主库) - Command Handler 必须在事务内写 Outbox 表 @@ -207,7 +212,12 @@ export class UserEntity { ) {} static create(props: UserCreateProps): UserEntity { - return new UserEntity(crypto.randomUUID(), props.email, props.name, new Date()); + return new UserEntity( + crypto.randomUUID(), + props.email, + props.name, + new Date(), + ); } rename(newName: string): UserRenamedEvent { @@ -218,6 +228,7 @@ export class UserEntity { ``` **规则**: + - Entity 构造函数私有,通过静态工厂方法创建 - Entity 字段私有,通过方法变更状态 - 状态变更方法返回领域事件,由 Application Service 发布 @@ -239,6 +250,7 @@ export class CreateUserDto { ``` **规则**: + - DTO 类名 `Create[Entity]Dto` / `Update[Entity]Dto` / `[Entity]Response` - DTO 字段使用 `readonly` 修饰 - 使用 `class-validator` 装饰器校验 @@ -264,13 +276,13 @@ export class CreateUserDto { ### 2.10 状态管理(沿用 CICD 5 层模型) -| 层级 | 场景 | 方案 | -|------|------|------| -| L1 URL | 可分享、可刷新的状态 | nuqs | -| L2 Server | 服务端数据 | TanStack Query | -| L3 Client Business | 客户端业务状态 | Zustand slice | -| L4 Global UI | 全局 UI 状态 | Zustand ui-store + ModalRoot | -| L5 Form | 表单状态 | react-hook-form + zodResolver | +| 层级 | 场景 | 方案 | +| ------------------ | -------------------- | ----------------------------- | +| L1 URL | 可分享、可刷新的状态 | nuqs | +| L2 Server | 服务端数据 | TanStack Query | +| L3 Client Business | 客户端业务状态 | Zustand slice | +| L4 Global UI | 全局 UI 状态 | Zustand ui-store + ModalRoot | +| L5 Form | 表单状态 | react-hook-form + zodResolver | --- @@ -328,6 +340,7 @@ user, _ := h.userService.GetUser(ctx, id) ``` **规则**: + - 错误必须显式处理,**禁止 `_ = err`** - 使用 `errors.Is` 和 `errors.As` 判断错误类型,禁止字符串匹配 - 自定义错误类型使用 `fmt.Errorf("...: %w", err)` 包装 @@ -349,6 +362,7 @@ type UserService struct { ``` **规则**: + - `context.Context` 作为函数第一个参数传递 - **禁止**将 context 存储在结构体字段中 - 超时/取消通过 context 传递,禁止使用 `time.Sleep` 等待 @@ -368,6 +382,7 @@ if err := g.Wait(); err != nil { ``` **规则**: + - 优先使用 `errgroup` 管理并发 goroutine - 禁止裸 `go func()` 不带 recover 和 context - 共享状态使用 channel 或 `sync` 包,禁止使用 `sync.Mutex` 嵌套锁 @@ -388,6 +403,7 @@ func RegisterRoutes(r *gin.Engine, h *Handler, mw *Middleware) { ``` **规则**: + - 路由分组按 API 版本(`/api/v1`) - 中间件链顺序:Recovery → RequestID → Logger → RateLimit → Auth → RequirePermission - Handler 函数签名固定:`func(c *gin.Context)` @@ -404,6 +420,7 @@ logger.Info("user login", "user_id", userID, "ip", ip) ``` **规则**: + - 使用标准库 `log/slog` 结构化日志 - 日志字段使用 kebab-case key - 必须包含 `request_id` 用于链路追踪 @@ -459,6 +476,7 @@ def get_user(user_id): ``` **规则**: + - 所有函数必须标注参数和返回值类型 - 使用 `from __future__ import annotations` 启用延迟注解求值 - 使用 `Optional[T]` 或 `T | None`(Python 3.10+)标注可选类型 @@ -480,6 +498,7 @@ async def fetch_user(user_id: str) -> User: ``` **规则**: + - I/O 操作(HTTP、DB、文件)必须使用 async/await - 禁止在 async 函数中调用同步阻塞 I/O,必须用 `asyncio.to_thread` 或 async 客户端 - CPU 密集任务用 `asyncio.to_thread` 或进程池 @@ -509,6 +528,7 @@ class UserResponse(BaseModel): ``` **规则**: + - 请求模型命名 `[Action][Entity]Request`,响应模型命名 `[Entity]Response` - 必须使用 `Field` 添加描述、约束 - 复杂校验使用 `@field_validator` 或 `@model_validator` @@ -534,6 +554,7 @@ async def get_user( ``` **规则**: + - 路由分组使用 `APIRouter`,按 API 版本组织 - 必须标注 `response_model` - 权限校验通过 `Depends` 注入,每个 endpoint 显式调用 `require_permission` @@ -557,6 +578,7 @@ settings = Settings() ``` **规则**: + - 配置使用 `pydantic-settings` 的 `BaseSettings` - 环境变量前缀按服务名(`INSIGHT_AI_`) - 禁止在业务代码中直接读取环境变量(`os.getenv`),统一通过 `settings` @@ -567,39 +589,40 @@ settings = Settings() ### 5.1 命名通用规则 -| 对象 | 风格 | 示例 | -|------|------|------| -| 目录 | kebab-case | `user-profile/` | -| 常量 | UPPER_SNAKE_CASE | `MAX_RETRY_COUNT` | -| 布尔值 | `is/has/can/should` 前缀 | `isVisible`、`is_active`、`hasPermission` | -| 类/接口/结构体 | PascalCase | `UserService`、`UserFetcher` | -| 服务名 | 小写单数 | `identity`、`teaching` | -| Kafka topic | 点分小写 | `edu.identity.user.created` | -| protobuf message | PascalCase | `UserCreatedEvent` | -| protobuf 字段 | snake_case | `user_id`、`created_at` | +| 对象 | 风格 | 示例 | +| ---------------- | ------------------------ | ----------------------------------------- | +| 目录 | kebab-case | `user-profile/` | +| 常量 | UPPER_SNAKE_CASE | `MAX_RETRY_COUNT` | +| 布尔值 | `is/has/can/should` 前缀 | `isVisible`、`is_active`、`hasPermission` | +| 类/接口/结构体 | PascalCase | `UserService`、`UserFetcher` | +| 服务名 | 小写单数 | `identity`、`teaching` | +| Kafka topic | 点分小写 | `edu.identity.user.created` | +| protobuf message | PascalCase | `UserCreatedEvent` | +| protobuf 字段 | snake_case | `user_id`、`created_at` | ### 5.2 文件行数通用规则 -| 文件类型 | 建议行数 | 硬性上限 | -|---------|---------|---------| -| 配置/常量/类型/proto | 无限制 | 无限制 | -| React 组件 | ≤ 500 | 800 | -| NestJS Controller/Service | ≤ 500 | 800 | -| Go handler/middleware | ≤ 400 | 600 | -| Python endpoint/service | ≤ 400 | 600 | -| 工具函数 | ≤ 40 | - | -| 自定义 Hook | ≤ 80 | - | -| **任何文件** | - | **1000,超过必须拆分** | +| 文件类型 | 建议行数 | 硬性上限 | +| ------------------------- | -------- | ---------------------- | +| 配置/常量/类型/proto | 无限制 | 无限制 | +| React 组件 | ≤ 500 | 800 | +| NestJS Controller/Service | ≤ 500 | 800 | +| Go handler/middleware | ≤ 400 | 600 | +| Python endpoint/service | ≤ 400 | 600 | +| 工具函数 | ≤ 40 | - | +| 自定义 Hook | ≤ 80 | - | +| **任何文件** | - | **1000,超过必须拆分** | ### 5.3 错误处理通用规则 -| 语言 | 规则 | -|------|------| +| 语言 | 规则 | +| ---------- | -------------------------------------------------------------- | | TypeScript | 错误通过抛出异常,Application Service 必须捕获并转为结构化响应 | -| Go | 错误必须显式处理,禁止 `_ = err`,使用 `errors.Is/As` 判断类型 | -| Python | 使用异常层次结构,自定义异常继承 `Exception`,禁止裸 `except:` | +| Go | 错误必须显式处理,禁止 `_ = err`,使用 `errors.Is/As` 判断类型 | +| Python | 使用异常层次结构,自定义异常继承 `Exception`,禁止裸 `except:` | **通用规则**: + - 错误信息对内详细(含上下文、堆栈),对外脱敏(不泄露实现细节) - 错误必须分类:业务错误(4xx)、系统错误(5xx)、依赖错误(502/503) - 错误必须记录日志,包含 request_id 用于链路追踪 @@ -607,13 +630,14 @@ settings = Settings() ### 5.4 日志通用规则 -| 语言 | 工具 | 说明 | -|------|------|------| +| 语言 | 工具 | 说明 | +| ---------- | -------------------- | ---------------- | | TypeScript | NestJS Logger + pino | 结构化 JSON 日志 | -| Go | log/slog | 标准库结构化日志 | -| Python | structlog 或 loguru | 结构化 JSON 日志 | +| Go | log/slog | 标准库结构化日志 | +| Python | structlog 或 loguru | 结构化 JSON 日志 | **通用规则**: + - 日志必须结构化(JSON),禁止纯文本 - 必须包含 `timestamp`、`level`、`service`、`request_id`、`trace_id` - 日志级别:DEBUG(开发)、INFO(关键业务)、WARN(异常可恢复)、ERROR(系统错误) @@ -622,13 +646,14 @@ settings = Settings() ### 5.5 测试通用规则 -| 语言 | 单元测试框架 | 覆盖率目标 | -|------|------------|-----------| -| TypeScript | Vitest + nestjs/testing | ≥ 80% | -| Go | 标准 testing 包 + testify | ≥ 80% | -| Python | pytest + pytest-asyncio | ≥ 80% | +| 语言 | 单元测试框架 | 覆盖率目标 | +| ---------- | ------------------------- | ---------- | +| TypeScript | Vitest + nestjs/testing | ≥ 80% | +| Go | 标准 testing 包 + testify | ≥ 80% | +| Python | pytest + pytest-asyncio | ≥ 80% | **通用规则**: + - 测试文件与源文件同目录或 `tests/` 子目录 - 命名:`*.test.ts` / `*_test.go` / `test_*.py` - 测试描述说明预期行为("should disable button while loading") @@ -714,6 +739,7 @@ enum UserStatus { ``` **规则**: + - 字段编号禁止复用,删除字段必须 `reserved` 标记 - 枚举第一个值必须为 `*_UNSPECIFIED = 0` - 时间使用 `google.protobuf.Timestamp`,不使用 string @@ -770,12 +796,12 @@ buf generate ### 7.1 令牌分层(沿用 CICD 模型,迁移至微前端共享包) -| Layer | 位置 | 用途 | -|-------|------|------| -| Layer 1 Primitive | `packages/ui-tokens/primitive.css` | 原始色板/字号/间距/阴影,业务代码不直接引用 | -| Layer 2 Semantic | `packages/ui-tokens/semantic-light.css` + `semantic-dark.css` | 语义令牌,业务代码唯一引用入口 | -| 模块命名空间 | `packages/ui-tokens/lesson-preparation.css` | `--lp-*` 令牌,明暗双份 | -| Tailwind 暴露 | `packages/ui-tokens/tailwind-theme.css` | `@theme inline` 暴露为 `bg-*`/`text-*`/`font-*` 类 | +| Layer | 位置 | 用途 | +| ----------------- | ------------------------------------------------------------- | -------------------------------------------------- | +| Layer 1 Primitive | `packages/ui-tokens/primitive.css` | 原始色板/字号/间距/阴影,业务代码不直接引用 | +| Layer 2 Semantic | `packages/ui-tokens/semantic-light.css` + `semantic-dark.css` | 语义令牌,业务代码唯一引用入口 | +| 模块命名空间 | `packages/ui-tokens/lesson-preparation.css` | `--lp-*` 令牌,明暗双份 | +| Tailwind 暴露 | `packages/ui-tokens/tailwind-theme.css` | `@theme inline` 暴露为 `bg-*`/`text-*`/`font-*` 类 | ### 7.2 强制规则 @@ -846,11 +872,11 @@ buf generate ### 8.6 依赖扫描 -| 语言 | 工具 | -|------|------| -| TS | `npm audit` + Snyk + Trivy | -| Go | `govulncheck` | -| Python | `pip-audit` + `safety` | +| 语言 | 工具 | +| ------ | -------------------------- | +| TS | `npm audit` + Snyk + Trivy | +| Go | `govulncheck` | +| Python | `pip-audit` + `safety` | 高危漏洞阻断合并。 @@ -873,12 +899,12 @@ buf generate ### 9.1 测试分层 -| 层级 | TS | Go | Python | 覆盖率 | -|------|-----|-----|--------|--------| -| 单元测试 | Vitest | testing + testify | pytest | ≥ 80% | -| 集成测试 | Vitest + Testcontainers | testing + Testcontainers | pytest + Testcontainers | 关键流程 | -| E2E 测试 | Playwright | - | - | 核心业务路径 | -| 契约测试 | pact + buf | pact + buf | pact + buf | 服务间契约 | +| 层级 | TS | Go | Python | 覆盖率 | +| -------- | ----------------------- | ------------------------ | ----------------------- | ------------ | +| 单元测试 | Vitest | testing + testify | pytest | ≥ 80% | +| 集成测试 | Vitest + Testcontainers | testing + Testcontainers | pytest + Testcontainers | 关键流程 | +| E2E 测试 | Playwright | - | - | 核心业务路径 | +| 契约测试 | pact + buf | pact + buf | pact + buf | 服务间契约 | ### 9.2 测试命令 @@ -965,15 +991,15 @@ pytest tests/integration -v ## 附录:与 CICD 单应用规范的差异 -| 项目 | CICD 单应用 | Edu 微服务 | 原因 | -|------|-----------|-----------|------| -| 项目结构 | 单 Next.js 应用 | 多语言 monorepo | 微服务拆分 | -| 数据获取层 | `modules/[module]/data-access.ts` | NestJS Repository + Domain Entity | DDD 分层 | -| 中间件 | `proxy.ts`(Next.js 16) | Go Gin Gateway | 网关独立 | -| 通信 | 函数调用 | gRPC + Kafka | 跨进程通信 | -| 状态管理 | Zustand + Context + nuqs | 沿用 | 团队熟悉 | -| 环境变量校验 | `@t3-oss/env-nextjs` + Zod | TS Zod / Go viper / Python pydantic-settings | 多语言 | -| 行数限制 | 单一规范 | 按语言分档 | 各语言惯例 | -| 契约 | 无(内部函数调用) | protobuf + buf | 跨服务通信需要 | -| 事件驱动 | 无 | Kafka + Outbox | 微服务最终一致 | -| 设计令牌 | `src/app/styles/tokens/` | `packages/ui-tokens/` | 微前端共享 | +| 项目 | CICD 单应用 | Edu 微服务 | 原因 | +| ------------ | --------------------------------- | -------------------------------------------- | -------------- | +| 项目结构 | 单 Next.js 应用 | 多语言 monorepo | 微服务拆分 | +| 数据获取层 | `modules/[module]/data-access.ts` | NestJS Repository + Domain Entity | DDD 分层 | +| 中间件 | `proxy.ts`(Next.js 16) | Go Gin Gateway | 网关独立 | +| 通信 | 函数调用 | gRPC + Kafka | 跨进程通信 | +| 状态管理 | Zustand + Context + nuqs | 沿用 | 团队熟悉 | +| 环境变量校验 | `@t3-oss/env-nextjs` + Zod | TS Zod / Go viper / Python pydantic-settings | 多语言 | +| 行数限制 | 单一规范 | 按语言分档 | 各语言惯例 | +| 契约 | 无(内部函数调用) | protobuf + buf | 跨服务通信需要 | +| 事件驱动 | 无 | Kafka + Outbox | 微服务最终一致 | +| 设计令牌 | `src/app/styles/tokens/` | `packages/ui-tokens/` | 微前端共享 | diff --git a/project_rules.md b/project_rules.md deleted file mode 100644 index ae35fee..0000000 --- a/project_rules.md +++ /dev/null @@ -1 +0,0 @@ -4. 若代码结构变??`pnpm run arch:scan` 确认 arch.db 已更? \ No newline at end of file