Files
junhong_cmp_fiber/openspec/changes/scope-expiry-reminder-to-current-asset/design.md
邹进 713045a657
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 12m9s
fix: 第1批 M9 H5 进入资产的临期个人通知写入即已读
H5 进入资产时已同步弹窗展示临期提醒,通知中心再记未读会重复提醒;
通知按剩余天数每天新增一条,保持未读会持续累积红点。
直发通知载荷新增可选 mark_read,仅临期个人通知设置,其他直发通知与店铺临期通知仍为未读。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 10:45:20 +09:00

3.9 KiB
Raw Blame History

Context

承接《第1批-8-9月迭代缺陷修复技术方案》第 4 节。packageexpiry 的 Publish 在每日扫描中给店铺接收人(appendShopNotification)和所有绑定客户(loadRecipients)批量写通知;个人通知列表(PersonalNotificationListRequest,internal/model/dto/notification_dto.go:94)无资产过滤。H5 令牌带当前资产(middleware.GetCurrentAsset),资产信息接口为 GET /api/c/v1/asset/info。Outbox 写入按 event_id 冲突忽略(internal/infrastructure/messaging/outbox/repository.go:103)。

Goals / Non-Goals

Goals: 临期提醒只在客户进入该资产时出现,每天一次;通知中心只显示当前资产的临期提醒。

Non-Goals: 不改到期推算、提醒窗口与等级、店铺通知;不新增接口入参;无迁移。

Decisions

  1. 进入时判定,复用最终到期推算。 在资产信息接口内按当前资产调用 packageexpiry 的推算,与每日扫描同口径。
  2. 去重顺序:先查键 → 写通知 → SET NX → 抢到才返回字段。 方案原顺序是“先写通知再 SET NX”,当天每次进入都会写一次 Outbox(虽冲突忽略,仍是无效写)。评审确认先用 Redis EXISTS/GET 检查,键存在直接返回,只有未提醒时才写通知。写通知成功后才占键,写失败不占键、不返回字段,避免“当天已去重但通知没发出”。两个并发请求都通过检查时,通知由事件号幂等,只有抢到键的一方返回字段。键定义放 pkg/constants/redis.go,TTL 到当天上海时间结束再加缓冲。
  3. Redis 不可用按未提醒处理。 字段可能当天多次返回,通知由事件号兜底不重复;接受该降级,不因 Redis 故障让资产信息接口失败。
  4. 只用 ref_key 过滤,列表、未读数、全部已读同一口径。 ref_id 不带资产类型,卡 5 与设备 5 冲突。过滤只作用于 type = package.expiring AND ref_type = asset。“全部已读”(PUT /notifications/read-all)也加同样的条件,否则会把客户在其他资产才能看到的临期提醒一并标为已读。
  5. 停用个人客户预发布。 去掉 Publish 里给绑定客户批量写通知的循环,店铺通知不变。
  6. 临期个人通知写入即已读,用载荷可选标记实现。 直发 Outbox 载荷(PersonalCustomerDirectPayload,和 AdminDirectPayload 共用一个结构)新增可选字段 mark_read,默认 false。只有 appendNotification(进入资产的临期提醒)设置为 true。deliverOne 创建通知时,标记为 true 就写 is_read=true、read_at=now;审计 after_data 改为按实际值记录,不再固定写 false。不采用“返回通知 ID,让前端关闭弹窗时调已读接口”(运营弹窗的做法),原因是通知由 Outbox 异步投递,接口响应时通知还不存在,拿不到 ID。改成按事件号标记已读又会带来时序问题,而且前后端都要改。

Risks / Trade-offs

  • [GET 接口产生写副作用] → 只在当天首次命中时写一次通知,其余请求只读 Redis。
  • [设备补虚拟号后历史提醒匹配不上] → 影响可接受,已在 spec 中写明。
  • [资产信息接口延迟增加] → 推算与 Redis 检查各一次;推算结果为非临期时不访问 Redis。
  • [接口已返回 expiry_reminder,但前端没有展示弹窗(页面关闭、网络中断),通知却已经是已读] → 接受这个风险。第二天剩余天数变化后会生成新通知、再次弹窗;通知中心仍能看到这条历史记录。

Migration Plan

无迁移。测试环境部署后,每日扫描不再产生个人客户临期通知;已有个人通知按过滤规则展示。已经存在的未读个人临期通知不处理。

Open Questions

  • 资产信息响应中提醒字段的具体命名在实现时确定,并写入接口文档。