Skip to content
bitzorcas
中EN

Concept

Reporting 报表数据集市

以当前源码为准说明 Reporting 的 QUERY 查询、异步导出、权限与 DataScope、工单事件投影、两张 owner-local Mart 表,以及仍需处理的数据生产和恢复缺口。

Last updated

Reporting 是面向读取的投影模块,不是通用 BI 引擎。模块拥有两张去规范化 Mart 表:Rpt_TicketSummary 保存工单当前快照,Rpt_AuditActivityDaily 保存租户、日期、用户和动作四个维度的日计数。公开业务面包括两条 RFC 10008 QUERY 查询和一条工单汇总异步导出提交端点。

1. 已实现能力

能力当前实现
工单汇总查询QUERY /api/reports/tickets/summary,POST 降级路径为 /api/reports/tickets/summary/_query
审计活动日报查询QUERY /api/reports/activities/daily,POST 降级路径为 /api/reports/activities/daily/_query
工单汇总导出POST /api/reports/tickets/summary/export,仅接受 csv 或 excel,始终异步
权限查询使用 .read,导出使用 .export
Feature运行时把资源模块 reporting 映射到 platform.reporting
数据范围Handler 再次执行授权决策,并且只接受 DataScope.Tenant
工单投影订阅 opened、assigned、started、resolved、closed、reopened 六个 topic
存储两张 owner-local Mart 表,通过 IEntitySet<T> 和 Query Shape 适配 ORM
无持久化宿主IReportingMartStore 使用 unavailable adapter 失败关闭,不返回伪空数据

当前没有报表设计器、图表或仪表盘引擎、跨租户分析、审计日报聚合任务、投影 checkpoint、inbox、按版本重放、对账、影子表重建、新鲜度 API 和 Mart 生命周期清理。

2. 核心流程

未实现

Ticket 聚合
六类 IIntegrationEvent

源生成 IntegrationTopic registry
topic + 业务字段

事务 CAP Outbox
eventId + eventType + 业务字段

TicketReportingEventConsumer

Rpt_TicketSummary

审计日报聚合 writer
当前不存在

Rpt_AuditActivityDaily

QUERY /api/reports/...

异步 Export Builder

platform.reporting + 精确权限
+ DataScope.Tenant

事件发布不是由业务 Handler 手工构造 Ticket*IntegrationEvent。Ticket 聚合抛出的领域事件同时实现 IIntegrationEvent 并带 [IntegrationTopic];源生成器为事件类型生成 topic 与标量 payload 映射;命令事务在提交前把消息写入 CAP Outbox。Reporting 中同名的 Ticket*IntegrationEvent 是 consumer 绑定模型。

3. 查询协议

列表和分页读取不提供 GET 别名。客户端应优先发送带 JSON 正文的 QUERY;代理或工具链不支持 QUERY 时,发送同正文的 POST 降级请求。

报表请求字段响应
工单汇总status?、from?、to?、pageIndex=1、pageSize=20PagedResult<TicketSummaryRow>
审计日报必填 from、to,以及 pageIndex=1、pageSize=20PagedResult<AuditActivityDailyRow>
查询 Closed 工单汇总
QUERY /api/reports/tickets/summary HTTP/1.1
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9
Content-Type: application/json
Accept: application/json
{
"status": "Closed",
"from": "2026-07-01T00:00:00Z",
"to": "2026-07-31T23:59:59Z",
"pageIndex": 1,
"pageSize": 50
}

兼容请求只改变方法和路径:

不支持 QUERY 时使用 POST 降级
POST /api/reports/tickets/summary/_query HTTP/1.1
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9
Content-Type: application/json
{"status":"Closed","from":"2026-07-01T00:00:00Z","to":"2026-07-31T23:59:59Z","pageIndex":1,"pageSize":50}

请求规则如下:

  • pageIndex 必须大于等于 1;pageSize 必须为 1–1000;
  • status 会 trim,最长 64 个字符,不能包含控制字符;当前不校验它是否属于 TicketStatus;
  • from 不得晚于 to,跨度不得超过 366 天;
  • From/To 都是闭区间,工单按 OpenedAt 过滤,审计日报按 ActivityDate 过滤;
  • 工单范围使用 DateTimeOffset,但不会强制转成 UTC;审计范围使用 DateTime,协议没有进一步约束 Kind。

4. 权限、Feature 与数据范围

三条业务入口使用以下稳定权限:

入口资源与动作派生权限
工单汇总查询reporting/ticket-summary + Readreporting.ticket-summary.read
审计日报查询reporting/activity + Readreporting.activity.read
工单汇总导出reporting/ticket-summary + Exportreporting.ticket-summary.export

统一 Feature evaluator 把 reporting 映射到中央 entitlement platform.reporting;禁用时返回 Deny。Reporting owner 另行贡献了 reporting.mart Feature 定义,但查询授权链并不读取这个代码。部署和套餐配置当前应以 platform.reporting 为运行时事实;两个 Feature 码的重复含义仍需在源码中收敛。

查询与导出 Handler 只接受已认证的真实用户或委托用户,要求有效的正数 UserId 和 TenantId。随后再次调用 IAuthorizationDecisionService,只有 IsAllowed=true 且 DataScope == Tenant 才继续。Own、Department、Office 等较窄范围会失败关闭,而不是转换成行级谓词。

这套规则避免了“先查全租户再在内存裁剪”,代价是只有租户级数据范围用户能使用报表。公开行仍含 Subject、RequesterId、AssigneeId 或逐用户活动计数;当前没有字段掩码。

5. 工单汇总异步导出

提交工单汇总导出
POST /api/reports/tickets/summary/export HTTP/1.1
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9
Content-Type: application/json
{
"status": "Closed",
"from": "2026-07-01T00:00:00Z",
"to": "2026-07-31T23:59:59Z",
"format": "csv",
"idempotencyKey": "reporting-202607-closed-v1"
}

提交成功返回 { "jobId": "..." }。实现约束包括:

  • 幂等键 trim 后必须为 8–128 个无控制字符的文本;筛选与格式进入请求指纹;
  • Builder Key 固定为 reporting.ticket-summary,列集合由服务端决定;
  • 只允许 ExportScope.All,不接受客户端 CheckedIds;
  • ForceAsync=true,原始 Mart 批读默认 5000、最大 100000,授权扫描批次为 1000;
  • Builder 对每个 Ticket 调用 Tickets owner 的 ITicketResourceAuthorizationReader,撤销权限后后续批次不再输出该行;
  • 重试时重新检查 .export 和租户级 DataScope;
  • 公开任务参数只显示规范化后的 status/from/to,不回显原始参数 JSON。

任务历史、状态、下载、取消和重试由平台 Export Center 的 /api/export/... 端点提供,不属于 Reporting 专用路由。

6. 工单投影现状

Topic投影变化
ticket.opened创建 New,写 Requester、Subject、Priority、OpenedAt
ticket.assigned写 AssigneeId,并改为 Assigned
ticket.started改为 InProgress
ticket.resolved改为 Resolved
ticket.closed改为 Closed,并写 ClosedAt
ticket.reopened改为 Reopened,并清空 ClosedAt

consumer 对直接重复的最后一个 EventId 跳过,对 OccurredAt < LastUpdatedAt 的非 opened 事件跳过;缺少 opened 前置行、Mart 读写失败或其他处理异常会重新抛出,让 CAP 执行重试。现有集成测试直接构造六种 consumer DTO,验证完整状态序列、直接重复和陈旧 closed。

仍有三个关键边界:

  1. Ticket.Open 直接 Raise(new TicketOpened(ticket.Id, ...)),此时 Id 为 "0";仓储稍后才分配最终 ID。opened 与后续事件无法按同一 TicketId 汇合。
  2. Mart 只保存最后一个 EventId,能处理 A,A,不能识别 A,B,A;事件也没有聚合版本或序号。
  3. Upsert 是先查后写,没有 compare-and-set;相同时间戳和并发消费仍可能由后提交者覆盖。

详见工单事件投影与乱序一致性。

7. 审计日报现状

Rpt_AuditActivityDaily 与 UpsertAuditActivityDailyAsync 已实现,但生产源码没有 consumer、JobHost executor、SQL 聚合器、checkpoint 或回补命令。现有 Handler 测试用 substitute 返回手工行,只验证映射。

ActivityDate 是完整 DateTime,Store 不规范到 UTC midnight;Upsert 覆盖完整 ActivityCount,不是原子递增。同一业务日可能因时分秒或 Kind 不同形成多个唯一键。详见审计活动日报与聚合任务。

8. Mart 查询与一致性

两条标准列表都通过 Query Shape 执行,并显式增加可信 TenantId 谓词:

  • 工单按 (OpenedAt desc, TicketId desc) 稳定排序;
  • 审计日报按 (ActivityDate desc, UserId desc, ActionType desc) 稳定排序;
  • From/To 都是闭区间;
  • 公开 DTO 不包含 Mart 的 LastEventId 或 LastUpdatedAt,调用方无法判断 watermark;
  • 两类 Upsert 都采用 check-then-insert/update,没有数据库原子 Upsert 或版本条件。

详见Mart 模型、分页与数据范围。

9. 测试证据与生产缺口

现有证据覆盖 Query Handler 规则、Read 权限、Tenant DataScope、Feature 映射、导出提交与逐行 owner 复核、六事件 consumer 状态序列、Infrastructure ORM 中立性、Mart 元数据,以及 API Shell unavailable adapter。

仍缺少:真实 Ticket 创建到 Outbox 再到 CAP 绑定的端到端测试、opened 最终 ID 守卫、ReportingMartStore 双 ORM 行为套件、版本/inbox/gap 语义、并发 Upsert、审计日报生产任务、真实 HTTP 授权矩阵、投影 watermark、对账、重建演练和生产规模查询计划。

生产验收清单见测试、可观测性、重建与 GA。

10. 源码导航

主题源码入口
查询src/Platform/Reporting/...Application/Queries
导出提交与 Builder...Application/Commands/ExportTicketSummary、TicketSummaryExportBuilder.cs
请求与 DataScope 规则...Application/ReportingApplicationRules.cs
权限与 owner FeatureReportingConstants.cs、ReportingFeatures.cs
运行时 Feature 映射src/Framework/BitzOrcas.Application/Authorization/Feature/FeaturePolicyEvaluator.cs
工单 consumer...Reporting.Infrastructure/TicketReportingEventConsumer.cs
Mart Store 与 Query Shape...Reporting.Infrastructure/ReportingMartStore.cs
工单发布事件src/Platform/Tickets/...Contracts/Tickets/Events/Ticket*.cs
审计日报行...Reporting.Infrastructure/Persistence/RptAuditActivityDailyRecord.cs

返回平台模块目录 · Tickets · Auditing · Authorization

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%