XuqmGroup-Server/xuqm-bugcollect-service/docs/BugCollect-API-v1-Review.md
XuqmGroup dcd429c52d feat(bugcollect): 更新 API 端点并改进数据结构
- 将 Android SDK 的 mapping 上传端点从 /log/v1/sourcemaps/upload 更改为 /bugcollect/v1/sourcemaps/upload
- 将 RN SDK 的 API 端点从 /log/v1/ 统一更改为 /bugcollect/v1/
- 在 LogQueue.ts 的请求体中添加 sentAt 时间戳和 SDK 信息
- 重构 BugCollect.ts 中的事件结构,将 appVersion 重命名为 release,添加 environment 和 sdk 字段
- 将 JS 错误上报的类型从 js_error 改为 issue,并调整错误级别分类
- 为 warn 和 info 方法添加完整的 issue 事件结构
- 在 types.ts 中添加新的数据类型定义,包括 Level、Platform、SdkInfo、ExceptionInfo 等
- 为 IssueEvent 添加详细的异常信息结构,包括类型、值和堆栈跟踪
- 添加完整的错误收集 API v1 规范审阅报告文档
- 在数据库迁移脚本中为日志表添加新字段,包括级别、环境、设备信息、SDK 信息等
2026-06-17 18:02:10 +08:00

14 KiB

BugCollect API v1 规范审阅报告

审阅对象docs/BugCollect-API-v1.md(版本 1.1.0
涉及范围:移动端 SDK、租户平台、服务端
审阅日期2026-06-17
审阅结论接口契约整体已比较完整,但与当前代码实现、SDK 客户端、租户平台存在较多不一致,且有多个端点/能力“文档已定义、服务端未实现”。


一、文档与实现不一致(优先级最高)

这些不匹配会导致 SDK、租户平台、服务端三方联调失败或语义错误。

1. Session 上报端点未实现

  • 文档4.4 定义了 POST /bugcollect/v1/sessions/batch,并声明用于计算 crashFreeSessionRate
  • 实现LogController.java:31-43 只有 /issues/batch/events/batch没有 /sessions/batch
  • 建议
    • 要么服务端补齐 Session 接收、聚合、Crash-Free 计算(推荐);
    • 要么文档中先标注「待定/未实现」,避免 SDK 团队按文档开发。

2. 服务端 Webhook 实现与文档严重不符

  • 事件类型 mismatch
    • 文档 8.2/8.3 定义 events: ["issue.created", "issue.fatal", ...]
    • 实现 WebhookService.java:52issue.getType()(实际是 levelfatal/error)去匹配事件列表,且永远发送 event: "issue.new"WebhookService.java:71)。
  • 签名校验缺失:文档 8 声称回调带 X-BugCollect-Signature: sha256=<hmac>,实现里完全没有签名。
  • 字段 mismatch:文档请求体有 secret,实现 WebhookRequest.java 根本没有 secret 字段,反而多了文档里没提到的 cooldownSec
  • 建议
    • 统一 Webhook 模型:按文档实现 secretevents、签名;
    • 事件触发逻辑改为按业务事件(issue.created/fatal/threshold/regressed/resolved)匹配;
    • 如果 cooldownSec 需要保留,也写进文档。

3. Issue 详情 / IssueEvent 响应字段结构不一致

  • 文档 6.3exception 是对象 {type, value, stacktrace, stackSymbolicated}breadcrumbs/tags/device 是 JSON 对象。
  • 实现 IssueEventResponse.java:字段被拍平为 exceptionTypeexceptionValuemessagestackstackSymbolicated,且 breadcrumbs/tags/deviceString(数据库 JSON 字符串直接返回)。
  • 影响:租户平台若按文档解析会拿到字符串而不是对象。
  • 建议
    • 服务端在 toIssueEventResponse 里把 JSON 字符串反序列化为对象返回;
    • 或者调整文档以匹配实现;但前者更符合 Sentry 对齐原则。

4. IssueResponse 仍返回已删除字段

  • 文档 13 Breaking ChangeisResolved 已移除,改用 status
  • 实现 IssueResponse.java:18 仍然包含 isResolved,且 events 字段虽然总是 null,却还存在。
  • 建议:清理 DTO,移除 isResolvedevents(如需兼容可加 @JsonIgnore 过渡)。

5. 分配责任人端点参数形式不一致

  • 文档 7.3PUT /issues/{id}/assign,请求体 JSON { "assignee": "user@example.com" }
  • 实现 LogController.java:106-110:使用 @RequestParam String assignee,即 ?assignee=xxx
  • 建议:按文档改为 @RequestBody 接收 JSON。

6. 批量操作缺少 appKey 说明

  • 文档 7.4:请求体只有 {ids, action}
  • 实现 LogController.java:114-120:额外要求 @RequestParam String appKey
  • 建议:文档补全 appKey 必填参数,并说明用于权限校验。

7. SourceMap 上传对多平台处理简陋

  • 文档 4.3Android 上传 mapping.txt,iOS 上传 dSYM.zip,RN 上传 .map
  • 实现 SourcemapService.java:43所有平台都保存为 index.map。iOS 的 zip 和 Android 的 txt 会被重命名为 .map,后续符号化无法正确识别。
  • 建议
    • platform 决定文件扩展名和解析方式;
    • Android mapping.txt 保留文本;
    • iOS dSYM.zip 解压后按 UUID/架构索引;
    • RN 按 bundleName + appVersion + 增加 bundleVersion/codePushVersion 维度存储。

8. 错误码表与代码/变更日志不一致

  • 文档 9 没有 40006(缺失 eventId),但 变更日志提到 40006
  • 实现 IssueBatchRequest.java:20eventId 未加 @NotBlank,所以缺失时不会被 40006 拒绝。
  • 建议
    • 文档补齐 40006
    • 如果 eventId 是必填项,给 DTO 加 @NotBlank 或业务校验。

二、服务端实现可升级项

9. affectedUsers 统计逻辑错误

LogService.java:84

if (userId != null) issue.setAffectedUsers(issue.getAffectedUsers() + 1);

这是“有 userId 就 +1”,同一个用户多次触发会重复累加,不是“受影响独立用户数”。

  • 建议:维护 log_issue_users 关联表或 HyperLogLog,按 appKey + fingerprint + userId 去重计算。

10. 符号化只是空壳

LogService.java:139-142triggerSymbolicationAsync 只打印 debug,没有真正的

  • ProGuard/R8 mapping 还原;
  • dSYM 解析;
  • SourceMap 解析。
  • 建议:补充符号化 Worker,或文档中标注该能力尚未可用;对移动 SDK 来说,符号化是核心卖点,不能仅停留在接口层面。

11. 概览统计 crashFreeSessionRate 未实现

OverviewResponse 里没有 crashFreeSessionRateLogService.getOverview 也没有相关计算。

  • 建议:补齐 Session 表和计算逻辑,否则文档 6.6 中的字段是空的。

12. log_sessions 表未创建

变更日志说 v1.1 新增 log_sessions,但 V3__bugcollect_v11_upgrade.sql没有 CREATE TABLE log_sessions

  • 建议:补 Flyway 迁移,并同步更新文档 12 的 Schema 章节。

13. 时间解析容错差

LogService.parseDate 直接把 YYYY-MM-DD 当 UTC/本地起始时间,且 to 默认加一天。对跨时区租户不友好。

  • 建议:明确文档中 from/to 是租户本地时区还是 UTC;服务端统一用 UTC 存储、按租户时区展示。

14. 漏斗分析未处理事件顺序

当前漏斗按 sessionId 集合去重,不检查步骤是否按顺序发生,也不支持时间窗口内必须完成。

  • 建议:文档明确漏斗语义(是否必须有序、是否允许跳步、时间窗口),实现按 sessionId + timestamp 排序校验。

15. 查询端点缺少 environment 筛选

文档 6.1 Issue 列表没有 environment 参数,但 SDK 上报会区分 production/staging/development/integration

  • 建议Issue/Event 列表都增加 environment 筛选,方便隔离开发噪声。

16. Issue 列表缺少 assignee 筛选

管理端常见需求是“我负责的 Issue”。

  • 建议GET /issues 增加 assignee 参数。

三、移动端 SDK 优化

17. React Native SDK 与文档能力不对齐

BugCollect.ts 当前缺失:

  • addBreadcrumb API文档 11.2 示例有);
  • captureCrash / fatal 级别上报;
  • device 详细字段(仅 model/osName/osVersion);
  • breadcrumbs 未附加到 IssueEvent;
  • 平台字段只返回 ios/android,文档还有 harmonyos/web/react-native
  • 建议RN SDK 补齐这些能力,版本号建议与文档/服务端对齐(目前是 0.2.0,文档示例是 1.0.0)。

18. Android SDK buildDeviceInfo 模拟器判断可加强

BugCollect.kt:174-177 只判断了部分模拟器特征,MiUI 云手机、第三方模拟器可能漏判。

  • 建议:增加 Build.HARDWAREBuild.PRODUCT 等特征,或允许租户平台配置过滤模拟器数据。

19. SDK 队列策略文档与实现不一致

  • 文档 11.4fatal/error 持久化补发,warning 及以下仅内存。
  • RN 实现 LogQueue.ts:所有事件都写 AsyncStorage,重试 3 次后丢弃,没有区分级别持久化。
  • 建议:对齐策略,避免低级别事件撑满存储。

20. LogQueue.ts 上报路径缺少面包屑和设备信息

RN SDK 的 IssueEvent 没有 breadcrumbsdevice,也没有 exception 对象里的完整内容。

  • 建议:补齐字段,否则服务端 Issue 详情会缺失上下文。

21. 缺少 iOS / HarmonyOS / Flutter / Web SDK

目前只有 Android 和 RN 有实现,其他平台文档里已列出但无代码。

  • 建议:文档中标注各平台 SDK 实现状态,避免误导集成方。

四、租户平台优化

22. TypeScript 类型与 v1.1 字段不同步

tenant-platform/src/api/bugcollect.ts

  • 仍使用 type(应改为 level);
  • 仍使用 isResolved(应改为 status);
  • 仍使用 appVersion(应改为 release);
  • BugCollectEventItem 仍用 message/stack/metadata(应改为 exception.value/exception.stacktrace/tags)。
  • 建议:按 v1.1 文档统一调整前端类型和字段映射。

23. Webhook 前端模型与服务端不匹配

前端 BugCollectWebhookeventTypescooldownSecondsenabled,但文档和服务端不完全一致。

  • 建议:先确定最终模型,再同步三端。

24. 缺少 Issue 管理操作的前端封装

bugcollect.ts 没有 resolveIssue/ignoreIssue/assignIssue/bulk 的 API 方法。

  • 建议:补齐管理端点调用。

25. 概览页类型缺少字段

BugCollectOverview 缺少 openIssuescrashFreeSessionRate 等文档字段。

  • 建议:与文档/服务端 DTO 对齐。

五、数据模型与 Schema

26. fingerprint 长度校验

文档说 fingerprint 是 64 字符 SHA-256 十六进制,但实现没有校验格式。

  • 建议DTO 加正则校验,或放宽文档描述(如果允许自定义 fingerprint

27. log_events.properties JSON 查询性能

漏斗、Event 查询直接查 JSON 字段,数据量大时会成为瓶颈。

  • 建议:对高频漏斗步骤考虑物化表或 properties 中关键字段单独建列。

28. SourceMap 缺少构建唯一标识

RN 热更新场景下,同一个 appVersion 可能对应多个 bundle 版本。

  • 建议SourceMap 上传增加 bundleVersion / codePushVersion / buildNumber 字段,否则堆栈无法定位到正确 bundle。

29. 索引建议

  • log_issue_events 已按 issue_id, created_at 建索引,但如果按 eventId 去重频繁,建议把 uk_app_event_id 中的 event_id 改为 NOT NULL
  • log_events 同理。

六、安全与合规

30. appKey 在上报体中双重携带

请求体里每个 event 都带 appKey,信封层没带;同时 RN SDK 还在 header 里带 X-App-Key

  • 建议:明确上报认证方式。如果按文档“只通过请求体 appKey + 服务开通状态鉴权”,可去掉 header 冗余;若要走 header,则文档也要说明。

31. Webhook secret 未持久化

文档要求配置 secret 用于签名,但数据库表、DTO、Service 都没有该字段。

  • 建议:数据库加 secret 列,并加密存储(至少不要明文落库)。

32. SourceMap 文件上传缺少大小/类型限制

实现直接写入磁盘,没有限制文件大小、校验 MIME/扩展名。

  • 建议:增加大小限制(如 200MB、平台对应扩展名校验,防止恶意上传。

33. 查询端点未校验 appKey 归属

文档 3 提到“查询参数中的 appKey 必须与鉴权租户匹配”,但 LogController 里没有这层校验(只是简单接收 appKey

  • 建议:在网关层或 Controller 层校验租户是否有权访问该 appKey

七、文档本身的可读性与一致性

34. 状态枚举冲突

  • 5.5.4 Issue Status 只有 open/resolved/ignored
  • 7.4 bulk actionreopen,对应状态 open
  • 建议文档说明 reopen 不是持久状态,而是把状态重置为 open

35. 6.5 Event 列表 响应类型错误

标题是 Event 列表,但返回示例写的是 IssueEventResponse。实际 LogService.queryEvents 返回的是自定义 analytics event。

  • 建议:文档增加 LogEventResponse 模型,字段为 namepropertiessessionId 等。

36. Level 与 SDK 方法映射不一致

文档 5.5.1warning 对应 warn(),但数据模型字段应统一为 warning。RN SDK 的 LogLevel 类型却是 'warn'

  • 建议文档、SDK、服务端统一用 warning 作为数据字段,SDK 方法名可以叫 warn()

37. 缺少 OpenAPI / Swagger 声明

当前是纯 Markdown,SDK 和后端维护成本高。

  • 建议:补充 OpenAPI 3.0 YAML,并用 codegen 生成前端/后端 DTO,减少字段 mismatch。

建议的优先级排序

优先级 事项
P0 补齐 /sessions/batch 或文档标注未实现;修复 Webhook 实现与文档严重不符;创建 log_sessions 表;修复 affectedUsers 统计
P1 统一 IssueEvent 响应结构JSON 对象 vs 字符串);清理 IssueResponse 遗留字段;修复 assign/bulk 参数形式;SourceMap 多平台处理
P2 RN SDK 补齐 breadcrumbs/fatal/device;租户平台 TypeScript 类型同步;增加 environment/assignee 筛选
P3 符号化 Worker、漏斗语义增强、OpenAPI 化、Webhook secret 加密存储

后续可执行动作

  1. 文档修正:先修订 BugCollect-API-v1.md,把当前未实现项标注为「未实现/TODO」,把字段 mismatch 统一成实现侧也认可的版本。
  2. 服务端补齐:按修订后的文档修复 LogControllerLogServiceWebhookServiceSourcemapService、Flyway 迁移。
  3. SDK 补齐Android 保持现状,RN SDK 补齐 fatal/breadcrumbs/device;iOS/HarmonyOS/Flutter/Web 按排期推进。
  4. 租户平台同步:更新 tenant-platform/src/api/bugcollect.ts 类型和接口封装。
  5. OpenAPI 化:在 docs/ 下新增 BugCollect-API-v1.yaml,后续作为唯一事实来源。