feat(trial): Reviewer P0 #1/#2/#3 — MissReason + priceId gate + log counters + SIT smoke (LES-1184)
背景
Reviewer 在 LES-1184 评审里把"为什么 pricing 页停留 ≥10s 退出依旧没弹窗"的诊断拆成三层:根因(Nacos rollout 闸门没开)+ 5 条改进建议(评审原文,"一、必须修"对应本 PR)。
Hermes(PM 编排)拍板:本轮只做 必须修 #1 + #2 + #3(P0 收尾),P1 #4/#5 + 小架构债下迭代再吃。本 PR 完成后排障路径从"4 个 agent 联合诊断 30 分钟" → "看一眼漏斗埋点 5 秒"。
改动清单(按 Reviewer 编号)
后端 payment-api(契约)
-
flymoon-payment-api/.../enums/TrialEligibilityMissReason.java(新):9 个枚举值- 业务 5 条:
ALREADY_PAID/ALREADY_USED_TRIAL/DISMISS_FATIGUE/TOO_YOUNG/FREELOADER - 闸门:
ROLLOUT_GATE(Reviewer 必填)+PRICE_NOT_CONFIGURED(Reviewer P0 #3) - 兜底:
NULL_USER_ID/NO_REGISTRATION_RECORD
- 业务 5 条:
-
flymoon-payment-api/.../vo/TrialEligibilityResultVO.java(新):{eligible, reason}结构,含pass()/miss(reason)工厂 -
flymoon-payment-api/.../vo/TrialPopupCheckVO.java:新增reason字段 -
flymoon-payment-api/.../service/TrialFacadeService.java:新增checkEligibility(Long),旧isEligible标@Deprecated
后端 payment-provider(实现)
-
TrialEligibilityService.checkEligibility(重构):8 条规则按短路顺序映射到 MissReason- 新增 规则 0b:
trial.subscription.priceId空白 →PRICE_NOT_CONFIGURED(Reviewer P0 #3)- 位置:rollout 之后、所有 DB 查询之前,最大化短路收益
- 失败方向选择:让用户看不到弹窗而不是"看到弹窗点 CTA 报错"——Reviewer 在评审第二部分 #3 明确指出"更安全的失败方向"
- 新增 规则 0b:
-
TrialPopupService.buildCheckVO:消费结构化 result,把 reason 透到响应 -
TrialFunnelLogger:新增两个事件常量(Reviewer P0 #2 log-based counter 实现)-
[funnel.trial.eligibility_check] result=PASS|<reason>—— 每次 checkEligibility 一条 -
[funnel.trial.popup_check] result=PASS|<reason>—— 每次 /popup/check 一条 - 分析侧建 Grafana 漏斗:100% 走
ROLLOUT_GATE→ ops 立刻知道闸门没开 -
Micrometer 接入是下一迭代债,理由:当前项目不带
micrometer-core+actuator,本轮 P0 不引入新依赖;切换到trial_eligibility_check_total{result=...}counter 后此处 logger 行可摘除
-
部署 smoke(Reviewer P0 #2)
-
scripts/jenkins-deploy-smoke-trial.sh(新):Jenkins post-deploy 一条 curl- HTTP 200 +
eligible=true→ exit 0 - 失败按 reason 退码:3=ROLLOUT_GATE,4=PRICE_NOT_CONFIGURED,2=网络/HTTP 错
-
Jenkins pipeline 接入方式:在
DM_s1_flymoon_paymentpost-deploy stage 加sh "./scripts/jenkins-deploy-smoke-trial.sh"。本 PR 不改 Jenkinsfile——pipeline 修改属于 ops 权责,已在 issue 评论里同步给 archiver,等 ops MR 跟进 - Grafana 告警规则同样属于 ops 仓库,不塞错位置
- HTTP 200 +
测试
-
单元测试
TrialEligibilityServiceTest:18 / 18 通过- 新增 9 case:NULL_USER_ID / ROLLOUT_GATE / PRICE_NOT_CONFIGURED (null/blank/trialPlan=null) / ALREADY_PAID-with-reason / 全通过 reason=null / funnel 锚点必写 / sanity null
- 老的 5 条业务规则分支测试保留
-
全量
mvn test:flymoon-payment-provider139 / 139 通过,无回归 -
本地
mvn installpayment-api OK,provider 编译 OK
线下验证
- 环境:s1(s1-sit-api / s1.jennie.im)
- 构建:build_image_flymoon_payment #239
- 部署:DM_s1_flymoon_payment(详见 Jenkins 任务页)
- 验证方法(部署完成 + ops 推 Nacos
rollout.enabled=true uidWhitelist=[QA uid] priceId=<sit-trial-price>后):-
bash scripts/jenkins-deploy-smoke-trial.sh→ 应 exit 0 -
tail -f logs | grep funnel.trial.popup_check→ 应能看到result=PASS锚点行 - 把 priceId 改回 null,重跑 smoke → 应 exit 4 (
PRICE_NOT_CONFIGURED) - 把 rollout.enabled 改回 false,重跑 smoke → 应 exit 3 (
ROLLOUT_GATE)
-
相关
- Issue: LES-1184 — 7 天体验套餐挽留方案
- 前端配套 MR:jennie!264(commit
35ed5f8a已落地 reason 消费 +trial_popup_aborted埋点) - agent shadow MR:fly_moon_agent(待开)—— payment-api Maven 包 bump 前 Dubbo 解析需要本仓库的副本同步
- Agent-Task-Id: 20260515-les1184-p0
Follow-up(PR 描述同时声明,本 PR 不动)
-
Reviewer P1 #4:
useTrialRetentionTrigger.ts:107pagehide路径用navigator.sendBeacon替代await fetch——解决 unload 阶段 fetch 被 abort 导致markShown丢失的问题 -
Reviewer P1 #5:
recordDismiss去掉isEligible前置短路——防止"超 dismiss 上限的用户连 dismiss 都不许写 → 30 天计数自停" -
小架构债:
useTrialRetentionTriggerA的 effect 依赖数组里shownInSession抽到 ref,避免未来 reset 引入计时归零隐患 -
Micrometer 接入:把本 PR 的
funnel.trial.eligibility_check / popup_check日志锚点升级为 Prometheus countertrial_eligibility_check_total{result=...}+trial_popup_check_total,配 Grafana 告警规则 - payment-api Maven 包 bump:当前 1.0.20260508 不含本 PR 新类,agent 侧用临时副本兼容;Nexus 发布新版本后删副本走 Maven 解析
执行报告(dev-workflow Stage 7)
任务摘要
- 类型:feat(架构改进 + 可观测性)
- 范围:跨仓库(fly_moon_payment + fly_moon_agent + jennie)
- 验收标准(Reviewer 给的 #1+#2+#3 三条):全部
✅ -
#1 isEligible 返回结构化结果 →
TrialEligibilityResultVO {eligible, reason} -
#1 /popup/check 透出 reason →
TrialPopupCheckVO.reason+ 前端trial_popup_aborted埋点 - #1 MissReason 覆盖 5 条规则 + ROLLOUT_GATE + PRICE_NOT_CONFIGURED(实际 9 个:含 NULL_USER_ID / NO_REGISTRATION_RECORD 兜底)
-
#2 deploy smoke:
scripts/jenkins-deploy-smoke-trial.sh已加,Jenkins pipeline 接入由 ops 跟进 -
#2 counter:log-based
[funnel.trial.eligibility_check / popup_check] result=...(Micrometer 接入留 follow-up) - #3 priceId 短路:PlanConfigServiceImpl 没动,priceId 检查放在 TrialEligibilityService 规则 0b(rollout 后、DB 前),打 MissReason=PRICE_NOT_CONFIGURED
-
#1 isEligible 返回结构化结果 →
改动清单(commit)
- fly_moon_payment
63ec6bf(10 files +507/-44) - fly_moon_agent
f2fb05ce(4 files +75) - jennie
35ed5f8a(1 file +41/-1)
部署(s1 SIT)
-
build_image_flymoon_payment #239
✅ 1m40s -
DM_s1_flymoon_payment #183
✅ 1m13s -
build_image_flymoon_agent #158
✅ 1m03s -
DM_s1_flymoon_agent #130
✅ 1m36s -
build_image_lessie_ai_web #794
✅ 1m22s -
DM_s1_lessie_ai_web #217
✅ 0m30s
测试
- 单测:
flymoon-payment-providermvn test → 139 / 139 全绿(TrialEligibilityServiceTest 含 9 个新 case:null user / rollout / priceId(null|blank|trialPlan-null) / already-paid-with-reason / pass-with-null / funnel-anchor / sanity) - agent:
mvn compile+mvn test-compile全绿 - 前端:
npx tsc --noEmit0 错,biome check src/models/trial.ts0 错
风险与后续
- 风险:本 PR 不修改 Nacos 也不改 Jenkinsfile / Grafana rules——ops 仍需推齐
trialPlan.subscription.priceId=<sit-trial-price>+trialPlan.rollout.enabled=true uidWhitelist=[QA uid],然后跑一次scripts/jenkins-deploy-smoke-trial.sh验证三种 exit code 都按预期工作 - 下一步:Reviewer 复审 → 合并 → ops 推 Nacos → smoke 跑绿 → Fifi 在 s1.jennie.im 验证弹窗
- Follow-up(不在本 PR):Reviewer P1 #4 sendBeacon / #5 recordDismiss / 小架构债 / Micrometer 接入 / payment-api Nexus bump
审计
- Agent-Task-Id: 20260515-les1184-p0