Files
railwaysystem/docs/development/dms-r3/14_decision_summary.md
T

19 KiB
Raw Blame History

14 DMS 门禁集成审计与设计决策一页纸总结 (Decision Summary)

面向对象:项目负责人、架构指导老师、业务决策评审委员会 核心宗旨:以最短篇幅、最清晰视角,讲透“现状、能力、接入边界、推荐架构与实施规划”。


1. 当前系统有什么?(Current RailwaySystem Assets)

  1. 业务与数据基线:
    • 当前生产分支基于 adcf930e,已完成 V2 数据库结构迁移。
    • 物理表层:train_dormitory_info(宿舍楼栋/房间台账)、train_accommodation(学员参训住宿分配事实表)、train_dorm_auth(门禁授权表,外键绑定 accommodation_id)已在 Kingbase 物理库建表。
    • 业务逻辑层:已具备完整的培训计划编排、学员报到核验、宿舍入住分配与床位容量实时统计能力。
  2. 本地模型漂移与前置对齐要求 (LOCAL_DOMAIN_ALIGNMENT_REQUIRED = YES):
    • train_accommodation:DB 物理表已建,但 Java 层尚无对应的实体类、Mapper 与业务 Service,未形成完整业务层。
    • train_dorm_auth:DB 已升级为以 accommodation_id 为外键的 V2 结构,但 Java 实体类与 XML Mapper 仍残留 V1 字段(student_id, plan_id, dorm_id)。
    • 决策红线:在真正编写外部 DMS Adapter 之前,必须在 Wave 0 优先完成本地住宿与门禁授权领域模型对齐,严禁将外部适配器直接架设在漂移模型上。

2. DMS 平台能提供什么?(DMS IoT Platform Capabilities)

外部 DMS 智能门锁平台(https://dms.dmsiot.com)具备完整的 RESTful 接口体系:

  1. 楼栋-楼层-房间-门锁全层级资产查询(可精确匹配房间获取 placeId,支持一房多锁)。
  2. 多模态电子钥匙下发能力:
    • 在线限时密码 (Online Password):系统可生成 4~8 位纯数字密码(Pilot 建议采用 6 位限时密码),指定起止有效时间,支持远程主动注销。
    • 在线实体芯片卡 (Online Card):支持将学员 IC/M1 卡按小端十六进制编码下发至锁具,支持远程主动注销。
    • 二维码/手机钥匙 (QR Key):端点已定义 (POST /rest/doorlock/qrcode/create 与 POST /rest/qrcode/delete),分类为 DOCUMENTED,但返回体存在数据污染且无具体二维码载荷,适用性归为 NEEDS_BUSINESS_CONFIRMATION。
  3. 低功耗异步执行与对账体系:门锁基于电池无线通信,下发指令后返回 operationId,要求 10 秒后通过接口查询终态。
  4. 设备运行指标:提供门锁电池电量、信号强度及门锁开门记录流水拉取。

3. 一期建议先接什么?暂时不接什么?(Scope Boundary)

+-------------------------------------------------------------------------------+
| 一期重点纳入 (P0 / P1)                                                         |
| 1. 认证鉴权: Token 内存单飞排他锁缓存 + 滑动刷新 + 401 单次重试自愈              |
| 2. 房源映射: 本地宿舍与 DMS placeId / lockId 的预绑定持久化 (支持一房多锁)       |
| 3. 首选凭据: 【在线限时密码】(零硬件与发卡器依赖, 支持4~8位/推荐6位, 随时主动撤销)  |
| 4. 异步对账: 后台调度器 10 秒后异步轮询 operationId,消除 HTTP 线程阻塞          |
| 5. 换房补偿: 严格遵循"先发新房权限、确认生效后再撤旧房"原则,避免学员无处可住      |
| 6. 结训撤权: 培训结束主动派发 Revoke 指令,同时以 validUntil 作为有效期边界兜底    |
| 7. 设备巡检: 门锁电量与信号查询 (P1),辅助宿管员发现低电量设备                    |
+-------------------------------------------------------------------------------+
                                       ▲
                                  【严格划清边界】
                                       ▼
+-------------------------------------------------------------------------------+
| 一期明确排除 (P2 / Out of Scope / Needs Confirmation)                         |
| 1. 取电开关全套接口 (P2): 涉及强电改造,与学员核心学籍住宿无关,暂缓接入          |
| 2. 远程网络开锁 (P2): 属于高危主动开门操作,一期严格封存,仅设计受控两票制应急方案 |
| 3. 二维码钥匙 (Needs Biz Confirm): 接口已文档化但载荷污染,一期不作首选方案      |
| 4. 离线密码与离线发卡 (Out of Scope): 缺乏可靠远程主动撤销机制,增加现场运维负担  |
+-------------------------------------------------------------------------------+

4. 需要向甲方与业务负责人确认的核心问题 (Blocking Decisions)

  1. 下发触发时机 (Q-BLK-03):
    • 推荐意见:学员在现场完成《报到核验》后自动触发门禁下发。确保人已到校才给钥匙,杜绝未报到人员提前进房。
  2. 首期钥匙类型 (Q-BLK-02):
    • 推荐意见:首选采用系统派发 6 位在线限时密码(学员移动端个人中心受控查看);若后续统一下发实体卡,可平滑启用在线卡片模式。
  3. 主数据权威归属 (Q-NON-01):
    • 推荐意见:坚决以 RailwaySystem 作为住宿与房间主数据,DMS 仅作为外部执行端,严禁让 DMS 状态覆盖本地系统。
  4. 现场网络连通性与沙箱 (Q-BLK-01 & Q-BLK-05):
    • 生产环境机房是否允许访问公网 dms.dmsiot.com?供应商必须提供包含测试网关与实验台门锁的独立联调测试沙箱。
  5. 设备离线时 validUntil 过期语义 (Q-BLK-06):
    • 门锁离线断网时,到达 validUntil 是否由锁端本地时钟强制失效?需供应商提供硬件保证级别说明。

5. 推荐技术架构设计

flowchart TD
    UI["前端 Accommodation / 个人中心"] --> Domain["业务领域层: 住宿分配 / 换房补偿 / 报到联动<br/>(绝对 Source of Truth)"]
    Domain -->|"通过强类型 DTO,屏蔽外部厂商细节"| Gateway["中立网关接口: DoorAccessGateway<br/>(grant / revoke / query)"]

    subgraph Adapter["DMS 集成适配器: DmsDoorAccessGateway (SPI 模式)"]
        direction TB
        TM["DmsTokenManager: 进程级单飞排他锁 (防并发覆盖踩踏)"]
        Clients["细分 HTTP 客户端: PlaceClient / DoorLockClient / KeyClient / OpClient"]
        Poller["DmsOperationPoller: 后台 10 秒对账调度器 (解除 HTTP 线程阻塞)"]
    end

    Gateway --> Adapter
    Adapter -->|"HTTPS / Cookie 传递 token"| External["外部 DMS 物联网平台: https://dms.dmsiot.com"]

6. 后续 R.3B 四阶段推进路线图 (Four Waves, 约 15~16 人天)

  1. Wave 0: Local Domain Alignment (本地领域模型对齐,3天):
    • 实现 TrainAccommodation Java 实体/Mapper/Service;升级并清洗 TrainDormAuth 对齐 V2 数据库;确立住宿事实与门禁授权的清晰边界。
  2. Wave 1: External Mapping & Operation Persistence (外部映射与持久化,2天):
    • 创建 train_external_resource_mapping 与 train_external_operation 物理表及 Migration 脚本;落地双层状态机模型。
  3. Wave 2: DMS Adapter & Mock Tests (DMS 适配器与离线仿真,5天):
    • 配置与环境变量绑定;DmsTokenManager 单飞排他锁并发控制;细分 HTTP 客户端;在线密码/卡片适配器;10 秒轮询调度器;WireMock 22 项单测全覆盖。
  4. Wave 3: Business Orchestration & UI & Sandbox (业务编排、界面与现场验收,5~6天):
    • 报到联动授权下发;“先发新房后撤旧房”换房补偿;退训/结训撤权;管理端门禁综合视图;学员端 30 秒倒计时密码受控查看;现场实验台沙箱 E2E 闭环验收。

6.1 Wave 0 Implementation Result (本地领域模型闭环)

  • 基线与状态:
    • 成功消除数据库 V2 模型与 Java 代码之间的全部结构漂移。
    • 严格保持 0 DMS 耦合:无 DmsClient、无 TokenManager、无外部调用、无假设备成功。
    • 保持 Kingbase 生产库只读,零 Migration(MIGRATION_REQUIRED = NO)。
    • 交付本地领域模型:TrainAccommodation 与升级后的 TrainDormAuth。

6.2 Wave 0.1 Accommodation History & Final Checkpoint Decision (基数模型升级与终态)

  • 核心基数关系冻结:
    • Enrollment 1:N Accommodation History:允许学员产生多次历史住宿记录(调房/换房留痕)。
    • Enrollment 1:0..1 Active Accommodation:同一时刻最多一条有效住宿(accommodation_status IN (0, 1))。
    • Accommodation 1:0..1 DoorAuthorization:门禁授权强引用住宿实体。
    • TIME_RANGE_SUPPORT = LIMITED:当前 Kingbase 物理表仅有 assigned_time,无 start_time / end_time 列,时间窗口支持为有限支持。
  • 006 Migration 方案设计:
    • 脚本路径:RuoYi-Vue/sql/system/kingbase/006_accommodation_history_constraint.sql。
    • 安全序号:006(001-003 为基线,004-005 已被 R.2 分支占用)。
    • 迁移安全护栏:前置重复 active 检查抛异常、仅在定义匹配时安全 DROP uq_accommodation_enroll、创建 uq_accommodation_enroll_active 局部唯一索引(WHERE accommodation_status IN (0, 1))、全流程幂等。
    • 生产执行纪律:禁止在生产库执行 006 迁移脚本,本 Wave 仅作资产与契约验证储备。
  • 质量与构建验收:
    • 单元与契约测试总数:174 项,全部 PASS(0 failures, 0 errors)。
    • Maven clean test 与 clean package 均顺利构建成功。

6.3 Wave 1 External Resource Mapping & Operation Persistence (Wave 1 implemented)

  • 阶段状态:Wave 1 implemented。
  • 架构决策与模型基线:
    • 资源映射模型:RESOURCE_MAPPING_REFERENCE_MODEL = DORM_ID_FK,以 dorm_id 外键强关联 train_dormitory_info。
    • 房间映射基数:ROOM_MAPPING_CARDINALITY = Dormitory 1:0..1 Active Room (Dormitory 1:N History)。
    • 门锁映射基数:LOCK_MAPPING_CARDINALITY = Dormitory 1:0..N DoorLocks(支持一房多锁)。
    • 外部资源防冲突:EXTERNAL_RESOURCE_ACTIVE_UNIQUENESS = Vendor + External Resource ID + Active Unique。
    • 操作流水模型:OPERATION_REFERENCE_MODEL = DOOR_AUTH_ID_FK,以 door_auth_id 外键强关联 train_dorm_auth。
    • 授权操作基数:DOOR_AUTH_OPERATION_CARDINALITY = DoorAuthorization 1:N ExternalOperation。
    • 操作类型与状态分离:OPERATION_TYPE_MODEL = GRANT, REVOKE;EXTERNAL_OPERATION_STATUS_MODEL = CREATED, REQUESTED, ACCEPTED, PENDING, RETRY_WAIT, SUCCESS, FAILED, TIMEOUT(REVOKED 属于 DoorAuthorization 业务凭据状态,不属于单次操作执行结果,注销操作的执行结果为 operation_type=REVOKE 达成 SUCCESS)。
    • 本地幂等模型:IDEMPOTENCY_MODEL 基于 idempotency_key 唯一索引防重。
    • 轮询检索支持:PENDING_OPERATION_QUERY 准备就绪,本 Wave 保持 0 调度器运行。
  • 安全红线保持:
    • 敏感字段:SENSITIVE_OPERATION_FIELD_COUNT = 0。
    • 外部耦合:DMS_HTTP_CLIENT_COUNT = 0,DMS_TOKEN_MANAGER_COUNT = 0。
    • 生产数据库:只读保护,PRODUCTION_DB_MODIFIED? NO。
  • Migration 证据与准入准则:
    • 008_RUNTIME_FIRST_RUN = NOT_EXECUTED,008_RUNTIME_SECOND_RUN = NOT_EXECUTED(生产与非隔离库绝不盲跑 DDL)。
    • 008_CONTRACT_TEST = PASS,008_IDEMPOTENCY_STATIC_VERIFICATION = PASS。
    • RUNTIME_MIGRATION_GATE_BEFORE_PRODUCTION = REQUIRED(在正式生产投产前必须在隔离 Kingbase 完成双跑验证)。
  • 测试与验证指标:
    • 测试套件全部通过:TOTAL_TEST_COUNT = 203 (ruoyi-train: 175, ruoyi-admin: 28),Failures = 0, Errors = 0, Skipped = 0。
    • Maven 构建:clean test 与 clean package 均 SUCCESS。
    • 代码格式校验:git diff --check = PASS。
    • 阶段评审状态:R3_WAVE1_REVIEW = PASS。
    • 提交状态:R3_WAVE1_COMMIT = COMMITTED (SHA: 22bcd1bacb66826e8e911454e9c01b54c8b64b32)。

6.4 Wave 2 DMS Adapter, Token, Poller & Mock Integration (Wave 2 implemented against Mock DMS only)

  • 阶段状态:R3_WAVE2_STATUS = PASS。
  • 配置与安全默认:
    • DMS_DEFAULT_ENABLED = FALSE:默认不开启 DMS 通信与轮询。
    • DMS_PROPERTIES:完整实现受控配置,零硬编码密钥,参数化超时与刷新窗口。
  • 令牌与通信架构:
    • TOKEN_TRANSPORT_MODEL = Cookie: token={token}(严禁使用未核实的 Authorization: Bearer)。
    • TOKEN_CACHE_MODEL = SINGLE_PROCESS_IN_MEMORY(全应用单一集中缓存)。
    • TOKEN_SINGLE_FLIGHT_MODEL = REENTRANT_LOCK_DCL(高并发过期单飞防击穿,实测 20 线程并发登录仅 1 次)。
    • TOKEN_TTL_MODEL = 7200S_WITH_REFRESH_SKEW(滑动窗口提前 120 秒平滑单飞刷新)。
    • SUCCESSFUL_API_EXTENDS_LOCAL_TTL = YES(成功调用 DMS API 顺延本地失效时间戳)。
    • AUTH_FAILURE_REFRESH_MODEL = INVALIDATE_THEN_SINGLE_FLIGHT(401 集中失效并在下一次请求单飞获取新 Token,无 login storm)。
    • AMBIGUOUS_MUTATION_AUTO_RETRY = NO(写操作读取超时坚决抑制自动重发,防止重复生成门锁凭据)。
    • DMS_HTTP_CLIENT = DmsHttpClient 统一底层通信与全局脱敏日志(零明文密码/Token/Secret 泄露)。
  • 设备与凭据适配能力:
    • LOCATION_ADAPTER = DmsLocationClient / ExternalLocationGateway(Building, Floor, Room 空间定位与 placeId 解析)。
    • DOORLOCK_ADAPTER = DmsDoorLockClient / ExternalDoorLockGateway(支持 0 把锁空列表与多把锁完整返回)。
    • ONLINE_PASSWORD_CREATE = DmsPasswordClient / ExternalCredentialGateway(支持 4~8 位数字限时密码下发,密码零落库)。
    • ONLINE_PASSWORD_DELETE = DmsPasswordClient / ExternalCredentialGateway(注销并返回 operationId)。
    • OPERATION_STATUS_QUERY = DmsOperationStatusClient。
    • VENDOR_STATUS_MAPPING = DmsOperationStatusMapper(集中统一映射,未知状态判定为 UNKNOWN,绝非 SUCCESS)。
  • 异步轮询与测试模拟:
    • POLLER_IMPLEMENTED = DmsOperationPoller(条件化启动,单进程并发防重,终态不可篡改保护,指数退避重试)。
    • POLLER_INITIAL_DELAY = 10s。
    • MULTI_INSTANCE_POLLER_LOCK = FUTURE_GATE。
    • MOCK_DMS_IMPLEMENTED = MockDmsServer(纯轻量 JDK 原生模拟,登录互斥、短 TTL、多锁/零锁与状态流转)。
  • 测试与质量指标:
    • OLD_TEST_COUNT = 203
    • NEW_TEST_COUNT = 26
    • TOTAL_TEST_COUNT = 229 (ruoyi-train: 201, ruoyi-admin: 28),Failures = 0, Errors = 0, Skipped = 0。
    • MAVEN_TEST = SUCCESS,MAVEN_PACKAGE = SUCCESS。
    • git diff --check = PASS。
  • 环境纪律与迁移标记:
    • LIVE_DMS_REQUEST_COUNT = 0(全生命周期未对公网真实 DMS 发起任何请求)。
    • FRONTEND_MODIFIED = 0,CONTROLLER_COUNT = 0。
    • 008_RUNTIME_FIRST_RUN = NOT_EXECUTED,008_RUNTIME_SECOND_RUN = NOT_EXECUTED。
    • RUNTIME_MIGRATION_GATE_BEFORE_PRODUCTION = REQUIRED。
    • COMMIT? NO,PUSH? NO,DEPLOY? NO(严格 HOLD 等待审查)。

6.5 Wave 3A Access Authorization Orchestration Dry-Run (Wave 3A implemented against Mock DMS only)

  • 阶段状态:R3_WAVE3A_STATUS = PASS。
  • 架构与模型扩展:
    • AUTH_SCHEMA_SUFFICIENT = NO(基线 train_dorm_auth 缺失凭据类型、细粒度状态、关联操作流水ID及版本号)。
    • 009_MIGRATION_REQUIRED = YES。
    • 009_MIGRATION_FILE = RuoYi-Vue/sql/system/kingbase/009_dorm_authorization_orchestration.sql(安全编号 009,幂等增量,纯非破坏性,零明文密钥)。
    • AUTHORIZATION_STATUS_MODEL = PENDING_GRANT / GRANTING / ACTIVE / PENDING_REVOKE / REVOKING / REVOKED / ERROR(厂商中立领域授权生命周期)。
    • CREDENTIAL_TYPE_MODEL = ONLINE_PASSWORD(未来可扩展 QR, CARD, MOBILE_KEY)。
    • VALIDITY_WINDOW_SOURCE = BUSINESS_POLICY_REQUIRED(一期从培训计划与住宿业务时间推导,未决策略显式记录)。
  • 统一编排与驱动机制:
    • RECONCILIATION_MODEL = AccessAuthorizationOrchestrator.reconcile(enrollmentId)(状态驱动对账,解耦业务事件发生顺序)。
    • GRANT_PRECONDITIONS = Enrollment status=1 (已报到) + Active Accommodation (status 0/1) + Active Room Mapping + Exactly 1 Primary DoorLock Mapping + 有效期可推导。
    • REPORT_CONFIRM_TRIGGER = reconcile(enrollmentId)(报到核验通过后驱动,异步对账)。
    • ACCOMMODATION_TRIGGER = reconcile(enrollmentId)(分配或激活住宿后驱动)。
    • REPORT_CONFIRM_EXTERNAL_FAILURE_ROLLBACK = NO(外部网络/DMS 失败绝不回滚报到主事务)。
    • LOCK_SELECTION_POLICY = PRIMARY_LOCK_ONLY(Least Privilege 原则,严格锁定唯一定义的主门锁发码,0主锁与多主锁阻断)。
    • RECONCILE_IDEMPOTENT = YES(多事件/重复报到触发多次 reconcile 结果幂等,无重复授权、无重复发码)。
  • 状态流转与时序保护:
    • GRANT_HTTP_SUCCESS_MARKS_ACTIVE = NO(HTTP 受理仅标记为 GRANTING/ACCEPTED,Poller 确认后方推进 ACTIVE)。
    • GRANT_SUCCESS_RESULT = ExternalOperation=SUCCESS, DoorAuthorization=ACTIVE。
    • GRANT_FAILED_RESULT = ExternalOperation=FAILED, DoorAuthorization=ERROR (保留上下文待重试)。
    • GRANT_TIMEOUT_RESULT = ExternalOperation=TIMEOUT, DoorAuthorization=ERROR (保留上下文待重试)。
    • REVOKE_SUCCESS_RESULT = ExternalOperation=SUCCESS, DoorAuthorization=REVOKED。
    • REVOKE_FAILED_RESULT = ExternalOperation=FAILED, DoorAuthorization=ERROR/REVOKING。
    • STALE_OPERATION_RESULT_GUARD = LATEST_OPERATION_OWNERSHIP_AND_VERSION_CHECK(防迟到旧操作结果覆盖已推进的新状态)。
    • LONG_DB_TRANSACTION_AROUND_HTTP = NO(本地短事务写库 -> 外部调用 -> 本地短事务更新,绝不用长事务包裹网络 IO)。
  • 换房调宿与高可用:
    • TRANSFER_POLICY = GRANT_NEW_THEN_REVOKE_OLD(先下发新宿舍门禁,对账确认 ACTIVE 后才撤销旧宿舍)。
    • TRANSFER_FAILURE_PRESERVES_OLD_ACCESS = YES(新宿舍发码失败严格保留旧宿舍门禁,保障学员可用性)。
    • TRANSFER_DUAL_ACCESS_WINDOW = ACKNOWLEDGED_FOR_AVAILABILITY(可用性优先,审计留痕)。
  • 凭据安全与零泄露:
    • PASSWORD_GENERATOR = SecurePasswordGenerator(SecureRandom 强随机、6 位纯数字、杜绝弱密码)。
    • PLAINTEXT_PASSWORD_PERSISTENCE_COUNT = 0(数据库、流水表、日志、异常栈、toString 全链路零明文留存)。
  • 未决业务与环境门禁:
    • CREDENTIAL_DELIVERY_POLICY = OPEN_QUESTION。
    • LEAVE_AUTO_REVOKE_POLICY = OPEN_QUESTION。
    • TOKEN_COOKIE_NAME = VENDOR_CONFIRMATION_REQUIRED。
    • LIVE_DMS_REQUEST_COUNT = 0(100% Mock DMS 验证)。
    • FRONTEND_MODIFIED = 0。
  • 全量测试指标:
    • OLD_TEST_COUNT = 233
    • NEW_TEST_COUNT = 18
    • TOTAL_TEST_COUNT = 251 (ruoyi-train: 219, ruoyi-admin: 32)
    • FAILURES = 0,ERRORS = 0,SKIPPED = 0。
    • MAVEN_TEST = SUCCESS,MAVEN_PACKAGE = SUCCESS。
    • git diff --check = PASS。
  • 环境纪律与迁移标记:
    • 008_RUNTIME_FIRST_RUN = NOT_EXECUTED,008_RUNTIME_SECOND_RUN = NOT_EXECUTED。
    • 009_RUNTIME_FIRST_RUN = NOT_EXECUTED,009_RUNTIME_SECOND_RUN = NOT_EXECUTED。
    • RUNTIME_MIGRATION_GATE_BEFORE_PRODUCTION = REQUIRED。
    • COMMIT? NO,PUSH? NO,DEPLOY? NO(严格 HOLD 等待审查)。