Files
starRiverProperty/docs/superpowers/specs/2026-05-05-tenant-visitor-floor-policy-redesign.md
T
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

189 lines
7.9 KiB
Markdown
Raw 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.
# 租户访客默认楼层策略 — 业务逻辑重设计
> **废止 / 仅作历史归档(2026-05-06**
> **现行规范**以 **[租户访客默认楼层策略 — 迁入组织组件](./2026-05-06-tenant-visitor-policy-organization-implementation.md)** 为准:租户策略 **`allow_zone_ids` 只能在组织 `PersonService.detail` 以「**替代**」写入 `floorList`**;**禁止**将策略定义为与被访人楼层 **「求交(∩)」**。电梯 `addVisitor` **不再**读取策略表、**不再**做 ∩。
> 下文保留 **2026-05-05** 草稿中的电梯侧求交流程图,**仅供对照旧表述**,勿作为实现或验收依据。
**日期**2026-05-05
**状态**:已废止(见上)
**设计依据**:产品方案 [租户访客默认楼层技术产品方案](../../business/租户访客默认楼层技术产品方案.md)
**涉及代码**`PersonRuleServiceImpl.addVisitor`(现行代码已按 2026-05-06 规范移除电梯侧策略 ∩)
---
## 1. 业务规则(核心不变量)—— **历史草案,已被「替代语义」取代**
| 规则 | 说明(历史) |
|------|------|
| ~~**策略全时生效**~~ | **废止**:电梯侧不再全时查策略表;策略在组织 detail **替代** `floorList`。 |
| **策略即安全边界** | `allow_zone_ids` 仍表达租户允许的 zone 集合;落实方式为 **替代写入 detail**,而非 ∩。 |
| **无策略不禁锢** | 组织未命中策略时,`floorList` 仍为 `listByImageId` 遍历结果。 |
| ~~**交集为空必须拒绝**~~ | **废止**:不再使用 `candidate ∩ allow`;空 `floorList`/effective 走 **`76260531`**。 |
---
## 2. 总流程
### 2.1 UC-01:调用方未传 floorIds
```mermaid
sequenceDiagram
participant Caller as 调用方/BFF
participant Elevator as 电梯应用<br/>cw-elevator-application
participant Org as 组织服务<br/>ninca-common-component-organization
participant PolicyDB as 策略表<br/>tenant_visitor_floor_policy
Caller->>Elevator: POST /elevator/person/add/visitor<br/>{personId, visitorId}<br/>(不传 floorIds)
Note over Elevator: 阶段1:查被访人信息
Elevator->>Org: POST /component/person/detail<br/>{personId, businessId}
Org-->>Elevator: PersonResult<br/>{floorList, organizationIds}
Note over Elevator: 阶段2:候选楼层 = floorList
Note over Elevator: floorList 来自组织服务
Note over Elevator: 阶段3:查策略
Elevator->>PolicyDB: SELECT * FROM tenant_visitor_floor_policy<br/>WHERE org_id IN (organizationIds) AND enabled=1
PolicyDB-->>Elevator: policy 行 / 空
alt 策略存在且生效
Note over Elevator: 最终楼层 = floorList ∩ allow_zone_ids
alt 交集为空
Elevator-->>Caller: 失败 76260532<br/>(租户策略与被访人授权无交集)
else 交集非空
Note over Elevator: 继续开通流程
Elevator-->>Caller: 成功,仅开通交集内楼层
end
else 无策略或未启用
Note over Elevator: 最终楼层 = floorList(原值)
Elevator-->>Caller: 成功
end
```
### 2.2 UC-02:调用方传入 floorIds
```mermaid
sequenceDiagram
participant Caller as 调用方/BFF
participant Elevator as 电梯应用<br/>cw-elevator-application
participant Org as 组织服务<br/>ninca-common-component-organization
participant PolicyDB as 策略表<br/>tenant_visitor_floor_policy
Caller->>Elevator: POST /elevator/person/add/visitor<br/>{personId, visitorId, floorIds:[...]}
Note over Elevator: 阶段1:查被访人信息(仅取 organizationIds
Elevator->>Org: POST /component/person/detail<br/>{personId, businessId}
Org-->>Elevator: PersonResult<br/>{organizationIds}
Note over Elevator: 阶段2:候选楼层 = 调用方传入的 floorIds
Note over Elevator: 阶段3:查策略(ALWAYS
Elevator->>PolicyDB: SELECT * FROM tenant_visitor_floor_policy<br/>WHERE org_id IN (organizationIds) AND enabled=1
PolicyDB-->>Elevator: policy 行 / 空
alt 策略存在且生效
Note over Elevator: 最终楼层 = callerFloorIds ∩ allow_zone_ids
alt 交集为空
Elevator-->>Caller: 失败 76260532<br/>(请求楼层不在策略允许范围内)
else 交集非空
Elevator-->>Caller: 成功,仅开通交集内楼层
end
else 无策略或未启用
Note over Elevator: 最终楼层 = callerFloorIds(原值)
Elevator-->>Caller: 成功
end
```
---
## 3. 控制流伪代码
```
addVisitor(param, context):
// === 阶段1:查被访人组织信息(ALWAYS)===
detailResult = personService.detail(personId, businessId)
if failed: return detailResult.error
person = detailResult.data
// === 阶段2:确定候选楼层 ===
if param.floorIds 非空: ← UC-02
candidate = param.floorIds
else: ← UC-01
candidate = person.floorList
if candidate 为空: return 76260531
// === 阶段3ALWAYS 查策略 ===
policy = findEnabledPolicy(person.organizationIds)
if policy != null:
effective = intersect(candidate, policy.allow_zone_ids)
if effective 为空: return 76260532
else:
effective = candidate
// === 阶段4:空集校验 ===
if effective 为空: return 76260531
param.floorIds = effective
// === 阶段5:开通流程(不变)===
zoneService.page → image_rule_ref → batchBind → ...
```
---
## 4. 场景对照矩阵
| 场景 | 调用方 floorIds | 策略状态 | 候选楼层 | 最终结果 |
|------|----------------|---------|---------|---------|
| UC-01 无策略 | 空 | 无策略行 | `floorList` | `floorList` ✅ |
| UC-01 + 策略通过 | 空 | 有且生效 | `floorList` | `floorList ∩ allow` ✅ |
| UC-01 + 策略无交集 | 空 | allow 与 floorList 无交集 | `floorList` | 失败 76260532 ✅ |
| UC-01 被访人无楼层 | 空 | 任意 | `floorList`=空 | 失败 76260531 ✅ |
| UC-02 无策略 | [A,B] | 无策略行 | [A,B] | [A,B] ✅ |
| UC-02 + 策略包含 | [A,B] | allow=[A,C] | [A,B] | [A] ✅ |
| UC-02 + 策略不包含 | [A,B] | allow=[C,D] | [A,B] | 失败 76260532 ✅ |
### 与当前实现的差异
| 场景 | 当前实现 | 重设计后 |
|------|---------|---------|
| UC-02 + 策略存在 | 绕过策略,按请求楼层开通 ❌ | 策略求交 ✅ |
| UC-02 + 策略不包含请求楼层 | 成功开通(本应拒绝)❌ | 失败 76260532 ✅ |
---
## 5. 错误码
| 错误码 | 触发条件 | 说明 |
|--------|---------|------|
| 76260531 | 候选楼层为空 | 被访人 `floorList` 为空,或有效楼层为空 |
| 76260532 | `candidate ∩ allow` 无交集 | 策略约束了可访楼层,但候选楼层全部不在允许范围内 |
| 76260533 | 策略配置错误 | `allow_zone_ids` 包含被访人无权限的 zoneId |
---
## 6. 日志规范
| 关键路径 | 日志内容 |
|---------|---------|
| 入口 | `businessId, personId, visitorId, requestFloorSize` |
| UC-01 | `调用方未传楼层,取被访人默认楼层 floorList=xxx` |
| UC-02 | `调用方已指定楼层,候选楼层=candidate` |
| 策略查询 | `查询组织 orgIds=xxx` |
| 策略命中 | `找到启用策略 policyId=xxx allow=xxx` |
| 策略未命中 | `未找到启用策略,使用候选楼层原值` |
| 求交成功 | `策略生效,最终楼层=effective` |
| 求交为空 | `候选楼层与策略无交集,返回 76260532` |
| 空楼层 | `无可用楼层,返回 76260531` |
---
## 7. 实施范围
| 变更点 | 影响 | 风险 |
|--------|------|------|
| UC-02 增加 `personService.detail()` 调用 | 多一次 RPC(数百微秒) | 低 |
| UC-02 增加策略求交逻辑 | 对传入楼层做过滤 | 中——调用方可能不符合预期 |
| 删除 `callerProvidedFloors` 分支 | 简化代码结构 | 低 |
> **兼容性提醒**:UC-02 行为改变意味着:之前能开通的请求(传入策略允许范围外的楼层)现在会失败。需通知集成方。