Files
railwaysystem/docs/development/rbac-r2/06_migration_plan.md
T

113 lines
5.6 KiB
Markdown

# RailwaySystem 数据库迁移方案设计 (Migration Plan)
- **设计版本**: R.2A Design Freeze
- **设计日期**: 2026-09-15
- **适用数据库**: 国产主库 KingbaseES V009R003C018 (JDBC 依赖 8.6.0, schema: public)
- **核心目标**: 规范 R.2B 阶段所需的数据库变更脚本清单、序号规则、幂等性保障与零风险回滚方案,确保 100% 兼容现有生产业务。
---
## 1. 现有正式 Migration 脚本全量排查
在设计新脚本前,已完成对代码库中所有既有 SQL 脚本的编号与职责排查:
### 1.1 `RuoYi-Vue/sql/system/kingbase/` (系统级通用补丁)
- `001_sys_oper_log_cost_time.sql`: 操作日志表新增 `cost_time` 耗时列 (BIGINT DEFAULT 0)。
- `002_legacy_analytics_permissions.sql`: 学员画像与学习时长按钮权限补齐。
- `003_report_attendance_action_permissions.sql`: 报到确认与课次考勤核心 Action 权限补齐。
- **最新可用起始编号**: `004`。
### 1.2 `RuoYi-Vue/sql/train/v2/` (培训业务领域专用)
- `000_preflight.sql` ~ `010_verify.sql` (覆盖 V2 架构演进全量表调整与数据过渡)。
- **红线警示**: `007_dicts.sql` 严禁在生产或后续环节执行 (**DO NOT EXECUTE**)。
---
## 2. R.2 计划发布的数据库迁移脚本清单 (PROPOSED_MIGRATIONS)
为避免目录混杂,R.2 的 RBAC 迁移脚本统一归入 `RuoYi-Vue/sql/system/kingbase/` 序列:
```
RuoYi-Vue/sql/system/kingbase/
├── 004_rbac_identity_binding.sql # 物理约束与身份唯一性索引
└── 005_training_roles_permissions.sql # 角色预置、菜单补全与权限映射
```
### 2.1 脚本 1: `004_rbac_identity_binding.sql`
- **执行目标**:
1. 幂等确认 `train_teacher` 和 `train_student` 的 `user_id BIGINT` 列。
2. 建立针对非空 `user_id` 的部分唯一索引(Partial Unique Index),保障一个登录账户只能绑定一个业务主体。
3. 增加注释与完整性元数据。
- **DDL 设计核心内容**:
```sql
BEGIN;
-- 1. 确保列存在 (兼容早期分支)
ALTER TABLE train_teacher ADD COLUMN IF NOT EXISTS user_id BIGINT;
ALTER TABLE train_student ADD COLUMN IF NOT EXISTS user_id BIGINT;
-- 2. 建立教师账号唯一索引 (忽略已删除 del_flag='2' 与空值)
DROP INDEX IF EXISTS uq_train_teacher_user_id;
CREATE UNIQUE INDEX uq_train_teacher_user_id
ON train_teacher(user_id)
WHERE user_id IS NOT NULL AND del_flag = '0';
-- 3. 建立学员账号唯一索引
DROP INDEX IF EXISTS uq_train_student_user_id;
CREATE UNIQUE INDEX uq_train_student_user_id
ON train_student(user_id)
WHERE user_id IS NOT NULL AND del_flag = '0';
COMMENT ON COLUMN train_teacher.user_id IS '关联sys_user.user_id (唯一绑定教师登录账号)';
COMMENT ON COLUMN train_student.user_id IS '关联sys_user.user_id (唯一绑定学员登录账号)';
COMMIT;
```
### 2.2 脚本 2: `005_training_roles_permissions.sql`
- **执行目标**:
1. 预置 3 个业务角色 (`train_admin`, `train_teacher`, `train_student`) 写入 `sys_role`。
2. 补齐 `sys_menu` 中历史遗漏的基础模块按钮级权限(`train:teacher:*`, `train:student:*`, `train:course:*`, `train:plan:*`, `train:lesson:*` 等)。
3. 将 `system:board:*` 权限标识收敛对齐为 `train:board:*`。
4. 插入 Teacher 工作台菜单与 Student 个人中心菜单节点。
5. 幂等配置 `sys_role_menu` 角色菜单权限映射。
- **DML 设计核心内容**:
```sql
BEGIN;
-- 1. 预置角色 (使用特定固定 role_id 3, 4, 5,采用 ON CONFLICT DO NOTHING 保证幂等)
INSERT INTO sys_role (role_id, role_name, role_key, role_sort, data_scope, menu_check_strictly, dept_check_strictly, status, del_flag, create_by, create_time, remark)
VALUES
(3, '培训管理员', 'train_admin', 3, '1', 1, 1, '0', '0', 'admin', CURRENT_TIMESTAMP, '一期业务全局管理角色'),
(4, '培训教师', 'train_teacher', 4, '2', 1, 1, '0', '0', 'admin', CURRENT_TIMESTAMP, '教师专属教学工作台'),
(5, '培训学员', 'train_student', 5, '2', 1, 1, '0', '0', 'admin', CURRENT_TIMESTAMP, '学员专属个人培训中心')
ON CONFLICT (role_id) DO NOTHING;
-- 2. 补齐基础管理模块按钮权限 (示例:教师管理按钮)
-- 采用 WHERE NOT EXISTS 确保多次执行安全幂等
-- ... (录入 train:teacher:list/add/edit/query/export 等节点)
-- 3. 统一规范电子班牌命名空间
UPDATE sys_menu SET perms = REPLACE(perms, 'system:board:', 'train:board:')
WHERE perms LIKE 'system:board:%';
-- 4. 建立角色与菜单权限关联 (sys_role_menu)
-- train_admin: 分配全部培训业务管理菜单及按钮
-- train_teacher: 分配教师工作台、我的课表、我的班级学员菜单
-- train_student: 分配学员中心、我的课表、我的报到、我的考勤菜单
COMMIT;
```
---
## 3. 生产兼容性与无损回滚设计 (Rollback Safety)
1. **绝对向前兼容 (Zero Breaking Change)**:
- 现有超级管理员 `admin (role_id=1)` 依靠 `*:*:*` 拥有全量通配权限,新增角色与菜单对已有超管管理流程无任何不良影响。
- 所有已有历史数据中 `train_teacher.user_id` 和 `train_student.user_id` 为 NULL 的记录完全保留,部分唯一索引不校验 NULL,历史数据不会产生约束冲突。
2. **零 DDL 锁表风险**:
- KingbaseES / PostgreSQL 架构中,`ADD COLUMN IF NOT EXISTS` 与 `CREATE INDEX ... WHERE ...` 操作毫秒级完成,不锁死数据读写。
3. **独立可执行与验证**:
- 脚本必须具备单向独立执行性,并在脚本末尾集成 `DO $$ ... RAISE NOTICE ... $$;` 自检核验块。