All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m32s
15 KiB
15 KiB
跨视角调查与前端导航契约
本文对应 build-multi-view-audit-center 任务 9.5,冻结 request、correlation、资金和风险调查接口,以及现有业务页面进入审计中心的第一跳。所有字段路径均位于统一响应的 response.data 下;列表字段位于 items[]。本文只定义前端调用契约,不包含前端页面实现。
跨视角只读接口
| 视角 | 接口 | 入参来源 | 响应重点 |
|---|---|---|---|
| 请求链路 | GET /api/admin/audit/requests/{request_id}/timeline |
审计或 Integration 节点的 investigation_refs.request_id,或开发人员从 Access Log 粘贴 |
request_id、access_log_lookup_request_id、nodes[] |
| 业务链路 | GET /api/admin/audit/correlations/{correlation_id}/timeline |
审计、Integration、Outbox、任务或业务详情中的稳定 correlation | correlation_id、nodes[] |
| 资金时间线 | GET /api/admin/audit/finance/timeline |
业务页面稳定 ID、调查节点引用或调查人员输入 | 分页 items[]、事实来源、金额权威、investigation_refs |
| 风险总览 | GET /api/admin/audit/risks/overview |
调查人员选择的 RFC3339 时间范围及可选筛选,最长 31 天 | 信号、风险、结果、动作、来源和趋势 |
| 风险明细 | GET /api/admin/audit/risks/events |
风险总览分桶携带相同筛选,或调查人员输入 | 分页风险事件及 investigation_refs |
以上接口仅允许超级管理员和平台账号访问,全部为 GET。认证身份只来自认证上下文;不提供导出、修改、删除、风险处置、自动封禁、重试、补偿或恢复能力。
资产和组织页面逐行导航
| 源页面 | 前置接口 | response.data 稳定字段 |
入口名称与可见条件 | 目标接口与参数映射 | 降级行为 |
|---|---|---|---|---|---|
| 卡列表 | GET /api/admin/iot-cards/standalone |
items[].id/iccid/virtual_no/shop_id/device_virtual_no/authorized_enterprise_id |
平台显示“审计记录”,要求 id 非零;代理显示“活动记录”,要求 iccid 非空;企业不从此列表进入 |
平台:/audit/resources/iot_card/{id}/timeline;代理:/agent/resource-activities/iot_card/{iccid} |
缺少对应 ID/ICCID 时隐藏;企业改从企业卡列表进入 |
| 设备列表 | GET /api/admin/devices |
items[].id/virtual_no/imei/sn/shop_id/bound_card_count/authorized_enterprise_id |
平台要求 id;代理要求 virtual_no;企业不从此列表进入 |
平台:/audit/resources/device/{id}/timeline;代理:/agent/resource-activities/device/{virtual_no} |
缺少字段时隐藏;企业改从企业设备列表进入 |
| 设备卡槽 | GET /api/admin/devices/{virtual_no}/cards |
bindings[].id/iot_card_id/iccid/slot_position/is_current |
平台可分别查看卡和绑定审计,要求相应 ID;代理可查看卡活动,要求 ICCID;企业仅在设备和卡均有效授权时显示卡活动 | 平台卡:iot_card/{iot_card_id};平台绑定:device_sim_binding/{bindings[].id};代理/企业卡:iot_card/{iccid} 的主体活动接口 |
不用绑定 ID 证明授权;设备时间线继续使用上层设备 ID/VirtualNo |
| 统一资产详情 | GET /api/admin/assets/resolve/{identifier} |
asset_type/asset_id/identifier/virtual_no/iccid/bound_device_id/cards[].card_id/exchange_trace[].asset_id/can_view |
平台在 asset_id 存在时显示“审计记录”;代理在卡 ICCID 或设备 VirtualNo 存在时显示“活动记录”;企业不显示 |
平台:card→iot_card/{asset_id}、device→device/{asset_id};代理:卡用 iot_card/{iccid}、设备用 device/{virtual_no} |
缺稳定字段时隐藏;换货轨迹仅 can_view=true 且资产 ID 存在时跳转;企业不得回退调用 resolve |
| 资产分配列表/详情 | GET /api/admin/asset-allocation-records[/{id}] |
items[].id/allocation_no/asset_type/asset_id/asset_identifier/from_owner_type/from_owner_id/to_owner_type/to_owner_id/related_device_id;详情另有 related_card_ids[] |
平台要求记录或资产 ID;代理要求 allocation_no 且当前关联资产或店铺仍在范围内;企业无独立入口 |
平台:asset_allocation_record/{id} 及 {asset_type}/{asset_id};代理:/agent/resource-activities/asset_allocation_record/{allocation_no} |
后端独立复核分配归属;不能因可打开旧详情就视为有权;企业从已授权资产活动查看结论 |
| 换货列表/详情 | GET /api/admin/exchanges[/{id}] |
items[].id/exchange_no/old_asset_type/old_asset_id/new_asset_type/new_asset_id/shop_id/submitter_id |
平台要求换货或资产 ID;代理要求 exchange_no 且换货店铺仍在范围内;企业无独立入口 |
平台:exchange_order/{id},旧新资产分别使用响应类型和 ID;代理:/agent/resource-activities/exchange_order/{exchange_no} |
旧新资产仅在各自仍可管理时开放;企业从有效授权资产活动查看结论 |
| 店铺列表/详情 | GET /api/admin/shops[/{id}] |
items[].id/shop_name/shop_code/parent_id/business_owner_account_id 或详情同名字段 |
平台要求 id;代理要求 shop_code 且为自己或下级店铺;企业不显示 |
平台:/audit/resources/shop/{id}/timeline;代理:/agent/resource-activities/shop/{shop_code} |
缺字段或越权时隐藏/显示不可用,不搜索平台审计 |
| 企业列表 | GET /api/admin/enterprises |
items[].id/enterprise_name/enterprise_code/owner_shop_id |
平台要求 id;代理要求 enterprise_code 且 owner shop 在范围内;企业自身不显示 |
平台:enterprise/{id};代理:/agent/resource-activities/enterprise/{enterprise_code} |
当前没有企业详情接口,前端不得假设存在;企业 ID 不作为主体活动路径参数 |
| 企业卡列表 | GET /api/admin/enterprises/{id}/cards |
items[].id/iccid/virtual_no/device_id |
平台要求 id;企业要求 iccid 且当前授权有效;代理不从此列表进入 |
平台:iot_card/{id};企业:/enterprise/resource-activities/iot_card/{iccid} |
路由中的企业 ID 不作为授权证明;后端始终使用认证上下文复核 |
| 企业设备列表 | GET /api/admin/enterprises/{id}/devices |
items[].device_id/virtual_no |
平台要求 device_id;企业要求 virtual_no 且当前授权有效;代理不从此列表进入 |
平台:device/{device_id};企业:/enterprise/resource-activities/device/{virtual_no} |
字段为空或授权撤销时隐藏/显示活动不可用,不回退平台接口 |
账号、交易和资金页面逐行导航
| 源页面 | 前置接口 | response.data 稳定字段 |
入口名称与可见条件 | 目标接口与参数映射 | 降级行为 |
|---|---|---|---|---|---|
| 账号列表/详情 | GET /api/admin/accounts[/{id}] |
列表 items[].id;详情 id |
平台在 ID 非零时显示“审计记录” | /audit/resources/account/{id}/timeline |
缺 ID 时隐藏,不按用户名搜索 |
| 店铺列表/详情 | GET /api/admin/shops[/{id}] |
列表 items[].id;详情 id |
ID 非零时显示“审计记录”和“资金链路” | 审计:shop/{id};资金:/audit/finance/timeline?shop_id={id} |
缺 ID 时两个入口均隐藏 |
| 企业列表 | GET /api/admin/enterprises |
items[].id |
ID 非零时显示“审计记录” | /audit/resources/enterprise/{id}/timeline |
不假设存在企业详情接口 |
| 订单列表/详情 | GET /api/admin/orders[/{id}] |
items[].id/order_no 或详情 id/order_no |
ID 非零时显示“审计记录”和“资金链路” | 审计:order/{id};资金:/audit/finance/timeline?order_id={id} |
不要求前端补 payment/refund ID;缺 ID 时隐藏 |
| 退款列表/详情 | GET /api/admin/refunds[/{id}] |
items[].id/refund_no/order_id/approval_instance_id 或详情同名字段 |
ID 非零时显示审计和资金入口;审批 ID 非零时显示“审批审计” | 审计:refund/{id};资金:finance/timeline?refund_id={id};审批:approval_instance/{approval_instance_id} |
缺审批 ID 只隐藏审批入口,不解析退款编号猜测 |
| 代理充值列表/详情 | GET /api/admin/agent-recharges[/{id}] |
items[].id/recharge_no/shop_id/agent_wallet_id/approval_instance_id 或详情同名字段 |
ID 非零时显示审计和资金入口;审批 ID 非零时显示审批审计 | 审计:agent_recharge/{id};资金:finance/timeline?recharge_id={id} |
缺 payment_no 由服务端关联,不要求前端补猜 |
| 代理在线充值结果 | POST /api/admin/agent-recharges |
recharge_id/recharge_no/payment_no |
recharge_id 非零时显示“资金链路” |
finance/timeline?recharge_id={recharge_id};可附加 payment_no 精确筛选 |
payment_no 不直接构造 Integration 详情;缺 recharge ID 时隐藏 |
| 资产钱包 | GET /api/admin/assets/{identifier}/wallet |
wallet_id/resource_type/resource_id |
wallet_id 非零时显示“资金链路”;资源类型和 ID 齐全时显示“资产审计” |
资金:finance/timeline?wallet_id={wallet_id};审计:resources/{resource_type}/{resource_id}/timeline |
两个入口独立判断;缺某组字段只隐藏对应入口 |
| 店铺资金概况 | GET /api/admin/shops/fund-summary |
items[].shop_id |
shop_id 非零时显示行内“资金链路” |
finance/timeline?shop_id={shop_id} |
不要求该接口未返回的 agent wallet ID |
| 店铺主钱包流水 | GET /api/admin/shops/{shop_id}/main-wallet/transactions |
path shop_id;items[].id/asset_type/asset_id/asset_identifier |
始终可按合法 path 显示资金入口;资产类型和 ID 齐全时显示资产审计 | 资金:finance/timeline?shop_id={shop_id};审计:resources/{asset_type}/{asset_id}/timeline |
缺资产 ID 仍保留店铺资金入口,不按资产编号猜测 |
| 资产钱包流水 | GET /api/admin/assets/{identifier}/wallet/transactions |
上层钱包接口 wallet_id;items[].id/reference_type/reference_no |
上层 wallet_id 非零时显示“资金链路” |
finance/timeline?wallet_id={wallet_id} |
reference_type/reference_no 仅展示;需后端节点明确返回资源引用后才能继续跳转 |
调查节点逐行跳转
investigation_refs 字段 |
入口名称 | 可见条件 | 目标接口与参数 | 降级行为 |
|---|---|---|---|---|
event_id |
“事件详情” | 非空 | GET /api/admin/audit/events/{event_id} |
空值隐藏 |
actor_ref.kind/id |
“查看操作者行为” | kind 和 id 均非空 | GET /api/admin/audit/actors/{kind}/{id}/events |
任一缺失即隐藏,不用当前账号资料补齐 |
resource_refs[] |
“查看资源审计” | resource_type/resource_id 均非空 |
GET /api/admin/audit/resources/{resource_type}/{resource_id}/timeline |
只有 Key 时先精确搜索;零或多命中不自动选择 |
request_id |
“查看请求链路” | 非空 | GET /api/admin/audit/requests/{request_id}/timeline |
空值隐藏,不扫描 Access Log 猜测 |
correlation_id |
“查看业务链路” | 非空 | GET /api/admin/audit/correlations/{correlation_id}/timeline |
空值隐藏,不按相近时间拼链路 |
integration_refs[].integration_id |
“查看外部交互” | 非空 | GET /api/admin/audit/integrations/{integration_id} |
空值隐藏,不使用数据库主键或相似资源猜测 |
actor_ref.kind 第一阶段只使用 account/openapi/system_task/scheduled_job/external_system。代理和企业活动响应不得包含 investigation_refs。
六条完整调用链
资产详情
- 调用
GET /api/admin/assets/resolve/{identifier}。 - 平台读取
data.asset_type/asset_id:卡将card转为iot_card,调用GET /api/admin/audit/resources/iot_card/{asset_id}/timeline?page=1&page_size=20;设备调用.../device/{asset_id}/timeline。 - 代理读取
data.iccid或data.virtual_no,调用对应/agent/resource-activities/...。 - 字段缺失时隐藏入口;企业不调用 resolve,也不回退平台接口。
订单
- 调用
GET /api/admin/orders/{id},读取data.id。 - “审计记录”调用
GET /api/admin/audit/resources/order/{id}/timeline。 - “资金链路”调用
GET /api/admin/audit/finance/timeline?order_id={id}&page=1&page_size=20。 - Payment、Refund、钱包等关联由服务端解析,前端不补猜。
退款
- 调用
GET /api/admin/refunds/{id},读取data.id和可选data.approval_instance_id。 - 审计调用
resources/refund/{id}/timeline,资金调用finance/timeline?refund_id={id}。 - 审批实例 ID 非零时再调用
resources/approval_instance/{approval_instance_id}/timeline。 - 审批字段缺失只隐藏审批入口,不影响退款审计与资金链路。
钱包
- 调用
GET /api/admin/assets/{identifier}/wallet,读取data.wallet_id/resource_type/resource_id。 - “资金链路”调用
finance/timeline?wallet_id={wallet_id}。 - “资产审计”调用
resources/{resource_type}/{resource_id}/timeline。 - 两组稳定字段分别判断,不使用交易备注或 reference 编号前缀推断资源。
通知
- 点击通知后先调用
GET /api/admin/notifications/{id}/target。 - 仅当
data.available=true时展示跳转。 data.target_type=integration_log且data.target_key非空时,将 target key 原样作为integration_id调用GET /api/admin/audit/integrations/{target_key}。- 其他 target type 先进入对应业务详情,再按本文业务页面矩阵进入审计;不可用时只展示通知正文。
风险节点
- 调用
GET /api/admin/audit/risks/overview?created_from={from}&created_to={to}。 - 点击风险、结果、动作或来源分桶时,将相同时间范围和对应稳定编码带入
GET /api/admin/audit/risks/events。 - 从明细
items[].investigation_refs直接进入事件、操作者、资源、request、correlation 或 Integration 视角。 - 缺少的引用入口隐藏;风险中心不提供处置、封禁或恢复按钮。
统一降级与事实边界
- 缺少目标接口必需的稳定 ID 或 identifier 时隐藏入口,不按名称、中文描述、时间或编号前缀猜测。
- 平台只有 Registry Key 时先调用精确资源搜索;零命中或多命中停留在搜索结果。
- 已删除资源只要调查节点仍有稳定资源类型和 ID,就可查看事件快照时间线。
- 代理或企业遇到越权、授权撤销或资源不存在时统一显示“活动不可用”,不回退平台调查、资源搜索或旧 operation log。
- request/correlation 时间线的
record_source保留 Audit Event、Integration Log、Outbox、Asynq 摘要和 Domain Ledger 引用的事实边界;Outbox 投递成功不等于业务成功。 - 资金金额和余额以钱包流水及对应业务表为权威;Audit Event 仅用于解释谁做了什么,不用于资金重算。
- 旧 operation log 仅由平台独立历史入口访问,不拼接到新
/api/admin/audit/*。