前言:一个「生活痛点」催生的 Side Project
带娃之后,家里最高频的三个问题不是「宝宝乖不乖」,而是:
- 上次几点喂的?
- 喝了多少?
- 现在该不该喂?
备忘录、家庭群、小本子都试过------能记,但不好统计、不好协作、换机就丢。
作为开发者,很自然想到:不如自己写一个小程序。
于是有了 喂宝助手(MilkTime):面向 0~3 岁宝宝家庭的喂养记录工具,支持记奶、统计、成长曲线、微信提醒和家人共享。
体验入口:微信搜索小程序「喂宝助手」

下面从工程视角,聊聊这个项目是怎么搭起来的。
一、产品要做什么
| 模块 | 能力 |
|---|---|
| 喂养记录 | 奶粉 / 母乳 / 混合,奶量 + 时间,CRUD |
| 首页倒计时 | 距上次喝奶间隔,实时刷新 |
| 统计 | 日/周趋势、奶量汇总、喂养方式分布 |
| 宝宝档案 | 多宝宝切换、成长曲线 |
| 微信提醒 | 订阅消息 + 间隔提醒 + 夜间免打扰 |
| 家人共享 | 邀请码加入、角色、权限、云端同步 |
| 运营后台 | 家长/家庭/喂养数据、访客埋点、数据看板 |
一句话:C 端记数据,B 端看运营,服务端统一鉴权与同步。
二、技术栈选型
整体架构
bash
MilkTime/
├── WX/ # UniApp 微信小程序(C 端)
├── SERVER/ # Node.js Express API
├── ADMIN/ # Vue3 管理后台
└── docs/ # 设计 & API 文档
bash
┌─────────────┐ POST /v1/h5/* ┌─────────────┐
│ UniApp WX │ ─────────────────────▶ │ Express │
└─────────────┘ │ SERVER │
└──────┬──────┘
┌─────────────┐ POST /v1/admin/* │
│ Vue3 ADMIN │ ────────────────────────────────┤
└─────────────┘ │
┌─────────────────────────┼─────────────────────────┐
▼ ▼ ▼
MongoDB Redis BullMQ
(业务持久化) (缓存/Session/队列) (喂养提醒任务)
各端技术栈
| 端 | 技术 |
|---|---|
| 小程序 | Vue2 + UniApp + uView UI + Options API |
| 后端 | Node.js + Express + Mongoose + express-validator |
| 缓存/队列 | Redis (ioredis) + BullMQ |
| 管理后台 | Vue3 + Vite + Element Plus + Pinia + ECharts |
| 鉴权 | 小程序 JWT / 后台 JWT + RBAC 权限树 |
| 部署 | PM2 + Nginx(API:https://mt.zhouyi.run) |
为什么用 UniApp?
- 一套 Vue 语法写微信小程序,上手快
- uView 组件库加速表单、弹层开发
- 后续若扩展 H5/App,成本相对可控
为什么 MongoDB?
喂养记录是典型的「用户 → 宝宝 → 多条时序记录」文档模型,家庭共享也是嵌套成员结构,MongoDB 比较贴合。
三、后端分层设计
SERVER 采用约定式路由 + 三层结构:
bash
routes/v1/h5/*.js
↓
controllers/v1/h5/*Controller.js # 参数校验 + 鉴权
↓
services/v1/h5/*Service.js # 业务逻辑
↓
models/v1/mapping/*Model.js # Mongoose Schema
C 端接口统一前缀:POST /v1/h5/...
管理端接口:POST /v1/admin/...
示例:喂养记录创建链路
js
// Controller:鉴权 + 校验
exports.create = [
wxTokenAuthentication,
[body('babyId').notEmpty(), body('amountMl').isNumeric()],
async (req, res, next) => {
const data = await FeedingsService.create(req.user.userId, req.body)
return apiResponse.successResponseWithData(res, data, 'Success')
},
]
设计原则:
- Controller 不写复杂业务
- Service 处理权限(如是否可编辑该宝宝)
- Model 一表一文件,
timestamps: true - 重要列表接口走 Redis 缓存(如微信
access_token、订阅模板列表)
四、小程序端几个关键实现
1. 全局页面埋点(未登录也可统计)
在 main.js 用 Vue.mixin 注入 onShow,统一上报访客:
js
Vue.mixin({
onShow() {
trackCurrentPageVisit()
},
})
服务端按 visitorId + visitDate 去重:同一访客同一天只一条记录,visitCount 累加,适合看日活和页面分布,而不必强制登录。
2. 家人共享 Deep Link
分享路径带邀请参数:
/subpackage/my/family?code=XXXXXX&name=家庭名
好友打开后:
- 未登录 → 跳转登录页(带
redirect回跳) - 已登录 → 自动弹窗选角色(妈妈/爸爸/爷爷...)
- 邀请码已填充 → 点确认加入
这里要注意 登录回跳 和 分享参数在 onLoad/onShow 中的解析顺序,否则容易出现「同意了但邀请码丢了」。
3. 微信订阅消息:必须在点击链路里同步调用
wx.requestSubscribeMessage 不能在 await 网络请求之后调用,否则微信会报 TAP gesture 相关错误。
我们的做法是:
App 启动 / 页面 onShow → prefetch 模板 ID(缓存到内存)
用户点击「开启提醒」→ 同步校验缓存 → 直接 requestSubscribeMessage
授权成功 → 再异步 report 到服务端
服务端下发模板 ID 前,会跟微信「我的模板」列表校验,避免把错误 ID 下发给客户端导致 20001(模板与 AppID 不匹配)。
五、微信喂养提醒:队列 + 定时扫描
提醒推送不是简单 cron 就完事,链路是:
用户授权订阅消息 → 写入 wx_subscribes
用户设置提醒间隔 → reminders 表
定时任务扫描到点记录 → BullMQ 入队
Worker 消费 → 调微信 subscribe/send API → 写推送日志
关键文件:
scheduler/task/feedRemindScanTask.js--- 每分钟扫描兜底jobs/workers/feedRemindWorker.js--- 队列消费services/v1/milk/feedRemindPush.js--- 组装模板数据并发送
模板字段要和公众平台「我的模板」关键词一一对应,否则发送阶段也会失败。
六、管理后台:运营视角
ADMIN 除了常规用户/角色/权限,还做了喂宝业务模块:
| 菜单 | 作用 |
|---|---|
| 家长信息 | 小程序用户、喂养次数 |
| 家庭管理 | 家庭成员、邀请码 |
| 宝宝档案 / 喂养记录 | 运营查询 |
| 数据概览 | KPI + ECharts 趋势 |
| 访客记录 | 页面埋点、日访问次数 |
权限用 meta.perms + 后端 checkApiPermission('milk:wxUsers:list') 双重校验,前后端一致。
七、项目现状与后续
已完成
- 喂养记录全流程 + 云端同步
- 家人邀请 / 加入 / 退出 / 权限
- 微信订阅提醒(含模板校验)
- 访客埋点 + 后台查询
- 数据看板
规划中 / 可优化
- 成长曲线标准参考线
- 奶量快捷按钮自定义
- 更细粒度的喂养数据分析
- 单元测试覆盖核心 Service
八、总结
这个项目对我来说,不只是一个「育儿工具」,更是一次 从真实需求出发的全栈实践:
- 产品要窄:只做记奶,不做大而全
- 多人协作要早设计:家庭模型、权限、邀请链路一开始就想清楚
- 运营需要数据:访客埋点、看板、日志,个人项目也值得做
欢迎微信搜索小程序「喂宝助手」体验,也可以在评论区交流。