跳到正文
余翰林 · 产品作品集
返回

案例研究

个人工作台:11 周 50 个版本的自我管理产品

给自己做的效率工作台:待办、计时、热点、复盘收进一个首页。11 周发了 50 个版本,每天凌晨自动生成一份 AI 日报。

更新于:
读法
只留每节结论

一、背景与问题

我同时管着课程、竞赛、部门事务和好几个开发项目,市面上的工具要么太重,要么各管一摊、数据分散。我想要一个打开就知道「今天该干什么」的入口。

重的那一类是 Notion 全家桶:学习成本高、打开慢;轻的那一类只解决单点——番茄钟、待办、笔记各自为政,数据分散在五个 App 里,复盘时凑不齐。

我要的是一个打开就能看到“今天该干什么”的单一入口:待办、学习目标、专注计时、热点资讯、健康打卡、每日复盘在同一个系统里互相引用(复盘能一键转成明日待办,考试倒计时能触发提醒)。

约束条件:学生预算(服务器成本必须为零)、手机 + 笔记本双端、数据云端同步且可备份导出。

二、我的角色

从需求到上线都是我一个人做;AI 帮我写代码,但架构、验收标准和发版节奏由我定。

独立产品人与开发者,own 全部环节:需求定义与优先级排序、模块规划与信息架构、技术选型、前后端实现、测试与发布流程。AI 深度参与编码与审查,但架构决策、验收标准、发版节奏由我把握——为此建立了版本号制度(SemVer 裁剪 + 发版 checklist)和自动化发版脚本(v1.15 起,一条命令出包)。

10 月的 AI 日报是我第一次把模型放进无人值守的位置:它每天凌晨自己跑完抓取、摘要、聚类和成稿,我只在上班前读结果。这一段经历把我对“AI 功能”的理解从“会写提示词”推到了“会设计失败面”。

三、过程与关键取舍

六次取舍里最值钱的一条,是把「要不要引一个库」从感觉变成数字:Motion 实测涨 123KB、超了预算,当场否掉。

取舍 1:模块注册表,让“加功能”不再是体力活。 多模块 SPA 的侧边栏、底部 Tab、路由、首页卡片最初分散在四处,新增模块要改 4 个文件。改为单一类型化注册表后,导航/路由/首页卡片全部由它生成,新增模块 = 新建文件夹 + 注册表加一行,且每个模块自动独立 chunk 懒加载。代价是注册表引用超前会卡构建,纪律是每个 commit 保持可构建。

取舍 2:双适配器数据层,不被云端阻塞。 Supabase 凭据、建表在开发早期无法就绪。我定义了 33 个方法的 Repository 接口,本地实现(localStorage)与云端实现(Supabase)按环境变量切换——整个开发周期无凭据也能全功能跑通。代价:两个实现必须逐方法对齐语义(任务完成状态机、upsert 必须带 id),这类“本地/云端行为分叉”是项目里最隐蔽的 bug 类。

取舍 3:体积预算门禁,被否掉的 Motion 方案。 v1.13 起引入客户端体积预算门禁 + Playwright E2E。v1.22 我想用 Motion 动画库做启动动画,实测包体 +123KB,破预算——放弃,降级为零依赖 Canvas 氛围层 + 手写 FLIP 动画替代。预算门禁的价值就在这一刻:它让“要不要引一个库”从感觉问题变成数字问题。v1.26 又把这一个数字拆成三个(首屏 JS / JS 总量 / 最大单 chunk)——旧口径量的是“代码总量”,却声称保护“移动端首屏”,判据和它声称保护的东西对不上,门禁就只是个仪式。

取舍 4:AI 代码审查不盲信。 v1.9 对一轮 72 条 AI 代码审查逐条核实:约 1/3 是误报,5 条标 CRITICAL 的全部不成立。AI 提效,但验证权必须留在人手里——这条后来成了我仓库执行规则的固定条款。

取舍 5:让 AI 进产品,但把不确定性关进三样东西。 v1.27 给「今日热点」加了一条 AI 日报链路:每天凌晨抓 25 个热榜源 → 模型逐条摘要 → 把同一件事的多篇报道聚成一个事件 → 编排成一份带来源链接的简报。难点不在提示词,而在让它一次函数执行、一份免费额度内稳定跑完:

  • 状态机 + 幂等:条目在「待处理 / 处理中 / 已完成 / 已跳过 / 已失败」之间流转,领取即置「处理中」。重跑因此是安全的——实测第二次运行只用 2.4 秒、新增 0 条。
  • 时间预算:整条链路切成「抓取 → 摘要(前 60%)→ 聚簇(后 40%)」,且预算按剩余时间切。第一版按总量切,抓取一吃掉 11 秒,摘要只剩 1 秒,一轮只处理得了 5 条、顺延 30 条,得连跑 7 轮才消化得完。
  • 成本:整条链路跑在模型的空闲计费时段(价格是高峰的一半),并关掉默认开启的「思考模式」。这个开关是实测逼出来的:18 条真实长度的标题能让它想掉 1900 个 token,而思考是从输出额度里扣的——2000 的额度只剩一百来个写正文,日报断在半截 JSON 上。更阴险的是它随输入长度漂移:换短标题只要 871 个 token,正好能过,所以本地小样本测试是绿的。

链路一变长,失败面就铺开(抓取、摘要、聚簇、编排四处都可能断),于是配了一个上线自检:一次调用把环境变量、四张表、归属账号、热榜连通、模型连通、通知通道全查一遍,且任何一项失败都不影响其余项继续检查。上线顺序固定为「先自检,再抓取,最后出稿」。

取舍 6:平台不保证准时,产品就不该承诺时刻。 定时任务落到 GitHub Actions(零成本,符合学生预算)。第一次全自动运行就暴露了一件事:计划任务不保证准时——日报排在早上 6 点,实际快 8 点才生成;提醒按每小时排,9 个整点里只有 2 个真的跑了。两条工程补偿:日报提前到凌晨 4 点起跑(早生成没有副作用,晚才有),提醒改成每 20 分钟扫一次(既然单次不可靠,就提高尝试频次)。同时改掉一句善意的谎——应用里原本写着「每天 06:00 自动生成」,既然实际时间会漂,就不该承诺具体时刻,改成「每天凌晨……通常在你起床前就备好了」。把不确定性讲清楚,比维护一个漂亮的承诺更值钱。

四、结果与量化

77 天发了 50 个版本,661 个单元测试全绿;AI 日报每天凌晨自己跑完抓取、摘要、聚簇和成稿。

  • 50 个版本 / 77 天(v1.0.0 → v1.33.0)。节奏分三段:8 月 22 版(前 4 周密集迭代)、9 月 7 版(按需维护)、10 月 21 版(先修 7 个体验缺陷,再走完 AI 日报从上线到定稿,最后是首页 12 列 Bento 改版)。全程每个 commit 可构建。
  • 质量门禁全绿:661 个单元测试(71 个文件)+ 13 条 Playwright 端到端 + 三项体积预算(首屏 JS 790KB / JS 总量 1150KB / 最大单 chunk 340KB)。体积预算拦下过 123KB 的劣化方案。
  • AI 日报进入无人值守:每天凌晨自动抓 25 个热榜源,落库 → 逐条摘要 → 事件聚簇 → 成稿。交付当日完整自动运行产出 14 条事件、5 个来源的简报;日报可一键复制为 Markdown,也能按日期回看历史。
  • 产品在线运行:workbench.yuhailinlxy.com,支持 PWA 安装、三通道提醒(Web Push / Server酱 / Telegram)、备份导出导入、云端多设备同步。源码在公开仓库——本页每个数字都能自己跑一遍。
  • 诚实交代:这是 N=1 的自用产品,没有外部用户数据。它的价值在于完整产品过程的证据——版本制度、发版 checklist、上线自检、体积预算,这套流程可以直接复用到团队场景。

五、复盘与反思

最贵的一课:600 多个测试全绿,上线后却一次都没跑成——测试里那个假数据库比真库宽松,漏掉的一个字段真库当场拒绝。

成立的:注册表 + 双适配器让密集迭代没有烂尾(此前我做项目常死于结构混乱);质量门禁让“快速迭代”没有变成“快速腐化”。这次再添一条:把不确定性关进状态机和时间预算,比事后反复调提示词有效得多——AI 功能的稳定性来自工程约束,不来自写得更好的那句话。

过度设计的:v1.18 我花两天纯 CSS 手绘启动动画,被打回重做——v1.19 换 Meteocons 素材库一天完成,效果更好。教训固化:先找现成方案,自研是最后选项。

代价最贵的一课:AI 日报上线当天,600 多个测试全绿,链路上线后却一次都没成功。建表时把状态机写成四种状态、漏了「处理中」,而领取条目的函数恰恰要写入它,于是每次调用都被数据库当场拒绝。根因不在漏写,而在:测试里的数据库是我自己写的替身,它只认逻辑、不认字段级约束。替身比真库宽松的地方,就是 bug 的藏身处。 现在有一条测试直接读建表 SQL,比对状态机的取值集合。

下次会验证的:三种提醒通道的到达率对比实验(Web Push / Server酱 / Telegram);把更新日志从首屏包体里挪出去改成按需加载——代码总量余量只剩 21KB,而它还在长。


  • 产品设计
  • React
  • 架构
  • AI 落地