修正数据
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m55s

This commit is contained in:
2026-04-27 18:10:08 +08:00
parent bb33232b1b
commit fe4c545308
57 changed files with 4477 additions and 226 deletions

View File

@@ -0,0 +1,160 @@
## Context
当前系统已有 `tb_account_operation_log`,但该模型以账号为中心(如 `target_account_id``target_username`),不适合承载资产域(卡/设备)高频敏感操作。现有资产相关写操作分散在多个模块:
- `iot_card`:分配、回收、系列绑定、轮询开关、实名策略、手动实名、删除
- `device`:删除、分配回收、绑定解绑、系列绑定、设备停复机、网关远程控制
- `asset`:统一入口停复机、停用、轮询状态、实名策略
- `auto-stop-resume`:轮询触发自动停复机
这些链路当前多为业务日志zap缺少可结构化查询的审计落库无法稳定支持安全审计、操作追责与问题复盘。
约束:
- 必须遵循 `Handler -> Service -> Store -> Model`,审计写入在 Service 层触发。
- 审计能力按业务域拆分,本次仅实现资产域,不做全局万能日志表。
- 主流程性能不可明显退化,审计写入采用异步非阻塞。
- 不新增自动化测试文件,采用 PostgreSQL MCP + Postman/curl 手工验证。
## Goals / Non-Goals
**Goals:**
- 新增资产域专用审计日志模型、存储与服务(`tb_asset_operation_log` + `asset_audit`)。
- 覆盖卡与设备敏感写操作,要求成功/失败/拒绝全部记录。
- 统一日志字段:操作人、时间、动作、目标资产、变更前后、请求上下文、结果。
- 在现有模块中实现可复用的审计调用模式,减少重复拼装逻辑。
- 提供可回滚的迁移方案与明确的手工验收清单。
**Non-Goals:**
- 本阶段不实现通用“跨域审计查询平台”。
- 本阶段不改造账号域日志(`tb_account_operation_log`)历史数据。
- 本阶段不新增审计查询 API先完成采集落库查询按 DB 手工验证)。
## Decisions
### 决策1资产域独立日志模型与表
**选择**:新增 `tb_asset_operation_log`,不复用 `tb_account_operation_log`
**理由**
- 资产日志与账号日志目标对象不同,字段语义差异大。
- 独立表可避免“万能表”字段污染,支持未来按域继续拆分(财务/权限等)。
- 资产操作体量高,独立索引策略可控。
**备选方案**:复用 `tb_account_operation_log` 增加 nullable 字段。
**放弃原因**:语义混杂、索引冲突、后续演进成本高。
---
### 决策2统一资产审计服务 + 结构化日志构建器
**选择**:新增 `internal/service/asset_audit`,提供统一 `LogOperation(ctx, entry)`;各业务 Service 在成功/失败/拒绝节点调用。
**理由**
- 降低每个模块重复组装字段成本。
- 便于统一控制日志格式、字段裁剪、异常降级。
- 与现有账号审计模式一致,降低团队理解成本。
**备选方案**:每个业务 Service 直接写 Store。
**放弃原因**:重复代码多,格式易漂移,难做统一治理。
---
### 决策3全结果态记录success/failed/denied
**选择**:结果字段使用 `result_status`(成功/失败/拒绝),并记录 `error_code/error_msg`(失败或拒绝时)。
**理由**
- 仅记录成功不足以支撑安全审计(越权尝试、失败操作同样关键)。
- 便于风控与运维排查(失败高发点、越权热点)。
**备选方案**:只记录成功。
**放弃原因**:审计链不完整。
---
### 决策4前后镜像字段规范化
**选择**`before_data/after_data` 统一为 JSONB
- create/绑定类:`before_data` 可为空,`after_data` 必填关键字段
- update/状态流转类:`before_data``after_data` 同时记录
- delete/解绑类:`before_data` 必填,`after_data` 可为空或最小状态
**理由**
- 满足“从什么变成什么”的核心诉求。
- 便于后续做差异化检索与审计导出。
---
### 决策5依赖注入与接入矩阵
**选择**:在 bootstrap 注入 `assetAuditService` 到以下服务:
- `iot_card.Service`
- `device.Service`
- `iot_card.StopResumeService`
- `asset.LifecycleService`
- `polling.AssetPollingService`(设备轮询开关路径)
- `device_import.Service` / `iot_card_import.Service`(任务创建记录)
**理由**
- 关键写操作分布在多个服务,必须覆盖所有真实入口。
- 避免仅在 Handler 记录导致丢失 Service 内部失败/回滚细节。
---
### 决策6异步写入 + 失败不阻断
**选择**:审计写入使用 Goroutine 异步落库,写入失败仅记录 Error 日志,不影响主业务结果。
**理由**
- 符合当前项目审计日志规范。
- 避免写操作主路径被审计 IO 放大。
**补充约束**
- 单条日志大小限制(对大字段做截断/脱敏),避免超大 JSON 影响 DB。
- 脱敏字段(如 WiFi 密码)仅记录摘要,不明文落库。
---
### 决策7常量与操作类型字典化
**选择**:在 `pkg/constants` 定义资产审计操作类型、结果类型、目标类型常量,禁止硬编码。
**理由**
- 统一语义,避免多模块字符串漂移。
- 便于统计与后续扩展。
## Risks / Trade-offs
- **[风险] 日志量增长导致表膨胀和查询变慢**
**缓解**:增加组合索引(资产、操作人、时间、结果),后续按月归档策略预留。
- **[风险] before/after 组装不一致,影响可读性**
**缓解**:统一字段模板与 helper代码评审按固定清单检查。
- **[风险] 异步写入在进程异常退出时丢少量日志**
**缓解**:接受该权衡;关键安全场景后续可升级为异步队列化写入。
- **[风险] 远程控制接口包含敏感参数(如密码)**
**缓解**:明确脱敏规则,禁止明文入 `after_data`
- **[权衡] 全量记录失败/拒绝会增加写入量**
**接受**:审计完整性优先于少量存储成本。
## Migration Plan
1. 新增模型与迁移:`tb_asset_operation_log`(含必要索引)。
2. 新增 `asset_audit` store/service并在 bootstrap 完成注入。
3. 按操作矩阵分批接入:
- 第一批:停复机、绑定解绑、分配回收、停用、实名策略、轮询开关
- 第二批:远程控制、导入任务创建、删除/批量删除
4. 补充常量与日志构建 helper统一字段格式与脱敏。
5. 使用 PostgreSQL MCP + Postman/curl 执行手工验收输出证据请求、响应、DB 快照)。
**回滚策略:**
- 业务回滚:关闭审计调用开关(或临时空实现),不影响主流程。
- 数据回滚:执行 migration down 删除新表。
## Open Questions
- 是否在本期即提供后台审计查询 API还是维持 DB 手工查询到下一期?
- `after_data` 的最大存储体积阈值定为多少(如 16KB/32KB
- 是否需要为“自动停复机(系统触发)”定义专门 `operator_type`system常量