Files
Edu/services/msg/docs/01-understanding.md
SpecialX faaaf29f67 docs: ai 协作文档体系重构与多 ai 仲裁结果落地
1.AI 协作文档体系重构(objections/worklines/contracts+matrix.md)

2.coord 仲裁文档(final-decisions/cross-review/final-rulings/orchestration)

3.各服务 01/02 文档补全

4.共享包初始化(shared-ts/shared-go/hooks/ui-components/ui-tokens)

5.Proto 契约补全

6.004 架构影响地图更新

7.端口分配表

8.设计规格文档
2026-07-10 12:58:22 +08:00

192 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 模块理解确认书 — msg
> AI 标识ai05初版→ ai10复核修订按 ai-allocation.md §3.2 重新分配)
> 负责模块msgP5
> 阶段:架构设计外包 · 阶段 1全局理解
> 初版日期2026-07-09
> 复核修订日期2026-07-09ai10 接手后修正 3 处失实条目 M2/M8/M12并补充 ai-allocation §5 缺失项)
> 关联文档:[ai-allocation.md](../../../docs/architecture/ai-allocation.md)、[004 架构影响地图](../../../docs/architecture/004_architecture_impact_map.md)、[pending-features.md](../../../docs/architecture/roadmap/pending-features.md)、[known-issues.md](../../../docs/troubleshooting/known-issues.md)
---
## 1. 我在架构中的位置
- **层级**业务微服务层L5DDD 限界上下文
- **业务领域**D5 沟通通知领域004 §1.1b
- **上游**(谁调用我):
- teacher-bff / student-bff / parent-bff聚合层调 msg 查询用户通知列表、发送通知
- api-gatewayREST 转发通知请求
- Kafka消费 core-edu / iam 事件触发通知004 §4.1 `CoreEdu -.事件.-> Msg``IAM -.事件.-> Msg`
- **下游**(我调用谁):
- MySQL写模型主库独占
- Elasticsearch全文检索已实现 safeSearch
- push-gatewaygRPC 推送通道004 §4.1 `PushGW → Msg`,当前用 fetch POST /internal/push 降级)
- **通信方式**
- 当前HTTP RESTController无 gRPC controller
- 目标态004 §4.1 / pending-features P5gRPC 暴露 `NotificationService`
- Kafka消费 core-eduExamPublished/HomeworkGraded/GradeRecorded、iamUserRegistered事件004 §7.3
- **端口**3007见 [msg env.ts](../src/config/env.ts)
## 2. 我的限界上下文
- **聚合职责**:管理 Notification通知聚合 + NotificationPreference用户通知偏好
- **我的数据属于**D5 沟通通知领域
- **我不负责**
- 不负责 WebSocket 长连接管理(由 push-gateway 承载)
- 不负责业务数据变更(仅消费事件触发通知)
- 不直接访问 core-edu / iam 的数据库
- **现有骨架领域模块**1 个,见 [msg/src](../src)
- `notifications/`:通知 CRUD + ES 全文检索 + Push Gateway 推送 + 用户偏好6 端点)
## 3. 我与外部的契约
- **消费的 proto message**(从 shared-proto
- 消费 `events.proto` 的事件 messageClassEvent/ExamEvent/HomeworkEvent/GradeEvent
- **events.proto 当前无 NotificationEvent**,若 msg 发事件需补充
- **暴露的契约**(见 [msg.proto](../../../packages/shared-proto/proto/msg.proto),包名 `next_edu_cloud.msg.v1`
- `NotificationService`SendNotification / ListNotifications / MarkAsRead / SearchNotifications
- **当前实现均为 RESTgRPC controller 未实现**
- **事件契约**
- 消费004 §7.2 / §7.3
- `edu.identity.user.created` / `edu.identity.user.updated`IAM 发msg 发欢迎通知)
- `edu.teaching.exam.published`core-edu 发msg 推送考试通知给学生)
- `edu.teaching.assignment.submitted`core-edu 发msg 通知教师)
- `edu.teaching.grade.recorded`core-edu 发msg 通知学生)
- `edu.insight.mastery.updated`data-ana 发msg 触发预警)
- 发布无明确pending-features 未要求 msg 发事件)
- **错误码前缀**`MSG_*`MSG_VALIDATION_ERROR / NOT_FOUND / PERMISSION_DENIED / CONFLICT / BUSINESS_ERROR / DATABASE_ERROR / INTERNAL_ERROR见 [application-error.ts](../src/shared/errors/application-error.ts)
- **权限点**3 个,见 [permission.guard.ts](../src/middleware/permission.guard.ts)
- `MSG_NOTIFICATION_SEND``MSG_NOTIFICATION_READ``MSG_NOTIFICATION_MANAGE`
## 4. 我的技术栈
- 语言TypeScript 5.6ESM 模式)
- 框架NestJS 10
- ORMDrizzle ORM 0.31 + mysql2 3.11
- 全文检索:@elastic/elasticsearch 8.15(已实现 safeIndex/safeSearch**无 mapping 定义**,依赖动态 mapping
- 消息总线kafkajs 2.2**已装依赖但无 consumer/producer 代码**env.ts 有 KAFKA_BROKERS 默认值)
- 推送fetch POST 到 push-gateway `/internal/push`降级模式PUSH_GATEWAY_URL 未配置或失败时跳过)
- 幂等去重Redis**env.ts 预留 REDIS_URL 但无 redis 客户端依赖**pending-features P5 要求 event_id 去重)
- 可观测pino + prom-client + OpenTelemetry三支柱已具备
## 5. 我的阶段归属
- **P5 沟通与 AI 阶段**pending-features §P5
- 会话/消息 CRUD + 调 Push Gateway 推送 + 通知偏好
- 多渠道(站内/SMS/邮件/微信),沿用旧项目 dispatcher 模式
- Elasticsearch 题库全文检索(从 MySQL 同步)
- **退出标准**:教师发广播通知 → 全在线学生实时收到Push Gateway→ AI 辅助出题流式返回 → 题库全文检索 < 200ms
- **依赖上游**P1 黄金模板 classes、P3 core-edu事件来源、P5 push-gateway推送通道ai01 设计、P5 ai无直接依赖
## 6. 我需要对齐的黄金模板项(对照 classes 服务)
- [x] 权限装饰器 `@RequirePermission`3 个 MSG_* 权限点,全部 Controller 方法已覆盖)
- [x] 错误码前缀统一(`MSG_*`
- [x] logger / metrics / tracer 三支柱(已具备)
- [x] `/healthz` 健康检查HealthModule 已注册)
- [⚠️] `/readyz`**仅检查 DB `SELECT 1`,未检查 ES 连通性**ES 故障时仍返回 ok
- [x] 优雅关闭 SIGTERMmain.ts 已处理app.close → closeEs → closeDb → shutdownTracer
- [ ] 测试覆盖率 ≥ 80%**当前 0%**,无测试文件)
- [x] Dockerfile 多阶段构建(已具备)
- [x] Zod 输入验证Controller 用 `schema.parse(body)`**GlobalErrorFilter 已识别 ZodError 返回 400**,见 [global-error.filter.ts](../src/shared/errors/global-error.filter.ts) L32-42ai10 复核修正)
- [x] GlobalErrorFilter 统一兜底
## 7. 现有骨架差距与待决策(提请 coord 仲裁)
| # | 差距 | 影响 | 提请决策 |
| --- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
| M1 | **Kafka 消费未实现**:装了 kafkajs 但无 consumer 代码,无 shared/kafka/ 目录 | 004 §7.3 列 msg 消费 5 类事件ExamPublished/HomeworkGraded/GradeRecorded/UserRegistered/MasteryUpdated | 阶段 2 设计需补 Kafka consumer + 幂等去重 |
| M2 | **无 Outbox**:骨架无 shared/outbox/ | 004 §7.2 明确 msg 生产 `edu.notification.events`NotificationRequested消费者 push-gateway**ai10 复核msg 必须有 Outbox**004 §7.2/§7.3 已定义,原"无明确"判断失实) | 阶段 2 设计补 Outbox参照 core-edu outbox.publisher.ts |
| M3 | **ES 无 mapping 定义**:依赖动态 mapping索引名 "notifications" 硬编码在 service | 检索质量不稳定,索引管理缺失 | 阶段 2 设计补 mapping + ensureIndex |
| M4 | **无独立 repository**notifications.service.ts 直接用 db无 repository 抽象 | 与黄金模板分层不一致iam 有 repository | 阶段 2 设计补 repository 层 |
| M5 | **Redis 未引入**env.ts 预留 REDIS_URL 但无 redis 客户端依赖 | pending-features P5 要求 event_id 去重Redis SETNX 或 DB 唯一索引) | 阶段 2 设计决策Redis SETNX vs DB 唯一索引 |
| M6 | **createBatch 无事务/无批量优化**for 循环串行调 send无批量 INSERT | 性能瓶颈(广播场景) | 阶段 2 设计改为批量 INSERT |
| M7 | **NotificationsModule 缺 exports**notifications.module.ts 无 `exports: [NotificationsService]` | 未来 BFF 注入受阻 | 阶段 2 设计补 exports |
| M8 | **~~ZodError 未特殊处理~~ai10 复核:已修复,失实条目)**GlobalErrorFilter 已识别 ZodError 返回 400见 [global-error.filter.ts](../src/shared/errors/global-error.filter.ts) L32-42 | 无(已修复) | ✅ 已修复,无需处理 |
| M9 | **gRPC 未实现**proto 定义了 NotificationService但无 gRPC controller | pending-features P5 未强制 gRPC | 确认 P5 是否启用 gRPCai03 提请统一决策) |
| M10 | **README 与实现脱节**README API 表标 `POST /notifications/:id/read`,实际是 PUT漏 batch/user/:userId/user/:userId/page 端点;声称"消费 Kafka 事件"但无代码 | 文档误导 | 阶段 2 设计同步修正 README |
| M11 | **main.ts 与 LifecycleService 重复关闭资源**:两者都调 closeDb/closeEs | 重复关闭可能报错(虽有 try-catch | 阶段 2 设计统一关闭逻辑到 LifecycleService |
| M12 | **~~proto 包名不一致~~ai10 复核:失实条目)**:实际 `next_edu_cloud.msg.v1` 完全符合 project_rules §5 `next_edu_cloud.<domain>.v1` 规范coord 已裁决采用 `next_edu_cloud.*` 格式) | 无(命名正确) | ✅ 命名正确,无需处理 |
---
## 服务审计表 — ai10msg 复核)
> 审计标准对照 [project_rules §3](../../../.trae/rules/project_rules.md) 与 [known-issues §2.2 classes 黄金模板](../../../docs/troubleshooting/known-issues.md)
| 服务 | 权限装饰器 | 错误码前缀 | logger | metrics | tracer | /healthz | /readyz | 优雅关闭 | 测试覆盖率 | Dockerfile |
| ---- | --------------- | ---------- | ------- | -------------- | ------------------------------- | -------- | ---------------- | --------------------------------------- | ---------- | ---------- |
| msg | ✅ 6 端点全覆盖 | ✅ `MSG_*` | ✅ pino | ✅ prom-client | ✅ OTel + auto-instrumentations | ✅ | ⚠️ 仅 DB 不查 ES | ⚠️ main.ts 与 LifecycleService 重复关闭 | 0% | ✅ |
## ai10 复核结论ai-allocation §5 设计重点对照)
ai-allocation.md §5 对 ai10msg明确列出 6 项设计重点,对照现有骨架:
| ai-allocation §5 设计重点 | 现状 | 阶段 2 是否需设计 |
| --------------------------------------------------- | ------------------------------ | ----------------- |
| 通知渠道抽象(站内信/邮件/短信,策略模式) | ❌ 无抽象,硬编码 | ✅ 必须 |
| ES 降级查询策略DB 不可用时走 ES 索引) | ❌ 仅 ES 降级,无 DB 降级到 ES | ✅ 必须 |
| Kafka 消费幂等设计event_id 去重 via Redis SETNX | ❌ 无 Kafka 代码 | ✅ 必须 |
| 与 ai02push-gateway的推送通道协议gRPC | ⚠️ 用 fetch POST 降级,无 gRPC | ✅ 需 gRPC 化 |
| 通知模板管理(模板 CRUD + 变量替换) | ❌ 无模板模块 | ✅ 必须 |
| 已读/未读状态管理Redis 位图) | ❌ 仅 DB boolean | ✅ 必须 |
**新增差距ai10 补充,原 ai05 文档遗漏)**
| # | 差距 | 影响 |
| --- | ------------------------------------------------------------------------------- | ----------------------------------------------------- |
| M13 | **无通知模板模块**:缺 msg_notification_templates 表、模板 CRUD、变量替换、i18n | ai-allocation §5 强制要求 |
| M14 | **无渠道策略抽象**send 方法硬编码 channel 判断,无 ChannelStrategy 接口 | 多渠道扩展困难(未来加微信/钉钉需改核心) |
| M15 | **无 Redis 位图已读/未读**isRead 仅 DB boolean无 unread 计数缓存 | 高频未读数查询打 DB广播场景性能瓶颈 |
| M16 | **无 DB→ES 降级读路径**:仅有 ES→空降级无 DB 故障时走 ES 读模型 | ai-allocation §5 要求 DB 不可用走 ES 索引 |
| M17 | **无投放记录表**:缺 msg_notification_deliveriesper-channel 投递状态) | 无法追踪邮件/短信投递成功失败 |
| M18 | **无幂等键**send 无 idempotencyKey 参数,重复请求会重复发通知 | 客户端重试导致重复通知 |
| M19 | **无通知优先级/分类**:缺 priority/category 字段 | 无法区分紧急通知与普通通知,无法按类退订 |
| M20 | **无调度/延迟发送**:缺 scheduledAt 字段与调度器 | 未来定时通知、每日摘要无法支持 |
| M21 | **权限模型过简**:仅 3 个权限点,硬编码 ROLE_PERMISSIONS | 应对齐 iam 的 RBAC + DataScopeDATA_SCOPE=SELF/ALL |
---
## 跨模块契约对齐提请coord 交叉审查)
### 接口一致性检查msg 相关)
| 本服务声明 | 对方服务声明 | 是否匹配 | 备注 |
| -------------------------------------------- | ------------------------------- | --------- | ------------------------------------------------------------------------------------------------ |
| ai05 msg: 消费 `edu.teaching.exam.published` | ai03 core-edu: 发布考试事件 | ⚠️ 待确认 | ai03 提请 topic 命名统一004 `edu.teaching.exam.published` vs core-edu 代码 `edu.exam.events` |
| ai05 msg: 消费 `edu.identity.user.created` | ai02 iam: 发布用户创建事件 | ⚠️ 待确认 | ai02 设计需确认 topic |
| ai05 msg: 调 push-gateway `/internal/push` | ai01 push-gateway: 暴露推送端点 | ✅ 已实现 | msg 当前用 fetch POSTpush-gateway 已有 /internal/push 端点 |
### 全局冲突检查msg 相关)
| 检查项 | 检查结果 | 备注 |
| -------------------- | --------------- | -------------------------------------------------------------------------------------------------------- |
| 端口不冲突 | ✅ msg 3007 | 与 iam(3002)/classes(3001)/teacher-bff(3003)/core-edu(3004)/content(3005)/data-ana(3006)/ai(3008) 不冲突 |
| Topic 不重复 | ⚠️ 待汇总 | msg 仅消费不发布 |
| 错误码前缀不重叠 | ✅ `MSG_*` 唯一 | 与 iam `IAM_*` / core-edu `CORE_EDU_*` / content `CONTENT_*` 不重叠 |
| Proto message 不遗漏 | ⚠️ 待确认 | events.proto 无 NotificationEvent若 msg 发事件需补充 |
| proto 包名规范 | ⚠️ 不一致 | 实际 `next_edu_cloud.<domain>.v1`,规则要求 `edu.<domain>.v1`**提请 coord 仲裁**ai03 已提请) |
### 待 coord 仲裁的决策项msg 相关)
1. ~~**proto 包名统一**`next_edu_cloud.*` vs `edu.*`~~ai10 复核coord 已裁决 `next_edu_cloud.*`,本项目全部 proto 已采用,无需再仲裁)
2. **gRPC 启用时机**P4/P5 是否启用 gRPC controller还是继续 REST影响 content/msg/iam/core-edu 全部服务)
3. ~~**msg Outbox**:是否需要~~ai10 复核004 §7.2 已明确 msg 生产 `edu.notification.events`**必须有 Outbox**,无需仲裁)
4. **msg Redis 引入**env.ts 预留 REDIS_URL 但无依赖,幂等去重用 Redis SETNX 还是 DB 唯一索引ai10 倾向 Redis SETNX + DB 唯一索引双保险,待 coord 确认 Redis 是否纳入 P5 基础设施)
5. **events.proto 补充**msg 发 NotificationRequested 事件需追加 NotificationEvent messagecoord 维护 proto
---
## 下一步
1. ~~等待 coord 审核本确认书~~ai10 复核修订完成,进入阶段 2
2. 进入**阶段 2模块架构设计文档**,按 ai-allocation.md §7 模板产出 [02-architecture.md](./02-architecture.md)
- msg 模块架构设计文档含通知渠道抽象策略模式、ES 降级查询、Kafka 消费幂等、push-gateway 推送协议、通知模板、已读/未读状态管理)
3. 阶段 2 设计完成后同步更新 README修正 §M10 文档脱节问题)
---
**AI Agent**: ai10 (msg)
**Coordinator**: coord-ai
**Branch**: 单仓库并行模式(直接 push main