# Phase 0:设计文档、实时Kingbase与代码三方差异 > 业务判断以 `doc/RailwaySystem 智慧培训系统一期 PRD V1.0.md` 为最高依据。原始表设计只用于说明V1数据库来源,不能否定PRD V1.0已经确认的新业务对象。 ## 1. 三方总览 14个 Mapper XML 的 `resultMap` 字段数与实时表列数逐表一致:157个实际列均在对应 Mapper映射中出现。当前 Entity/Mapper与旧14表可以静态对接;主要问题来自旧表模型与PRD V1.0业务对象不一致,以及若依系统表schema冲突。 | 表 | 原设计文档 | 实际Kingbase | Entity / Mapper | 是否一致 | 主要差异 | | --- | --- | --- | --- | --- | --- | | `train_teacher` | 12列,`t_id varchar(20)` | 12列,`t_id varchar(32)`,PK,更新时间触发器,1行 | 12列全映射,`TrainTeacher` | 部分一致 | ID长度不同;PRD不再强制院系/高校职称,缺启停等培训字段 | | `train_student` | 12列,`s_id varchar(20)` | 12列,`s_id varchar(32)`,PK,更新时间触发器,0行 | 12列全映射,`TrainStudent` | 部分一致 | ID长度不同;缺加密身份证、人脸关联、培训型主档字段 | | `train_course` | 14列 | 14列,PK,更新时间触发器,0行 | 14列全映射,`TrainCourse` | 字段一致 | 附件/模型为文本列;PRD要求可选择教学资源对象 | | `train_class_plan` | 14列,单一`c_id/t_id` | 14列,`c_id/t_id`均NOT NULL且有FK,0行 | 14列全映射,`TrainClassPlan` | 旧模型一致 | 与PRD一班多课、课次教师关系直接冲突;缺报到截止规则 | | `train_dormitory_info` | 11列 | 11列,房间组合UNIQUE,更新时间触发器,0行 | 11列全映射 | 字段一致 | 只有楼栋+房间汇总,无楼层、床位、男女属性 | | `train_dorm_auth` | 12列,INT自增 | 12列,`bigint identity`,3个FK,学员/计划UNIQUE,0行 | 12列全映射,Long + generated keys | 语义部分一致 | 住宿安排与门禁授权耦合;`bed_no`是自由文本 | | `train_classroom_info` | 9列 | 9列,PK,更新时间触发器,0行 | 9列全映射 | 一致 | 基础对象符合PRD;排课关系应由课次表达 | | `train_training_site` | 10列 | 10列,PK,更新时间触发器,0行 | 10列全映射 | 一致 | 基础对象可留;`site_device`为文本而非资源关系 | | `train_class_report` | 11列,INT自增 | 11列,`bigint identity`,5个FK,计划/学员UNIQUE,0行 | 11列全映射 | 旧模型一致 | 应基于参训关系;报到行混入宿舍/教室/场地分配 | | `train_electronic_board` | 14列 | 14列,PK,SN唯一,教室/计划FK,0行 | 14列全映射 | 旧模型一致 | 缺设备名称/接口配置;直接绑计划不能表达当前课次 | | `train_student_checkin` | 10列,INT自增 | 10列,`bigint identity`,4个FK,旧课次组合UNIQUE,0行 | 10列全映射 | 旧模型一致 | 无`lesson_id`和参训关系;起止时间重复保存;没有签到/签退事件模型 | | `train_score_info` | 10列,固定三类成绩 | 10列,`bigint identity`,3个FK,计划/课程/学员UNIQUE,0行 | 10列全映射 | 旧模型一致 | 被PRD“成绩项目+权重+学员得分”正式替代 | | `train_study_duration` | 9列,INT自增 | 9列,`bigint identity`,3个FK,0行 | 9列全映射 | 一致 | PRD需参训关系、学习内容/来源和可幂等接入信息 | | `train_student_portrait` | 9列,INT自增 | 9列,`bigint identity`,学员/计划UNIQUE,0行 | 9列全映射 | 基础一致 | 与PRD简单画像接近;需参训关系和雷达展示所需基础指标 | ## 2. 旧设计与实际Kingbase的结构差异 ### 2.1 类型映射 - 设计 `DATETIME` 在Kingbase实际为 `timestamp`。 - 设计 `TINYINT` 在实际为 `smallint`。 - 设计6个 `INT AUTO_INCREMENT` 主键在实际为 `bigint GENERATED BY DEFAULT AS IDENTITY`。 - `train_teacher.t_id`、`train_student.s_id` 由设计的 `varchar(20)`扩大为实际 `varchar(32)`。 - `numeric(5,2)`、`numeric(8,2)` 精度与设计一致。 这些类型差异与当前 Java `Date`、`Long`、`BigDecimal`、`String` 基本兼容。 ### 2.2 实际约束超过设计文本 实时库明确存在24个外键,以及以下业务唯一约束: - 报到:`plan_id + student_id` - 宿舍授权:`student_id + plan_id` - 宿舍房间:`dorm_building + dorm_room` - 班牌:`board_sn` - 成绩:`plan_id + c_id + student_id` - 签到:`plan_id + c_id + student_id + lesson_start_time` - 画像:`student_id + plan_id` 这些约束未体现在 Entity注解或业务校验中,错误主要由数据库返回。除主键/唯一索引外,外键列没有额外非唯一索引。 ### 2.3 更新时间 教师、学员、课程、计划、宿舍、宿舍授权、教室、场地、班牌9张表有UPDATE触发器维护 `update_time`。部分 ServiceImpl同时设置更新时间,形成数据库与应用双重维护。 ## 3. 一班多课与课次迁移影响 ### 当前结构 ```text train_class_plan ├── c_id NOT NULL -> train_course └── t_id NOT NULL -> train_teacher ``` 这会把“培训班”“本期课程”“具体授课安排”压在一行中。 ### PRD V1.0要求的初步迁移方向 ```text 开班计划 ↔ 开班课程 → 课次(教师、时间、教室或实训场地) ``` - `train_class_plan`保留培训班核心信息。 - `c_id`对应的信息迁入独立“开班课程”关系,一个计划可多条。 - `t_id`不应继续代表整个培训班唯一教师;PRD将教师安排到具体课次。 - 计划应补充开班级报到截止规则。 - 当前 `train_class_plan` 为0行,实时库不存在需要搬迁的历史计划;这降低数据风险,但不消除 Controller、页面、Mapper和外键改造范围。 本报告不确定最终表名、主键或DDL。 ## 4. 参训关系缺口与迁移影响 当前没有独立 `student + plan` 参训关系。以下6张表重复保存两者: | 当前表 | 重复字段 | 新增参训关系后的初步引用对象 | 当前行数 | | --- | --- | --- | ---: | | `train_dorm_auth` | `student_id + plan_id` | 住宿安排/门禁授权所属参训人 | 0 | | `train_class_report` | `student_id + plan_id` | 报到所属参训人 | 0 | | `train_student_checkin` | `student_id + plan_id` | 考勤所属参训人 | 0 | | `train_score_info` | `student_id + plan_id` | 成绩所属参训人 | 0 | | `train_study_duration` | `student_id + plan_id` | 学习记录所属参训人 | 0 | | `train_student_portrait` | `student_id + plan_id` | 画像所属参训人 | 0 | 新增参训关系后,上述对象可以引用参训关系,避免每个模块独立解释学员在本期的资格和状态。同一学员/计划应由参训关系保证唯一。 当前6张表均为空,没有现存业务行需要转换。若数据库V2前产生数据,迁移时必须先按唯一的 `student_id + plan_id` 生成参训记录,再把报到、考勤、成绩、学习、画像、住宿/授权关联到相应参训记录。 ## 5. `lesson_id` 对现有数据和代码的影响 ### 当前签到 `train_student_checkin` 用: ```text plan_id + c_id + student_id + lesson_start_time ``` 模拟课次身份,并保存 `lesson_end_time`;唯一约束也以这组字段为基础。 ### 加入正式课次后的影响 - 签到/考勤需要引用课次和参训关系,旧 `plan_id/c_id/lesson_start_time/lesson_end_time` 不再承担课次主键作用。 - `train_class_plan.t_id` 中的教师关系应进入课次。 - 教室和实训场地应由课次安排,不应继续由 `train_class_report.alloc_classroom_id/alloc_site_id` 作为学员报到分配。 - 班牌保留与教室关系;当前展示内容应由教室在当前时段的课次决定,`bind_plan_id`不能覆盖多班多课排期。 - Controller、查询条件、前端签到表单、唯一约束、统计维度和Mock班牌接口都会受影响。 - 当前计划、签到、教室、场地和班牌表均为0行,不存在历史课次数据;未来迁移不能只凭相同起止时间推断课次,需在产生数据前冻结V2。 ## 6. 宿舍:资源、床位、住宿安排、门禁授权 当前表达为: ```text train_dormitory_info(房间汇总+bed_total/bed_used+门锁SN) → train_dorm_auth(学员+计划+房间+bed_no+人脸同步状态) ← train_class_report.alloc_dorm_id(报到记录再次保存房间) ``` 无法完整表达PRD V1.0的: ```text 宿舍资源 → 床位 → 住宿安排 → 门禁授权 ``` 初步影响: - `train_dormitory_info`可作为房间资源的来源,但缺楼层、床位实体、男女属性和可靠剩余量。 - `bed_no`只是授权表文本,不能单独管理床位占用。 - `train_dorm_auth`同时保存住宿事实和设备同步事实,需要拆开看待。 - `train_class_report.alloc_dorm_id`与报到前预分配冲突;报到应读取已有住宿安排,而不是创建住宿事实。 - 这3张表当前均0行,没有现有住宿数据需要搬迁;V2仍需定义从旧授权行拆出住宿安排和门禁授权的规则,以防切换前产生数据。 ## 7. 成绩模型变化 ### 当前字段 `train_score_info` 固定: ```text plan_id, c_id, student_id, course_score, train_score, exam_score, source_type, source_system, import_time ``` ### PRD V1.0目标 ```text 培训班 → 成绩项目 → 权重 参训学员 → 成绩项目 → 得分 ``` ### 初步迁移判断 - `course_score`、`train_score`、`exam_score` 三个固定分数字段将不再是最终模型,未来可能废弃或仅作为迁移来源。 - `plan_id`、`c_id`、`student_id` 可用于识别旧成绩所属培训班/课程/学员;其中学员+计划应先映射参训关系,课程或其他考核类型应映射成绩项目。 - `source_type`、`source_system`、`import_time` 的来源追溯语义仍有保留价值,可随具体得分记录迁移。 - 旧唯一约束 `plan_id+c_id+student_id` 无法支持同课程多个成绩项目或非课程考核。 - 当前 `train_score_info` 精确行数为0,因此不存在真实成绩迁移;从数据角度现在是调整模型的低风险窗口。 - 代码层仍有 Entity、Mapper、Controller、API、成绩CRUD、课程成绩页和学员成绩页依赖固定三列,因此不能只改数据库。所谓“安全重构”仅指没有生产成绩数据需要保留,不代表代码改造可以无评审完成。 ## 8. PRD V1.0明确不应再作为一期阻塞的旧要求 - 课程版本、课程审批、草稿/发布/归档、复杂标签、热门、初级/进阶:PRD V1.0明确不做;当前代码缺少这些能力不是一期阻塞。 - 复杂画像规则引擎:一期只需基础指标、简单标签、雷达图。当前画像表可作为简单结果载体,主要缺参训关系、指标生成和雷达展示。 - 自动结业规则引擎:一期按培训结束、状态完成、历史数据保留处理。当前不应新增“签到率+成绩+时长”自动结业复杂逻辑。 ## 9. 实时数据库数据对迁移窗口的影响 - 必须保留/迁移:`train_teacher`唯一1行教师数据。 - 当前无历史业务数据:其余13张培训表全部0行,包括成绩、计划、参训相关明细、住宿、签到、学习和画像。 - 需要保留并重新评审的系统配置:23条培训菜单行。 - 需要先处理的数据异常:`public.sys_role`为空,而用户角色、角色菜单关系已有孤儿数据;不能把这些关系直接当作有效权限基线迁入V2。