From 277c9e210ef489fbf0a95afee917afd3ec46a2f7 Mon Sep 17 00:00:00 2001 From: wangzhibiao Date: Mon, 14 Sep 2026 02:13:01 +0800 Subject: [PATCH] =?UTF-8?q?docs(db):=20=E5=86=BB=E7=BB=93RailwaySystem?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93V2=E8=AE=BE=E8=AE=A1=E5=9F=BA?= =?UTF-8?q?=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...�®库 V2 字段设计与 Kingbase DDL 规范 V1.0.md | 1514 +++++++++++++++++ 1 file changed, 1514 insertions(+) create mode 100644 doc/RailwaySystem 数据库 V2 字段设计与 Kingbase DDL 规范 V1.0.md diff --git a/doc/RailwaySystem 数据库 V2 字段设计与 Kingbase DDL 规范 V1.0.md b/doc/RailwaySystem 数据库 V2 字段设计与 Kingbase DDL 规范 V1.0.md new file mode 100644 index 000000000..e49c68486 --- /dev/null +++ b/doc/RailwaySystem 数据库 V2 字段设计与 Kingbase DDL 规范 V1.0.md @@ -0,0 +1,1514 @@ +# RailwaySystem 数据库 V2 字段设计与 Kingbase DDL 规范 V1.0 + +> **状态:** 数据库设计冻结稿 +> **业务依据:** PRD V1.0 + 第二次会议记录 +> **技术基线:** `main@4b450f46` +> +> 本文档目标: +> +> 1. 冻结一期 21 张培训业务表; +> 2. 冻结关键字段和关系; +> 3. 冻结 PK / FK / UNIQUE / INDEX; +> 4. 为下一步 Kingbase 可执行 DDL 提供唯一依据。 + +第二次会议已经明确:一个培训班包含多门课程,之后再安排教师、时间、教室和场地形成课程表;另外需要独立关系表示“哪些人员参加哪个班”。 + +--- + +# 1. 最终表清单 + +## 1.1 基础资料 + +```text +1 train_teacher +2 train_student +3 train_course +4 train_resource +5 train_course_resource +6 train_classroom_info +7 train_training_site +8 train_electronic_board +9 train_dormitory_info +``` + +## 1.2 培训组织 + +```text +10 train_class_plan +11 train_plan_course +12 train_enrollment +13 train_lesson +``` + +## 1.3 培训执行 + +```text +14 train_accommodation +15 train_dorm_auth +16 train_class_report +17 train_student_checkin +``` + +## 1.4 培训结果 + +```text +18 train_score_item +19 train_student_score +20 train_study_duration +21 train_student_portrait +``` + +--- + +# 2. 淘汰旧表 + +```text +train_score_info +``` + +不进入 V2 正式模型。 + +当前真实表中该表为 0 行,因此没有成绩历史迁移压力。 + +--- + +# 3. 公共规范 + +## 3.1 字符集 + +字符串默认: + +```text +varchar +text +``` + +数据库: + +```text +KingbaseES +schema = public +``` + +--- + +## 3.2 主键 + +基础主数据继续使用: + +```text +varchar(32) +``` + +关系与业务记录统一: + +```sql +bigint GENERATED BY DEFAULT AS IDENTITY +``` + +--- + +# 3.3 时间类型 + +统一使用: + +```sql +timestamp +``` + +禁止再使用设计文档里的: + +```text +DATETIME +``` + +--- + +# 3.4 状态字段 + +统一: + +```sql +smallint +``` + +状态实际含义放入: + +```text +sys_dict_type +sys_dict_data +``` + +--- + +# 3.5 公共审计字段 + +主数据: + +```text +create_by varchar(64) +create_time timestamp +update_by varchar(64) +update_time timestamp +remark varchar(500) +del_flag char(1) +``` + +业务过程表根据需要缩减。 + +--- + +# 4. `train_teacher` + +## 用途 + +教师主档。 + +### 字段 + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---:|---| +| `t_id` | varchar(32) | Y | 教师ID | +| `user_id` | bigint | N | sys_user逻辑关联 | +| `t_name` | varchar(50) | Y | 姓名 | +| `t_gender` | char(1) | N | 性别 | +| `t_birth` | date | N | 出生日期 | +| `org_name` | varchar(100) | N | 所属单位 | +| `job_title` | varchar(50) | N | 职务/职称 | +| `t_phone` | varchar(20) | N | 电话 | +| `t_email` | varchar(100) | N | 邮箱 | +| `status` | smallint | Y | 启用状态 | +| `create_by` | varchar(64) | N | 创建人 | +| `create_time` | timestamp | Y | 创建时间 | +| `update_by` | varchar(64) | N | 更新人 | +| `update_time` | timestamp | N | 更新时间 | +| `remark` | varchar(500) | N | 备注 | +| `del_flag` | char(1) | Y | 逻辑删除 | + +### PK + +```text +t_id +``` + +### INDEX + +```text +idx_teacher_user_id(user_id) +idx_teacher_name(t_name) +``` + +不对 `sys_user` 创建 FK。 + +--- + +# 5. `train_student` + +## 用途 + +学员长期主档。 + +会议明确身份证不能明文保存,要使用可逆加密;培训状态也不应该套用学校里的休学、退学模型。 + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---:|---| +| `s_id` | varchar(32) | Y | 学员ID | +| `user_id` | bigint | N | 登录账号逻辑关联 | +| `s_name` | varchar(50) | Y | 姓名 | +| `s_gender` | char(1) | N | 性别 | +| `s_birth` | date | N | 出生日期 | +| `org_name` | varchar(100) | N | 所属单位 | +| `s_phone` | varchar(20) | N | 电话 | +| `s_email` | varchar(100) | N | 邮箱 | +| `id_card_ciphertext` | text | N | 身份证密文 | +| `id_card_hash` | varchar(128) | N | 精确匹配Hash | +| `id_card_last4` | varchar(4) | N | 展示辅助 | +| `face_ref` | varchar(255) | N | 人脸数据引用 | +| `source_type` | smallint | Y | 来源 | +| `status` | smallint | Y | 主档状态 | +| 公共字段 | | | | + +### UNIQUE + +```text +id_card_hash +``` + +允许 NULL。 + +### INDEX + +```text +idx_student_name(s_name) +idx_student_org(org_name) +idx_student_user_id(user_id) +``` + +--- + +# 6. `train_course` + +## 用途 + +长期课程定义。 + +| 字段 | 类型 | 必填 | +|---|---|---:| +| `c_id` | varchar(32) | Y | +| `c_code` | varchar(50) | N | +| `c_name` | varchar(100) | Y | +| `c_type` | varchar(30) | N | +| `c_duration` | integer | N | +| `teaching_objective` | text | N | +| `course_content` | text | N | +| `status` | smallint | Y | +| 公共字段 | | | + +### UNIQUE + +```text +c_code +``` + +### INDEX + +```text +idx_course_name(c_name) +idx_course_status(status) +``` + +旧附件字段全部迁出。 + +--- + +# 7. `train_resource` + +## 用途 + +统一教学资源。 + +会议明确教学资源包括文档、视频、VR、模型及访问链接,并由课程选择已有资源。 + +| 字段 | 类型 | 必填 | +|---|---|---:| +| `resource_id` | varchar(32) | Y | +| `resource_name` | varchar(150) | Y | +| `resource_type` | smallint | Y | +| `resource_url` | text | Y | +| `description` | text | N | +| `status` | smallint | Y | +| 公共字段 | | | + +### INDEX + +```text +idx_resource_type(resource_type) +idx_resource_status(status) +``` + +--- + +# 8. `train_course_resource` + +## 用途 + +课程与教学资源 N:M。 + +| 字段 | 类型 | +|---|---| +| `id` | bigint identity | +| `c_id` | varchar(32) | +| `resource_id` | varchar(32) | +| `sort_no` | integer | +| `create_by` | varchar(64) | +| `create_time` | timestamp | + +### FK + +```text +c_id → train_course.c_id +resource_id → train_resource.resource_id +``` + +### UNIQUE + +```text +(c_id, resource_id) +``` + +### INDEX + +```text +idx_course_resource_course(c_id) +idx_course_resource_resource(resource_id) +``` + +--- + +# 9. `train_classroom_info` + +## 用途 + +教室主数据。 + +| 字段 | 类型 | +|---|---| +| `class_room_id` | varchar(32) | +| `room_name` | varchar(60) | +| `room_location` | varchar(100) | +| `capacity` | integer | +| `room_status` | smallint | +| 公共字段 | | + +基本沿用现有模型。 + +--- + +# 10. `train_training_site` + +## 用途 + +VR、3D、实操等实训场地。 + +| 字段 | 类型 | +|---|---| +| `site_id` | varchar(32) | +| `site_name` | varchar(80) | +| `site_location` | varchar(100) | +| `capacity` | integer | +| `site_device` | text | +| `site_status` | smallint | +| 公共字段 | | + +一期暂不把设备资产继续复杂拆分。 + +--- + +# 11. `train_electronic_board` + +## 用途 + +电子班牌设备。 + +会议明确电子班牌需要和教室对应,并根据教室课程表展示当前课程,同时承接签到/签退。 + +| 字段 | 类型 | +|---|---| +| `board_id` | varchar(32) | +| `board_name` | varchar(100) | +| `board_sn` | varchar(64) | +| `bind_classroom_id` | varchar(32) | +| `board_ip` | varchar(50) | +| `api_endpoint` | varchar(255) | +| `support_checkin_type` | varchar(50) | +| `board_status` | smallint | +| `last_heartbeat` | timestamp | +| 公共字段 | | + +### UNIQUE + +```text +board_sn +``` + +### FK + +```text +bind_classroom_id → train_classroom_info.class_room_id +``` + +不再保留: + +```text +bind_plan_id +``` + +作为核心关系。 + +--- + +# 12. `train_dormitory_info` + +## 用途 + +宿舍房间。 + +会议明确一期主要维护楼层、房号、容量、已住/剩余、男女属性等房间信息。 + +| 字段 | 类型 | +|---|---| +| `dorm_id` | varchar(32) | +| `dorm_building` | varchar(50) | +| `dorm_floor` | varchar(20) | +| `dorm_room` | varchar(30) | +| `capacity` | integer | +| `gender_type` | smallint | +| `lock_device_sn` | varchar(64) | +| `dorm_status` | smallint | +| 公共字段 | | + +### UNIQUE + +```text +(dorm_building, dorm_room) +``` + +### 不保存 + +```text +bed_used +``` + +入住人数实时从住宿安排统计。 + +--- + +# 13. `train_class_plan` + +## 用途 + +一次完整培训班。 + +| 字段 | 类型 | 必填 | +|---|---|---:| +| `plan_id` | varchar(32) | Y | +| `plan_name` | varchar(150) | Y | +| `start_time` | timestamp | Y | +| `end_time` | timestamp | Y | +| `train_address` | varchar(200) | N | +| `recruit_num` | integer | N | +| `apply_condition` | text | N | +| `report_deadline` | timestamp | N | +| `plan_status` | smallint | Y | +| 公共字段 | | | + +### 删除旧字段 + +```text +c_id +t_id +``` + +原因:会议已经明确培训班包含多门课,教师、教室和场地随后通过排课确定。 + +--- + +# 14. `train_plan_course` + +## 用途 + +某一期培训包含哪些课程。 + +| 字段 | 类型 | +|---|---| +| `plan_course_id` | bigint identity | +| `plan_id` | varchar(32) | +| `c_id` | varchar(32) | +| `sort_no` | integer | +| `create_by` | varchar(64) | +| `create_time` | timestamp | +| `remark` | varchar(500) | + +### FK + +```text +plan_id → train_class_plan.plan_id +c_id → train_course.c_id +``` + +### UNIQUE + +```text +(plan_id, c_id) +``` + +### INDEX + +```text +idx_plan_course_plan(plan_id) +idx_plan_course_course(c_id) +``` + +--- + +# 15. `train_enrollment` + +## 用途 + +系统最核心关系: + +> 哪个学员参加哪个培训班。 + +会议直接确认需要一张表表达“哪些人员参加哪个班”。 + +| 字段 | 类型 | +|---|---| +| `enrollment_id` | bigint identity | +| `plan_id` | varchar(32) | +| `student_id` | varchar(32) | +| `source_type` | smallint | +| `enrollment_status` | smallint | +| `accommodation_required` | smallint | +| `join_time` | timestamp | +| `complete_time` | timestamp | +| `create_by` | varchar(64) | +| `create_time` | timestamp | +| `update_by` | varchar(64) | +| `update_time` | timestamp | +| `remark` | varchar(500) | + +### FK + +```text +plan_id → train_class_plan.plan_id +student_id → train_student.s_id +``` + +### UNIQUE + +```text +(plan_id, student_id) +``` + +### INDEX + +```text +idx_enrollment_plan(plan_id) +idx_enrollment_student(student_id) +idx_enrollment_status(enrollment_status) +``` + +--- + +# 16. `train_lesson` + +## 用途 + +具体一次教学活动。 + +| 字段 | 类型 | +|---|---| +| `lesson_id` | bigint identity | +| `plan_course_id` | bigint | +| `t_id` | varchar(32) | +| `start_time` | timestamp | +| `end_time` | timestamp | +| `venue_type` | smallint | +| `class_room_id` | varchar(32) | +| `site_id` | varchar(32) | +| `create_by` | varchar(64) | +| `create_time` | timestamp | +| `update_by` | varchar(64) | +| `update_time` | timestamp | +| `remark` | varchar(500) | + +### FK + +```text +plan_course_id → train_plan_course.plan_course_id +t_id → train_teacher.t_id +class_room_id → train_classroom_info.class_room_id +site_id → train_training_site.site_id +``` + +### CHECK + +建议: + +```text +start_time < end_time +``` + +场地二选一主要由 Service 校验。 + +### INDEX + +```text +idx_lesson_plan_course(plan_course_id) +idx_lesson_teacher_time(t_id,start_time,end_time) +idx_lesson_classroom_time(class_room_id,start_time,end_time) +idx_lesson_site_time(site_id,start_time,end_time) +``` + +--- + +# 17. `train_accommodation` + +## 用途 + +本次参训住宿安排。 + +会议确认报到前应有预分配,但是否具体分床没有完全定死,因此采用: + +> 房间必填 + 床号可选。 + +| 字段 | 类型 | +|---|---| +| `accommodation_id` | bigint identity | +| `enrollment_id` | bigint | +| `dorm_id` | varchar(32) | +| `bed_no` | varchar(20) | +| `assigned_time` | timestamp | +| `accommodation_status` | smallint | +| `create_by` | varchar(64) | +| `create_time` | timestamp | +| `update_by` | varchar(64) | +| `update_time` | timestamp | +| `remark` | varchar(500) | + +### FK + +```text +enrollment_id → train_enrollment.enrollment_id +dorm_id → train_dormitory_info.dorm_id +``` + +### UNIQUE + +```text +enrollment_id +``` + +表示一期一次参训只保留一个当前住宿安排。 + +--- + +# 18. `train_dorm_auth` + +## 用途 + +门禁授权同步。 + +住宿安排由本系统完成,真实门禁权限下发属于外部系统。会议已经明确两者不同。 + +| 字段 | 类型 | +|---|---| +| `auth_id` | bigint identity | +| `accommodation_id` | bigint | +| `auth_start` | timestamp | +| `auth_end` | timestamp | +| `face_sync_status` | smallint | +| `retry_count` | integer | +| `last_error` | varchar(500) | +| `external_auth_id` | varchar(100) | +| `last_sync_time` | timestamp | +| `create_by` | varchar(64) | +| `create_time` | timestamp | +| `update_by` | varchar(64) | +| `update_time` | timestamp | +| `remark` | varchar(500) | + +### UNIQUE + +```text +accommodation_id +``` + +### FK + +```text +accommodation_id → train_accommodation.accommodation_id +``` + +--- + +# 19. `train_class_report` + +## 用途 + +报到事件。 + +| 字段 | 类型 | +|---|---| +| `report_id` | bigint identity | +| `enrollment_id` | bigint | +| `report_way` | smallint | +| `report_device_sn` | varchar(64) | +| `report_time` | timestamp | +| `verify_result` | smallint | +| `verify_note` | varchar(500) | +| `create_by` | varchar(64) | +| `create_time` | timestamp | +| `remark` | varchar(500) | + +### UNIQUE + +```text +enrollment_id +``` + +### FK + +```text +enrollment_id → train_enrollment.enrollment_id +``` + +不再保存: + +```text +alloc_dorm_id +alloc_classroom_id +alloc_site_id +``` + +因为会议业务顺序已经明确:资源提前安排,报到只展示结果。 + +--- + +# 20. `train_student_checkin` + +## 用途 + +某参训人员针对具体课次的最终考勤结果。 + +会议明确签到/签退最终用于统计学员是否参加某课程、培训班出勤率以及个人出勤情况。 + +| 字段 | 类型 | +|---|---| +| `checkin_id` | bigint identity | +| `enrollment_id` | bigint | +| `lesson_id` | bigint | +| `board_id` | varchar(32) | +| `checkin_way` | smallint | +| `sign_in_time` | timestamp | +| `sign_out_time` | timestamp | +| `attendance_status` | smallint | +| `manual_flag` | smallint | +| `create_by` | varchar(64) | +| `create_time` | timestamp | +| `update_by` | varchar(64) | +| `update_time` | timestamp | +| `remark` | varchar(500) | + +### UNIQUE + +```text +(enrollment_id, lesson_id) +``` + +### FK + +```text +enrollment_id → train_enrollment +lesson_id → train_lesson +board_id → train_electronic_board +``` + +### 不再保存 + +```text +plan_id +c_id +student_id +lesson_start_time +lesson_end_time +``` + +--- + +# 21. `train_score_item` + +## 用途 + +某培训班的成绩组成项。 + +会议明确成绩由本期多门课程、实训等项目构成,并由用户自己配置权重。 + +| 字段 | 类型 | +|---|---| +| `score_item_id` | bigint identity | +| `plan_id` | varchar(32) | +| `plan_course_id` | bigint | +| `item_name` | varchar(100) | +| `item_type` | smallint | +| `weight` | numeric(5,2) | +| `full_score` | numeric(5,2) | +| `sort_no` | integer | +| `create_by` | varchar(64) | +| `create_time` | timestamp | +| `update_by` | varchar(64) | +| `update_time` | timestamp | +| `remark` | varchar(500) | + +### FK + +```text +plan_id → train_class_plan +plan_course_id → train_plan_course +``` + +`plan_course_id` 可为空,例如: + +```text +综合考核 +``` + +### CHECK + +```text +weight >= 0 AND weight <= 100 +full_score > 0 +``` + +### INDEX + +```text +idx_score_item_plan(plan_id) +idx_score_item_plan_course(plan_course_id) +``` + +--- + +# 22. `train_student_score` + +## 用途 + +一个参训人员在某一个成绩项目上的得分。 + +| 字段 | 类型 | +|---|---| +| `score_id` | bigint identity | +| `enrollment_id` | bigint | +| `score_item_id` | bigint | +| `score` | numeric(7,2) | +| `source_type` | smallint | +| `source_system` | varchar(100) | +| `source_event_id` | varchar(100) | +| `import_time` | timestamp | +| `create_by` | varchar(64) | +| `create_time` | timestamp | +| `update_by` | varchar(64) | +| `update_time` | timestamp | +| `remark` | varchar(500) | + +### UNIQUE + +```text +(enrollment_id, score_item_id) +``` + +### FK + +```text +enrollment_id → train_enrollment +score_item_id → train_score_item +``` + +### 综合成绩 + +不保存冗余总分。 + +动态: + +```text +Σ(score / full_score × 100 × weight / 100) +``` + +如果一期统一满分 100,则简化成: + +```text +Σ(score × weight / 100) +``` + +--- + +# 23. `train_study_duration` + +## 用途 + +自主学习 / VR / 3D / 实训系统返回的学习记录。 + +会议明确外部系统自己记录开始、结束及使用时长,再回传本系统。 + +| 字段 | 类型 | +|---|---| +| `dur_id` | bigint identity | +| `enrollment_id` | bigint | +| `plan_course_id` | bigint | +| `resource_id` | varchar(32) | +| `learning_content` | varchar(200) | +| `source_system` | varchar(100) | +| `source_event_id` | varchar(100) | +| `start_time` | timestamp | +| `end_time` | timestamp | +| `study_seconds` | integer | +| `sync_time` | timestamp | +| `create_by` | varchar(64) | +| `create_time` | timestamp | +| `remark` | varchar(500) | + +### FK + +```text +enrollment_id → train_enrollment +plan_course_id → train_plan_course +resource_id → train_resource +``` + +### UNIQUE + +建议: + +```text +(source_system, source_event_id) +``` + +仅当 `source_event_id` 不为空。 + +### INDEX + +```text +idx_study_enrollment(enrollment_id) +idx_study_plan_course(plan_course_id) +idx_study_sync(sync_time) +``` + +--- + +# 24. `train_student_portrait` + +## 用途 + +一期简单画像结果。 + +会议明确画像需求还不完全确定,一期只围绕出勤、理论、实操、学习时长等做简单标签。 + +| 字段 | 类型 | +|---|---| +| `portrait_id` | bigint identity | +| `enrollment_id` | bigint | +| `attendance_rate` | numeric(5,2) | +| `theory_score` | numeric(7,2) | +| `practical_score` | numeric(7,2) | +| `total_study_hour` | numeric(8,2) | +| `label_tag` | text | +| `portrait_content` | text | +| `generated_time` | timestamp | +| `create_by` | varchar(64) | +| `create_time` | timestamp | +| `update_by` | varchar(64) | +| `update_time` | timestamp | +| `remark` | varchar(500) | + +### UNIQUE + +```text +enrollment_id +``` + +--- + +# 25. 核心关系最终冻结 + +```mermaid +erDiagram + + TRAIN_CLASS_PLAN ||--o{ TRAIN_PLAN_COURSE : contains + TRAIN_COURSE ||--o{ TRAIN_PLAN_COURSE : belongs + + TRAIN_CLASS_PLAN ||--o{ TRAIN_ENROLLMENT : enrolls + TRAIN_STUDENT ||--o{ TRAIN_ENROLLMENT : participates + + TRAIN_PLAN_COURSE ||--o{ TRAIN_LESSON : schedules + TRAIN_TEACHER ||--o{ TRAIN_LESSON : teaches + + TRAIN_CLASSROOM_INFO ||--o{ TRAIN_LESSON : classroom + TRAIN_TRAINING_SITE ||--o{ TRAIN_LESSON : site + + TRAIN_COURSE ||--o{ TRAIN_COURSE_RESOURCE : uses + TRAIN_RESOURCE ||--o{ TRAIN_COURSE_RESOURCE : contains + + TRAIN_CLASSROOM_INFO ||--o{ TRAIN_ELECTRONIC_BOARD : binds + + TRAIN_ENROLLMENT ||--o| TRAIN_ACCOMMODATION : accommodation + TRAIN_DORMITORY_INFO ||--o{ TRAIN_ACCOMMODATION : room + + TRAIN_ACCOMMODATION ||--o| TRAIN_DORM_AUTH : access + + TRAIN_ENROLLMENT ||--o| TRAIN_CLASS_REPORT : report + + TRAIN_ENROLLMENT ||--o{ TRAIN_STUDENT_CHECKIN : attendance + TRAIN_LESSON ||--o{ TRAIN_STUDENT_CHECKIN : lesson + + TRAIN_CLASS_PLAN ||--o{ TRAIN_SCORE_ITEM : defines + TRAIN_PLAN_COURSE ||--o{ TRAIN_SCORE_ITEM : optional + + TRAIN_ENROLLMENT ||--o{ TRAIN_STUDENT_SCORE : gets + TRAIN_SCORE_ITEM ||--o{ TRAIN_STUDENT_SCORE : score + + TRAIN_ENROLLMENT ||--o{ TRAIN_STUDY_DURATION : learns + + TRAIN_ENROLLMENT ||--o| TRAIN_STUDENT_PORTRAIT : portrait +``` + +--- + +# 26. 核心业务唯一约束 + +必须存在: + +```text +train_plan_course +UNIQUE(plan_id, c_id) + +train_enrollment +UNIQUE(plan_id, student_id) + +train_course_resource +UNIQUE(c_id, resource_id) + +train_accommodation +UNIQUE(enrollment_id) + +train_dorm_auth +UNIQUE(accommodation_id) + +train_class_report +UNIQUE(enrollment_id) + +train_student_checkin +UNIQUE(enrollment_id, lesson_id) + +train_student_score +UNIQUE(enrollment_id, score_item_id) + +train_student_portrait +UNIQUE(enrollment_id) + +train_electronic_board +UNIQUE(board_sn) +``` + +--- + +# 27. 不使用级联删除 + +所有业务 FK: + +```text +ON DELETE NO ACTION +``` + +原因: + +培训班删除、课程停用、学员离开系统,都不能导致: + +```text +成绩 +签到 +学习 +住宿 +``` + +自动消失。 + +--- + +# 28. 状态字典 + +建议第一批: + +```text +train_common_status +train_plan_status +train_enrollment_status +train_student_source +train_resource_type +train_room_status +train_dorm_status +train_gender_type +train_accommodation_status +train_auth_sync_status +train_report_way +train_verify_result +train_checkin_way +train_attendance_status +train_score_item_type +train_score_source +``` + +--- + +# 29. 开班状态 + +一期最简单: + +```text +0 未开始 +1 进行中 +2 已结束 +3 已取消 +``` + +不强制加入: + +```text +报名中 +``` + +因为第二次会议明确强调不要为了已有文档增加没有实际业务动作的复杂状态。 + +--- + +# 30. 参训状态 + +```text +0 待报到 +1 已报到 +2 请假 +3 放弃 +4 已完成 +``` + +培训结束后: + +```text +有效参训学员 → 已完成 +``` + +一期暂不扩: + +```text +合格 +不合格 +证书状态 +``` + +--- + +# 31. 关键 Service 规则 + +数据库只负责结构完整性。 + +Service 必须负责: + +### 开班 + +```text +start_time < end_time +``` + +### 参训 + +```text +同一学员不能重复加入同一培训班 +``` + +### 排课 + +检测: + +```text +教师冲突 +教室冲突 +实训场地冲突 +培训班自身课次重叠 +``` + +### 住宿 + +检查: + +```text +gender_type +capacity +当前有效住宿人数 +``` + +### 成绩 + +检查: + +```text +一个培训班成绩项目有效权重总和 = 100% +``` + +### 学习记录 + +检查: + +```text +end_time >= start_time +study_seconds >= 0 +``` + +--- + +# 32. Kingbase DDL 编写规范 + +正式 SQL 必须使用: + +```sql +BIGINT GENERATED BY DEFAULT AS IDENTITY +TIMESTAMP +SMALLINT +NUMERIC +VARCHAR +TEXT +``` + +禁止: + +```text +AUTO_INCREMENT +ENGINE=InnoDB +ON UPDATE CURRENT_TIMESTAMP +``` + +--- + +# 33. 更新时间机制 + +V2 不新增数据库 UPDATE Trigger。 + +统一由应用 Service 设置: + +```text +create_time +update_time +``` + +现有旧表触发器在迁移时逐步移除。 + +--- + +# 34. 数据库脚本目录 + +正式采用: + +```text +RuoYi-Vue/sql/train/v2/ +``` + +文件: + +```text +001_backup_current_schema.sql + +002_create_new_tables.sql + +003_alter_master_tables.sql + +004_rebuild_business_tables.sql + +005_constraints.sql + +006_indexes.sql + +007_dicts.sql + +008_migrate_teacher.sql + +009_drop_legacy_score.sql + +010_verify.sql + +rollback/ +``` + +--- + +# 35. 不允许直接 ALTER 生产式操作 + +虽然当前 13 张表为空,仍必须: + +```text +SQL脚本 +→ Review +→ 执行 +→ Verify +``` + +禁止: + +```text +Agent直接连库 +ALTER完 +再补文档 +``` + +--- + +# 36. 数据迁移策略 + +由于目前只有: + +```text +train_teacher = 1行 +``` + +其余业务表全部为空。 + +因此采用简单方案: + +```text +备份现有DDL +↓ +保存唯一教师数据 +↓ +重建/调整空培训表 +↓ +迁移教师 +↓ +创建V2新表 +↓ +重建约束 +↓ +验证 +``` + +不需要复杂数据 ETL。 + +--- + +# 37. V2 验证 SQL 必须检查 + +`010_verify.sql` 至少检查: + +```text +21张正式业务表是否存在 + +train_score_info是否退出正式模型 + +PK数量 + +FK数量 + +UNIQUE数量 + +索引数量 + +train_teacher原1条数据是否保留 + +所有新关系表是否为空 + +是否存在孤儿引用 + +identity是否正确 + +sys_*表是否未被修改 +``` + +--- + +# 38. 数据库 V2 验收标准 + +只有全部满足才算通过: + +```text +1. 21张正式业务表结构正确 +2. teacher原始1条数据保留 +3. sys_*结构未变化 +4. 一班多课可以表达 +5. 参训关系可以表达 +6. 多课次可以表达 +7. 教师/教室/场地可以按课次变化 +8. 报到与资源分配解耦 +9. 住宿与门禁解耦 +10. 成绩项目和权重可配置 +11. 外部学习记录可幂等接入 +12. 学员画像可以关联本次培训 +13. 所有核心FK成立 +14. 核心查询列具备索引 +15. Generator可正常读取V2表 +``` + +--- + +# 39. 数据库 V2 最终业务骨架 + +```mermaid +flowchart TD + A[创建培训班] + --> B[配置多门课程] + --> C[安排课次] + + D[加入学员] + --> E[Enrollment] + + E --> F[住宿预分配] + F --> G[门禁授权] + + E --> H[报到] + + C --> I[正式上课] + + E --> J[考勤] + I --> J + + E --> K[成绩] + E --> L[学习记录] + + J --> M[统计] + K --> M + L --> M + + M --> N[简单画像] + + A --> O[培训结束] + O --> P[参训状态完成] +``` + +--- + +# 40. 冻结结论 + +数据库 V2 正式冻结: + +### 培训组织核心 + +```text +train_class_plan +train_plan_course +train_enrollment +train_lesson +``` + +### 学员全过程主键 + +```text +enrollment_id +``` + +### 培训课程实例主键 + +```text +plan_course_id +``` + +### 实际教学活动主键 + +```text +lesson_id +``` + +以后开发过程中: + +> **任何 Agent 如果重新在考勤、成绩、学习等表中到处复制 `student_id + plan_id + c_id` 作为核心关系,都应视为偏离 V2 架构。** + +--- + +# 41. 下一步正式工作 + +数据库字段已经能够冻结。 + +下一阶段: + +```mermaid +flowchart LR + A[字段设计冻结] + --> B[生成Kingbase V2 DDL] + + B --> C[DDL静态Review] + C --> D[可回滚测试迁移] + + D --> E[Generator重新读取] + E --> F[API契约设计] + + F --> G[Issue拆分] + G --> H[Codex核心重构] +``` + +下一步可以让 Agent **只生成 SQL 文件,不执行数据库修改**。 + +之后由高级技术负责人 Review SQL,再允许执行测试迁移。 \ No newline at end of file