128 lines
4.0 KiB
Markdown
128 lines
4.0 KiB
Markdown
# 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<string>`
|
||
- 首次生成 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 推送可达
|
||
- [ ] 修改次数:后端计划生成正确(一天内不超发)
|
||
- [ ] 关闭:后端停止后续推送(不再生成计划/不再发送)
|
||
|