mirror of
https://github.com/hpd840321/starRiverProperty.git
synced 2026-06-09 08:20:31 +08:00
1cac12d940
- Add §7 initialization flow: /component/person/detail call chain from decompiled component-organization source - Document floorList assembly in ImgPersonServiceImpl (via elevatorFeignClient.listByImageId) - Analyze init vs submit consistency: gap when policy exists
7.2 KiB
7.2 KiB
租户访客默认楼层策略 — 业务逻辑重设计
日期:2026-05-05
状态:待审核
设计依据:产品方案 租户访客默认楼层技术产品方案
涉及代码:PersonRuleServiceImpl.addVisitor
1. 业务规则(核心不变量)
| 规则 | 说明 |
|---|---|
| 策略全时生效 | 无论调用方是否传入 floorIds,始终查询该机构是否有启用策略 |
| 策略即安全边界 | 策略的 allow_zone_ids 定义访客可达楼层的上限集合,任何路径都不能超出此集合 |
| 无策略不禁锢 | 机构未配置策略或策略未启用时,行为与无策略版本完全一致 |
| 交集为空必须拒绝 | candidate ∩ allow 为空时禁止继续开通,返回明确错误码 |
2. 总流程
2.1 UC-01:调用方未传 floorIds
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
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
// === 阶段3:ALWAYS 查策略 ===
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 行为改变意味着:之前能开通的请求(传入策略允许范围外的楼层)现在会失败。需通知集成方。