Skip to content

feat(audit): 支持团队与系统审计日志 CSV 导出 #561

Description

@AptS-1547

问题

AsterDrive 当前已经提供三类审计查询入口,但都只返回分页 JSON:

  • 用户侧团队管理:GET /api/v1/teams/{id}/audit-logs,团队 owner/admin 查看自己有权管理的团队审计。
  • 管理员团队详情:GET /api/v1/admin/teams/{id}/audit-logs,系统管理员查看指定团队审计。
  • 管理员系统审计:GET /api/v1/admin/audit-logs,系统管理员查看全站审计。

团队 owner/admin 和系统管理员需要把筛选后的审计记录交给合规、故障排查或离线分析流程。当前只能逐页复制界面,难以稳定导出完整结果,也容易遗漏分页、排序和筛选条件。前端不应把分页 JSON 在浏览器里拼成 CSV:大日志量会占用大量内存,且难以形成与权限边界一致的服务端结果集。

目标

在保持现有 JSON 列表接口兼容的前提下,增加服务端生成并下载 CSV 的能力,覆盖用户侧团队审计、管理员团队审计和管理员系统审计。导出结果必须是当前调用者在当前筛选条件下可见的同一批审计记录,使用导出入口不得扩大数据范围。

建议增加独立的导出路由,避免让普通列表响应根据 query 参数隐式改变媒体类型:

GET /api/v1/teams/{id}/audit-logs/export
GET /api/v1/admin/teams/{id}/audit-logs/export
GET /api/v1/admin/audit-logs/export

三个入口复用各自现有列表的过滤参数:

  • user_id
  • action
  • entity_type
  • entity_id
  • after
  • before
  • 系统审计额外复用现有 sort_by / sort_order

团队导出沿用团队查询强制的 entity_type=teamentity_id=团队 ID,调用者身份仍由现有 service 权限检查决定。不要新增前端根据角色或团队成员列表推断权限的逻辑。

后端与 API 设计

结果与流式行为

  • 返回 200 OKContent-Type: text/csv; charset=utf-8Content-Disposition: attachment,文件名包含导出类型、团队标识(如适用)和 UTC 时间戳;文件名必须经过安全规范化。
  • 采用服务端流式/游标式读取,禁止先把全部行收集到 Vec。设置明确的单次导出上限或可配置上限,并在超限时返回稳定错误;上限和错误文案写入 API 文档。
  • 导出顺序必须稳定。系统审计按现有 sort_by / sort_order 工作,并用 id 作为同值二级排序;团队审计至少使用 created_at + id 的确定性排序。
  • 查询开始前刷新异步审计写入管理器,确保已经完成的审计事件进入结果;导出过程中不得为了生成 CSV 改变审计保留策略。
  • 任何数据库、流、取消或客户端断开错误都要记录并结束响应,禁止静默吞错或返回半截成功状态而不留诊断。

CSV 契约

固定、可文档化的列顺序,至少包含:

id,created_at,actor_user_id,actor_username,action,entity_type,entity_id,entity_name,detail,ip_address,user_agent

团队审计可以在同一契约中追加或明确空值列:

member_user_id,member_username,role,previous_role,next_role
  • 所有单元格按 RFC 4180 风格正确转义逗号、双引号、换行和 Unicode;空值保持为空,不把 null 写成误导性的字符串。
  • created_at 使用 UTC RFC 3339;枚举值使用稳定 API 名称,禁止把当前语言的展示文案写成数据契约。
  • detail 使用结构化审计详情的稳定 JSON 字符串或明确的扁平化字段,必须保证每行只有固定列数;不得把带换行的 presentation 文案直接拼入未转义单元格。
  • 密码、token、MFA secret、外部认证凭据、存储 secret 等敏感值排除在导出之外。对已有 details 中可能出现的敏感字段建立服务端白名单/脱敏规则,禁止只依赖前端隐藏列。
  • 默认使用 UTF-8;如为桌面表格兼容增加 BOM,必须在 API 文档和测试中固定行为。

权限、审计与一致性

  • 用户侧导出必须和 list_team_audit_entries 使用同一团队存在性、成员角色和 can_manage_team() 检查;普通成员、已移除成员和越权团队 ID 均返回现有 403/404 语义。
  • 管理员两个导出入口必须复用现有管理员 guard;禁止因为导出是流响应而绕过 admin 权限或隐藏团队检查。
  • 导出本身建议记录独立审计动作(包含导出类型、团队 ID、筛选摘要和行数/截断结果),但禁止把完整筛选内容、CSV 内容或任何 secret 写进审计详情;需要避免导出动作递归污染本次结果的定义。
  • 同一个请求中的权限判定、筛选条件和数据读取必须来自服务端权威状态。reader 数据库可用于纯读,但要明确快照/滞后边界,禁止依赖前端缓存。
  • 记录空结果导出、达到上限和取消/失败,便于管理员区分“没有事件”和“导出失败”。

前端行为

用户侧团队审计

  • 在团队管理的审计页提供带下载图标的“导出 CSV”按钮,仅在当前用户可访问审计 tab 时显示。
  • 导出携带当前团队和当前筛选条件;下载期间显示 loading/禁用重复点击,成功后恢复,可处理 401/403、上限和网络错误并给出本地化提示。
  • 保持现有分页、空状态、审计详情展示和 URL 查询状态;导出是完整筛选结果,不只导出当前页。

管理员侧

  • 在系统审计页提供导出按钮,带上当前 action/entity type/时间/用户等筛选和排序条件。
  • 在管理员团队详情的审计页提供同样入口,导出指定团队的完整筛选结果。
  • 统一通过 service/resource 层发起二进制下载,组件不直接拼 /api、credentials、blob URL 或 Content-Disposition 解析;下载策略、文件名解析、错误映射和 blob URL 释放集中实现并可测试。
  • 英文和中文文案、无权限/空结果/超限/失败状态完整覆盖;按钮使用现有 Icon 组件并提供可访问名称。

验收标准

  • 三个导出 endpoint 已加入路由、权限 guard、OpenAPI 和生成 SDK;现有三个 JSON 列表 endpoint 行为不变。
  • 用户侧团队 owner/admin、管理员团队详情、管理员系统审计均可下载 CSV;普通成员和越权请求保持 403/404 语义。
  • 导出复用列表筛选条件;系统审计复用排序条件;导出是完整匹配结果而不是当前分页页。
  • 响应 headers、UTF-8、文件名规范化、固定列顺序和 RFC 4180 转义均有契约测试。
  • 大结果使用有界流式/游标读取;配置的单次行数上限、超限错误、空结果和客户端取消均有测试。
  • CSV 行不会因逗号、引号、换行或 Unicode 破坏列数;时间、枚举、空值和团队成员字段格式稳定。
  • 服务端白名单/脱敏测试证明密码、token、MFA、外部认证和存储 secret 不会进入导出;导出审计详情不会泄露完整原始 payload。
  • 导出前已刷新异步审计写入;数据库/流失败有可观测错误且不静默吞掉。
  • 导出动作(若采用独立审计 action)不会递归计入当前结果,并覆盖成功、空结果、超限和失败记录语义。
  • 前端用户侧团队审计、管理员团队审计、管理员系统审计均有按钮、loading、错误、权限和下载回收测试;当前筛选/排序参数正确传递。
  • 前端下载策略集中在 service/resource 层,覆盖 blob URL 释放、文件名解析、401/403 和重复点击竞态;中英文 i18n 完整。
  • 后端 repository/service/route、OpenAPI/SDK、前端 service/页面和相关文档均完成 focused 测试;运行 git diff --check

相关代码

  • src/api/routes/teams.rs
  • src/api/routes/admin/teams.rs
  • src/api/routes/admin/audit_logs.rs
  • src/services/workspace/team/mod.rs
  • src/services/ops/audit/filters.rs
  • src/services/ops/audit/query.rs
  • src/services/ops/audit/models.rs
  • src/db/repository/audit_log_repo.rs
  • frontend-panel/src/services/teamService.ts
  • frontend-panel/src/services/adminService.ts
  • frontend-panel/src/services/auditService.ts
  • frontend-panel/src/components/settings/team-manage-detail/TeamManageAuditSection.tsx
  • frontend-panel/src/components/admin/admin-team-detail/AdminTeamDetailAuditSection.tsx
  • frontend-panel/src/pages/admin/AdminAuditPage.tsx
  • frontend-panel/src/services/http.ts

非目标

  • 不在本 issue 重做审计事件记录矩阵、保留策略、presentation 国际化或团队文件活动的定义。
  • 不导出审计以外的文件、分享、用户、配置或存储报表;不新增异步报表任务、邮件投递或云端归档。
  • 不让前端合并分页数据或维护一套独立于后端的 CSV 字段/权限矩阵。

Checklist

  • 已搜索现有 issue 和代码,确认当前只有三类分页 JSON 审计查询,没有等价的 CSV 导出能力。
  • 已确认用户侧团队审计仅允许团队 owner/admin,管理员侧通过现有 admin guard 访问。

Metadata

Metadata

Assignees

Labels

DocumentationImprovements or additions to documentationEnhancementNew feature or requestPriority: MediumMedium priority issueRisk: HighChanges a high-risk data, security, protocol, or deployment boundaryRustPull requests that update Rust codeScope: Admin UIAdministrator-facing frontend workflows and management interfacesTypeScriptPull requests that update JavaScript code

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions