# 租户访客默认楼层:技术产品方案 > **文档类型**:产品与工程技术方案(含**登记页数据项与接口溯源**、端到端闭环、数据模型与实施路线)。 > **前置阅读**:[访客注册与派梯楼层业务流程走查](访客注册与派梯楼层业务流程走查.md)(UC-01~UC-06、对外 HTTP/Feign 与代码位置)。 > **关联工程**:[Maven 聚合工程说明](../architecture/Maven聚合工程说明.md)(`maven-cw-elevator-application`、`maven-intelligent-cwoscomponent` 等边界)。 --- ## 1. 背景与问题陈述 ### 1.1 业务背景 多租户部署下,不同机构对**访客可达楼层**的策略不一致: - **默认诉求**:访客开通派梯时,若业务侧**不显式传楼层列表**(与 [UC-01](访客注册与派梯楼层业务流程走查.md) 一致),系统仍应开通派梯,但**不应简单等同于被访人组织侧 `floorList` 全集**。 - **典型例子(产品化名)**:**「广发基金」类租户**要求:访客**默认仅可派梯至 28 楼**(或某固定接待层),而被访人本人在组织中可能仍具备多层办公权限。 ### 1.2 `floorIds` 是谁的字段、空与非空分别代表什么 #### 1.2.1 字段归属(哪个主体的属性) `floorIds` **不是**组织人员主数据里「被访人」的持久化字段,也**不是**访客人员档案在组织库里的固定属性;在现有实现中,它是 **电梯应用对外接口** 的一次请求参数。 | 项目 | 说明 | |------|------| | **载体** | HTTP **`POST /elevator/person/add/visitor`** 的请求体(`AcsPersonAddVisitorForm` / 服务层 `AcsPersonAddVisitorParam`,见 `maven-cw-elevator-application`)。 | | **语义** | **本次「给访客开通派梯」操作**中,调用方希望电梯在哪些 **空间分区(`zoneId`)** 上为 `visitorId` 写入默认通行规则并绑图库。 | | **主体** | 归属主体是 **「派梯开通请求」**(一次 API 调用),由 **调用方**(第三方 BFF、访客业务后台、或 `intelligent-cwoscomponent-rest` 等)填入;电梯服务**读取**后执行落库与远程绑图库。 | 因此:在集成文档中应写清——**`floorIds` 列出的是「本次开通涉及的楼层 zoneId 列表」,由调用方在请求时提供;缺省(空)时电梯才按约定去组织侧拉被访人的 `floorList` 补全。** #### 1.2.2 `floorIds` 非空时:业务含义与电梯行为 当调用方传入 **非空** `floorIds` 时(走查文档中的 **UC-02:访客派梯-第三方指定楼层**): | 项目 | 说明 | |------|------| | **业务含义** | 调用方已明确「本次访客只(或优先)开通这些楼层」的意图;常见来源包括:登记/审批流程里已算好的**生效楼层**、访客在允许范围内**勾选的多层**、或业务规则直接指定的接待层列表。 | | **电梯侧行为** | **不再**为补楼层去调 **`POST /component/person/detail`**;直接使用请求中的 `floorIds` 作为待写入规则的楼层列表,后续步骤(`zone/page` 取楼栋、`getDefaultByZoneId`、写 `image_rule_ref`、`batchBind` 等)与「列表来自组织补全」时相同,**仅楼层列表来源不同**。 | | **责任边界** | **正确性、合法性、与租户策略及被访人授权的一致性**由调用方负责(或通过 BFF 统一校验);电梯按列表执行;若需「仍不得超过被访人 `floorList`」的硬约束,须在 **BFF、intelligent 或电梯增强**中择一层实现(见 §4、§5)。 | #### 1.2.3 为什么调用方会选择「非空」(不依赖空列表) | 动机 | 说明 | |------|------| | **与 UI/审批结果一致** | 登记页或审批单已确定可访楼层,开通时**显式写入**同一列表,避免电梯侧再解释「默认」。 | | **多租户策略在域外已算完** | 推荐做法(§4):在第三方 BFF 做 `tenantAllow ∩ hostFloors`,把结果作为 `floorIds` 传入,电梯无需理解租户表。 | | **避免 UC-01 与产品语义冲突** | 不传 `floorIds` 时电梯等价于「被访人 `floorList` 全集」;若产品要「小于全集」,**应传非空** `floorIds`,否则现网电梯逻辑无法满足。 | | **集成契约清晰** | 显式列表便于审计、重放、幂等比对(可与登记快照 `effective_preview_json` 逐字一致)。 | #### 1.2.4 `floorIds` 为空时:电梯侧补全(与上文对照) 当前电梯侧实现(`PersonRuleServiceImpl.addVisitor`)在 **`floorIds` 为空或缺省** 时: 1. 调用组织 **`/component/person/detail`**(`personId` + `businessId`); 2. 将返回的 **`PersonResult.getFloorList()`** 赋给本次执行使用的楼层列表; 3. **不使用** `defaultFloor` 单字段作为补全依据。 因此:**仅在「调用方不传 `floorIds`」这一模式下**,现网电梯无法表达租户级收敛;多租户默认接待层需在 **调用方传非空 `floorIds`** 或 **电梯/ BFF 增强兜底** 中实现(见全文 §4、§6)。 ### 1.3 文档目标 | 维度 | 目标 | |------|------| | **产品** | 定义租户策略、角色权限、配置流程、登记/邀约 **UX 与开通结果一致**、验收标准。 | | **闭环** | 从**第三方系统在注册/邀约流程中初始化访客登记页**开始,明确**每个数据项从哪个系统、哪类接口获取**;经提交、审批(若有)到 **`add/visitor`** 生效,并给出**一致性校验**与回读建议。 | | **技术** | 可选架构、推荐组合、数据模型与接口草案、改造边界、安全求交、**多租户默认访客楼层的实现路径综合评估**。 | --- ## 2. 端到端闭环:从第三方登记页初始化到派梯生效 本章回答:**登记页打开时要拉哪些数据、按什么顺序调接口、算出什么给 UI 存什么草稿、审批后如何与电梯开通对齐**,从而形成可审计、可测试的闭环。 ### 2.1 闭环目标 | 目标 | 说明 | |------|------| | **同源计算** | 「页面上展示的预计可派梯楼层」与「最终调用 `add/visitor` 的 `floorIds`(或电梯兜底前的逻辑输入)」由**同一套规则函数**得出,避免两套逻辑漂移。 | | **接口可追溯** | 每个 UI 字段可映射到**具体外部接口或本地配置**;本仓库已明确的接口见走查文档 §3~§4。 | | **租户可配置** | `businessId`(机构 ID)贯穿上下文;租户策略变更后,**进行中的登记单**行为需在产品中定义(见 §2.7)。 | ### 2.2 阶段划分(第三方视角) | 阶段 | 名称 | 参与系统 | 产出 | |------|------|----------|------| | **P0** | 登记页/邀约页 **初始化** | 第三方 + 组织 + 空间 +(可选)租户策略服务 | 表单默认值、`effectiveFloorsPreview`、可选楼层展示文案 | | **P1** | 用户填写与 **校验** | 第三方前端 + 后端 | 通过校验的草稿 DTO | | **P2** | **提交**登记/发起邀约 | 第三方 DB、工作流引擎 | 业务主键、状态机(待审批/已登记) | | **P3** | **审批**(若存在) | 第三方审批流 | 通过/驳回;通过则触发 P4 | | **P4** | **组织侧** 写入访客人员、拿到 `visitorId` | 组织/访客模块(**不在本反编译仓**,以实际 API 为准) | `visitorId` | | **P5** | **派梯开通** | 第三方或 intelligent → **电梯** `POST /elevator/person/add/visitor` | 规则写入、图库绑定 | | **P6** | **回读与告知** | 第三方查询电梯/通行结果或异步任务状态 | 与 P0 展示一致的「已开通楼层」说明 | ### 2.3 访客登记/邀约页:数据项定义与数据来源 下表面向**第三方业务系统**实现同学:列的是**逻辑字段**;物理表名由各自系统定义。接口路径以走查文档为准;**组织人员搜索**(选被访人)在走查中未展开,行内标注为**待对接清单**。 | 逻辑数据项 | 典型 UI 表现 | 数据来源 | 接口或服务(已知/占位) | 关键入参 / 出参 | 与租户楼层关系 | |-------------|--------------|----------|---------------------------|-----------------|----------------| | **租户/机构 ID** | 隐藏或顶部切换 | 登录态 / 网关注入 | 上下文 `businessId`,与 `CloudwalkCallContext.company` 一致 | `businessId` | 策略表主键维度 | | **被访人 `personId`** | 选人组件 | **组织人员检索**(具体路径以 `ninca-common-component-organization` 或网关文档为准) | 占位:`POST .../person/page` 或等价检索 API | 选中行 → `personId` | 后续 `detail` 入参 | | **被访人姓名/部门等展示** | 选人后回显 | 同上检索结果或二次 `detail` | 检索结果字段 **或** `POST /component/person/detail` | `PersonResult` 展示字段 | 非楼层核心 | | **被访人授权楼层 ID 列表 `hostFloors`** | 一般不直接展示 ID | **组织**(与电梯 UC-01 同源) | **`POST /component/person/detail`** | 请求:`id`=被访人 `personId`,`businessId`;响应:`PersonResult.floorList` | 求交上界 | | **`defaultFloor` / `floorInfoList` 等** | 若产品要展示「默认办公层」文案 | **组织** `detail` 同响应 | 同上 | `PersonResult.defaultFloor`、`floorInfoList` | **电梯补全不用 `defaultFloor`**;若 UI 用其展示,须与 `floorList` 语义对齐(走查 §8 风险 1) | | **空间树/楼层名称** | 楼层中文名、楼栋 | **空间服务** `ninca-common` | **`POST /sysetting/zone/tree`**、**`POST /sysetting/zone/page`** | 用 `hostFloors` 中 `zoneId` **反查** `zoneName`、楼栋 | 仅展示增强 | | **租户访客楼层策略** | 管理员配置页;登记页可不直接展示 | **租户策略存储**(自建表或配置中心) | 草案 §4.3 管理 API **或** 第三方本地表 + 管理端 | `policy_type`、`allow_zone_ids`、版本号 | **与 `hostFloors` 求交**得预览 | | **`effectiveFloorsPreview`** | 「本次访问预计可开通派梯的楼层」 | **计算字段**(禁止手写死) | `computeEffective(policy, hostFloors, userOverride?)` | 输出 `List`,可附 `displayNames` | **必须与 P5 输入一致** | | **访客可选楼层(若产品允许访客改)** | 多选框,默认选中 `effectiveFloorsPreview` | `effectiveFloorsPreview` 的子集 | 前端约束:用户勾选 ⊆ 预览集 | 提交 `userSelectedZoneIds` | 高敏租户可关闭多选 | | **访客姓名、证件、事由、到访时间等** | 表单 | 用户输入 + 机构规则 | 第三方本地 | — | 与楼层正交 | | **人脸/照片** | 采集/上传 | 用户 + 第三方存储 | 组织图库/人像接口以实际为准 | — | 走查未展开 | | **策略版本号 `policyVersion`** | 可不展示 | 租户策略表 | 读取策略时返回 | 写入登记草稿 | 审计与回放 | | **登记单草稿持久化** | — | 第三方 DB | 本地表建议字段:`draft_id, business_id, host_person_id, host_floors_snapshot_json, policy_snapshot_json, effective_preview_json, policy_version, status` | P5 时读出 `effective_preview` 或重算 | 支持审批前后回放 | **不在本仓库的接口**(须在集成清单中单独列出):访客人员创建、`visitorId` 发放、审批流回调 URL、人像入库等——闭环在 P4 前依赖这些能力,本文仅要求:**P5 的 `floorIds` 与 P0 预览同源**。 ### 2.4 接口编排顺序(推荐:登记页初始化一次请求链) 第三方**后端聚合接口**(推荐由自有 **BFF** 实现,避免前端直连多枚令牌)建议内部按序调用: ``` 1) 校验 businessId、操作者权限 2) GET 租户访客楼层策略(若无则视为 HOST_FLOOR_LIST) 3) POST /component/person/detail(id=被访人 personId, businessId) → 得 hostFloors = floorList(可能 null/空) 4) computeEffective(policy, hostFloors, requestedFromClient=null) → 若空:返回明确错误码,登记页展示「无法为该被访人开通访客派梯,请联系管理员」 5) 可选:POST /sysetting/zone/page 或 tree 子集调用,将 zoneId 映射为 zoneName / 楼栋 6) 返回给前端:{ hostPerson, effectiveFloorsPreview, displayNames, policyVersion, warnings } ``` 前端**仅展示**第 6 步结果,**不在前端重复实现求交**(防篡改可签短期 token 或仅信服务端字段)。 ### 2.5 可选:统一「预览」能力(降低集成方重复劳动) 可在 **第三方 BFF** 或 **intelligent** 增加只读接口(路径示例): | 方法 | 路径(示例) | 入参 | 出参 | |------|----------------|------|------| | `POST` | `/api/visitor/register/preview-floors` | `businessId`, `hostPersonId`, 可选 `userSelectedZoneIds` | `hostFloors`, `tenantPolicy`, `effectiveZoneIds`, `displayFloors[]`, `policyVersion`, `canSubmit` | **契约**:`effectiveZoneIds` 的计算规则须与 P5 调用 `add/visitor` 时组装的 `floorIds` **完全一致**(同一服务端模块单元测试)。 ### 2.6 P5 派梯开通:与登记页的衔接 | 路径 | 做法 | |------|------| | **推荐(方案 B)** | 审批通过后,从登记单读出 **快照**或 **用相同函数重算**(若策略允许重算):组装 **`floorIds` = `effectiveZoneIds`**,调用 **`POST /elevator/person/add/visitor`**(或 `ElevatorPersonFeignClient.addVisitor`),走 **UC-02**。 | | **兜底(方案 C/D)** | 若历史集成方坚持不传 `floorIds`,则由电梯或 intelligent 在服务端求交(见 §4);登记页仍应按 §2.3 展示**与兜底后一致**的预览(通过同一预览 API 或文档约定算法)。 | **时间参数**:`begVisitorTime` / `endVisitorTime` 与走查一致,须与登记单有效期对齐。 ### 2.7 闭环一致性:策略中途变更、重试与幂等 | 场景 | 产品建议 | |------|----------| | 管理员在**登记草稿未提交**时修改策略 | 下次打开登记页重新走 P0,**以新策略为准**。 | | 草稿已提交、**待审批**期间策略变更 | 二选一并在需求中写死:**(a)** 审批节点展示「策略已变更请重审」并阻塞直到人工确认;**(b)** 以提交时刻 `policyVersion` **冻结**计算结果,审批通过仍按旧结果开通(需评估合规)。 | | **审批通过瞬间**策略变更 | P5 使用**出队消息中的快照** `effective_preview_json`,避免 TOCTOU。 | | 重复点击开通 | `visitorId` + 时间窗幂等;与电梯侧是否已存在规则引用需对齐(可查电梯侧人员规则再调,属增强项)。 | ### 2.8 端到端泳道图(闭环) ```mermaid sequenceDiagram participant U as 访客用户 participant FE as 第三方前端 participant BFF as 第三方BFF participant Pol as 租户策略存储 participant Org as 组织 person/detail participant Zone as 空间 zone/tree|page participant Reg as 第三方登记库 participant Apv as 审批流 participant OrgW as 组织写访客 participant Elv as 电梯 add/visitor U->>FE: 打开登记页 FE->>BFF: 初始化(被访人personId) BFF->>Pol: 读策略(businessId) BFF->>Org: detail(personId) Org-->>BFF: floorList BFF->>BFF: computeEffective opt 展示楼层名 BFF->>Zone: page/tree(zoneIds) Zone-->>BFF: names end BFF-->>FE: 预览+policyVersion U->>FE: 填写并提交 FE->>BFF: 提交草稿 BFF->>Reg: 持久化快照 Reg-->>FE: draftId opt 需审批 BFF->>Apv: 发起 Apv-->>BFF: 通过+token end BFF->>OrgW: 创建访客→visitorId BFF->>Elv: add/visitor(visitorId,personId,floorIds=effective,...) Elv-->>BFF: 成功/失败 BFF-->>FE: 结果与楼层说明 ``` --- ## 3. 产品方案 ### 3.1 目标用户与角色 | 角色 | 职责 | |------|------| | **平台/租户管理员** | 在本机构内配置「访客默认楼层策略」、维护允许的 `zoneId` 列表或与楼栋的映射、查看审计日志。 | | **被访人员工** | 日常办公权限仍在组织侧维护;不强制要求其理解访客策略。 | | **访客** | 通过邀约/登记获得限时通行;仅应看到**实际可派梯楼层**(与开通结果一致)。 | | **运维/实施** | 将「28 楼」等业务语言映射为空间服务中的 **`zoneId`**,并录入策略或导入模板。 | ### 3.2 用户故事(示例) 1. **作为租户管理员**,我希望为本机构配置「访客默认仅开放指定楼层集合」,以便满足物业/合规对访客活动范围的要求。 2. **作为租户管理员**,我希望可选策略为「与员工授权楼层求交」或「固定楼层但必须仍在员工授权内」,以便在**不放大访客权限**的前提下简化配置。 3. **作为访客业务系统**,在调用电梯开通接口时,我可以在不传 `floorIds` 的情况下仍得到符合租户策略的派梯结果(若采用电梯或 BFF 兜底策略)。 4. **作为访客**,我在登记完成前看到的「可访问楼层」说明,应与最终开通的楼层**一致**,避免纠纷。 ### 3.3 策略类型(产品枚举建议) | 策略代码(建议) | 产品名称 | 行为摘要 | 适用场景 | |------------------|----------|----------|----------| | `HOST_FLOOR_LIST` | 与现网 UC-01 一致 | 不传 `floorIds` 时,等价于被访人 **`floorList` 全集** | 默认租户、未配置策略时的回退 | | `INTERSECT_ALLOWLIST` | 租户允许列表 ∩ 被访人楼层 | 最终楼层 = **`allowZoneIds` ∩ `floorList`**(交集为空则失败并提示) | **广发基金类**:员工多层、访客只允许接待层等 | | `FIXED_ZONES` | 固定楼层(仍 ∩ 被访人) | 最终楼层 = **`fixedZoneIds` ∩ `floorList`** | 强固定少量楼层且必须与员工授权一致 | | `EXPLICIT_ONLY` | 仅显式开通 | 业务侧**必须**传 `floorIds`(等价 UC-02);租户策略关闭「空列表自动补全」 | 金融高敏楼栋 | **产品原则(建议写进需求)**:凡涉及「租户默认/固定楼层」的,**最终生效楼层必须 ⊆ 被访人 `floorList`**(安全底线,见第 5 章)。 ### 3.4 管理端功能清单(MVP → 完整) **MVP(最小可用)** - 租户级开关:是否启用「访客楼层策略」。 - 策略类型选择 + **允许楼层多选**(选项数据来自空间树 `/sysetting/zone/tree` 或分页接口,与走查文档一致)。 - 保存后**审计**:操作人、时间、前后 JSON 快照。 **增强** - 按**楼栋**分别配置(多栋园区)。 - 按**被访部门**或**职级**附加规则(优先级:部门规则 > 租户默认)。 - 导入/导出 CSV(`businessId, zoneName, zoneId`)。 - 与「访客类型」联动(VIP 可走多层等,需单独权限模型)。 ### 3.5 验收标准(补充闭环相关) | 编号 | 场景 | 期望 | |------|------|------| | AC-1 | 租户配置「允许 {28F}」,被访人 `floorList` 含 28F 与其它层 | 不传 `floorIds` 时(若走兜底),访客**仅**开通 28F | | AC-2 | 同上,被访人 `floorList` **不含** 28F | **开通失败**,返回明确错误(禁止静默落到其它层) | | AC-3 | 租户未配置策略 | 行为与现网 **UC-01** 一致 | | AC-4 | 业务显式传 `floorIds`(UC-02) | **以传入为准**(或启用「显式也求交」须在集成合同写明) | | AC-5 | 注册前 UI 展示楼层 | 与 `add/visitor` **最终生效楼层**一致(含策略与求交) | | **AC-6** | 登记页初始化与 P5 开通相隔任意时间(策略不变) | **两次 `computeEffective` 结果一致**(或均使用快照) | | **AC-7** | 仅改展示文案、不改服务端 | **禁止**;展示必须以服务端预览为准 | --- ## 4. 技术方案 ### 4.1 方案族对比 | 方案 | 实现位置 | 优点 | 缺点 | 新租户扩展 | |------|----------|------|------|------------| | **A. 组织侧收窄 `floorList`** | `ninca-common-component-organization` | 不改电梯;与 UC-01 完全一致 | 员工本人权限与「访客可继承列表」易混 | 每租户数据治理 | | **B. 业务/访客层显式传 `floorIds`** | 第三方 BFF:登记页与 P5 **同源计算** | 不改电梯;闭环最清晰(UC-02) | 多调用入口需统一 | 租户表在**业务库** | | **C. 电梯侧策略引擎** | `PersonRuleServiceImpl.addVisitor` | 直连电梯的旧集成也能兜底 | 电梯存策略、发版耦合 | `businessId` 维表 | | **D. intelligent BFF** | `intelligent-cwoscomponent-rest` | 不直接改电梯包 | 绕过 intelligent 的直连须约束 | 表可在 intelligent 库 | | **E. 配置中心** | Nacos 等 | 变更快 | 审计弱 | 适合灰度,长期建议落库 | **推荐组合(工程上较稳)** 1. **首选**:**方案 B** — 第三方 **BFF** 在 **P0 与 P5 共用** `computeEffective`;`add/visitor` **始终传 `floorIds`**。 2. **可选兜底**:**方案 C 或 D** 仅在 `floorIds` 为空时求交;登记页预览仍应调用**同一预览逻辑**(可部署在 BFF 或 D),避免「兜底路径」与「预览路径」算法分叉。 ### 4.2 核心算法(推荐伪代码) 设: - `hostFloors` = 组织 `detail` 返回的 `floorList`(可能为空)。 - `tenantAllow` = 租户配置的允许访客楼层 `zoneId` 集合。 - `requested` = 调用方传入的 `floorIds`(可能为空)。 ``` if requested 非空: effective = requested // 默认信任;高敏合同可改为 requested ∩ tenantAllow ∩ hostFloors else: effective = tenantAllow ∩ hostFloors // 或 policy=HOST 时 tenantAllow 视为全集 if effective 为空: 返回业务错误(勿继续 zone page / insert) ``` **电梯 `addVisitor` 当前风险点**:补全后未校验空列表即使用 `floorIds.get(0)`。无论采用何种产品方案,**建议在生效列表计算完成后统一做空集校验**,与 [UC-04](访客注册与派梯楼层业务流程走查.md) 治理合并。 ### 4.3 数据模型草案(租户策略落库) ```sql CREATE TABLE tenant_visitor_floor_policy ( id VARCHAR(32) PRIMARY KEY, business_id VARCHAR(64) NOT NULL COMMENT '机构/租户 ID', policy_type VARCHAR(32) NOT NULL, allow_zone_ids TEXT COMMENT 'JSON 数组 zoneId', building_id VARCHAR(64) COMMENT '可选', enabled TINYINT(1) NOT NULL DEFAULT 1, policy_version BIGINT NOT NULL DEFAULT 1 COMMENT '每次更新+1,供登记快照引用', remark VARCHAR(256), created_by VARCHAR(64), created_at BIGINT, updated_by VARCHAR(64), updated_at BIGINT, UNIQUE KEY uk_biz_building (business_id, building_id) ); ``` **缓存**:按 `businessId` 缓存;更新策略时递增 `policy_version` 并使缓存失效。 ### 4.4 管理 API 草案(REST) | 方法 | 路径 | 说明 | |------|------|------| | `GET` | `/admin/tenant/{businessId}/visitor-floor-policy` | 查询当前策略 | | `PUT` | `/admin/tenant/{businessId}/visitor-floor-policy` | 全量更新;**递增** `policy_version` | | `POST` | `/admin/tenant/{businessId}/visitor-floor-policy/preview` | body:`hostPersonId`;返回与登记页同源结构 | ### 4.5 电梯服务改造要点(若采用方案 C) 见前文;补充:**登记页预览若不走电梯**,则电梯内求交逻辑须与 BFF **算法对齐**(共享库或 OpenAPI 生成的客户端 stub 中携带版本号)。 ### 4.6 「28 楼」与 zoneId 映射 - 空间:**`/sysetting/zone/tree`**、**`/sysetting/zone/page`**(走查 §3.2)。 - 台账:`businessId`、`buildingId`、`display_name`、`zoneId`、生效日期。 ### 4.7 兼容性与集成契约 | 项目 | 建议 | |------|------| | **与 UC-02** | 集成合同写明:`floorIds` 非空是否二次求交。 | | **幂等** | 审批消息带 `draft_id` + `effective_hash`;P5 去重。 | | **版本** | 请求带 `policyVersion`,与快照比对可告警。 | --- ## 5. 安全与合规 1. **权限上界**:访客生效楼层 ⊆ 被访人 **`floorList`**。 2. **禁止静默降级**:交集为空则失败并记录。 3. **审计**:策略变更、预览请求、开通请求(可采样)。 4. **数据隔离**:所有查询带 `businessId`。 --- ## 6. 多租户「默认访客楼层」实现路径综合评估 在已具备 **§2 闭环**(登记页初始化 → 快照 → 审批 → `add/visitor`)的前提下,对各实现路径按维度打分(**高 / 中 / 低** 为实施与维护成本或风险的主观分级,供选型会使用)。 ### 6.1 评估维度说明 | 维度 | 含义 | |------|------| | **登记页契合** | 能否自然地在 **P0** 提供准确预览、少调接口。 | | **闭环一致性** | 单源计算、快照、防 TOCTOU 是否易实现。 | | **新租户成本** | 新开租户时配置、实施、回归工作量。 | | **入侵性** | 对电梯/组织/第三方存量改动的范围。 | | **绕过风险** | 存在不经过 BFF 直连电梯时是否仍安全。 | ### 6.2 综合对比表 | 路径 | 登记页契合 | 闭环一致性 | 新租户成本 | 入侵性 | 绕过风险 | 结论 | |------|------------|------------|------------|--------|----------|------| | **B:第三方 BFF + 显式 `floorIds`** | **高**(BFF 聚合 detail+策略+zone) | **高**(同函数+快照) | **低**(插策略行 + 空间台账) | **低**(电梯可不改) | **中**(依赖网关禁止直连) | **首推** | | **D:intelligent 预览 + 转发** | **高** | **高**(预览与转发同模块) | **中**(需发布 intelligent) | **中** | **中** | 适合已统一走 intelligent 的客户 | | **C:仅电梯兜底** | **低**(预览仍需别处算,否则与 UI 不一致) | **中**(易双算法) | **低** | **高** | **低** | 作**兜底**,不宜单独承担预览 | | **A:仅组织改 `floorList`** | **中** | **中**(与员工权限耦合) | **高**(组织数据治理难) | **高** | **低** | 仅当组织域已区分访客继承列时考虑 | | **B + C** | **高** | **高** | **低** | **中** | **低** | **大型项目推荐**:B 主路径 + C 防直连漏传 | ### 6.3 新租户接入检查清单(SOP) 1. 在空间服务确认 **`zoneId`** 与接待层名称。 2. 在租户策略表插入 **`business_id` + `INTERSECT_ALLOWLIST` + allow_zone_ids**(或走管理端保存)。 3. 第三方 BFF 配置 **Nexus/网关** 指向组织与空间。 4. 跑通 **P0 预览** 与 **P5 add/visitor** 自动化用例(覆盖 AC-1~AC-7)。 5. 培训租户管理员:**改策略会影响后续新单**;进行中单据策略见 §2.7。 --- ## 7. 实施路线(建议阶段) | 阶段 | 内容 | 产出 | |------|------|------| | **0** | 盘点所有 `add/visitor` 入口;登记页是否已有 `detail` 调用 | 调用方与数据项缺口表 | | **1** | 定稿:§2.3 数据项表 + §2.7 策略变更策略 + AC-6/7 | PRD、接口契约 | | **2** | 实现 BFF 聚合初始化 + 登记快照 + P5 显式 `floorIds` | 广发基金类租户上线 | | **3** | 可选:电梯空列表校验 + C/D 兜底 + 监控 | 零 NPE、直连防护 | --- ## 8. 测试用例矩阵(摘录) | ID | 阶段 | 条件 | 期望 | |----|------|------|------| | T0 | P0 | 被访人无 `floorList` | 预览失败,禁止提交 | | T1 | P0→P5 | INTERSECT,有交集 | 预览与开通均为交集 | | T6 | P0→P5 | 审批期间策略变更 + 冻结快照 | 开通结果与提交时预览一致 | | T7 | P0 | 仅前端改楼层展示 | 服务端拒绝或覆盖(AC-7) | (原 T1~T5 矩阵仍适用于纯开通层逻辑,可与上表合并维护。) --- ## 9. 文档版本与维护 | 项目 | 内容 | |------|------| | 输出路径 | `docs/business/租户访客默认楼层技术产品方案.md` | | 依据代码 | `maven-cw-elevator-application`、`maven-intelligent-cwoscomponent`;闭环 P4 依赖组织访客 API(仓外) | | 修订触发 | 登记页字段增减;`person/detail` 字段变更;`add/visitor` 契约变更 | --- *本文档为方案级输出;组织人员检索、访客建档等接口以实际部署与网关路由为准。表结构与路径在实施前需经安全评审。*