# 租户 / 组织 / 人员 / 访客 — 数据模型、表关系与用例 **文档性质**:架构梳理(电梯仓 + 组织组件约定)。 **校验状态**:已使用 [`tools/visitor_floor_verification/.env.visitor_verify`](../../maven-cw-elevator-application/tools/visitor_floor_verification/.env.visitor_verify) 所列主机(本地开发库)执行 **`INFORMATION_SCHEMA` + 抽样查询**,纪要见 **§6.1**(日期 **2026-04-30**)。其它环境仍以现场库为准。 **关联精读**:[访客注册与派梯楼层 — 业务流程](../testing/visitor-registration-business-flow.md)、[租户访客默认楼层隔离边界](../testing/tenant-visitor-default-floor-isolation.md)。 --- ## 1. 术语与请求上下文 | 术语 | 含义 | 典型落点 | |------|------|----------| | **租户 / 机构 ID** | 多租户数据隔离边界 | HTTP Header **`businessid`** → `FeignThreadLocalUtil` → `CloudwalkCallContext.company.companyId` | | **`business_id`(库列)** | 与上下文 **`businessid`** 相同的字符串 | 组织库 `cw_is_organization.BUSINESS_ID`、`cw_is_person.BUSINESS_ID`;电梯库 `tenant_visitor_floor_policy.business_id`、`image_rule_ref.business_id` | | **组织节点 ID** | 机构树上一节点(公司、部门等) | `cw_is_organization.ID`;父子关系 **`PARENT_ID` → `ID`** | | **人员主键 `personId`** | API / 组件语境的人员 ID | 对应组织库 **`cw_is_person.ID`**(导出 CSV 列名为 **`ID`**) | | **被访人** | 接待访客的员工 | `add/visitor` 请求体字段 **`personId`**(勿与访客混淆) | | **访客** | 访客档案 | 请求体 **`visitorId`**;派梯写库时 **`image_rule_ref.person_id` = 访客 ID** | **关键辨析** - **`business_id` 不是 `cw_is_organization` 的主键**。组织节点主键为 **`ID`**;**`BUSINESS_ID`** 是在**同一租户下多行组织节点上重复出现**的作用域字段。 - 跨库之间**不存在**数据库级外键;一致性依赖 **`business_id`** 与 **`cw_is_person.ID`**(API 字段 `personId`)。关联表 **`cw_is_person_organization_ref.PERSON_ID`** 存储的也是该 **`ID`**。 --- ## 2. 数据库边界(两库) ```mermaid flowchart TB subgraph orgLib [component_organization] O[cw_is_organization] P[cw_is_person] R[cw_is_person_organization_ref] L[cw_is_person_label_ref] LB[cw_is_label] end subgraph elevLib [cw_elevator_application] POL[tenant_visitor_floor_policy] IRR[image_rule_ref] end O -->|"树 PARENT_ID"| O R -->|"ORG_ID"| O R -->|"PERSON_ID"| P L -->|"PERSON_ID"| P L -->|"LABEL_ID"| LB POL -.->|"business_id 对齐 BUSINESS_ID"| P IRR -.->|"business_id"| P IRR -.->|"person_id 常为访客"| P ``` --- ## 3. 逻辑 ER(组织库) 组织侧表无权威 DDL 收于本仓库;下列字段来自导出脚本、测试文档与 [`export_catalog.py`](../../maven-cw-elevator-application/tools/visitor_floor_verification/scripts/export_catalog.py) 中的 SQL 用法。 ```mermaid erDiagram cw_is_organization { string ID PK "组织节点" string PARENT_ID FK "父节点 ID 可空" string BUSINESS_ID "租户范围重复列" string NAME "节点名称" } cw_is_person { string ID PK "人员主键 API personId" string BUSINESS_ID "租户" string NAME "姓名" int IS_DEL "是否删除" } cw_is_person_organization_ref { string PERSON_ID FK "人员" string ORG_ID FK "组织节点" } cw_is_organization ||--o{ cw_is_organization : "parent_child" cw_is_person ||--o{ cw_is_person_organization_ref : "membership" cw_is_organization ||--o{ cw_is_person_organization_ref : "org_node" ``` **`cw_is_person` 列名与访客判定** - 仓库内导出示例 [docs/testing/_cw_is_person__202604302030.csv](../testing/_cw_is_person__202604302030.csv) 表头为 **`ID`**, **`BUSINESS_ID`**, **`IS_DEL`** 等,与 **2026-04-30 开发库**一致。 - 开发库 **`cw_is_person` 不存在**列:`person_id`、`deleted`、`labels`、`business_name`、`organization_name`。访客标签通过 **`cw_is_person_label_ref`**(`PERSON_ID`、`LABEL_ID`)关联 **`cw_is_label`**(含 `BUSINESS_ID`、`NAME`);示例租户下 **`NAME='访客'`** 对应 **`LABEL_ID=ed2dbab6d6234a7287106b80857c819e`**。 --- ## 4. 逻辑 ER(电梯库) 依据 [`tenant_visitor_floor_policy.sql`](../../maven-cw-elevator-application/releases/v2.0.0/ddl/tenant_visitor_floor_policy.sql) 与 [`ImageRuleRefMapper.xml`](../../maven-cw-elevator-application/cw-elevator-application-data/src/main/java/cn/cloudwalk/elevator/record/mapper/ImageRuleRefMapper.xml)。 ```mermaid erDiagram tenant_visitor_floor_policy { string id PK string business_id "租户 UK 组成部分" string policy_type "如 INTERSECT_ALLOWLIST" text allow_zone_ids "JSON zoneId 数组" string building_id "预留楼栋维度可空" int enabled bigint policy_version } image_rule_ref { string id PK string business_id string zone_id "楼层区域" string zone_name string parent_rule "父规则" string person_id "访客开通场景为访客" int person_delete string include_labels string include_organizations int is_default } ``` **访客默认楼层策略语义(UC-01,未传 `floorIds`)** - **规范**:启用租户访客策略且 **`allow_zone_ids` 非空**时,组织 **`PersonService.detail`** 应将 **`floorList` 替换为 `allow_zone_ids`(替代,非 ∩)**;电梯 **`addVisitor`** 仅使用 `personResult.getFloorList()`,**不再**在电梯侧与 allow 求交。 - 详见 [`PersonRuleServiceImpl#addVisitor`](../../maven-cw-elevator-application/cw-elevator-application-service/src/main/java/cn/cloudwalk/elevator/person/impl/PersonRuleServiceImpl.java)、[迁入组织组件规格](../superpowers/specs/2026-05-06-tenant-visitor-policy-organization-implementation.md) 与 [租户访客默认楼层-数据库配置阶段技术设计](../business/租户访客默认楼层-数据库配置阶段技术设计.md)。 --- ## 5. 角色与派梯用例(电梯侧) ```mermaid flowchart LR actor Caller as Caller_BFF participant API as AcsPersonController participant PR as PersonRuleServiceImpl participant Org as PersonService_detail participant IRR as ImageRuleRefDao participant Img as ImageStorePersonService Caller -->|"POST_add_visitor"| API --> PR PR --> Org PR --> IRR PR --> Img ``` ```mermaid flowchart TD subgraph UC01 [UC01不传floorIds] U1[add_visitor] U2[detail_host_floorList已含策略替代] U4[write_image_rule_ref_visitor] U5[batchBind_visitor] U1 --> U2 --> U4 --> U5 end subgraph UC02 [UC02显式floorIds] V1[add_visitor] V2[detail校验被访人] V2b[effective=请求floorIds] V3[write_rules_bind] V1 --> V2 --> V2b --> V3 end subgraph UCRead [回读验收] R1[passRule_image_personId_visitor] end ``` --- ## 6. 附录:现场核对 SQL 与纪要 ### 6.1 开发库核对纪要(2026-04-30) 以下为使用 **`maven-cw-elevator-application/tools/visitor_floor_verification/.env.visitor_verify`**(主机、端口、账号由本地填写,**勿将密钥写入 Git**)连接所得摘要: | 项目 | 结果 | |------|------| | 根机构 **`BUSINESS_ID=2524639890ba4f2cba9ba1a4eeaa4015`** | 节点 **`NAME=星河湾中心`**,`ID=d656e3ab3f61440bb7b9bc23b76834b9`,**与 `BUSINESS_ID` 字符串不相等** | | `cw_is_person` | 主键列 **`ID`**;删除 **`IS_DEL`**;**无** `person_id`、`deleted`、`labels`、`business_name`、`organization_name` | | `cw_is_organization` | 含 **`ID`、`PARENT_ID`、`BUSINESS_ID`、`NAME`、`IS_DEL`** 等(大量 `EXT*`) | | `cw_is_person_organization_ref` | **`ID`、`PERSON_ID`、`ORG_ID`** 及审计列 | | `cw_is_person_label_ref` / `cw_is_label` | 用于人员标签;访客标签 **`NAME='访客'`** 对应 **`LABEL_ID=ed2dbab6d6234a7287106b80857c819e`**(该租户) | | `information_schema.TABLE_CONSTRAINTS` | 上述组织表 **仅有 `PRIMARY KEY` / `UNIQUE`**,**未声明 FOREIGN KEY** | | `cw-elevator-application.tenant_visitor_floor_policy` | 列与仓库 DDL 一致;示例租户 **`enabled=1`**,`allow_zone_ids` 含 **`605560545117995008`** | ### 6.2 INFORMATION_SCHEMA 模板(任意环境) ```sql -- 组织库:核心表列一览 SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'component-organization' AND TABLE_NAME IN ( 'cw_is_organization', 'cw_is_person', 'cw_is_person_organization_ref', 'cw_is_person_label_ref', 'cw_is_label' ) ORDER BY TABLE_NAME, ORDINAL_POSITION; -- 根节点与 BUSINESS_ID 是否相等(现场逐项核对) SELECT ID, PARENT_ID, BUSINESS_ID, NAME FROM cw_is_organization WHERE BUSINESS_ID = '2524639890ba4f2cba9ba1a4eeaa4015' ORDER BY ID LIMIT 20; -- 电梯库:策略表列 SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'cw-elevator-application' AND TABLE_NAME IN ('tenant_visitor_floor_policy', 'image_rule_ref') ORDER BY TABLE_NAME, ORDINAL_POSITION; ``` --- ## 7. 文档索引(与本模型一致) | 文档 | 用途 | |------|------| | [visitor-registration-business-flow.md](../testing/visitor-registration-business-flow.md) | 被访人 / 访客 / 楼层源码链路 | | [visitor-registration-floor-validation.md](../testing/visitor-registration-floor-validation.md) | 测试矩阵与现场组织示例 | | [tenant-visitor-default-floor-isolation.md](../testing/tenant-visitor-default-floor-isolation.md) | `business_id` 粒度与隔离边界 | | [租户访客默认楼层-数据库配置阶段技术设计.md](../business/租户访客默认楼层-数据库配置阶段技术设计.md) | **替代**语义与迁移(历史文档含「求交」表述处以 2026-05-06 规格为准) |