feat(shared): A5 审计契约、动作目录与配置

新增审计动作目录(10 分类 / 54 动作)、前后值 diff 纯函数、列表 / 详情 / 导出 Zod 契约;system_configs 增加 audit 分组与保留期 / 导出上限 / 日志平台地址 3 项配置。
This commit is contained in:
Stev_Wang committed 2026-11-04 16:26:03 +08:00
1 parent a5a2914214
commit 408dc5e81b
9 files changed
+1211

No files matched your search

@@ -13,6 +13,7 @@ export const SYSTEM_CONFIG_GROUP_KEYS = [
'notify',
'limits',
'threshold',
'audit',
] as const;
export type SystemConfigGroupKey = (typeof SYSTEM_CONFIG_GROUP_KEYS)[number];
@@ -44,6 +45,12 @@ export const SYSTEM_CONFIG_GROUPS: readonly {
description: '爆量判定、审核超时与质量告警',
sortOrder: 60,
},
{
key: 'audit',
name: '审计与日志',
description: '审计保留期、导出上限与运行日志平台入口',
sortOrder: 70,
},
];
export type SystemConfigInputType = 'text' | 'number' | 'boolean' | 'pattern';
@@ -451,6 +458,52 @@ export const SYSTEM_CONFIG_DEFINITIONS: readonly SystemConfigDefinition[] = [
public: false,
sortOrder: 260,
},
// 审计与日志(A5)
{
key: 'audit.retention_months',
group: 'audit',
label: '审计日志保留期',
description: '审计日志在线保留的最短月数;归档任务按该值执行(QT-10 最终值待确认)',
impact:
'影响审计可检索范围与归档策略;PRD Q-08 要求 ≥ 12 个月,归档只做只读搬迁、不删除审计数据',
type: 'number',
defaultValue: 12,
unit: '个月',
min: 12,
max: 60,
editable: true,
public: false,
sortOrder: 270,
},
{
key: 'audit.export_max_rows',
group: 'audit',
label: '审计导出单次行数上限',
description: '单次异步导出的最大行数,超出部分截断并在导出任务上标记 truncated',
impact: '影响导出文件体积与导出耗时;截断后需缩小筛选条件重新导出',
type: 'number',
defaultValue: 50000,
unit: '条',
min: 1000,
max: 200000,
editable: true,
public: true,
sortOrder: 280,
},
{
key: 'audit.logs_platform_url',
group: 'audit',
label: '运行日志平台地址',
description: '后台「运行日志」入口跳转的 Grafana / Loki 地址;只存链接,不含任何密钥',
impact: '仅影响前端跳转链接;运行日志不入业务库(工程规范 08)',
type: 'text',
defaultValue: '',
maxLength: 500,
editable: true,
public: true,
sortOrder: 290,
},
];
const DEFINITION_MAP: ReadonlyMap<string, SystemConfigDefinition> = new Map(
@@ -518,6 +571,10 @@ export function validateSystemConfigValue(
}
const text = value.trim();
if (text.length === 0) {
// 允许默认值为空串的文本项(如 audit.logs_platform_url:未配置日志平台时为空)
if (definition.defaultValue === '') {
return { ok: true, value: '' };
}
return { ok: false, message: '配置值不能为空' };
}
if (definition.type === 'pattern') {