Add tenant-safe value, telemetry, connector, commercial, and production-readiness foundations.
107 lines
6.1 KiB
Markdown
107 lines
6.1 KiB
Markdown
# Hermes、本体解析与财务报告多租户安全 概念文档
|
||
|
||
更新时间:2026-07-17
|
||
|
||
## 功能一句话
|
||
|
||
让本体解析、员工行为画像、Hermes 扫描、数字员工看板和定时财务报告从请求到存储全程绑定可信企业,并在任何租户上下文缺失或冲突时停止运行。
|
||
|
||
## 背景与问题
|
||
|
||
本体解析曾在建立 `AgentRun` 前调用模型,并从全局员工、组织、客户、供应商、项目和单据字典构造提示词;员工画像详情可按任意员工 ID 查询;Hermes 扫描、看板和财务报告存在全表读取、全局收件人以及跨企业复用存储路径的风险。内部 Orchestrator 调用还可在没有认证用户时继续运行,无法证明 `AgentRun` 的企业归属。
|
||
|
||
## 目标与非目标
|
||
|
||
### 目标
|
||
|
||
- HTTP 入口只信任 `CurrentUserContext.tenant_id`,内部任务只接受显式、已注册且启用的 `trusted_tenant_id`。
|
||
- 本体解析在任何模型调用前创建租户化 `AgentRun`,商业运行上下文和失败证据可追溯。
|
||
- 员工、组织、费用、应收、应付、画像、风险、提醒和看板查询在首个 SQL 中限定租户。
|
||
- 员工画像仅允许本人、直属领导、财务/高管或管理员读取;越权和跨租户统一返回 404。
|
||
- 财务报告按租户配置收件人、生成内容、存储文件和幂等运行账本,不使用全局邮件回退。
|
||
- 所有 Hermes 定时任务逐个枚举 `status=active` 的企业,运行记录同时在 route/ontology 保存租户快照。
|
||
|
||
### 非目标
|
||
|
||
- 不提供客户端选择或覆盖租户的兼容参数。
|
||
- 不实现跨企业合并分析、集团穿透报表或平台运营后台。
|
||
- 不在本切片中重构预算分配等仍属旧模型的全部业务域。
|
||
|
||
## 信任边界
|
||
|
||
```text
|
||
HTTP 请求 ── CurrentUserContext.tenant_id ─┐
|
||
├─→ tenant-scoped AgentRun
|
||
内部任务 ── active trusted_tenant_id ──────┘ ├─ route_json.tenant_id
|
||
└─ ontology_json.tenant_id
|
||
```
|
||
|
||
- 客户端 `context_json.tenant_id` 会被可信租户覆盖,不能参与授权。
|
||
- 同时传入登录用户和内部租户时,两者必须一致。
|
||
- 内部任务租户必须存在于租户注册表且状态为 active;缺失、停用或不存在均在创建 Run 前拒绝。
|
||
- 后台消费者从数据库 Run 恢复租户,并校验 route/ontology 两份快照一致。
|
||
|
||
## 功能设计
|
||
|
||
### 本体解析
|
||
|
||
- 接口覆盖请求中的 user id,并把认证企业传给 `SemanticOntologyService`。
|
||
- `parse()` 先建立 `running/pending_model_analysis` Run,再加载租户字典、商业运行上下文并调用模型。
|
||
- 模型、规则降级和失败路径都更新同一 Run;失败不会留下无企业、无状态的调用。
|
||
- 员工、部门、费用申请、应收、应付和项目参考目录均以租户作为第一层 SQL 条件。
|
||
|
||
### 员工画像
|
||
|
||
- 快照保存 `tenant_id`,并用 `(tenant_id, subject_id)` 复合外键绑定员工。
|
||
- Profile Service 的快照、费用单和 Agent Run 查询均先限定租户。
|
||
- 详情接口先在当前企业解析目标员工,再执行本人/直属领导/财务/高管/管理员访问矩阵。
|
||
- 附带 `claim_id` 时必须同时属于目标员工和当前企业。
|
||
|
||
### Hermes 与数字员工
|
||
|
||
- 风险扫描、画像扫描、风险线索、提醒扫描和看板均接受显式租户。
|
||
- 调度器只枚举 active 企业,并为每个企业独立创建任务与结果。
|
||
- 看板只统计 route/ontology 租户快照均匹配的 Run;缺少或冲突快照的历史记录不会被猜测归属。
|
||
- 提醒任务的费用单、员工和关联报销查询在首个 SQL 限制当前企业。
|
||
|
||
### 财务分析报告
|
||
|
||
- `TenantFinanceReportConfig` 保存企业启停状态和经校验的收件人。
|
||
- `TenantFinanceReportRun` 以 `(tenant_id, idempotency_key)` 防止同企业同周期重复发送。
|
||
- 报告上下文只读取当前企业的费用、风险、画像和 Agent Run。
|
||
- 邮件发送只使用当前企业配置;未配置、停用或无有效收件人时 fail-closed。
|
||
- 文件存储目录使用企业标识哈希,避免路径注入和跨企业文件覆盖。
|
||
|
||
## 数据与迁移
|
||
|
||
`20260717_0028_hermes_ontology_tenant_security.py` 完成:
|
||
|
||
- 员工行为画像、Hermes 任务配置/日志和风险报告新增租户列、索引、唯一约束和复合外键。
|
||
- 新增租户财务报告配置和周期运行账本。
|
||
- 旧记录回填为 `default`,再移除 server default,后续写入必须显式确定企业。
|
||
- 仅支持 PostgreSQL;upgrade/downgrade 在任何 DDL 前检查方言,其他数据库直接拒绝。
|
||
- downgrade 在存在非默认企业事实或报告账本时拒绝有损回滚。
|
||
|
||
## 降级与回滚
|
||
|
||
- 租户缺失、停用、不存在或上下文冲突:不创建 Run、不查询业务数据。
|
||
- 跨企业员工、画像、费用单:统一按不存在处理。
|
||
- 企业未配置报告收件人:保留失败/跳过证据,不回退环境变量中的全局地址。
|
||
- 历史 Run 没有双租户快照:看板不纳入企业统计。
|
||
- 生产升级前必须在数据库备份副本演练 `0027 → 0028 → 0027 → 0028`。
|
||
|
||
## 测试与验收
|
||
|
||
- 两企业本体目录、画像 IDOR、Hermes 扫描、风险线索、看板和报告内容/收件人/路径/幂等隔离。
|
||
- Orchestrator 缺租户、停用租户、不存在租户和认证/内部租户冲突均在 Run 前拒绝。
|
||
- 本体模型调用前存在 running Run,失败后仍保存同企业失败证据。
|
||
- PostgreSQL 完成 fresh `base → 0028`、`0028 → 0027 → 0028` 及旧表回填/外键验证。
|
||
- 所有后端测试和 Ruff 均在 `local-x-financial-linux` 容器内执行,单命令不超过 60 秒。
|
||
|
||
## 本轮实现记录
|
||
|
||
- 2026-07-17:完成本体解析前置 Run、可信商业上下文和租户参考目录。
|
||
- 2026-07-17:完成员工画像模型、服务和 API 的租户隔离与访问矩阵。
|
||
- 2026-07-17:完成 Hermes 扫描、提醒、看板、调度和财务报告的逐租户运行。
|
||
- 2026-07-17:完成 `20260717_0028` PostgreSQL 迁移、反向回滚和安全回归。
|