Files
railwaysystem/docs/development/dms-r3/02_current_accommodation_audit.md
T

140 lines
11 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.
# 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 集成适配器直接架设在当前存在严重漂移的本地模型之上。