Files
Genarrative/docs/technical/ANALYTICS_DATE_DIMENSION_IMPLEMENTATION_2026-05-04.md
kdletters 5c7c039e52
Some checks failed
CI / verify (push) Has been cancelled
feat: add analytics date dimension bindings
- lock profile task tracking scope to user

- add analytics date dimension module support and tests

- regenerate SpacetimeDB Rust bindings with private APIs
2026-05-04 13:54:41 +08:00

289 lines
9.1 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。
## 阶段结论
当前阶段已经完成“个人任务埋点范围收紧”和“日期维表 module 侧能力”的核心落地,并已生成 SpacetimeDB Rust client bindings。
剩余工作不再是 bindings 环境阻塞,而是后续业务接入范围:是否增加 `spacetime-client` facade以及是否继续推进事件写入链路、聚合查询 API 和前端 analytics contracts。