5.5 KiB
5.5 KiB
Daily Widget Reco(任务清单)
对应计划:
spec_kit/Daily Widget Reco/plan.md标记规则:
- 执行完成后将对应项从
- [ ]改为- [x],并把“状态”改为 已完成- 进行中改为 进行中
- 阻塞写明原因与解除条件
0. 清单状态说明
- 状态:未开始 / 进行中 / 已完成 / 阻塞
- 阻塞:必须写明阻塞点与解除条件
1. 客户端:补齐 Widget 场景 API(RN)
- 新增
fetchRecoWidget(POST /v1/reco/widget)- 状态:未开始
- 文件:
client/src/services/recoApi.ts - 要求:
- Header
Accept-Language逻辑沿用fetchRecoFeed - body 结构沿用
RecoRequest - timeout 建议 12s
- Header
- 验收:在 App 内调用可拿到
items[0].text(允许为空但不报错)
2. iOS 原生能力:App Group 共享读写(suiteName 已确认)
suiteName:
group.com.damer.mindfulness
-
新增 App Group 共享存储原生模块(RN Bridge)
- 状态:未开始
- 目标:RN 可写/读共享
UserDefaults(suiteName:) - 要求:
- 支持
setString(key, value)/getString(key)(最小闭环) - 以 JSON 字符串形式存储(上层 JS 自行
JSON.stringify/parse)
- 支持
- 验收:
- RN 写入后,Widget 侧能读到同一 key
- 解析失败不 crash(返回
null/空字符串均可,按上层回退)
-
新增触发 Widget 刷新的原生方法(可选但建议)
- 状态:未开始
- 目标:App 写入缓存后触发
WidgetCenter.reloadAllTimelines() - 验收:App 调用后,Widget 在合理时间内刷新显示新内容(允许系统延迟)
3. 客户端:写入共享配置/画像/每日缓存(App ↔ Widget 共通)
-
写入共享配置
widget.config.v1(包含apiBaseUrl)- 状态:未开始
- 要求:
- App 启动后(或 baseURL 计算完成后)写入
- JSON 字段最少包含:
schema_version、apiBaseUrl、saved_at
- 验收:Widget 侧可读到正确 baseURL(dev/pro 随 App 切换)
-
写入共享画像
widget.userProfile.v1_2(Onboarding 完成后)- 状态:未开始
- 依赖:客户端已能获取/持久化用户画像(本地存储已有
user.profileScoring) - 要求:
- 结构以现有
UserProfileV1_2输出为准 - JSON 字段建议包含:
schema_version、saved_at、user_profile
- 结构以现有
- 验收:Widget 侧可读到
user_profile,且可用于请求后端
-
实现 App 前台“可选主动拉取”并写入
widget.dailyReco.v1- 状态:未开始
- 要求:
- 判断
day_key(用户时区YYYY-MM-DD)不是今天时才拉取 - 调用
fetchRecoWidget(k=1),成功写入缓存 - 失败不影响 UI,不阻塞主流程
- 判断
- 验收:App 打开后能把今日推荐写入共享缓存,Widget reload 后展示一致
4. iOS Widget:读取共享缓存并展示(先不接网络也能跑通)
- Widget 读取
widget.dailyReco.v1并展示- 状态:未开始
- 要求:
- JSON 解析失败容错:视为无缓存
- 展示优先级:今日缓存 → 最近缓存 → 兜底文案
- 验收:手动写入共享缓存后,Widget 立即能展示对应文案(或在下一次 reload 展示)
5. iOS Widget:网络拉取每日推荐 + Timeline 每日刷新(核心)
-
Widget 在缓存过期时请求
POST /v1/reco/widget并写回缓存- 状态:未开始
- 依赖:可读到
widget.config.v1(apiBaseUrl)与widget.userProfile.v1_2(user_profile) - 要求:
- 无鉴权
- 超时建议 8~12s
Accept-Language与 App 保持一致(en/tc)items=[]视为失败,走回退
- 验收:清空今日缓存后,Widget 能在一次 timeline 请求内拉取并展示今日推荐(允许先兜底再更新)
-
实现每日刷新调度(TimelinePolicy)
- 状态:未开始
- 要求:
nextRefreshDate设置为“下一天本地时间 00:10~01:00 随机”之一- 不追求严格准点,但确保每日范围内能更新
- 验收:通过修改系统日期/模拟 day_key 变化,可观察到会进入“过期→重新拉取”逻辑
6. 联调与验收验证(必须)
-
联调:添加小组件后,未打开 App 也能每日更新(尽力而为)
- 状态:未开始
- 步骤:
- 安装带 Widget 的开发包
- 在桌面添加 Widget
- 清空今日缓存并等待 Widget 刷新(或手动触发 reload)
- 验收:Widget 能从后端拉取并展示;隔天能更新到新内容(允许系统延迟)
-
回退验证:断网/后端不可用/返回异常
- 状态:未开始
- 验收:
- Widget 不崩溃
- 展示最近缓存或兜底文案
-
一致性验证:App 与 Widget 当天展示一致
- 状态:未开始
- 验收:App 主动拉取并写入缓存后,Widget reload 后展示同一条
content_id/text
7. 文档与总览更新
-
补充实现说明(可放入客户端 README 或本需求 overflow)
- 状态:未开始
- 要求:记录 suiteName、共享 key、如何本地验证
-
更新
spec_kit/overview.md- 状态:未开始
- 要求:在“Spec Kit Overview”中新增本需求摘要(目标/产物/已完成编码变更)