# ADR-002: 订阅与每日运势推送功能设计 ## 状态 ✅ 已采纳 ## 日期 2026-08-13 ## 背景 用户希望在小程序端获得每日运势推送功能,无需手动打开应用即可在每日固定时间收到个性化运势推送。 ## 需求 1. 用户可订阅每日运势推送服务 2. 每日固定时间(默认 07:00)推送当日运势 3. 推送内容基于用户生辰信息的紫微斗数命盘,由现有算法本地生成 4. 用户可自定义推送时间 5. 仅限微信小程序平台 ## 约束 1. 纯客户端 → 需引入轻量后端用于推送(微信订阅消息要求服务端调用) 2. 微信订阅消息模板需在微信小程序后台申请,使用 `wx.subscribeMessage.send` 接口 3. 云函数运行环境为 Node.js,需兼容现有 TypeScript 算法 ## 数据模型 ### 云数据库:subscriptions 集合 ```typescript interface Subscription { _id: string // 云数据库自动 ID openid: string // 用户微信 openid(唯一索引) templateId: string // 微信订阅消息模板 ID birthInfo: { // 用户生辰信息(用于服务器端生成运势) birthDate: string // 公历出生日期 YYYY-MM-DD birthHour: number // 出生小时 (0-23) birthMinute: number // 出生分钟 (0-59) birthPlace: string // 出生地名称 longitude: number // 出生地经度 latitude: number // 出生地纬度 gender: 'MALE' | 'FEMALE' } pushTime: string // 推送时间,格式 "HH:mm",默认 "07:00" pushEnabled: boolean // 是否开启推送 subscribedAt: Date // 订阅时间 lastPushDate: string // 最后推送日期 YYYY-MM-DD(防重复推送) expireAt: Date // 订阅过期时间(微信订阅消息有效期) } ``` ### 小程序端本地存储(新增) | Key | 类型 | 存储内容 | 生命周期 | |-----|------|---------|---------| | `eis_push_subscription` | `Subscription` | 订阅信息缓存 | 持久化,订阅/取消时更新 | ## 决策 ### 决策1:推送方案 — 微信订阅消息 + 微信云开发 **方案**:微信订阅消息(`wx.subscribeMessage.send`)+ 微信云开发(CloudBase) **选择理由**: - 微信订阅消息是微信小程序原生推送能力,用户可在"服务通知"中收到推送 - 微信云开发提供云函数 + 云数据库 + 定时触发器,与微信生态无缝集成 - 无需额外服务器,按量计费,小规模使用在免费额度内 - 云函数定时触发器(cron)支持每日定时执行 **替代方案排除**: - 自建后端服务器:运维成本高,超出当前项目规模 - 纯本地推送:H5 不支持后台推送,小程序端无法跨平台 - 第三方推送服务:增加外部依赖和费用 ### 决策2:算法复用方案 — 共享算法包 **方案**:将现有运势算法(纯函数层)抽取为独立 npm 包,小程序和云函数共享 **选择理由**: - 现有运势算法(`fortuneStrategy.ts`、`ziweiAlgorithm.ts`、`fortune.ts`)是纯函数,无 UI 依赖 - 输入 `ZiweiChart + Date` 输出 `DailyFortune`,可在 Node.js 环境直接运行 - 结果一致性保障:小程序端和云函数推送使用同一份代码 - 后续算法更新只需维护一份代码 **依赖映射**: ``` 共享算法包 @everything-suitable/algorithm/ ├── fortuneStrategy.ts # 运势生成策略(纯函数) ├── fortune.ts # 综合运势生成(纯函数) ├── ziweiAlgorithm.ts # 紫微算法基础(纯函数,含幸运色/数字/方位) ├── types.ts # 类型定义 ├── enums.ts # 枚举定义 └── index.ts # 导出入口 ``` ### 决策3:数据流设计 **订阅流程**: ``` 小程序端 → 用户订阅 → 收集生辰信息 → 上传至云函数 → 存储至云数据库 ``` **每日推送流程**: ``` 云函数定时触发器 (07:00) → 查询当日所有订阅 → 对每用户调用共享算法生成运势 → 调用 wx.subscribeMessage.send → 用户收到服务通知 ``` ### 决策4:推送模板结构 | 模板字段 | 内容 | 数据来源 | |---------|------|---------| | `date1` | 今日日期 | `new Date().toLocaleDateString('zh-CN')` | | `thing2` | 综合运势评分 + 等级 | `overallScore` + `overallLuck` | | `thing3` | 各维度运势建议 | `careerAdvice` / `wealthAdvice` / `relationshipAdvice` / `healthAdvice` | | `thing4` | 幸运色 + 幸运数字 | `luckyColor` + `luckyNumber` | ## 影响 1. **新增目录**:`everything-is-suitable-uniapp/cloudfunctions/`(云函数目录) 2. **新增目录**:`packages/algorithm/`(共享算法包) 3. **新增依赖**:`@everything-suitable/algorithm`(共享算法包的本地引用) 4. **新增页面**:小程序端订阅管理页面(订阅/取消/配置推送时间) 5. **新增存储**:微信云开发环境配置(云数据库、云函数、定时触发器) 6. **不影响现有功能**:现有运势页面、紫微排盘、黄历查询不受影响 7. **不影响现有测试**:共享算法包抽取后,现有测试仍可正常运行 ## 术语表 | 术语 | 定义 | |------|------| | 微信订阅消息 | 微信小程序提供的消息推送能力,用户订阅后可在"服务通知"中收到消息 | | 微信云开发 | 微信生态内的 Serverless 云服务,提供云函数、云数据库、存储等 | | 云函数 | 运行在微信云端的 Node.js 函数,通过定时触发器或事件触发 | | 定时触发器 | 云函数的 cron 触发机制,支持按指定时间定期执行 | | 共享算法包 | 从应用中抽取的纯算法模块,可在多环境(小程序/云函数)复用 | | 生辰信息 | 用户的出生日期、时间、地点、性别等用于紫微斗数排盘的数据 | | 服务通知 | 微信内用户接收订阅消息的入口,位于微信聊天列表"服务通知" |