14 KiB
14 KiB
系统使用统计表设计
1. 设计目标
基于《系统使用统计最终需求》和《系统使用统计接口设计》,设计一套可落地的数据库方案,用于支持以下统计场景:
- 登录统计
- 文档上传统计
- 文档评查统计
- 按用户、部门、地区、文档大类、文档类型、入口模块进行动态汇总
- 支持时间范围查询、排行榜、趋势图与明细导出
本次设计遵循两个原则:
- 能复用现有业务表的地方尽量复用
- 只为现有表无法满足的统计能力补最小新增表结构
2. 总体设计思路
统计数据来源分为两类:
- 现有业务事实表
- 新增统计事件表
其中:
- 上传、评查相关统计,尽量直接复用现有业务表
- 登录统计由于当前没有稳定入库明细,需要新增登录事件表
- 为了提升用户管理页的查询效率,建议给
sso_users增加最近登录时间字段
3. 现有可复用表
3.1 用户表 sso_users
用途:
- 用户基础信息来源
- 部门、地区、组织维度来源
- 最近登录时间展示
当前已使用字段:
idsubusernamenick_namephone_numberemailou_idou_nameareatenant_namedep_namedep_short_namestatusdeleted_at
代码参考:
fastapi_modules/fastapi_leaudit/services/impl/authServiceImpl.py:36fastapi_modules/fastapi_leaudit/services/impl/rbacAdminServiceImpl.py:374
3.2 文档主表 leaudit_documents
用途:
- 文档主记录
- 文档类型、地区、版本、处理状态来源
主要字段:
idtype_idgroup_idregionprocessing_statuscurrent_run_idversion_group_keyversion_nois_latest_versioncreated_atupdated_atdeleted_at
代码参考:
fastapi_modules/fastapi_leaudit/models/leauditDocument.py:19
3.3 文档文件表 leaudit_document_files
用途:
- 上传主文件统计
- 上传附件统计
- 上传人、上传时间明细来源
主要字段:
iddocument_idfile_rolefile_namefile_extmime_typefile_sizeoss_urlis_activecreated_bycreated_at
口径建议:
- 主文件上传:
file_role = 'primary' - 附件上传:
file_role = 'attachment'
代码参考:
fastapi_modules/fastapi_leaudit/models/leauditDocumentFile.py:15fastapi_modules/fastapi_leaudit/services/impl/documentServiceImpl.py:224fastapi_modules/fastapi_leaudit/services/impl/documentServiceImpl.py:889
3.4 评查运行表 leaudit_audit_runs
用途:
- 评查发起次数
- 评查完成次数
- 评查失败次数
- 评查时间趋势
- 评查状态与结果明细
主要字段:
iddocument_iddocument_file_idrun_notrigger_sourcetrigger_user_idstatusphaserule_set_idrule_version_idresult_statustotal_scorepassed_countfailed_countskipped_countstarted_atfinished_atcreated_atupdated_at
现状说明:
- 表结构已预留
trigger_user_id - 但当前代码创建 run 时尚未写入该字段
- 统计功能上线前建议补齐该字段写入逻辑
代码参考:
fastapi_modules/fastapi_leaudit/models/leauditAuditRun.py:16fastapi_modules/fastapi_leaudit/services/impl/auditServiceImpl.py:203
3.5 评查指标表 leaudit_run_metrics
用途:
- 评查页数
- 评查耗时
- 规则数量等运行指标
主要字段:
run_idocr_secondsnormalize_secondsextract_secondsevaluate_secondsrescue_secondstotal_secondspage_countsub_document_countfield_countrule_countllm_call_countvlm_call_countrescue_rule_countartifact_count
代码参考:
fastapi_modules/fastapi_leaudit/leaudit_bridge/storage_adapter.py:260
3.6 文档类型表 leaudit_document_types
用途:
- 文档类型维度统计
- 入口模块归属
建议依赖字段:
idcodenameentry_module_idis_enabledsort_order
3.7 入口模块表 leaudit_entry_modules
用途:
- 入口模块维度统计
- 首页/业务模块使用分析
建议依赖字段:
idnamepathsort_orderis_enabled
4. 建议调整的现有表
4.1 为 sso_users 增加最近登录时间字段
建议新增字段
ALTER TABLE sso_users
ADD COLUMN IF NOT EXISTS last_login_at TIMESTAMPTZ NULL;
字段说明
| 字段 | 类型 | 允许空 | 说明 |
|---|---|---|---|
last_login_at |
TIMESTAMPTZ |
是 | 最近一次登录成功时间 |
用途
- 用户列表展示“最近登录时间”
- 后台快速判断用户活跃情况
- 避免每次都扫登录事件表取最大时间
更新规则
- 登录成功:更新
last_login_at - 登录失败:不更新
5. 新增表设计
5.1 登录事件表 usage_login_events
设计目的
当前系统缺少结构化登录明细表,无法稳定支撑:
- 登录次数
- 登录用户数
- 按部门登录统计
- 按地区登录统计
- 登录趋势图
- 最近登录明细导出
因此建议新增登录事件表。
建表建议
CREATE TABLE IF NOT EXISTS usage_login_events (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NULL,
sub VARCHAR(128) NULL,
username_snapshot VARCHAR(128) NULL,
nick_name_snapshot VARCHAR(128) NULL,
department_name_snapshot VARCHAR(255) NULL,
ou_id_snapshot VARCHAR(128) NULL,
ou_name_snapshot VARCHAR(255) NULL,
area_snapshot VARCHAR(64) NULL,
login_time TIMESTAMPTZ NOT NULL DEFAULT NOW(),
login_result VARCHAR(16) NOT NULL,
login_type VARCHAR(32) NOT NULL,
ip_address VARCHAR(64) NULL,
user_agent VARCHAR(1024) NULL,
client_type VARCHAR(32) NULL,
token_jti VARCHAR(128) NULL,
failure_reason VARCHAR(255) NULL,
extra JSONB NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
id |
BIGSERIAL |
主键 |
user_id |
BIGINT |
用户 ID,失败登录时可为空 |
sub |
VARCHAR(128) |
登录标识,兼容账号字段 |
username_snapshot |
VARCHAR(128) |
登录时用户名快照 |
nick_name_snapshot |
VARCHAR(128) |
登录时姓名快照 |
department_name_snapshot |
VARCHAR(255) |
登录时部门快照 |
ou_id_snapshot |
VARCHAR(128) |
登录时组织 ID 快照 |
ou_name_snapshot |
VARCHAR(255) |
登录时组织名称快照 |
area_snapshot |
VARCHAR(64) |
登录时地区快照 |
login_time |
TIMESTAMPTZ |
登录时间 |
login_result |
VARCHAR(16) |
success / failed |
login_type |
VARCHAR(32) |
password / oauth |
ip_address |
VARCHAR(64) |
登录来源 IP |
user_agent |
VARCHAR(1024) |
浏览器/终端标识 |
client_type |
VARCHAR(32) |
pc / mobile / other |
token_jti |
VARCHAR(128) |
成功登录后的 token jti,可选 |
failure_reason |
VARCHAR(255) |
失败原因 |
extra |
JSONB |
扩展字段 |
created_at |
TIMESTAMPTZ |
记录创建时间 |
索引建议
CREATE INDEX IF NOT EXISTS idx_usage_login_events_login_time
ON usage_login_events(login_time DESC);
CREATE INDEX IF NOT EXISTS idx_usage_login_events_user_id
ON usage_login_events(user_id, login_time DESC);
CREATE INDEX IF NOT EXISTS idx_usage_login_events_department
ON usage_login_events(department_name_snapshot, login_time DESC);
CREATE INDEX IF NOT EXISTS idx_usage_login_events_area
ON usage_login_events(area_snapshot, login_time DESC);
CREATE INDEX IF NOT EXISTS idx_usage_login_events_result
ON usage_login_events(login_result, login_time DESC);
统计口径建议
- 登录次数:仅统计
login_result = 'success' - 登录失败次数:统计
login_result = 'failed' - 最近登录时间:按用户取最后一次成功登录时间
5.2 文档大类映射表 usage_document_category_mappings(可选但强烈建议)
设计目的
需求中明确要求:
- 不写死“合同类”“案卷类”
- 后续新增文档大类、文档类型后可自动纳入统计
如果当前系统已经有稳定的一级文档大类实体,可直接复用; 如果没有一张适合统计使用的稳定“大类表”,建议新增一张统计映射表。
建表建议
CREATE TABLE IF NOT EXISTS usage_document_category_mappings (
id BIGSERIAL PRIMARY KEY,
category_code VARCHAR(64) NOT NULL,
category_name VARCHAR(128) NOT NULL,
document_type_id BIGINT NOT NULL,
entry_module_id BIGINT NULL,
is_enabled BOOLEAN NOT NULL DEFAULT TRUE,
sort_order INTEGER NOT NULL DEFAULT 0,
created_by BIGINT NULL,
updated_by BIGINT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ NULL
);
字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
id |
BIGSERIAL |
主键 |
category_code |
VARCHAR(64) |
统计大类编码 |
category_name |
VARCHAR(128) |
统计大类名称 |
document_type_id |
BIGINT |
关联文档类型 ID |
entry_module_id |
BIGINT |
可选,关联入口模块 |
is_enabled |
BOOLEAN |
是否启用 |
sort_order |
INTEGER |
排序 |
created_by |
BIGINT |
创建人 |
updated_by |
BIGINT |
更新人 |
created_at |
TIMESTAMPTZ |
创建时间 |
updated_at |
TIMESTAMPTZ |
更新时间 |
deleted_at |
TIMESTAMPTZ |
软删除时间 |
约束与索引建议
CREATE UNIQUE INDEX IF NOT EXISTS uq_usage_document_category_type
ON usage_document_category_mappings(document_type_id)
WHERE deleted_at IS NULL;
CREATE INDEX IF NOT EXISTS idx_usage_document_category_code
ON usage_document_category_mappings(category_code, is_enabled);
CREATE INDEX IF NOT EXISTS idx_usage_document_category_module
ON usage_document_category_mappings(entry_module_id, is_enabled);
说明
- 一种文档类型只归属一个统计大类
- 若后续系统已有成熟的一级文档大类表,可取消本表,直接复用业务表
6. 查询口径与表关系建议
6.1 登录统计
来源:
usage_login_eventssso_users.last_login_at
用途:
- 登录次数
- 登录用户数
- 最近登录时间
- 按部门、地区统计登录情况
6.2 上传统计
来源:
leaudit_document_filesleaudit_documentssso_usersleaudit_document_typesleaudit_entry_modulesusage_document_category_mappings(若启用)
口径:
- 主文件上传:
leaudit_document_files.file_role = 'primary' - 附件上传:
leaudit_document_files.file_role = 'attachment'
6.3 评查统计
来源:
leaudit_audit_runsleaudit_documentsleaudit_document_typesleaudit_entry_modulesusage_document_category_mappings(若启用)
口径:
- 发起评查次数:
leaudit_audit_runs记录数 - 完成评查次数:
status = 'completed' - 失败评查次数:
status = 'failed'
6.4 地区统计
支持两种口径:
- 用户地区口径
- 登录:取
usage_login_events.area_snapshot - 上传:取上传人
sso_users.area - 评查:优先取触发人地区
- 登录:取
- 文档地区口径
- 上传:取
leaudit_documents.region - 评查:取
leaudit_documents.region
- 上传:取
7. 一期是否需要聚合表
7.1 一期建议
一期先不新增日汇总聚合表,先使用:
- 明细事实表 + SQL 聚合
原因:
- 功能验证阶段,需求还可能变
- 统计范围目前只有登录、上传、评查三类,复杂度可控
- 先把口径跑通,比过早做聚合更重要
7.2 二期建议
若后续数据量变大,再补以下日汇总表:
usage_user_daily_statsusage_department_daily_statsusage_area_daily_statsusage_document_category_daily_statsusage_entry_module_daily_stats
8. 配套代码改造建议
8.1 登录成功时
需要做两件事:
- 写入
usage_login_events - 更新
sso_users.last_login_at
8.2 登录失败时
建议:
- 写入
usage_login_events - 不更新
sso_users.last_login_at
8.3 触发评查时
建议补齐:
leaudit_audit_runs.trigger_user_id
当前表已存在该字段,但创建 run 时未写入,需要补逻辑。
9. 推荐 SQL 变更清单
9.1 为 sso_users 增加最近登录时间
ALTER TABLE sso_users
ADD COLUMN IF NOT EXISTS last_login_at TIMESTAMPTZ NULL;
9.2 新增登录事件表
CREATE TABLE IF NOT EXISTS usage_login_events (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NULL,
sub VARCHAR(128) NULL,
username_snapshot VARCHAR(128) NULL,
nick_name_snapshot VARCHAR(128) NULL,
department_name_snapshot VARCHAR(255) NULL,
ou_id_snapshot VARCHAR(128) NULL,
ou_name_snapshot VARCHAR(255) NULL,
area_snapshot VARCHAR(64) NULL,
login_time TIMESTAMPTZ NOT NULL DEFAULT NOW(),
login_result VARCHAR(16) NOT NULL,
login_type VARCHAR(32) NOT NULL,
ip_address VARCHAR(64) NULL,
user_agent VARCHAR(1024) NULL,
client_type VARCHAR(32) NULL,
token_jti VARCHAR(128) NULL,
failure_reason VARCHAR(255) NULL,
extra JSONB NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
9.3 新增登录事件索引
CREATE INDEX IF NOT EXISTS idx_usage_login_events_login_time
ON usage_login_events(login_time DESC);
CREATE INDEX IF NOT EXISTS idx_usage_login_events_user_id
ON usage_login_events(user_id, login_time DESC);
CREATE INDEX IF NOT EXISTS idx_usage_login_events_department
ON usage_login_events(department_name_snapshot, login_time DESC);
CREATE INDEX IF NOT EXISTS idx_usage_login_events_area
ON usage_login_events(area_snapshot, login_time DESC);
CREATE INDEX IF NOT EXISTS idx_usage_login_events_result
ON usage_login_events(login_result, login_time DESC);
9.4 新增统计大类映射表(可选)
CREATE TABLE IF NOT EXISTS usage_document_category_mappings (
id BIGSERIAL PRIMARY KEY,
category_code VARCHAR(64) NOT NULL,
category_name VARCHAR(128) NOT NULL,
document_type_id BIGINT NOT NULL,
entry_module_id BIGINT NULL,
is_enabled BOOLEAN NOT NULL DEFAULT TRUE,
sort_order INTEGER NOT NULL DEFAULT 0,
created_by BIGINT NULL,
updated_by BIGINT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ NULL
);
10. 一期最终建议
一期最小可落地表设计建议如下:
必须做:
sso_users.last_login_atusage_login_events- 补齐
leaudit_audit_runs.trigger_user_id写入逻辑
建议做:
usage_document_category_mappings
可后置:
- 各类日汇总聚合表
- 复杂会话表
- 全量行为审计表