Files
starRiverProperty/docs/business/租户访客默认楼层技术产品方案.md
hpd840321 7b2bd307f1 Initial commit: reorganized source tree
- backend/: 13 Maven modules (cw-elevator-application, cloudwalk-cloud, intelligent-cwoscomponent, ninca-crk, etc.)
- frontend/: 4 Vue projects (elevator-front, cwos-portal, alarm-front, front_acs) + decompiled + scripts
- scripts/: build, test-env, tools (Docker Compose, service templates, API parity)
- docs/: AGENTS.md, superpowers specs, architecture docs
- .gitignore: standard Java/Maven exclusions

Moved from legacy maven-*/ root layout to backend/ organized structure.
2026-05-09 09:56:45 +08:00

428 lines
29 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 租户访客默认楼层:技术产品方案
> **文档类型**:产品与工程技术方案(含**登记页数据项与接口溯源**、端到端闭环、数据模型与实施路线)。
> **前置阅读**:[访客注册与派梯楼层业务流程走查](访客注册与派梯楼层业务流程走查.md)(UC-01UC-06、对外 HTTP/Feign 与代码位置)。
> **关联工程**[Maven 聚合工程说明](../architecture/Maven聚合工程说明.md)`maven-cw-elevator-application`、`maven-intelligent-cwoscomponent` 等边界)。
> **排期(2026-04)**:凡依赖**物业管理端、登记页、第三方前端**改动的阶段,在取得可维护前端工程前**暂时跳过**;见 [docs/README 当前排期与范围](../README.md#当前排期与范围2026-04)。本文中**纯后端/接口/数据**部分仍可独立推进。
> **术语对齐(2026-05-06,强制)**:租户访客楼层策略的工程语义 **只能是「替代」**——在 **`PersonService.detail`** 将 **`allow_zone_ids` 写入 `PersonResult.floorList`**;电梯 **`addVisitor`** **不透传策略表、不与 allow 求交(∩)**。下文表格中出现的 **INTERSECT / ∩ / 求交** 多为历史方案或 **BFF 侧自选收窄**,**不等价**于现行后端规范;以 [迁入组织组件规格](../superpowers/specs/2026-05-06-tenant-visitor-policy-organization-implementation.md) 为准。
---
## 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<zoneId>`,可附 `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/detailid=被访人 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 | **高**(同函数+快照) | **低**(插策略行 + 空间台账) | **低**(电梯可不改) | **中**(依赖网关禁止直连) | **首推** |
| **Dintelligent 预览 + 转发** | **高** | **高**(预览与转发同模块) | **中**(需发布 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` 契约变更 |
---
*本文档为方案级输出;组织人员检索、访客建档等接口以实际部署与网关路由为准。表结构与路径在实施前需经安全评审。*