Files
Genarrative/docs/technical/ANALYTICS_DATE_DIMENSION_IMPLEMENTATION_2026-05-04.md
历冰郁-hermes版 1d9d8c2e41
Some checks failed
CI / verify (push) Has been cancelled
feat: add analytics metric granularity query
2026-05-04 16:29:48 +08:00

368 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Analytics Date Dimension 与个人任务埋点范围收口记录2026-05-04
## 背景
本记录用于收口 `.hermes/plans/2026-05-04_022223-analytics-time-dimension-mapping.md` 中当前阶段已经落地的内容,并明确尚未执行的后续范围。
本阶段目标不是完整上线运营统计查询,而是先完成两件基础工作:
1. 收紧个人任务系统的埋点范围,避免运营或接口把个人任务错误配置为 `site``module``work` 等非用户维度。
2. 新增统一日期维表 `analytics_date_dimension`,为后续按周、月、季、年聚合埋点数据提供稳定的日期 bucket 映射。
## 当前已完成范围
### 1. 个人任务埋点范围锁定为 User
当前个人任务系统首版只支持用户维度埋点。
已完成:
- Admin 任务配置页不再展示“埋点范围”选择。
- Admin 保存任务配置时固定传 `scopeKind: 'user'`
- API 层拒绝非 `user` 的个人任务配置。
- 领域输入构造层拒绝非 `User` 的个人任务配置。
- `Work => user_id` 的错误映射已移除。
- 任务进度刷新、任务中心快照、领奖链路遇到非 `User` 的异常个人任务配置时显式报错,不再静默按 0 进度处理。
相关文件:
```text
apps/admin-web/src/pages/AdminTaskConfigPage.tsx
apps/admin-web/src/api/adminApiTypes.ts
server-rs/crates/api-server/src/runtime_profile.rs
server-rs/crates/module-runtime/src/commands.rs
server-rs/crates/module-runtime/src/errors.rs
server-rs/crates/spacetime-module/src/runtime/profile.rs
```
### 2. 日期维表领域模型与纯函数
已在 `module-runtime` 中补充日期维表快照和纯函数。
日期维表使用现有北京时间业务日 `day_key` 语义:
```text
date_key = floor((occurred_at_micros + 8h) / 1d)
```
已完成能力:
-`YYYY-MM-DD` 解析业务日 `date_key`
-`date_key` 构造日期维表快照。
- 生成 ISO weekday周一=1周日=7。
- 生成 ISO week key`YYYYWW`,跨年周按 ISO week-year。
- 生成 week/month/quarter/year 的 key 和起止 `date_key`
- 限制日期维表支持范围为:
- `2000-01-01`
-`2100-12-31`
相关文件:
```text
server-rs/crates/module-runtime/src/domain.rs
server-rs/crates/module-runtime/src/application.rs
server-rs/crates/module-runtime/src/lib.rs
```
### 3. SpacetimeDB 日期维表与 reducer
已新增 SpacetimeDB 表:
```text
analytics_date_dimension
```
表字段包括:
```text
date_key
calendar_date
weekday
iso_week_key
week_start_date_key
week_end_date_key
month_key
month_start_date_key
month_end_date_key
quarter_key
quarter_start_date_key
quarter_end_date_key
year_key
year_start_date_key
year_end_date_key
created_at
updated_at
```
已新增索引:
```text
iso_week_key
month_key
quarter_key
year_key
```
已新增 reducer
```text
ensure_analytics_date_dimension_for_date
seed_analytics_date_dimensions
```
当前 reducer 行为:
- `ensure` 单日幂等补齐。
- `seed` 按日期范围幂等补齐。
- `seed` 拒绝 `start_date > end_date`
- `seed` 单次最多允许 `ANALYTICS_DATE_DIMENSION_MAX_SEED_DAYS = 3660` 天。
-`date_key` 进入 ensure 前先做支持范围校验,避免极端整数进入日历算法。
相关文件:
```text
server-rs/crates/spacetime-module/src/runtime/analytics_date_dimension.rs
server-rs/crates/spacetime-module/src/runtime/mod.rs
server-rs/crates/spacetime-module/src/migration.rs
docs/technical/SPACETIMEDB_TABLE_CATALOG.md
```
### 4. SpacetimeDB Rust client bindings
已按项目脚本生成 Rust bindings并在生成参数中显式包含 private tables/functions
```bash
PATH="/tmp/spacetime-bin:$PATH" npm run spacetime:generate -- --rust-only
```
本次已修改生成脚本:
```text
scripts/generate-spacetime-bindings.mjs
```
`spacetime generate` 参数中加入:
```text
--include-private
```
说明SpacetimeDB CLI 2.1.0 的参数名是 `--include-private`,不是 `--non-private`。该参数含义是将 private tables/functions 也包含进生成代码,满足 api-server 通过 Rust bindings 访问 module private table/reducer 的需求。
```text
spacetimedb tool version 2.1.0; spacetimedb-lib version 2.1.0
```
生成脚本:
```text
scripts/generate-spacetime-bindings.mjs
```
已新增 analytics date dimension 相关 bindings
```text
server-rs/crates/spacetime-client/src/module_bindings/analytics_date_dimension_ensure_input_type.rs
server-rs/crates/spacetime-client/src/module_bindings/analytics_date_dimension_seed_input_type.rs
server-rs/crates/spacetime-client/src/module_bindings/analytics_date_dimension_type.rs
server-rs/crates/spacetime-client/src/module_bindings/analytics_date_dimension_table.rs
server-rs/crates/spacetime-client/src/module_bindings/ensure_analytics_date_dimension_for_date_reducer.rs
server-rs/crates/spacetime-client/src/module_bindings/seed_analytics_date_dimensions_reducer.rs
```
并更新了:
```text
server-rs/crates/spacetime-client/src/module_bindings/mod.rs
```
注意:
- `analytics_date_dimension` 表当前是 private table由于生成脚本已加 `--include-private`,本次 codegen 已生成 `analytics_date_dimension_table.rs`,可通过 `ctx.db.analytics_date_dimension()` 访问 client cache / query builder。
- bindings 目录是自动生成产物,本次以项目脚本整体刷新,除新增 analytics 文件外,也带来了大量已存在 table/reducer/procedure 文件的格式化/生成器输出差异。
### 5. 测试覆盖
已新增测试:
```text
server-rs/crates/module-runtime/tests/analytics_date_dimension.rs
server-rs/crates/module-runtime/tests/profile_task_scope.rs
server-rs/crates/shared-contracts/tests/profile_task_contract.rs
```
覆盖重点:
- `2024-02-29` 闰年。
- `2025-12-29` ISO week 跨年。
- `2026-01-01` 跨年周。
- `2026-03-31` Q1 结束。
- `2026-04-01` Q2 开始。
- `2026-12-31` 年末。
- 非法日期解析失败。
- 超出日期维表支持范围失败。
- 个人任务 `scopeKind=user` 成功。
- 个人任务 `scopeKind=site/module/work` 失败。
- `work` scope 不会静默映射到 `user_id`
- Admin 个人任务配置 contract 保持 `scopeKind: user`
## 已验证命令
`server-rs/` 执行:
```bash
cargo fmt -p module-runtime -p spacetime-module -p spacetime-client
cargo test -p spacetime-client --no-run
cargo test -p spacetime-module --no-run
cargo test -p module-runtime --test analytics_date_dimension
cargo test -p module-runtime --test profile_task_scope
cargo test -p shared-contracts --test profile_task_contract
```
从项目根目录执行:
```bash
npm run admin-web:typecheck
```
当前结果:
- `spacetime-client --no-run` 编译通过。
- `spacetime-module --no-run` 编译通过。
- `analytics_date_dimension` 测试通过8 passed。
- `profile_task_scope` 测试通过3 passed。
- `profile_task_contract` 测试通过2 passed。
- `admin-web:typecheck` 通过。
已知非本阶段阻塞:
- 完整运行 `cargo test -p spacetime-module` 时,曾出现既有 puzzle 测试失败:
```text
puzzle::tests::puzzle_preview_is_publishable_with_complete_draft FAILED
assertion failed: preview.publish_ready
```
该失败与当前埋点范围和日期维表改动无直接关系,本阶段以 `cargo test -p spacetime-module --no-run` 作为编译门禁。
## 当前未完成 / 暂缓项
### 1. 暂未新增 spacetime-client facade
当前没有新增:
```text
SpacetimeClient::ensure_analytics_date_dimension_for_date
SpacetimeClient::seed_analytics_date_dimensions
```
原因:
- 生成脚本已加入 `--include-private`private reducer/type/table bindings 已可用于后续 facade 实现。
- 但 Step 7/8/9 暂缓,尚未由 `api-server` 或统计查询链路调用该能力。
- 如后续只是 SpacetimeDB module 内部写入统计时 ensure可以直接复用 module 内部 helper不一定需要远程 client facade。
- 若后续需要由 API 或运维接口触发 seed/ensure可基于本次已生成的 reducer bindings 再补 facade。
### 2. Step 7/8/9 暂缓
本阶段未接入:
- 事件写入链路自动 ensure 日期维表。
- 聚合查询 API 的 `granularity = day | week | month | quarter | year`
- shared contracts / 前端 analytics contracts。
- 历史事件回填。
这些应作为后续阶段单独设计和落地。
## 后续建议顺序
1. 如需提交本阶段改动,确认是否接受 `module_bindings` 整体刷新带来的大量生成文件 diff。
2. 如希望 diff 更小,可评估仅提交 analytics date dimension 相关生成文件与 `mod.rs`;但需要非常谨慎,因为 `module_bindings` 是自动生成产物。
3. 如需要由 `api-server` 触发 seed/ensure再补 `spacetime-client` facade。
4. 进入 Step 7/8/9事件写入链路、聚合查询 API、前端 contracts。
## Step 7/8/9 后续接入记录2026-05-04
本次继续推进此前暂缓的 Step 7/8/9 中“按日期维度聚合查询 API / contracts / client facade”部分。
### 已新增能力
1. `module-runtime` 新增 analytics metric 聚合领域类型与纯函数:
- `AnalyticsGranularity = day | week | month | quarter | year`
- `AnalyticsMetricQueryInput`
- `AnalyticsBucketMetric`
- `AnalyticsMetricQueryResponse`
- `aggregate_runtime_tracking_daily_stats(...)`
2. `spacetime-module` 新增 `query_analytics_metric` procedure直接聚合 tracking daily stat输出按 bucket 排序的统计结果。
3. `spacetime-client` 新增 facade
```rust
SpacetimeClient::query_analytics_metric(event_key, scope_kind, scope_id, granularity)
```
4. `api-server` 新增登录态接口:
```http
GET /api/profile/analytics/metric?eventKey=...&scopeKind=user&scopeId=...&granularity=day
```
请求参数:
| 参数 | 说明 |
| --- | --- |
| `eventKey` | 埋点事件 key必填 |
| `scopeKind` | `site | work | module | user` |
| `scopeId` | 对应范围 ID必填 |
| `granularity` | `day | week | month | quarter | year` |
响应 data
```ts
type AnalyticsMetricQueryResponse = {
buckets: Array<{
bucketKey: string;
bucketStartDateKey: number;
bucketEndDateKey: number;
value: number;
}>;
};
```
5. shared contracts / 前端 shared contracts 已新增 analytics query 类型:
- `AnalyticsMetricQueryRequest`
- `AnalyticsMetricQueryResponse`
- `AnalyticsBucketMetricResponse` / `AnalyticsBucketMetric`
- `AnalyticsGranularity`
### 本次验证
`server-rs/` 执行通过:
```bash
cargo test -p module-runtime --test analytics_granularity
cargo check -p spacetime-module
cargo check -p spacetime-client
cargo check -p api-server
```
验证结果:
- `analytics_granularity` 测试通过3 passed。
- `spacetime-module` 编译通过,仅存在既有 dead_code warnings。
- `spacetime-client` 编译通过。
- `api-server` 编译通过,仅存在既有 prompt dead_code warnings。
### 注意事项
当前环境未检测到 `spacetime` / `spacetimedb` CLI因此 analytics metric 相关 `module_bindings` 是按现有生成物结构手动补齐的临时生成物。后续有 CLI 的开发机应优先通过项目脚本重新生成 bindings并复核手写生成物是否可被正式生成输出覆盖。
---
## 阶段结论
当前阶段已经完成“个人任务埋点范围收紧”和“日期维表 module 侧能力”的核心落地,并已生成 SpacetimeDB Rust client bindings。
剩余工作不再是 bindings 环境阻塞,而是后续业务接入范围:是否增加 `spacetime-client` facade以及是否继续推进事件写入链路、聚合查询 API 和前端 analytics contracts。