Files
railwaysystem/docs/current/03-DATABASE-AND-TABLES.md
T

193 lines
17 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.
# 03 - 数据库架构、迁移链与真实 Bootstrap Chain (Database and Tables)
> **核心原则**:当前阶段**严格只读,不修改数据库,不清库,不执行数据变更,不创建新库**。
> 本文件严谨定义未来纯净演示库建立的真正可重复引导链 (`CLEAN_DATABASE_BOOTSTRAP_CHAIN`)。
---
## 1. 数据库基本信息
- **数据库管理系统 (DBMS)**:国产人大金仓分析型/事务型关系数据库 (KingbaseES V009R003C018)
- **数据库兼容模式**:`database_mode = mysql`(兼容 MySQL DDL/DML 方言与自增特性)
- **底层内核兼容版本**:`server_version = 12.1` (PostgreSQL 12 兼容内核)
- **默认 Schema**:`public`
- **正式综合验收数据库**:`railwaysystem_integrated_qa_20260916`
- **当前共享试用数据库**:`training`
- **未来纯净演示数据库规划**:`training_demo_clean` (详见 [CLEAN_DEMO_DATABASE_SPEC.md](CLEAN_DEMO_DATABASE_SPEC.md))
---
## 2. 数据库真正 Bootstrap Chain 深度审计 (Task 1 结论)
### 2.1 核心疑问解答与实证剖析
#### A. 一个完全空的 Kingbase 数据库,必须先执行哪个 Base Schema?
**确凿结论**:
1. **系统底座首要执行脚本**:`RuoYi-Vue/sql/ry_20250522.sql`
- **内容**:创建若依基础平台核心表(`sys_dept`、`sys_user`、`sys_post`、`sys_role`、`sys_menu`、`sys_user_role`、`sys_role_menu`、`sys_role_dept`、`sys_user_post`、`sys_oper_log`、`sys_dict_type`、`sys_dict_data`、`sys_config`、`sys_logininfor`、`sys_notice`、`gen_table`、`gen_table_column`),并插入超级管理员账号 (`admin` / `user_id=1`)、组织部门、基础字典数据与基础菜单;
- **方言依赖**:必须在 KingbaseES `database_mode=mysql` 模式下执行。
2. **定时调度基础设施脚本**:`RuoYi-Vue/sql/quartz.sql`
- **内容**:创建 Quartz 调度框架所需的 11 张 `QRTZ_*` 表结构;
3. **代码生成器自增主键兼容补丁**:
- `RuoYi-Vue/sql/generator/kingbase/002a_gen_table_identity_patch.sql`
- `RuoYi-Vue/sql/generator/kingbase/002b_gen_table_column_identity_patch.sql`
- **内容**:将 `gen_table` 与 `gen_table_column` 主键修正为 `GENERATED BY DEFAULT AS IDENTITY`,防止导入表元数据时发生主键冲突 (02_kingbase_import_identity_patch)。
#### B. train/v2 migration 的真正前置 schema 是什么?
**确凿结论**:
`RuoYi-Vue/sql/train/v2/` 是一套**增量重构与演进迁移脚本**,**绝非**从零建库脚本!
其各步骤依赖的前置物理表如下:
- `000_preflight.sql`:严格断言必须精确存在 Phase 0.5 历史基线的 **14 张旧业务表**、14 PK、24 FK、7 UNIQUE、6 Identity、9 个触发器,且断言 `sys_user` 必须恰为 1 行、`sys_menu` 为 106 行、`sys_dept` 为 15 行、`sys_dict_type` 为 44 行、`sys_dict_data` 为 500 行;
- `001_backup_current_schema.sql`:通过 `CREATE TABLE bak_v1_* AS SELECT * FROM ...` 备份 14 张旧表,**直接依赖** 14 张 Phase 0.5 旧表已存在;
- `002_create_new_tables.sql`:创建 V2 新增的 8 张核心表(`train_resource`、`train_course_resource`、`train_plan_course`、`train_enrollment`、`train_lesson`、`train_accommodation`、`train_score_item`、`train_student_score`);
- `003_alter_master_tables.sql`:**直接依赖** 8 张主数据表已存在并对其执行 `ALTER TABLE`(`train_teacher`、`train_student`、`train_course`、`train_classroom_info`、`train_training_site`、`train_electronic_board`、`train_dormitory_info`、`train_class_plan`);
- `004_rebuild_business_tables.sql`:**直接依赖** 5 张旧过程表已存在(`train_dorm_auth`、`train_class_report`、`train_student_checkin`、`train_study_duration`、`train_student_portrait`),校验其为 0 行后 DROP 并重建;
- `008_migrate_teacher.sql`:**直接依赖** `train_teacher` 已存在、具备旧字段(`t_department`、`t_title`、`create_user`)及新扩展字段,且**严格断言 `SELECT count(*) FROM train_teacher = 1`**(必须有且仅有 1 行基线数据可供清洗提升);
- `009_drop_legacy_score.sql`:**直接依赖** `train_score_info` 已存在且行数为 0,随后解除约束并 DROP。
👉 **前置基线提供源**:`RuoYi-Vue/sql/train/v2/rollback/000_phase05_exact_schema.sql`!
该文件精确定义了 Phase 0.5 历史基线 14 张表物理 DDL、约束与触发器。在一个全新空数据库中,必须先执行该文件并写入 1 条基线教师占位记录,`000~010` 迁移链方可成功跑通!
#### C. system/kingbase 001~015 的前置条件是什么?
**确凿结论**:
`RuoYi-Vue/sql/system/kingbase/` 中的补丁同样是增量补丁,其依赖条件如下:
- `001_sys_oper_log_cost_time.sql`:依赖 `public.sys_oper_log` 表存在;
- `002`、`003`、`010`、`011`、`012`、`013`、`014`、`015`:均对 `public.sys_menu` 及 `public.sys_role_menu` 执行 INSERT / UPDATE,依赖 `sys_menu`、`sys_role_menu` 存在;
- `004_rbac_identity_binding.sql`:对 `train_teacher` 与 `train_student` 增加 `user_id` 并创建外键指向 `sys_user(user_id)`,**必须依赖 `train_teacher`、`train_student` 与 `sys_user` 均已存在**;
- `005_training_roles_permissions.sql`:创建培训角色(`role_id=3` train_admin, `role_id=4` train_teacher, `role_id=5` train_student),依赖 `sys_role`、`sys_menu`、`sys_role_menu` 存在;
- `006_accommodation_history_constraint.sql`:在 `train_accommodation` 上创建局部唯一索引,**依赖 `train_accommodation` 表已存在**(由 `002_create_new_tables.sql` 创建);
- `008_external_resource_operation.sql`:创建 `train_external_resource_mapping`(外键引用 `train_dormitory_info(dorm_id)`)与 `train_external_operation`,**依赖 `train_dormitory_info` 表已存在**;
- `009_dorm_authorization_orchestration.sql`:修改 `train_dorm_auth` 表结构并添加指向 `train_accommodation(accommodation_id)` 的外键,**依赖 `train_dorm_auth`(004 重建后)与 `train_accommodation` 均已存在**;
- `015_dms_package_a_hardening.sql`:向 `role_id=3` (train_admin) 授权 `menu_id=2263` (`train:accommodation:edit`),**依赖 `sys_role` (已包含 role_id=3) 与 `sys_menu` 均已存在**;
- *(注:`007` 号脚本因历史规划冲突被跳过,严禁执行 `007_dicts.sql`)*。
---
### 2.2 严格可重复执行的引导链定义 (`CLEAN_DATABASE_BOOTSTRAP_CHAIN`)
基于上述源码与 SQL 依赖实证,建立唯一的 7 阶段标准建库流水线:
```text
================================================================================
CLEAN_DATABASE_BOOTSTRAP_CHAIN (标准纯净库引导执行链)
================================================================================
[STEP 0: 数据库实例与方言就绪]
└─ 执行: CREATE DATABASE training_demo_clean WITH OWNER = kingbase;
└─ 确保: database_mode = mysql, search_path = public
[STEP 1: RuoYi 基础平台结构与初始化]
├─ 1.1 RuoYi-Vue/sql/ry_20250522.sql (sys_* 基础表与系统管理员、默认字典)
├─ 1.2 RuoYi-Vue/sql/quartz.sql (QRTZ_* 调度引擎 11 张基础表)
└─ 1.3 RuoYi-Vue/sql/generator/kingbase/ (002a + 002b Generator 主键 Identity 补丁)
[STEP 2: 培训业务历史基线骨架构建]
├─ 2.1 RuoYi-Vue/sql/train/v2/rollback/000_phase05_exact_schema.sql
│ (创建 14 张 Phase 0.5 历史基线表、外键、唯一约束与 update_time 触发器函数)
└─ 2.2 RuoYi-Vue/sql/train/v2/bootstrap/000_seed_baseline_teacher.sql
(确定性注入 1 条基线教师记录 T001,满足 000 预检精确断言与 008 迁移清洗)
[STEP 3: 培训业务 V2 结构演进迁移]
├─ 3.1 000_preflight.sql (严格只读核验 Phase 0.5 基线与 sys_* 行数)
├─ 3.2 000_tx_capability_probe.sql (验证显式事务与 DDL 回滚能力)
├─ 3.3 001_backup_current_schema.sql (创建 bak_v1_* 历史结构快照)
├─ 3.4 002_create_new_tables.sql (创建 8 张 V2 新表: 排课、选课、住宿台账等)
├─ 3.5 003_alter_master_tables.sql (解绑旧外键/触发器,扩展主数据表字段)
├─ 3.6 004_rebuild_business_tables.sql (重构 5 张空业务过程表)
├─ 3.7 005_constraints.sql (补充 V2 级联完整性与 CHECK 互斥约束)
├─ 3.8 006_indexes.sql (创建排课冲突与高频组合性能索引)
├─ 3.9 【跳过 007_dicts.sql】(严禁执行)
├─ 3.10 008_migrate_teacher.sql (清洗提升 1 条基线教师并固化 NOT NULL 约束)
├─ 3.11 009_drop_legacy_score.sql (安全淘汰旧 train_score_info 表)
└─ 3.12 010_verify.sql (终检验收 V2 架构 100% 合规)
[STEP 4: 系统底层与权限治理强化补丁]
├─ 4.1 001_sys_oper_log_cost_time.sql (日志耗时字段)
├─ 4.2 002_legacy_analytics_permissions.sql
├─ 4.3 003_report_attendance_action_permissions.sql
├─ 4.4 004_rbac_identity_binding.sql (强绑定教师/学员与 sys_user 账号)
├─ 4.5 005_training_roles_permissions.sql (初始化 train_admin/teacher/student 3大业务角色)
├─ 4.6 006_accommodation_history_constraint.sql (在用床位局部唯一索引)
├─ 4.7 008_external_resource_operation.sql (创建外部资源映射与操作流水表)
├─ 4.8 009_dorm_authorization_orchestration.sql (门禁凭据与授权生命周期扩展)
├─ 4.9 010_dms_access_management_permissions.sql
├─ 4.10 011_teacher_student_remove_permissions.sql
├─ 4.11 012_analytics_v1_permissions.sql
├─ 4.12 013_interaction_route_cleanup.sql
├─ 4.13 014_dms_access_safety_and_accommodation_permissions.sql
└─ 4.14 015_dms_package_a_hardening.sql (ACCOM_PERM 闭环,授权 role_id=3 拥有 menu 2263)
[STEP 5: 数据库架构与完整性断言终检]
├─ 断言 21 张 train_* 业务表全部存在且 DDL 结构合规
├─ 断言 15 张核心 sys_* 表无受损,角色 3 具备 menu 2263 且无破坏性 remove 权限
└─ 检查 0 孤儿外键、0 冲突索引
[STEP 6: 确定性演示种子数据灌入 (Deterministic Demo Seed)]
└─ 灌入时序严密、100% 覆盖 UI 界面的高质量确定性演示业务数据 (绝不含历史脏数据)
================================================================================
```
---
## 3. 全量业务数据表总账 (21 张 V2 核心业务表 + 2 张 DMS 扩展表 + 1 张历史表)
### 3.1 核心业务表总账 (21 张 `train_*` 表,由 `010_verify.sql` 强制断言)
| 序号 | 表名 (TABLE_NAME) | 物理主键类型 | 来源迁移脚本 | 表职责说明 (PURPOSE) | 核心外键与关键关联 (RELATIONSHIPS) |
| :---: | :--- | :--- | :---: | :--- | :--- |
| **01** | `train_teacher` | `VARCHAR(32)` | 000 + 003 + 008 | 授课教师档案主表,记录姓名、工号、职称、身份证密文 | `sys_user.user_id` (账号强绑定) |
| **02** | `train_student` | `VARCHAR(32)` | 000 + 003 | 参训学员主档表,记录学员信息、单位、手机与身份证密文 | `sys_user.user_id` (账号强绑定) |
| **03** | `train_course` | `VARCHAR(32)` | 000 + 003 | 课程标准库主表,记录课程编号、名称、理论/实作类别与学时 | 被 `train_plan_course`、`train_lesson` 引用 |
| **04** | `train_resource` | `VARCHAR(32)` | 002 | 统一教学资源主表,存放课件、视频、教材电子档等元数据 | 被 `train_course_resource`、`train_study_duration` 引用 |
| **05** | `train_course_resource` | `BIGINT (ID)` | 002 | 课程与教学资源关联表 (N:M),指定课程关联课件与资料 | 关联 `c_id`、`resource_id` |
| **06** | `train_classroom_info` | `BIGINT (ID)` | 000 + 003 | 教学教室信息表,记录教室编号、楼栋、容纳人数与配备 | 被 `train_lesson` 引用 (教室时段互斥) |
| **07** | `train_training_site` | `BIGINT (ID)` | 000 + 003 | 实训演练场地表,记录室内/室外工区、容量与安全规范 | 被 `train_lesson` 引用 (场地时段互斥) |
| **08** | `train_electronic_board` | `BIGINT (ID)` | 000 + 003 | 电子班牌硬件设备信息表,记录设备 MAC、SN、挂接教室与通信时间 | 关联 `bind_classroom_id` |
| **09** | `train_dormitory_info` | `BIGINT (ID)` | 000 + 003 | 宿舍房间主表,记录宿舍楼栋、房号、性别分类、总床位数与在用数 | 被 `train_accommodation`、`train_external_resource_mapping` 引用 |
| **10** | `train_class_plan` | `VARCHAR(32)` | 000 + 003 | 培训开班计划主表 (物理表名 `train_class_plan`,非 `train_plan`),控制班级全生命周期 | 驱动 `train_plan_course`、`train_enrollment`、`train_score_item` |
| **11** | `train_plan_course` | `BIGINT (ID)` | 002 | 班级课程关系表 (N:M),指定培训班开设课程及授课教师 | 关联 `plan_id`、`c_id` |
| **12** | `train_enrollment` | `BIGINT (ID)` | 002 | 参训人员名册表,定义学员参加班级及参训状态 (待报到/在训/结训) | 关联 `plan_id`、`student_id` |
| **13** | `train_lesson` | `BIGINT (ID)` | 002 | 课次排课表,记录每次课的具体时段、地点与授课教师 (互斥 CHECK) | 关联 `plan_course_id`、`t_id`、场地/教室 |
| **14** | `train_accommodation` | `BIGINT (ID)` | 002 | 学员住宿分配台账表,记录床位分配、入住/退宿/调房生命周期 | 关联 `enrollment_id`、`dorm_id` |
| **15** | `train_dorm_auth` | `BIGINT (ID)` | 004 + 系统 009 | 门禁卡/密码授权编排状态表,维护门锁下发授权生命周期 | 关联 `accommodation_id` |
| **16** | `train_class_report` | `BIGINT (ID)` | 004 重建 | 现场报到核验记录表,学员到校开班报到凭据流水 | 关联 `enrollment_id` |
| **17** | `train_student_checkin` | `BIGINT (ID)` | 004 重建 | 课堂考勤打卡流水表,记录学员签到、签退与出勤状态 | 关联 `enrollment_id`、`lesson_id` |
| **18** | `train_score_item` | `BIGINT (ID)` | 002 | 成绩考评科目项标准表 (理论/实作/平时),定义满分与权重 | 关联 `plan_id`、`plan_course_id` |
| **19** | `train_student_score` | `BIGINT (ID)` | 002 | 学员细粒度科目成绩得分表,记录各项考评实得分数 | 关联 `enrollment_id`、`score_item_id` |
| **20** | `train_study_duration` | `BIGINT (ID)` | 004 重建 | 自主学习时长流水表,记录学员研读教学资料的计时时长 | 关联 `enrollment_id`、`plan_course_id`、`resource_id` |
| **21** | `train_student_portrait` | `BIGINT (ID)` | 004 重建 | 学员参训全过程综合评估与画像表,多维画像统计数据 | 关联 `enrollment_id` (uq_student_portrait_enroll) |
---
### 3.2 外部集成扩展表 (2 张 `train_*` 表,由系统脚本 008 创建)
| 序号 | 表名 (TABLE_NAME) | 物理主键类型 | 来源迁移脚本 | 表职责说明 (PURPOSE) | 核心外键与关键关联 (RELATIONSHIPS) |
| :---: | :--- | :--- | :---: | :--- | :--- |
| **22** | `train_external_resource_mapping` | `BIGINT (ID)` | 系统 008 | 外部资源映射关联表,记录本地宿舍与外部 DMS 空间/锁具的映射关系 | 关联 `dorm_id` (train_dormitory_info)、`external_resource_id` |
| **23** | `train_external_operation` | `BIGINT (ID)` | 系统 008 | 外部异步操作流水表,记录向 DMS 下发密码/撤销的异步 operationId 对账流水 | 关联 `door_auth_id` (train_dorm_auth)、幂等键 `idempotency_key` |
---
### 3.3 历史遗留与系统底座数据表说明
| 类别 | 表名 (TABLE_NAME) | 状态与职责说明 |
| :--- | :--- | :--- |
| **历史下线表** | `train_score_info` | 历史 Phase 0.5 单表成绩模型。状态为 **`LEGACY_DROPPED / NON_RUNTIME`**。已由 `009_drop_legacy_score.sql` 彻底删除,并由 `010_verify.sql` 强断言不存在。所有 Controller 与运行时 Mapper 已完成 V2 架构平滑切换,底层直接读写 `train_score_item` 与 `train_student_score`,代码库与运行时已实现 0 引用。 |
| **系统底座表** | `sys_user` | 若依平台核心用户主档表,与 `train_teacher`、`train_student` 通过 `user_id` 建立强外键关联与 RBAC 权限绑定。 |
| **平台管理表** | `sys_dept`、`sys_role`、`sys_menu`、`sys_dict_type`、`sys_dict_data`、`sys_config`、`sys_oper_log` 等 | 若依平台底层通用表结构,支持多部门组织架构、角色菜单授权与操作审计。 |
---
### 3.4 数据库备份与恢复命令核验 (Kingbase Backup Command Verification)
- **环境识别**:KingbaseES V009R003C018(默认端口 4321,协议兼容 PostgreSQL 语法但系统字典与扩展类型具备独立实现)。
- **备份工具核验**:
- macOS 本地开发机未安装本地 Kingbase/Postgres 二进制工具 (`sys_dump`/`pg_dump` not found);
- 生产及测试环境(宿主机 `192.168.139.218`)采用 KingbaseES 官方原生逻辑备份工具 **`sys_dump`**;
- 官方标准二进制逻辑归档备份命令:
`sys_dump -h 192.168.139.218 -p 4321 -U <user> -d <dbname> -F c -b -v -f <backup_file.dmp>`
- 官方纯文本 SQL 逻辑导出命令:
`sys_dump -h 192.168.139.218 -p 4321 -U <user> -d <dbname> -f <backup_file.sql>`
- 对应恢复工具为 **`sys_restore`** 或 **`ksql`**;
- 严禁在未验证客户端直接假设 `pg_dump`,必须使用 KingbaseES 原生 `sys_dump` 确保对象权限、OID、Identity 自增列序列元数据完整备份。