140 lines
11 KiB
Markdown
140 lines
11 KiB
Markdown
# 02 本地住宿、宿舍与门禁模型现状审计 (Current Accommodation Audit)
|
||
|
||
> **基准代码版本**:`adcf930ea0a880e1faae36ff3d3e6539d0c0b8f9` (`HEAD`)
|
||
> **审计范围**:Kingbase 物理数据库、Java 后端代码、MyBatis XML、前端 Vue 代码
|
||
> **审计执行方式**:只读安全查询脚本 (`DbTableAuditor.java`),无任何写操作与数据破坏
|
||
|
||
---
|
||
|
||
## 1. Kingbase 数据库真实物理表事实 (Physical Table Facts)
|
||
|
||
通过直接连接正式 Kingbase 数据库 (`jdbc:kingbase8://127.0.0.1:4321/training?currentSchema=public,sys_catalog`) 进行只读元数据审计,物理表事实如下:
|
||
|
||
### 1.1 `train_dormitory_info` (宿舍物理资源表)
|
||
- **TABLE_EXISTS**: `true`
|
||
- **ROW_COUNT**: `1`
|
||
- **KEY_COLUMNS (14列)**:
|
||
- `dorm_id` (`varchar(32)`, `NOT NULL`, 主键 UUID)
|
||
- `dorm_building` (`varchar(50)`, `NOT NULL`, 宿舍楼栋)
|
||
- `dorm_floor` (`varchar(20)`, `NOT NULL`, 所在楼层)
|
||
- `dorm_room` (`varchar(20)`, `NOT NULL`, 房间号)
|
||
- `capacity` (`integer`, `NOT NULL`, 核定床位数, 1~8)
|
||
- `gender_type` (`smallint`, `NOT NULL`, 适用性别: 0不限, 1男, 2女)
|
||
- `lock_device_sn` (`varchar(64)`, `NULLABLE`, 智能门锁设备硬件序列号)
|
||
- `dorm_status` (`smallint`, `NOT NULL`, 房间状态: 0禁用, 1可用)
|
||
- `del_flag` (`bpchar(1)`, `NOT NULL`, 逻辑删除: 0正常, 2删除)
|
||
- `create_by`, `create_time`, `update_by`, `update_time`, `remark` (标准审计列)
|
||
- **物理约束**: 唯一约束 `uq_dorm_building_room (dorm_building, dorm_room)`。
|
||
|
||
### 1.2 `train_accommodation` (学员住宿安排事实表)
|
||
- **TABLE_EXISTS**: `true`
|
||
- **ROW_COUNT**: `0`
|
||
- **KEY_COLUMNS (11列)**:
|
||
- `accommodation_id` (`bigint`, `NOT NULL`, 主键 IDENTITY)
|
||
- `enrollment_id` (`bigint`, `NOT NULL`, 参训档案ID, 唯一约束 `uq_accommodation_enroll`)
|
||
- `dorm_id` (`varchar(32)`, `NOT NULL`, 分配宿舍ID, 外键 `fk_accomm_dorm` 引用 `train_dormitory_info.dorm_id`)
|
||
- `bed_no` (`varchar(20)`, `NULLABLE`, 分配床位号)
|
||
- `assigned_time` (`timestamp`, `NOT NULL`, 分配时间, 默认 `CURRENT_TIMESTAMP`)
|
||
- `accommodation_status` (`smallint`, `NOT NULL`, 住宿状态: 0预分配, 1已入住, 2已退宿)
|
||
- `create_by`, `create_time`, `update_by`, `update_time`, `remark` (标准审计列)
|
||
- **外键约束**:
|
||
- `fk_accomm_enrollment`: 引用 `train_enrollment(enrollment_id)`
|
||
- `fk_accomm_dorm`: 引用 `train_dormitory_info(dorm_id)`
|
||
|
||
### 1.3 `train_dorm_auth` (门禁同步与下发表 - 数据库 V2 重建版本)
|
||
- **TABLE_EXISTS**: `true`
|
||
- **ROW_COUNT**: `0`
|
||
- **KEY_COLUMNS (14列)**:
|
||
- `auth_id` (`bigint`, `NOT NULL`, 主键 IDENTITY)
|
||
- `accommodation_id` (`bigint`, `NOT NULL`, 住宿安排ID, 外键 `fk_dormauth_accomm`, 唯一约束 `uq_dorm_auth_accomm`)
|
||
- `auth_start` (`timestamp`, `NULLABLE`, 权限生效开始时间)
|
||
- `auth_end` (`timestamp`, `NULLABLE`, 权限失效结束时间)
|
||
- `face_sync_status` (`smallint`, `NOT NULL`, 默认 0; 0待下发, 1已下发, 2下发失败, 3已注销)
|
||
- `retry_count` (`integer`, `NOT NULL`, 默认 0, 同步失败重试次数)
|
||
- `last_error` (`varchar(500)`, `NULLABLE`, 最后一次下发失败错误信息)
|
||
- `external_auth_id` (`varchar(100)`, `NULLABLE`, 外部门禁硬件系统下发唯一凭证ID)
|
||
- `last_sync_time` (`timestamp`, `NULLABLE`, 最近一次同步请求时间)
|
||
- `create_by`, `create_time`, `update_by`, `update_time`, `remark` (标准审计列)
|
||
|
||
### 1.4 其它相关表事实
|
||
- `bak_v1_train_dorm_auth`: 存在历史 V1 备份表(行数 0),包含废弃的 `student_id`, `plan_id`, `dorm_id`, `bed_no`。
|
||
- 数据库中**不存在**任何以 `door_*`, `lock_*`, `access_*` 命名的其他物理表。
|
||
|
||
---
|
||
|
||
## 2. 真实代码层实现现状审计 (Code Implementation Facts)
|
||
|
||
| 模块 / 类 | 当前代码存在情况 | 承担职责与现实状态 |
|
||
| :--- | :--- | :--- |
|
||
| **`TrainDormitoryInfo`** (Domain/VO/Service/Controller) | **已完整实现** | 负责物理宿舍增删改查。包含 `lockDeviceSn` 单一字符串字段;通过 SQL 实时统计 `train_accommodation` 的 `usedCount` 与计算 `remainingBeds`。 |
|
||
| **`TrainDormAuth`** (Domain/Mapper/Service/Controller) | **实现脱节 (V1 遗留代码)** | 当前 Java 实体类 `TrainDormAuth.java`、Mapper 与 Controller **依然映射的是 V1 结构**(持有 `studentId`, `planId`, `dormId`, `bedNo`, `faceSyncStatus`),**尚未重构对齐数据库 V2 的 `accommodation_id` 关联结构**! |
|
||
| **`TrainAccommodation`** (Domain/Service/Controller) | **代码层缺失** | 数据库已存在 `train_accommodation` 物理表,且 `TrainDormitoryInfoMapper.xml` 和 `TrainEnrollmentMapper.xml` 已在子查询中引用该表,但 Java 层尚无对应的 `TrainAccommodation.java` 实体及专用 Service/Controller。 |
|
||
| **前端 Vue 页面** | **未实现专用页面** | `ruoyi-ui/src/views/` 目录下尚未建立 `train/dormitory` 或 `train/auth` 前端业务界面,目前仅有大盘总览。 |
|
||
|
||
---
|
||
|
||
## 3. 三大核心业务边界辨析 (Current Business Boundary)
|
||
|
||
当前系统必须在概念模型与后续实现中**严格切分以下三个业务对象**,严禁混为一谈:
|
||
|
||
```
|
||
+-----------------------------------------------------------------------------+
|
||
| A. 物理宿舍资源 (Dormitory Resource - train_dormitory_info) |
|
||
| - 物理属性:楼栋、楼层、房间号、核定床位容量、适用性别、房间可用/停用状态 |
|
||
| - 生命周期:独立于任何培训班和学员,长期相对稳定 |
|
||
+-----------------------------------------------------------------------------+
|
||
▲
|
||
│ 1 间宿舍可容纳多个住宿安排
|
||
+-----------------------------------------------------------------------------+
|
||
| B. 住宿业务事实 (Accommodation - train_accommodation) |
|
||
| - 业务属性:某个学员参训档案 (enrollment_id) 在本次开班中分配到了哪个房间与床位 |
|
||
| - 状态流转:预分配 (0) -> 已入住 (1) -> 已退宿 (2) |
|
||
| - 事实归属:RailwaySystem 是本业务的绝对 Source of Truth (事实唯一真源) |
|
||
+-----------------------------------------------------------------------------+
|
||
▲
|
||
│ 1 条住宿事实产生门禁授权要求
|
||
+-----------------------------------------------------------------------------+
|
||
| C. 门锁设备授权 (Door Authorization - 门禁授权模型) |
|
||
| - 设备属性:基于该住宿事实,向 DMS 门锁下发的有效时间区间与电子钥匙凭据 (密码/卡片) |
|
||
| - 状态流转:待下发 -> 平台已受理 -> 设备执行中 -> 设备生效 -> 撤销中 -> 已注销 |
|
||
| - 属性特征:依赖外部网络与硬件状态,可异步重试,失败不推翻住宿业务事实 |
|
||
+-----------------------------------------------------------------------------+
|
||
```
|
||
|
||
---
|
||
|
||
## 4. `train_dorm_auth` 当前角色与演进方案比选 (TRAIN_DORM_AUTH_CURRENT_ROLE)
|
||
|
||
### 4.1 当前角色定性
|
||
在当前代码与数据库混合状态下:
|
||
- **Java 代码层**:`train_dorm_auth` 承担了“住宿分配 + 门锁序列号关联 + 人脸同步标记”的**混合式职责**。
|
||
- **数据库 V2 迁移设计**:设计意图已将其向“纯门禁授权下发同步表”推进(引入 `accommodation_id`, `retry_count`, `last_error`, `external_auth_id`),但尚未考虑**一个房间多把锁**、**多凭据类型(密码/卡片)**以及 **DMS `operationId` 异步轮询生命周期**。
|
||
|
||
### 4.2 三种演进方案详细比选
|
||
|
||
| 评估维度 | 方案 A: 沿用并继续扩展 `train_dorm_auth` | 方案 B: 收敛 `train_dorm_auth` + 独立 `train_external_operation` | 方案 C: 新建通用 `train_door_authorization` + `train_external_operation` |
|
||
| :--- | :--- | :--- | :--- |
|
||
| **设计描述** | 在现有的 `train_dorm_auth` 上追加 `lock_id`, `operation_id`, `credential_type`, `credential_value` 等列 | 将 `train_dorm_auth` 代码升级对齐 V2(作为授权事实主表),另建异步操作流水表记录轮询与对账 | 新建专用的门禁授权表与外部操作流水表,彻底废弃/弃用命名有误导的 `train_dorm_auth` |
|
||
| **职责清晰度** | 差。混合业务授权与设备异步任务,字段臃肿且无法表达多锁与多钥匙 | 良好。主表表达“谁拥有该房间的有效授权”,流水表表达“向设备发送的异步指令状态” | 优秀。命名脱离“人脸/宿舍”局部限制,完全按照通用门禁控制抽象 |
|
||
| **与 Accommodation 关系** | 外键引用 `accommodation_id`,但多锁时难以保持 1:1 唯一约束 | 主表通过 `accommodation_id` 关联,支持按锁/凭据类型建立多条授权;流水表关联主表 | 清晰明确,一个 Accommodation 可派生多条 Authorization 凭据 |
|
||
| **DMS Operation 生命周期支持** | 极差。无法保存多次重试、多次轮询的轨迹与错误历史 | 优秀。所有异步 `operationId`、轮询重试、超时记录在流水表完整归档 | 优秀。支持完整的异步生命周期追踪与审计 |
|
||
| **多锁扩展性** | 无法支持(同一个房间若有外门锁与内门锁,会导致主键或关联冲突) | 良好(主表以 `(accommodation_id, lock_id, credential_type)` 为逻辑单元) | 优秀(原生支持一房多锁与多供应商适配) |
|
||
| **迁移与代码改动成本** | 表面成本低,但后期技术债务严重 | **适中**。数据库 V2 已就绪 `train_dorm_auth`,只需调整列定义或补充流水表 | 略高。需要新增两张物理表并做数据迁移 |
|
||
| **审计与故障追溯** | 弱(覆写 `last_error` 导致历史丢失) | **强**(流水表不可变追加,完整记录每一次操作) | **强** |
|
||
|
||
### 4.3 演进建议结论
|
||
1. **本轮 R.3A 不执行任何 DDL**。
|
||
2. **架构倾向**:推荐采纳 **方案 B/C 的分层解耦思想**。绝不能将 DMS 的 `operationId` 轮询与重试直接塞在单个授权记录中覆写,必须将**“门禁业务授权事实 (Door Authorization)”**与**“外部硬件异步操作记录 (External Operation)”**彻底解耦为两层模型。
|
||
|
||
---
|
||
|
||
## 5. 本地模型漂移事实与前置对齐要求 (`LOCAL_DOMAIN_ALIGNMENT_REQUIRED`)
|
||
|
||
### 5.1 现实漂移事实总结
|
||
- **`LOCAL_DOMAIN_ALIGNMENT_REQUIRED = YES`**
|
||
- **当前核心矛盾**:
|
||
1. **`train_accommodation`**:Kingbase 物理表已在 V2 迁移中正式建立,但 Java 代码层尚未建立对应的实体类、Mapper 与业务 Service,未形成闭环业务层。
|
||
2. **`train_dorm_auth`**:Kingbase 物理表已在 V2 中升级为以 `accommodation_id` 为外键的门禁授权结构,但 Java 实体类 `TrainDormAuth.java` 与 XML Mapper 依然停留在 V1 旧结构(持有 `student_id`, `plan_id`, `dorm_id`, `bed_no`)。
|
||
- **执行原则**:
|
||
在进入 R.3B 真正编写 DMS Adapter 之前,**必须先在 Wave 0 完成本地住宿与门禁授权领域模型对齐**!严禁让外部 DMS 集成适配器直接架设在当前存在严重漂移的本地模型之上。
|