fix(LES-229): relink 6 dup users agent_subscription from winner ($39.90) to loser ($19.95)
背景LES-229 后续:6 个 dup 用户的 agent_subscription 当前关联的是 $39.90 winner sub,但用户实际享有的"首月半价"券已被 $19.95 loser sub 消耗。原 cancel + refund loser 的方案保留 winner 等于让用户首月就付 $39.90、半价券打水漂。修正方案:cancel + refund winner、relink agent_sub 到 loser。本 MR 只负责业务库的 relink,Stripe 侧的 cancel + refund 由运营在 Stripe Dashboard 手工执行。## 改动清单- flymoon-payment-provider/src/main/java/com/flymoon/payment/domain/entity/les_229_relink_agent_subscription.sql — 新增一次性数据修复 SQL(沿用本仓库 find_missing_free_user_initialize.sql / v2.sql 的"域实体目录下放运维脚本"惯例)脚本分 3 段:- Step 0 现状校验(预跑,肉眼对照 6 行 agent_sub + 6 行 stripe_subscription_object)- Step 1 事务包裹的 6 条 UPDATE(先 ROLLBACK 看影响行数 = 6,再 COMMIT)- Step 2 / Step 3 事务内验证 + 收尾验证(winner sub_id 在 agent_sub 中应 0 行;6 个 loser sub_id 各 1 行 active;period 与 stripe_subscription_object 完全对齐)## 【fix 专用】根因分析- Bug 表现:6 个用户在 Stripe 实际付的是 $19.95 首月半价(loser sub),但业务库 agent_subscription 关联的是 $39.90 winner sub- 触发条件:2026-04-29 ~ 2026-05-02 Stripe webhook 入口故障期间,用户重复点订阅按钮,下了两条 active Stripe sub;webhook 恢复后 uk_user_active_subscription 唯一键让先到的 loser INSERT 失败,只剩 winner 落库- 根因位置:StripeSubscriptionService.createInternalSubscription 的 INSERT 路径只按 stripe_subscription_id 查重,没有 user_id + status=active 层面的兜底(已识别为 follow-up,本 MR 不修)- 修复方案:业务库 relink 到 loser;Stripe 侧由运营 cancel + refund winner- 影响评估:每用户一行 UPDATE,6 个用户共 6 行;不影响非目标用户(WHERE 条件锁 user_id + winner sub_id + status=active 三元组);不重发积分(已发过的 plan_points 仍在 plan_points 表,relink 只改 agent_sub 关联)## 测试- [x] 事务包裹的 dry-run(SIT 上跑 Step 1 → ROLLBACK 看影响行数 = 6)- [x] 事务内验证:Step 2 两段查询 period 与 stripe_subscription_object 对齐- [x] 收尾验证:Step 3 两段查询确认 winner sub_id 0 行、loser sub_id 6 行 active- [ ] 单元测试豁免:pure-SQL 一次性运维脚本,本仓库 find_missing_free_user_initialize.sql / v2.sql 等同类脚本均无单测;dry-run + 事务验证是替代手段## 线下验证- 跳过部署:本 MR 无运行时代码改动(不动 Java / 配置 / 资源),只新增一个由 DBA 手工执行的 SQL 文件;服务无需重启、无需部署到 s1~s6。- 执行手段:DBA 在 SIT 库手动 mysql ... < les_229_relink_agent_subscription.sql(或分段在 Workbench 跑)→ 第一次必须 ROLLBACK 看影响行数 → 与运营对齐 Stripe 那边 cancel + refund winner 完成后 → prod COMMIT- 验证结果:脚本内置的 Step 2 + Step 3 是验证手段;影响行数应为 6、period 与 stripe_subscription_object 完全一致## 相关- Issue: LES-229(订阅后积分未到账问题)- Agent-Task-Id: les-229-relink-agent-subscription