8.8 KiB
8.8 KiB
PRD:UR#62 H5 购买与实名顺序配置
Status: ready-for-agent
Problem Statement
卡和设备已经保存 realname_policy,也已有单资产修改接口,但 C 端充值、购买、实名入口分别维护局部判断,接口仍只返回原始策略,无法稳定表达“运营商实名能力优先于资产顺序策略”。后台也缺少卡和设备的批量配置能力。
设备场景还存在两个容易混淆的概念:每张卡是否需要实名由其运营商 realname_link_type 决定;设备的 realname_policy 只决定购买和实名的先后顺序。本期设备数据前提是所有有效绑定卡都需要实名,不提前设计设备内混有无需实名卡的流程。
Solution
建立统一的有效实名策略解析和购买资格规则。独立卡使用卡策略;设备以及从设备入口访问的卡使用设备策略。对每张卡,realname_link_type=none 表示无需实名,template/gateway 表示需要实名。独立卡据此计算有效策略;设备本期仅允许 before_order/after_order,并按全部有效绑定卡的实名结果决定购买资格。
保留现有单资产修改接口,新增卡和设备批量配置接口。C 端初始化直接返回有效策略、是否需要实名和实际实名状态,前端只编排页面,不复制后端判断。
User Stories
- 作为 C 端客户,我希望无需实名的独立卡直接进入购买流程。
- 作为 C 端客户,我希望“先实名后购买”的独立卡在未实名时先完成实名。
- 作为设备客户,我希望设备配置为先实名时,全部有效绑定卡完成实名后才能购买。
- 作为设备客户,我希望设备配置为先购买时,可以完成购买后再逐张处理未实名卡。
- 作为运营人员,我希望在卡或设备列表一次修改最多 500 个资产的实名顺序,并保证全成全败。
- 作为运营人员,我希望设备下卡的页面明确提示 H5 顺序由设备策略控制。
- 作为审计人员,我希望单条和批量变更都留下统一审计记录。
Implementation Decisions
领域语义
- 卡的
realname_link_type始终决定该卡是否需要实名:none为无需实名,template/gateway为需要实名。 realname_policy只描述购买与实名顺序:none、before_order、after_order;默认值继续为after_order。- 独立卡使用卡自身
realname_policy。若realname_link_type=none,有效策略固定为none;若为template/gateway而卡策略为none,这是冲突数据,初始化和购买均明确报错,不得静默放行。 - 设备以及从设备入口解析出的卡使用设备
realname_policy,绑定卡自身策略不参与设备 H5 顺序。 - 本期确认设备的全部有效绑定卡都需要实名,因此设备策略只允许
before_order或after_order;设备配置none属于非法配置。 - 本期仍按每张卡的
realname_link_type生成具体实名入口,但不设计设备内出现realname_link_type=none卡时的资格、展示和批量交互;未来出现该业务后另行扩展。 - 设备
before_order的购买资格是所有有效绑定、未软删除的卡均real_name_status=1;无绑定卡或任一卡未实名都不允许购买。 - 设备
after_order允许先购买;购买完成后返回全部尚未实名的有效绑定卡,前端逐张引导实名。 - UR#53 的设备
real_name_status是列表筛选投影,语义为“任一有效绑定卡已实名”;不得用该快照代替本需求的“全部有效绑定卡已实名”购买资格判断。 - 卡的
realname_link_type、实名状态及有效绑定关系由数据同步公共 DDD 提供;本需求不得在 C 端 Handler 复制第二套状态规则。
API 契约
- 保留
PATCH /api/admin/assets/{identifier}/realname-mode,请求为{ "realname_policy": "none|before_order|after_order" }。 - 新增
POST /api/admin/iot-cards/batch-update-realname-policy。 - 新增
POST /api/admin/devices/batch-update-realname-policy。 - 两个批量接口统一请求:
asset_ids为去重后的正整数数组,1~500 项;realname_policy使用上述枚举。 - 卡批量配置允许三个值,但每张卡都执行运营商能力冲突校验;设备批量配置只允许
before_order/after_order。 - 任一资产不存在、软删除、越权、类型不符或策略冲突时整批失败,不更新任何资产;错误不得泄露越权资源是否存在。
- 单条和批量接口复用同一 Application 校验规则,不能出现单条可写、批量不可写或反向不一致。
- C 端
GET /api/c/v1/asset/info增加effective_realname_policy、realname_required,继续返回实际real_name_status;原realname_policy在兼容期保留为配置原值,不再供新前端决定流程。 - 设备响应还应返回
pending_realname_cards,仅包含当前客户有权操作且尚未实名的有效绑定卡必要信息;不得返回身份证等敏感信息。 realname_required对独立卡按卡运营商能力返回;对设备本期固定为true,但仍必须经过设备绑定完整性校验。- 充值校验、创建充值、创建套餐订单和实名链接入口都调用统一有效策略/资格用例,禁止继续散落比较
RealnamePolicy。 - 参数解析和完整 DTO 校验失败统一返回参数错误;所有枚举 description 从常量原文同步。
事务、权限与审计
- 批量写操作使用 Application 事务脚本:一次批量加载权限范围内资产及必要运营商能力,完成全量校验后批量更新。
- 不逐资产查询运营商、绑定或权限,最多 500 项仍必须批量读取。
- 单条和批量成功后写 Audit Event;批量事件记录目标类型、数量、目标策略和请求 ID,不在日志中写客户实名敏感数据。
- 代理和平台账号继续使用现有资产数据范围;批量更新不得绕过 GORM Callback 和业务权限检查。
- 重复设置相同策略按幂等成功处理,不制造多次业务副作用;审计中可标记实际变更数量。
前端
- 卡、设备列表分别增加批量“修改实名顺序”,显示已选择数量,最多 500 项。
- 卡可选无需实名、先实名后购买、先购买后实名;设备只展示后两项。
- 修改设备下卡策略时提示“实际 H5 流程由设备策略决定”。
- C 端只读取
effective_realname_policy、realname_required和后端返回的待实名卡,不按资产类型或运营商类型自行覆盖。 before_order未满足时引导实名;after_order在购买完成后引导未实名卡;冲突数据展示后端中文错误并停止流程。
发布与依赖
- 本需求依赖数据同步公共 DDD 提供统一卡事实和有效绑定读取边界;公共能力未落地前不得在旧 C 端 Handler 增加临时分支。
- 发布前扫描独立卡
realname_link_type!=none && realname_policy=none以及设备realname_policy=none的冲突数据,形成修复清单;运行时仍保留拒绝保护。 - API 和对应 C 端、后台前端同一维护窗口发布;旧
realname_policy响应字段只做兼容,不长期承载流程语义。
Testing Decisions
- 领域测试覆盖独立卡的
none/template/gateway × none/before_order/after_order × 实名0/1组合。 - 设备测试覆盖无绑定卡、单卡、多卡、全部已实名、部分实名、全部未实名、无效绑定和软删除卡。
- 明确验证设备资格使用“全部有效卡已实名”,而 UR#53 设备列表快照仍是“任一有效卡已实名”。
- 批量接口覆盖 1、500、501 项,重复 ID、零 ID、不存在、越权、软删除、策略冲突和整批回滚。
- HTTP 集成测试使用真实开发 PostgreSQL、Redis、JWT 和进程内 Fiber App;实名 Gateway 使用测试 Adapter,不调用真实上游。
- 回归充值校验、创建充值、套餐购买、实名链接和设备逐卡实名,证明所有入口使用同一策略。
- 验证相同策略重复提交幂等、审计实际变更数量正确,且批量查询无 N+1。
- 前端验收三种独立卡流程、两种设备流程、批量交互、冲突错误和购买后逐卡引导。
Out of Scope
- 不设计设备内混有无需实名卡时的有效策略和 UI。
- 不修改
realname_link_type的配置入口或实名链接生成协议。 - 不改变 UR#53 的设备实名筛选投影语义。
- 不新增全局实名策略默认配置。
- 不实现数据同步公共 DDD、运营商回调或实名轮询本身。
Further Notes
- 当前代码已经具备字段、默认值、单条接口和部分前置校验,但这些属于迁移输入;目标是统一资格用例,而不是继续复制条件。
realname_link_type决定“这张卡是否需要实名”,realname_policy决定“什么时候实名”,两者不得互相替代。