@microi.net/cli 5.5.8 → 5.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/.codebuddy-plugin/marketplace.json +2 -2
  2. package/.codebuddy-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.mcp.json +1 -1
  5. package/.workbuddy-plugin/marketplace.json +2 -2
  6. package/.workbuddy-plugin/plugin.json +1 -1
  7. package/README.md +71 -71
  8. package/assets/build-meta.json +5 -5
  9. package/assets/feature-matrix.json +129 -129
  10. package/cordis.patch.yml +1 -1
  11. package/package.json +1 -1
  12. package/scripts/codex-marketplace.json +20 -20
  13. package/scripts/mcp-codex-stdio-adapter.js +189 -189
  14. package/scripts/mcp-trae-windows-launcher.cmd +21 -21
  15. package/scripts/microi-cli-mcp.js +7 -7
  16. package/scripts/microi-codex-broker.js +447 -447
  17. package/scripts/microi-codex-router.js +582 -582
  18. package/scripts/microi-skills.meta.json +336 -336
  19. package/skills/.microi-skills-version.json +2 -2
  20. package/skills/.progressive-disclosure-manifest.json +3566 -3566
  21. package/skills/README.md +3 -3
  22. package/skills/ai-engine/SKILL.md +45 -43
  23. package/skills/ai-platform-governance/SKILL.md +177 -177
  24. package/skills/ai-platform-governance/references/progressive-01-/345/212/237/350/203/275/345/274/200/345/205/263.md +190 -190
  25. package/skills/app-store/SKILL.md +177 -177
  26. package/skills/business-blueprint/SKILL.md +85 -85
  27. package/skills/datasource-engine/SKILL.md +91 -91
  28. package/skills/dos-orm/SKILL.md +81 -81
  29. package/skills/dos-orm/references/api-reference.md +229 -229
  30. package/skills/email-engine/SKILL.md +80 -80
  31. package/skills/email-engine/references/v8-email.md +34 -34
  32. package/skills/job-engine/SKILL.md +154 -143
  33. package/skills/message-notification/SKILL.md +126 -126
  34. package/skills/message-notification/agents/openai.yaml +5 -5
  35. package/skills/message-notification/references/contracts.md +102 -102
  36. package/skills/microi-ai-app-auth.js +652 -652
  37. package/skills/microi-ai-application/SKILL.md +102 -94
  38. package/skills/microi-ai-application/agents/openai.yaml +4 -4
  39. package/skills/microi-ai-application/references/frontend-baseline.md +164 -164
  40. package/skills/microi-client-frontend/SKILL.md +43 -43
  41. package/skills/microi-client-frontend/references/progressive-01-3-/345/212/250/346/200/201/346/214/211/351/222/256/347/263/273/347/273/237.md +2 -2
  42. package/skills/microi-client-frontend/references/progressive-02-8-/350/277/220/350/241/214/346/227/266/351/253/230/351/242/221/345/235/221/345/244/215/347/233/230.md +28 -28
  43. package/skills/microi-client-frontend/references/progressive-03-vue3-/345/211/215/347/253/257/345/276/256/346/234/215/345/212/241/345/256/277/344/270/273/350/247/204/345/210/231.md +56 -56
  44. package/skills/microi-codex/SKILL.md +46 -46
  45. package/skills/microi-codex-installer/SKILL.md +216 -216
  46. package/skills/microi-codex-installer/agents/openai.yaml +7 -7
  47. package/skills/microi-datasource-mapping/SKILL.md +67 -67
  48. package/skills/microi-db-schema/SKILL.md +6 -6
  49. package/skills/microi-db-schema/references/core-tables.md +18 -18
  50. package/skills/microi-db-schema/references/form-component-options.md +256 -256
  51. package/skills/microi-db-schema/references/schema-overview.md +11 -11
  52. package/skills/microi-db-schema/references/schema.md +46 -46
  53. package/skills/microi-db-schema/references/table-catalog.md +57 -57
  54. package/skills/microi-deployment/SKILL.md +18 -1
  55. package/skills/microi-deployment/references/deployment-matrix.md +101 -101
  56. package/skills/microi-docs-coverage/SKILL.md +123 -123
  57. package/skills/microi-docs-coverage/references/capability-map.md +1 -0
  58. package/skills/microi-docs-coverage/scripts/audit-doc-skill-coverage.mjs +894 -894
  59. package/skills/microi-form-engine/SKILL.md +50 -50
  60. package/skills/microi-form-engine/references/component-catalog.md +218 -218
  61. package/skills/microi-form-engine/references/data-source-events.md +124 -124
  62. package/skills/microi-form-layout/SKILL.md +13 -13
  63. package/skills/microi-form-layout/references/progressive-01-3-/344/270/211/347/247/215/345/210/206/347/273/204/347/232/204/345/255/230/345/202/250/344/270/216/351/205/215/347/275/256.md +235 -235
  64. package/skills/microi-frontend-sdk/SKILL.md +4 -4
  65. package/skills/microi-frontend-sdk/references/progressive-01-token-/345/275/223/345/211/215/347/231/273/345/275/225/347/224/250/346/210/267/344/270/216/345/275/223/345/211/215/347/273/210/347/253/257/347/231/273/345/275/225/345/215/217/350/256/256.md +175 -175
  66. package/skills/microi-left-right-layout/SKILL.md +141 -141
  67. package/skills/microi-microservice/SKILL.md +12 -10
  68. package/skills/microi-microservice/references/runtime-delivery.md +278 -278
  69. package/skills/microi-mobile-app-quality/references/progressive-01-4-/351/207/215/350/246/201/346/214/211/351/222/256/345/277/205/351/241/273/345/270/246/345/233/276/346/240/207.md +213 -213
  70. package/skills/microi-solution-quotation/SKILL.md +78 -78
  71. package/skills/microi-solution-quotation/agents/openai.yaml +4 -4
  72. package/skills/microi-solution-quotation/scripts/build_solution_quote.py +296 -296
  73. package/skills/microi-sso/SKILL.md +85 -85
  74. package/skills/microi-sso/references/acceptance.md +49 -49
  75. package/skills/microi-sso/references/configuration-and-security.md +53 -53
  76. package/skills/microi-sso/references/inbound.md +53 -53
  77. package/skills/microi-sso/references/outbound.md +39 -39
  78. package/skills/microi-system-delivery/references/progressive-02-/350/207/252/345/212/250/345/214/226/346/265/213/350/257/225/345/277/205/351/241/273/350/246/206/347/233/226/347/232/204/345/235/221.md +20 -20
  79. package/skills/microi-ui/SKILL.md +7 -2
  80. package/skills/microi-uniapp-frontend/SKILL.md +134 -134
  81. package/skills/microi-uniapp-frontend/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/210/206/347/261/273-/345/217/214/346/240/217/345/210/227/350/241/250/347/213/254/347/253/213/346/273/232/345/212/250.md +136 -136
  82. package/skills/microi-uniapp-frontend/references/progressive-02-/345/205/263/351/224/256/344/270/232/345/212/241/350/265/204/344/272/247/344/270/215/345/276/227/351/273/230/350/256/244/351/200/211/344/270/255.md +124 -124
  83. package/skills/module-engine/SKILL.md +16 -16
  84. package/skills/ocr-engine/SKILL.md +2 -2
  85. package/skills/ocr-engine/agents/openai.yaml +1 -1
  86. package/skills/page-engine/SKILL.md +28 -28
  87. package/skills/page-engine/references/progressive-01-/346/211/200/346/234/211/347/273/204/344/273/266/347/261/273/345/236/213.md +126 -126
  88. package/skills/page-engine/references/progressive-02-/347/211/210/346/234/254/345/216/206/345/217/262-/345/271/266/345/217/221/344/277/235/345/255/230/344/270/216/345/233/236/346/273/232.md +42 -42
  89. package/skills/performance-testing/SKILL.md +120 -120
  90. package/skills/playwright-e2e/SKILL.md +84 -84
  91. package/skills/playwright-e2e/references/progressive-01-/345/205/250/350/207/252/345/212/250/347/231/273/345/275/225-/345/205/215/351/252/214/350/257/201/347/240/201-/344/275/206/344/270/215/345/205/215/345/257/206/347/240/201-/345/277/205/350/257/273.md +68 -68
  92. package/skills/playwright-e2e/references/progressive-02-/346/226/207/345/255/227/345/257/271/346/257/224/345/272/246/344/270/216/345/217/257/350/257/273/346/200/247/350/207/252/345/212/250/345/214/226/346/243/200/346/237/245-/345/277/205/345/201/232.md +64 -64
  93. package/skills/playwright-e2e/references/progressive-03-microi-helper-/346/250/241/346/235/277.md +20 -20
  94. package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +69 -69
  95. package/skills/print-engine/SKILL.md +36 -36
  96. package/skills/production-readonly-audit/SKILL.md +41 -41
  97. package/skills/report-engine/SKILL.md +71 -71
  98. package/skills/scripts/optimize-progressive-disclosure.mjs +204 -204
  99. package/skills/scripts/refresh-progressive-disclosure.mjs +64 -64
  100. package/skills/scripts/validate-progressive-disclosure.mjs +52 -52
  101. package/skills/search-engine/SKILL.md +75 -75
  102. package/skills/spider-engine/SKILL.md +190 -190
  103. package/skills/system-observability/SKILL.md +162 -162
  104. package/skills/system-observability/references/memory-incident-triage.md +73 -73
  105. package/skills/translate-engine/SKILL.md +1 -1
  106. package/skills/ui-design/SKILL.md +3 -1
  107. package/skills/uniapp-mall-assets/SKILL.md +170 -170
  108. package/skills/unity-integration/SKILL.md +155 -155
  109. package/skills/unity-integration/agents/openai.yaml +4 -4
  110. package/skills/unity-integration/references/ai-app-delivery.md +103 -103
  111. package/skills/unity-integration/references/sdk-api.md +82 -82
  112. package/skills/unity-integration/references/toolbox-migration.md +66 -66
  113. package/skills/unity-integration/references/webgl-hosting.md +57 -57
  114. package/skills/v8-api-config/SKILL.md +378 -378
  115. package/skills/v8-cache-pattern/SKILL.md +306 -306
  116. package/skills/v8-crud-api/SKILL.md +29 -29
  117. package/skills/v8-crud-api/references/progressive-01-/346/237/245/350/257/242/345/210/227/350/241/250-/345/210/206/351/241/265.md +56 -56
  118. package/skills/v8-debugging/SKILL.md +143 -143
  119. package/skills/v8-explorer-tree/SKILL.md +64 -64
  120. package/skills/v8-export-import/references/progressive-01-excellayout-/351/253/230/347/272/247/350/207/252/347/224/261/345/270/203/345/261/200.md +201 -201
  121. package/skills/v8-export-import/references/progressive-02-powerpoint-/345/257/274/345/207/272.md +118 -118
  122. package/skills/v8-export-import/references/progressive-03-/345/256/211/345/205/250-/346/200/247/350/203/275/346/263/250/346/204/217.md +32 -32
  123. package/skills/v8-file-upload/SKILL.md +154 -154
  124. package/skills/v8-file-upload/references/progressive-01-/345/205/254/346/234/211/346/241/266-vs-/347/247/201/346/234/211/346/241/266.md +133 -133
  125. package/skills/v8-file-upload/references/progressive-02-office-/346/226/207/344/273/266/345/234/250/347/272/277/347/274/226/350/276/221/347/211/210/346/234/254/345/217/267/350/247/204/345/210/231.md +138 -138
  126. package/skills/v8-formengine-http/SKILL.md +107 -107
  127. package/skills/v8-frontend-events/SKILL.md +22 -22
  128. package/skills/v8-frontend-events/references/bluetooth-print-api.md +135 -135
  129. package/skills/v8-frontend-events/references/bluetooth-print.md +247 -247
  130. package/skills/v8-frontend-events/references/progressive-01-/345/210/227/350/241/250/344/272/213/344/273/266.md +50 -50
  131. package/skills/v8-http-integration/SKILL.md +106 -106
  132. package/skills/v8-http-integration/references/progressive-01-get-/350/257/267/346/261/202.md +31 -31
  133. package/skills/v8-http-integration/references/progressive-02-/351/224/231/350/257/257/345/244/204/347/220/206/346/250/241/345/274/217.md +5 -5
  134. package/skills/v8-image-processing/SKILL.md +190 -190
  135. package/skills/v8-image-processing/agents/openai.yaml +4 -4
  136. package/skills/v8-image-processing/references/api-reference.md +623 -623
  137. package/skills/v8-menu-buttons/SKILL.md +103 -103
  138. package/skills/v8-menu-buttons/references/progressive-01-2-/346/214/211/351/222/256/345/257/271/350/261/241-schema.md +145 -145
  139. package/skills/v8-menu-buttons/references/progressive-02-8-/346/250/241/345/274/217-f-/345/220/216/345/217/260/344/273/273/345/212/241/346/214/211/351/222/256-/351/225/277/344/273/273/345/212/241.md +228 -228
  140. package/skills/v8-menu-buttons/references/progressive-03-10-/345/217/215/346/250/241/345/274/217-/351/201/277/345/205/215.md +43 -43
  141. package/skills/v8-mongodb/SKILL.md +65 -65
  142. package/skills/v8-mq-mqtt/SKILL.md +175 -175
  143. package/skills/v8-mq-mqtt/references/mqtt-production.md +342 -342
  144. package/skills/v8-mq-mqtt/references/progressive-01-v8-mqtt-iot-/347/211/251/350/201/224/347/275/221.md +137 -137
  145. package/skills/v8-mq-mqtt/scripts/check-mqtt-skill-coverage.mjs +203 -203
  146. package/skills/v8-saas-multi-tenant/SKILL.md +223 -223
  147. package/skills/v8-security/SKILL.md +25 -25
  148. package/skills/v8-security/references/progressive-01-2-/346/235/203/351/231/220/346/240/241/351/252/214.md +122 -122
  149. package/skills/v8-sql-query/SKILL.md +127 -127
  150. package/skills/v8-table-event/SKILL.md +20 -20
  151. package/skills/v8-table-event/references/progressive-01-informv8-js-/350/241/250/345/215/225/346/211/223/345/274/200/344/272/213/344/273/266.md +18 -18
  152. package/skills/v8-table-event/references/progressive-02-/345/211/215/347/253/257/344/272/213/344/273/266/345/220/215-v8-eventname-/345/217/257/350/203/275/347/232/204/345/200/274.md +15 -15
  153. package/skills/v8-tcp-integration/SKILL.md +1 -1
  154. package/skills/v8-tcp-integration/agents/openai.yaml +4 -4
  155. package/skills/v8-template-engine/SKILL.md +59 -59
  156. package/skills/v8-utilities/SKILL.md +92 -92
  157. package/skills/v8-utilities/references/client-api-index.md +143 -143
  158. package/skills/v8-utilities/references/platform-http-routes.md +83 -83
  159. package/skills/v8-utilities/references/server-api-index.md +74 -74
  160. package/skills/v8-workflow/SKILL.md +44 -44
  161. package/skills/vision-engine/SKILL.md +19 -19
  162. package/skills/vision-engine/references/architecture-and-acceptance.md +34 -34
  163. package/skills/workspace-conventions/SKILL.md +236 -236
  164. package/skills/workspace-conventions/references/progressive-01-/347/211/210/346/234/254/346/233/264/346/226/260/346/227/245/345/277/227/344/277/235/346/212/244/350/247/204/345/210/231-/345/274/272/345/210/266.md +208 -208
  165. package/skills/workspace-conventions/references/progressive-02-microi-net-api-/346/234/254/345/234/260/345/220/257/345/212/250/347/272/246/345/256/232.md +179 -179
  166. package/skills/workspace-conventions/references/progressive-03-cli-/344/270/216-ide-/346/217/222/344/273/266/351/224/231/347/211/210/345/205/261/345/255/230/347/272/246/345/256/232.md +21 -21
@@ -1,126 +1,126 @@
1
- ---
2
- name: message-notification
3
- description: 设计、实现、迁移和验收 Microi 多通道消息通知。用于涉及 wx_tpl_msg、mic_msgset、mic_msg_event_log、微信公众号或服务号模板消息、小程序跳转、短信、邮件、平台内部通知、V8.Notification、通知中心 SignalR、msg_event、消息幂等或通知应用商城交付的任务。
4
- ---
5
-
6
- > **Codex 非阻塞自动更新:** 当前宿主为 Codex 时,吾码 CLI、Codex 插件与工作区 AI/MCP 由后台自动更新;需要诊断时读取 `../microi-codex-installer/SKILL.md`。更新失败、等待空闲或尚未重载均不得阻断当前、正在进行或新建任务。非 Codex 宿主跳过此项。
7
-
8
- # Microi 消息通知
9
-
10
- ## 目标
11
-
12
- 交付“配置可维护、事件先持久化、实时可降级、多节点不重复、租户不串线”的通知能力。支持微信公众号/服务号模板消息、短信、邮件和平台内部通知;小程序是公众号模板消息的跳转目标,不是独立的公众号发送主体。
13
-
14
- ## 开始前
15
-
16
- 1. 读取工作区 `AGENTS.md`,并按任务同时读取 `microi-db-schema`、`v8-api-config`、`v8-frontend-events`、`microi-client-frontend`;涉及商城时再读 `app-store`,涉及浏览器时再读 `playwright-e2e`。
17
- 2. 用用户点名的 MCP 连接读取实时结构,不以本地字典替代远端事实。至少读取 `wx_tpl_msg`、`mic_msgset`、`mic_msg_event_log`,按需读取 `wx_mp`、`wx_mini_program`、`sys_menu` 和接口引擎。
18
- 3. 多租户比较按字段语义合并:保留双方新增字段、控件、说明和数据源,再把并集同步到双方。每次写入后重新读取字段、物理索引和接口源码。
19
- 4. 只有用户明确要求时才复制渠道配置。复制微信公众号/小程序密钥时不在输出中打印秘密;模板、发送主体和小程序跳转引用必须一起回读验证。
20
-
21
- ## 核心模型
22
-
23
- - `mic_msgset`:通知策略。`Key` 是稳定业务键,`Type` 是多选渠道,`ChannelApiEngineMap` 配置短信、邮件或自定义渠道适配器。
24
- - `wx_tpl_msg`:微信公众号/服务号模板。`WxMpId` 决定发送主体;`MiniProgramId`、`MiniProgramAppId`、`MiniProgramPagePath` 仅表示点击模板消息后跳入的小程序。
25
- - `mic_msg_event_log`:每位接收人、每个渠道的权威事件记录。至少包含稳定 `EventId`、`ChannelType`、`ReceiverUserId`、标题、内容、链接、Payload、已读状态和结果。
26
- - 唯一约束:`EventId + ChannelType + ReceiverUserId`。租户使用独立业务库时表内无需虚构 `OsClient` 字段;共享库模型则必须把租户键加入唯一约束。
27
-
28
- 完整字段、接口和可靠性契约见 [references/contracts.md](references/contracts.md)。
29
-
30
- ## 实现流程
31
-
32
- ### 1. 合并结构
33
-
34
- 对两个租户分别读取字段列表,按 `Name` 生成差异表。新增缺失字段后刷新缓存,并回读:
35
-
36
- - `mic_msgset.Type` 包含 `微信公众号模板消息`、`短信`、`邮件`、`平台内部`;
37
- - `mic_msgset.ChannelApiEngineMap` 为 JSON 对象;
38
- - `wx_tpl_msg` 同时有 `WxMpId/WxMpName` 和小程序跳转字段;
39
- - `mic_msg_event_log` 有完整的事件、接收人、渠道、内容和已读字段;
40
- - 业务唯一索引与常用未读查询索引存在。
41
-
42
- 不要用一次性 SQL 修某个租户而跳过通用表单/资源升级路径。应用包与平台升级资源必须携带同一结构。
43
-
44
- ### 2. 配置发送策略
45
-
46
- `mic_msgset.Key` 对业务长期稳定。接收人可以来自固定用户、角色和调用参数,必须去重并限制扇出。渠道适配器统一接收:
47
-
48
- ```js
49
- {
50
- EventId: '业务稳定幂等键',
51
- ChannelType: '短信',
52
- User: { Id: '...', Phone: '...', Email: '...', WxOpenId: '...' },
53
- Title: '审批提醒',
54
- Content: '您有一条待审批记录',
55
- LinkUrl: '/#/approval/123',
56
- Payload: { BusinessId: '123' }
57
- }
58
- ```
59
-
60
- 适配器必须按 `EventId` 幂等。不要把密钥放进 `ChannelApiEngineMap` 或 Payload;密钥保存在对应渠道配置表或租户安全配置中。
61
-
62
- ### 3. 后端发送
63
-
64
- 业务代码优先调用 `msg_event`,由它读取策略、解析接收人、原子登记日志后分发。调用方在重试时保持同一个 `EventId`:
65
-
66
- ```js
67
- return V8.ApiEngine.Run('msg_event', {
68
- MsgKey: 'order_wait_approve',
69
- EventId: 'order-wait-approve-' + V8.Param.OrderId,
70
- ReceiverUserIds: [V8.Param.ApproverId],
71
- Content: '订单 ' + V8.Param.OrderNo + ' 等待审批',
72
- LinkUrl: '/#/orders/detail?id=' + V8.Param.OrderId,
73
- Payload: { OrderId: V8.Param.OrderId }
74
- }, V8.DbTrans);
75
- ```
76
-
77
- `V8.Notification.Send` 是宿主的“平台内部实时提示”原语。它不替代日志 claim,通常只由 `msg_event` 在日志成功登记后调用。事务存在时,推送在提交后进行有界等待;回滚不得推送。
78
-
79
- ### 4. 前端通知中心
80
-
81
- 前端 V8 使用 `V8.Notification.List` 获取当前登录用户的权威快照,使用 `MarkRead` 标记本人通知。SignalR 固定事件 `ReceivePlatformNotification` 只用于低延迟刷新:客户端按 `Id/EventId` 去重,收到后仍以列表接口回读为准。
82
-
83
- ```js
84
- await V8.Notification.Send('order_wait_approve', {
85
- EventId: 'order-wait-approve-' + V8.Form.Id,
86
- ReceiverUserIds: [V8.Form.ApproverId],
87
- Content: '订单等待审批'
88
- });
89
-
90
- var result = await V8.Notification.List({ PageIndex: 1, PageSize: 20 });
91
- await V8.Notification.MarkRead(result.Data[0].Id);
92
- await V8.Notification.MarkRead({ All: true });
93
- ```
94
-
95
- 列表和已读接口必须以 `V8.CurrentUser.Id` 作为服务端过滤条件,不能信任客户端传入的用户 Id。外链只允许站内路径、锚点或 `http/https`。
96
-
97
- ### 5. 多节点可靠性
98
-
99
- - 数据库日志是事实源,SignalR 是可丢失提示;Redis backplane 使任一节点能通知连接在其它节点的用户。
100
- - “先查询再新增”不能防并发;依赖唯一索引抢占。同一事件重复投递只能产生一份 `EventId + 渠道 + 接收人` 记录。
101
- - 外部供应商在“已发送但响应丢失”时无法凭本地状态保证恰好一次。适配器必须把 `EventId` 传给支持幂等的供应商;不支持时进入可审计的人工确认/重试状态。
102
- - 发布中新旧版本短暂共存,先扩展字段与接口,再发布读写代码,最后才收缩旧字段。
103
-
104
- ## 应用商城交付
105
-
106
- “消息通知”应用包必须包含 `mic_msgset`、`mic_msg_event_log`、`wx_tpl_msg`、`wx_mp`、`wx_mini_program` 五张结构资源,以及相关菜单、`msg_event`、`msg_internal_list`、`msg_internal_mark_read`、`platform-chat-system-message`、`platform-chat-runtime`、`platform-message-notification-custom-hook` 和必要索引。`wx_mp`、`wx_mini_program` 只交付物理表结构与表单字段元数据,不得携带数据集;否则既可能泄露真实公众号/小程序密钥,也会覆盖目标租户配置。`sys_user.WxMpId` 和 `wx_tpl_msg` 会读取 `wx_mp`,漏包会使 `/system/diy-user` 等无关页面在加载 Select 数据源时触发 `GetDiyFieldSqlData` 缺表错误。包内不得包含真实公众号 Token/AppSecret、用户接收人、OpenId、历史发送记录或租户专属 URL。先 `ValidateOnly`,再在全新或缺表目标租户真实安装,回读五张表、应用版本和依赖页面;结构校验不能替代真实安装验收。
107
-
108
- 应用包中的 `sys_apiengine.Id` 是跨应用共享物理表的稳定主键,必须在全部官方应用范围内全局唯一;不能只检查单包内 Key/Id。发布前必须同时扫描全部官方包的 `Id` 与 `ApiEngineKey`,任一跨包重复都应阻断发布和离线包生成。
109
-
110
- 系统聊天门面 `platform-chat-system-message`(`Managed`)完成平台超级管理员校验后,只转调本应用单一拥有的 `platform-chat-runtime`(`Managed`)。运行时统一编排 `PersistMessage / PersistSystemMessage / PersistAssistantMessage / GetHistoryAndMarkRead / GetUnreadCount / TouchContact / ListContacts / DeleteContact`;Hub/Controller 旧入口只保留 DiyToken 认证、SignalR 投递和 AI 流式协议,不得直连 MongoDB/FormEngine 复制业务。访问密钥会话、空 Token、伪造租户/发送人必须失败关闭。
111
-
112
- `platform-chat-runtime` 以 `V8.CurrentUser` / `V8.OsClient` 为唯一身份与租户事实源,对“租户 + 稳定 RequestId”生成确定性 Mongo `_id`;只有全部载荷哈希一致才复用旧记录。MongoDB 不参与 `V8.DbTrans`,因此消息/已读/联系人成功后即是已提交事实;SignalR、投影或 After Hook 失败必须保持 `Code=1` 并通过 `DataAppend.HookWarning` / `ProjectionWarnings` 告警,不得伪装未发生而引导盲目重试。调用 `V8.MongoDb.UptFormDataByWhere` / `DelFormDataByWhere` 时必须使用包含当前用户/权威资源边界的非空参数化 `_Where`,规则详见 `../v8-mongodb/SKILL.md`。
113
-
114
- `platform-chat-runtime` 必须保持 `StopHttp=1`、`AllowAnonymous=0`。SignalR Hub 在 DiyToken 与租户核验后,通过宿主一次性可信协议作用域调用,并携带宿主生成的权威当前用户快照;V8 对 `_InvokeType=Client` 的调用必须先执行 `V8.Method.RequireManagedProtocolContext()` 原子消费。不得为修复 Hub 误报“禁止 HTTP 调用”而开放 `StopHttp`,也不得接受 Param 中的信任布尔值、用户或租户覆盖;接口引擎内部 `Server` 嵌套调用保持原有语义。
115
-
116
- 租户个性化仅写入 `platform-message-notification-custom-hook`(`CreateIfMissing`),默认正文必须精确为 `return { Code : 1 };`。运行时在 `BeforeChatRuntime / AfterChatRuntime` 调用 Hook:Before 失败在 Mongo 写前阻断,After 失败只告警。Hook 只接收 `Stage`、`SourceApiEngineKey`、`Action`、`ActorUserId`、`PeerUserId`、`MessageId`、`MessageType`;正文、头像、OpenId、Token 与其它秘密不得进入租户扩展。三项接口的源码顶部都要保留官方恢复/租户不覆盖提示,并在包合同测试中逐字核对独立源码、包内副本、所有权策略和 HTTP/匿名开关。
117
-
118
- ## 最低验收
119
-
120
- 1. 两个 MCP 租户的字段、数据源、物理索引和三段接口代码回读一致。
121
- 2. 重复 `EventId`、重复接收人和两个 API 节点并发发送,持久副作用仅一次。
122
- 3. 事务回滚不推送;提交后在线用户即时收到,离线/SignalR/Redis 故障后登录仍能回读。
123
- 4. 用户只能查询和标记自己的通知;危险链接、超长正文、跨租户接收人和匿名调用被拒绝。
124
- 5. 公众号/服务号发送主体与小程序跳转目标分别验证,不把 `MiniProgramAppId` 当作模板发送主体。
125
- 6. 源码定向测试、后端编译、远端 MCP 回读、真实浏览器点击和商城安装/校验分别报告;未执行的生产发布不得写成已上线。
126
- 7. 聊天空 Token/访问密钥/伪造租户失败关闭;相同 `RequestId` 并发只有一份 Mongo 事实,不同载荷冲突拒绝;已持久后 SignalR/After Hook 失败仍返回成功并可回读。
1
+ ---
2
+ name: message-notification
3
+ description: 设计、实现、迁移和验收 Microi 多通道消息通知。用于涉及 wx_tpl_msg、mic_msgset、mic_msg_event_log、微信公众号或服务号模板消息、小程序跳转、短信、邮件、平台内部通知、V8.Notification、通知中心 SignalR、msg_event、消息幂等或通知应用商城交付的任务。
4
+ ---
5
+
6
+ > **Codex 非阻塞自动更新:** 当前宿主为 Codex 时,吾码 CLI、Codex 插件与工作区 AI/MCP 由后台自动更新;需要诊断时读取 `../microi-codex-installer/SKILL.md`。更新失败、等待空闲或尚未重载均不得阻断当前、正在进行或新建任务。非 Codex 宿主跳过此项。
7
+
8
+ # Microi 消息通知
9
+
10
+ ## 目标
11
+
12
+ 交付“配置可维护、事件先持久化、实时可降级、多节点不重复、租户不串线”的通知能力。支持微信公众号/服务号模板消息、短信、邮件和平台内部通知;小程序是公众号模板消息的跳转目标,不是独立的公众号发送主体。
13
+
14
+ ## 开始前
15
+
16
+ 1. 读取工作区 `AGENTS.md`,并按任务同时读取 `microi-db-schema`、`v8-api-config`、`v8-frontend-events`、`microi-client-frontend`;涉及商城时再读 `app-store`,涉及浏览器时再读 `playwright-e2e`。
17
+ 2. 用用户点名的 MCP 连接读取实时结构,不以本地字典替代远端事实。至少读取 `wx_tpl_msg`、`mic_msgset`、`mic_msg_event_log`,按需读取 `wx_mp`、`wx_mini_program`、`sys_menu` 和接口引擎。
18
+ 3. 多租户比较按字段语义合并:保留双方新增字段、控件、说明和数据源,再把并集同步到双方。每次写入后重新读取字段、物理索引和接口源码。
19
+ 4. 只有用户明确要求时才复制渠道配置。复制微信公众号/小程序密钥时不在输出中打印秘密;模板、发送主体和小程序跳转引用必须一起回读验证。
20
+
21
+ ## 核心模型
22
+
23
+ - `mic_msgset`:通知策略。`Key` 是稳定业务键,`Type` 是多选渠道,`ChannelApiEngineMap` 配置短信、邮件或自定义渠道适配器。
24
+ - `wx_tpl_msg`:微信公众号/服务号模板。`WxMpId` 决定发送主体;`MiniProgramId`、`MiniProgramAppId`、`MiniProgramPagePath` 仅表示点击模板消息后跳入的小程序。
25
+ - `mic_msg_event_log`:每位接收人、每个渠道的权威事件记录。至少包含稳定 `EventId`、`ChannelType`、`ReceiverUserId`、标题、内容、链接、Payload、已读状态和结果。
26
+ - 唯一约束:`EventId + ChannelType + ReceiverUserId`。租户使用独立业务库时表内无需虚构 `OsClient` 字段;共享库模型则必须把租户键加入唯一约束。
27
+
28
+ 完整字段、接口和可靠性契约见 [references/contracts.md](references/contracts.md)。
29
+
30
+ ## 实现流程
31
+
32
+ ### 1. 合并结构
33
+
34
+ 对两个租户分别读取字段列表,按 `Name` 生成差异表。新增缺失字段后刷新缓存,并回读:
35
+
36
+ - `mic_msgset.Type` 包含 `微信公众号模板消息`、`短信`、`邮件`、`平台内部`;
37
+ - `mic_msgset.ChannelApiEngineMap` 为 JSON 对象;
38
+ - `wx_tpl_msg` 同时有 `WxMpId/WxMpName` 和小程序跳转字段;
39
+ - `mic_msg_event_log` 有完整的事件、接收人、渠道、内容和已读字段;
40
+ - 业务唯一索引与常用未读查询索引存在。
41
+
42
+ 不要用一次性 SQL 修某个租户而跳过通用表单/资源升级路径。应用包与平台升级资源必须携带同一结构。
43
+
44
+ ### 2. 配置发送策略
45
+
46
+ `mic_msgset.Key` 对业务长期稳定。接收人可以来自固定用户、角色和调用参数,必须去重并限制扇出。渠道适配器统一接收:
47
+
48
+ ```js
49
+ {
50
+ EventId: '业务稳定幂等键',
51
+ ChannelType: '短信',
52
+ User: { Id: '...', Phone: '...', Email: '...', WxOpenId: '...' },
53
+ Title: '审批提醒',
54
+ Content: '您有一条待审批记录',
55
+ LinkUrl: '/#/approval/123',
56
+ Payload: { BusinessId: '123' }
57
+ }
58
+ ```
59
+
60
+ 适配器必须按 `EventId` 幂等。不要把密钥放进 `ChannelApiEngineMap` 或 Payload;密钥保存在对应渠道配置表或租户安全配置中。
61
+
62
+ ### 3. 后端发送
63
+
64
+ 业务代码优先调用 `msg_event`,由它读取策略、解析接收人、原子登记日志后分发。调用方在重试时保持同一个 `EventId`:
65
+
66
+ ```js
67
+ return V8.ApiEngine.Run('msg_event', {
68
+ MsgKey: 'order_wait_approve',
69
+ EventId: 'order-wait-approve-' + V8.Param.OrderId,
70
+ ReceiverUserIds: [V8.Param.ApproverId],
71
+ Content: '订单 ' + V8.Param.OrderNo + ' 等待审批',
72
+ LinkUrl: '/#/orders/detail?id=' + V8.Param.OrderId,
73
+ Payload: { OrderId: V8.Param.OrderId }
74
+ }, V8.DbTrans);
75
+ ```
76
+
77
+ `V8.Notification.Send` 是宿主的“平台内部实时提示”原语。它不替代日志 claim,通常只由 `msg_event` 在日志成功登记后调用。事务存在时,推送在提交后进行有界等待;回滚不得推送。
78
+
79
+ ### 4. 前端通知中心
80
+
81
+ 前端 V8 使用 `V8.Notification.List` 获取当前登录用户的权威快照,使用 `MarkRead` 标记本人通知。SignalR 固定事件 `ReceivePlatformNotification` 只用于低延迟刷新:客户端按 `Id/EventId` 去重,收到后仍以列表接口回读为准。
82
+
83
+ ```js
84
+ await V8.Notification.Send('order_wait_approve', {
85
+ EventId: 'order-wait-approve-' + V8.Form.Id,
86
+ ReceiverUserIds: [V8.Form.ApproverId],
87
+ Content: '订单等待审批'
88
+ });
89
+
90
+ var result = await V8.Notification.List({ PageIndex: 1, PageSize: 20 });
91
+ await V8.Notification.MarkRead(result.Data[0].Id);
92
+ await V8.Notification.MarkRead({ All: true });
93
+ ```
94
+
95
+ 列表和已读接口必须以 `V8.CurrentUser.Id` 作为服务端过滤条件,不能信任客户端传入的用户 Id。外链只允许站内路径、锚点或 `http/https`。
96
+
97
+ ### 5. 多节点可靠性
98
+
99
+ - 数据库日志是事实源,SignalR 是可丢失提示;Redis backplane 使任一节点能通知连接在其它节点的用户。
100
+ - “先查询再新增”不能防并发;依赖唯一索引抢占。同一事件重复投递只能产生一份 `EventId + 渠道 + 接收人` 记录。
101
+ - 外部供应商在“已发送但响应丢失”时无法凭本地状态保证恰好一次。适配器必须把 `EventId` 传给支持幂等的供应商;不支持时进入可审计的人工确认/重试状态。
102
+ - 发布中新旧版本短暂共存,先扩展字段与接口,再发布读写代码,最后才收缩旧字段。
103
+
104
+ ## 应用商城交付
105
+
106
+ “消息通知”应用包必须包含 `mic_msgset`、`mic_msg_event_log`、`wx_tpl_msg`、`wx_mp`、`wx_mini_program` 五张结构资源,以及相关菜单、`msg_event`、`msg_internal_list`、`msg_internal_mark_read`、`platform-chat-system-message`、`platform-chat-runtime`、`platform-message-notification-custom-hook` 和必要索引。`wx_mp`、`wx_mini_program` 只交付物理表结构与表单字段元数据,不得携带数据集;否则既可能泄露真实公众号/小程序密钥,也会覆盖目标租户配置。`sys_user.WxMpId` 和 `wx_tpl_msg` 会读取 `wx_mp`,漏包会使 `/system/diy-user` 等无关页面在加载 Select 数据源时触发 `GetDiyFieldSqlData` 缺表错误。包内不得包含真实公众号 Token/AppSecret、用户接收人、OpenId、历史发送记录或租户专属 URL。先 `ValidateOnly`,再在全新或缺表目标租户真实安装,回读五张表、应用版本和依赖页面;结构校验不能替代真实安装验收。
107
+
108
+ 应用包中的 `sys_apiengine.Id` 是跨应用共享物理表的稳定主键,必须在全部官方应用范围内全局唯一;不能只检查单包内 Key/Id。发布前必须同时扫描全部官方包的 `Id` 与 `ApiEngineKey`,任一跨包重复都应阻断发布和离线包生成。
109
+
110
+ 系统聊天门面 `platform-chat-system-message`(`Managed`)完成平台超级管理员校验后,只转调本应用单一拥有的 `platform-chat-runtime`(`Managed`)。运行时统一编排 `PersistMessage / PersistSystemMessage / PersistAssistantMessage / GetHistoryAndMarkRead / GetUnreadCount / TouchContact / ListContacts / DeleteContact`;Hub/Controller 旧入口只保留 DiyToken 认证、SignalR 投递和 AI 流式协议,不得直连 MongoDB/FormEngine 复制业务。访问密钥会话、空 Token、伪造租户/发送人必须失败关闭。
111
+
112
+ `platform-chat-runtime` 以 `V8.CurrentUser` / `V8.OsClient` 为唯一身份与租户事实源,对“租户 + 稳定 RequestId”生成确定性 Mongo `_id`;只有全部载荷哈希一致才复用旧记录。MongoDB 不参与 `V8.DbTrans`,因此消息/已读/联系人成功后即是已提交事实;SignalR、投影或 After Hook 失败必须保持 `Code=1` 并通过 `DataAppend.HookWarning` / `ProjectionWarnings` 告警,不得伪装未发生而引导盲目重试。调用 `V8.MongoDb.UptFormDataByWhere` / `DelFormDataByWhere` 时必须使用包含当前用户/权威资源边界的非空参数化 `_Where`,规则详见 `../v8-mongodb/SKILL.md`。
113
+
114
+ `platform-chat-runtime` 必须保持 `StopHttp=1`、`AllowAnonymous=0`。SignalR Hub 在 DiyToken 与租户核验后,通过宿主一次性可信协议作用域调用,并携带宿主生成的权威当前用户快照;V8 对 `_InvokeType=Client` 的调用必须先执行 `V8.Method.RequireManagedProtocolContext()` 原子消费。不得为修复 Hub 误报“禁止 HTTP 调用”而开放 `StopHttp`,也不得接受 Param 中的信任布尔值、用户或租户覆盖;接口引擎内部 `Server` 嵌套调用保持原有语义。
115
+
116
+ 租户个性化仅写入 `platform-message-notification-custom-hook`(`CreateIfMissing`),默认正文必须精确为 `return { Code : 1 };`。运行时在 `BeforeChatRuntime / AfterChatRuntime` 调用 Hook:Before 失败在 Mongo 写前阻断,After 失败只告警。Hook 只接收 `Stage`、`SourceApiEngineKey`、`Action`、`ActorUserId`、`PeerUserId`、`MessageId`、`MessageType`;正文、头像、OpenId、Token 与其它秘密不得进入租户扩展。三项接口的源码顶部都要保留官方恢复/租户不覆盖提示,并在包合同测试中逐字核对独立源码、包内副本、所有权策略和 HTTP/匿名开关。
117
+
118
+ ## 最低验收
119
+
120
+ 1. 两个 MCP 租户的字段、数据源、物理索引和三段接口代码回读一致。
121
+ 2. 重复 `EventId`、重复接收人和两个 API 节点并发发送,持久副作用仅一次。
122
+ 3. 事务回滚不推送;提交后在线用户即时收到,离线/SignalR/Redis 故障后登录仍能回读。
123
+ 4. 用户只能查询和标记自己的通知;危险链接、超长正文、跨租户接收人和匿名调用被拒绝。
124
+ 5. 公众号/服务号发送主体与小程序跳转目标分别验证,不把 `MiniProgramAppId` 当作模板发送主体。
125
+ 6. 源码定向测试、后端编译、远端 MCP 回读、真实浏览器点击和商城安装/校验分别报告;未执行的生产发布不得写成已上线。
126
+ 7. 聊天空 Token/访问密钥/伪造租户失败关闭;相同 `RequestId` 并发只有一份 Mongo 事实,不同载荷冲突拒绝;已持久后 SignalR/After Hook 失败仍返回成功并可回读。
@@ -1,5 +1,5 @@
1
- interface:
2
- display_name: "Microi 消息通知"
3
- short_description: "设计、实现并验收租户安全的多通道与平台内部实时消息通知"
4
- brand_color: "#409EFF"
5
- default_prompt: "Use $message-notification to design and verify a tenant-safe Microi notification flow."
1
+ interface:
2
+ display_name: "Microi 消息通知"
3
+ short_description: "设计、实现并验收租户安全的多通道与平台内部实时消息通知"
4
+ brand_color: "#409EFF"
5
+ default_prompt: "Use $message-notification to design and verify a tenant-safe Microi notification flow."
@@ -1,102 +1,102 @@
1
- # 消息通知契约
2
-
3
- ## 表结构并集
4
-
5
- ### `mic_msgset`
6
-
7
- | 字段 | 用途 |
8
- |---|---|
9
- | `Key` | 稳定业务键,租户内唯一 |
10
- | `Title` | 配置名称/默认标题 |
11
- | `IsEnable` | 总开关 |
12
- | `Type` | 多选渠道:微信公众号模板消息、短信、邮件、平台内部 |
13
- | `Receivers` | 固定接收用户 JSON |
14
- | `ReceiversRoles` | 固定接收角色 JSON |
15
- | `WxTplMsgId` | 公众号模板配置 Id |
16
- | `ChannelApiEngineMap` | 渠道到适配器接口引擎 Key 的 JSON 映射 |
17
- | `TenantId/TenantName` | 业务层租户信息;不能替代 MCP 的 OsClient 边界 |
18
- | `TableChild99` | 兼容已有子表配置 |
19
-
20
- ### `wx_tpl_msg`
21
-
22
- | 字段 | 用途 |
23
- |---|---|
24
- | `Key/Title/TemplateId/Content/Remark/LinkUrl` | 模板业务键、标题、微信模板 Id、内容与普通跳转 |
25
- | `WxMpId/WxMpName` | 发送模板消息的公众号或服务号;关联 `wx_mp` |
26
- | `MiniProgramId/MiniProgramName` | 可选小程序配置;关联 `wx_mini_program` |
27
- | `MiniProgramAppId/MiniProgramPagePath` | 模板消息的可选小程序跳转目标 |
28
-
29
- 公众号和服务号都属于微信公众帐号,由 `wx_mp` 保存发送凭据。小程序由 `wx_mini_program` 保存,不能使用小程序 AppId 调用公众号模板消息发送接口。
30
-
31
- ### `mic_msg_event_log`
32
-
33
- | 字段 | 用途 |
34
- |---|---|
35
- | `EventId` | 调用方稳定幂等键 |
36
- | `MsgEventId` | 关联的消息设置 Id |
37
- | `ChannelType` | 本条日志对应的渠道 |
38
- | `ReceiverUserId` | 单一接收用户 Id |
39
- | `Receivers` | 接收人安全快照 JSON |
40
- | `Title/MsgContent/LinkUrl/Payload` | 通知展示快照 |
41
- | `IsRead/ReadTime` | 平台内部通知已读状态 |
42
- | `IsSuccess/MsgResult` | 分发状态和经过脱敏的结果 |
43
-
44
- 索引基线:
45
-
46
- - 唯一:`EventId, ChannelType, ReceiverUserId`;共享表模型再前置 `OsClient`。
47
- - 普通:`ReceiverUserId, ChannelType, IsRead, CreateTime`。
48
- - `mic_msgset.Key`、`wx_tpl_msg.Key` 在租户业务库内唯一。
49
-
50
- ## V8 接口
51
-
52
- ### `msg_event`
53
-
54
- 输入:
55
-
56
- ```js
57
- {
58
- MsgKey: '策略 Key',
59
- EventId: '稳定幂等键',
60
- ReceiverUserId: '可选单用户',
61
- ReceiverUserIds: ['可选用户数组'],
62
- Title: '可覆盖配置标题',
63
- Content: '正文',
64
- LinkUrl: '/#/route',
65
- Payload: { BusinessId: '...' }
66
- }
67
- ```
68
-
69
- 处理顺序:校验当前租户与登录上下文 → 读取启用策略 → 合并固定用户、角色用户和参数用户 → 去重/限流 → 按接收人和渠道插入日志 claim → 仅对 claim 成功项分发 → 汇总成功、失败、重复。出现部分失败时仍要提交已经产生的日志与外部副作用,并把失败逐项返回,不能为了漂亮的 `Code` 回滚成功事实。
70
-
71
- ### `msg_internal_list`
72
-
73
- - 仅返回 `V8.CurrentUser.Id` 的 `ChannelType=平台内部` 记录。
74
- - 支持 `PageIndex/PageSize`,`PageSize` 最大 100。
75
- - `DataAppend.UnreadCount` 返回同一用户权威未读数。
76
- - 每条记录统一投影 `SenderUserId/Account=AI`、`SenderName=AI助手`、`ReadOnly=false`;聊天侧只能固定一个 AI 助手联系人,并将通知权威历史与 AI 聊天历史按时间合并。
77
- - 兼容旧 `MICROI_PLATFORM_ADMIN/admin` 元数据时只改显示投影,不批量删除或改写 `mic_msg_event_log` 历史事实。
78
-
79
- ### `msg_internal_mark_read`
80
-
81
- - `{ Id }` 只允许更新当前用户拥有的单条平台内部通知。
82
- - `{ All: true }` 更新当前用户全部未读平台内部通知。
83
- - 不接受客户端指定 `ReceiverUserId` 越权操作。
84
-
85
- ### `V8.Notification.Send`
86
-
87
- `ReceiverUserId/ReceiverUserIds` 必填其一,最多 200 个;`Title` 最长 200 字符;`Content` 与序列化后的 `Payload` 各最多 32 KiB;`LinkUrl` 最长 500 字符且只允许站内路径、锚点、HTTP/HTTPS。事件名固定为 `ReceivePlatformNotification`。
88
-
89
- ## 验收矩阵
90
-
91
- | 场景 | 断言 |
92
- |---|---|
93
- | 重复请求 | 同一接收人/渠道只存在一条日志,适配器不重复产生业务副作用 |
94
- | 两节点同时发送 | 唯一索引只有一个 claim 成功,两节点都不崩溃 |
95
- | 写入后节点退出 | 日志仍可查询;发送状态可审计、可补偿 |
96
- | SignalR/Redis 短故障 | 业务写入不回滚,客户端列表回读恢复 |
97
- | SignalR Hub 调用聊天运行时 | `StopHttp=1` 保持关闭;仅固定 Key/租户/权威用户绑定的一次性宿主上下文可通过,V8 原子消费一次 |
98
- | 事务回滚 | 不产生实时通知,业务日志随事务回滚 |
99
- | 离线用户 | 下次打开通知中心能看到并标记已读 |
100
- | 越权读取/已读 | 其它用户 Id 无效,记录不改变 |
101
- | 微信配置 | `WxMpId` 决定发送主体,小程序字段只决定跳转 |
102
- | 应用安装 | 无密钥、OpenId、历史日志或固定用户;安装后字段/索引/接口回读一致 |
1
+ # 消息通知契约
2
+
3
+ ## 表结构并集
4
+
5
+ ### `mic_msgset`
6
+
7
+ | 字段 | 用途 |
8
+ |---|---|
9
+ | `Key` | 稳定业务键,租户内唯一 |
10
+ | `Title` | 配置名称/默认标题 |
11
+ | `IsEnable` | 总开关 |
12
+ | `Type` | 多选渠道:微信公众号模板消息、短信、邮件、平台内部 |
13
+ | `Receivers` | 固定接收用户 JSON |
14
+ | `ReceiversRoles` | 固定接收角色 JSON |
15
+ | `WxTplMsgId` | 公众号模板配置 Id |
16
+ | `ChannelApiEngineMap` | 渠道到适配器接口引擎 Key 的 JSON 映射 |
17
+ | `TenantId/TenantName` | 业务层租户信息;不能替代 MCP 的 OsClient 边界 |
18
+ | `TableChild99` | 兼容已有子表配置 |
19
+
20
+ ### `wx_tpl_msg`
21
+
22
+ | 字段 | 用途 |
23
+ |---|---|
24
+ | `Key/Title/TemplateId/Content/Remark/LinkUrl` | 模板业务键、标题、微信模板 Id、内容与普通跳转 |
25
+ | `WxMpId/WxMpName` | 发送模板消息的公众号或服务号;关联 `wx_mp` |
26
+ | `MiniProgramId/MiniProgramName` | 可选小程序配置;关联 `wx_mini_program` |
27
+ | `MiniProgramAppId/MiniProgramPagePath` | 模板消息的可选小程序跳转目标 |
28
+
29
+ 公众号和服务号都属于微信公众帐号,由 `wx_mp` 保存发送凭据。小程序由 `wx_mini_program` 保存,不能使用小程序 AppId 调用公众号模板消息发送接口。
30
+
31
+ ### `mic_msg_event_log`
32
+
33
+ | 字段 | 用途 |
34
+ |---|---|
35
+ | `EventId` | 调用方稳定幂等键 |
36
+ | `MsgEventId` | 关联的消息设置 Id |
37
+ | `ChannelType` | 本条日志对应的渠道 |
38
+ | `ReceiverUserId` | 单一接收用户 Id |
39
+ | `Receivers` | 接收人安全快照 JSON |
40
+ | `Title/MsgContent/LinkUrl/Payload` | 通知展示快照 |
41
+ | `IsRead/ReadTime` | 平台内部通知已读状态 |
42
+ | `IsSuccess/MsgResult` | 分发状态和经过脱敏的结果 |
43
+
44
+ 索引基线:
45
+
46
+ - 唯一:`EventId, ChannelType, ReceiverUserId`;共享表模型再前置 `OsClient`。
47
+ - 普通:`ReceiverUserId, ChannelType, IsRead, CreateTime`。
48
+ - `mic_msgset.Key`、`wx_tpl_msg.Key` 在租户业务库内唯一。
49
+
50
+ ## V8 接口
51
+
52
+ ### `msg_event`
53
+
54
+ 输入:
55
+
56
+ ```js
57
+ {
58
+ MsgKey: '策略 Key',
59
+ EventId: '稳定幂等键',
60
+ ReceiverUserId: '可选单用户',
61
+ ReceiverUserIds: ['可选用户数组'],
62
+ Title: '可覆盖配置标题',
63
+ Content: '正文',
64
+ LinkUrl: '/#/route',
65
+ Payload: { BusinessId: '...' }
66
+ }
67
+ ```
68
+
69
+ 处理顺序:校验当前租户与登录上下文 → 读取启用策略 → 合并固定用户、角色用户和参数用户 → 去重/限流 → 按接收人和渠道插入日志 claim → 仅对 claim 成功项分发 → 汇总成功、失败、重复。出现部分失败时仍要提交已经产生的日志与外部副作用,并把失败逐项返回,不能为了漂亮的 `Code` 回滚成功事实。
70
+
71
+ ### `msg_internal_list`
72
+
73
+ - 仅返回 `V8.CurrentUser.Id` 的 `ChannelType=平台内部` 记录。
74
+ - 支持 `PageIndex/PageSize`,`PageSize` 最大 100。
75
+ - `DataAppend.UnreadCount` 返回同一用户权威未读数。
76
+ - 每条记录统一投影 `SenderUserId/Account=AI`、`SenderName=AI助手`、`ReadOnly=false`;聊天侧只能固定一个 AI 助手联系人,并将通知权威历史与 AI 聊天历史按时间合并。
77
+ - 兼容旧 `MICROI_PLATFORM_ADMIN/admin` 元数据时只改显示投影,不批量删除或改写 `mic_msg_event_log` 历史事实。
78
+
79
+ ### `msg_internal_mark_read`
80
+
81
+ - `{ Id }` 只允许更新当前用户拥有的单条平台内部通知。
82
+ - `{ All: true }` 更新当前用户全部未读平台内部通知。
83
+ - 不接受客户端指定 `ReceiverUserId` 越权操作。
84
+
85
+ ### `V8.Notification.Send`
86
+
87
+ `ReceiverUserId/ReceiverUserIds` 必填其一,最多 200 个;`Title` 最长 200 字符;`Content` 与序列化后的 `Payload` 各最多 32 KiB;`LinkUrl` 最长 500 字符且只允许站内路径、锚点、HTTP/HTTPS。事件名固定为 `ReceivePlatformNotification`。
88
+
89
+ ## 验收矩阵
90
+
91
+ | 场景 | 断言 |
92
+ |---|---|
93
+ | 重复请求 | 同一接收人/渠道只存在一条日志,适配器不重复产生业务副作用 |
94
+ | 两节点同时发送 | 唯一索引只有一个 claim 成功,两节点都不崩溃 |
95
+ | 写入后节点退出 | 日志仍可查询;发送状态可审计、可补偿 |
96
+ | SignalR/Redis 短故障 | 业务写入不回滚,客户端列表回读恢复 |
97
+ | SignalR Hub 调用聊天运行时 | `StopHttp=1` 保持关闭;仅固定 Key/租户/权威用户绑定的一次性宿主上下文可通过,V8 原子消费一次 |
98
+ | 事务回滚 | 不产生实时通知,业务日志随事务回滚 |
99
+ | 离线用户 | 下次打开通知中心能看到并标记已读 |
100
+ | 越权读取/已读 | 其它用户 Id 无效,记录不改变 |
101
+ | 微信配置 | `WxMpId` 决定发送主体,小程序字段只决定跳转 |
102
+ | 应用安装 | 无密钥、OpenId、历史日志或固定用户;安装后字段/索引/接口回读一致 |