Skip to content

企业身份与归属模型 ​

平台上同时存在两套用户体系:平台运营,和客户企业。 企业是实体(可以独立存在),Agent 是业务单元(服务于某家企业,也可以不属于任何企业)。 这两件事分开回答,是这一页的全部内容。


四类主体 ​

平台运营(system.user/role/dept)          客户侧(user_client)
        │                                        │
        │ 管平台参数                             ├─ 企业组织 organization(实体)
        │                                        │     ├─ ownerUserIds(管理员名单)
        ▼                                        │     ├─ reviewStatus(审核状态)
  /sys/* 后台接口                                │     └─ approval-policy(版本化策略)
                                                 │
                                                 └─ Agent(业务单元)
                                                       ├─ ownerId(主所有者)
                                                       ├─ ownerIds(共同维护人)
                                                       └─ organizationId(归属企业,可选)
主体存在哪回答什么问题
平台运营system 的 user / role / dept(MySQL)谁能改平台参数、看全局
终端用户user_client(MySQL)谁在平台上注册、用服务
企业组织/master/organization/{orgId}(主数据,版本化)这是哪家企业、谁在管它、审核到哪一步
业务单元(Agent)agent-profiles(MongoDB)这个 Agent 提供什么能力、属于谁、服务哪家企业

双轨身份:两套判定,绝不混用 ​

平台运营客户企业
用户表system 的 user / role / deptuser_client(没有角色字段)
判定依据@RequiresRoles(['admin','system']) + 角色守卫组织管理员名单 ∪ Agent owner
管什么平台参数、全局运营、排障自己的企业、自己的 Agent

不能用平台角色管客户:那会出现「平台运营能改客户审批链」或「客户 owner 需要平台发角色」的双重错位。 也不能用客户身份管平台:客户侧没有角色表,只有 owner 关系。

客户侧判定:两条来源取并集 ​

能管这家企业 ⇔ userId ∈ organization.ownerUserIds           ① 组织自己的管理员名单
             ∪  userId 是「归属该企业的某个 Agent」的
                      ownerId / ownerIds                   ② 业务单元的维护人
  • ① 建组织的人自动进入 ownerUserIds —— 所以没有 Agent 也能建企业并管理它
  • ② Agent 挂进企业后,它的 ownerId / ownerIds(共同维护人)同样算这家企业的管理员
  • 两条都不命中 ⇒ 拒绝;platform / system 视同所有者(排障与系统任务);外部 API 客户端拒绝
  • fail closed:空 userId、查不到记录、脏数据(ownerId: '' / ownerIds: [''])一律不放行

三层归属:每个数据只回答一个问题 ​

层数据归属字段性质
组织/master/organization/{orgId}ownerUserIds、reviewStatus主数据(唯一 + 版本留痕)
业务单元agent-profiles.organizationId指向组织;可选业务归属,不填即与任何企业无关
运行时事实/orders/{orderId}/approvals/{orgId}/master/approval-policy/{orgId}事件(仅追加)+ 版本化配置

规则:Agent 归属企业是可选的。未归属的 Agent 仍能上架、接单、被派单,只是不会出现在 /organization/mine 与企业管理页里。这正是「平台预置 + 用户认领」与「用户自建」两条 Agent 来源 都不受企业约束的原因。


组织生命周期 ​

① 创建           任何登录用户都能建(不要求先有 Agent)
   └─ 产出 reviewStatus = 'pending'(未审核;审核流程后期做)
                    ownerUserIds = [创建者]

② 接入 Agent      可选。两种顺序都成立:
                   · 建组织 → 之后在「我的 Agent」里选归属企业
                   · 先有 Agent → 建组织时顺手填 agentId(校验该 Agent 属于调用者)

③ 配审批链        /master/approval-policy/{orgId}
                   每次实质变更追加一版(actor + at + note + diff),决策可反查「按哪版批的」

④ 跑决策          /orders/{orderId}/approvals/{orgId}
                   结果带 rule_version(策略内容版本)与 policy_version(库里的版本号)

为什么这样设计 ​

为什么企业不挂在 Agent 上 ​

因为「谁是这家企业的管理员」和「这个 Agent 服务哪家企业」是两个问题。 早期把前者也交给 Agent owner 回答,代价是:一个人没有 Agent 就建不了企业。 现在的取舍是承认两条来源,允许它们出现分歧(Agent 转走、组织管理员仍在)—— 这个分歧是刻意的,也是现实里企业该有的样子。

为什么企业创建先开放、审核只留字段 ​

企业资质审核需要真实运营流程(谁批、批什么材料、驳回后能不能重提)。 先把状态字段和读取入口做出来(reviewStatus),审核动作留到有运营能力时再加, 避免为了一个没有执行者的流程挡住所有企业注册。

为什么组织与策略都放主数据域 ​

它们都是结构(唯一、低频写、高频读),不是事实(事件流)。 主数据域已经解决了「唯一约束 + 版本历史 + 乐观并发」,再写一套只会让审计出现两个口径。 运行时的审批决策才是事实,落 state 事件。


与既有架构的关系 ​

既有能力与本模型的关系
主数据域(master-data)组织与审批策略的存储与版本化都复用它
状态层(state)审批决策是仅追加事件,带 actor / 因果链
一致性阶梯 L4(multi-org-approval)审批链的判定逻辑仍是一份纯函数 + 配置;企业数据只是配置的来源
门面 Agent 双面隔离(resolveAudience)客户侧身份判定的纯函数收口,本页的「来源 ②」直接复用

边界(当前明确不做) ​

  • 多准则并行 / 组织层级合并:只做维度隔离(谁能看到哪条记录)
  • 币种换算、重估、汇兑损益:只做记账与显示精度
  • 审批链的代理人、加签、会签:只做金额阈值 + 角色顺序
  • 企业资质审核流程:只有 reviewStatus 字段与展示,没有审批动作
  • 组织成员的两级角色(管理员 / 普通成员):当前只有「是不是管理员」

Released under the MIT License.