11 KiB
Analytics Date Dimension 与个人任务埋点范围收口记录(2026-05-04)
背景
本记录用于收口 .hermes/plans/2026-05-04_022223-analytics-time-dimension-mapping.md 中当前阶段已经落地的内容,并明确尚未执行的后续范围。
本阶段目标不是完整上线运营统计查询,而是先完成两件基础工作:
- 收紧个人任务系统的埋点范围,避免运营或接口把个人任务错误配置为
site、module、work等非用户维度。 - 新增统一日期维表
analytics_date_dimension,为后续按周、月、季、年聚合埋点数据提供稳定的日期 bucket 映射。
当前已完成范围
1. 个人任务埋点范围锁定为 User
当前个人任务系统首版只支持用户维度埋点。
已完成:
- Admin 任务配置页不再展示“埋点范围”选择。
- Admin 保存任务配置时固定传
scopeKind: 'user'。 - API 层拒绝非
user的个人任务配置。 - 领域输入构造层拒绝非
User的个人任务配置。 Work => user_id的错误映射已移除。- 任务进度刷新、任务中心快照、领奖链路遇到非
User的异常个人任务配置时显式报错,不再静默按 0 进度处理。
相关文件:
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 语义:
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
相关文件:
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 表:
analytics_date_dimension
表字段包括:
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
已新增索引:
iso_week_key
month_key
quarter_key
year_key
已新增 reducer:
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 前先做支持范围校验,避免极端整数进入日历算法。
相关文件:
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:
PATH="/tmp/spacetime-bin:$PATH" npm run spacetime:generate -- --rust-only
本次已修改生成脚本:
scripts/generate-spacetime-bindings.mjs
在 spacetime generate 参数中加入:
--include-private
说明:SpacetimeDB CLI 2.1.0 的参数名是 --include-private,不是 --non-private。该参数含义是将 private tables/functions 也包含进生成代码,满足 api-server 通过 Rust bindings 访问 module private table/reducer 的需求。
spacetimedb tool version 2.1.0; spacetimedb-lib version 2.1.0
生成脚本:
scripts/generate-spacetime-bindings.mjs
已新增 analytics date dimension 相关 bindings:
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
并更新了:
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. 测试覆盖
已新增测试:
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-29ISO week 跨年。2026-01-01跨年周。2026-03-31Q1 结束。2026-04-01Q2 开始。2026-12-31年末。- 非法日期解析失败。
- 超出日期维表支持范围失败。
- 个人任务
scopeKind=user成功。 - 个人任务
scopeKind=site/module/work失败。 workscope 不会静默映射到user_id。- Admin 个人任务配置 contract 保持
scopeKind: user。
已验证命令
从 server-rs/ 执行:
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
从项目根目录执行:
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 测试失败:
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
当前没有新增:
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。
- 历史事件回填。
这些应作为后续阶段单独设计和落地。
后续建议顺序
- 如需提交本阶段改动,确认是否接受
module_bindings整体刷新带来的大量生成文件 diff。 - 如希望 diff 更小,可评估仅提交 analytics date dimension 相关生成文件与
mod.rs;但需要非常谨慎,因为module_bindings是自动生成产物。 - 如需要由
api-server触发 seed/ensure,再补spacetime-clientfacade。 - 进入 Step 7/8/9:事件写入链路、聚合查询 API、前端 contracts。
Step 7/8/9 后续接入记录(2026-05-04)
本次继续推进此前暂缓的 Step 7/8/9 中“按日期维度聚合查询 API / contracts / client facade”部分。
已新增能力
-
module-runtime新增 analytics metric 聚合领域类型与纯函数:AnalyticsGranularity = day | week | month | quarter | yearAnalyticsMetricQueryInputAnalyticsBucketMetricAnalyticsMetricQueryResponseaggregate_runtime_tracking_daily_stats(...)
-
spacetime-module新增query_analytics_metricprocedure,直接聚合 tracking daily stat,输出按 bucket 排序的统计结果。 -
spacetime-client新增 facade:
SpacetimeClient::query_analytics_metric(event_key, scope_kind, scope_id, granularity)
api-server新增登录态接口:
GET /api/profile/analytics/metric?eventKey=...&scopeKind=user&scopeId=...&granularity=day
请求参数:
| 参数 | 说明 |
|---|---|
eventKey |
埋点事件 key,必填 |
scopeKind |
`site |
scopeId |
对应范围 ID,必填 |
granularity |
`day |
响应 data:
type AnalyticsMetricQueryResponse = {
buckets: Array<{
bucketKey: string;
bucketStartDateKey: number;
bucketEndDateKey: number;
value: number;
}>;
};
- shared contracts / 前端 shared contracts 已新增 analytics query 类型:
AnalyticsMetricQueryRequestAnalyticsMetricQueryResponseAnalyticsBucketMetricResponse/AnalyticsBucketMetricAnalyticsGranularity
本次验证
从 server-rs/ 执行通过:
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。