# 后台埋点数据明细与 Excel 导出方案 > **For Hermes:** Use subagent-driven-development skill to implement this plan task-by-task. **Goal:** 在百梦后台新增“埋点数据”页,展示每条埋点原始事件的详细字段,并支持导出为 Excel 可直接打开的表格文件。 **Architecture:** 后端继续由 `api-server` 作为后台 BFF,经 SpacetimeDB HTTP SQL 只读查询 `tracking_event`,不改变表结构和 reducer。前端在 `apps/admin-web` 中新增独立路由与页面,页面渲染后端返回的原始明细,并在浏览器侧导出 Excel 兼容的 `.xls` HTML 表格,避免新增依赖。 **Tech Stack:** Rust Axum、SpacetimeDB HTTP SQL、shared-contracts、React 19、TypeScript、Vite。 --- ## 范围 本次只做后台只读能力: - 展示 `tracking_event` 原始事件明细。 - 每条埋点展示:事件 ID、Event Key、事件名称、Scope、Scope ID、Day Key、用户 ID、作品拥有者、Profile ID、模块、metadata、发生时间。 - 支持按 Event Key、用户 ID、Scope Kind、Scope ID 筛选。 - 支持导出当前筛选结果为 Excel 可打开文件。 不做: - 不新增或修改 SpacetimeDB 表结构。 - 不在后台写入或删除埋点。 - 不把埋点聚合口径下沉到前端计算。 ## 后端契约 新增接口: ```text GET /admin/api/tracking/events?eventKey=&userId=&scopeKind=&scopeId=&limit= ``` 鉴权:复用后台 `require_admin_auth`。 返回: ```json { "entries": [ { "eventId": "daily-login:user:xxx:123", "eventKey": "daily_login", "eventTitle": "每日登录", "scopeKind": "user", "scopeId": "xxx", "dayKey": 20580, "userId": "xxx", "ownerUserId": null, "profileId": null, "moduleKey": "profile", "metadataJson": "{}", "occurredAt": "2026-05-07T00:00:00Z" } ] } ``` 后端实现要点: 1. DTO 放在 `shared-contracts/src/admin.rs`,避免 Rust 与前端口径分叉。 2. Handler 放在 `api-server/src/admin.rs`,使用当前已有 SpacetimeDB HTTP SQL helper 思路。 3. SQL 只读 `tracking_event`,固定白名单列;由于 SpacetimeDB 2.2 HTTP SQL 不支持 `ORDER BY`,后端取回默认 200 / 最大 1000 条后在 API 层按 `occurred_at` 倒序排序。 4. 查询条件只通过字符串转义函数拼接,禁止直接拼接未转义用户输入。 5. `eventTitle` 由后端根据已知事件 key 映射,未知事件返回 `eventKey`。 ## 前端页面 新增路由:`#tracking`,导航标题为“埋点数据”。 页面能力: 1. 顶部筛选区:Event Key、用户 ID、Scope Kind、Scope ID、刷新、导出 Excel。 2. 列表区:移动端可横向滚动,桌面端表格展示。 3. 详情区:每行有“详情”按钮,弹出独立面板展示完整字段与格式化后的 metadata JSON。 4. 导出:导出当前页面已加载结果,文件名形如 `tracking-events-2026-05-07.xls`。 导出实现: - 使用 HTML table + Excel MIME:`application/vnd.ms-excel;charset=utf-8`。 - 文件扩展名使用 `.xls`,Excel/WPS 可直接打开。 - 所有单元格做 HTML 转义。 - metadata 保留原始 JSON 文本,便于运营继续筛选。 ## 验收命令 ```bash npm run check:encoding npm run admin-web:typecheck cargo test -p shared-contracts -p api-server admin_tracking -- --nocapture ``` 如后端接口改动较大,再补充: ```bash npm run api-server curl http://127.0.0.1:/healthz ``` ## 实施任务 ### Task 1: 补充 shared-contracts 后台埋点 DTO **Files:** - Modify: `server-rs/crates/shared-contracts/src/admin.rs` **Steps:** 1. 新增 `AdminTrackingEventListQuery`。 2. 新增 `AdminTrackingEventEntryPayload`。 3. 新增 `AdminTrackingEventListResponse`。 4. 为 DTO 添加中文注释。 ### Task 2: 增加后端后台埋点查询接口 **Files:** - Modify: `server-rs/crates/api-server/src/admin.rs` - Modify: `server-rs/crates/api-server/src/app.rs` **Steps:** 1. 在 `admin.rs` 新增 query 解析与 SQL 构造。 2. 复用 SpacetimeDB HTTP SQL 调用风格读取 rows。 3. 新增 `admin_list_tracking_events` handler。 4. 在 `app.rs` 挂载 `/admin/api/tracking/events`。 5. 添加单元测试覆盖 SQL 字符串转义、limit clamp、SQL 响应解析。 ### Task 3: 增加前端 API 类型与客户端方法 **Files:** - Modify: `apps/admin-web/src/api/adminApiTypes.ts` - Modify: `apps/admin-web/src/api/adminApiClient.ts` **Steps:** 1. 新增埋点 entry/list/query 类型。 2. 新增 `listAdminTrackingEvents(token, query)`。 3. 使用 `URLSearchParams` 拼接非空查询字段。 ### Task 4: 新增后台埋点数据页面 **Files:** - Create: `apps/admin-web/src/pages/AdminTrackingEventsPage.tsx` - Modify: `apps/admin-web/src/styles/admin.css` **Steps:** 1. 实现筛选、刷新、错误状态。 2. 实现明细表格。 3. 实现独立详情面板。 4. 实现 Excel `.xls` 导出。 5. 保持 UI 简洁,不添加说明类大段文案。 ### Task 5: 接入后台路由与导航 **Files:** - Modify: `apps/admin-web/src/app/adminRoutes.ts` - Modify: `apps/admin-web/src/app/AdminShell.tsx` - Modify: `apps/admin-web/src/app/AdminApp.tsx` **Steps:** 1. 增加 `tracking` 路由。 2. 导航增加图标。 3. `AdminApp` 渲染新页面。 ### Task 6: 验证并提交 **Steps:** 1. 运行 `npm run check:encoding`。 2. 运行 `npm run admin-web:typecheck`。 3. 运行后端相关 cargo test。 4. 修复问题后提交并推送当前分支。