Files
junhong_cmp_fiber/openspec/changes/refactor-audit-log-persistence/proposal.md
邹进 b7a7430cc3
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 12m8s
feat: 审计动作按落库策略分级写入,系统过程动作改写应用日志
- 审计注册表为可由系统任务、定时任务发起的动作声明落库策略(always/on_success/outcome/log_only/none),未声明按 log_only
- 人工、开放接口、个人客户、外部系统发起的动作始终写审计表
- log_only 写所在服务 app.log(logger=audit),不含快照
- 对接日志不再补写 integration.attempt_started,无上游审计时 audit_event_id 为空
- 新增 audit.persist_overrides 按动作覆盖策略
- 审计覆盖扫描要求机器动作必须声明策略
- 新增 OpenSpec 提案 refactor-audit-log-persistence 与技术方案文档

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 18:27:24 +09:00

82 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Why
统一审计表被当作过程日志使用。系统任务每次同步、扣减、对接调用开始、失败重试,都会写一条审计事件,外加 2–3 条资源快照。生产近 14 天日均写入约 122 万条,其中 99% 以上由机器发起;测试环境日均约 12.6 万条。两张审计表合计 21 个索引,写入成本高,是 11-03 生产数据库 IO 打满、轮询停摆的主要原因之一。
同时,从审计中移出的过程数据必须仍能查到。现有采集记录、停复机记录等业务表大多只能按单卡查询,筛选条件少。采集失败的具体原因被丢弃,也没有保存运营商原始响应,出了问题无据可查。
方案依据:`docs/2026-11-05-审计日志写入改造技术方案.md`(方案 B)。本 Change 基于 `Iteration/8-11` 实施,只部署到测试环境。
## What Changes
**审计写入**
- 统一审计注册表为每个动作声明落库策略:总是写、只写成功、只写结论、只写应用日志、不写。
- 未声明策略的系统任务、定时任务动作,默认只写应用日志。
- 后台账号、个人客户、OpenAPI、外部系统发起的动作始终写审计。
- 系统任务的过程类动作不再写审计表,改写到所在服务的应用日志(`logs/app.log`,带 `logger=audit` 标记,不含变更前后快照)。涉及的动作包括:流量同步、网络状态同步、流量扣减、停机原因更新、通知投递、优先轮询、流量重置明细等。
- 自动重试类动作只写最终结论:最终成功,或重试用尽转人工。每一次尝试都记录在业务尝试记录表中。
- **BREAKING** 对接日志不再补写 `integration.attempt_started` 审计事件。没有上游审计事件的对接日志,其 `audit_event_id` 允许为空。
- 提供按动作的运行时覆盖配置,不发版即可临时调整某个动作的落库策略。
**退款资产后处理**
- 新增退款后处理尝试记录,每次尝试一条,只增不改。
- 自动重试最多 10 次,指数退避,间隔最长 1 小时。超过上限后标记"需人工处理",不再自动重投。
**停复机记录**
- 停复机指令在调用上游之前就结束时(已是目标状态、条件不再满足、不允许停复机),写一条结果为"跳过"的停复机记录,并写明原因。
**运营商流量采集记录**
- **BREAKING** 成功与失败分表:现有采集记录表只写成功读数,新增采集失败表。
- 失败记录带错误类别、上游返回码与信息、耗时。
- 失败记录不再判断卡有没有套餐,所有轮询到的卡都写。
- 成功表和失败表都保存网关原始请求(加密前明文业务参数)与原始响应。
- **BREAKING** 在线保留由 90 天改为 2 个月(当月加最近 2 个整月)。到期的月分区按"摘出分区、导出 `csv.gz`、校验、删除"四步处理,压缩包和说明文件留在 worker 运行目录,由同步服务器拉走。
**记录查询接口**
- 每类独立记录各提供一个列表接口:传卡标识查单个,不传查全部。
- 都支持分页和条件筛选,时间范围必填。所需索引随筛选条件新建或重建。
- 覆盖的记录:采集成功、采集失败、停复机、套餐日流量详单、卡日流量、流量冲正、退款后处理尝试。退款列表增加后处理状态筛选。
**测试环境部署配置**
- api、worker 各自挂载自己的 `logs/` 目录,不再共用同一个 `app.log`。
- 每个服务保留 40 个压缩备份。
- worker 挂载 `archive/` 目录。
## Capabilities
### New Capabilities
- `operational-record-query`:独立业务记录的统一分页条件查询。覆盖采集成功与失败、停复机、套餐日流量、卡日流量、流量冲正、退款后处理尝试;可查单个,也可查全部。
- `refund-asset-post-processing`:退款资产后处理的逐次尝试记录、重试上限、退避与转人工。
### Modified Capabilities
- `operations-audit`:审计落库策略分级;系统过程动作改写应用日志;结论型写入;对接日志允许无审计关联;轮询审计边界调整。
- `card-traffic-metering`:采集记录成功与失败分表、保存原始请求与响应、失败记录不再判断有无套餐、在线保留 2 个月并到期归档为压缩包。该 capability 来自尚未归档的 `add-card-traffic-queue-and-observed-deduction`,本 Change 须在其归档后再归档。
- `gateway-call-observability`:停复机指令在调用前结束时写"跳过"记录。该 capability 来自尚未归档的 `add-carrier-gateway-rate-limit`,本 Change 须在其归档后再归档。
## Impact
- **审计**:`internal/infrastructure/audit`(注册表、Writer)、`pkg/constants/audit.go`、`internal/governance/auditcoverage`、`internal/query/audit`(时间线合并停复机记录)。
- **对接日志**:`internal/infrastructure/integrationlog/repository.go`。
- **退款**:`internal/service/refund`、`internal/infrastructure/commissiondelivery`(补偿扫描),新增尝试记录表。
- **停复机**:停复机指令执行路径中写入跳过记录。
- **采集**:
- 原始数据收集器:`internal/gateway/client.go`
- 采集写入:`internal/task/polling_carddata_handler.go`、`internal/application/cardobservation`
- 存储与分区维护:`internal/store/postgres/card_traffic_collection_store.go`、`cmd/worker/main.go`
- **接口**:`internal/routes`、`internal/handler/admin`、`internal/model/dto`、`internal/store/postgres`,并同步生成接口文档。
- **数据库迁移**:
- 新增采集失败表、退款后处理尝试表;
- 采集成功表增加 `carrier_id` 与原始数据列;
- 退款单增加后处理状态字段;
- 各记录表新建或重建索引。
- **配置与部署**:`pkg/config`(`audit.persist_overrides`)、`docker-compose.prod.yml`、`.gitea/workflows/deploy.yaml`。
- **与已有 Change 的关系**:`add-audit-integration-write-switches` 的全局写入开关保持不变。全局开关用于应急全停;本 Change 是常态下按动作分级,两者互不替代。
- **不涉及**:生产环境的代码、配置与服务;已有审计数据的删除或迁移。