Files
railwaysystem/docs/codebase-audit/14_database_code_diff.md
wangzhibiao fb00f67d3b docs(审计): 完成Phase 0工程与数据库基线核验
记录当前Git开发基线、Kingbase真实表结构、培训数据与权限状态。

补充数据库与代码差异、只读兼容性验证及PRD V1.0核心对象映射,未包含业务代码或数据库修改。
2026-09-14 00:36:53 +08:00

186 lines
11 KiB
Markdown
Raw Permalink 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.
# 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。