All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 12m9s
H5 进入资产时已同步弹窗展示临期提醒,通知中心再记未读会重复提醒; 通知按剩余天数每天新增一条,保持未读会持续累积红点。 直发通知载荷新增可选 mark_read,仅临期个人通知设置,其他直发通知与店铺临期通知仍为未读。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.9 KiB
3.9 KiB
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
- 进入时判定,复用最终到期推算。 在资产信息接口内按当前资产调用
packageexpiry的推算,与每日扫描同口径。 - 去重顺序:先查键 → 写通知 →
SET NX→ 抢到才返回字段。 方案原顺序是“先写通知再SET NX”,当天每次进入都会写一次 Outbox(虽冲突忽略,仍是无效写)。评审确认先用 RedisEXISTS/GET检查,键存在直接返回,只有未提醒时才写通知。写通知成功后才占键,写失败不占键、不返回字段,避免“当天已去重但通知没发出”。两个并发请求都通过检查时,通知由事件号幂等,只有抢到键的一方返回字段。键定义放pkg/constants/redis.go,TTL 到当天上海时间结束再加缓冲。 - Redis 不可用按未提醒处理。 字段可能当天多次返回,通知由事件号兜底不重复;接受该降级,不因 Redis 故障让资产信息接口失败。
- 只用
ref_key过滤,列表、未读数、全部已读同一口径。ref_id不带资产类型,卡 5 与设备 5 冲突。过滤只作用于type = package.expiring AND ref_type = asset。“全部已读”(PUT /notifications/read-all)也加同样的条件,否则会把客户在其他资产才能看到的临期提醒一并标为已读。 - 停用个人客户预发布。 去掉
Publish里给绑定客户批量写通知的循环,店铺通知不变。 - 临期个人通知写入即已读,用载荷可选标记实现。 直发 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
- 资产信息响应中提醒字段的具体命名在实现时确定,并写入接口文档。