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

13 KiB
Raw Blame History

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)

当前系统必须在概念模型与后续实现中严格切分以下三个业务对象,严禁混为一谈:

flowchart TB
    subgraph LayerA["A. 物理宿舍资源 (train_dormitory_info)"]
        direction TB
        A1["物理属性:楼栋、楼层、房间号、核定床位容量、适用性别、房间可用/停用状态<br/>生命周期:独立于任何培训班和学员,长期相对稳定"]
    end

    subgraph LayerB["B. 住宿业务事实 (train_accommodation)"]
        direction TB
        B1["业务属性:学员参训档案 (enrollment_id) 在本次开班中分配到的房间与床位<br/>状态流转:预分配 (0) -> 已入住 (1) -> 已退宿 (2)<br/>事实归属:RailwaySystem 是本业务的绝对 Source of Truth (事实唯一真源)"]
    end

    subgraph LayerC["C. 门锁设备授权 (门禁授权模型)"]
        direction TB
        C1["设备属性:向 DMS 门锁下发的有效时间区间与电子钥匙凭据 (密码/卡片)<br/>状态流转:待下发 -> 平台已受理 -> 设备执行中 -> 设备生效 -> 撤销中 -> 已注销<br/>属性特征:依赖外部网络与硬件状态,可异步重试,失败不推翻住宿业务事实"]
    end

    LayerB -->|"1 间宿舍可容纳多个住宿安排"| LayerA
    LayerC -->|"1 条住宿事实产生门禁授权要求"| LayerB

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

5.2 Wave 0 Implementation Result (本地模型对齐实施完成)

  • 完成状态:已全面对齐并消除结构漂移。
  • 实体层:
    • 新增 TrainAccommodation.java,严格对应 Kingbase V2 生产物理表(accommodation_id, enrollment_id, dorm_id, bed_no, assigned_time, accommodation_status, 审计列)。
    • 重构 TrainDormAuth.java,外键核心对齐 accommodation_id,持久化字段剔除 V1 遗留字段(student_id, plan_id, dorm_id, bed_no, createUser),保留为非持久化兼容视图字段以保障只读兼容。
  • Mapper/SQL:
    • 新增 TrainAccommodationMapper.java / TrainAccommodationMapper.xml,所有字段显式指定,严禁 SELECT *。
    • 重构 TrainDormAuthMapper.xml,INSERT/UPDATE 语句彻底清理 V1 废弃字段写入,通过 LEFT JOIN 视图提供兼容字段。
  • 业务服务:
    • 新增 ITrainAccommodationService / TrainAccommodationServiceImpl,落地“同一时刻最多1个有效住宿安排”(Duplicate Active Accommodation Guard)、宿舍核定容量边界检查(Capacity Boundary Guard)与换房原子流转(Transfer)。
    • 升级 TrainDormAuthServiceImpl,严格执行“Enrollment -> Accommodation -> Door Authorization”业务单向依赖,禁止绕过住宿事实直接授权。

5.3 Wave 0.1 Accommodation History & 006 Migration (基数模型升级与迁移方案)

  • 基数语义冻结:
    • Enrollment 1:N Accommodation History(一个报名记录可有多条历史住宿记录,调房换房产生历史轨迹)
    • Enrollment 1:0..1 Active Accommodation(同一时间一个报名记录最多只能有 1 条有效住宿记录,accommodation_status IN (0, 1))
    • Accommodation 1:0..1 DoorAuthorization(门禁授权强依赖具体的某一次住宿记录)
    • TIME_RANGE_SUPPORT = LIMITED(当前 Kingbase 物理表仅包含 assigned_time,无 start_time/end_time,时间窗口支持为有限支持)
  • 006 迁移脚本方案 (006_accommodation_history_constraint.sql):
    • 脚本路径:RuoYi-Vue/sql/system/kingbase/006_accommodation_history_constraint.sql
    • 安全编号:006(001-003 为基线,004-005 已被 R.2 分支占用)
    • 前置检查:Fail-fast,若发现同一 enrollment_id 存在多条 active(accommodation_status IN (0, 1))则 RAISE EXCEPTION 阻止迁移
    • 安全 DROP:仅在原约束 uq_accommodation_enroll 确认为 UNIQUE (enrollment_id) 时安全移除
    • 局部唯一索引:创建 uq_accommodation_enroll_active 并在 WHERE accommodation_status IN (0, 1) 生效
    • 幂等性防护:重复执行不会报错或破坏表结构
    • 生产执行纪律:本迁移脚本仅完成工程资产化与隔离测试,严禁在生产数据库执行
  • 自动化测试:
    • AccommodationHistoryMigrationContractTest(契约测试:SQL 语法、前置检查、条件 DROP、局部索引及幂等性)
    • AccommodationServiceTest(10 项测试,包含调房历史与并发唯一性)
    • DormAuthAlignmentTest(7 项测试,包含依赖住宿与换房级联)
    • 全量测试套件 174 项全部 PASS(0 failures, 0 errors)。