@microi.net/cli 5.7.8 → 5.8.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 (189) 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/.workbuddy-plugin/marketplace.json +2 -2
  5. package/.workbuddy-plugin/plugin.json +1 -1
  6. package/LICENSE +21 -21
  7. package/README.md +71 -71
  8. package/assets/build-meta.json +6 -6
  9. package/assets/feature-matrix.json +138 -138
  10. package/assets/logo.svg +4 -4
  11. package/cordis.patch.yml +1 -1
  12. package/package.json +1 -1
  13. package/scripts/mcp-codex-stdio-adapter.js +0 -0
  14. package/scripts/mcp-server.js +113 -112
  15. package/scripts/microi-cli.js +57 -57
  16. package/scripts/microi-codex-broker.js +450 -450
  17. package/scripts/microi-codex-router.js +0 -0
  18. package/scripts/microi-skills.meta.json +364 -364
  19. package/skills/.microi-skills-version.json +2 -2
  20. package/skills/README.md +286 -286
  21. package/skills/ai-engine/SKILL.md +265 -265
  22. package/skills/ai-engine/agents/openai.yaml +4 -4
  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 +396 -396
  26. package/skills/app-store/agents/openai.yaml +4 -4
  27. package/skills/business-blueprint/SKILL.md +193 -193
  28. package/skills/datasource-engine/SKILL.md +90 -90
  29. package/skills/datasource-engine/agents/openai.yaml +4 -4
  30. package/skills/dos-orm/references/api-reference.md +229 -229
  31. package/skills/email-engine/SKILL.md +78 -78
  32. package/skills/email-engine/references/v8-email.md +34 -34
  33. package/skills/job-engine/SKILL.md +172 -172
  34. package/skills/job-engine/agents/openai.yaml +4 -4
  35. package/skills/message-notification/SKILL.md +156 -156
  36. package/skills/message-notification/agents/openai.yaml +5 -5
  37. package/skills/message-notification/references/contracts.md +102 -102
  38. package/skills/microi-ai-app-auth.js +652 -652
  39. package/skills/microi-ai-application/SKILL.md +106 -106
  40. package/skills/microi-ai-application/agents/openai.yaml +4 -4
  41. package/skills/microi-ai-application/references/frontend-baseline.md +164 -164
  42. package/skills/microi-client-frontend/SKILL.md +237 -237
  43. 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 +144 -144
  44. 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 +196 -196
  45. 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 +167 -167
  46. package/skills/microi-codex/SKILL.md +72 -70
  47. package/skills/microi-codex-installer/SKILL.md +225 -223
  48. package/skills/microi-codex-installer/agents/openai.yaml +7 -7
  49. package/skills/microi-datasource-mapping/SKILL.md +108 -108
  50. package/skills/microi-db-schema/SKILL.md +175 -175
  51. package/skills/microi-db-schema/agents/openai.yaml +4 -4
  52. package/skills/microi-db-schema/references/core-tables.md +695 -695
  53. package/skills/microi-db-schema/references/form-component-options.md +256 -256
  54. package/skills/microi-db-schema/references/schema-overview.md +202 -202
  55. package/skills/microi-db-schema/references/schema.md +646 -646
  56. package/skills/microi-db-schema/references/table-catalog.md +1599 -1599
  57. package/skills/microi-deployment/references/deployment-matrix.md +101 -101
  58. package/skills/microi-docs-coverage/scripts/audit-doc-skill-coverage.mjs +894 -894
  59. package/skills/microi-form-engine/SKILL.md +226 -226
  60. package/skills/microi-form-engine/references/component-catalog.md +216 -216
  61. package/skills/microi-form-engine/references/data-source-events.md +124 -124
  62. package/skills/microi-form-layout/SKILL.md +205 -205
  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 +188 -188
  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 +176 -176
  66. package/skills/microi-left-right-layout/SKILL.md +141 -141
  67. package/skills/microi-microservice/SKILL.md +323 -323
  68. package/skills/microi-microservice/references/runtime-delivery.md +278 -278
  69. package/skills/microi-mobile-app-quality/SKILL.md +181 -181
  70. 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
  71. package/skills/microi-mobile-app-quality/references/progressive-02-9-/344/270/273/351/242/230/345/210/207/346/215/242/345/277/205/351/241/273/347/234/237/345/256/236/344/270/224/345/205/250/345/261/200/347/224/237/346/225/210.md +128 -128
  72. package/skills/microi-solution-quotation/SKILL.md +78 -78
  73. package/skills/microi-solution-quotation/agents/openai.yaml +4 -4
  74. package/skills/microi-solution-quotation/scripts/build_solution_quote.py +296 -296
  75. package/skills/microi-sso/references/acceptance.md +49 -49
  76. package/skills/microi-sso/references/configuration-and-security.md +53 -53
  77. package/skills/microi-sso/references/inbound.md +53 -53
  78. package/skills/microi-sso/references/outbound.md +39 -39
  79. package/skills/microi-system-delivery/SKILL.md +134 -134
  80. package/skills/microi-system-delivery/references/progressive-01-/346/240/207/345/207/206/345/267/245/344/275/234/346/265/201.md +193 -193
  81. 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 +189 -189
  82. package/skills/microi-ui/SKILL.md +174 -174
  83. package/skills/microi-ui/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/234/272/346/231/257/350/223/235/345/233/276.md +183 -183
  84. package/skills/microi-uniapp-frontend/SKILL.md +193 -193
  85. 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 +225 -225
  86. 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 +154 -154
  87. package/skills/microi.v8.js +1921 -1921
  88. package/skills/module-engine/SKILL.md +250 -250
  89. package/skills/module-engine/references/module-config.md +204 -204
  90. package/skills/ocr-engine/SKILL.md +113 -113
  91. package/skills/ocr-engine/agents/openai.yaml +4 -4
  92. package/skills/page-engine/SKILL.md +182 -182
  93. 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 +234 -234
  94. 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 +60 -60
  95. package/skills/performance-testing/SKILL.md +221 -221
  96. package/skills/playwright-e2e/SKILL.md +197 -197
  97. 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 +173 -173
  98. 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 +183 -183
  99. package/skills/playwright-e2e/references/progressive-03-microi-helper-/346/250/241/346/235/277.md +221 -221
  100. package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +115 -115
  101. package/skills/print-engine/SKILL.md +259 -259
  102. package/skills/production-readonly-audit/SKILL.md +41 -41
  103. package/skills/report-engine/SKILL.md +71 -71
  104. package/skills/report-engine/agents/openai.yaml +4 -4
  105. package/skills/scripts/optimize-progressive-disclosure.mjs +204 -204
  106. package/skills/scripts/refresh-progressive-disclosure.mjs +64 -64
  107. package/skills/search-engine/SKILL.md +75 -75
  108. package/skills/search-engine/agents/openai.yaml +4 -4
  109. package/skills/spider-engine/SKILL.md +190 -190
  110. package/skills/system-observability/SKILL.md +238 -238
  111. package/skills/system-observability/references/memory-incident-triage.md +70 -70
  112. package/skills/translate-engine/SKILL.md +140 -140
  113. package/skills/translate-engine/agents/openai.yaml +4 -4
  114. package/skills/ui-design/SKILL.md +191 -191
  115. package/skills/ui-design/assets/templates/MCI-DESIGN.md +198 -198
  116. package/skills/ui-design/references/design-pattern-library.md +184 -184
  117. package/skills/ui-design/references/mci-design-contract.md +163 -163
  118. package/skills/ui-design/references/progressive-01-/351/242/234/350/211/262/344/275/223/347/263/273-css-variables-/346/224/257/346/214/201/344/270/273/351/242/230/345/210/207/346/215/242.md +218 -218
  119. package/skills/ui-design/references/progressive-02-/345/255/227/344/275/223.md +137 -137
  120. package/skills/ui-design/references/progressive-03-/345/212/250/346/225/210/350/247/204/350/214/203-/344/270/260/345/257/214/344/275/206/344/270/215/345/215/241.md +235 -235
  121. package/skills/ui-design/references/progressive-04-/347/273/204/344/273/266/351/243/216/346/240/274/351/200/237/346/237/245.md +152 -152
  122. package/skills/ui-design/references/progressive-05-/347/247/273/345/212/250/347/253/257/344/270/223/347/224/250/350/247/204/350/214/203.md +238 -238
  123. package/skills/ui-design/references/progressive-06-/344/270/273/351/242/230/345/210/207/346/215/242/345/256/236/347/216/260.md +194 -194
  124. package/skills/ui-design/references/progressive-07-/351/200/237/346/237/245-/344/273/216/345/244/264/346/220/255/345/273/272/344/270/200/344/270/252/347/247/273/345/212/250/347/253/257/351/241/265/351/235/242.md +207 -207
  125. package/skills/ui-design/references/progressive-08-/350/241/250/345/215/225/345/210/206/347/273/204/350/247/204/350/214/203-tabs-vs-collapsegroup-/345/274/272/345/210/266.md +117 -117
  126. package/skills/uniapp-mall-assets/SKILL.md +176 -176
  127. package/skills/unity-integration/SKILL.md +155 -155
  128. package/skills/unity-integration/agents/openai.yaml +4 -4
  129. package/skills/unity-integration/references/ai-app-delivery.md +103 -103
  130. package/skills/unity-integration/references/sdk-api.md +82 -82
  131. package/skills/unity-integration/references/toolbox-migration.md +66 -66
  132. package/skills/unity-integration/references/webgl-hosting.md +57 -57
  133. package/skills/v8-cache-pattern/SKILL.md +306 -306
  134. package/skills/v8-crud-api/SKILL.md +175 -175
  135. 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 +226 -226
  136. package/skills/v8-crud-api/references/progressive-02-where-/346/235/241/344/273/266/350/257/255/346/263/225/351/200/237/346/237/245.md +49 -49
  137. package/skills/v8-debugging/SKILL.md +284 -284
  138. package/skills/v8-explorer-tree/SKILL.md +228 -228
  139. package/skills/v8-export-import/SKILL.md +209 -209
  140. 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 +211 -211
  141. package/skills/v8-export-import/references/progressive-02-powerpoint-/345/257/274/345/207/272.md +202 -202
  142. 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 +42 -42
  143. package/skills/v8-file-upload/SKILL.md +263 -263
  144. 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 +101 -101
  145. 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 +150 -150
  146. package/skills/v8-formengine-http/SKILL.md +219 -219
  147. package/skills/v8-frontend-events/SKILL.md +178 -178
  148. package/skills/v8-frontend-events/references/bluetooth-print-api.md +135 -135
  149. package/skills/v8-frontend-events/references/bluetooth-print.md +246 -246
  150. package/skills/v8-frontend-events/references/progressive-01-/345/210/227/350/241/250/344/272/213/344/273/266.md +219 -219
  151. package/skills/v8-http-integration/SKILL.md +182 -182
  152. package/skills/v8-http-integration/references/progressive-01-get-/350/257/267/346/261/202.md +220 -220
  153. 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 +44 -44
  154. package/skills/v8-image-processing/SKILL.md +190 -190
  155. package/skills/v8-image-processing/agents/openai.yaml +4 -4
  156. package/skills/v8-image-processing/references/api-reference.md +623 -623
  157. package/skills/v8-menu-buttons/SKILL.md +180 -180
  158. package/skills/v8-menu-buttons/references/progressive-01-2-/346/214/211/351/222/256/345/257/271/350/261/241-schema.md +222 -222
  159. 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
  160. 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 +104 -104
  161. package/skills/v8-mongodb/SKILL.md +192 -192
  162. package/skills/v8-mq-mqtt/SKILL.md +176 -176
  163. package/skills/v8-mq-mqtt/references/mqtt-production.md +342 -342
  164. package/skills/v8-mq-mqtt/references/progressive-01-v8-mqtt-iot-/347/211/251/350/201/224/347/275/221.md +181 -181
  165. package/skills/v8-mq-mqtt/scripts/check-mqtt-skill-coverage.mjs +203 -203
  166. package/skills/v8-saas-multi-tenant/SKILL.md +219 -219
  167. package/skills/v8-security/SKILL.md +168 -168
  168. package/skills/v8-security/references/progressive-01-2-/346/235/203/351/231/220/346/240/241/351/252/214.md +198 -198
  169. package/skills/v8-security/references/progressive-02-7-/346/227/245/345/277/227/350/256/260/345/275/225.md +158 -158
  170. package/skills/v8-sql-query/SKILL.md +302 -302
  171. package/skills/v8-table-event/SKILL.md +144 -144
  172. 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 +197 -197
  173. 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 +46 -46
  174. package/skills/v8-tcp-integration/SKILL.md +147 -147
  175. package/skills/v8-tcp-integration/agents/openai.yaml +4 -4
  176. package/skills/v8-template-engine/SKILL.md +167 -167
  177. package/skills/v8-utilities/SKILL.md +90 -90
  178. package/skills/v8-utilities/references/client-api-index.md +143 -143
  179. package/skills/v8-utilities/references/platform-http-routes.md +83 -83
  180. package/skills/v8-utilities/references/server-api-index.md +188 -188
  181. package/skills/v8-workflow/SKILL.md +243 -243
  182. package/skills/v8-workflow/references/progressive-01-/350/212/202/347/202/271/345/274/200/345/247/213-v8-/344/272/213/344/273/266.md +180 -180
  183. package/skills/vision-engine/SKILL.md +159 -159
  184. package/skills/vision-engine/agents/openai.yaml +4 -4
  185. package/skills/vision-engine/references/architecture-and-acceptance.md +194 -194
  186. package/skills/workspace-conventions/SKILL.md +261 -261
  187. 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
  188. 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 +216 -216
  189. 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 +27 -27
@@ -1,156 +1,156 @@
1
- ---
2
- name: message-notification
3
- description: 设计、实现、迁移和验收 Microi 多通道消息通知与平台提醒。用于平台提醒、SaaS 系统提醒、试用到期、维护公告、定时弹窗、官方版本提醒、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
- ## 统一配置入口与 MCP
11
-
12
- - 安装同一个 `app.microi.message-notification` 应用后,统一从“系统引擎 → 消息通知”进入系统公告、业务通知与投递记录。禁止再建独立“系统提醒”应用或向 SaaS 表单添加入口。旧 `/xiaoxitongzhisz` 配置并入业务通知,原 `mic_msgset` 和历史数据保留。
13
- - 先用当前用户自己的 MCP 调用 `microi_get_notification_context`,读取 `Capabilities / BusinessRules / BusinessRule / Reminders / Reminder / Recipients / Templates / Adapters / Logs / History`。`Adapters` 按关键词分页发现本租户已启用的接口 Key,不读取源码或密钥。用户和角色只在当前租户读取,跨租户/产品版本仅选择 `AllAccounts / SuperAdmins`,不得读取其它服务器角色。
14
- - `microi_configure_business_notification` 的 `Validate` 不写入、不发送;`Save` 写原通知表,通过固定 `platform-message-notification-config` 接口编排。确认串为 `Save:<id或Key>`;修改必须传 `expectedRevision`,不能把密钥写进 `ChannelApiEngineMap`。
15
- - `microi_manage_system_reminder` 提供 `Validate / Save / Publish / Withdraw`,确认串为 `<action>:<id或requestId>`。保存仅草稿;发布前核对用户已经授权的具体内容、范围与时间。保存/发布使用稳定 `requestId`,编辑/发布/撤回传最新 `expectedRevision`,超时先按原 Id/Key 回读,禁止换请求标识盲目新建。
16
- - `AccountScope` 在本租户 `Users` 默认 `AllAccounts`,在 `Tenants / Editions` 默认 `SuperAdmins`;不要让已指定的普通帐号被默认管理员筛选误排除。用户显式指定的帐号范围优先。
17
- - 配置接口只管理原表、校验引用和读取脱敏投递记录;实际发送继续调用 `msg_event`。`ConfigRevision` 缺省按 0 兼容旧记录,更新使用同事务条件写,失败不能覆盖别人修改。停用旧配置允许保留失效引用,再启用时重新核验。
18
- - MCP 缺少上述工具时优先更新本机插件/CLI;当前宿主未重载可复用已有 `microi_run_engine` 调用同一固定接口,不另建临时维护引擎或绕过授权。明确区分本机工具打包成功与用户渠道已发布。
19
-
20
- ## 目标
21
-
22
- 交付“配置可维护、事件先持久化、实时可降级、多节点不重复、租户不串线”的通知能力。支持微信公众号/服务号模板消息、短信、邮件和平台内部通知;小程序是公众号模板消息的跳转目标,不是独立的公众号发送主体。
23
-
24
- ## 开始前
25
-
26
- 1. 读取工作区 `AGENTS.md`,并按任务同时读取 `microi-db-schema`、`v8-api-config`、`v8-frontend-events`、`microi-client-frontend`;涉及商城时再读 `app-store`,涉及浏览器时再读 `playwright-e2e`。
27
- 2. 用用户点名的 MCP 连接读取实时结构,不以本地字典替代远端事实。至少读取 `wx_tpl_msg`、`mic_msgset`、`mic_msg_event_log`,按需读取 `wx_mp`、`wx_mini_program`、`sys_menu` 和接口引擎。
28
- 3. 多租户比较按字段语义合并:保留双方新增字段、控件、说明和数据源,再把并集同步到双方。每次写入后重新读取字段、物理索引和接口源码。
29
- 4. 只有用户明确要求时才复制渠道配置。复制微信公众号/小程序密钥时不在输出中打印秘密;模板、发送主体和小程序跳转引用必须一起回读验证。
30
-
31
- ## 核心模型
32
-
33
- - `mic_msgset`:通知策略。`Key` 是稳定业务键,`Type` 是多选渠道,`ChannelApiEngineMap` 配置短信、邮件或自定义渠道适配器。
34
- - `wx_tpl_msg`:微信公众号/服务号模板。`WxMpId` 决定发送主体;`MiniProgramId`、`MiniProgramAppId`、`MiniProgramPagePath` 仅表示点击模板消息后跳入的小程序。
35
- - `mic_msg_event_log`:每位接收人、每个渠道的权威事件记录。至少包含稳定 `EventId`、`ChannelType`、`ReceiverUserId`、标题、内容、链接、Payload、已读状态和结果。
36
- - 唯一约束:`EventId + ChannelType + ReceiverUserId`。租户使用独立业务库时表内无需虚构 `OsClient` 字段;共享库模型则必须把租户键加入唯一约束。
37
-
38
- 完整字段、接口和可靠性契约见 [references/contracts.md](references/contracts.md)。
39
-
40
- ## 实现流程
41
-
42
- ### 1. 合并结构
43
-
44
- 对两个租户分别读取字段列表,按 `Name` 生成差异表。新增缺失字段后刷新缓存,并回读:
45
-
46
- - `mic_msgset.Type` 包含 `微信公众号模板消息`、`短信`、`邮件`、`平台内部`;
47
- - `mic_msgset.ChannelApiEngineMap` 为 JSON 对象;
48
- - `wx_tpl_msg` 同时有 `WxMpId/WxMpName` 和小程序跳转字段;
49
- - `mic_msg_event_log` 有完整的事件、接收人、渠道、内容和已读字段;
50
- - 业务唯一索引与常用未读查询索引存在。
51
-
52
- 不要用一次性 SQL 修某个租户而跳过通用表单/资源升级路径。应用包与平台升级资源必须携带同一结构。
53
-
54
- ### 2. 配置发送策略
55
-
56
- `mic_msgset.Key` 对业务长期稳定。接收人可以来自固定用户、角色和调用参数,必须去重并限制扇出。渠道适配器统一接收:
57
-
58
- ```js
59
- {
60
- EventId: '业务稳定幂等键',
61
- ChannelType: '短信',
62
- User: { Id: '...', Phone: '...', Email: '...', WxOpenId: '...' },
63
- Title: '审批提醒',
64
- Content: '您有一条待审批记录',
65
- LinkUrl: '/#/approval/123',
66
- Payload: { BusinessId: '123' }
67
- }
68
- ```
69
-
70
- 适配器必须按 `EventId` 幂等。不要把密钥放进 `ChannelApiEngineMap` 或 Payload;密钥保存在对应渠道配置表或租户安全配置中。
71
-
72
- ### 3. 后端发送
73
-
74
- 业务代码优先调用 `msg_event`,由它读取策略、解析接收人、原子登记日志后分发。调用方在重试时保持同一个 `EventId`:
75
-
76
- ```js
77
- return V8.ApiEngine.Run('msg_event', {
78
- MsgKey: 'order_wait_approve',
79
- EventId: 'order-wait-approve-' + V8.Param.OrderId,
80
- ReceiverUserIds: [V8.Param.ApproverId],
81
- Content: '订单 ' + V8.Param.OrderNo + ' 等待审批',
82
- LinkUrl: '/#/orders/detail?id=' + V8.Param.OrderId,
83
- Payload: { OrderId: V8.Param.OrderId }
84
- }, V8.DbTrans);
85
- ```
86
-
87
- `V8.Notification.Send` 是宿主的“平台内部实时提示”原语。它不替代日志 claim,通常只由 `msg_event` 在日志成功登记后调用。事务存在时,推送在提交后进行有界等待;回滚不得推送。
88
-
89
- ### 4. 前端通知中心
90
-
91
- 前端 V8 使用 `V8.Notification.List` 获取当前登录用户的权威快照,使用 `MarkRead` 标记本人通知。SignalR 固定事件 `ReceivePlatformNotification` 只用于低延迟刷新:客户端按 `Id/EventId` 去重,收到后仍以列表接口回读为准。
92
-
93
- ```js
94
- await V8.Notification.Send('order_wait_approve', {
95
- EventId: 'order-wait-approve-' + V8.Form.Id,
96
- ReceiverUserIds: [V8.Form.ApproverId],
97
- Content: '订单等待审批'
98
- });
99
-
100
- var result = await V8.Notification.List({ PageIndex: 1, PageSize: 20 });
101
- await V8.Notification.MarkRead(result.Data[0].Id);
102
- await V8.Notification.MarkRead({ All: true });
103
- ```
104
-
105
- 列表和已读接口必须以 `V8.CurrentUser.Id` 作为服务端过滤条件,不能信任客户端传入的用户 Id。外链只允许站内路径、锚点或 `http/https`。
106
-
107
- ### 5. 多节点可靠性
108
-
109
- - 数据库日志是事实源,SignalR 是可丢失提示;Redis backplane 使任一节点能通知连接在其它节点的用户。
110
- - “先查询再新增”不能防并发;依赖唯一索引抢占。同一事件重复投递只能产生一份 `EventId + 渠道 + 接收人` 记录。
111
- - 外部供应商在“已发送但响应丢失”时无法凭本地状态保证恰好一次。适配器必须把 `EventId` 传给支持幂等的供应商;不支持时进入可审计的人工确认/重试状态。
112
- - 发布中新旧版本短暂共存,先扩展字段与接口,再发布读写代码,最后才收缩旧字段。
113
-
114
- ## 应用商城交付
115
-
116
- “消息通知”应用包必须包含 `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`,再在全新或缺表目标租户真实安装,回读五张表、应用版本和依赖页面;结构校验不能替代真实安装验收。
117
-
118
- 应用包中的 `sys_apiengine.Id` 是跨应用共享物理表的稳定主键,必须在全部官方应用范围内全局唯一;不能只检查单包内 Key/Id。发布前必须同时扫描全部官方包的 `Id` 与 `ApiEngineKey`,任一跨包重复都应阻断发布和离线包生成。
119
-
120
- 系统聊天门面 `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、伪造租户/发送人必须失败关闭。
121
-
122
- `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`。
123
-
124
- `platform-chat-runtime` 必须保持 `StopHttp=1`、`AllowAnonymous=0`。SignalR Hub 在 DiyToken 与租户核验后,通过宿主一次性可信协议作用域调用,并携带宿主生成的权威当前用户快照;V8 对 `_InvokeType=Client` 的调用必须先执行 `V8.Method.RequireManagedProtocolContext()` 原子消费。不得为修复 Hub 误报“禁止 HTTP 调用”而开放 `StopHttp`,也不得接受 Param 中的信任布尔值、用户或租户覆盖;接口引擎内部 `Server` 嵌套调用保持原有语义。
125
-
126
- 租户个性化仅写入 `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/匿名开关。
127
-
128
- ## 平台提醒的使用与交付
129
-
130
- - 居中可关闭的公告、试用到期与定时提醒统一从“系统引擎 → 消息通知 → 系统公告”配置,使用 `platform-reminder-runtime` 和内置 `microi-platform-service` 的 `/platform-reminders` 页面。在同一页面选择单个、多个或全部租户及用户;不得再向 SaaS 引擎添加提醒按钮、提醒 Tab 或嵌入组件,也不得改为 `TableChild` 或在 V8 中拼接复杂 HTML。
131
- - 四张表分别是 `mci_platform_reminder` 草稿、`mci_platform_reminder_batch` 发布快照、`mci_platform_reminder_target` 接收映射和 `mci_platform_reminder_receipt` 关闭回执。普通客户端不能直接写表。保存草稿不发送;版本条件更新、批次稳定主键、接收映射与状态修改必须共享 `V8.DbTrans`,不要混用独立 `V8.Db.FromSql` 写入。
132
- - `Users` 面向当前租户用户,`Tenants` 仅允许主租户选择当前环境和网络的启用子租户,`Editions` 仅由宿主现有 License 发放判断确定官方身份。官方选项需明确选择 `OpenSource / Personal / Enterprise`,不得默认给全部版本发送。请求中的用户、租户、官方标志和产品版本不构成授权。
133
- - 试用提醒只绑定一个子租户,配置到期时间和提前分钟数,不改 License。所有提醒都必须有有效结束时间,支持 `Once / EveryEntry / AfterServerRestart`;定时支持一次、每日、每周和分钟间隔。每日/每周是固定时间间隔;时间传 UTC,界面显示浏览器时区;恢复上线不补弹所有历史周期。
134
- - 后端三个 Managed Key 为 `platform-reminder-runtime / platform-reminder-official-feed / platform-reminder-tick`。运行时动作包括 `Capabilities / Recipients / List / Get / Validate / Save / Publish / Withdraw / History / Inbox / Presented / Acknowledge`。发布需草稿 Id、`ExpectedRevision` 和稳定 `RequestId`;每次进入模式的收件箱和回执需稳定的本页面 `EntryId`。
135
- - `AccountScope=SuperAdmins` 的提醒接收资格由接收服务的真实 DiyToken 与主库有效用户 Level >= 9999 双重核验,不限 admin 或指定角色;配置写权限继续额外核验有效管理员角色。`AllAccounts` 面向全部帐号。缺省字段保留旧公告的全部帐号语义;新 UI 和 MCP 的跨租户/版本默认范围为超级管理员。普通服务器不能伪造官方 License 发放身份。
136
- - 自动授权提醒通过 `LicensePolicyGet/LicensePolicyValidate/LicensePolicySave` 配置,`ScopeType=Editions` 仅官方,`Tenants` 仅主租户。Policy 为 `{Personal:{AdvanceDays:7,Content:''},Enterprise:{AdvanceDays:7,Content:''}}`,天数 1–3650;空文案回退默认,支持 `{版本}/{到期时间}/{倒计时}`,分钟倒计时总会保留。保存携带 ExpectedRevision(首次 0)并回读,不通过普通公告 Save/Withdraw 修改策略。MCP 复用 get_notification_context(recipientScope)和 manage_system_reminder(scopeType、policy),确认串 `LicensePolicySave:<scopeType>`。
137
- - 接收端先检查固定官方源,再独立检查主租户对子租户的授权提醒。签名期限、子租户期限和超级管理员身份只接受宿主可信上下文;每次真实登录分别去重,未确认刷新继续出现,站内“查看授权”不能写确认回执。右上角版本标签固定在不足 7 天时显示秒级倒计时。验收覆盖两层同时触发、各自确认、30 天配置、空默认与非 admin 管理员。
138
- - 开源版无付费到期日;`DateTime.MinValue`(`0001-01-01`)不是已到期授权,不得生成“系统授权已到期”提醒或按付费版向官方源请求。官方 OpenSource 欢迎公告沿用已发布的 `Editions + OpenSource + SuperAdmins + AfterServerRestart` 规则,不另建硬编码弹窗;每名有效 `Level >= 9999` 帐号分别领取、确认,同批次不重复,下次 API 进程启动批次重新领取。真实已验签且有有效日期的付费合同到期后,仍保留其付费到期提醒。
139
- - `AfterServerRestart` 用可信后端进程启动标识和主租户当前运行分区的共享 Redis 最新批次计算 occurrence,`Presented` 按数据库稳定回执主键抢占领取资格;同帐号多页面只有一个领取,刷新和重新登录不再次弹出。展示成功前回执应已持久化;响应丢失以同一个页面 `EntryId` 恢复,不以 localStorage 作为事实源。`ShownAt` 与 `ClosedAt` 分离,当前已领取弹窗需保留到关闭、撤回或过期。
140
- - 超级管理员范围和重启频率的最低接收协议为 2;官方 feed 必须对协议 1 隐去此类公告,接收端出缓存后再次按当前身份裁剪。未知范围、异常协议或无法核验的启动批次失败关闭。重启频率不能再叠加周期计划;多节点滚动发布采用共享最新启动批次,验证负载切换不回退、不重复。
141
- - 定时任务 `platform-reminder-tick` 每分钟只发送唤醒信号;权威计划与回执保存在数据库。前端监听 `ReceivePlatformReminder` 后回读,SignalR 正常约 60 秒对账、断线约 15 秒轮询并对错误退避;关闭失败重试、撤回和过期收回,禁止使用本机定时器或 localStorage 作为已读事实源。
142
- - 跨服务器官方源由 `Microi.net` 固定请求 `api.itdos.com`,不允许任意 URL/重定向、不发送用户或密钥,按真实本地 License 筛选并缓存;官方源降级不得阻断本地提醒。匿名 feed 只暴露已发布的版本公告,不可读草稿、租户目标或回执。
143
- - 官方“消息通知”包单一拥有配置接口 `platform-message-notification-config`、三个提醒接口、四表六索引、统一菜单、每分钟任务与当前内置微服务产物;SaaS 包同步统一菜单、基础空库结构和旧布局退役声明。先更新支持 `DiyFieldRetirements` 的商城,再安装新版 SaaS 包,清理旧入口且保留业务数据。商城包的内置微服务版本需同步。导出母版可能不带物理索引,按已验证 Manifest 补独立 `CREATE INDEX`,由安装器幂等检查;禁止发布测试提醒、真实接收人或回执数据。
144
- - 共享微服务发布闭包还包含独立“系统日志/监控”包,不能只核对 SaaS、商城和消息通知。先读取相关商城选择清单与实际包,确认 `microi-platform-service` 的所有携带者;按 `platform-service-release.json` 校验同一版本、构建字节与路由。监控包从 `system-observability-package-source.json` 和当前共享运行包经 `configure-system-observability-package.mjs` 再生成,元数据变化要先合并官方母版并升独立包版本。发布前验证各包,安装全部平台应用后再验消息通知页面,避免后安装的旧运行包覆盖新页面;不能通过修改安装器的 Managed 覆盖语义规避。
145
- - MCP 复用 `microi_get_db_schema / microi_generate_system / microi_admin_table_data / microi_save_engine_code / microi_run_engine`,以及在线应用发现、源码同步和流式发布工具;入口调整使用 `microi_update_module / microi_update_table / microi_delete_field`,写后回读确认不存在旧入口。
146
- - 源码升级与应用安装缺一不可。验收覆盖正式 SDK 的 JSON 字符串响应、居中/拖动/关闭、每次刷新、单/多/全租户入口、权限隔离、重复发布、事务失败、到点/过期、断线轮询;多节点与实际其它服务器需要独立集成证据,不能由单机或模型测试替代。
147
-
148
- ## 最低验收
149
-
150
- 1. 两个 MCP 租户的字段、数据源、物理索引和三段接口代码回读一致。
151
- 2. 重复 `EventId`、重复接收人和两个 API 节点并发发送,持久副作用仅一次。
152
- 3. 事务回滚不推送;提交后在线用户即时收到,离线/SignalR/Redis 故障后登录仍能回读。
153
- 4. 用户只能查询和标记自己的通知;危险链接、超长正文、跨租户接收人和匿名调用被拒绝。
154
- 5. 公众号/服务号发送主体与小程序跳转目标分别验证,不把 `MiniProgramAppId` 当作模板发送主体。
155
- 6. 源码定向测试、后端编译、远端 MCP 回读、真实浏览器点击和商城安装/校验分别报告;未执行的生产发布不得写成已上线。
156
- 7. 聊天空 Token/访问密钥/伪造租户失败关闭;相同 `RequestId` 并发只有一份 Mongo 事实,不同载荷冲突拒绝;已持久后 SignalR/After Hook 失败仍返回成功并可回读。
1
+ ---
2
+ name: message-notification
3
+ description: 设计、实现、迁移和验收 Microi 多通道消息通知与平台提醒。用于平台提醒、SaaS 系统提醒、试用到期、维护公告、定时弹窗、官方版本提醒、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
+ ## 统一配置入口与 MCP
11
+
12
+ - 安装同一个 `app.microi.message-notification` 应用后,统一从“系统引擎 → 消息通知”进入系统公告、业务通知与投递记录。禁止再建独立“系统提醒”应用或向 SaaS 表单添加入口。旧 `/xiaoxitongzhisz` 配置并入业务通知,原 `mic_msgset` 和历史数据保留。
13
+ - 先用当前用户自己的 MCP 调用 `microi_get_notification_context`,读取 `Capabilities / BusinessRules / BusinessRule / Reminders / Reminder / Recipients / Templates / Adapters / Logs / History`。`Adapters` 按关键词分页发现本租户已启用的接口 Key,不读取源码或密钥。用户和角色只在当前租户读取,跨租户/产品版本仅选择 `AllAccounts / SuperAdmins`,不得读取其它服务器角色。
14
+ - `microi_configure_business_notification` 的 `Validate` 不写入、不发送;`Save` 写原通知表,通过固定 `platform-message-notification-config` 接口编排。确认串为 `Save:<id或Key>`;修改必须传 `expectedRevision`,不能把密钥写进 `ChannelApiEngineMap`。
15
+ - `microi_manage_system_reminder` 提供 `Validate / Save / Publish / Withdraw`,确认串为 `<action>:<id或requestId>`。保存仅草稿;发布前核对用户已经授权的具体内容、范围与时间。保存/发布使用稳定 `requestId`,编辑/发布/撤回传最新 `expectedRevision`,超时先按原 Id/Key 回读,禁止换请求标识盲目新建。
16
+ - `AccountScope` 在本租户 `Users` 默认 `AllAccounts`,在 `Tenants / Editions` 默认 `SuperAdmins`;不要让已指定的普通帐号被默认管理员筛选误排除。用户显式指定的帐号范围优先。
17
+ - 配置接口只管理原表、校验引用和读取脱敏投递记录;实际发送继续调用 `msg_event`。`ConfigRevision` 缺省按 0 兼容旧记录,更新使用同事务条件写,失败不能覆盖别人修改。停用旧配置允许保留失效引用,再启用时重新核验。
18
+ - MCP 缺少上述工具时优先更新本机插件/CLI;当前宿主未重载可复用已有 `microi_run_engine` 调用同一固定接口,不另建临时维护引擎或绕过授权。明确区分本机工具打包成功与用户渠道已发布。
19
+
20
+ ## 目标
21
+
22
+ 交付“配置可维护、事件先持久化、实时可降级、多节点不重复、租户不串线”的通知能力。支持微信公众号/服务号模板消息、短信、邮件和平台内部通知;小程序是公众号模板消息的跳转目标,不是独立的公众号发送主体。
23
+
24
+ ## 开始前
25
+
26
+ 1. 读取工作区 `AGENTS.md`,并按任务同时读取 `microi-db-schema`、`v8-api-config`、`v8-frontend-events`、`microi-client-frontend`;涉及商城时再读 `app-store`,涉及浏览器时再读 `playwright-e2e`。
27
+ 2. 用用户点名的 MCP 连接读取实时结构,不以本地字典替代远端事实。至少读取 `wx_tpl_msg`、`mic_msgset`、`mic_msg_event_log`,按需读取 `wx_mp`、`wx_mini_program`、`sys_menu` 和接口引擎。
28
+ 3. 多租户比较按字段语义合并:保留双方新增字段、控件、说明和数据源,再把并集同步到双方。每次写入后重新读取字段、物理索引和接口源码。
29
+ 4. 只有用户明确要求时才复制渠道配置。复制微信公众号/小程序密钥时不在输出中打印秘密;模板、发送主体和小程序跳转引用必须一起回读验证。
30
+
31
+ ## 核心模型
32
+
33
+ - `mic_msgset`:通知策略。`Key` 是稳定业务键,`Type` 是多选渠道,`ChannelApiEngineMap` 配置短信、邮件或自定义渠道适配器。
34
+ - `wx_tpl_msg`:微信公众号/服务号模板。`WxMpId` 决定发送主体;`MiniProgramId`、`MiniProgramAppId`、`MiniProgramPagePath` 仅表示点击模板消息后跳入的小程序。
35
+ - `mic_msg_event_log`:每位接收人、每个渠道的权威事件记录。至少包含稳定 `EventId`、`ChannelType`、`ReceiverUserId`、标题、内容、链接、Payload、已读状态和结果。
36
+ - 唯一约束:`EventId + ChannelType + ReceiverUserId`。租户使用独立业务库时表内无需虚构 `OsClient` 字段;共享库模型则必须把租户键加入唯一约束。
37
+
38
+ 完整字段、接口和可靠性契约见 [references/contracts.md](references/contracts.md)。
39
+
40
+ ## 实现流程
41
+
42
+ ### 1. 合并结构
43
+
44
+ 对两个租户分别读取字段列表,按 `Name` 生成差异表。新增缺失字段后刷新缓存,并回读:
45
+
46
+ - `mic_msgset.Type` 包含 `微信公众号模板消息`、`短信`、`邮件`、`平台内部`;
47
+ - `mic_msgset.ChannelApiEngineMap` 为 JSON 对象;
48
+ - `wx_tpl_msg` 同时有 `WxMpId/WxMpName` 和小程序跳转字段;
49
+ - `mic_msg_event_log` 有完整的事件、接收人、渠道、内容和已读字段;
50
+ - 业务唯一索引与常用未读查询索引存在。
51
+
52
+ 不要用一次性 SQL 修某个租户而跳过通用表单/资源升级路径。应用包与平台升级资源必须携带同一结构。
53
+
54
+ ### 2. 配置发送策略
55
+
56
+ `mic_msgset.Key` 对业务长期稳定。接收人可以来自固定用户、角色和调用参数,必须去重并限制扇出。渠道适配器统一接收:
57
+
58
+ ```js
59
+ {
60
+ EventId: '业务稳定幂等键',
61
+ ChannelType: '短信',
62
+ User: { Id: '...', Phone: '...', Email: '...', WxOpenId: '...' },
63
+ Title: '审批提醒',
64
+ Content: '您有一条待审批记录',
65
+ LinkUrl: '/#/approval/123',
66
+ Payload: { BusinessId: '123' }
67
+ }
68
+ ```
69
+
70
+ 适配器必须按 `EventId` 幂等。不要把密钥放进 `ChannelApiEngineMap` 或 Payload;密钥保存在对应渠道配置表或租户安全配置中。
71
+
72
+ ### 3. 后端发送
73
+
74
+ 业务代码优先调用 `msg_event`,由它读取策略、解析接收人、原子登记日志后分发。调用方在重试时保持同一个 `EventId`:
75
+
76
+ ```js
77
+ return V8.ApiEngine.Run('msg_event', {
78
+ MsgKey: 'order_wait_approve',
79
+ EventId: 'order-wait-approve-' + V8.Param.OrderId,
80
+ ReceiverUserIds: [V8.Param.ApproverId],
81
+ Content: '订单 ' + V8.Param.OrderNo + ' 等待审批',
82
+ LinkUrl: '/#/orders/detail?id=' + V8.Param.OrderId,
83
+ Payload: { OrderId: V8.Param.OrderId }
84
+ }, V8.DbTrans);
85
+ ```
86
+
87
+ `V8.Notification.Send` 是宿主的“平台内部实时提示”原语。它不替代日志 claim,通常只由 `msg_event` 在日志成功登记后调用。事务存在时,推送在提交后进行有界等待;回滚不得推送。
88
+
89
+ ### 4. 前端通知中心
90
+
91
+ 前端 V8 使用 `V8.Notification.List` 获取当前登录用户的权威快照,使用 `MarkRead` 标记本人通知。SignalR 固定事件 `ReceivePlatformNotification` 只用于低延迟刷新:客户端按 `Id/EventId` 去重,收到后仍以列表接口回读为准。
92
+
93
+ ```js
94
+ await V8.Notification.Send('order_wait_approve', {
95
+ EventId: 'order-wait-approve-' + V8.Form.Id,
96
+ ReceiverUserIds: [V8.Form.ApproverId],
97
+ Content: '订单等待审批'
98
+ });
99
+
100
+ var result = await V8.Notification.List({ PageIndex: 1, PageSize: 20 });
101
+ await V8.Notification.MarkRead(result.Data[0].Id);
102
+ await V8.Notification.MarkRead({ All: true });
103
+ ```
104
+
105
+ 列表和已读接口必须以 `V8.CurrentUser.Id` 作为服务端过滤条件,不能信任客户端传入的用户 Id。外链只允许站内路径、锚点或 `http/https`。
106
+
107
+ ### 5. 多节点可靠性
108
+
109
+ - 数据库日志是事实源,SignalR 是可丢失提示;Redis backplane 使任一节点能通知连接在其它节点的用户。
110
+ - “先查询再新增”不能防并发;依赖唯一索引抢占。同一事件重复投递只能产生一份 `EventId + 渠道 + 接收人` 记录。
111
+ - 外部供应商在“已发送但响应丢失”时无法凭本地状态保证恰好一次。适配器必须把 `EventId` 传给支持幂等的供应商;不支持时进入可审计的人工确认/重试状态。
112
+ - 发布中新旧版本短暂共存,先扩展字段与接口,再发布读写代码,最后才收缩旧字段。
113
+
114
+ ## 应用商城交付
115
+
116
+ “消息通知”应用包必须包含 `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`,再在全新或缺表目标租户真实安装,回读五张表、应用版本和依赖页面;结构校验不能替代真实安装验收。
117
+
118
+ 应用包中的 `sys_apiengine.Id` 是跨应用共享物理表的稳定主键,必须在全部官方应用范围内全局唯一;不能只检查单包内 Key/Id。发布前必须同时扫描全部官方包的 `Id` 与 `ApiEngineKey`,任一跨包重复都应阻断发布和离线包生成。
119
+
120
+ 系统聊天门面 `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、伪造租户/发送人必须失败关闭。
121
+
122
+ `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`。
123
+
124
+ `platform-chat-runtime` 必须保持 `StopHttp=1`、`AllowAnonymous=0`。SignalR Hub 在 DiyToken 与租户核验后,通过宿主一次性可信协议作用域调用,并携带宿主生成的权威当前用户快照;V8 对 `_InvokeType=Client` 的调用必须先执行 `V8.Method.RequireManagedProtocolContext()` 原子消费。不得为修复 Hub 误报“禁止 HTTP 调用”而开放 `StopHttp`,也不得接受 Param 中的信任布尔值、用户或租户覆盖;接口引擎内部 `Server` 嵌套调用保持原有语义。
125
+
126
+ 租户个性化仅写入 `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/匿名开关。
127
+
128
+ ## 平台提醒的使用与交付
129
+
130
+ - 居中可关闭的公告、试用到期与定时提醒统一从“系统引擎 → 消息通知 → 系统公告”配置,使用 `platform-reminder-runtime` 和内置 `microi-platform-service` 的 `/platform-reminders` 页面。在同一页面选择单个、多个或全部租户及用户;不得再向 SaaS 引擎添加提醒按钮、提醒 Tab 或嵌入组件,也不得改为 `TableChild` 或在 V8 中拼接复杂 HTML。
131
+ - 四张表分别是 `mci_platform_reminder` 草稿、`mci_platform_reminder_batch` 发布快照、`mci_platform_reminder_target` 接收映射和 `mci_platform_reminder_receipt` 关闭回执。普通客户端不能直接写表。保存草稿不发送;版本条件更新、批次稳定主键、接收映射与状态修改必须共享 `V8.DbTrans`,不要混用独立 `V8.Db.FromSql` 写入。
132
+ - `Users` 面向当前租户用户,`Tenants` 仅允许主租户选择当前环境和网络的启用子租户,`Editions` 仅由宿主现有 License 发放判断确定官方身份。官方选项需明确选择 `OpenSource / Personal / Enterprise`,不得默认给全部版本发送。请求中的用户、租户、官方标志和产品版本不构成授权。
133
+ - 试用提醒只绑定一个子租户,配置到期时间和提前分钟数,不改 License。所有提醒都必须有有效结束时间,支持 `Once / EveryEntry / AfterServerRestart`;定时支持一次、每日、每周和分钟间隔。每日/每周是固定时间间隔;时间传 UTC,界面显示浏览器时区;恢复上线不补弹所有历史周期。
134
+ - 后端三个 Managed Key 为 `platform-reminder-runtime / platform-reminder-official-feed / platform-reminder-tick`。运行时动作包括 `Capabilities / Recipients / List / Get / Validate / Save / Publish / Withdraw / History / Inbox / Presented / Acknowledge`。发布需草稿 Id、`ExpectedRevision` 和稳定 `RequestId`;每次进入模式的收件箱和回执需稳定的本页面 `EntryId`。
135
+ - `AccountScope=SuperAdmins` 的提醒接收资格由接收服务的真实 DiyToken 与主库有效用户 Level >= 9999 双重核验,不限 admin 或指定角色;配置写权限继续额外核验有效管理员角色。`AllAccounts` 面向全部帐号。缺省字段保留旧公告的全部帐号语义;新 UI 和 MCP 的跨租户/版本默认范围为超级管理员。普通服务器不能伪造官方 License 发放身份。
136
+ - 自动授权提醒通过 `LicensePolicyGet/LicensePolicyValidate/LicensePolicySave` 配置,`ScopeType=Editions` 仅官方,`Tenants` 仅主租户。Policy 为 `{Personal:{AdvanceDays:7,Content:''},Enterprise:{AdvanceDays:7,Content:''}}`,天数 1–3650;空文案回退默认,支持 `{版本}/{到期时间}/{倒计时}`,分钟倒计时总会保留。保存携带 ExpectedRevision(首次 0)并回读,不通过普通公告 Save/Withdraw 修改策略。MCP 复用 get_notification_context(recipientScope)和 manage_system_reminder(scopeType、policy),确认串 `LicensePolicySave:<scopeType>`。
137
+ - 接收端先检查固定官方源,再独立检查主租户对子租户的授权提醒。签名期限、子租户期限和超级管理员身份只接受宿主可信上下文;每次真实登录分别去重,未确认刷新继续出现,站内“查看授权”不能写确认回执。右上角版本标签固定在不足 7 天时显示秒级倒计时。验收覆盖两层同时触发、各自确认、30 天配置、空默认与非 admin 管理员。
138
+ - 开源版无付费到期日;`DateTime.MinValue`(`0001-01-01`)不是已到期授权,不得生成“系统授权已到期”提醒或按付费版向官方源请求。官方 OpenSource 欢迎公告沿用已发布的 `Editions + OpenSource + SuperAdmins + AfterServerRestart` 规则,不另建硬编码弹窗;每名有效 `Level >= 9999` 帐号分别领取、确认,同批次不重复,下次 API 进程启动批次重新领取。真实已验签且有有效日期的付费合同到期后,仍保留其付费到期提醒。
139
+ - `AfterServerRestart` 用可信后端进程启动标识和主租户当前运行分区的共享 Redis 最新批次计算 occurrence,`Presented` 按数据库稳定回执主键抢占领取资格;同帐号多页面只有一个领取,刷新和重新登录不再次弹出。展示成功前回执应已持久化;响应丢失以同一个页面 `EntryId` 恢复,不以 localStorage 作为事实源。`ShownAt` 与 `ClosedAt` 分离,当前已领取弹窗需保留到关闭、撤回或过期。
140
+ - 超级管理员范围和重启频率的最低接收协议为 2;官方 feed 必须对协议 1 隐去此类公告,接收端出缓存后再次按当前身份裁剪。未知范围、异常协议或无法核验的启动批次失败关闭。重启频率不能再叠加周期计划;多节点滚动发布采用共享最新启动批次,验证负载切换不回退、不重复。
141
+ - 定时任务 `platform-reminder-tick` 每分钟只发送唤醒信号;权威计划与回执保存在数据库。前端监听 `ReceivePlatformReminder` 后回读,SignalR 正常约 60 秒对账、断线约 15 秒轮询并对错误退避;关闭失败重试、撤回和过期收回,禁止使用本机定时器或 localStorage 作为已读事实源。
142
+ - 跨服务器官方源由 `Microi.net` 固定请求 `api.itdos.com`,不允许任意 URL/重定向、不发送用户或密钥,按真实本地 License 筛选并缓存;官方源降级不得阻断本地提醒。匿名 feed 只暴露已发布的版本公告,不可读草稿、租户目标或回执。
143
+ - 官方“消息通知”包单一拥有配置接口 `platform-message-notification-config`、三个提醒接口、四表六索引、统一菜单、每分钟任务与当前内置微服务产物;SaaS 包同步统一菜单、基础空库结构和旧布局退役声明。先更新支持 `DiyFieldRetirements` 的商城,再安装新版 SaaS 包,清理旧入口且保留业务数据。商城包的内置微服务版本需同步。导出母版可能不带物理索引,按已验证 Manifest 补独立 `CREATE INDEX`,由安装器幂等检查;禁止发布测试提醒、真实接收人或回执数据。
144
+ - 共享微服务发布闭包还包含独立“系统日志/监控”包,不能只核对 SaaS、商城和消息通知。先读取相关商城选择清单与实际包,确认 `microi-platform-service` 的所有携带者;按 `platform-service-release.json` 校验同一版本、构建字节与路由。监控包从 `system-observability-package-source.json` 和当前共享运行包经 `configure-system-observability-package.mjs` 再生成,元数据变化要先合并官方母版并升独立包版本。发布前验证各包,安装全部平台应用后再验消息通知页面,避免后安装的旧运行包覆盖新页面;不能通过修改安装器的 Managed 覆盖语义规避。
145
+ - MCP 复用 `microi_get_db_schema / microi_generate_system / microi_admin_table_data / microi_save_engine_code / microi_run_engine`,以及在线应用发现、源码同步和流式发布工具;入口调整使用 `microi_update_module / microi_update_table / microi_delete_field`,写后回读确认不存在旧入口。
146
+ - 源码升级与应用安装缺一不可。验收覆盖正式 SDK 的 JSON 字符串响应、居中/拖动/关闭、每次刷新、单/多/全租户入口、权限隔离、重复发布、事务失败、到点/过期、断线轮询;多节点与实际其它服务器需要独立集成证据,不能由单机或模型测试替代。
147
+
148
+ ## 最低验收
149
+
150
+ 1. 两个 MCP 租户的字段、数据源、物理索引和三段接口代码回读一致。
151
+ 2. 重复 `EventId`、重复接收人和两个 API 节点并发发送,持久副作用仅一次。
152
+ 3. 事务回滚不推送;提交后在线用户即时收到,离线/SignalR/Redis 故障后登录仍能回读。
153
+ 4. 用户只能查询和标记自己的通知;危险链接、超长正文、跨租户接收人和匿名调用被拒绝。
154
+ 5. 公众号/服务号发送主体与小程序跳转目标分别验证,不把 `MiniProgramAppId` 当作模板发送主体。
155
+ 6. 源码定向测试、后端编译、远端 MCP 回读、真实浏览器点击和商城安装/校验分别报告;未执行的生产发布不得写成已上线。
156
+ 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、历史日志或固定用户;安装后字段/索引/接口回读一致 |