Files
Edu/docs/architecture/issues/contracts/msg_contract.md

16 KiB
Raw Blame History

msg 对接契约

负责人ai10 关联:matrix.mdmsg.protoevents.proto02-architecture-design.md 仲裁依赖ISSUE-008topic 命名、ISSUE-009RPC 数量、ISSUE-013events.proto 补齐)


§1 我提供什么(对外接口)

1.1 gRPC 接口

端口50056 | proto 包名:next_edu_cloud.msg.v1 | proto 文件:msg.proto

⚠️ ISSUE-009 待仲裁ai-allocation.md 规定 13 RPC02-architecture-design.md 设计 17 RPC。下表列出设计文档完整 17 RPC标注基线 13 RPC基线 / 扩展待仲裁。coord 裁决后裁剪或放宽。

NotificationService9 RPC5 基线 + 4 扩展)

RPC 请求 响应 基线/扩展 说明
SendNotification SendNotificationRequest{user_id, type, title, content, channel, metadata?, related_entity_type?, related_entity_id?} Notification 基线 单条发送
BatchSendNotification BatchSendNotificationRequest{items[], group_id?} BatchSendNotificationResponse{ids[], failed[]} 扩展 批量发送
ListNotifications ListNotificationsRequest{user_id, only_unread?, type?, page?, page_size?} ListNotificationsResponse{notifications[], total} 基线 列表(补分页)
GetUnreadCount GetUnreadCountRequest{user_id} GetUnreadCountResponse{count} 扩展 未读数Redis
MarkAsRead MarkAsReadRequest{id, user_id} Empty 基线 标记已读
BatchMarkAsRead BatchMarkAsReadRequest{ids[], user_id} Empty 扩展 批量已读
MarkAllAsRead MarkAllAsReadRequest{user_id, before?} Empty 扩展 全部已读
SearchNotifications SearchNotificationsRequest{user_id, query, type?, page?, page_size?} SearchNotificationsResponse{notifications[], total} 基线 ES 全文检索
RecallNotification RecallNotificationRequest{group_id, reason?} RecallNotificationResponse{recalled_count} 基线 撤回广播

NotificationPreferenceService2 RPC 基线)

RPC 请求 响应 基线/扩展 说明
GetPreferences GetPreferencesRequest{user_id} GetPreferencesResponse{preferences[]} 基线 偏好查询
UpdatePreferences UpdatePreferencesRequest{user_id, preferences[]} Empty 基线 偏好更新

02-architecture-design.md 设计 2 RPC原 contract 版本的 GetPreferenceByChannel / ListPreferences 暂移除(待 ISSUE-009 仲裁是否保留)

NotificationTemplateService4 RPC4 基线 + 2 扩展)

RPC 请求 响应 基线/扩展 说明
CreateTemplate CreateTemplateRequest{code, type, title_template, content_template, default_channels, variables} NotificationTemplate 基线 创建模板
GetTemplate GetTemplateRequest{id} NotificationTemplate 基线 查询模板
ListTemplates ListTemplatesRequest{type?, status?} ListTemplatesResponse{templates[]} 基线 模板列表
UpdateTemplate UpdateTemplateRequest{id, ...} NotificationTemplate 扩展 更新模板
DeleteTemplate DeleteTemplateRequest{id} Empty 扩展 删除模板
RenderTemplate RenderTemplateRequest{code, variables, locale?} RenderedNotification{title, content} 基线 渲染模板

汇总:基线 13 RPC9 基线表中 × 5 + 偏好 × 2 + 模板 × 4 = 11... 实际基线 = NotificationService 5 + Preference 2 + Template 4 = 11:若严格按 ai-allocation 13 RPC基线应为 13此处设计文档 11 基线 + 6 扩展 = 17与 13 预算差 4。待 ISSUE-009 仲裁后最终确认。

1.2 HTTP 端点

msg 对外以 gRPC 为主BFF 通过 gRPC 调用)。以下 REST 端点为过渡期/管理端使用,最终将逐步迁移至 gRPC。

Method Path 权限 说明
POST /notifications/send MSG_NOTIFICATION_SEND 单条发送
POST /notifications/batch MSG_NOTIFICATION_SEND 批量发送
GET /notifications/user/:userId MSG_NOTIFICATION_READ 用户通知列表
GET /notifications/user/:userId/unread-count MSG_NOTIFICATION_READ 未读数Redis
PUT /notifications/:id/read MSG_NOTIFICATION_READ 标记已读
GET /notifications/search MSG_NOTIFICATION_READ ES 全文检索
GET /preferences/user/:userId MSG_NOTIFICATION_READ 用户偏好
PUT /preferences/user/:userId MSG_NOTIFICATION_MANAGE 更新偏好
GET /templates MSG_NOTIFICATION_MANAGE 模板列表
POST /templates MSG_NOTIFICATION_MANAGE 创建模板

1.3 GraphQL schema

不适用msg 是业务服务,非 BFF

1.4 Kafka 事件发布

⚠️ ISSUE-008 待仲裁topic 命名存在三套约定per-event / aggregate / aggregate+action。本表采用 02-architecture-design.md §5.2 约定per-event topic与 004 §7.2 一致。coord 裁决后统一。

Topic Event Type 触发时机 消费方 Outbox
edu.notification.sent NotificationSent 通知发送成功 push-gateway / data-ana
edu.notification.read NotificationRead 通知被标记已读 data-ana
edu.notification.recalled NotificationRecalled 通知被撤回 push-gateway删除已推送消息
edu.notification.failed NotificationFailed 通知投递失败 data-ana监控告警

Producer 幂等idempotent=true + transactionalId=msg-producer DLQ:消费失败超 3 次投递 edu.notification.dlq(见 02-architecture-design.md §5待补充

1.5 错误码前缀

MSG_(完整清单见 02-architecture-design.md §6.2

  • MSG_VALIDATION_ERROR / MSG_NOT_FOUND / MSG_PERMISSION_DENIED / MSG_CONFLICT / MSG_BUSINESS_ERROR / MSG_DATABASE_ERROR / MSG_INTERNAL_ERROR当前已实现 7 个)
  • MSG_ES_UNAVAILABLE / MSG_REDIS_UNAVAILABLE / MSG_PUSH_GATEWAY_UNAVAILABLE / MSG_TEMPLATE_NOT_FOUND / MSG_TEMPLATE_RENDER_ERROR / MSG_RATE_LIMIT_EXCEEDEDP5 新增 6 个)

§2 我消费什么(依赖上游)

2.1 gRPC 调用(同步)

调用方 对方服务 协议 RPC 用途 状态
msg → push push-gateway gRPC PushService.Push 实时推送通知到在线用户 P5 待实现D5

当前降级fetch POST /internal/push(见 notifications.service.ts L179 调用方向澄清ISSUE-005004 §4.1 表述"push-gateway → Msg"有歧义,实际方向是 msg → push-gateway

2.2 Kafka 事件订阅(异步)

⚠️ ISSUE-008 待仲裁topic 命名采用 02-architecture-design.md §5.1 约定per-event topic与 004 §7.2 一致)。原 contract 版本的 aggregate topicedu.iam.user.events / edu.exam.events待 coord 裁决后统一。

Topic 来源服务 处理逻辑 触发通知 幂等键 阻塞性
edu.identity.user.created iam (ai06) 发送欢迎通知 welcome 通知 event_id 🟡
edu.identity.user.updated iam (ai06) 用户信息变更,清理缓存 event_id 🟡
edu.identity.user.deleted iam (ai06) 用户删除,归档通知 event_id 🟡
edu.identity.user.role_changed iam (ai06) 角色变更通知 system 通知 event_id 🟡
edu.identity.role.created iam (ai06) 角色新增(管理通知) system 通知 event_id 🟡
edu.identity.role.updated iam (ai06) 角色权限变更通知 system 通知 event_id 🟡
edu.teaching.exam.published core-edu (ai08) 推送考试通知给班级学生 exam 通知fan-out event_id 🟡
edu.teaching.assignment.submitted core-edu (ai08) 通知教师有学生提交作业 homework 通知 event_id 🟡
edu.teaching.assignment.graded core-edu (ai08) 通知学生作业已批改 grade 通知 event_id 🟡
edu.teaching.grade.recorded core-edu (ai08) 通知学生成绩已录入 grade 通知 event_id 🟡
edu.teaching.attendance.recorded core-edu (ai08) 出勤异常通知家长 attendance 通知 event_id 🟡
edu.insight.mastery.updated data-ana (ai11) 学情掌握度下降,触发预警 mastery_alert 通知 event_id 🟡

⚠️ ISSUE-013 阻塞events.proto 当前仅有 ClassEvent / ExamEvent / HomeworkEvent / GradeEvent缺 UserEvent / RoleEvent / MasteryEvent / NotificationEvent 4 类 message。msg 消费需 coord 补齐 protoD1。补齐前用通用 JSON payload 解析。

幂等去重三层防线L1 Redis SETNX msg:processed:{event_id} TTL 7d / L2 msg_idempotency 表 / L3 notifications.event_id UNIQUE INDEX

2.3 HTTP 调用

无主动 HTTP 调用上游push-gateway 走 gRPCHTTP 仅为降级)。


§3 就绪信号

3.1 我依赖的上游就绪标志

标志 提供方 阻塞性 说明
events.proto 补 UserEvent/RoleEvent/MasteryEvent/NotificationEvent coord 🔴 阻塞 T9 D1ISSUE-013
events.proto GradeEvent 补 class_id全部补 student_ids[] coord 🔴 阻塞 fan-out D2ISSUE-006
msg.proto 补 5 扩展 RPC + Preference/Template Service coord 🔴 阻塞 gRPC D3-D4ISSUE-009
push-gateway gRPC PushService.Push ai02 🔴 阻塞 T8 D5
iam 发布 6 类 user/role 事件 ai06 🟡 集成验证 D6开发期用 mock
core-edu 发布 5 类教学事件 ai08 🟡 集成验证 D7
data-ana 发布 mastery 事件 ai11 🟡 集成验证 D8
Redis 集群可用 infra 🟡 降级 DB D9

3.2 我的就绪标志(供下游消费)

  • msg gRPC 50056 启用HealthService.Check 返回 SERVING
  • NotificationService RPC 可调用(基线 5 + 扩展 4待 ISSUE-009 仲裁)
  • NotificationPreferenceService 2 RPC 可调用
  • NotificationTemplateService RPC 可调用(基线 4 + 扩展 2含 RenderTemplate
  • edu.notification.sent/read/recalled/failed topic 可发布(待 ISSUE-008 仲裁命名)
  • /readyz 返回 6 项依赖状态DB/ES/Redis/Kafka producer/Kafka consumer/PushGateway
  • 测试覆盖率 ≥ 80%

§4 Mock 策略

4.1 我提供的 mock供下游

在 msg 真实服务就绪前为下游teacher-bff / student-bff / parent-bff / push-gateway提供 mock

  • gRPC mockgrpc-mock 拦截 50056 端口
    • ListNotifications 返回固定 10 条未读通知
    • MarkAsRead 返回 success=true
    • GetPreferences 返回默认偏好in_app + email 开启sms + push 关闭)
    • RenderTemplate 返回固定 title + content
  • Kafka mockmsg 就绪前不发布真实通知事件push-gateway 使用本地 stub 推送

4.2 我消费的 mock开发期间

在真实上游就绪前msg 使用以下 mock

  • 业务事件core-edu / data-ana 就绪前msg 内置定时器发布本地 stub 事件ExamEvent / HomeworkEvent触发 mock 通知流程
  • 用户偏好iam 就绪前使用默认偏好(所有用户 in_app 开启)
  • 模板渲染:内置 5 个常用模板exam.published / homework.graded / grade.recorded / mastery.warning / system.notice
  • Push Gatewayai02 就绪前用 fetch POST /internal/push 降级(当前实现保留)

§5 待仲裁项汇总

ISSUE 主题 阻塞性 当前采用
ISSUE-008 Kafka topic 命名per-event vs aggregate 🟡 per-event02-architecture-design.md §5 + 004 §7.2
ISSUE-009 RPC 数量13 vs 17 🟡 1702-architecture-design.md §4.2),标注基线/扩展
ISSUE-013 events.proto 缺 4 类 message 🔴 用 JSON payload 降级,待 coord 补齐
ISSUE-006 events.proto P9 字段描述 🟡 待 coord 修正
ISSUE-010 markAsRead 权限点 🟡 以 02-architecture-design.md §6.1 为准READ
ISSUE-011 DB↔ES 降级方向 🟡 待 coord 仲裁(双向降级 vs 单向)