From dcd429c52d043859bb742cca93eb274add435f7a Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Wed, 17 Jun 2026 18:02:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(bugcollect):=20=E6=9B=B4=E6=96=B0=20API=20?= =?UTF-8?q?=E7=AB=AF=E7=82=B9=E5=B9=B6=E6=94=B9=E8=BF=9B=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 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 信息等 --- .../docs/BugCollect-API-v1-Review.md | 285 ++++++++++++++++++ .../migration/V2__bugcollect_v1_upgrade.sql | 18 ++ 2 files changed, 303 insertions(+) create mode 100644 xuqm-bugcollect-service/docs/BugCollect-API-v1-Review.md create mode 100644 xuqm-bugcollect-service/src/main/resources/db/migration/V2__bugcollect_v1_upgrade.sql diff --git a/xuqm-bugcollect-service/docs/BugCollect-API-v1-Review.md b/xuqm-bugcollect-service/docs/BugCollect-API-v1-Review.md new file mode 100644 index 0000000..df69939 --- /dev/null +++ b/xuqm-bugcollect-service/docs/BugCollect-API-v1-Review.md @@ -0,0 +1,285 @@ +# 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:52` 用 `issue.getType()`(实际是 `level`:`fatal`/`error`)去匹配事件列表,且永远发送 `event: "issue.new"`(`WebhookService.java:71`)。 +- **签名校验缺失**:文档 `8` 声称回调带 `X-BugCollect-Signature: sha256=`,实现里完全没有签名。 +- **字段 mismatch**:文档请求体有 `secret`,实现 `WebhookRequest.java` 根本没有 `secret` 字段,反而多了文档里没提到的 `cooldownSec`。 +- **建议**: + - 统一 Webhook 模型:按文档实现 `secret`、`events`、签名; + - 事件触发逻辑改为按业务事件(`issue.created`/`fatal`/`threshold`/`regressed`/`resolved`)匹配; + - 如果 `cooldownSec` 需要保留,也写进文档。 + +### 3. Issue 详情 / IssueEvent 响应字段结构不一致 + +- **文档 `6.3`**:`exception` 是对象 `{type, value, stacktrace, stackSymbolicated}`,`breadcrumbs`/`tags`/`device` 是 JSON 对象。 +- **实现 `IssueEventResponse.java`**:字段被拍平为 `exceptionType`、`exceptionValue`、`message`、`stack`、`stackSymbolicated`,且 `breadcrumbs`/`tags`/`device` 是 **String**(数据库 JSON 字符串直接返回)。 +- **影响**:租户平台若按文档解析会拿到字符串而不是对象。 +- **建议**: + - 服务端在 `toIssueEventResponse` 里把 JSON 字符串反序列化为对象返回; + - 或者调整文档以匹配实现;但前者更符合 Sentry 对齐原则。 + +### 4. IssueResponse 仍返回已删除字段 + +- **文档 `13` Breaking Change**:`isResolved` 已移除,改用 `status`。 +- **实现 `IssueResponse.java:18`** 仍然包含 `isResolved`,且 `events` 字段虽然总是 `null`,却还存在。 +- **建议**:清理 DTO,移除 `isResolved` 和 `events`(如需兼容可加 `@JsonIgnore` 过渡)。 + +### 5. 分配责任人端点参数形式不一致 + +- **文档 `7.3`**:`PUT /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.3`**:Android 上传 `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:20`**:`eventId` 未加 `@NotBlank`,所以缺失时不会被 `40006` 拒绝。 +- **建议**: + - 文档补齐 `40006`; + - 如果 `eventId` 是必填项,给 DTO 加 `@NotBlank` 或业务校验。 + +--- + +## 二、服务端实现可升级项 + +### 9. `affectedUsers` 统计逻辑错误 + +`LogService.java:84`: +```java +if (userId != null) issue.setAffectedUsers(issue.getAffectedUsers() + 1); +``` +这是“有 userId 就 +1”,同一个用户多次触发会重复累加,不是“受影响独立用户数”。 +- **建议**:维护 `log_issue_users` 关联表或 HyperLogLog,按 `appKey + fingerprint + userId` 去重计算。 + +### 10. 符号化只是空壳 + +`LogService.java:139-142` 的 `triggerSymbolicationAsync` 只打印 debug,没有真正的: +- ProGuard/R8 mapping 还原; +- dSYM 解析; +- SourceMap 解析。 +- **建议**:补充符号化 Worker,或文档中标注该能力尚未可用;对移动 SDK 来说,符号化是核心卖点,不能仅停留在接口层面。 + +### 11. 概览统计 `crashFreeSessionRate` 未实现 + +`OverviewResponse` 里没有 `crashFreeSessionRate`,`LogService.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.HARDWARE`、`Build.PRODUCT` 等特征,或允许租户平台配置过滤模拟器数据。 + +### 19. SDK 队列策略文档与实现不一致 + +- **文档 `11.4`**:`fatal`/`error` 持久化补发,`warning` 及以下仅内存。 +- **RN 实现 `LogQueue.ts`**:所有事件都写 `AsyncStorage`,重试 3 次后丢弃,没有区分级别持久化。 +- **建议**:对齐策略,避免低级别事件撑满存储。 + +### 20. `LogQueue.ts` 上报路径缺少面包屑和设备信息 + +RN SDK 的 `IssueEvent` 没有 `breadcrumbs`、`device`,也没有 `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 前端模型与服务端不匹配 + +前端 `BugCollectWebhook` 有 `eventTypes`、`cooldownSeconds`、`enabled`,但文档和服务端不完全一致。 +- **建议**:先确定最终模型,再同步三端。 + +### 24. 缺少 Issue 管理操作的前端封装 + +`bugcollect.ts` 没有 `resolveIssue`/`ignoreIssue`/`assignIssue`/`bulk` 的 API 方法。 +- **建议**:补齐管理端点调用。 + +### 25. 概览页类型缺少字段 + +`BugCollectOverview` 缺少 `openIssues`、`crashFreeSessionRate` 等文档字段。 +- **建议**:与文档/服务端 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 action` 有 `reopen`,对应状态 `open`; +- 建议文档说明 `reopen` 不是持久状态,而是把状态重置为 `open`。 + +### 35. `6.5 Event 列表` 响应类型错误 + +标题是 Event 列表,但返回示例写的是 `IssueEventResponse`。实际 `LogService.queryEvents` 返回的是自定义 analytics event。 +- **建议**:文档增加 `LogEventResponse` 模型,字段为 `name`、`properties`、`sessionId` 等。 + +### 36. `Level` 与 SDK 方法映射不一致 + +文档 `5.5.1` 中 `warning` 对应 `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. **服务端补齐**:按修订后的文档修复 `LogController`、`LogService`、`WebhookService`、`SourcemapService`、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`,后续作为唯一事实来源。 diff --git a/xuqm-bugcollect-service/src/main/resources/db/migration/V2__bugcollect_v1_upgrade.sql b/xuqm-bugcollect-service/src/main/resources/db/migration/V2__bugcollect_v1_upgrade.sql new file mode 100644 index 0000000..6defc69 --- /dev/null +++ b/xuqm-bugcollect-service/src/main/resources/db/migration/V2__bugcollect_v1_upgrade.sql @@ -0,0 +1,18 @@ +-- BugCollect API v1 upgrade: add new columns for Sentry-aligned fields + +-- log_issues: add level column +ALTER TABLE log_issues ADD COLUMN level VARCHAR(20) NOT NULL DEFAULT 'error'; + +-- log_issue_events: add new columns +ALTER TABLE log_issue_events ADD COLUMN level VARCHAR(20) NOT NULL DEFAULT 'error'; +ALTER TABLE log_issue_events ADD COLUMN environment VARCHAR(50) DEFAULT 'production'; +ALTER TABLE log_issue_events ADD COLUMN device JSON; +ALTER TABLE log_issue_events ADD COLUMN tags JSON; +ALTER TABLE log_issue_events ADD COLUMN sdk_name VARCHAR(100); +ALTER TABLE log_issue_events ADD COLUMN sdk_version VARCHAR(20); + +-- log_events: add new columns +ALTER TABLE log_events ADD COLUMN environment VARCHAR(50) DEFAULT 'production'; +ALTER TABLE log_events ADD COLUMN device JSON; +ALTER TABLE log_events ADD COLUMN sdk_name VARCHAR(100); +ALTER TABLE log_events ADD COLUMN sdk_version VARCHAR(20);