# App Push|每日提醒推送(客户端 + 后端)|Tasks > 阶段:任务清单(tasks) > > 依赖:`spec_kit/App Push/spec.md`、`spec_kit/App Push/plan.md` --- ## 0. 约束与共识(本期已确认) - 每日次数:**0~5 条/天** - 发送窗口:**9:00~24:00(按客户端上报时区)** - 时间点:窗口内 **随机抖动** - 勿扰:**不做** - 文案:使用后端推荐模块的 **Push 场景个性化模板(降风险)** --- ## 1. 客户端(Expo RN) ### 1.1 UUID(client_user_id) - [ ] 在 `client/src/storage/appStorage.ts`(或新模块)实现: - `getOrCreateClientUserId(): Promise` - 首次生成 UUID 并持久化,后续复用 ### 1.2 Push 权限与 token - [ ] 接入获取 Expo Push Token 的封装(例如 `src/features/push/`): - 获取权限状态 - 请求权限 - 获取 Expo Push Token - [ ] 在 Onboarding / push 引导完成后: - granted 时:获取 token + 调 `register` - 未 granted:仅保存本地设置,不阻塞进入主功能 ### 1.3 “每日提醒次数”入口 - [ ] Onboarding:新增/复用一个步骤页面 - 选择 0~5 次(0 表示关闭) - 支持跳过 - 完成后写本地存储,并调用后端 `preferences` - [ ] 个人主页弹窗: - 修复“测试模式强制无权限”的逻辑 - 次数限制 0~5;关闭等价 0 - denied 时提示去系统设置 - 修改后写本地存储,并调用后端 `preferences` ### 1.4 接口封装 - [ ] 新增 `client/src/services/pushApi.ts` - `registerPushToken(...)` - `setPushPreferences(...)` - `getPushPreferences(...)`(可选) - [ ] 统一使用 `client/src/utils/http.ts` 的请求封装 ### 1.5 联调开关与日志 - [ ] 开发环境输出必要日志(不打印敏感信息): - client_user_id 生成结果 - 权限状态与 token 是否获取成功 - register/preferences 的请求是否成功与错误原因 --- ## 2. 后端(FastAPI) ### 2.1 数据模型与迁移 - [ ] 新增表(或等价模型): - `push_tokens` - `push_preferences` - `push_send_log`(幂等防重复) - [ ] 增加迁移脚本(Alembic 或项目现有迁移机制) > 注意:不执行任何破坏性数据库操作;运行迁移前若涉及真实库,需要你明确回复“允许操作数据库”。 ### 2.2 API - [ ] `POST /v1/push/register` - 幂等:`env + app_id + push_token` 唯一 - 更新 `client_user_id` 归属与 `last_seen_at` - [ ] `PUT /v1/push/preferences` - 校验 `times_per_day` ∈ [0,5] - `enabled=false` 或 `times_per_day=0` 时停止后续推送 - [ ] `GET /v1/push/preferences` - 返回当前偏好与更新时间 - [ ] `POST /v1/push/test`(仅 dev) - 立即向该用户发送一条测试推送(用于真机联调) ### 2.3 Expo 推送发送器 - [ ] 实现 `send_expo_push(token, title, body, data?)` - 处理 Expo 返回错误并对不可恢复错误停用 token - 记录发送结果到 `push_send_log` ### 2.4 推送文案(推荐模板) - [ ] 在推送任务中调用后端推荐模块的 Push 场景模板: - 输入:`client_user_id`、语言/时区(可选) - 输出:`title/body` - 默认“降个性化/降风险” --- ## 3. 定时任务(每日计划 + ETA 发送) - [ ] 每日“计划生成任务” - 扫描 `enabled && times_per_day>0` 用户 - 按用户时区在 9:00~24:00 生成 N 个随机抖动时间点 - 写入 `push_send_log`(唯一键保证幂等) - 投递 ETA 发送任务(或按项目现有任务系统实现) - [ ] ETA “发送任务” - 拉取当次发送所需 token/偏好 - 生成文案(推荐模板) - 调用 Expo push 发送 - 更新 `push_send_log` 状态 --- ## 4. 验收与回归 - [ ] iOS 真机:权限申请、token 获取、test 推送可达 - [ ] Android 真机:权限申请、token 获取、test 推送可达 - [ ] 修改次数:后端计划生成正确(一天内不超发) - [ ] 关闭:后端停止后续推送(不再生成计划/不再发送)