Repository navigation
Closed
Description
背景
#3402 暴露:上传文件会刷「系统文件 "xxx" 已分配给你」噪音通知。直接原因链:
- 分配通知作为全局行为硬编码在 plugin-audit 的
afterInsert/afterUpdatehook 里(packages/plugins/plugin-audit/src/audit-writers.ts的writeAssignmentNotifications),唯一过滤是SKIP_OBJECTS; - 「谁是负责人」靠字段名启发式(
OWNER_FIELDS含owner_id)猜测,把sys_file.owner_id(存储层 ACL 归属)误判成业务指派; - 「自我分配静默」守卫
newOwner === actorId因sys_file由存储服务裸引擎写库(service-storage/src/metadata-store.ts的engine.insert('sys_file', …),无用户上下文 →actorId=null)而穿透; sys_file生命周期多次写库(pending → committed),dedupKey 按updated_at变化,同一文件重复刷屏。
经维护者讨论,结论是:问题不在于缺一个跳过名单或开关,而在于这个功能本身放错了层。
决策
移除内核内置分配通知,「分配通知」回归用户态:平台只提供机制(记录变更触发器 + notify 节点 + 消息模板),通知策略由应用/管理员用自动化流程按需配置,文案可自定义。
理由:
- 业务策略不该硬编码在平台内核。 内核版无法自定义文案、条件、渠道;字段名启发式对语义的误判正是 上传文件后收到大量「系统文件 xxx 已分配给你」噪音通知 #3402 这类 bug 的土壤(
owner_id在不同对象上语义不同)。 - 业界同类产品均为「机制内置、策略配置」:Salesforce(Assignment Rules 逐规则勾选通知 / Flow 自建,文件类对象从不触发)、ServiceNow(按表逐条配置 Notification 记录)、Odoo(模型字段显式声明 tracking)。没有平台对文件/附件等系统记录发分配通知。
- 替代能力已经完整存在(见下),showcase 应用已有现成范例流程演示同一场景。
- 否决 per-object 开关方案(
enable.assignmentNotifications):平台替用户做业务决策、再发一个反悔开关,分层仍然是错的,且徒增 metadata-protocol 面积和逐对象配置负担。
替代路径(现已可用,无需新开发)
- 触发:
record-after-update/record-after-create,条件可用previous访问更新前的行(service-automation/src/engine.ts触发上下文注入record/previous); - 动作:
notify节点(service-automation/src/builtin/notify-node.ts):recipients支持记录字段插值,title/message/actionUrl全部模板插值,走 ADR-0030 messaging 单一入口; - 现成范例:
examples/app-showcase/src/automation/flows/index.ts的showcase_task_assigned_notify:
{ id: 'start', type: 'start', config: {
objectName: 'showcase_task',
triggerType: 'record-after-update',
condition: 'assignee != previous.assignee',
} },
{ id: 'notify_assignee', type: 'notify', config: {
topic: 'task.assigned',
recipients: ['{record.assignee}'],
channels: ['inbox'],
title: 'New task assigned: {record.title}',
actionUrl: '/showcase_task/{record.id}',
} },拆除清单
packages/plugins/plugin-audit/src/audit-writers.ts:删除writeAssignmentNotifications、OWNER_FIELDS、pickOwner、writeAudit内的调用点及makeTitle。保留:sys_audit_log/sys_activity写入不受影响;@mention 通知(writeCommentMentions)是独立功能,保留;packages/plugins/plugin-audit/src/translations/messages.ts:删各语言assignedToYoukey(mentionedYou等保留;注意同步 spec 侧TranslationData['messages']类型如有枚举);packages/plugins/plugin-audit/src/audit-writers.test.ts:删两条 assignment 用例(localizes the assignment notification title …、falls back to an English title …),mention 用例保留;packages/services/service-messaging/src/recipient-resolver.ts:owner_of:audience 与DEFAULT_OWNER_FIELDS是独立机制,保留,仅更新"Mirrors the audit writer's OWNER_FIELDS"注释;- 设计文档
docs/design/notification-platform-convergence.md、docs/handoff/adr-0030-notification-convergence.md中 assignment 段落加废弃标注(历史记录不重写); - changeset(breaking):必须携带 FROM→TO 迁移说明——想保留分配通知的用户,按上面 showcase 范例给目标对象配一条流程;
- 可选:
examples/app-crm预置一条 lead 分配通知流程作迁移范例(注意crm_lead.assigned_to目前是自由文本字段,要真正可通知需先改为用户 lookup,实施时一并决定)。
已知差异(实施时确认)
- 收件人 locale 本地化:内核版按收件人语言渲染标题([plugin-audit] 活动 summary 硬编码英文动词 + 用对象 API 名(非 label),无 i18n(zh-CN 显示 Created os_xxx) #3039
makeTitle);流程模板是单语言的。实施时确认消息模板的 i18n 能力,或接受差异; - 自我分配静默:内核版有
newOwner === actorId守卫;流程触发上下文目前未注入操作人变量,自我变更也会通知。可评估为触发上下文注入操作人变量(供条件使用)或在 messaging 层支持自我抑制,或接受差异; - 去重:内核版有
updated_at版本 dedupKey;流程版靠previous条件天然只在真实变更时触发,可接受。
验收
- 上传文件不再产生任何「已分配给你」通知(上传文件后收到大量「系统文件 xxx 已分配给你」噪音通知 #3402 现象消失,
sys_saved_report/sys_report_schedule的同类潜在噪音一并消除); - 业务对象 owner/assignee 变更默认不再自动发铃铛;showcase 范例流程照常可发;
- plugin-audit 测试更新后全绿;changeset 携带迁移说明。
取代并关闭 #3402。
Metadata
Metadata
Assignees
Labels
No labels
Activity
remove(plugin-audit): drop kernel-built-in assignment notifications (#…
docs(qa): reconcile the i18n checklist items with the shipped contract (