Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8.1 KiB
schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | author | change_type | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 8754 | 通知中心内部接口「按事件码查通知事件配置」出参新增 smsTemplateReady(短信模板是否已配真实号) | internal | jw(GIT) | 修改接口 | deployed | not_required | not_required | GET /internal/notification/event-config/{eventCode} 出参纯新增派生字段 smsTemplateReady(模板号非空且非哨兵 TODO_PLACEHOLDER 为 true),首个调用方为 order-v3 补发成团通知。内部接口不经网关,前端无需对接。已合并 dev-v3(PR #8775,merge aac6a6a13)并部署 TEST,经 order-v3 补发链路验证哨兵 / 假模板号 / 还原三态读数正确。管理后台侧变化见同日 04_8754 修改接口·管理后台那份。 | 2026-10-04 | dev-v3 |
user-service: 内部接口「按事件码查通知事件配置」新增 smsTemplateReady
服务: hl-user-service(内部接口,网关不放行) PR:
#8775(已合入dev-v3,合并提交aac6a6a13) Issue: #8754
⚠️ 关键变化
🟢 GET /internal/notification/event-config/{eventCode} 出参纯新增一个派生字段 smsTemplateReady(Boolean):短信模板号非空且不是哨兵 TODO_PLACEHOLDER 时为 true。入参、其余出参、错误行为不变。
🟢 新增首个调用方:order-v3 补发成团通知(NotificationSendLogFeignClient#getEventConfig)据此判断短信能不能真发,补发回执才能如实计数。
一、背景
「先开发、模板后补」期间,事件配置的 sms_enabled=1 而 sms_template_code='TODO_PLACEHOLDER':通知中心照常进短信通道,但 SmsChannelSender 遇哨兵只记 SKIP_NO_TEMPLATE、不真发。调用方只看 smsEnabled 会把发不出去的短信算成送达。哨兵判定原只写在 SmsChannelSender 里,本单收成 SmsTemplateCodes.isConfigured 一处,发送侧与本接口共用,调用方不必知道哨兵字面量。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 按事件码查通知事件配置 | GET | /internal/notification/event-config/{eventCode} |
修改 | 出参新增派生字段 smsTemplateReady |
三、接口详情
1. 按事件码查通知事件配置 GET /internal/notification/event-config/{eventCode}
VO: Result<NotificationEventConfigRespVO>
使用场景
服务间只读查询某通知事件的通道开关与模板配置。order-v3 补发成团通知时调用,按 inappEnabled、smsEnabled && smsTemplateReady 判断两条客户通道能否真发出。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| eventCode | Path | String | ✅ | 事件编码 | 不变,如 GROUP_BATCH_FORMED |
| X-Internal-Token | Header | String | ✅ | 集群内部令牌 | 不变,与其他 /internal/** 相同 |
出参
| 字段 | 类型 | 说明 |
|---|---|---|
| smsTemplateReady | Boolean | 🆕 短信模板是否已就绪:smsTemplateCode 非空且不是 TODO_PLACEHOLDER 为 true。派生字段,不落库。与 smsEnabled=1 同时成立短信才会进入真实发送 |
| eventCode / eventName / categoryCode | String | 不变 |
| inappEnabled / smsEnabled / miniappEnabled / oaEnabled / weworkEnabled | Integer | 不变,0=关 1=开 |
| smsTemplateCode / smsSignName / smsFieldMapping 等模板字段 | String | 不变 |
请求示例
GET /internal/notification/event-config/GROUP_BATCH_FORMED HTTP/1.1
Host: hl-user-service
X-Internal-Token: <集群内部令牌>
响应示例
{
"code": 200,
"message": "success",
"data": {
"eventCode": "GROUP_BATCH_FORMED",
"eventName": "成团通知",
"categoryCode": "GROUP_BATCH",
"inappEnabled": 1,
"inappTitleTemplate": "您报名的团已成团",
"inappContentTemplate": "您报名的${productName}(出发日期${departDate})已成团,请留意后续出行安排。",
"inappLinkTemplate": "/packages/order/detail/detail?id=${orderId}",
"smsEnabled": 1,
"smsTemplateCode": "TODO_PLACEHOLDER",
"smsSignName": null,
"smsFieldMapping": "{\"productName\":\"${productName}\",\"departureDate\":\"${departDate}\",\"batchNo\":\"${groupBatchNo}\"}",
"miniappEnabled": 0,
"oaEnabled": 0,
"weworkEnabled": 0,
"weworkReceiverType": null,
"smsTemplateReady": false
},
"success": true
}
空数据 / 降级响应
事件不存在时 data=null(不变),调用方应视为所有通道不可达。order-v3 侧降级(调用失败 / 熔断)返回失败结果 100903,补发接口据此返回 589595,不会把失败当成「未配置」。
错误响应
缺少或错误的 X-Internal-Token 被 InternalAuthInterceptor 拦截(不变):HTTP 403,响应体如下(注意字段是 msg 不是 message):
{
"code": 403,
"msg": "内部接口禁止外部访问"
}
业务边界
smsTemplateReady只看模板号,不看smsEnabled;调用方须两者同时判断。- 不判断阿里云凭据是否配置:TEST 未配凭据时短信为模拟成功(只打日志不真发),本字段仍可能为
true。
四、契约约束与正确调用方式
- 判断「短信能否真发」:
smsEnabled == 1 && smsTemplateReady == true。不要在调用方写死TODO_PLACEHOLDER字面量。 - 调用方本地 VO 建议
@JsonIgnoreProperties(ignoreUnknown = true),只取需要的字段。
五、数据库行为
- 本接口只读,零写入;
smsTemplateReady由sms_template_code派生,不落库。 - 同批迁移
V20261003_8754改了notification_event_config中GROUP_BATCH_FORMED一行(开短信、模板号哨兵、变量映射),与本接口契约无关。
六、边界行为
smsTemplateCode为null/ 空串 /TODO_PLACEHOLDER→false;其他任意值 →true(不校验是否为阿里云真实存在的模板号)。
六.6、修改前后对比
| 场景 | 改前 | 改后 |
|---|---|---|
| 模板号为哨兵 | 出参无此字段,调用方只能自己比对字面量 | smsTemplateReady=false |
| 模板号为真实值 | 同上 | smsTemplateReady=true |
六.7、影响评估
- 是否破坏向后兼容:否,纯新增字段;改前全仓零调用方。
- 回滚:revert PR #8775 后重新部署 user-service(order-v3 读不到该字段时按「短信未就绪」保守计数)。
七、不影响范围
- 其他
/internal/notification/**接口、通知分发逻辑、短信发送行为(哨兵判定结果与改前逐字等价)。 - 管理后台通知配置接口。
八、测试环境已验证
环境:TEST 验证时间:2026-10-03 20:43~20:50
构建身份:user-service dev-v3 @ aac6a6a13。
本接口不经网关,经它唯一的调用方 order-v3 补发链路间接验证:
| 配置状态 | order-v3 补发回执 | 说明 |
|---|---|---|
smsEnabled=1,smsTemplateCode=TODO_PLACEHOLDER |
smsReady=false、smsCount=0 |
order-v3 读到 smsTemplateReady=false |
后台把模板号改成假号 SMS_TEST_8754 |
smsReady=true、smsCount=2 |
读到 smsTemplateReady=true;后台改配置时清了缓存,3 秒后即生效 |
还原为 TODO_PLACEHOLDER |
smsReady=false |
读到 smsTemplateReady=false |
本地:InternalNotificationControllerTest 15 例(含哨兵 → false 且序列化进 JSON)、SmsTemplateCodesTest 2 例、SmsChannelSenderTest 37 例;user-service 全量 4211 例 0 失败。
十、相关文档
- Issue
#8754;PR#8775;管理后台侧变化见同日04_8754修改接口·管理后台那份
关联 / 联系人
链接
联系人
- 后端负责人: @jw