This commit is contained in:
98
docs/add-asset-operation-audit-log/功能总结.md
Normal file
98
docs/add-asset-operation-audit-log/功能总结.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# 资产操作审计日志功能总结
|
||||
|
||||
## 1. 功能目标
|
||||
|
||||
为资产域(IoT 卡/设备)补齐统一审计落库能力,解决“谁在什么时间对哪个资产做了什么变更、结果如何”的追溯问题。
|
||||
|
||||
## 2. 数据模型与落库
|
||||
|
||||
- 新增表:`tb_asset_operation_log`
|
||||
- 关键字段:
|
||||
- 操作人:`operator_id/operator_type/operator_name`
|
||||
- 资产:`asset_type/asset_id/asset_identifier`
|
||||
- 操作:`operation_type/operation_desc`
|
||||
- 镜像:`before_data/after_data`(JSONB)
|
||||
- 请求上下文:`request_id/ip_address/user_agent/request_path/request_method`
|
||||
- 结果:`result_status/error_code/error_msg`
|
||||
- 批量统计:`batch_total/success_count/fail_count`
|
||||
- 索引:
|
||||
- `idx_asset_log_asset_created`
|
||||
- `idx_asset_log_identifier_created`
|
||||
- `idx_asset_log_operator_created`
|
||||
- `idx_asset_log_operation_created`
|
||||
- `idx_asset_log_result_created`
|
||||
|
||||
## 3. 统一封装设计
|
||||
|
||||
### 3.1 基础设施统一入口
|
||||
|
||||
- `internal/service/asset_audit/service.go`
|
||||
- 统一 `LogOperation(ctx, log)` 异步写入
|
||||
- 写入失败只打 Error 日志,不阻断业务
|
||||
- `internal/service/asset_audit/builder.go`
|
||||
- 统一组装 `before/after`、请求上下文、错误码摘要
|
||||
- 统一脱敏与裁剪
|
||||
|
||||
### 3.2 业务侧统一 helper
|
||||
|
||||
- IoT 卡:`internal/service/iot_card/audit.go`
|
||||
- 设备:`internal/service/device/audit.go`
|
||||
- 统一资产入口轮询:`internal/service/polling/asset_polling_service.go` 内部 helper
|
||||
- 资产停用:`internal/service/asset/lifecycle_service.go` 内部 helper
|
||||
- 导入任务:
|
||||
- `internal/service/device_import/audit.go`
|
||||
- `internal/service/iot_card_import/audit.go`
|
||||
|
||||
业务函数只传结构化参数,避免日志拼装散落在各分支。
|
||||
|
||||
## 4. 覆盖范围
|
||||
|
||||
### 4.1 IoT 卡
|
||||
|
||||
- 分配/回收、系列绑定、轮询开关、实名策略、手动实名状态、删除/批量删除
|
||||
- 自动停复机 + 手动停复机(含 denied/failed)
|
||||
|
||||
### 4.2 设备
|
||||
|
||||
- 删除、分配/回收、系列绑定、绑卡/解绑
|
||||
- 设备停机/复机(含成功数、失败数、失败摘要)
|
||||
- 远程控制:限速、WiFi、切卡、切卡模式、重启、恢复出厂
|
||||
|
||||
### 4.3 统一资产入口与导入
|
||||
|
||||
- 统一入口:停用、轮询状态、实名策略
|
||||
- 导入任务创建:设备导入、卡导入
|
||||
|
||||
## 5. 脱敏与体积控制
|
||||
|
||||
- 敏感键脱敏:`password/passwd/pwd/secret/token/wifi_password/wifipwd`
|
||||
- WiFi 场景使用 `password` 键传参,落库前统一掩码处理
|
||||
- `before_data/after_data` 超过阈值时裁剪并标记 `_truncated=true`
|
||||
|
||||
## 6. 查询与排障示例
|
||||
|
||||
### 6.1 审计日志查询 API(前端)
|
||||
|
||||
- 路径:`GET /api/admin/assets/:identifier/operation-logs`
|
||||
- 操作人相关字段:
|
||||
- `operator_type` 返回中文标准文案(如平台用户、代理账号、企业账号、个人客户、系统)
|
||||
- `operator_type_code` 保留底层枚举编码(如 `admin_user`、`agent_user`)
|
||||
- `operator_name` 优先返回可读名称,历史 `类型#ID` 占位值会在查询时尽量补全
|
||||
- 建议前端优先使用:
|
||||
- `operation_content_before`(操作内容变更前)
|
||||
- `operation_content_after`(操作内容变更后)
|
||||
- `operation_fields_desc`(字段中文说明)
|
||||
- 原始字段 `before_data/after_data` 建议仅用于调试回放。
|
||||
- 字段明细文档:`docs/add-asset-operation-audit-log/操作内容字段说明.md`
|
||||
|
||||
### 6.2 SQL 排障示例
|
||||
|
||||
完整 SQL 见:
|
||||
|
||||
- `docs/add-asset-operation-audit-log/手工验收脚本.sql`
|
||||
|
||||
常用排障问题:
|
||||
|
||||
1. 某资产最近操作:按 `asset_type + asset_id` 查询
|
||||
2. 某操作人近期高风险动作:按 `operator_id` + `result_status in ('failed','denied')`
|
||||
3. WiFi 明文泄露检查:检索 `after_data::text ILIKE '%\"password\":\"%'` 并人工确认是否掩码
|
||||
89
docs/add-asset-operation-audit-log/手工验收脚本.sql
Normal file
89
docs/add-asset-operation-audit-log/手工验收脚本.sql
Normal file
@@ -0,0 +1,89 @@
|
||||
-- 资产操作审计日志手工验收 SQL
|
||||
-- 表:tb_asset_operation_log
|
||||
|
||||
-- 1) 表结构与索引核验
|
||||
SELECT table_name
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'tb_asset_operation_log';
|
||||
|
||||
SELECT indexname, indexdef
|
||||
FROM pg_indexes
|
||||
WHERE schemaname = 'public'
|
||||
AND tablename = 'tb_asset_operation_log'
|
||||
ORDER BY indexname;
|
||||
|
||||
-- 2) 最近 50 条审计日志
|
||||
SELECT id,
|
||||
created_at,
|
||||
operator_type,
|
||||
operator_id,
|
||||
asset_type,
|
||||
asset_id,
|
||||
asset_identifier,
|
||||
operation_type,
|
||||
result_status,
|
||||
batch_total,
|
||||
success_count,
|
||||
fail_count
|
||||
FROM tb_asset_operation_log
|
||||
ORDER BY id DESC
|
||||
LIMIT 50;
|
||||
|
||||
-- 3) success / failed / denied 三态分布
|
||||
SELECT operation_type, result_status, COUNT(*) AS cnt
|
||||
FROM tb_asset_operation_log
|
||||
GROUP BY operation_type, result_status
|
||||
ORDER BY operation_type, result_status;
|
||||
|
||||
-- 4) before/after 镜像完整性核验(近 200 条)
|
||||
SELECT id,
|
||||
operation_type,
|
||||
result_status,
|
||||
(before_data IS NOT NULL) AS has_before,
|
||||
(after_data IS NOT NULL) AS has_after
|
||||
FROM tb_asset_operation_log
|
||||
ORDER BY id DESC
|
||||
LIMIT 200;
|
||||
|
||||
-- 5) 批量聚合字段核验(batch_total/success_count/fail_count)
|
||||
SELECT id,
|
||||
operation_type,
|
||||
batch_total,
|
||||
success_count,
|
||||
fail_count,
|
||||
(batch_total >= success_count + fail_count) AS counter_ok
|
||||
FROM tb_asset_operation_log
|
||||
WHERE batch_total > 0
|
||||
ORDER BY id DESC
|
||||
LIMIT 200;
|
||||
|
||||
-- 6) 系统触发语义核验
|
||||
SELECT id,
|
||||
operation_type,
|
||||
operator_type,
|
||||
operator_id,
|
||||
operator_name,
|
||||
result_status
|
||||
FROM tb_asset_operation_log
|
||||
WHERE operation_type IN ('card_auto_stop', 'card_auto_start')
|
||||
ORDER BY id DESC
|
||||
LIMIT 100;
|
||||
|
||||
-- 7) WiFi 脱敏核验(不应出现明文密码)
|
||||
SELECT id,
|
||||
operation_type,
|
||||
after_data
|
||||
FROM tb_asset_operation_log
|
||||
WHERE operation_type = 'device_set_wifi'
|
||||
ORDER BY id DESC
|
||||
LIMIT 20;
|
||||
|
||||
-- 8) 拒绝与失败热点排查
|
||||
SELECT operation_type,
|
||||
result_status,
|
||||
COUNT(*) AS cnt
|
||||
FROM tb_asset_operation_log
|
||||
WHERE result_status IN ('failed', 'denied')
|
||||
GROUP BY operation_type, result_status
|
||||
ORDER BY cnt DESC, operation_type;
|
||||
69
docs/add-asset-operation-audit-log/接口回放示例.md
Normal file
69
docs/add-asset-operation-audit-log/接口回放示例.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# 资产审计日志接口回放示例
|
||||
|
||||
以下示例用于构造 success / failed / denied 三类日志数据。请替换 `<token>`、`<identifier>`、`<device_id>`、`<card_id>` 等占位符。
|
||||
|
||||
## 1. success 示例
|
||||
|
||||
### 1.1 设备限速(`device_speed_limit`)
|
||||
|
||||
```bash
|
||||
curl -X POST "http://127.0.0.1:8080/api/admin/devices/<identifier>/speed-limit" \
|
||||
-H "Authorization: Bearer <token>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"speed_limit":1024}'
|
||||
```
|
||||
|
||||
### 1.2 资产轮询开关(`asset_polling_status`)
|
||||
|
||||
```bash
|
||||
curl -X PATCH "http://127.0.0.1:8080/api/admin/assets/<identifier>/polling-status" \
|
||||
-H "Authorization: Bearer <token>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"enable_polling":false}'
|
||||
```
|
||||
|
||||
## 2. denied 示例
|
||||
|
||||
### 2.1 保护期内停机(`device_stop` / `card_manual_stop`)
|
||||
|
||||
```bash
|
||||
curl -X POST "http://127.0.0.1:8080/api/admin/assets/<identifier>/stop" \
|
||||
-H "Authorization: Bearer <token>"
|
||||
```
|
||||
|
||||
若命中保护期规则,应返回拒绝并写入 `result_status=denied`。
|
||||
|
||||
### 2.2 越权分配设备(`device_allocate`)
|
||||
|
||||
```bash
|
||||
curl -X POST "http://127.0.0.1:8080/api/admin/devices/allocate" \
|
||||
-H "Authorization: Bearer <agent-token>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"target_shop_id":999999,"device_ids":[1,2,3],"remark":"审计验收"}'
|
||||
```
|
||||
|
||||
## 3. failed 示例
|
||||
|
||||
### 3.1 无效设备标识触发远程控制失败(`device_reboot`)
|
||||
|
||||
```bash
|
||||
curl -X POST "http://127.0.0.1:8080/api/admin/devices/<invalid-identifier>/reboot" \
|
||||
-H "Authorization: Bearer <token>"
|
||||
```
|
||||
|
||||
### 3.2 导入任务入队失败(`device_import_task_create` / `iot_card_import_task_create`)
|
||||
|
||||
通过临时关闭队列依赖或传入无效参数触发失败,确认写入 `result_status=failed` 和错误摘要。
|
||||
|
||||
## 4. 结果核对
|
||||
|
||||
执行完回放后,使用:
|
||||
|
||||
- `docs/add-asset-operation-audit-log/手工验收脚本.sql`
|
||||
|
||||
重点核对:
|
||||
|
||||
1. 同一操作存在 success/failed/denied
|
||||
2. `before_data` 与 `after_data` 有效
|
||||
3. WiFi 密码字段为掩码
|
||||
4. 批量字段 `batch_total/success_count/fail_count` 合理
|
||||
102
docs/add-asset-operation-audit-log/操作内容字段说明.md
Normal file
102
docs/add-asset-operation-audit-log/操作内容字段说明.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# 资产审计日志操作内容字段说明
|
||||
|
||||
## 1. 查询接口
|
||||
|
||||
- 路径:`GET /api/admin/assets/:identifier/operation-logs`
|
||||
- 说明:先按资产标识符解析资产,再查询该资产的审计日志。
|
||||
|
||||
## 2. 前端应优先使用的字段
|
||||
|
||||
为避免历史数据格式差异,前端应优先使用以下三个字段:
|
||||
|
||||
1. `operation_content_before`:操作内容(变更前)
|
||||
2. `operation_content_after`:操作内容(变更后)
|
||||
3. `operation_fields_desc`:字段中文说明(`key=字段名`,`value=中文解释`)
|
||||
|
||||
`before_data/after_data` 保留为原始审计数据,建议仅作为调试或回放使用。
|
||||
|
||||
## 3. 通用字段
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `operator_type` | 操作人类型中文名称(如平台用户、代理账号、企业账号、个人客户、系统) |
|
||||
| `operator_type_code` | 操作人类型编码(如 `admin_user`、`agent_user`) |
|
||||
| `operator_name` | 操作人可读名称,优先返回用户名/店铺名/企业名/客户昵称 |
|
||||
| `batch_total` | 批量总数 |
|
||||
| `success_count` | 成功数量 |
|
||||
| `fail_count` | 失败数量 |
|
||||
| `failed_items` | 失败明细 |
|
||||
| `reason` | 原因说明 |
|
||||
|
||||
## 4. 常见操作字段
|
||||
|
||||
### 4.1 分配/回收
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `target_shop_id` / `to_shop_id` | 目标店铺ID |
|
||||
| `source_shop_id` / `from_shop_id` | 来源店铺ID |
|
||||
| `device_ids` | 设备ID列表 |
|
||||
| `card_ids` | 卡ID列表 |
|
||||
| `selection_type` | 选择方式 |
|
||||
| `new_status` | 变更后状态 |
|
||||
|
||||
### 4.2 设备绑卡/解绑
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `binding_id` | 绑定记录ID |
|
||||
| `slot_position` | 插槽位置 |
|
||||
| `iot_card_id` | 卡ID |
|
||||
| `iccid` | 卡ICCID |
|
||||
| `unbind` | 是否执行解绑 |
|
||||
|
||||
### 4.3 设备停复机
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `success_count` | 成功数量 |
|
||||
| `fail_count` | 失败数量 |
|
||||
| `skip_count` | 跳过数量 |
|
||||
| `failed_items` | 失败明细(含ICCID和原因) |
|
||||
|
||||
### 4.4 远程控制
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `speed_limit` | 限速值(KB/s) |
|
||||
| `ssid` | WiFi 名称 |
|
||||
| `password` | WiFi 密码(已脱敏) |
|
||||
| `enabled` | WiFi 开关状态 |
|
||||
| `target_iccid` | 目标ICCID |
|
||||
| `switch_mode` | 切卡模式(0自动/1手动) |
|
||||
|
||||
### 4.5 轮询与实名
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `enable_polling` | 轮询开关 |
|
||||
| `realname_policy` | 实名策略(none/before_order/after_order) |
|
||||
| `real_name_status` | 实名状态(0未实名/1已实名) |
|
||||
|
||||
## 5. 兼容性说明
|
||||
|
||||
历史日志中 `before_data` 可能是资产快照而不是操作内容。接口已做归一化处理:
|
||||
|
||||
- 自动抽取并返回 `operation_content_before/after`
|
||||
- 当历史数据缺少“变更前操作内容”时,会按“变更后字段”与资产快照尽量回填
|
||||
- 历史日志中的 `后台用户#ID`、`代理用户#ID` 等占位名称,接口会尽量按当前账号资料补全为可读名称
|
||||
|
||||
因此,前端无需再自行解析 `before_data/after_data` 的多种历史格式。
|
||||
|
||||
## 6. 前端处理建议
|
||||
|
||||
建议前端按以下优先级渲染变更明细:
|
||||
|
||||
1. 遍历 `operation_content_after` 的字段键作为“变更项集合”
|
||||
2. 字段名展示优先使用 `operation_fields_desc[key]`,没有则回退为 `key`
|
||||
3. 变更前值读取 `operation_content_before[key]`
|
||||
4. 变更后值读取 `operation_content_after[key]`
|
||||
5. 当前值为 `null` 时按“未知/未记录”展示,不要直接当空字符串
|
||||
|
||||
`before_data/after_data` 建议只用于问题排查,不参与主界面渲染。
|
||||
Reference in New Issue
Block a user