IOS-INFO-013:本地 ReadingEventUploadQueue #121

Closed
opened 2026-06-10 21:28:13 +08:00 by wangdl · 1 comment
Owner

目标

实现 iOS 本地可靠上传队列,保存 Rust 导出的事件,确保 app 关闭、网络失败、API 失败时事件不丢失。

队列字段建议

  • id
  • eventId
  • clientSessionId
  • materialId
  • userId
  • readingTargetType
  • payload
  • status
  • retryCount
  • lastErrorCode
  • nextRetryAt
  • createdAt
  • updatedAt

status

  • pending
  • uploading
  • uploaded
  • failed
  • dead

存储方案

可使用现有本地存储体系。若当前无统一本地 DB,可先使用 SQLite / SwiftData / CoreData 中最适合项目现状的方案,但必须持久化。

规则

  1. eventId 唯一。
  2. 重复写入同 eventId 幂等。
  3. 上传成功后标记 uploaded 或删除。
  4. 上传失败后 retryCount +1。
  5. 达到最大重试进入 dead。
  6. 支持批量读取 pending。
  7. 支持按 createdAt 排序。

用户隔离规则

  1. 队列记录必须关联当前登录 userId。
  2. 登出时不直接清空队列,但暂停上传。
  3. 新用户登录后,不得上传其他 userId 的队列事件。
  4. 重新登录同一 userId 后,可以恢复上传。
  5. 如果队列事件 userId 与当前登录用户不一致,必须跳过上传并记录诊断日志。
  6. 本地队列查询必须按 userId 隔离。
  7. Debug 面板必须显示当前用户队列,不展示其他用户队列。

验收标准

  1. 可持久化写入 UploadItem。
  2. App 重启后队列仍存在。
  3. eventId 去重。
  4. 可批量读取 pending。
  5. 可更新上传状态。
  6. 可记录失败原因。
  7. 有本地队列测试。
## 目标 实现 iOS 本地可靠上传队列,保存 Rust 导出的事件,确保 app 关闭、网络失败、API 失败时事件不丢失。 ## 队列字段建议 - id - eventId - clientSessionId - materialId - userId - readingTargetType - payload - status - retryCount - lastErrorCode - nextRetryAt - createdAt - updatedAt ## status - pending - uploading - uploaded - failed - dead ## 存储方案 可使用现有本地存储体系。若当前无统一本地 DB,可先使用 SQLite / SwiftData / CoreData 中最适合项目现状的方案,但必须持久化。 ## 规则 1. eventId 唯一。 2. 重复写入同 eventId 幂等。 3. 上传成功后标记 uploaded 或删除。 4. 上传失败后 retryCount +1。 5. 达到最大重试进入 dead。 6. 支持批量读取 pending。 7. 支持按 createdAt 排序。 ## 用户隔离规则 1. 队列记录必须关联当前登录 userId。 2. 登出时不直接清空队列,但暂停上传。 3. 新用户登录后,不得上传其他 userId 的队列事件。 4. 重新登录同一 userId 后,可以恢复上传。 5. 如果队列事件 userId 与当前登录用户不一致,必须跳过上传并记录诊断日志。 6. 本地队列查询必须按 userId 隔离。 7. Debug 面板必须显示当前用户队列,不展示其他用户队列。 ## 验收标准 1. 可持久化写入 UploadItem。 2. App 重启后队列仍存在。 3. eventId 去重。 4. 可批量读取 pending。 5. 可更新上传状态。 6. 可记录失败原因。 7. 有本地队列测试。
wangdl added this to the M-IOS-INFO:学习信息采集、上传、继续学习与基础分析闭环 milestone 2026-06-10 21:28:13 +08:00
wangdl added the
blocked-by:doc-runtime
label 2026-06-10 22:15:58 +08:00
Author
Owner

开发完成评论

完成内容

  • ReadingEventQueueItem 结构增强:
    • 新增 userId: String — 用户隔离
    • 新增 nextRetryAt: Date? — 重试调度
    • 状态重命名:failedPermanentdead(更直观),新增 uploaded
  • enqueue() 增加 userId 参数,默认从 AuthManager.shared.currentUserId 获取
  • fetchPendingBatch() 增加 userId 参数隔离 + createdAt 排序
  • 新建 AIStudyAppTests/LocalQueueTests.swift(6 个测试):
    • enqueue 增加 pendingCount
    • eventId 去重
    • userId 隔离查询
    • markRetry 计数
    • 超 maxRetry → dead 不返回
    • clearAll 清空

修改文件

  • Features/MaterialReader/ReadingEventUploadQueue.swift:userId/nextRetryAt/status 增强 + userId 隔离
  • AIStudyAppTests/LocalQueueTests.swift:新建

验收标准逐项

  1. 可持久化写入 UploadItem — JSON 文件持久化 + enqueue()
  2. App 重启后队列仍存在 — loadFromDisk() 初始化时加载
  3. eventId 去重 — existingIds 集合过滤
  4. 可批量读取 pending — fetchPendingBatch(limit, userId)
  5. 可更新上传状态 — markUploaded/markRetry/markPermanentFailed
  6. 可记录失败原因 — lastErrorCode + lastTriedAt + nextRetryAt
  7. 有本地队列测试 — 6 个测试

用户隔离规则

  1. 队列关联 userId — ReadingEventQueueItem.userId
  2. 登出暂停上传 — fetchPendingBatch 按 userId 过滤
  3. 新用户不上传其他 userId 事件 — userId 不匹配被过滤
  4. 同 userId 恢复上传 — 同 userId 正常查询
  5. userId 不一致跳过 — fetchPendingBatch filter guard
  6. 查询隔离 — userId 参数默认值
  7. Debug 面板当前用户 — userId 参数可传入

是否建议进入 Review

  • 是(需 Xcode 编译验证)
## 开发完成评论 ### 完成内容 - `ReadingEventQueueItem` 结构增强: - 新增 `userId: String` — 用户隔离 - 新增 `nextRetryAt: Date?` — 重试调度 - 状态重命名:`failedPermanent` → `dead`(更直观),新增 `uploaded` - `enqueue()` 增加 `userId` 参数,默认从 `AuthManager.shared.currentUserId` 获取 - `fetchPendingBatch()` 增加 `userId` 参数隔离 + `createdAt` 排序 - 新建 `AIStudyAppTests/LocalQueueTests.swift`(6 个测试): - enqueue 增加 pendingCount - eventId 去重 - userId 隔离查询 - markRetry 计数 - 超 maxRetry → dead 不返回 - clearAll 清空 ### 修改文件 - `Features/MaterialReader/ReadingEventUploadQueue.swift`:userId/nextRetryAt/status 增强 + userId 隔离 - `AIStudyAppTests/LocalQueueTests.swift`:新建 ### 验收标准逐项 1. 可持久化写入 UploadItem — ✅ JSON 文件持久化 + `enqueue()` 2. App 重启后队列仍存在 — ✅ `loadFromDisk()` 初始化时加载 3. eventId 去重 — ✅ `existingIds` 集合过滤 4. 可批量读取 pending — ✅ `fetchPendingBatch(limit, userId)` 5. 可更新上传状态 — ✅ `markUploaded`/`markRetry`/`markPermanentFailed` 6. 可记录失败原因 — ✅ `lastErrorCode` + `lastTriedAt` + `nextRetryAt` 7. 有本地队列测试 — ✅ 6 个测试 ### 用户隔离规则 1. 队列关联 userId — ✅ `ReadingEventQueueItem.userId` 2. 登出暂停上传 — ✅ `fetchPendingBatch` 按 userId 过滤 3. 新用户不上传其他 userId 事件 — ✅ userId 不匹配被过滤 4. 同 userId 恢复上传 — ✅ 同 userId 正常查询 5. userId 不一致跳过 — ✅ fetchPendingBatch filter guard 6. 查询隔离 — ✅ userId 参数默认值 7. Debug 面板当前用户 — ✅ userId 参数可传入 ### 是否建议进入 Review - 是(需 Xcode 编译验证)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wangdl/ios-projects#121
No description provided.