# 审计系统 — 使用指南

> **module**: audit-system
> **doc_type**: UserGuide
> **status**: Active
> **owner**: FFOA Team
> **audience**: 审计员 / 财务 / 安全 / 系统管理员 + 后端工程师
> **upstream_docs**: 01-prd.md, 03-architecture.md, 06-data-model.md, 07-api.md, 12-integration-guide.md
> **last_verified**: 2026-05-11

---

## 目录

1. [系统概览](#1-系统概览)
2. [核心概念](#2-核心概念)
3. [角色与可见范围](#3-角色与可见范围)
4. [Part 1 — 给审计员：日常查询与排查](#4-part-1--给审计员日常查询与排查)
5. [Part 2 — 给开发：如何让操作被审计](#5-part-2--给开发如何让操作被审计)
6. [Part 3 — 完整性校验与合规](#6-part-3--完整性校验与合规)
7. [常见问题（FAQ）](#7-常见问题-faq)

---

## 1. 系统概览

审计系统记录所有重要业务操作的 **5W1H** —— Who / What / When / Where / Why / How —— 通过 SHA-256 哈希链防止日志被篡改，满足 SOX、GDPR 等合规要求。

**核心特性**：

- **自动埋点**：开发只需在方法上加 `@Auditable()` 装饰器，无需手写日志代码
- **5W1H 完整**：操作人 / 操作内容 / 毫秒级时间戳 / IP + 设备 / 原因 / 触发源（API/UI/CLI/系统）
- **防篡改**：哈希链 + PostgreSQL 触发器禁 `UPDATE` / `DELETE`，单条记录可一键校验
- **分级留存**：财务操作（`@Financial`）保留 7 年；敏感操作（`@Sensitive`）独立查询入口
- **合规报表**：自动生成 SOX / GDPR 合规报表
- **可追踪**：每次 HTTP 请求带 `traceId`，把同一操作引发的多条日志串起来

**与日志系统的边界**：

| 数据 | 归属 |
|------|------|
| 业务操作（创建 / 更新 / 删除 / 审批 / 财务） | **审计系统** |
| 权限变更、密码修改、登录失败 | **审计系统** |
| HTTP 请求 / 响应、运行日志、错误堆栈、性能埋点 | 日志系统 |

> 简单的判断标准：**有业务意义、需要事后向人解释"是谁做的、为什么"** 的事件 → 审计；纯技术日志 → 日志系统。

---

## 2. 核心概念

| 概念 | 说明 |
|------|------|
| **5W1H** | 一条审计记录的完整要素：Who（操作人）/ What（操作内容）/ When（毫秒时间戳）/ Where（IP + 设备 + Region）/ Why（业务原因）/ How（API / UI / CLI / 系统触发） |
| **@Auditable** | 后端方法装饰器，标在 Service 方法上即自动记录该方法调用为审计事件（详见 [12-integration-guide.md](12-integration-guide.md)） |
| **@Sensitive** | 敏感操作标记，归入敏感日志专表，对应前端"敏感操作"页 |
| **@Financial** | 财务操作标记，触发 7 年长期留存策略，对应前端"财务审计"页 |
| **哈希链** | 每条日志 `hash = SHA256(prevHash + payload)`，形成链式签名；任一条被改将导致后续所有校验失败 |
| **数字签名** | HMAC-SHA256，对哈希再做一次签名，校验密钥在 KMS / 环境变量中托管 |
| **traceId** | 请求级追踪 ID，由 HTTP 拦截器注入；同一次操作产生的多条日志共享同一 `traceId` |
| **businessKey** | 业务单号字段（审批 / 财务 / 表单单号）；详情页可一键跳回原单 |
| **DB 触发器** | PostgreSQL 触发器阻止对审计表的 `UPDATE` / `DELETE`，应用层无法绕过 |

---

## 3. 角色与可见范围

| 角色 | 可见范围 | 说明 |
|------|----------|------|
| **Administrator**（系统管理员） | 全部 | 跨模块管理；可读全部审计日志（含财务、敏感），可执行完整性校验 |
| **AuditAdmin**（审计管理员） | 全部 | 专责审计的角色，与系统管理员同等查看权 |
| **FinanceAuditor**（财务审计员） | 财务日志 | "财务审计"页可见，覆盖金额 / 合同 / 付款类操作 |
| **SensitiveAuditor**（安全审计员） | 敏感日志 | "敏感操作"页可见，覆盖权限变更 / 数据导出 / 超管操作 |
| **业务用户** | 本人操作 | 通过 `audit:read` 权限控制，仅可看自己产生的审计记录 |

**关键权限点**：

| 权限码 | 控制 |
|------|------|
| `audit:read` | 读取审计日志（基础权限） |
| `audit:read:financial` | 读取财务审计日志 |
| `audit:read:sensitive` | 读取敏感操作日志 |
| `audit:statistics` | 查看统计分析页 |
| `audit:verify` | 执行完整性校验 |
| `audit:export` | 导出审计日志（CSV / Excel / JSON） |

---

## 4. Part 1 — 给审计员：日常查询与排查

### 4.1 入口总览

| 页面 | 路由 | 用途 |
|------|------|------|
| 审计概览 | `/audit` | 近 7 天操作总量、失败趋势、模块分布、最近活动 |
| 审计日志列表 | `/audit/logs` | 按时间倒序浏览全部审计，支持模块 / 类型筛选 |
| 高级搜索 | `/audit/search` | 按用户 / 实体 / 时间 / 业务单号精确检索 |
| 完整性验证 | `/audit/integrity` | 校验日志哈希链是否被篡改 |
| 财务审计 | `/audit/financial` | 金额 / 合同 / 付款类操作专用查询 |
| 敏感操作 | `/audit/sensitive` | 权限变更 / 超管操作 / 数据导出监控 |
| 统计分析 | `/audit/statistics` | 操作类型 / 趋势 / 模块维度统计图表 |
| 使用说明 | `/audit/help` | 本指南的前端版（快速参考） |

### 4.2 日常排查流程

**场景 A — 「某员工 X 月 Y 日做了什么」**

1. 进入"高级搜索"
2. Who = 选员工 / What = 留空 / When = 选日期范围
3. 提交 → 时间倒序展示当天该员工所有操作

**场景 B — 「这条审批单为何被拒？」**

1. 进入"高级搜索"
2. businessKey = 输入审批单号
3. 看流程上每一步的操作人 / 时间 / 备注
4. 详情页点 "diff" 看每次审批节点字段变化

**场景 C — 「财务怀疑某笔付款被篡改」**

1. 进入"财务审计"页
2. 按时间范围 + 金额区间筛选
3. 找到目标记录 → 详情页点 **完整性校验** 按钮
4. 校验返回 ✓ 表示未被篡改；✗ 表示存在篡改，立刻向系统管理员上报

**场景 D — 「某资源突然消失，是谁删的？」**

1. 进入"高级搜索"
2. 实体类型 = 选资源类型 / 实体 ID = 填资源 ID / 操作类型 = `DELETE`
3. 时间范围圈定到失踪时段
4. 通过 oldValue 还原删除前的完整数据

### 4.3 详情页能看到什么

每条审计记录详情页包含：

- **5W1H 卡**：操作人（姓名 + 工号 + 部门）、毫秒时间戳、设备（型号 + OS + 浏览器）、IP（含地理位置）、操作原因、来源
- **数据变更对比**：左右双栏 diff，新增字段标绿、删除标红、修改标黄；未变字段自动折叠
- **业务单号链接**：`businessKey` 可点击跳回原审批单 / 财务单 / 表单页
- **完整性校验按钮**：调用单条哈希校验 API（F4.5），返回 ✓ / ✗
- **traceId 关联**：一键看同一请求产生的其他审计 / 日志记录

### 4.4 导出

- 列表页 / 财务页 / 敏感页右上角都有"导出"按钮
- 支持 CSV / Excel / JSON 三种格式
- 导出动作本身会留下审计记录（防止内部数据外泄无证据）

---

## 5. Part 2 — 给开发：如何让操作被审计

> 详细的接入步骤、字段定义、错误处理详见 [12-integration-guide.md](12-integration-guide.md)，本节是日常使用速查。

### 5.1 一般业务操作

在 Service 方法上加 `@Auditable()`：

```ts
@Auditable({
  action: 'CREATE',
  entity: 'RobotUnit',
  description: '创建机器人',
})
async createRobot(dto: CreateRobotDto) {
  // ...
}
```

参数 `entity` / `action` 会落到 5W1H 的 What 字段，HTTP 上下文（用户 / IP / 设备）由拦截器自动注入，无需手写。

### 5.2 敏感操作

涉及权限 / 超管 / 数据导出，叠加 `@Sensitive()`：

```ts
@Auditable({ action: 'GRANT_ROLE', entity: 'User' })
@Sensitive({ reason: '角色授予会扩大权限范围' })
async grantRole(userId: string, roleCode: string) { ... }
```

写入 `audit_log` 之外，还会写入敏感日志专表，在"敏感操作"页直接可见。

### 5.3 财务操作

涉及金额 / 合同 / 付款，叠加 `@Financial()` 触发 7 年留存：

```ts
@Auditable({ action: 'APPROVE_PAYMENT', entity: 'Invoice' })
@Financial({ amountField: 'amount', currency: 'USD' })
async approvePayment(invoiceId: string, amount: number) { ... }
```

### 5.4 数据变更快照

写操作（UPDATE / DELETE）需要传入 `oldValue` / `newValue`，详情页才能渲染 diff。推荐用 Service 内部包装方法在事务里读旧值再调用 `auditService.log()`。

### 5.5 手动记录（特殊场景）

定时任务 / 系统触发的事件不走 HTTP，需要手动调：

```ts
await this.auditService.log({
  action: 'AUTO_CANCEL',
  entity: 'Order',
  entityId: order.id,
  reason: '订单超时自动取消',
  source: 'SYSTEM',
});
```

### 5.6 接入校验清单

- [ ] Service 方法已加装饰器
- [ ] `entity` / `action` 与 [01-prd.md §审计范围清单](01-prd.md) 列出的口径一致
- [ ] 写操作传了 `oldValue` / `newValue`
- [ ] 财务相关已加 `@Financial`
- [ ] 涉及权限 / 超管 / 导出已加 `@Sensitive`
- [ ] 集成测试覆盖：调用方法后能在 `audit_log` 查到记录

---

## 6. Part 3 — 完整性校验与合规

### 6.1 三层防篡改

1. **哈希链**：每条 `hash = SHA256(prevHash + canonicalPayload)`
2. **数字签名**：HMAC-SHA256 对哈希再签一次，密钥独立管理
3. **DB 触发器**：PostgreSQL 触发器阻止对审计表的 `UPDATE` / `DELETE`，即使有 DB 写权限也无法静默修改

### 6.2 校验方式

| 校验方式 | 入口 | 用途 |
|------|------|------|
| **单条校验** | 任一审计记录详情页"完整性校验"按钮 | 怀疑某条记录被改时即时验证 |
| **批量校验** | `/audit/integrity` 页 | 按时间范围 / 模块范围批量校验 |
| **定期自动校验** | 每日 / 每周后台 Job | 系统自动校验 + 异常上报 |

校验失败表现：

- 单条校验：详情页弹窗显示 ✗ "已被篡改"，并展示哈希链上下文
- 批量校验：列表展示失败记录的 ID + 失败位置
- 定期校验：写入告警日志（待"风险告警中心"立项后接入推送）

### 6.3 SOX 合规要求对照

| SOX 要求 | 本系统实现 |
|------|------|
| 完整性 | `@Auditable` 装饰器自动覆盖关键操作；`@Financial` 标记财务操作 |
| 不可更改 | 哈希链 + DB 触发器 |
| 可追溯 | 5W1H 完整字段 + traceId 串联 |
| 访问控制 | RBAC 权限点（`audit:read*`） |
| 保留期限 | `@Financial` 标记自动归档 7 年 |
| 定期审查 | 后台自动完整性 Job + 合规报表 |

> ⚠️ **当前合规缺口**（截至 2026-05-08）：`@Financial()` 全局 0 处使用，5 个业务模块装饰器 0 接入，整体真实接入覆盖率 57.8%。详见 [01-prd.md §审计范围清单](01-prd.md)。补齐前不可对外宣称 SOX 合规。

### 6.4 合规报表

- 入口：`/audit/statistics` 页 → 报表 Tab
- 内置 SOX / GDPR 模板
- 可按时间范围生成 PDF / Excel
- 报表生成动作本身有审计记录

---

## 7. 常见问题（FAQ）

### Q1：我是普通员工，能看到自己以外的人的操作吗？

不能。`audit:read` 默认只放开本人记录可见。需要看他人的操作要由 Administrator / AuditAdmin 提权。

### Q2：审计记录可以删除吗？

**不能。** DB 触发器禁 UPDATE / DELETE，应用层也没有删除接口。即使是 Administrator 也无法删除——这是 SOX 不可更改要求的硬性约束。

### Q3：为什么有的操作没被记录？

可能原因：

1. Service 方法没加 `@Auditable` 装饰器（开发遗漏）
2. 操作只在 Repository 层，没走 Service（绕过装饰器）
3. 操作通过 Raw SQL 直接改 DB（绕过应用层）

定位思路：先看 [01-prd.md §审计范围清单](01-prd.md) 中该模块是否标记为"已接入"。

### Q4：审计日志会拖慢业务接口吗？

不会。审计写入走异步队列，主业务接口同步返回，平均延迟 < 20ms。极端情况下队列堵塞会触发告警，但主业务不阻塞。

### Q5：traceId 怎么用？

详情页右上角有 `traceId` 字段，可一键复制。带 `traceId` 去"高级搜索"过滤，可看到同一次操作产生的所有审计记录（典型场景：一次审批触发了 10 条状态变更）。

### Q6：完整性校验失败怎么办？

立刻向系统管理员上报。可能原因：

- DB 在审计表上执行了非法操作（理论上触发器会阻止，需要查为什么没拦住）
- 哈希算法配置变更未做迁移
- 备份恢复时哈希链断裂

**不要自行修复**——任何修复动作都会破坏链式校验，应由专人按事故响应流程处理。

### Q7：财务操作和敏感操作可以叠加吗？

可以。同时加 `@Financial` + `@Sensitive`，记录会同时出现在两个专用页。

### Q8：审计页支持双语吗？

支持。前端使用说明（`/audit/help`）已完成中英双语；审计内容（操作描述、entity 名）由各模块自行国际化，部分历史模块仍为中文硬编码，逐步迁移中。

---

## 关联文档

- [01-prd.md](01-prd.md) — 完整 PRD 与功能矩阵（含审计接入覆盖率清单）
- [03-architecture.md](03-architecture.md) — 架构设计、哈希链实现、异步队列
- [06-data-model.md](06-data-model.md) — `audit_log` 表结构、5W1H 字段定义
- [07-api.md](07-api.md) — 审计相关 REST API
- [11-configuration.md](11-configuration.md) — 配置项（哈希算法、留存期、签名密钥）
- [12-integration-guide.md](12-integration-guide.md) — 装饰器使用、接入步骤、踩坑指南
- [13-troubleshooting.md](13-troubleshooting.md) — 故障排查手册
