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

7.9 KiB
Raw Blame History

Capability: 资产实名策略

ADDED Requirements

Requirement: 资产实名策略字段定义

系统 SHALL 在 IotCardDevice 模型上各新增 realname_policy 字段VARCHAR(20)NOT NULLDEFAULT 'none'),用于控制该资产的实名认证要求。

枚举值

  • none:无需实名,充值/购买/实名链接均不受限
  • before_order:先实名后充值/购买,充值/购买前若未实名则拦截并返回 CodeNeedRealname
  • after_order:先充值/购买后实名,充值/购买放行;实名链接在无有效充值/订单记录前拦截

常量定义pkg/constants/iot.gopkg/constants/realname.go

const (
    RealnmePolicyNone        = "none"         // 无需实名
    RealnmePolicyBeforeOrder = "before_order" // 先实名后充值/购买
    RealnmePolicyAfterOrder  = "after_order"  // 先充值/购买后实名
)

Scenario: 默认值为 none

  • WHEN 新建 IotCard 或 Device 时未传入 realname_policy
  • THEN 系统自动填充 realname_policy = "none"

Scenario: 存量数据迁移后行为不变

  • WHEN 数据库迁移执行后,存量 IotCard 和 Device 的 realname_policy 均为 "none"
  • THEN 充值、购买、实名链接行为与迁移前完全相同(均放行)

Requirement: 生效策略优先级(设备卡 vs 单卡)

系统 SHALL 按以下规则确定一张卡的生效实名策略:

  • 单卡(该卡未绑定任何设备):使用 IotCard.realname_policy
  • 设备卡(该卡已绑定设备):使用 Device.realname_policy,忽略 IotCard.realname_policy

此规则 SHALL 封装为 Service 层公共方法 GetEffectiveRealnamePolicy,所有需要策略判断的场景均调用该方法,不得在多处重复实现。

Scenario: 设备卡使用设备策略

  • WHEN IotCard.realname_policy="none" 且该卡绑定了 Device.realname_policy="before_order"
  • THEN 生效策略为 "before_order"(设备策略覆盖卡策略)

Scenario: 单卡使用卡策略

  • WHEN IotCard.realname_policy="before_order" 且该卡未绑定任何设备
  • THEN 生效策略为 "before_order"

Requirement: C 端充值接口实名策略拦截

系统 SHALL 在 C 端充值预检接口C3 GET /api/c/v1/wallet/recharge-check和充值下单接口C4 POST /api/c/v1/wallet/recharge)中,按生效实名策略执行以下逻辑:

  • before_order + real_name_status=0未实名MUST 拦截,返回 CodeNeedRealname(错误码 1187
  • before_order + real_name_status=1(已实名):放行
  • after_order:放行(不检查实名状态)
  • none:放行

Scenario: before_order 模式未实名时充值被拦截

  • WHEN 资产 realname_policy="before_order" 且 real_name_status=0用户调用充值下单接口
  • THEN 系统返回错误码 1187CodeNeedRealname

Scenario: before_order 模式已实名时充值放行

  • WHEN 资产 realname_policy="before_order" 且 real_name_status=1用户调用充值下单接口
  • THEN 系统正常创建充值订单

Scenario: after_order 模式充值放行

  • WHEN 资产 realname_policy="after_order" 且 real_name_status=0用户调用充值下单接口
  • THEN 系统正常创建充值订单,不检查实名状态

Requirement: C 端购买套餐/订单接口实名策略拦截

系统 SHALL 在 C 端创建订单接口D1 POST /api/c/v1/orders/create和支付接口D4 POST /api/c/v1/orders/:id/pay按生效实名策略执行与充值相同的拦截规则。D1 中原 REALNAME-03 注释代码 SHALL 被删除,由新策略逻辑替代。

Scenario: before_order 模式未实名时购买套餐被拦截

  • WHEN 资产 realname_policy="before_order" 且 real_name_status=0用户调用创建订单接口
  • THEN 系统返回错误码 1187CodeNeedRealname订单不创建

Scenario: none 模式购买套餐放行

  • WHEN 资产 realname_policy="none",用户调用创建订单接口
  • THEN 系统正常创建订单,不检查实名状态

Requirement: C 端实名链接接口策略拦截

系统 SHALL 在 C 端实名链接接口E1 GET /api/c/v1/realname/link)中,按生效实名策略执行以下逻辑:

  • none:放行,正常返回实名链接(用户可自愿实名)
  • before_order:放行,正常返回实名链接(引导用户先实名再充值)
  • after_order:检查该资产当前 generation 内是否存在有效充值(status=2)或已支付订单(payment_status=2
    • 有记录 → 放行
    • 无记录 → 拦截,返回错误码(新错误码 CodeRealnameNotAvailable),消息为"请先完成充值或购买套餐后再进行实名认证"

Scenario: after_order 模式有充值记录时实名链接放行

  • WHEN 资产 realname_policy="after_order" 且当前 generation 内存在 status=2 的充值记录
  • THEN 系统正常返回实名链接

Scenario: after_order 模式无充值/订单记录时实名链接被拦截

  • WHEN 资产 realname_policy="after_order" 且当前 generation 内无任何有效充值或已支付订单
  • THEN 系统返回错误,消息为"请先完成充值或购买套餐后再进行实名认证"

Scenario: before_order 模式正常返回实名链接

  • WHEN 资产 realname_policy="before_order"
  • THEN 系统正常返回实名链接(引导用户完成实名)

Requirement: 后台管理更新资产实名策略接口

系统 SHALL 提供 PATCH /api/admin/assets/:identifier/realname-mode,仅限后台管理端认证用户访问。接口通过 assetService.Resolve() 将标识符ICCID/虚拟号)解析为具体资产,按 asset_type 分别更新 IotCard.realname_policyDevice.realname_policy

请求体

{ "realname_policy": "none | before_order | after_order" }

响应体

{ "asset_type": "card | device", "asset_id": 123, "realname_policy": "before_order" }

Scenario: 通过 ICCID 更新单卡策略

  • WHEN 管理员传入 identifier=ICCIDrealname_policy="before_order"
  • THEN 系统更新对应 IotCard 的 realname_policy 为 "before_order",返回 asset_type="card"

Scenario: 通过设备号更新设备策略

  • WHEN 管理员传入 identifier=设备虚拟号realname_policy="after_order"
  • THEN 系统更新对应 Device 的 realname_policy 为 "after_order",返回 asset_type="device"

Scenario: 传入无效枚举值被拒绝

  • WHEN 管理员传入 realname_policy="invalid_value"
  • THEN 系统返回参数校验错误,提示实名策略值无效

Requirement: 所有查询接口返回 realname_policy 字段

以下所有 DTO SHALL 新增 realname_policy 字段string及对应的 description 标签:

后台管理端 DTO

  • StandaloneIotCardResponseIoT 卡详情/列表)
  • DeviceResponse(设备详情/列表)
  • AssetResolveResponse(统一资产解析)
  • AssetRealtimeStatusResponse(资产实时状态)
  • DeviceCardBindingResponse(设备绑卡记录)
  • BoundCardInfoasset_dto.go 中的通用子结构)
  • ImportTaskResponseiot 卡导入任务)
  • DeviceImportTaskResponse(设备导入任务)

C 端 DTO

  • AssetInfoResponseB1 资产信息)
  • BoundCardInfoclient_asset_dto.go 中的 C 端子结构)
  • DeviceCardItemF1 设备卡列表项)

description 标签统一格式

RealnamePolicy string `json:"realname_policy" description:"实名认证策略 (none:无需实名, before_order:先实名后充值/购买, after_order:先充值/购买后实名)"`

Scenario: 资产详情接口返回 realname_policy

  • WHEN 后台管理员查询 IoT 卡详情或资产解析
  • THEN 响应中包含 realname_policy 字段

Scenario: C 端资产信息接口返回 realname_policy

  • WHEN C 端用户调用 GET /api/c/v1/asset/info
  • THEN 响应中包含 realname_policy 字段(前端可据此展示提示)