docs: design cloudflare analytics only migration

This commit is contained in:
2026-06-22 18:41:45 -07:00
parent 0ac1b7dd13
commit 1ccb966085

View File

@@ -0,0 +1,219 @@
# Cloudflare Analytics Only 设计
## 背景
当前 `server/src` 已经有 Cloudflare Analytics Engine 热查询和 Cloudflare Pipelines 归档写入的第一阶段代码,但分析链路仍保留 Tinybird 作为写入目标、读路径回退和部分审计存储。用户目标是移除 Tinybird 回退方案,只保留 Cloudflare analytics pipelines并移除 `@tinybirdco/sdk` 依赖。
本设计覆盖:
- `/Volumes/sker/autumn/server/src`
- `/Volumes/sker/autumn/vite/src`
- 与上述改动直接相关的 `server/package.json``bun.lock``server/wrangler.jsonc`、单元测试和文档
本设计不把整个项目一次性改成完全无 Tinybird 代码。重点是移除 analytics 的 Tinybird fallback/dual-write以及删除 `@tinybirdco/sdk` 的运行时依赖来源。
## 目标
- 事件分析写入只走 Cloudflare Analytics Engine 和 Cloudflare Pipelines。
- analytics 读路径不再静默回退 Tinybird。
- 移除 `@tinybirdco/sdk` 依赖和 `server/src` 中对它的 import。
- 前端不再显示 Tinybird 专有错误文案。
- migration item audit 不再依赖 Tinybird SDK改为 Cloudflare-friendly 的稳定存储边界。
- 保留主业务可靠性:分析写入失败不影响 `track/check`、余额、扣减、订阅或幂等状态。
## 非目标
- 不在本次彻底删除 `@chronark/zod-bird` 和所有 Tinybird pipes。
- 不重写所有 revenue analytics、复杂 aggregate/groupable 查询和 ClickHouse SQL 查询。
- 不把 R2/R2 SQL 冷归档同步接入实时 dashboard。
- 不把 Cloudflare analytics 写入失败升级为业务请求失败。
- 不在本次解决所有 Cloudflare-only runtime 遗留项,例如 `nodejs_compat` 或全部 Node/Bun SDK 残留;这些已有独立设计线。
## 推荐方案
采用聚焦方案:
1. 移除 analytics 的 Tinybird 写入和读回退。
2. 保留 Cloudflare hot store 作为唯一实时 analytics store。
3. 对 Cloudflare hot store 暂不支持的查询返回明确错误,而不是回退 Tinybird。
4. 将 migration item audit 从 Tinybird SDK 改到 Postgres-backed 存储。
5. 删除 `@tinybirdco/sdk` 依赖。
不采用“彻底移除所有 Tinybird 代码”的原因是范围会扩大到 revenue analytics、复杂 pipes 和历史 SQL 语义,风险明显高于当前目标。不采用“只删 `@tinybirdco/sdk`”的原因是它保留 analytics fallback不满足用户目标。
## 架构边界
`server/src/internal/analytics` 继续拥有业务 analytics 接口,但生产运行路径收敛为 Cloudflare
- `EventBatchingManager` 继续负责批处理和 Postgres 插入队列。
- 事件分析写入改为语义明确的 `writeEventsToCloudflareAnalytics(...)`
- `Analytics Engine` 承载近实时热查询。
- `EVENTS_ARCHIVE_PIPELINE` 承载归档写入。
- `AnalyticsStore` 接口可以保留,但 selector 不再返回 Tinybird store 作为 fallback。
- `tinybirdEventStore` 可以在后续彻底迁移时删除;本次若仍被未迁移路径引用,必须确保它不是 Cloudflare analytics 读路径的 fallback。
`vite/src` 只做用户可见状态调整:移除 `Tinybird is disabled` 文案和对 `ErrCode.TinybirdDisabled` 的 analytics 页面专属判断,改为 Cloudflare analytics unavailable/unsupported 的通用状态。
## 写入数据流
写入流:
1. 业务产生 `EventInsert[]`
2. `EventBatchingManager` 将事件批量入队到 Postgres 插入 job。
3. 同一批事件发送到 `writeEventsToCloudflareAnalytics({ env, events, logger })`
4. `writeEventsToAnalyticsEngine(...)` 调用 `env.EVENTS_ANALYTICS.writeDataPoint(...)`
5. `writeEventsToArchivePipeline(...)` 调用 `env.EVENTS_ARCHIVE_PIPELINE.send(...)`
6. 任一 Cloudflare analytics 写入失败只记录日志和 Sentry不抛出到主业务流。
Cloudflare Analytics Engine 的 datapoint 字段顺序是稳定契约。现有 `CLOUDFLARE_ANALYTICS_INDEX_FIELDS``CLOUDFLARE_ANALYTICS_BLOB_FIELDS``CLOUDFLARE_ANALYTICS_DOUBLE_FIELDS` 必须继续由测试锁定,避免查询层的 `blobN``doubleN` 映射漂移。
Pipelines binding 继续使用 `wrangler.jsonc``pipelines` 配置,并使用 `stream` 字段。不要回退到旧字段名,也不要在业务代码里硬编码 Cloudflare 资源名。
## 读取数据流
实时 analytics 读路径:
1. `listEventNames``listRawEvents``listEvents``listByCursor` 调用 store selector 或直接调用 `cloudflareHotEventStore`
2. Cloudflare hot read 开启且查询在热窗口内时执行 Analytics Engine SQL API 查询。
3. 查询使用当前 `eventSchema` 字段顺序构建 SQL。
4. 查询结果映射回现有 API response shape。
不再支持的自动回退:
- Cloudflare hot read disabled -> 不回退 Tinybird。
- 超出热窗口 -> 不回退 Tinybird。
- `filter_by` 等 hot store 暂不支持能力 -> 不回退 Tinybird。
- Analytics Engine SQL API 未配置 -> 不回退 Tinybird。
这些情况应返回明确错误。建议新增或复用语义清楚的错误码:
- `CloudflareAnalyticsUnavailable`
- `CloudflareAnalyticsUnsupportedQuery`
错误文案应描述当前 analytics 查询不可用或查询能力暂不支持,不提 Tinybird。
## Migration Item Audit 替代
`@tinybirdco/sdk` 当前还用于 migration item audit。为了删除该依赖本次将该审计存储改为 Postgres-backed。
理由:
- migration item audit 是低频业务审计数据,不是高吞吐指标。
- 它需要按 `org_id``env``migration_internal_id``migration_run_id``item_kind``item_id` 做精确读取和 latest-by-item 聚合。
- Postgres 已经是业务主存储,事务、索引和测试路径都更清楚。
- 这避免为了低频审计路径引入 R2 SQL 或 Analytics Engine 查询语义。
设计:
- 定义 Postgres 表或复用现有迁移审计表,字段对应当前 `TinybirdMigrationItemEvent`
- 保留当前 repo 函数名或导出 shape降低调用方改动。
- `insertMigrationItemEvents` 批量插入 Postgres失败只记录日志不阻塞 migration 主流程。
- `listMigrationItemEvents``listLatestMigrationItemEvents` 从 Postgres 查询,并保持现有排序和空列表行为。
- 删除 `initTinybirdV2.ts``migrationItemEventsDataSource.ts``@tinybirdco/sdk` 的依赖。
如果已有数据库迁移框架需要 schema 变更,本实现计划必须使用数据库迁移安全流程:先加表/索引,再切代码,避免读写代码和 schema 不匹配。
## 配置变化
移除或废弃:
- `CLOUDFLARE_ANALYTICS_TINYBIRD_FALLBACK_ENABLED`
- Tinybird secondary dual-write 配置
- `TINYBIRD_API_URL` / `TINYBIRD_TOKEN` 在 analytics 写入路径中的使用
- `@tinybirdco/sdk` package dependency
保留或确认:
- `CLOUDFLARE_ANALYTICS_WRITE_ENABLED`
- `CLOUDFLARE_ANALYTICS_ARCHIVE_ENABLED`
- `CLOUDFLARE_ANALYTICS_HOT_READ_ENABLED`
- `CLOUDFLARE_ANALYTICS_HOT_RETENTION_DAYS`
- `CLOUDFLARE_ANALYTICS_DATASET`
- `EVENTS_ANALYTICS`
- `EVENTS_ARCHIVE_PIPELINE`
- `CLOUDFLARE_ACCOUNT_ID``CLOUDFLARE_API_TOKEN`,用于 Analytics Engine SQL API
Cloudflare 写入和归档 flags 可以继续独立控制,但它们不表示 Tinybird fallback 是否存在。
## 错误处理
- 写入失败Cloudflare analytics 写入失败不影响主业务。记录结构化日志和 Sentry包含 service、eventCount 和错误信息。
- 读取失败:不隐藏失败,不回退 Tinybird。返回 Cloudflare analytics unavailable/unsupported 类型错误。
- 配置缺失hot read 开启但缺少 SQL API token 或 account id 时返回 service unavailable 类错误。
- 查询不支持:`filter_by` 或超出热窗口等情况返回 unsupported query 类错误。
- migration audit 写入失败:记录日志,不阻塞 migration 主流程。
- migration audit 读取无数据:保持当前保守行为,返回空列表。
## 前端行为
`vite/src/views/customers/customer/analytics/AnalyticsView.tsx` 不再使用 `ErrCode.TinybirdDisabled` 驱动 UI 状态。
新行为:
- 对 Cloudflare analytics unavailable 显示中性状态。
- 对 unsupported query 显示查询暂不支持状态。
- 页面文案不出现 `Tinybird`
- 不改变 analytics 页面主体布局和交互,避免把后端迁移扩大成 UI 重构。
## 测试计划
更新现有测试:
- `server/tests/unit/analytics/cloudflare-config.test.ts`
- 删除 `tinybirdFallbackEnabled` 断言。
- 验证 Cloudflare write/read/archive flags 和 bindings。
- `server/tests/unit/analytics/select-analytics-store.test.ts`
- 不再期待 Tinybird fallback。
- 验证 disabled、outside range、unsupported feature 返回 Cloudflare analytics 错误或 unsupported decision。
- `server/tests/unit/analytics/cloudflare-writers.test.ts`
- 验证 Cloudflare 写入失败不抛出到调用方。
- 验证没有 Tinybird 调用。
- `server/tests/unit/runtime-env-imports.test.ts`
- 增加 `server/src` 禁止 import `@tinybirdco/sdk` 的 guard。
- `vite` 相关测试或静态断言
- 验证 `vite/src` 不再出现 `Tinybird is disabled`
新增或调整测试:
- migration item audit Postgres repo 单元测试。
- package dependency guard验证 `server/package.json` 不声明 `@tinybirdco/sdk`
- 如果新增数据库表,增加迁移 shape 或 repo 查询测试。
推荐验证命令:
```sh
cd server && bun test --isolate tests/unit/analytics
cd server && bun test --isolate tests/unit/runtime-env-imports.test.ts
bun -F @autumn/server ts
bun -F @autumn/vite ts
```
如果数据库迁移加入本次实现计划,还需要运行对应 migration/schema 验证命令。
## 验收标准
- `rg -n "@tinybirdco/sdk" server/src server/package.json` 无结果。
- `server/package.json` 不再依赖 `@tinybirdco/sdk`
- analytics 写入路径不再调用 `sendEventsToTinybird`
- Cloudflare analytics 写入仍可同时覆盖 Analytics Engine 和 Pipelines。
- analytics 读路径不再因为 disabled、outside range、unsupported feature 回退 Tinybird。
- `vite/src` 不再显示 Tinybird 专有文案。
- analytics 单元测试和 runtime import guard 通过。
- TypeScript 检查通过,或明确记录与本次无关的既有失败。
## 实施顺序
1. 先更新测试和 guards让 Tinybird fallback 与 `@tinybirdco/sdk` import 成为可重复验证的失败。
2. 收敛 analytics 写入函数命名和调用方,删除 Tinybird primary/secondary dual-write。
3. 收敛 analytics store selection移除 Tinybird fallback。
4. 新增 Cloudflare analytics unavailable/unsupported 错误语义,并更新前端文案。
5. 将 migration item audit 改为 Postgres-backed。
6. 删除 `@tinybirdco/sdk` 依赖并更新 lockfile。
7. 跑验证命令,修复由本次变更引入的失败。
## 风险与后续
- 部分复杂 analytics 查询仍可能依赖 Tinybird pipes 或 ClickHouse SQL。若它们属于 dashboard 核心能力,应单独开第二份 spec 迁移到 Analytics Engine、R2 SQL 或 Postgres 聚合。
- Revenue analytics 当前不纳入本次迁移,后续需要单独设计指标语义和数据源。
- Analytics Engine 热窗口之外的历史查询当前不自动支持。后续应基于 Pipelines 归档和 R2 SQL 设计异步或低频历史查询路径。
- Cloudflare-only runtime 仍有更大范围的 Node/Bun 兼容残留,本次只处理与 analytics/Tinybird SDK 直接相关的部分。