做了快十年前端,最近一年在业余时间做了一个宝可梦答题小程序。它是微信原生 + 云开发起步,后来把判题和后端整体迁到了自建的 Fastify + Prisma 服务,现在累计 2700 多个用户。最近产品进入「该往哪使劲」的迷茫期,这一篇记录我是怎么用一次后端查询把方向定下来的,以及随之落地的一次前端改造。
直觉先放一边,去库里跑一遍
产品侧的直觉是「拉新不够,得加投」。这种话我听过太多次了,十年经验告诉我,先别急着加功能,去库里把数跑出来再说。
我对自建后端的 Record 集合跑了三条聚合查询:拉新、留存、首日行为。结果把原假设直接推翻了。
拉新侧其实够用:最近一周新增 846 人,累计 2714,其中公众号来源占 66%。小红书工具向 + 公众号冷知识这条内容流水线已经在稳定供货,根本不需要再加投。
真正的瓶颈在第一日体验。库里有记录的用户 1502 人,只来过 1 天的就有 944 人,占 63%,人均活跃才 2.96 天。
「首日只玩一个」是失血点
再看首日行为这条线,数据非常锋利:当天只玩了 1 个玩法的人,次日回访率只有 7%;玩到 6 个以上的,回访率能到 35%。换句话说,能不能把人从「只玩一个」推到「玩第二个」,基本决定了他留不留得下来。这 388 个「首日只玩 1 个」的人,是留存失血的大头。
那他们卡在哪?我拉了首日交叉分析(1490 个可判 D1 的用户):没猜中的 211 人里,48% 是把 6 次机会全部用完才走的。
这个发现很关键:他们不是「看不懂规则」,是「打到最后一颗子弹被劝退」。问题出在局后,不是局前。那在局前加引导只会更劝退——失败那一刻,得给他一个顺手的「下一把」出口。
结算卡按输赢拆两支
于是我做了一次前端改造。结算卡的按钮区,原来是一条固定顺序(分享 → 下一个玩法),现在按对局结果拆成两支:
<!-- components/reveal-card/reveal-card.wxml -->
<view wx:if="{{!solved}}" class="reveal-actions">
<button class="next-quiz-btn">换个玩法 · 今日还剩 {{left}} 个</button>
<button class="reveal-share is-minor">分享</button>
</view>
<wx:else>
<button class="reveal-share">分享</button>
<button class="next-quiz-btn">下一个玩法</button>
</wx:else>
输了的时候,第一动作变成「换个玩法 · 今日还剩 N 个」(主橙色),把「失败即结束」改成「就地换一题 / 换玩法」;赢了才走原来的分享出口。
这次改动落在 7 个文件上:结算卡组件 reveal-card 的 wxml/wxss 用 wx:if / wx:else 拆两支,通用按钮组件 next-quiz-btn 加了一个 label 属性(默认「下一个玩法」,文案改用 {{label}}),app.wxss 补 .reveal-share.is-minor 白底描边次按钮,6 个玩法页各自接 solved 标志。
几个边界坑
- replay 模式本来就没有「下一个玩法」,
next-quiz-btn内部currentMode()==='replay'直接不渲染,否则分享按钮会被错误降级。 - 9 个玩法全通时的 done 状态,失败分支只剩一句灰字加次按钮分享,极低频,可接受。
- 最阴的是
solved标志:reveal-card 的 6 个页面(move/silhouette/stats/dex/wordle/type)必须都传solved,有一页漏传,成功局也会走失败分支,按钮顺序全反。这种坑本地跑不出来,得 grep 消费点逐一核对。
验收判据前置
我坚持把验收判据写死在发布前:4 周内「首日只玩 1 个」的次日回访从 7% 提到 11%。得老实说,这不是翻盘——上限大约每周多 15 个回访,对 DAU 500 的量级是 +8% 的量级。
但它验证了「数据 → 决策 → 改造」这条链路本身。对求职来说,比起单篇爆款,我更愿意把这种「先用查询推翻假设、再把结论落成可验收的前端改造」的过程写进简历——它同时覆盖了后端数据分析和前端工程落地,是一个完整的全栈闭环。
如果你也在做小程序或前端,想知道你的留存瓶颈到底在拉新还是首日在哪道墙,可以聊聊你怎么查首日行为这条线。