All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m55s
161 lines
6.8 KiB
Markdown
161 lines
6.8 KiB
Markdown
## 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)常量?
|