mirror of
https://github.com/hpd840321/starRiverProperty.git
synced 2026-06-09 08:20:31 +08:00
7b2bd307f1
- 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.
428 lines
29 KiB
Markdown
428 lines
29 KiB
Markdown
# 租户访客默认楼层:技术产品方案
|
||
|
||
> **文档类型**:产品与工程技术方案(含**登记页数据项与接口溯源**、端到端闭环、数据模型与实施路线)。
|
||
> **前置阅读**:[访客注册与派梯楼层业务流程走查](访客注册与派梯楼层业务流程走查.md)(UC-01~UC-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/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` 契约变更 |
|
||
|
||
---
|
||
|
||
*本文档为方案级输出;组织人员检索、访客建档等接口以实际部署与网关路由为准。表结构与路径在实施前需经安全评审。*
|