Launch 套餐产品映射并发修复
已修复授权审查中的 AUTH-03。仅修改 Launch 服务端与对应回归测试,未部署、未发布 SDK;Licentivo 和 SDK 的授权决定边界不变。
修改
- 保存映射时,在事务内先锁定共同的 Launch 产品记录,再锁套餐版本。不同套餐或不同进程的保存请求因此遵守同一产品锁;冲突请求返回 HTTP 409
PRODUCT_MAPPING_CONFLICT。 products.licentivo_product_id保存稳定的公开产品路由。首次成功保存映射后,同一 Launch 产品的其他套餐只能选择这个 Licentivo 产品;允许选择其不同策略。该字段不保存功能权限、设备额度或客户授权状态。- 客户身份读取稳定路由,不再根据所有套餐的最大版本选择产品。发布套餐及生成 SDK 接入配置时也核对同一绑定。
- 旧库自动增加可空字段。尚无稳定字段的数据依次参考已付款等购买历史、历史发布记录和其余映射;同一优先级存在多个产品时明确提示冲突,不猜测。唯一的已购产品优先于无关草稿,之后保存兼容映射可固化绑定。产品内容编辑保留绑定。
已经售往多个 Licentivo 产品的历史错误数据仍需人工核对,本次不会改写购买记录或远端许可证。需要改用另一个 Licentivo 产品时,应建立新的 Launch 产品,不能借新套餐改写原产品路由。
实现见 映射保存、产品路由、身份签发、发布校验、接入检查、数据模型。
本地验证
| 检查 | 结果 |
|---|---|
| 修复前实现对照 | 同一回归测试稳定捕获两个冲突保存同时成功,按预期失败 |
| 修复后的映射专项回归 | 冲突请求一个成功、一个 409;两个兼容保存均成功;付款同步后身份不受错误草稿影响;SDK 接入层接受正确产品上下文 |
| 历史数据保护 | 已购路由优先、歧义报错、错误草稿禁止发布、错误历史发布无法生成 SDK 配置、内容编辑保留绑定,均通过 |
| Go 全部源码包及 MySQL 回归 | 192 条测试通过记录,含子用例;无失败。TestProductUploadRoundTrip 跳过,未计作通过 |
| 旧库结构升级 | 缺少路由列的结构经初始化后补齐可空字段;重复初始化通过 |
| 真实 Launch、Licentivo 与 Go SDK 联调 | 13 个业务阶段通过,涵盖购买、真实签名功能执行、普通关闭恢复、退出、远程解绑、旧代次、续费退款、账号撤销及退款/拒付后的拒绝运行 |
| 最终补测 | 在新的空库通过映射专项回归,补含历史发布的接入配置检查;go vet 通过 |
完整回归及真实服务联调完成后,最后增加了 SDK 接入检查的一致性校验,并单独重新运行包含此场景的专项回归和 go vet。旧实现的预期失败用于证明测试能抓到原竞态,不是未解决的回归失败。
联调使用本机独立 MySQL 8.0.32、当前 Licentivo 服务与实际 Go SDK;支付渠道和 DeepL 使用隔离模拟服务,没有实际扣款或付费翻译。并发与历史错误映射专项测试使用实际 Launch 业务、MySQL 和协议模拟器;不声称九种 SDK 均完成本轮真实服务联调。
本轮未访问 192.168.2.177。本次启动的 MySQL、Licentivo 临时进程已停止,原有服务保留。原始材料留在忽略目录 .local/mapping-fix-20261024/,可分享摘要见 验证证据。