# S26 Dashboard 聚合 Runbook ## 范围 S26 在 API 中新增 Dashboard 聚合接口: - `GET /api/v2/dashboard/summary` - `GET /api/v2/dashboard/trends?hours=24&bucketMinutes=60` 两个接口均要求 `dashboard.view` 权限。S26 未连接服务器、未重启服务、未执行数据库迁移,也未修改 Redis/OpenSIPS 配置。 ## 数据来源 当前实现基于已有 V2 Schema: - `raw_cdrs`:今日通话数、接通数、失败数、接通率、通话时长、失败响应码、趋势通话量。 - `rated_cdrs` + `raw_cdrs.started_at`:客户费用、供应商成本、毛利和趋势金额。 - `customers`、`customer_gateways`、`vendor_gateways`:启用实体数量。 - `recordings` + `quality_reviews`:待质检录音数。 - `raw_cdrs.vendor_gateway_id`:今日失败落地网关 Top 10。 实时在线通话和注册数在 S26 返回 `0` 且标记 `source: "not_configured"`。这部分应在后续接入 Redis/OpenSIPS 指标后替换,避免返回伪实时数据。 ## 查询窗口 - Summary 的“今日”按 `Asia/Shanghai` 自然日计算,数据库时间仍按 UTC ISO 语义传入。 - Trends 默认最近 24 小时,支持 `hours=1..168`。 - `bucketMinutes` 仅允许 `5`、`15`、`60`。 - 所有 CDR 查询都带 `started_at` 时间窗口,避免首页扫描全量 CDR。 ## 后续预聚合演进 设计文档要求 24 小时趋势最终使用 5 分钟或 1 小时预聚合。当前 S26 没有新增指标表,是为了避免把本任务扩大为数据库迁移和 worker 部署。 后续可新增 `worker-metrics` 或复用 CDR Worker 增量写入统计表,例如: ```text dashboard_call_buckets(bucket_start, bucket_minutes, total_calls, answered_calls, failed_calls, duration_sec, customer_fee, vendor_cost, gross_profit) dashboard_failure_codes(bucket_start, bucket_minutes, sip_code, count) dashboard_gateway_health(vendor_gateway_id, status, reason, updated_at) ``` 切换时保持 API 响应结构不变,只替换 `DashboardRepository` 的数据来源。 ## 验证 本地验收命令: ```bash corepack pnpm@10.33.0 exec vitest run apps/api/src/modules/dashboard/dashboard.service.spec.ts corepack pnpm@10.33.0 typecheck corepack pnpm@10.33.0 lint corepack pnpm@10.33.0 build ``` ## 回滚 代码级回滚: 1. 从 `apps/api/src/modules/app.module.ts` 移除 `DashboardModule`。 2. 删除 `apps/api/src/modules/dashboard/`。 3. 删除本 Runbook。 4. 重新执行 `corepack pnpm@10.33.0 build`。 S26 未执行数据库迁移、服务器写操作或真实数据写入,因此没有远端数据回滚点。