feat: add analytics date dimension bindings
Some checks failed
CI / verify (push) Has been cancelled

- lock profile task tracking scope to user

- add analytics date dimension module support and tests

- regenerate SpacetimeDB Rust bindings with private APIs
This commit is contained in:
2026-05-04 13:41:22 +08:00
committed by 历冰郁-hermes版
parent 9f3e34e81a
commit 5c7c039e52
253 changed files with 14783 additions and 1462 deletions

View File

@@ -0,0 +1,20 @@
# AdminTaskConfigPage 埋点范围收口记录2026-05-04
## 变更目标
- 前端隐藏「埋点范围」选择项。
- 保存任务配置时固定传递 `scopeKind=user`,避免运营在后台选择其他范围。
## 落地结果
- `apps/admin-web/src/pages/AdminTaskConfigPage.tsx`
- 移除了「埋点范围」下拉选择 UI。
- 保存时改为固定提交 `scopeKind: 'user'`
- 回填表单时不再读取或维护 `scopeKind` 的可编辑状态。
## 验证结果
- 已检查页面源码,确认不再存在「埋点范围」字段与可编辑逻辑。
- 已执行 `npm run admin-web:typecheck`
- 当前验证失败原因为环境缺少 `node_modules/typescript/bin/tsc`,属于依赖安装状态问题,不是本次前端改动引入的代码错误。
## 遗留说明
- `apps/admin-web/src/api/adminApiTypes.ts` 中仍保留 `TrackingScopeKind` 类型,供接口契约与其他前端模块兼容使用。
- `apps/admin-web/src/config/trackingEventDefinitions.ts` 仍保留事件定义中的 `scopeKind` 元数据,但页面不再允许运营修改。

View File

@@ -0,0 +1,288 @@
# 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。

View File

@@ -0,0 +1,18 @@
# 个人任务 scope 限制说明2026-05-04
## 背景
个人任务配置首版只支持按用户维度统计进度,即 `RuntimeTrackingScopeKind::User` / API `scopeKind: "user"``site``module``work` 未来可作为全站、模块或作品维度任务扩展,但当前不应被个人任务配置接受。
## 后端约束
- HTTP 管理接口 `admin_upsert_profile_task_config` 在解析 `scopeKind` 后立即校验:非 `user` 返回 400并提示“个人任务 scopeKind 首版仅支持 user”。
- 领域构造函数 `build_runtime_profile_task_config_admin_upsert_input` 兜底校验:非 `RuntimeTrackingScopeKind::User` 返回 `RuntimeProfileFieldError::UnsupportedProfileTaskScopeKind`
- SpacetimeDB 模块内 `profile_task_tracking_scope_id` 不再把 `Work` 静默映射到 `user_id`;非 User scope 返回 `None`,个人任务进度读取按 0 处理,避免错误串桶。
## 测试覆盖
`module-runtime` 单元测试覆盖:
- `User` scope 可成功构造个人任务配置输入。
- `Site` / `Module` / `Work` scope 均被拒绝,错误为 `UnsupportedProfileTaskScopeKind`