diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/README.md b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/README.md new file mode 100644 index 000000000..a45c46bf4 --- /dev/null +++ b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/README.md @@ -0,0 +1,21 @@ +# SYFJGYD学员管理系统 R.2B Wave 3 E2E 验收证据包 + +- **验收单号 (RUN_ID)**: `RBAC_E2E_R2_20260916_102500` +- **代码候选基准 (CANDIDATE_COMMIT)**: `81e7d5447c2ea32e4a6c717cd3bb3d1e38b6aad3` +- **系统对外正式名称 (SYSTEM_DISPLAY_NAME)**: `SYFJGYD学员管理系统` +- **测试环境 (ENVIRONMENT)**: `ISOLATED QA` (数据库 127.0.0.1:4321/training, Redis 127.0.0.1:6379, 后端 8090, 前端 8080) +- **迁移验证复用基准 (MIGRATION_VALIDATION_RUN)**: `RBAC_E2E_R2_20260916_100800` (`MIGRATION_VALIDATION_REUSED = YES`) +- **端到端验收状态 (E2E_R2_STATUS)**: `PASS` +- **高清截图总数 (SCREENSHOT_COUNT)**: `21` (存放于 `screenshots/`) + +## 交付文档目录索引 (>=10 项完整清单) +1. [README.md](README.md): 交付包综述与验收元数据索引 +2. [report.md](report.md): R.2 三角色认证、功能权限与数据权限 E2E 综合验收报告 +3. [report.html](report.html): 离线可视化交互式交付报告 (集成 21 张全链路无损截图画廊) +4. [run-data.json](run-data.json): 42 项机器可读验收指标字典 (JSON 标准格式) +5. [role-matrix.md](role-matrix.md): 三角色 (Admin / Teacher / Student) 及特例主体功能、路由与数据矩阵 +6. [idor-results.md](idor-results.md): 横向越权 (IDOR) 与垂直越权全链路防御渗透记录 +7. [account-binding-results.md](account-binding-results.md): 管理员开户与业务身份绑定正负向及安全边界测试记录 +8. [migration-validation.md](migration-validation.md): 004/005 增量数据库迁移脚本幂等性验证记录 +9. [network-summary.md](network-summary.md): 全流程 HTTP 网络请求监控与异常排查表 (500 异常与预期 403 拦截) +10. [console-summary.md](console-summary.md): 浏览器前端控制台日志监控与阻断性错误排查汇总 diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/account-binding-results.md b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/account-binding-results.md new file mode 100644 index 000000000..bd9d114c5 --- /dev/null +++ b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/account-binding-results.md @@ -0,0 +1,31 @@ +# SYFJGYD学员管理系统 管理端正式账号开通与业务身份绑定验证 + +- **验收单号 (RUN_ID)**: `RBAC_E2E_R2_20260916_102500` +- **代码候选基准 (CANDIDATE_COMMIT)**: `81e7d5447c2ea32e4a6c717cd3bb3d1e38b6aad3` +- **系统对外正式名称 (SYSTEM_DISPLAY_NAME)**: `SYFJGYD学员管理系统` +- **测试环境 (ENVIRONMENT)**: `ISOLATED QA` + +## 一、测试账号与角色档案对应清单 +1. `admin` (userId=1): 超级管理员,系统全局最高权限 +2. `qa_tea_a` (userId=100): 教师 A,分配 `train_teacher` 角色,绑定师资档案张建国 (`T_DOM_A`) +3. `qa_tea_b` (userId=101): 教师 B,分配 `train_teacher` 角色,绑定师资档案王守诚 (`T_DOM_B`) +4. `qa_stu_a` (userId=102): 学员 A,分配 `train_student` 角色,绑定学员主档李明 (`S_DOM_A`) +5. `qa_stu_b` (userId=103): 学员 B,分配 `train_student` 角色,绑定学员主档赵强 (`S_DOM_B`) +6. `qa_no_id_tea` (userId=104): 未绑定档案教师,分配 `train_teacher` 角色,业务主档未关联 +7. `qa_no_id_stu` (userId=105): 未绑定档案学员,分配 `train_student` 角色,业务主档未关联 +8. `qa_admin_tea` (userId=106): 复合身份账号,分配 `admin` 与 `train_teacher` 双重角色,绑定师资档案张建国 + +## 二、功能与安全边界用例验证明细 + +| 序号 | 验证用例 | 操作说明 | 预期结果 | 实际执行结果 | 判定 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| 1 | **Admin 正向绑定 Teacher** | 管理员调用 `PUT /train/teacher/{tId}/user-binding` 绑定合法教师账号 | 状态码 200,教师档案记录 `user_id` | 成功建立绑定,数据落库 | **PASS** | +| 2 | **Admin 正向绑定 Student** | 管理员调用 `PUT /train/student/{sId}/user-binding` 绑定合法学员账号 | 状态码 200,学员档案记录 `user_id` | 成功建立绑定,数据落库 | **PASS** | +| 3 | **错误角色绑定拒止 (Teacher 错配)** | 将学员角色账号 (`qa_stu_a`) 绑定至教师档案 | 拒绝绑定,返回角色不匹配提示 | 返回 400 校验异常,拒止成功 | **DENIED (PASS)** | +| 4 | **错误角色绑定拒止 (Student 错配)** | 将教师角色账号 (`qa_tea_a`) 绑定至学员档案 | 拒绝绑定,返回角色不匹配提示 | 返回 400 校验异常,拒止成功 | **DENIED (PASS)** | +| 5 | **防静默覆盖 (Silent Overwrite)** | 对已绑定系统用户的教师/学员档案直接发起新绑定请求 | 拒绝静默覆盖,要求必须显式先解绑 | 返回 400 校验错误,防止数据覆盖 | **DENIED (PASS)** | +| 6 | **Teacher XOR Student 业务互斥** | 尝试将已被绑定为教师的 `qa_tea_a` 账号再绑定至学员档案 | 拒绝多重身份冲突,维持身份互斥 | 返回 400 拦截,业务互斥生效 | **PASS** | +| 7 | **解绑不删除系统用户** | 管理员调用 `DELETE /train/teacher/{tId}/user-binding` 解除绑定 | 仅将业务档案 `user_id` 置为 NULL,系统用户账号仍然保留 | 档案解绑成功,`sys_user` 完好保留 | **PASS** | +| 8 | **运行时绑定权限拦截 (Admin)** | 管理员身份调用绑定与解绑接口 | 正常执行 | 具备 2241~2244 权限,允许操作 | **PASS** | +| 9 | **运行时绑定权限拦截 (Teacher)** | 教师账号越权调用 `PUT /train/teacher/{tId}/user-binding` | 权限拦截拒止 | Framework 403 拦截,无权操作 | **DENIED (PASS)** | +| 10 | **运行时绑定权限拦截 (Student)** | 学员账号越权调用 `PUT /train/student/{sId}/user-binding` | 权限拦截拒止 | Framework 403 拦截,无权操作 | **DENIED (PASS)** | diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/console-summary.md b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/console-summary.md new file mode 100644 index 000000000..a5ca7b7cc --- /dev/null +++ b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/console-summary.md @@ -0,0 +1,15 @@ +# SYFJGYD学员管理系统 浏览器前端控制台日志排查汇总 + +- **验收单号 (RUN_ID)**: `RBAC_E2E_R2_20260916_102500` +- **代码候选基准 (CANDIDATE_COMMIT)**: `81e7d5447c2ea32e4a6c717cd3bb3d1e38b6aad3` +- **系统对外正式名称 (SYSTEM_DISPLAY_NAME)**: `SYFJGYD学员管理系统` +- **测试环境 (ENVIRONMENT)**: `ISOLATED QA` + +## 控制台质量指标 +- **阻断性控制台错误 (BLOCKING_CONSOLE_ERROR_COUNT)**: `0` +- **未捕获的 JavaScript 异常 (Uncaught Exceptions)**: `0` +- **Vue 渲染运行时崩溃 (Vue Runtime Errors)**: `0` +- **静态资源加载 404 (Asset 404)**: `0` + +## 控制台日志审计结论 +全链路 21 个核心页面在 Playwright 高清渲染与截图采集过程中,所有 Vue 组件初始化、Element UI 渲染、路由导航守卫均无阻断性错误,页面 Title 统一展示为 `SYFJGYD学员管理系统`,系统运行表现平稳。 diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/idor-results.md b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/idor-results.md new file mode 100644 index 000000000..932305b9f --- /dev/null +++ b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/idor-results.md @@ -0,0 +1,24 @@ +# SYFJGYD学员管理系统 RBAC 横向越权 (IDOR) 与垂直越权测试结果 + +- **验收单号 (RUN_ID)**: `RBAC_E2E_R2_20260916_102500` +- **代码候选基准 (CANDIDATE_COMMIT)**: `81e7d5447c2ea32e4a6c717cd3bb3d1e38b6aad3` +- **系统对外正式名称 (SYSTEM_DISPLAY_NAME)**: `SYFJGYD学员管理系统` +- **测试环境 (ENVIRONMENT)**: `ISOLATED QA` +- **框架权限拦截语义说明**: 若依 (RuoYi) 框架标准权限校验拦截遵循 `Framework authorization response semantics`,即在网关/MVC 统一拦截时返回 **HTTP 200** 状态码,响应体携带 **`{"code": 403, "msg": "没有权限,请联系管理员授权"}`**。以下测试结果均按实际返回严格记录。 + +## 越权测试用例执行明细表 + +| 序号 | 越权类型 | 攻击主体 | 目标资源 / 越权操作 | HTTP Status | Body Code | 拦截响应语义说明 | 最终判定 | +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +| 1 | **教师跨域班级 IDOR** | Teacher A (`qa_tea_a`) | 越权查询 Domain B 班级名册 (`PLAN_DOM_B`) | `HTTP 200` | `403` | Framework authorization response semantics (非本人任教计划,数据权限拦截) | **DENIED (PASS)** | +| 2 | **教师跨域课次 IDOR** | Teacher A (`qa_tea_a`) | 越权对 Domain B 课次 (`302001`) 发起考勤录入 | `HTTP 200` | `403` | Framework authorization response semantics (非本人授课课次,禁止打卡) | **DENIED (PASS)** | +| 3 | **教师垂直越权** | Teacher A (`qa_tea_a`) | 越权调用系统用户管理端点 (`GET /system/user/list`) | `HTTP 200` | `403` | Framework authorization response semantics (缺少 `system:user:list` 权限) | **DENIED (PASS)** | +| 4 | **教师垂直越权** | Teacher A (`qa_tea_a`) | 越权调用全局师资档案接口 (`GET /train/teachers`) | `HTTP 200` | `403` | Framework authorization response semantics (缺少全局师资查询权限) | **DENIED (PASS)** | +| 5 | **学员跨人数据 IDOR** | Student A (`qa_stu_a`) | 篡改参数获取 Student B 参训记录 (`?studentId=S_DOM_B`) | `HTTP 200` | `200` | 自服务安全机制强制使用当前 Token 绑定的 `student_id`,篡改参数被强制忽略,仅返回本人数据 | **DENIED (PASS)** | +| 6 | **学员跨人凭据 IDOR** | Student A (`qa_stu_a`) | 越权查询 Student B 报到凭据 (`/train/me/student/checkin-voucher/S_DOM_B`) | `HTTP 200` | `403` | Framework authorization response semantics (非本人凭证,阻断访问) | **DENIED (PASS)** | +| 7 | **学员垂直越权** | Student A (`qa_stu_a`) | 越权调用系统用户管理端点 (`GET /system/user/list`) | `HTTP 200` | `403` | Framework authorization response semantics (缺少系统管理员角色与权限) | **DENIED (PASS)** | +| 8 | **学员垂直越权** | Student A (`qa_stu_a`) | 越权调用全局学员主档接口 (`GET /train/students`) | `HTTP 200` | `403` | Framework authorization response semantics (缺少全局学员管理权限) | **DENIED (PASS)** | + +## 越权防御汇总 +- **越权数据泄露数 (IDOR_LEAK_COUNT)**: `0` +- **防御结论**: 横向越权 (IDOR) 与垂直越权防御 100% 生效,严格遵循若依权限框架拦截语义规范。 diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/migration-validation.md b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/migration-validation.md new file mode 100644 index 000000000..2ad61bcb9 --- /dev/null +++ b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/migration-validation.md @@ -0,0 +1,27 @@ +# SYFJGYD学员管理系统 数据库增量迁移验证记录 + +- **验收单号 (RUN_ID)**: `RBAC_E2E_R2_20260916_102500` +- **代码候选基准 (CANDIDATE_COMMIT)**: `81e7d5447c2ea32e4a6c717cd3bb3d1e38b6aad3` +- **系统对外正式名称 (SYSTEM_DISPLAY_NAME)**: `SYFJGYD学员管理系统` +- **测试环境 (ENVIRONMENT)**: `ISOLATED QA` (Kingbase 127.0.0.1:4321/training) +- **迁移验证基准执行 (MIGRATION_VALIDATION_RUN)**: `RBAC_E2E_R2_20260916_100800` +- **迁移验证复用标识 (MIGRATION_VALIDATION_REUSED)**: `YES` +- **迁移证据真实性声明 (MIGRATION_EVIDENCE_TRUTHFUL)**: `YES` + +## 验证结论与幂等性复核 +在基准执行 `RBAC_E2E_R2_20260916_100800` 中,004 与 005 迁移脚本在隔离 QA 数据库中已完成连续两次无报错执行验证: +1. `004_rbac_identity_binding.sql`: + - `004_FIRST_RUN = PASS` + - `004_SECOND_RUN = PASS` (验证 DDL 幂等性,包括 `IF NOT EXISTS`、唯一索引与外键防御) +2. `005_training_roles_permissions.sql`: + - `005_FIRST_RUN = PASS` + - `005_SECOND_RUN = PASS` (验证菜单、角色及权限冲突防护 `ON CONFLICT DO NOTHING` 幂等性) + +## 真实性与变更边界审计 +本次验收单号 `RBAC_E2E_R2_20260916_102500` 未重新执行 004/005 迁移,严谨真实复用基准执行成果。 +原因说明:在 `RBAC_E2E_R2_20260916_100800` 完成后,代码仓库仅发生了一次纯前端系统对外显示名称与文档提交(Commit `81e7d5447c2ea32e4a6c717cd3bb3d1e38b6aad3`),`004_rbac_identity_binding.sql`、`005_training_roles_permissions.sql`、数据库表结构及后端 Java 业务代码零变动。 + +## 生产安全确认 +- `004_EXECUTED_PRODUCTION = NO` +- `005_EXECUTED_PRODUCTION = NO` +- `PRODUCTION_DB_MODIFIED = NO` diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/network-summary.md b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/network-summary.md new file mode 100644 index 000000000..110c57ce2 --- /dev/null +++ b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/network-summary.md @@ -0,0 +1,24 @@ +# SYFJGYD学员管理系统 HTTP 网络请求监控汇总 + +- **验收单号 (RUN_ID)**: `RBAC_E2E_R2_20260916_102500` +- **代码候选基准 (CANDIDATE_COMMIT)**: `81e7d5447c2ea32e4a6c717cd3bb3d1e38b6aad3` +- **系统对外正式名称 (SYSTEM_DISPLAY_NAME)**: `SYFJGYD学员管理系统` +- **测试环境 (ENVIRONMENT)**: `ISOLATED QA` + +## 核心网络质量指标 +- **非预期服务器异常 (UNEXPECTED_HTTP500_COUNT)**: `0` +- **网络中断 / 超时请求数**: `0` +- **网关契约失配数**: `0` + +## 预期安全拦截分类统计 (Expected Authorization Rejections) +以下请求均为安全测试用例主动作出的越权渗透或非法参数试探,服务端均按既定安全策略予以受控拒绝,**不属于系统故障**: +1. **教师跨域班级 IDOR 拦截**: 1 次 (返回 code 403,无权限查看) +2. **教师跨域考勤 IDOR 拦截**: 1 次 (返回 code 403,无权限打卡) +3. **教师访问管理员端点拦截**: 2 次 (返回 code 403,权限不足) +4. **学员访问管理员端点拦截**: 2 次 (返回 code 403,权限不足) +5. **学员跨人凭据访问拦截**: 1 次 (返回 code 403,凭据归属不符) +6. **无业务身份自服务拦截**: 2 次 (返回受控 403,提示绑定业务身份) +7. **教师/学员越权调用绑定接口**: 2 次 (返回 code 403,无 2241~2244 权限) +8. **角色错配与业务互斥校验拦截**: 3 次 (返回 code 400,业务规则防御) + +全部网络请求与安全防御完全符合契约设计规范。 diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/report.html b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/report.html new file mode 100644 index 000000000..921d9a3ea --- /dev/null +++ b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/report.html @@ -0,0 +1,233 @@ + + + + +SYFJGYD学员管理系统 - R.2 三角色认证、功能权限与数据权限 E2E 验收报告 + + + + +
+

SYFJGYD学员管理系统 · R.2 三角色认证、功能权限与数据权限 E2E 验收交付报告

+

+ 验收单号 (RUN_ID): RBAC_E2E_R2_20260916_102500  |  + 代码候选基线: 81e7d5447c2ea32e4a6c717cd3bb3d1e38b6aad3  |  + 环境: ISOLATED QA  |  + E2E_R2_STATUS: PASS +

+

+ 测试数据库: Kingbase 隔离 QA 环境 (127.0.0.1:4321/training)  |  + 迁移复用基准: RBAC_E2E_R2_20260916_100800 (004/005 双次幂等通过)  |  + 全链路无损截图: 21 张就绪 +

+
+ +
+

核心检查项与断言结论

+ + + + + + + + + + + + +
分类测试项断言结论说明
环境隔离生产数据库与服务隔离保护PASS (TEST_DB_ISOLATED=YES)生产库 192.168.139.230 与生产端口 8082 零触碰
迁移验证004/005 增量迁移脚本幂等性PASS (MIGRATION_VALIDATION_REUSED=YES)复用基准运行成果,004/005 连续执行两次无报错
账号开通管理端正式开户与角色分配PASS (ADMIN_CAN_CREATE_SYS_USER=YES)开通 7 个专用测试账号,精准分配业务角色
账号绑定管理端业务档案与用户绑定PASS (ADMIN_ACCOUNT_BINDING=PASS)正向绑定建立正常,解绑不删除系统用户
安全边界Teacher XOR Student 互斥保护PASS (TEACHER_STUDENT_MUTEX_RESULT=PASS)防静默覆盖、角色错配拒止、业务互斥拦截
越权防护IDOR 横向与垂直越权渗透防御PASS (IDOR_LEAK_COUNT=0)严格遵循若依框架权限拦截语义,越权请求 100% 阻断
教师工作台Own Data 数据范围精确控制PASS (TEACHER_OWN_DATA=PASS)仅见本人任教计划、课表、学员及考勤打卡
学员中心学员业务闭环与数据安全PASS (STUDENT_OWN_DATA=PASS)仅见本人报到凭证、参训记录、课表及画像
特例主体未绑定账号与复合角色支持PASS无身份账号受控提示,管理员+教师双角色优先驾驶舱
管理回归核心业务 13 大模块综合回归PASS (ADMIN_REGRESSION=PASS)排课预检确认、报到 0->1、考勤幂等性全部正常
+
+ +
+

全链路 21 张无损高清截图画廊 (SCREENSHOT_COUNT = 21)

+ +
+ + + diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/report.md b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/report.md new file mode 100644 index 000000000..645530919 --- /dev/null +++ b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/report.md @@ -0,0 +1,46 @@ +# R.2 三角色认证、功能权限与数据权限 E2E 综合验收报告 + +## 一、验收运行总览 +- **验收单号 (RUN_ID)**: `RBAC_E2E_R2_20260916_102500` +- **代码候选基准 (CANDIDATE_COMMIT)**: `81e7d5447c2ea32e4a6c717cd3bb3d1e38b6aad3` +- **系统对外正式名称 (SYSTEM_DISPLAY_NAME)**: `SYFJGYD学员管理系统` +- **测试环境 (ENVIRONMENT)**: `ISOLATED QA` (数据库 127.0.0.1:4321, Redis 127.0.0.1:6379, 后端 8090, 前端 8080) +- **后端单测与契约测试**: `BACKEND_TEST_TOTAL = 205`,0 failures, 0 errors +- **构建状态**: Maven `BUILD SUCCESS`,Frontend `BUILD SUCCESS`,ESLint 0 errors / 0 warnings +- **生产隔离安全**: `004_EXECUTED_PRODUCTION = NO`, `005_EXECUTED_PRODUCTION = NO`, `PRODUCTION_DB_MODIFIED = NO` +- **综合验收结论**: `E2E_R2_STATUS = PASS` + +## 二、核心验证阶段与断言矩阵 +1. **增量迁移验证 (复用)**: 复用基准 `RBAC_E2E_R2_20260916_100800` 成果,004 与 005 连续两次幂等执行全部 PASS。 +2. **账号开通与角色分配**: 管理员调用 `POST /system/user` 成功创建 7 个独立测试账号并分配合规角色。 +3. **账号绑定与安全边界**: 教师/学员绑定成功;角色错配拒止;防静默覆盖生效;Teacher XOR Student 互斥成立;解绑操作不删除系统用户;Teacher/Student 越权调用绑定接口被 403 拦截。 +4. **三角色登录与菜单隔离**: Admin、Teacher A/B、Student A/B 登录与 Token 发放完全正常。Teacher/Student 动态路由完全隔离,无任何管理端与全局档案菜单。 +5. **教师自服务与 IDOR 防御**: 仅可见本人所授课程与班级;跨班名册 IDOR 拦截 (HTTP 200 / code 403);跨课次考勤打卡拦截 (HTTP 200 / code 403);调用 Admin API 被 403 拦截;Teacher B 对称验证 PASS。 +6. **学员自服务与 IDOR 防御**: 仅可见本人参训、排课日程、报到凭证、考勤打卡与学情画像;参数篡改防御生效;跨人凭证拦截 (HTTP 200 / code 403);调用 Admin API 被 403 拦截;Student B 对称验证 PASS。 +7. **特例主体处理**: 无业务身份账号访问自服务返回受控友好 403 提示;Admin + Teacher 复合角色默认优先进入管理驾驶舱,工作台自服务双向连通。 + +## 三、Admin 核心业务 13 大模块全覆盖回归核实 + +| 序号 | 业务模块 | 覆盖功能点 | 自动化回归结论 | +| :--- | :--- | :--- | :--- | +| 1 | **Teacher (师资管理)** | 教师档案列表、详情展示、业务字段检索 | **PASS** | +| 2 | **Student (学员主档)** | 学员花名册列表、身份类别过滤、分页查询 | **PASS** | +| 3 | **Course (课程库)** | 课程分类字典、课程目录检索、学时学分配置 | **PASS** | +| 4 | **Plan (培训计划)** | 开班计划制定、培训周期管理、班级状态流转 | **PASS** | +| 5 | **Enrollment (参训名册)** | 学员参训名册关联、报名状态流转与名单核对 | **PASS** | +| 6 | **Scheduling (排课与日程)** | 课次编排、时间场地校验、**软冲突预检与二次确认保存** | **PASS** | +| 7 | **Report (学员报到)** | 报到名单流水、**报到状态 0->1 确认核销** | **PASS** | +| 8 | **Attendance (考勤打卡)** | 考勤流水记录、**签到签退幂等性验证、非法状态 5 拒止** | **PASS** | +| 9 | **Board (班牌信息展示)** | 培训场地动态看板、今日日程与班级动态大屏 | **PASS** | +| 10 | **Analytics (学情分析)** | 参训率、考勤合格率、综合学情统计分析大屏 | **PASS** | +| 11 | **Account Binding (账号绑定)** | 教师与学员正式用户绑定弹窗、解除绑定功能 | **PASS** | +| 12 | **OperLog (操作日志审计)** | 审计流水全量记录、管理端关键操作日志落库正常 | **PASS** | +| 13 | **Swagger (API 契约文档)** | API 契约接口文档规范渲染与可访问性验证 | **PASS** | + +## 四、网络与控制台稳定性指标 +- **非预期 HTTP 500 数量 (UNEXPECTED_HTTP500_COUNT)**: `0` +- **阻断性控制台错误 (BLOCKING_CONSOLE_ERROR_COUNT)**: `0` +- **受控拦截 (Expected Authorization Rejections)**: 越权与互斥拦截均符合框架标准语义,未发生系统未捕获异常。 + +## 五、验收判定 +**E2E_R2_STATUS = PASS** diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/role-matrix.md b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/role-matrix.md new file mode 100644 index 000000000..057656aaf --- /dev/null +++ b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/role-matrix.md @@ -0,0 +1,27 @@ +# SYFJGYD学员管理系统 三角色及特例主体权限矩阵 + +- **验收单号 (RUN_ID)**: `RBAC_E2E_R2_20260916_102500` +- **代码候选基准 (CANDIDATE_COMMIT)**: `81e7d5447c2ea32e4a6c717cd3bb3d1e38b6aad3` +- **系统对外正式名称 (SYSTEM_DISPLAY_NAME)**: `SYFJGYD学员管理系统` +- **测试环境 (ENVIRONMENT)**: `ISOLATED QA` + +## 覆盖主体全量清单 +1. **Admin** (`admin`): 系统与教务超级管理员 +2. **Teacher A** (`qa_tea_a`): 域 A 教师 (张建国 `T_DOM_A`) +3. **Teacher B** (`qa_tea_b`): 域 B 教师 (王守诚 `T_DOM_B`) +4. **Student A** (`qa_stu_a`): 域 A 学员 (李明 `S_DOM_A`) +5. **Student B** (`qa_stu_b`): 域 B 学员 (赵强 `S_DOM_B`) +6. **NoIdentity Teacher/Student** (`qa_no_id_tea`, `qa_no_id_stu`): 拥有教师/学员角色但未绑定业务主档账号 +7. **Admin + Teacher** (`qa_admin_tea`): 同时拥有管理员与教师双重角色主体 + +## 详细维度对比矩阵 + +| 序号 | 验证主体 | 用户账号 | 角色分配 | Menu (动态路由可见性) | Self-Service (自服务Own Data) | Admin API (全局管理接口) | Binding API (2241~2244 账号绑定) | +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +| 1 | **Admin** | `admin` | `admin` | 全局系统管理、教务全业务、排课、考勤、报到、分析等 | 全局可见,不限制单人 | 完全允许 (全量读写放行) | 允许 (具备 2241~2244 完整权限) | +| 2 | **Teacher A** | `qa_tea_a` | `train_teacher` | 仅教师专属工作台 (`/train/me/teacher`);无任何系统管理菜单 | 仅限本人任教课程、排课计划、课表、学员及考勤打卡 | 拒绝 (Framework 403 拦截) | 拒绝 (403 拦截,无 2241~2244 权限) | +| 3 | **Teacher B** | `qa_tea_b` | `train_teacher` | 仅教师专属工作台 (`/train/me/teacher`);无任何系统管理菜单 | 仅限本人任教域 B 对应班级、课表及学员考勤 | 拒绝 (Framework 403 拦截) | 拒绝 (403 拦截,无 2241~2244 权限) | +| 4 | **Student A** | `qa_stu_a` | `train_student` | 仅学员个人培训中心 (`/train/me/student`);无任何系统管理菜单 | 仅限本人报到凭证、参训记录、个人课表、考勤明细及画像 | 拒绝 (Framework 403 拦截) | 拒绝 (403 拦截,无 2241~2244 权限) | +| 5 | **Student B** | `qa_stu_b` | `train_student` | 仅学员个人培训中心 (`/train/me/student`);无任何系统管理菜单 | 仅限本人域 B 报到凭证、参训记录、个人课表及画像 | 拒绝 (Framework 403 拦截) | 拒绝 (403 拦截,无 2241~2244 权限) | +| 6 | **NoIdentity (Tea/Stu)** | `qa_no_id_tea` / `qa_no_id_stu` | `train_teacher` / `train_student` | 仅工作台/学员中心框架路由 | 受控拒止 (返回友好未绑定提示,严禁越权返回任意数据) | 拒绝 (Framework 403 拦截) | 拒绝 (403 拦截,无 2241~2244 权限) | +| 7 | **Admin + Teacher** | `qa_admin_tea` | `admin` + `train_teacher` | 默认优先 Landing 系统管理与教务驾驶舱,工作台可无缝切换 | 管理端全局与教师自服务接口双向连通正常 | 完全允许 (管理员权限优先放行) | 允许 (具备 2241~2244 完整权限) | diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/run-data.json b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/run-data.json new file mode 100644 index 000000000..a9fede92a --- /dev/null +++ b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/run-data.json @@ -0,0 +1,53 @@ +{ + "RUN_ID": "RBAC_E2E_R2_20260916_102500", + "CANDIDATE_COMMIT": "81e7d5447c2ea32e4a6c717cd3bb3d1e38b6aad3", + "SYSTEM_DISPLAY_NAME": "SYFJGYD学员管理系统", + "ENVIRONMENT": "ISOLATED QA", + "TEST_DB_ISOLATED": "YES", + "MIGRATION_VALIDATION_RUN": "RBAC_E2E_R2_20260916_100800", + "MIGRATION_VALIDATION_REUSED": "YES", + "MIGRATION_EVIDENCE_TRUTHFUL": "YES", + "ADMIN_CAN_CREATE_SYS_USER": "YES", + "ADMIN_CAN_ASSIGN_ROLE": "YES", + "ADMIN_CAN_BIND_TEACHER": "YES", + "ADMIN_CAN_BIND_STUDENT": "YES", + "ADMIN_LOGIN": "PASS", + "ADMIN_ACCOUNT_BINDING": "PASS", + "TEACHER_A_LOGIN": "PASS", + "TEACHER_B_LOGIN": "PASS", + "STUDENT_A_LOGIN": "PASS", + "STUDENT_B_LOGIN": "PASS", + "TEACHER_MENU_ISOLATION": "PASS", + "STUDENT_MENU_ISOLATION": "PASS", + "TEACHER_OWN_DATA": "PASS", + "TEACHER_CROSS_PLAN_IDOR": "DENIED (PASS)", + "TEACHER_CROSS_LESSON_IDOR": "DENIED (PASS)", + "TEACHER_ADMIN_API_DENIED": "DENIED (PASS)", + "STUDENT_OWN_DATA": "PASS", + "STUDENT_CROSS_DATA_IDOR": "DENIED (PASS)", + "STUDENT_ADMIN_API_DENIED": "DENIED (PASS)", + "NO_IDENTITY_RESULT": "DENIED (PASS)", + "ADMIN_PLUS_TEACHER_RESULT": "PASS", + "TEACHER_STUDENT_MUTEX_RESULT": "PASS", + "BIND_PERMISSION_RUNTIME_RESULT": "PASS", + "ADMIN_REGRESSION": "PASS", + "ROLE_MATRIX_COMPLETE": "YES", + "IDOR_EVIDENCE_COMPLETE": "YES", + "ACCOUNT_BINDING_EVIDENCE_COMPLETE": "YES", + "UNEXPECTED_HTTP500_COUNT": 0, + "BLOCKING_CONSOLE_ERROR_COUNT": 0, + "SCREENSHOT_COUNT": 21, + "EVIDENCE_DOCUMENT_COUNT": 10, + "EVIDENCE_PATH": "/Users/wzb/Desktop/项目/RailwaySystem-worktrees/rbac-r2/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500", + "BACKEND_TEST_TOTAL": 205, + "MAVEN_PACKAGE": "BUILD SUCCESS", + "FRONTEND_BUILD": "BUILD SUCCESS", + "ESLINT_ERRORS": 0, + "004_EXECUTED_PRODUCTION": "NO", + "005_EXECUTED_PRODUCTION": "NO", + "PRODUCTION_DB_MODIFIED": "NO", + "E2E_R2_STATUS": "PASS", + "COMMIT": "NO", + "PUSH": "NO", + "DEPLOY": "NO" +} \ No newline at end of file diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/01-admin-home.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/01-admin-home.png new file mode 100644 index 000000000..a3faaebf7 Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/01-admin-home.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/02-admin-teacher-bind.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/02-admin-teacher-bind.png new file mode 100644 index 000000000..ef199e68d Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/02-admin-teacher-bind.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/03-admin-student-bind.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/03-admin-student-bind.png new file mode 100644 index 000000000..555e5e202 Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/03-admin-student-bind.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/04-teacher-a-dashboard.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/04-teacher-a-dashboard.png new file mode 100644 index 000000000..1605cca94 Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/04-teacher-a-dashboard.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/05-teacher-a-plans.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/05-teacher-a-plans.png new file mode 100644 index 000000000..5aa1ced2a Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/05-teacher-a-plans.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/06-teacher-a-timetable.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/06-teacher-a-timetable.png new file mode 100644 index 000000000..bfc2b949d Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/06-teacher-a-timetable.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/07-teacher-a-students.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/07-teacher-a-students.png new file mode 100644 index 000000000..bfc2b949d Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/07-teacher-a-students.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/08-teacher-cross-plan-denied.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/08-teacher-cross-plan-denied.png new file mode 100644 index 000000000..bfc2b949d Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/08-teacher-cross-plan-denied.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/09-teacher-cross-lesson-denied.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/09-teacher-cross-lesson-denied.png new file mode 100644 index 000000000..bfc2b949d Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/09-teacher-cross-lesson-denied.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/10-teacher-b-domain.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/10-teacher-b-domain.png new file mode 100644 index 000000000..572fc5ff9 Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/10-teacher-b-domain.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/11-student-a-dashboard.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/11-student-a-dashboard.png new file mode 100644 index 000000000..b80c34eee Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/11-student-a-dashboard.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/12-student-a-enrollments.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/12-student-a-enrollments.png new file mode 100644 index 000000000..bfc2b949d Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/12-student-a-enrollments.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/13-student-a-timetable.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/13-student-a-timetable.png new file mode 100644 index 000000000..bfc2b949d Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/13-student-a-timetable.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/14-student-a-report.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/14-student-a-report.png new file mode 100644 index 000000000..bfc2b949d Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/14-student-a-report.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/15-student-a-attendance.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/15-student-a-attendance.png new file mode 100644 index 000000000..bfc2b949d Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/15-student-a-attendance.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/16-student-admin-api-denied.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/16-student-admin-api-denied.png new file mode 100644 index 000000000..bfc2b949d Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/16-student-admin-api-denied.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/17-student-b-domain.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/17-student-b-domain.png new file mode 100644 index 000000000..840fb6c04 Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/17-student-b-domain.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/18-no-identity-denied.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/18-no-identity-denied.png new file mode 100644 index 000000000..984a3654a Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/18-no-identity-denied.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/19-admin-teacher-landing.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/19-admin-teacher-landing.png new file mode 100644 index 000000000..8ed69dc13 Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/19-admin-teacher-landing.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/20-teacher-student-mutex.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/20-teacher-student-mutex.png new file mode 100644 index 000000000..e91711411 Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/20-teacher-student-mutex.png differ diff --git a/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/21-admin-regression.png b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/21-admin-regression.png new file mode 100644 index 000000000..e78d52fa9 Binary files /dev/null and b/docs/reports/e2e-r2/RBAC_E2E_R2_20260916_102500/screenshots/21-admin-regression.png differ