Files
junhong_cmp_fiber/openspec/changes/fix-realname-activation-logic/proposal.md
huang 4aab0bcbf2
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 4m39s
提案以及归档
2026-04-18 09:10:29 +08:00

3.4 KiB
Raw Blame History

Why

当前系统存在两个关联缺陷,且缺陷 A 的影响远不止套餐激活本身:

缺陷 A:代理商先给设备/卡实名,再购买 expiry_base=from_activation 的套餐,系统未检查当前实名状态,无条件将套餐标记为 pending_realname_activation=true待生效status=0。这不仅导致套餐永久无法激活连带阻断了购买后的自动复机链路tryResumeAfterPayment 在检查到 activatedCount=0 时直接跳过,即使卡此前因无套餐而停机,购买成功后也不会自动开机。

缺陷 B卡首次实名0→1实名轮询处理器只触发卡级套餐激活不处理该卡所属设备的设备级套餐导致设备级套餐在"购买后某张卡实名"场景下永不激活,同样无法触发设备下绑定卡的复机。

修复后的规则:from_activation 套餐在购买时检查实名状态,已实名则直接激活(同时保障复机链路正常触发);卡首次实名时同时触发其所属设备的设备级套餐激活与复机

What Changes

  • 购买时实名状态检查:在 activateMainPackage 中,当判断 expiry_base != "from_purchase" 时,额外检查载体当前实名状态:
    • iot_card:查询该卡的 real_name_status
    • device:通过 tb_device_sim_binding 查询是否存在任意已实名的绑定卡
    • 已实名 → 直接激活(status=ActivetryResumeAfterPayment 检查到 activatedCount>0 后正常触发复机链路
    • 未实名 → 保持原有逻辑等待实名触发
  • 实名轮询触发设备级激活与复机:在 PollingRealnameHandler 的卡首次实名0→1路径中额外查询该卡所属设备若设备存在则同时提交 carrier_type=deviceTaskTypePackageFirstActivation 任务;任务执行后 ActivateByRealname 内部会调用 ResumeCardIfStopped("device", deviceID) 触发设备下符合条件卡的复机
  • NewPollingRealnameHandler 构造函数新增 *postgres.DeviceSimBindingStore 参数

复机行为说明:自动复机仅针对由轮询系统引起的停机(stop_reasonno_packagetraffic_exhaustednot_realname),手动停机(manual)不受影响,设备下每张卡独立判断实名状态后再决定是否复机。

Capabilities

New Capabilities

无新能力,均为现有逻辑的修正。

Modified Capabilities

  • package-realname-activation:补充"购买时载体已实名则直接激活"的决策分支,以及"设备下卡实名时触发设备级套餐激活"的联动规则
  • polling-task-handlersPollingRealnameHandler 新增 DeviceSimBindingStore 依赖,新增 triggerDeviceRealnameActivation 函数

Impact

涉及文件

  • internal/service/order/service.goactivateMainPackage 函数,~1782-1807 行)
  • internal/task/polling_realname_handler.go(结构体、构造函数、新增函数)
  • pkg/queue/handler.goregisterPollingHandlers 中的构造调用)

数据库:无 schema 变更,无迁移

API:无接口变更,对外透明

当前问题设备的直接影响:设备 862639076038233 的套餐(tb_package_usage.id=1)需要手动修复(修改 pending_realname_activation=false、激活套餐),代码修复仅防止新订单再次陷入同样问题。手动修复套餐后,还需手动触发设备复机(或等待轮询系统下次评估),因为历史停机事件不会被追溯重放。