diff --git a/docs/current/00-START-HERE.md b/docs/current/00-START-HERE.md index accb57351..ed4485e37 100644 --- a/docs/current/00-START-HERE.md +++ b/docs/current/00-START-HERE.md @@ -52,6 +52,7 @@ docs/reports/** MUST NOT be treated as current truth. | **03** | [**03-DATABASE-AND-TABLES.md**](03-DATABASE-AND-TABLES.md) | **数据库架构、迁移链与数据表总账**
KingbaseES DDL、21张业务表、系统表、真正可重复建库流水线说明(附设计规约草案 [CLEAN_DEMO_DATABASE_SPEC.md](CLEAN_DEMO_DATABASE_SPEC.md))。 | 后端开发、DBA、数据审计人员 | | **04** | [**04-API-INVENTORY.md**](04-API-INVENTORY.md) | **全量 API 接口总账**
全量后端 Controller 接口路径、HTTP 方法、源码级校验表关联、build_ui 实际调用关系与实现状态。 | 前后端研发、接口自动化测试 | | **05** | [**05-CLIENT-API-STATUS.md**](05-CLIENT-API-STATUS.md) | **甲方与外部接口状态清单**
记录 DMS 及电子班牌等外部接口的实时连通、鉴权、真实联调凭据与 Mock 状态,严禁 Mock 冒充真实。 | 集成工程师、外部联调人员 | +| **05A** | [**05A-CLIENT-PROVIDED-API-CATALOG.md**](05A-CLIENT-PROVIDED-API-CATALOG.md) | **甲方提供外部接口总账 (27 个唯一接口)**
记录甲方正式向项目交付的原始 DMS API 契约、参数结构、响应要素与脱敏凭据,严格区分契约来源与运营提供商。 | 甲方对接、集成工程师、契约审计 | | **06** | [**06-DEMO-BASELINE.md**](06-DEMO-BASELINE.md) | **演示基线准则与重构要求**
明确旧 Demo 不可信与新 Demo 尚未开始的事实,确立纯净数据库与确定性数据等 7 大原则。 | QA、测试架构师、验收人员 | | **07** | [**07-KNOWN-GAPS.md**](07-KNOWN-GAPS.md) | **内部已知缺口与外部阻塞清单**
仅记录经过严格验证的真实缺口(ACCOM-PERM-01 已解决闭环,记录 DMS 外部硬件阻塞与 C03 成绩收敛等)。 | 研发团队、排期人员、问题排查 | | **08** | [**08-NEXT-ACTIONS.md**](08-NEXT-ACTIONS.md) | **下一阶段标准化 16 步行动路线图**
固定从环境冻结、纯净库重建、种子数据灌入到最终 Docs Phase B 的 16 步标准流。 | 项目经理、技术负责人 | diff --git a/docs/current/02-FUNCTION-MODULES.md b/docs/current/02-FUNCTION-MODULES.md index 9944162fb..750001bee 100644 --- a/docs/current/02-FUNCTION-MODULES.md +++ b/docs/current/02-FUNCTION-MODULES.md @@ -19,7 +19,7 @@ | **02** | **学员档案管理** | **`IMPLEMENTED`** | `TrainStudentController`
`TrainStudentMeController` | `train_student`
`sys_user` | 学员主档管理、身份证密文脱敏、批量导入、学员自服务培训中心(个人课表、考勤、住宿查询)。 | | **03** | **课程资源库** | **`IMPLEMENTED`** | `TrainCourseController` | `train_course`
`train_resource` | 理论/实作课程分类管理、标准学时/学分配置、教学大纲、统一资源关联。 | | **04** | **场地与教室** | **`IMPLEMENTED`** | `TrainClassroomInfoController`
`TrainTrainingSiteController` | `train_classroom_info`
`train_training_site` | 教室与实训场地物理档案管理、容纳人数上限控制、使用状态互斥校验。 | -| **05** | **开班计划管理** | **`IMPLEMENTED`** | `TrainPlanController` | `train_plan` | 培训班全生命周期流转(草稿 0 → 已发布 1 → 培训中 2 → 已结训 3)、多班级并行管理。 | +| **05** | **开班计划管理** | **`IMPLEMENTED`** | `TrainPlanController` | `train_class_plan` | 培训班全生命周期流转(草稿 0 → 已发布 1 → 培训中 2 → 已结训 3)、多班级并行管理。 | | **06** | **开班课程配置** | **`IMPLEMENTED`** | `TrainPlanCourseController` | `train_plan_course` | 一班多课绑定、分配各门课程任课教师、排课先后序号与学时分配。 | | **07** | **课次日程与排课**| **`IMPLEMENTED`** | `TrainLessonController` | `train_lesson` | 课次生成、时段安排;**四维时段冲突校验(教师、教室、学员班级、起止日期范围)**。 | | **08** | **考勤与报到管理**| **`IMPLEMENTED`** | `TrainReportActionController`
`TrainStudentCheckinController`
`AttendanceController` | `train_class_report`
`train_student_checkin`
`train_lesson` | 开班现场报到核验、课次签到/签退、教师代签补卡、人工标记缺勤、请假记录。 | diff --git a/docs/current/03-DATABASE-AND-TABLES.md b/docs/current/03-DATABASE-AND-TABLES.md index 7fa934305..bfc133bc3 100644 --- a/docs/current/03-DATABASE-AND-TABLES.md +++ b/docs/current/03-DATABASE-AND-TABLES.md @@ -128,30 +128,49 @@ --- -## 3. 全量业务数据表总账 (21 张 `train_*` 表) +## 3. 全量业务数据表总账 (21 张 V2 核心业务表 + 2 张 DMS 扩展表 + 1 张历史表) -当前正式数据库设计包含且仅包含以下 21 张业务表: +### 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_classroom_info` | `BIGINT (ID)` | 000 + 003 | 教学教室信息表,记录教室编号、楼栋、容纳人数与配备 | 被 `train_lesson` 引用 (教室时段互斥) | -| **05** | `train_training_site` | `BIGINT (ID)` | 000 + 003 | 实训演练场地表,记录室内/室外工区、容量与安全规范 | 被 `train_lesson` 引用 (场地时段互斥) | -| **06** | `train_plan` | `VARCHAR(32)` | 000 + 003 | 培训开班计划主表,控制培训项目全生命周期与时间跨度 | 驱动 `train_plan_course`、`train_enrollment` | -| **07** | `train_plan_course` | `BIGINT (ID)` | 002 | 班级课程关系表 (N:M),指定培训班开设课程及授课教师 | 关联 `plan_id`、`c_id`、`t_id` | -| **08** | `train_enrollment` | `BIGINT (ID)` | 002 | 参训人员名册表,定义学员参加班级及参训状态 (待报到/在训/结训) | 关联 `plan_id`、`s_id` | -| **09** | `train_lesson` | `BIGINT (ID)` | 002 | 课次排课表,记录每次课的具体时段、地点与授课教师 (互斥 CHECK) | 关联 `plan_id`、`plan_course_id`、`t_id`、场地 | -| **10** | `train_student_checkin` | `BIGINT (ID)` | 004 重建 | 课堂考勤打卡流水表,记录学员签到、签退与出勤状态 | 关联 `lesson_id`、`s_id` | -| **11** | `train_class_report` | `BIGINT (ID)` | 004 重建 | 现场报到核验记录表,学员到校开班报到凭据流水 | 关联 `enrollment_id`、`s_id`、`plan_id` | -| **12** | `train_dormitory_info` | `BIGINT (ID)` | 000 + 003 | 宿舍房间主表,记录宿舍楼栋、房号、性别分类、总床位数与在用数 | 被 `train_accommodation` 引用 | -| **13** | `train_accommodation` | `BIGINT (ID)` | 002 | 学员住宿分配台账表,记录床位分配、入住/退宿/调房生命周期 | 关联 `s_id`、`dorm_id`、`plan_id` | -| **14** | `train_score_info` | `BIGINT (ID)` | 002 | 学员培训成绩表,记录各科目考评得分与最终成绩评定 | 关联 `plan_id`、`s_id`、`c_id` (score >= 0 CHECK) | -| **15** | `train_study_duration` | `BIGINT (ID)` | 004 重建 | 自主学习时长流水表,记录学员研读教学资料的计时时长 | 关联 `s_id`、`resource_id` | -| **16** | `train_resource` | `VARCHAR(32)` | 002 | 统一教学资源主表,存放课件、视频、教材电子档等元数据 | 被 `train_course_resource` 引用 | -| **17** | `train_course_resource`| `BIGINT (ID)` | 002 | 课程与教学资源关联表 (N:M) | 关联 `c_id`、`resource_id` | -| **18** | `train_electronic_board`| `BIGINT (ID)` | 000 + 003 | 电子班牌硬件设备信息表,记录设备 MAC、IP、挂接教室与通信时间 | 关联 `classroom_id` | -| **19** | `train_external_resource_mapping` | `BIGINT (ID)` | 系统 008 | 外部资源映射表,记录本地宿舍与外部 DMS 空间/锁具的映射关系 | 关联 `dorm_id`、`external_resource_id` | -| **20** | `train_dorm_auth` | `BIGINT (ID)` | 004 + 系统 009 | 门禁卡/密码授权编排状态表,维护门锁下发授权生命周期 | 关联 `accommodation_id`、`external_auth_id` | -| **21** | `train_external_operation` | `BIGINT (ID)` | 系统 008 | 外部异步操作流水表,记录向 DMS 下发密码/撤销的异步 operationId | 关联 `auth_id`、`operation_type`、重试次数 | +| **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 单表成绩模型。V2 迁移脚本 `009_drop_legacy_score.sql` 已下线并在 `010_verify.sql` 中断言不存在;但在未完成完整成绩重构前,旧 Controller 仍保留只读兼容映射。 | +| **系统底座表** | `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` 等 | 若依平台底层通用表结构,支持多部门组织架构、角色菜单授权与操作审计。 | diff --git a/docs/current/04-API-INVENTORY.md b/docs/current/04-API-INVENTORY.md index 7082db07a..1429bb910 100644 --- a/docs/current/04-API-INVENTORY.md +++ b/docs/current/04-API-INVENTORY.md @@ -1,152 +1,160 @@ # 04 - 系统全量 API 接口总账与数据库调用链 (API Inventory & Database Lineage) > **最高原则**:**拒绝根据 URL 猜测表名与调用状态**! -> 1. **`PRIMARY_TABLE` / `READ_TABLES` / `WRITE_TABLES`**:必须通过 `Controller → Service → Mapper → XML/SQL` 源码调用链完整确认,标记为 **`VERIFIED_FROM_SOURCE`**;未穷尽调用链的标注为 `NOT_YET_VERIFIED`; -> 2. **`USED_BY_UI`**:必须通过 `build_ui/src/api/**` 与 `build_ui/src/views/**` 实际调用证据确认,分为 **`VERIFIED_USED_BY_UI`**(API 文件定义且被 View 组件导入调用)、**`DEFINED_IN_UI_API_ONLY`**(API 文件已声明函数但 View 暂未直接引用)、**`NOT_FOUND_IN_UI`**(前端未定义),严禁无证据一刀切填 `YES`; -> 3. **`IMPLEMENTATION_STATUS`**:Controller 存在仅证明端点已定义,标注为 **`ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)`**,受外部硬件阻断的标注为 **`ENDPOINT_DEFINED (BLOCKED_EXTERNAL)`**。 +> 1. **`PRIMARY_TABLE` / `READ_TABLES` / `WRITE_TABLES`**:必须通过 `Controller → Service → Mapper → XML/SQL` 源码调用链完整确认,标记为 **`VERIFIED_FROM_SOURCE`**;严禁规则推导,严禁使用过时推测表名(如将物理表 `train_class_plan` 误写为 `train_plan`); +> 2. **`USED_BY_UI`**:必须通过 `build_ui/src/api/**` 与 `build_ui/src/views/**` 实际调用证据确认,分为 **`VERIFIED_USED_BY_UI`**、**`DEFINED_IN_UI_API_ONLY`**、**`NOT_FOUND_IN_UI`**; +> 3. **`IMPLEMENTATION_STATUS`**:Controller 存在证明端点已定义,标注为 **`ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)`**,受外部硬件阻断的标注为 **`ENDPOINT_DEFINED (BLOCKED_EXTERNAL)`**。 --- -## 1. 核心培训业务 API 账本 (`CUSTOM_TRAIN_BUSINESS_API`) +## 1. 核心培训业务 API 账本 (`CUSTOM_TRAIN_BUSINESS_API` — 107 个端点源码穿透验证) -| 接口路径 (API) | 请求方式 (METHOD) | 数据来源 (SOURCE) | 承载控制器 (CONTROLLER) | 主实体表 (PRIMARY_TABLE) | 读操作表 (READ_TABLES) | 写操作表 (WRITE_TABLES) | 调用链追踪状态 (LINEAGE_STATUS) | UI调用状态 (USED_BY_UI) | 实现状态 (STATUS) | -| :--- | :---: | :---: | :--- | :--- | :--- | :--- | :---: | :---: | :---: | -| `/train/teacher/list` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainTeacherController` | `train_teacher` | `train_teacher` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/teacher/{tId}` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainTeacherController` | `train_teacher` | `train_teacher` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/teacher` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainTeacherController` | `train_teacher` | `NONE` | `train_teacher` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/teacher` | `PUT` | `RAILWAYSYSTEM_INTERNAL` | `TrainTeacherController` | `train_teacher` | `train_teacher` | `train_teacher` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/teacher/{tIds}` | `DELETE` | `RAILWAYSYSTEM_INTERNAL` | `TrainTeacherController` | `train_teacher` | `train_teacher` | `train_teacher` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/teacher/export` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainTeacherController` | `train_teacher` | `NONE` | `train_teacher` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/me/teacher/plans` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainTeacherMeController` | `train_teacher` | `train_teacher` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/me/teacher` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainTeacherMeController` | `train_teacher` | `train_teacher` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/me/teacher/students` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainTeacherMeController` | `train_teacher` | `train_teacher` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/me/teacher/lessons/{lessonId}/attendance` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainTeacherMeController` | `train_teacher` | `train_teacher` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/student/list` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainStudentController` | `train_student` | `train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/student/{sId}` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainStudentController` | `train_student` | `train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/student` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainStudentController` | `train_student` | `NONE` | `train_student` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/student` | `PUT` | `RAILWAYSYSTEM_INTERNAL` | `TrainStudentController` | `train_student` | `train_student` | `train_student` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/student/{sIds}` | `DELETE` | `RAILWAYSYSTEM_INTERNAL` | `TrainStudentController` | `train_student` | `train_student` | `train_student` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/student/export` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainStudentController` | `train_student` | `train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/student/importTemplate` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainStudentController` | `train_student` | `train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/student/importData` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainStudentController` | `train_student` | `NONE` | `train_student` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/me/student/enrollments` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainStudentMeController` | `train_student` | `train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/me/student/timetable` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainStudentMeController` | `train_student` | `train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/me/student/report` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainStudentMeController` | `train_student` | `train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/me/student/attendance` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainStudentMeController` | `train_student` | `train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/me/student/duration` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainStudentMeController` | `train_student` | `train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/me/student/portrait` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainStudentMeController` | `train_student` | `train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/course/list` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainCourseController` | `train_course` | `train_course` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/course/{cId}` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainCourseController` | `train_course` | `train_course` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/course` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainCourseController` | `train_course` | `NONE` | `train_course` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/course` | `PUT` | `RAILWAYSYSTEM_INTERNAL` | `TrainCourseController` | `train_course` | `train_course` | `train_course` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/course/{cIds}` | `DELETE` | `RAILWAYSYSTEM_INTERNAL` | `TrainCourseController` | `train_course` | `train_course` | `train_course` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/classroom/list` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainClassroomInfoController` | `train_classroom_info` | `train_classroom_info` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/classroom/{classRoomId}` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainClassroomInfoController` | `train_classroom_info` | `train_classroom_info` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/classroom` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainClassroomInfoController` | `train_classroom_info` | `NONE` | `train_classroom_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/classroom` | `PUT` | `RAILWAYSYSTEM_INTERNAL` | `TrainClassroomInfoController` | `train_classroom_info` | `train_classroom_info` | `train_classroom_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/classroom/{classRoomIds}` | `DELETE` | `RAILWAYSYSTEM_INTERNAL` | `TrainClassroomInfoController` | `train_classroom_info` | `train_classroom_info` | `train_classroom_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/training-site/list` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainTrainingSiteController` | `train_training_site` | `train_training_site` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/training-site/{siteId}` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainTrainingSiteController` | `train_training_site` | `train_training_site` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/training-site` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainTrainingSiteController` | `train_training_site` | `NONE` | `train_training_site` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/training-site` | `PUT` | `RAILWAYSYSTEM_INTERNAL` | `TrainTrainingSiteController` | `train_training_site` | `train_training_site` | `train_training_site` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/training-site/{siteIds}` | `DELETE` | `RAILWAYSYSTEM_INTERNAL` | `TrainTrainingSiteController` | `train_training_site` | `train_training_site` | `train_training_site` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainPlanController` | `train_plan` | `train_class_plan` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans/{planId}` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainPlanController` | `train_plan` | `train_class_plan` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainPlanController` | `train_plan` | `train_class_plan` | `train_class_plan` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans/{planId}` | `PUT` | `RAILWAYSYSTEM_INTERNAL` | `TrainPlanController` | `train_plan` | `train_class_plan` | `train_class_plan` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans/{planIds}` | `DELETE` | `RAILWAYSYSTEM_INTERNAL` | `TrainPlanController` | `train_plan` | `train_class_plan` | `train_class_plan` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans/{planId}/publish` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainPlanController` | `train_plan` | `train_class_plan` | `train_class_plan` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans/{planId}/start` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainPlanController` | `train_plan` | `train_class_plan` | `train_class_plan` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans/{planId}/complete` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainPlanController` | `train_plan` | `train_class_plan` | `train_class_plan` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans/{planId}/courses` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainPlanCourseController` | `train_plan_course` | `train_plan_course, train_course, train_teacher` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans/{planId}/courses` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainPlanCourseController` | `train_plan_course` | `train_plan_course` | `train_plan_course` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans/{planId}/courses/{planCourseId}` | `DELETE` | `RAILWAYSYSTEM_INTERNAL` | `TrainPlanCourseController` | `train_plan_course` | `train_plan_course` | `train_plan_course` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans/{planId}/enrollments` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainEnrollmentController` | `train_enrollment` | `train_enrollment, train_student, train_class_plan` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans/{planId}/enrollments` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainEnrollmentController` | `train_enrollment` | `train_enrollment, train_student` | `train_enrollment` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans/{planId}/enrollments/batch` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainEnrollmentController` | `train_enrollment` | `train_enrollment, train_student` | `train_enrollment` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/enrollments/{enrollmentId}` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainEnrollmentController` | `train_enrollment` | `train_enrollment, train_student, train_class_plan` | `NONE` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/enrollments/{enrollmentId}/status` | `PUT` | `RAILWAYSYSTEM_INTERNAL` | `TrainEnrollmentController` | `train_enrollment` | `train_enrollment` | `train_enrollment` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/enrollments/{enrollmentId}` | `DELETE` | `RAILWAYSYSTEM_INTERNAL` | `TrainEnrollmentController` | `train_enrollment` | `train_enrollment` | `train_enrollment` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans/{planId}/lessons` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainLessonController` | `train_lesson` | `train_lesson, train_class_plan, train_course, train_teacher, train_classroom_info, train_training_site` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans/{planId}/lessons` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainLessonController` | `train_lesson` | `train_lesson, train_classroom_info, train_training_site` | `train_lesson` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/lessons/{lessonId}` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainLessonController` | `train_lesson` | `train_lesson, train_class_plan, train_course, train_teacher, train_classroom_info, train_training_site` | `NONE` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/lessons/{lessonId}` | `PUT` | `RAILWAYSYSTEM_INTERNAL` | `TrainLessonController` | `train_lesson` | `train_lesson, train_classroom_info, train_training_site` | `train_lesson` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/lessons/{lessonId}` | `DELETE` | `RAILWAYSYSTEM_INTERNAL` | `TrainLessonController` | `train_lesson` | `train_lesson, train_classroom_info, train_training_site` | `train_lesson` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/lessons/check-conflict` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainLessonController` | `train_lesson` | `train_lesson, train_classroom_info, train_training_site` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/lessons/scheduling-options` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainLessonController` | `train_classroom_info` | `train_classroom_info, train_training_site, train_teacher` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/plans/{planId}/timetable` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainLessonController` | `train_lesson` | `train_lesson, train_class_plan, train_course, train_teacher, train_classroom_info, train_training_site` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/enrollments/{enrollmentId}/report` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainReportActionController` | `train_class_report` | `train_enrollment, train_class_report` | `train_class_report, train_enrollment` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/report/list` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainClassReportController` | `train_class_report` | `train_class_report, train_student, train_class_plan` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/checkin/list` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainStudentCheckinController` | `train_student_checkin` | `train_student_checkin, train_student, train_lesson` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/attendance/lessons/{lessonId}/checkins` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `AttendanceController` | `train_student_checkin` | `train_student_checkin, train_lesson, train_enrollment` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/attendance/sign-in` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `AttendanceController` | `train_student_checkin` | `train_student_checkin, train_lesson` | `train_student_checkin` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/attendance/sign-out` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `AttendanceController` | `train_student_checkin` | `train_student_checkin, train_lesson` | `train_student_checkin` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/attendance/proxy-checkin` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `AttendanceController` | `train_student_checkin` | `train_student_checkin, train_lesson` | `train_student_checkin` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/attendance/mark-absent` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `AttendanceController` | `train_student_checkin` | `train_student_checkin, train_lesson` | `train_student_checkin` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/attendance/adjust` | `PUT` | `RAILWAYSYSTEM_INTERNAL` | `AttendanceController` | `train_student_checkin` | `train_student_checkin, train_lesson` | `train_student_checkin` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/dormitory/list` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainDormitoryInfoController` | `train_dormitory_info` | `train_dormitory_info` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/dormitory/{dormId}` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainDormitoryInfoController` | `train_dormitory_info` | `train_dormitory_info` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/dormitory` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainDormitoryInfoController` | `train_dormitory_info` | `NONE` | `train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/dormitory` | `PUT` | `RAILWAYSYSTEM_INTERNAL` | `TrainDormitoryInfoController` | `train_dormitory_info` | `train_dormitory_info` | `train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/dormitory/{dormIds}` | `DELETE` | `RAILWAYSYSTEM_INTERNAL` | `TrainDormitoryInfoController` | `train_dormitory_info` | `train_dormitory_info` | `train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/accommodation/list` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccommodationController` | `train_accommodation` | `train_accommodation, train_dormitory_info, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/accommodation/{accommodationId}` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccommodationController` | `train_accommodation` | `train_accommodation, train_dormitory_info, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/accommodation/enrollment/{enrollmentId}` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccommodationController` | `train_accommodation` | `train_accommodation, train_dormitory_info, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/accommodation/enrollment/{enrollmentId}/history` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccommodationController` | `train_accommodation` | `train_accommodation, train_dormitory_info, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/accommodation` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccommodationController` | `train_accommodation` | `train_accommodation, train_dormitory_info` | `train_accommodation, train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/accommodation/{accommodationId}/checkin` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccommodationController` | `train_accommodation` | `train_accommodation, train_dormitory_info` | `train_accommodation, train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/accommodation/{accommodationId}/checkout` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccommodationController` | `train_accommodation` | `train_accommodation, train_dormitory_info` | `train_accommodation, train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/accommodation/{accommodationId}/transfer` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccommodationController` | `train_accommodation` | `train_accommodation, train_dormitory_info` | `train_accommodation, train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/accommodation/{accommodationIds}` | `DELETE` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccommodationController` | `train_accommodation` | `train_accommodation` | `train_accommodation, train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/score/list` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainScoreInfoController` | `train_score_info` | `train_score_info, train_student, train_course` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/score/{scoreId}` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainScoreInfoController` | `train_score_info` | `train_score_info, train_student, train_course` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/score` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainScoreInfoController` | `train_score_info` | `NONE` | `train_score_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/score` | `PUT` | `RAILWAYSYSTEM_INTERNAL` | `TrainScoreInfoController` | `train_score_info` | `train_score_info` | `train_score_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/score/{scoreIds}` | `DELETE` | `RAILWAYSYSTEM_INTERNAL` | `TrainScoreInfoController` | `train_score_info` | `train_score_info` | `train_score_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/analysis/dashboard/overview` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainAnalysisController` | `聚合多表` | `train_class_plan, train_enrollment, train_lesson, train_student_checkin, train_accommodation` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/analysis/dashboard/charts` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainAnalysisController` | `聚合多表` | `train_class_plan, train_enrollment, train_lesson, train_student_checkin, train_accommodation` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/analysis/attendance/summary` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainAnalysisController` | `聚合多表` | `train_student_checkin, train_lesson, train_class_plan` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/analysis/attendance/charts` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainAnalysisController` | `聚合多表` | `train_student_checkin, train_lesson, train_class_plan` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/analysis/portrait/student-360/{studentId}` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainAnalysisController` | `聚合多表` | `train_student, train_enrollment, train_student_checkin, train_score_info, train_study_duration` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/access/mapping/list` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccessManagementController` | `train_external_resource_mapping` | `train_external_resource_mapping, train_dormitory_info` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/access/auth/list` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccessManagementController` | `train_dorm_auth` | `train_dorm_auth, train_accommodation, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/access/operation/list` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccessManagementController` | `train_external_operation` | `train_external_operation` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/access/capability` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccessManagementController` | `N/A (配置与常量)` | `NONE` | `NONE` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/access/issue` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccessManagementController` | `train_dorm_auth` | `train_dorm_auth, train_accommodation` | `train_dorm_auth, train_external_operation` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BLOCKED_EXTERNAL)` | -| `/train/access/revoke` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccessManagementController` | `train_dorm_auth` | `train_dorm_auth, train_accommodation` | `train_dorm_auth, train_external_operation` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BLOCKED_EXTERNAL)` | -| `/train/binding/teachers/bindable-users` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccountBindingAdminController` | `sys_user` | `sys_user, train_teacher, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `NOT_FOUND_IN_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/binding/teachers/{teacherId}/bind` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccountBindingAdminController` | `train_teacher` | `sys_user, train_teacher` | `train_teacher (user_id)` | `VERIFIED_FROM_SOURCE` | `NOT_FOUND_IN_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/binding/students/bindable-users` | `GET` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccountBindingAdminController` | `sys_user` | `sys_user, train_teacher, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `NOT_FOUND_IN_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | -| `/train/binding/students/{studentId}/bind` | `POST` | `RAILWAYSYSTEM_INTERNAL` | `TrainAccountBindingAdminController` | `train_student` | `sys_user, train_student` | `train_student (user_id)` | `VERIFIED_FROM_SOURCE` | `NOT_FOUND_IN_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| 接口路径 (API) | 请求方式 (METHOD) | 领域模块 | 控制器方法 (CTRL_METHOD) | 服务层方法 (SERVICE_METHOD) | 映射层方法 (MAPPER_METHOD) | 映射XML语句 (XML_STMT) | 主实体表 (PRIMARY_TABLE) | 读操作表 (READ_TABLES) | 写操作表 (WRITE_TABLES) | 调用链状态 (LINEAGE_STATUS) | UI调用状态 (USED_BY_UI) | 实现状态 (STATUS) | +| :--- | :---: | :---: | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :---: | :---: | :---: | +| `/train/teacher/list` | `GET` | `Train` | `list` | `ITrainTeacherService.selectTrainTeacherList` | `TrainTeacherMapper.selectTrainTeacherList` | `selectTrainTeacherList` | `train_teacher` | `train_teacher` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/teacher/{tId}` | `GET` | `Train` | `getInfo` | `ITrainTeacherService.selectTrainTeacherByTId` | `TrainTeacherMapper.selectTrainTeacherByTId` | `selectTrainTeacherByTId` | `train_teacher` | `train_teacher` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/teacher` | `POST` | `Train` | `add` | `ITrainTeacherService.insertTrainTeacher` | `TrainTeacherMapper.insertTrainTeacher` | `insertTrainTeacher` | `train_teacher` | `NONE` | `train_teacher` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/teacher` | `PUT` | `Train` | `edit` | `ITrainTeacherService.updateTrainTeacher` | `TrainTeacherMapper.updateTrainTeacher` | `updateTrainTeacher` | `train_teacher` | `train_teacher` | `train_teacher` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/teacher/{tIds}` | `DELETE` | `Train` | `remove` | `ITrainTeacherService.deleteTrainTeacherByTIds` | `TrainTeacherMapper.deleteTrainTeacherByTIds` | `deleteTrainTeacherByTIds` | `train_teacher` | `train_teacher` | `train_teacher` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/teacher/export` | `POST` | `Train` | `export` | `ITrainTeacherService.selectTrainTeacherList` | `TrainTeacherMapper.selectTrainTeacherList` | `selectTrainTeacherList` | `train_teacher` | `train_teacher` | `NONE` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/me/teacher/plans` | `GET` | `Train` | `getMyPlans` | `ITrainingIdentityService.assertTeacherIdentity` | `TrainLessonMapper.selectPlansByTeacherId` | `selectPlansByTeacherId` | `train_class_plan` | `train_class_plan, train_plan_course, train_lesson` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/me/teacher` | `GET` | `Train` | `getTeacherProfile` | `ITrainingIdentityService.assertTeacherIdentity` | `TrainTeacherMapper.selectTrainTeacherByTId` | `selectTrainTeacherByTId` | `train_teacher` | `train_teacher` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/me/teacher/students` | `GET` | `Train` | `getMyClassStudents` | `TrainLessonMapper.countTeacherInPlan` | `TrainEnrollmentMapper.selectEnrollmentItemList` | `selectEnrollmentItemList` | `train_enrollment` | `train_enrollment, train_lesson, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/me/teacher/lessons/{lessonId}/attendance` | `GET` | `Train` | `getLessonAttendance` | `TrainLessonMapper.selectTrainLessonById` | `TrainStudentCheckinMapper.selectCheckinsByLessonId` | `selectCheckinsByLessonId` | `train_student_checkin` | `train_lesson, train_student_checkin` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/student/list` | `GET` | `Train` | `list` | `ITrainStudentService.selectTrainStudentList` | `TrainStudentMapper.selectTrainStudentList` | `selectTrainStudentList` | `train_student` | `train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/student/{sId}` | `GET` | `Train` | `getInfo` | `ITrainStudentService.selectTrainStudentBySId` | `TrainStudentMapper.selectTrainStudentBySId` | `selectTrainStudentBySId` | `train_student` | `train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/student` | `POST` | `Train` | `add` | `ITrainStudentService.insertTrainStudent` | `TrainStudentMapper.insertTrainStudent` | `insertTrainStudent` | `train_student` | `NONE` | `train_student` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/student` | `PUT` | `Train` | `edit` | `ITrainStudentService.updateTrainStudent` | `TrainStudentMapper.updateTrainStudent` | `updateTrainStudent` | `train_student` | `train_student` | `train_student` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/student/{sIds}` | `DELETE` | `Train` | `remove` | `ITrainStudentService.deleteTrainStudentBySIds` | `TrainStudentMapper.deleteTrainStudentBySIds` | `deleteTrainStudentBySIds` | `train_student` | `train_student` | `train_student` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/student/export` | `POST` | `Train` | `export` | `ITrainStudentService.selectTrainStudentList` | `TrainStudentMapper.selectTrainStudentList` | `selectTrainStudentList` | `train_student` | `train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/student/importTemplate` | `GET` | `Train` | `importTemplate` | `ITrainStudentService.importTemplate` | `NONE` | `NONE` | `train_student` | `NONE` | `NONE` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/student/importData` | `POST` | `Train` | `importData` | `ITrainStudentService.importStudent` | `TrainStudentMapper.insertTrainStudent` | `insertTrainStudent` | `train_student` | `train_student` | `train_student` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/me/student/enrollments` | `GET` | `Train` | `getMyEnrollments` | `ITrainingIdentityService.assertStudentIdentity` | `TrainEnrollmentMapper.selectEnrollmentsByStudentId` | `selectEnrollmentsByStudentId` | `train_enrollment` | `train_enrollment, train_class_plan` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/me/student/timetable` | `GET` | `Train` | `getMyTimetable` | `ITrainingIdentityService.assertStudentIdentity` | `TrainLessonMapper.selectScheduleLessonsByStudentId` | `selectScheduleLessonsByStudentId` | `train_lesson` | `train_lesson, train_plan_course, train_course, train_classroom_info, train_training_site` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/me/student/report` | `GET` | `Train` | `getMyReport` | `ITrainingIdentityService.assertStudentIdentity` | `TrainClassReportMapper.selectLatestReportByStudentId` | `selectLatestReportByStudentId` | `train_class_report` | `train_class_report, train_enrollment, train_class_plan` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/me/student/attendance` | `GET` | `Train` | `getMyAttendance` | `ITrainingIdentityService.assertStudentIdentity` | `TrainStudentCheckinMapper.selectCheckinsByStudentId` | `selectCheckinsByStudentId` | `train_student_checkin` | `train_student_checkin, train_lesson, train_enrollment` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/me/student/duration` | `GET` | `Train` | `getMyDuration` | `ITrainingIdentityService.assertStudentIdentity` | `TrainStudyDurationMapper.selectDurationsByStudentId` | `selectDurationsByStudentId` | `train_study_duration` | `train_study_duration, train_course` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/me/student/portrait` | `GET` | `Train` | `getMyPortrait` | `ITrainingIdentityService.assertStudentIdentity` | `TrainStudentPortraitMapper.selectPortraitByStudentId` | `selectPortraitByStudentId` | `train_student_portrait` | `train_student_portrait, train_enrollment, train_class_plan, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/course/list` | `GET` | `Train` | `list` | `ITrainCourseService.selectTrainCourseList` | `TrainCourseMapper.selectTrainCourseList` | `selectTrainCourseList` | `train_course` | `train_course` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/course/{cId}` | `GET` | `Train` | `getInfo` | `ITrainCourseService.selectTrainCourseByCId` | `TrainCourseMapper.selectTrainCourseByCId` | `selectTrainCourseByCId` | `train_course` | `train_course` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/course` | `POST` | `Train` | `add` | `ITrainCourseService.insertTrainCourse` | `TrainCourseMapper.insertTrainCourse` | `insertTrainCourse` | `train_course` | `NONE` | `train_course` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/course` | `PUT` | `Train` | `edit` | `ITrainCourseService.updateTrainCourse` | `TrainCourseMapper.updateTrainCourse` | `updateTrainCourse` | `train_course` | `train_course` | `train_course` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/course/{cIds}` | `DELETE` | `Train` | `remove` | `ITrainCourseService.deleteTrainCourseByCIds` | `TrainCourseMapper.deleteTrainCourseByCIds` | `deleteTrainCourseByCIds` | `train_course` | `train_course` | `train_course` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/classroom/list` | `GET` | `Train` | `list` | `ITrainClassroomInfoService.selectTrainClassroomInfoList` | `TrainClassroomInfoMapper.selectTrainClassroomInfoList` | `selectTrainClassroomInfoList` | `train_classroom_info` | `train_classroom_info` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/classroom/{classRoomId}` | `GET` | `Train` | `getInfo` | `ITrainClassroomInfoService.selectTrainClassroomInfoByClassRoomId` | `TrainClassroomInfoMapper.selectTrainClassroomInfoByClassRoomId` | `selectTrainClassroomInfoByClassRoomId` | `train_classroom_info` | `train_classroom_info` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/classroom` | `POST` | `Train` | `add` | `ITrainClassroomInfoService.insertTrainClassroomInfo` | `TrainClassroomInfoMapper.insertTrainClassroomInfo` | `insertTrainClassroomInfo` | `train_classroom_info` | `NONE` | `train_classroom_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/classroom` | `PUT` | `Train` | `edit` | `ITrainClassroomInfoService.updateTrainClassroomInfo` | `TrainClassroomInfoMapper.updateTrainClassroomInfo` | `updateTrainClassroomInfo` | `train_classroom_info` | `train_classroom_info` | `train_classroom_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/classroom/{classRoomIds}` | `DELETE` | `Train` | `remove` | `ITrainClassroomInfoService.deleteTrainClassroomInfoByClassRoomIds` | `TrainClassroomInfoMapper.deleteTrainClassroomInfoByClassRoomIds` | `deleteTrainClassroomInfoByClassRoomIds` | `train_classroom_info` | `train_classroom_info` | `train_classroom_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/training-site/list` | `GET` | `Train` | `list` | `ITrainTrainingSiteService.selectTrainTrainingSiteList` | `TrainTrainingSiteMapper.selectTrainTrainingSiteList` | `selectTrainTrainingSiteList` | `train_training_site` | `train_training_site` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/training-site/{siteId}` | `GET` | `Train` | `getInfo` | `ITrainTrainingSiteService.selectTrainTrainingSiteBySiteId` | `TrainTrainingSiteMapper.selectTrainTrainingSiteBySiteId` | `selectTrainTrainingSiteBySiteId` | `train_training_site` | `train_training_site` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/training-site` | `POST` | `Train` | `add` | `ITrainTrainingSiteService.insertTrainTrainingSite` | `TrainTrainingSiteMapper.insertTrainTrainingSite` | `insertTrainTrainingSite` | `train_training_site` | `NONE` | `train_training_site` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/training-site` | `PUT` | `Train` | `edit` | `ITrainTrainingSiteService.updateTrainTrainingSite` | `TrainTrainingSiteMapper.updateTrainTrainingSite` | `updateTrainTrainingSite` | `train_training_site` | `train_training_site` | `train_training_site` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/training-site/{siteIds}` | `DELETE` | `Train` | `remove` | `ITrainTrainingSiteService.deleteTrainTrainingSiteBySiteIds` | `TrainTrainingSiteMapper.deleteTrainTrainingSiteBySiteIds` | `deleteTrainTrainingSiteBySiteIds` | `train_training_site` | `train_training_site` | `train_training_site` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans` | `GET` | `Train` | `list` | `PlanAppService.selectPlanItemList` | `TrainClassPlanMapper.selectTrainClassPlanList` | `selectTrainClassPlanList` | `train_class_plan` | `train_class_plan, train_plan_course, train_enrollment` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans/{planId}` | `GET` | `Train` | `getInfo` | `ITrainClassPlanService.selectTrainClassPlanByPlanId` | `TrainClassPlanMapper.selectTrainClassPlanByPlanId` | `selectTrainClassPlanByPlanId` | `train_class_plan` | `train_class_plan` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans` | `POST` | `Train` | `add` | `PlanAppService.createPlan` | `TrainClassPlanMapper.insertTrainClassPlan` | `insertTrainClassPlan` | `train_class_plan` | `NONE` | `train_class_plan` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans/{planId}` | `PUT` | `Train` | `edit` | `PlanAppService.updatePlan` | `TrainClassPlanMapper.updateTrainClassPlan` | `updateTrainClassPlan` | `train_class_plan` | `train_class_plan` | `train_class_plan` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans/{planIds}` | `DELETE` | `Train` | `remove` | `ITrainClassPlanService.deleteTrainClassPlanByPlanIds` | `TrainClassPlanMapper.deleteTrainClassPlanByPlanIds` | `deleteTrainClassPlanByPlanIds` | `train_class_plan` | `train_class_plan` | `train_class_plan` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans/{planId}/publish` | `POST` | `Train` | `publish` | `PlanAppService.publishPlan` | `TrainClassPlanMapper.updateTrainClassPlan` | `updateTrainClassPlan` | `train_class_plan` | `train_class_plan` | `train_class_plan` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans/{planId}/start` | `POST` | `Train` | `start` | `PlanAppService.startPlan` | `TrainClassPlanMapper.updateTrainClassPlan` | `updateTrainClassPlan` | `train_class_plan` | `train_class_plan` | `train_class_plan` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans/{planId}/complete` | `POST` | `Train` | `complete` | `PlanAppService.completePlan` | `TrainClassPlanMapper.updateTrainClassPlan` | `updateTrainClassPlan` | `train_class_plan` | `train_class_plan, train_enrollment` | `train_class_plan, train_enrollment` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans/{planId}/courses` | `GET` | `Train` | `list` | `PlanAppService.listCourses` | `TrainPlanCourseMapper.selectCourseItemsByPlanId` | `selectCourseItemsByPlanId` | `train_plan_course` | `train_plan_course, train_course` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans/{planId}/courses` | `POST` | `Train` | `bind` | `PlanAppService.bindCourses` | `TrainPlanCourseMapper.insertTrainPlanCourse` | `insertTrainPlanCourse` | `train_plan_course` | `train_plan_course` | `train_plan_course` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans/{planId}/courses/{planCourseId}` | `DELETE` | `Train` | `unbind` | `PlanAppService.unbindCourse` | `TrainPlanCourseMapper.deleteTrainPlanCourseByPlanCourseId` | `deleteTrainPlanCourseByPlanCourseId` | `train_plan_course` | `train_plan_course` | `train_plan_course` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans/{planId}/enrollments` | `GET` | `Train` | `list` | `EnrollmentAppService.listEnrollments` | `TrainEnrollmentMapper.selectEnrollmentItemList` | `selectEnrollmentItemList` | `train_enrollment` | `train_enrollment, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans/{planId}/enrollments` | `POST` | `Train` | `enroll` | `EnrollmentAppService.enrollStudent` | `TrainEnrollmentMapper.insertTrainEnrollment` | `insertTrainEnrollment` | `train_enrollment` | `train_enrollment` | `train_enrollment` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans/{planId}/enrollments/batch` | `POST` | `Train` | `batchEnroll` | `EnrollmentAppService.batchEnrollStudents` | `TrainEnrollmentMapper.insertTrainEnrollment` | `insertTrainEnrollment` | `train_enrollment` | `train_enrollment` | `train_enrollment` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/enrollments/{enrollmentId}` | `GET` | `Train` | `getInfo` | `EnrollmentAppService.getEnrollmentDetail` | `TrainEnrollmentMapper.selectEnrollmentItemById` | `selectEnrollmentItemById` | `train_enrollment` | `train_enrollment, train_student, train_class_plan` | `NONE` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/enrollments/{enrollmentId}/status` | `PUT` | `Train` | `updateStatus` | `EnrollmentAppService.updateStatus` | `TrainEnrollmentMapper.updateTrainEnrollment` | `updateTrainEnrollment` | `train_enrollment` | `train_enrollment` | `train_enrollment` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/enrollments/{enrollmentId}` | `DELETE` | `Train` | `remove` | `EnrollmentAppService.removeEnrollment` | `TrainEnrollmentMapper.deleteTrainEnrollmentByEnrollmentId` | `deleteTrainEnrollmentByEnrollmentId` | `train_enrollment` | `train_enrollment` | `train_enrollment` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans/{planId}/lessons` | `GET` | `Train` | `list` | `SchedulingAppService.listLessons` | `TrainLessonMapper.selectLessonItemsByPlanId` | `selectLessonItemsByPlanId` | `train_lesson` | `train_lesson, train_plan_course, train_course, train_teacher, train_classroom_info, train_training_site` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans/{planId}/lessons` | `POST` | `Train` | `schedule` | `SchedulingAppService.scheduleLesson` | `TrainLessonMapper.insertTrainLesson` | `insertTrainLesson` | `train_lesson` | `train_lesson` | `train_lesson` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/lessons/{lessonId}` | `GET` | `Train` | `getInfo` | `SchedulingAppService.getLessonDetail` | `TrainLessonMapper.selectLessonItemById` | `selectLessonItemById` | `train_lesson` | `train_lesson, train_plan_course, train_course, train_teacher, train_classroom_info, train_training_site` | `NONE` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/lessons/{lessonId}` | `PUT` | `Train` | `update` | `SchedulingAppService.updateLesson` | `TrainLessonMapper.updateTrainLesson` | `updateTrainLesson` | `train_lesson` | `train_lesson` | `train_lesson` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/lessons/{lessonId}` | `DELETE` | `Train` | `cancel` | `SchedulingAppService.cancelLesson` | `TrainLessonMapper.deleteTrainLessonByLessonId` | `deleteTrainLessonByLessonId` | `train_lesson` | `train_lesson` | `train_lesson` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/lessons/check-conflict` | `POST` | `Train` | `checkConflict` | `SchedulingAppService.checkConflict` | `TrainLessonMapper.countTeacherConflicts` | `countTeacherConflicts` | `train_lesson` | `train_lesson` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/lessons/scheduling-options` | `GET` | `Train` | `getOptions` | `SchedulingAppService.getSchedulingOptions` | `TrainClassroomInfoMapper.selectTrainClassroomInfoList` | `selectTrainClassroomInfoList` | `train_classroom_info` | `train_classroom_info, train_training_site, train_teacher` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/plans/{planId}/timetable` | `GET` | `Train` | `getTimetable` | `SchedulingAppService.getTimetable` | `TrainLessonMapper.selectScheduleLessonsByPlanId` | `selectScheduleLessonsByPlanId` | `train_lesson` | `train_lesson, train_plan_course, train_course, train_teacher, train_classroom_info, train_training_site` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/enrollments/{enrollmentId}/report` | `POST` | `Train` | `report` | `ITrainClassReportService.reportEnrollment` | `TrainClassReportMapper.insertTrainClassReport` | `insertTrainClassReport` | `train_class_report` | `train_enrollment, train_class_plan` | `train_class_report` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/report/list` | `GET` | `Train` | `list` | `ITrainClassReportService.selectTrainClassReportList` | `TrainClassReportMapper.selectTrainClassReportList` | `selectTrainClassReportList` | `train_class_report` | `train_class_report, train_enrollment, train_student, train_class_plan` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/checkin/list` | `GET` | `Train` | `list` | `ITrainStudentCheckinService.selectTrainStudentCheckinList` | `TrainStudentCheckinMapper.selectTrainStudentCheckinList` | `selectTrainStudentCheckinList` | `train_student_checkin` | `train_student_checkin, train_student, train_lesson` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/attendance/lessons/{lessonId}/checkins` | `GET` | `Train` | `getLessonRoster` | `AttendanceAppService.getLessonRoster` | `TrainStudentCheckinMapper.selectCheckinsByLessonId` | `selectCheckinsByLessonId` | `train_student_checkin` | `train_student_checkin, train_enrollment, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/attendance/sign-in` | `POST` | `Train` | `signIn` | `AttendanceAppService.signIn` | `TrainStudentCheckinMapper.insertTrainStudentCheckin` | `insertTrainStudentCheckin` | `train_student_checkin` | `train_student_checkin` | `train_student_checkin` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/attendance/sign-out` | `POST` | `Train` | `signOut` | `AttendanceAppService.signOut` | `TrainStudentCheckinMapper.updateTrainStudentCheckin` | `updateTrainStudentCheckin` | `train_student_checkin` | `train_student_checkin` | `train_student_checkin` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/attendance/proxy-checkin` | `POST` | `Train` | `signIn` | `AttendanceAppService.signIn` | `TrainStudentCheckinMapper.insertTrainStudentCheckin` | `insertTrainStudentCheckin` | `train_student_checkin` | `train_student_checkin` | `train_student_checkin` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/attendance/mark-absent` | `POST` | `Train` | `markAbsence` | `AttendanceAppService.markAbsence` | `TrainStudentCheckinMapper.insertTrainStudentCheckin` | `insertTrainStudentCheckin` | `train_student_checkin` | `train_student_checkin` | `train_student_checkin` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/attendance/adjust` | `PUT` | `Train` | `adjust` | `AttendanceAppService.adjust` | `TrainStudentCheckinMapper.updateTrainStudentCheckin` | `updateTrainStudentCheckin` | `train_student_checkin` | `train_student_checkin` | `train_student_checkin` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/dormitory/list` | `GET` | `Train` | `list` | `ITrainDormitoryInfoService.selectTrainDormitoryInfoList` | `TrainDormitoryInfoMapper.selectTrainDormitoryInfoList` | `selectTrainDormitoryInfoList` | `train_dormitory_info` | `train_dormitory_info` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/dormitory/{dormId}` | `GET` | `Train` | `getInfo` | `ITrainDormitoryInfoService.selectTrainDormitoryInfoByDormId` | `TrainDormitoryInfoMapper.selectTrainDormitoryInfoByDormId` | `selectTrainDormitoryInfoByDormId` | `train_dormitory_info` | `train_dormitory_info` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/dormitory` | `POST` | `Train` | `add` | `ITrainDormitoryInfoService.insertTrainDormitoryInfo` | `TrainDormitoryInfoMapper.insertTrainDormitoryInfo` | `insertTrainDormitoryInfo` | `train_dormitory_info` | `NONE` | `train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/dormitory` | `PUT` | `Train` | `edit` | `ITrainDormitoryInfoService.updateTrainDormitoryInfo` | `TrainDormitoryInfoMapper.updateTrainDormitoryInfo` | `updateTrainDormitoryInfo` | `train_dormitory_info` | `train_dormitory_info` | `train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/dormitory/{dormIds}` | `DELETE` | `Train` | `remove` | `ITrainDormitoryInfoService.deleteTrainDormitoryInfoByDormIds` | `TrainDormitoryInfoMapper.deleteTrainDormitoryInfoByDormIds` | `deleteTrainDormitoryInfoByDormIds` | `train_dormitory_info` | `train_dormitory_info` | `train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/accommodation/list` | `GET` | `Train` | `list` | `ITrainAccommodationService.selectTrainAccommodationList` | `TrainAccommodationMapper.selectTrainAccommodationList` | `selectTrainAccommodationList` | `train_accommodation` | `train_accommodation, train_dormitory_info, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/accommodation/{accommodationId}` | `GET` | `Train` | `getInfo` | `ITrainAccommodationService.selectTrainAccommodationByAccommodationId` | `TrainAccommodationMapper.selectTrainAccommodationByAccommodationId` | `selectTrainAccommodationByAccommodationId` | `train_accommodation` | `train_accommodation, train_dormitory_info, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/accommodation/enrollment/{enrollmentId}` | `GET` | `Train` | `getByEnrollment` | `ITrainAccommodationService.selectTrainAccommodationByEnrollmentId` | `TrainAccommodationMapper.selectTrainAccommodationByEnrollmentId` | `selectTrainAccommodationByEnrollmentId` | `train_accommodation` | `train_accommodation, train_dormitory_info, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/accommodation/enrollment/{enrollmentId}/history` | `GET` | `Train` | `getHistory` | `ITrainAccommodationService.selectAccommodationHistory` | `TrainAccommodationMapper.selectAccommodationHistory` | `selectAccommodationHistory` | `train_accommodation` | `train_accommodation, train_dormitory_info, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/accommodation` | `POST` | `Train` | `add` | `ITrainAccommodationService.insertTrainAccommodation` | `TrainAccommodationMapper.insertTrainAccommodation` | `insertTrainAccommodation` | `train_accommodation` | `train_accommodation, train_dormitory_info` | `train_accommodation, train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/accommodation/{accommodationId}/checkin` | `POST` | `Train` | `checkin` | `ITrainAccommodationService.checkinAccommodation` | `TrainAccommodationMapper.updateTrainAccommodation` | `updateTrainAccommodation` | `train_accommodation` | `train_accommodation, train_dormitory_info` | `train_accommodation, train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/accommodation/{accommodationId}/checkout` | `POST` | `Train` | `checkout` | `ITrainAccommodationService.checkoutAccommodation` | `TrainAccommodationMapper.updateTrainAccommodation` | `updateTrainAccommodation` | `train_accommodation` | `train_accommodation, train_dormitory_info` | `train_accommodation, train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/accommodation/{accommodationId}/transfer` | `POST` | `Train` | `transfer` | `ITrainAccommodationService.transferAccommodation` | `TrainAccommodationMapper.updateTrainAccommodation` | `updateTrainAccommodation` | `train_accommodation` | `train_accommodation, train_dormitory_info` | `train_accommodation, train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/accommodation/{accommodationIds}` | `DELETE` | `Train` | `remove` | `ITrainAccommodationService.deleteTrainAccommodationByAccommodationIds` | `TrainAccommodationMapper.deleteTrainAccommodationByAccommodationIds` | `deleteTrainAccommodationByAccommodationIds` | `train_accommodation` | `train_accommodation` | `train_accommodation, train_dormitory_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/score/list` | `GET` | `Train` | `list` | `ITrainScoreInfoService.selectTrainScoreInfoList` | `TrainScoreInfoMapper.selectTrainScoreInfoList` | `selectTrainScoreInfoList` | `train_score_info` | `train_score_info, train_student, train_course` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/score/{scoreId}` | `GET` | `Train` | `getInfo` | `ITrainScoreInfoService.selectTrainScoreInfoByScoreId` | `TrainScoreInfoMapper.selectTrainScoreInfoByScoreId` | `selectTrainScoreInfoByScoreId` | `train_score_info` | `train_score_info, train_student, train_course` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/score` | `POST` | `Train` | `add` | `ITrainScoreInfoService.insertTrainScoreInfo` | `TrainScoreInfoMapper.insertTrainScoreInfo` | `insertTrainScoreInfo` | `train_score_info` | `NONE` | `train_score_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/score` | `PUT` | `Train` | `edit` | `ITrainScoreInfoService.updateTrainScoreInfo` | `TrainScoreInfoMapper.updateTrainScoreInfo` | `updateTrainScoreInfo` | `train_score_info` | `train_score_info` | `train_score_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/score/{scoreIds}` | `DELETE` | `Train` | `remove` | `ITrainScoreInfoService.deleteTrainScoreInfoByScoreIds` | `TrainScoreInfoMapper.deleteTrainScoreInfoByScoreIds` | `deleteTrainScoreInfoByScoreIds` | `train_score_info` | `train_score_info` | `train_score_info` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/analysis/dashboard/overview` | `GET` | `Train` | `getDashboardOverview` | `ITrainAnalysisService.getDashboardOverview` | `TrainAnalysisMapper.selectDashboardOverview` | `selectDashboardOverview` | `train_class_plan` | `train_class_plan, train_enrollment, train_lesson, train_student_checkin, train_accommodation` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/analysis/dashboard/charts` | `GET` | `Train` | `getDashboardCharts` | `ITrainAnalysisService.getDashboardCharts` | `TrainAnalysisMapper.selectDashboardCharts` | `selectDashboardCharts` | `train_class_plan` | `train_class_plan, train_enrollment, train_lesson, train_student_checkin, train_accommodation` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/analysis/attendance/summary` | `GET` | `Train` | `getAttendanceSummary` | `ITrainAnalysisService.getAttendanceSummary` | `TrainAnalysisMapper.selectAttendanceSummary` | `selectAttendanceSummary` | `train_student_checkin` | `train_student_checkin, train_lesson, train_class_plan` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/analysis/attendance/charts` | `GET` | `Train` | `getAttendanceCharts` | `ITrainAnalysisService.getAttendanceCharts` | `TrainAnalysisMapper.selectAttendanceCharts` | `selectAttendanceCharts` | `train_student_checkin` | `train_student_checkin, train_lesson, train_class_plan` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/analysis/portrait/student-360/{studentId}` | `GET` | `Train` | `getStudent360` | `ITrainAnalysisService.getStudent360` | `TrainAnalysisMapper.selectStudent360` | `selectStudent360` | `train_student` | `train_student, train_enrollment, train_student_checkin, train_score_info, train_study_duration` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/access/mapping/list` | `GET` | `Train` | `getDormMapping` | `IExternalResourceMappingService.getActiveRoomMapping` | `TrainExternalResourceMappingMapper.selectTrainExternalResourceMappingList` | `selectTrainExternalResourceMappingList` | `train_external_resource_mapping` | `train_external_resource_mapping, train_dormitory_info` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/access/auth/list` | `GET` | `Train` | `listAuth` | `ITrainDormAuthService.selectTrainDormAuthList` | `TrainDormAuthMapper.selectTrainDormAuthList` | `selectTrainDormAuthList` | `train_dorm_auth` | `train_dorm_auth, train_accommodation, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/access/operation/list` | `GET` | `Train` | `getOperationHistory` | `IExternalOperationService.listOperationsByDoorAuthId` | `TrainExternalOperationMapper.selectTrainExternalOperationList` | `selectTrainExternalOperationList` | `train_external_operation` | `train_external_operation` | `NONE` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/access/capability` | `GET` | `Train` | `getCapabilities` | `N/A (配置与只读状态)` | `NONE` | `NONE` | `N/A (配置与常量)` | `NONE` | `NONE` | `VERIFIED_FROM_SOURCE` | `DEFINED_IN_UI_API_ONLY` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/access/issue` | `POST` | `Train` | `issueCredential` | `AccessAuthorizationOrchestrator.issueAuthorization` | `TrainDormAuthMapper.updateTrainDormAuth` | `updateTrainDormAuth` | `train_dorm_auth` | `train_dorm_auth, train_accommodation` | `train_dorm_auth, train_external_operation` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BLOCKED_EXTERNAL)` | +| `/train/access/revoke` | `POST` | `Train` | `revokeAuth` | `AccessAuthorizationOrchestrator.revokeAuthorization` | `TrainDormAuthMapper.updateTrainDormAuth` | `updateTrainDormAuth` | `train_dorm_auth` | `train_dorm_auth, train_accommodation` | `train_dorm_auth, train_external_operation` | `VERIFIED_FROM_SOURCE` | `VERIFIED_USED_BY_UI` | `ENDPOINT_DEFINED (BLOCKED_EXTERNAL)` | +| `/train/binding/teachers/bindable-users` | `GET` | `Train` | `getTeacherBindableUsers` | `TrainAccountBindingAdminService.selectBindableUsers` | `SysUserMapper.selectUserList` | `selectUserList` | `sys_user` | `sys_user, train_teacher, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `NOT_FOUND_IN_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/binding/teachers/{teacherId}/bind` | `POST` | `Train` | `bindTeacherUser` | `TrainAccountBindingAdminService.bindTeacherAccount` | `TrainTeacherMapper.updateTrainTeacher` | `updateTrainTeacher` | `train_teacher` | `sys_user, train_teacher` | `train_teacher` | `VERIFIED_FROM_SOURCE` | `NOT_FOUND_IN_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/binding/students/bindable-users` | `GET` | `Train` | `getStudentBindableUsers` | `TrainAccountBindingAdminService.selectBindableUsers` | `SysUserMapper.selectUserList` | `selectUserList` | `sys_user` | `sys_user, train_teacher, train_student` | `NONE` | `VERIFIED_FROM_SOURCE` | `NOT_FOUND_IN_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | +| `/train/binding/students/{studentId}/bind` | `POST` | `Train` | `bindStudentUser` | `TrainAccountBindingAdminService.bindStudentAccount` | `TrainStudentMapper.updateTrainStudent` | `updateTrainStudent` | `train_student` | `sys_user, train_student` | `train_student` | `VERIFIED_FROM_SOURCE` | `NOT_FOUND_IN_UI` | `ENDPOINT_DEFINED (BACKEND_IMPLEMENTED)` | --- -## 2. 统计汇总与实证说明 +## 2. 统计汇总与一致性强制检查 (Task F & Task G) ### 2.1 端点数量与结构化审计指标 -- **表格端点行数 (TOTAL_ENDPOINT_ROWS)**:107 行 -- **唯一端点标识 (UNIQUE_METHOD_PATH_COUNT)**:107 项(以 `METHOD + PATH` 为联合主键) -- **重复端点数量 (DUPLICATE_METHOD_PATH_COUNT)**:0 项(0 冲突,0 重复记录) +- **内部业务端点总数 (`INTERNAL_API_COUNT`)**:**107 个** +- **唯一端点标识 (`UNIQUE_METHOD_PATH_COUNT`)**:**107 项**(以 `METHOD + PATH` 为联合主键,0 冲突,0 重复记录) ### 2.2 数据库调用链追踪分布 (`LINEAGE_STATUS`) -- **`VERIFIED_FROM_SOURCE`**:107 / 107 (100% 经 Controller → Service → Mapper → XML 链路追踪验证) -- **`NOT_YET_VERIFIED`**:0 项(无未经证实的猜测项) -- **细粒度读写分离**:所有 107 个端点均明确标注了读取表清单 (`READ_TABLES`) 与写入变更表清单 (`WRITE_TABLES`),包含 5 个聚合分析类复杂多表只读端点。 +- **源码逐项验证通过 (`API_DB_LINEAGE_VERIFIED_COUNT`)**:**107 个** (100% 经 Controller → Service → Mapper → XML 链路追踪验证) +- **规则启发式推导 (`API_DB_LINEAGE_HEURISTIC_COUNT`)**:**0 个** (彻底清零规则推导,全部端点均具备源码定位凭据) +- **未经证实猜测量 (`API_DB_LINEAGE_UNVERIFIED_COUNT`)**:**0 个** +- **已知表名纠偏完成**: + - 彻底纠偏历史文档中的 `train_plan` 误称,物理主表统一修正为实际数据库表名 **`train_class_plan`**; + - 彻底核验 **`train_student_portrait`** 为真实物理业务表(定义于 `004_rebuild_business_tables.sql`,由 `010_verify.sql` 强断言)。 ### 2.3 前端调用状态分布 (`USED_BY_UI` 基于 `build_ui/` 扫描) -- **`VERIFIED_USED_BY_UI`**:92 项(在 `build_ui/src/views/` 页面中实际被用户交互触发) -- **`DEFINED_IN_UI_API_ONLY`**:11 项(在 `build_ui/src/api/` 中已封装接口,但页面视图暂未直接引用,如部分导出/批量导入端点) -- **`NOT_FOUND_IN_UI`**:4 项(纯管理端底层端点,前端未声明:教师/学员账号手工绑定与候选人过滤接口) +- **`VERIFIED_USED_BY_UI`**:**92 项**(在 `build_ui/src/views/` 页面中实际被用户交互触发) +- **`DEFINED_IN_UI_API_ONLY`**:**11 项**(在 `build_ui/src/api/` 中已封装接口,但页面视图暂未直接引用) +- **`NOT_FOUND_IN_UI`**:**4 项**(纯管理端底层端点,前端未声明:教师/学员账号手工绑定与候选人过滤接口) -### 2.4 四类 API 边界范围确立 (API Scope Definition) -为彻底杜绝不同领域接口职责混淆,系统 API 划分为以下四大独立边界: +### 2.4 四类 API 边界范围确立 (API Scope Definition — 概念分离) 1. **`CUSTOM_TRAIN_BUSINESS_API` (RailwaySystem 自研培训业务端点)**:**107 个** - - 涵盖 24 个培训核心控制器,承载开班、排课、学员、考勤、报到、住宿、成绩与画像全生命周期; + - 涵盖开班、排课、学员、考勤、报到、住宿、成绩与画像全生命周期; 2. **`RUOYI_PLATFORM_API` (RuoYi 底座系统平台端点)**:**95 个** - - 涵盖 `/login`、`/captchaImage`、`/system/user/*`、`/system/role/*`、`/system/menu/*`、`/system/dict/*`、`/monitor/*` 等若依通用平台能力; -3. **`CLIENT_PROVIDED_API` (甲方沈阳房建公寓段自身提供的接口)**:**0 个** - - 甲方当前未向本项目开放或提供任何内部信息化系统的 Web API,系统业务主流程完全由自建数据库闭环; -4. **`THIRD_PARTY_API` (第三方外部服务端点,以 DMS 门锁平台为主)**:**9 个** - - 涵盖 DMS Token、建筑、楼层、房间、门锁查询、在线密码增删及状态轮询; + - 涵盖 `/login`、`/captchaImage`、`/system/user/*`、`/system/role/*`、`/system/menu/*`、`/system/dict/*`、`/monitor/*` 等通用平台能力; +3. **`CLIENT_PROVIDED_API` (甲方沈阳房建公寓段向项目交付的外部接口契约)**:**27 个** + - 甲方正式提供的完整外部技术契约(详见 [05A-CLIENT-PROVIDED-API-CATALOG.md](05A-CLIENT-PROVIDED-API-CATALOG.md)),禁止再标记为 0 个; +4. **`DMS_VENDOR_API` (由第三方 DMS 物联网厂商托管运营的接口)**:**27 个** + - 实际运行于厂商 IoT 云管平台,与甲方交付契约完全对齐; 5. **`MOCK_ONLY_INTERFACE` (纯本地模拟桩接口)**:**1 个** - - 电子班牌硬件数据推送(由于缺少现场物理联网班牌,当前由本地模拟桩与心跳表驱动)。 + - 电子班牌硬件数据推送。 + +### 2.5 数据库与 API 调用链强制一致性检查 (Task G) +- **`LINEAGE_TABLE_NOT_IN_DATABASE_CATALOG`**:**0 项**(所有 API 引用的表均存在于 03 数据库总账中) +- **`DATABASE_TABLE_NOT_REFERENCED_BY_ANY_API`**:**5 项** + - 说明:`train_course_resource`、`train_electronic_board`、`train_resource`、`train_score_item`、`train_student_score` 5 张表暂未暴露于当前 107 个内部 HTTP API 中(如电子班牌由独立控制器处理,成绩 V2 细粒度表等待 C03 成绩闭环对接); +- **`UNKNOWN_TABLE_REFERENCES`**:**0 项**(无任何未识别或猜测表名引用) +- **`API_DB_LINEAGE_FREEZE`**:**YES** diff --git a/docs/current/05-CLIENT-API-STATUS.md b/docs/current/05-CLIENT-API-STATUS.md index 9175deba1..0aa54480d 100644 --- a/docs/current/05-CLIENT-API-STATUS.md +++ b/docs/current/05-CLIENT-API-STATUS.md @@ -6,59 +6,81 @@ --- -## 1. 外部接口状态模型与三维判定准则 +## 1. 契约来源与提供方概念分离 (Task A & Task E) -为了杜绝“接口 HTTP 200”与“演示业务可用”之间的混淆,外部接口引入**三维判定模型**: - -1. **真实网络连通性 (CONNECTIVITY_STATUS)**: - - **`REAL_LIVE`**:外部真实网络畅通、凭据认证通过、成功发起 HTTP 请求并收到 200 响应; - - **`CLIENT_REAL_AUTH_BLOCKED`**:外部网络可达,但因密钥错误或缺少角色权限被 401/403 阻断; - - **`CLIENT_REAL_UNREACHABLE`**:外部网络不通、连接超时、域名未解析或接口已下线; - - **`NOT_YET_TESTED`**:代码已编写适配器,但受安全红线或硬件限制尚未发起真实外网调用; - - **`MOCK_SIMULATION`**:无外部真实服务支撑,完全由本地假数据桩或单元测试套件驱动; - - **`SECURITY_PROHIBITED` / `OUT_OF_SCOPE`**:系统安全政策明确禁止实现与调用的高危接口(如远程开门)。 - -2. **真实数据状态 (REAL_DATA_STATUS)**: - - **`REAL_DATA_AVAILABLE`**:真实接口返回了非空的物理硬件或业务资源数据; - - **`EMPTY_DATA`**:真实接口返回成功,但目标列表数据量为 0(如 0 栋楼、0 间房、0 把锁); - - **`NOT_APPLICABLE`**:接口属于写操作、认证或禁止调用,不适用数据查询。 - -3. **演示可用性 (DEMO_USABILITY)**: - - **`LIVE_API_BUT_NO_REAL_RESOURCE_DATA`**:接口虽在线但因厂商测试环境缺少物理资源,不可用于全真实数据演示; - - **`MOCK_SIMULATION_REQUIRED`**:端到端演示必须使用受控 Mock 桩模拟硬件反馈; - - **`PROHIBITED_FROM_DEMO`**:绝不允许在演示中调用。 +根据项目负责人裁定,系统严格区分**契约来源**与**服务运营提供方**: +- **`CLIENT_PROVIDED_API_COUNT = 27`**:甲方正式交付给项目的完整 DMS 外部接口契约中 unique METHOD + PATH 数量(详见 [05A-CLIENT-PROVIDED-API-CATALOG.md](05A-CLIENT-PROVIDED-API-CATALOG.md)); +- **`DMS_VENDOR_API_COUNT = 27`**:上述 27 个接口均由 DMS 门锁物联网厂商平台托管运营; +- 严禁再以“服务商为第三方厂商”为由将甲方交付契约排除在 `CLIENT_PROVIDED_API` 统计之外。 --- -## 2. 外部接口状态与证据矩阵表 (External API Matrix) +## 2. 契约路径冲突排查与审计结论 (Task C) -| 序号 | 外部接口名称 | 协议与端点 (API ENDPOINT) | 提供方 (PROVIDER) | 网络连通性 (CONNECTIVITY) | 真实数据状态 (DATA_STATUS) | 演示可用性 (DEMO_USABILITY) | 最近验证时间 (LAST_VERIFIED_AT) | 验证方式 (METHOD) | 证据来源 (EVIDENCE_SOURCE) | 实时返回特征 (LIVE_RESULT) | 破坏性风险说明 | -| :---: | :--- | :--- | :---: | :---: | :---: | :---: | :---: | :--- | :--- | :--- | :--- | -| **01** | **DMS 第三方应用凭据获取** | `POST /public/rest/third-party-app/token/get` | DMS 厂商平台 | **`REAL_LIVE`** | `NOT_APPLICABLE` | **`LIVE_AUTH_READY`** | 2026-09-17 | 真实外网 HTTP POST 携带有效 AppId/Secret 探测 | `docs/reports/integrated-acceptance/FINAL_PHASE1_20260917_101044/dms-final-status.md` | HTTP 200,取得有效 Token,`expires_in: 7200`,Cookie Token 认证机制验证通过 | 只读认证,无破坏性风险 | -| **02** | **DMS 建筑空间列表查询** | `POST /rest/place/building/list` | DMS 厂商平台 | **`REAL_LIVE`** | **`EMPTY_DATA`**
(`BUILDING=0`) | **`LIVE_API_BUT_NO_REAL_RESOURCE_DATA`** | 2026-09-17 | 真实外网携带 Cookie Token 发起 POST 查询 | `docs/reports/integrated-acceptance/FINAL_PHASE1_20260917_101044/dms-final-status.md` | HTTP 200,外层 JSON 符合契约,列表数据量为 0 (`BUILDING=0`) | 只读查询,安全 | -| **03** | **DMS 楼层空间列表查询** | `POST /rest/place/floor/list` | DMS 厂商平台 | **`REAL_LIVE`** | **`EMPTY_DATA`**
(`FLOOR=0`) | **`LIVE_API_BUT_NO_REAL_RESOURCE_DATA`** | 2026-09-17 | 真实外网携带 Cookie Token 发起 POST 查询 | `docs/reports/integrated-acceptance/FINAL_PHASE1_20260917_101044/dms-final-status.md` | HTTP 200,外层 JSON 符合契约,列表数据量为 0 (`FLOOR=0`) | 只读查询,安全 | -| **04** | **DMS 房间空间列表查询** | `POST /rest/place/room/list` | DMS 厂商平台 | **`REAL_LIVE`** | **`EMPTY_DATA`**
(`ROOM=0`) | **`LIVE_API_BUT_NO_REAL_RESOURCE_DATA`** | 2026-09-17 | 真实外网携带 Cookie Token 发起 POST 查询 | `docs/reports/integrated-acceptance/FINAL_PHASE1_20260917_101044/dms-final-status.md` | HTTP 200,外层 JSON 符合契约,列表数据量为 0 (`ROOM=0`) | 只读查询,安全 | -| **05** | **DMS 智能门锁设备列表查询** | `POST /rest/doorlock/list` | DMS 厂商平台 | **`REAL_LIVE`** | **`EMPTY_DATA`**
(`LOCK=0`) | **`LIVE_API_BUT_NO_REAL_RESOURCE_DATA`** | 2026-09-17 | 真实外网携带 Cookie Token 发起 POST 查询 | `docs/reports/integrated-acceptance/FINAL_PHASE1_20260917_101044/dms-final-status.md` | HTTP 200,外层 JSON 符合契约,挂载门锁数为 0 (`LOCK=0`) | 只读查询,安全 | -| **06** | **DMS 在线密码下发 (Mutation)** | `POST /rest/doorlock/online-password-key/create` | DMS 厂商平台 | **`NOT_YET_TESTED`**
(本地单测为 `MOCK_SIMULATION`) | `NOT_APPLICABLE` | **`MOCK_SIMULATION_REQUIRED`** | 2026-09-17 (Mock) | 本地 MockServer 单元契约测试 (`MockDmsServer.java`) | `RuoYi-Vue/ruoyi-train/src/test/java/com/ruoyi/train/integration/dms/client/DmsPasswordAdapterTest.java` | 真实环境因无指定房间与锁具,禁止发起调用 (`REAL_DMS_MUTATION_COUNT = 0`);Mock 环境返回模拟 operationId | **写操作**:严禁向未知门锁发起下发,待划拨测试硬件后联调 | -| **07** | **DMS 在线密码撤销 (Mutation)** | `POST /rest/doorlock/online-password-key/delete` | DMS 厂商平台 | **`NOT_YET_TESTED`**
(本地单测为 `MOCK_SIMULATION`) | `NOT_APPLICABLE` | **`MOCK_SIMULATION_REQUIRED`** | 2026-09-17 (Mock) | 本地 MockServer 单元契约测试 | `RuoYi-Vue/ruoyi-train/src/test/java/com/ruoyi/train/integration/dms/client/DmsPasswordAdapterTest.java` | 真实环境未调用;Mock 环境成功模拟撤销响应 | **写操作**:严禁向未知设备发起撤销 | -| **08** | **DMS 异步操作状态轮询** | `POST /rest/doorlock/operation/status` | DMS 厂商平台 | **`NOT_YET_TESTED`**
(本地单测为 `MOCK_SIMULATION`) | `NOT_APPLICABLE` | **`MOCK_SIMULATION_REQUIRED`** | 2026-09-17 (Mock) | 本地 MockServer 轮询测试 (`DmsOperationStatusAdapterTest.java`) | `RuoYi-Vue/ruoyi-train/src/test/java/com/ruoyi/train/integration/dms/client/DmsOperationStatusAdapterTest.java` | 真实环境无有效 operationId 供轮询;Mock 仿真状态机轮询成功 | 只读轮询,安全 | -| **09** | **DMS 远程开门 (Remote Unlock)** | 门锁远程触发开门接口 | DMS 厂商平台 | **`SECURITY_PROHIBITED`**
(`OUT_OF_SCOPE`) | `NOT_APPLICABLE` | **`PROHIBITED_FROM_DEMO`** | 2026-09-17 | 架构与安全红线基线审查 | `docs/decisions/security/` 与项目安全红线规则 | 历史证据表明系统安全政策严格禁止实现与调用远程开锁,未配置客户端亦未调用(非网络故障不可达,系范围外安全阻断) | **极高危险**:绝对禁止集成与调用 | -| **10** | **电子班牌实时数据推送** | 班牌通信端口与协议 | 电子班牌硬件厂商 | **`MOCK_SIMULATION`** | `SIMULATED_DATA` | **`LOCAL_SIMULATION_READY`** | 2026-09-20 | 本地数据库档案与模拟心跳更新 | `TrainElectronicBoardController.java` | 现场缺少实际联网电子班牌设备;系统当前在数据库记录心跳时间与班牌档案,通信属于模拟桩 | 无物理设备破坏风险 | +对历史文档中曾出现的契约路径漂移展开全工程源码与测试桩穿透检查: + +| 业务项 | 甲方契约路径 (CONTRACT_PATH) | 源码客户端路径 (CURRENT_CODE_PATH) | 本地Mock桩路径 (CURRENT_MOCK_PATH) | 历史文档路径 (CURRENT_DOC_PATH) | 源码契约一致性 (MATCH) | 缺陷裁决说明 | +| :--- | :--- | :--- | :--- | :--- | :---: | :--- | +| **在线密码删除** | `POST /rest/doorlock/online-password/delete` | `POST /rest/doorlock/online-password/delete`
(`DmsPasswordClient.java:89`) | `POST /rest/doorlock/online-password/delete`
(`MockDmsServer.java:286`) | `POST /rest/doorlock/online-password-key/delete`
(旧版 05 文档) | **YES** | **文档漂移笔误**。生产代码与 Mock 代码完全符合甲方真实契约,无需修改代码,已纠正文档。 | +| **操作状态查询** | `POST /rest/doorlock/query-operation-status` | `POST /rest/doorlock/query-operation-status`
(`DmsOperationStatusClient.java:33`) | `POST /rest/doorlock/query-operation-status`
(`MockDmsServer.java:316`) | `POST /rest/doorlock/operation/status`
(旧版 05 文档) | **YES** | **文档漂移笔误**。生产代码与 Mock 代码完全符合甲方真实契约,无需修改代码,已纠正文档。 | + +- **`CLIENT_CONTRACT_MISMATCH_COUNT`**:**0 项**(后端产品代码与甲方原始接口契约保持 100% 严格一致)。 --- -## 3. 统计汇总与客观边界说明 +## 3. 四层 DMS 集成覆盖矩阵 (Task D — 4-Tier Integration Matrix) -### 3.1 外部接口统计指标 (Task 6 对齐) -- **`RAILWAYSYSTEM_CUSTOM_BUSINESS_API_COUNT`**:107 个(详见 04-API-INVENTORY.md) -- **`RUOYI_PLATFORM_API_COUNT`**:95 个(底座通用管理与监控接口) -- **`CLIENT_PROVIDED_API_COUNT`**:0 个(甲方沈阳房建公寓段自身未提供信息化接口) -- **`THIRD_PARTY_API_COUNT`**:9 个(DMS 门锁平台接口:01~09) -- **`MOCK_ONLY_INTERFACE_COUNT`**:1 个(电子班牌推送接口:10) +涵盖甲方原始契约中全部 27 个唯一接口,穿透追踪: +```text +CLIENT CONTRACT API → RAILWAYSYSTEM ADAPTER / CLIENT → RAILWAYSYSTEM INTERNAL API → RUNTIME VERIFICATION +``` -### 3.2 外部接口真实状态分布 -- **真实网络连通端点数 (`CLIENT_API_REAL_CONNECTIVITY_COUNT`)**:5 个 (Token, Building, Floor, Room, Lock) -- **真实数据非空端点数 (`CLIENT_API_REAL_DATA_NONEMPTY_COUNT`)**:0 个 (**当前真实资源数量:BUILDING=0, FLOOR=0, ROOM=0, LOCK=0**) -- **受控待测写操作端点数 (`CLIENT_API_NOT_YET_TESTED_COUNT`)**:3 个 (密码下发、撤销、操作轮询) -- **安全红线禁止端点数 (`CLIENT_API_SECURITY_PROHIBITED_COUNT`)**:1 个 (远程开门) -- **纯本地模拟桩端点数 (`CLIENT_API_MOCK_COUNT`)**:1 个 (电子班牌) +| 序号 | 甲方契约接口 (CLIENT_API) | 适配器类 (ADAPTER_CLASS) | 适配器方法 (ADAPTER_METHOD) | 对应内部接口 (INTERNAL_API) | 实现状态 (IMPLEMENTATION_STATUS) | 真实测试状态 (REAL_TEST_STATUS) | 实时返回特征与证据 (REAL_RESULT) | 演示可用性 (DEMO_USABILITY) | +| :---: | :--- | :--- | :--- | :--- | :---: | :---: | :--- | :---: | +| **01** | `POST /public/rest/third-party-app/token/get` | `DmsTokenClient` | `obtainToken` | `DmsClient / DmsProperties` (底层服务) | `IMPLEMENTED` | `REAL_LIVE_EMPTY_DATA` | 真实外网 HTTP 200,取得有效 Token (`expires_in: 7200`),Cookie Token 认证通过 | `LIVE_AUTH_READY` | +| **02** | `POST /public/rest/security/logout` | `N/A` | `N/A` | `N/A` | `NOT_IMPLEMENTED` | `NOT_YET_TESTED` | 未封装客户端;Token 自然过期或会话替换 | `NOT_APPLICABLE` | +| **03** | `POST /rest/place/building/list` | `DmsPlaceClient` | `listBuildings` | `N/A` (集成探测) | `IMPLEMENTED` | `REAL_LIVE_EMPTY_DATA` | 真实外网 HTTP 200,返回 JSON 结构符合契约,数据量为 0 (`BUILDING=0`) | `LIVE_API_BUT_NO_REAL_RESOURCE_DATA` | +| **04** | `POST /rest/place/floor/list` | `DmsPlaceClient` | `listFloors` | `N/A` (集成探测) | `IMPLEMENTED` | `REAL_LIVE_EMPTY_DATA` | 真实外网 HTTP 200,返回 JSON 结构符合契约,数据量为 0 (`FLOOR=0`) | `LIVE_API_BUT_NO_REAL_RESOURCE_DATA` | +| **05** | `POST /rest/place/room/list` | `DmsPlaceClient` | `listRooms` | `N/A` (集成探测) | `IMPLEMENTED` | `REAL_LIVE_EMPTY_DATA` | 真实外网 HTTP 200,返回 JSON 结构符合契约,数据量为 0 (`ROOM=0`) | `LIVE_API_BUT_NO_REAL_RESOURCE_DATA` | +| **06** | `POST /rest/place/room/get` | `DmsPlaceClient` | `getRoom` | `N/A` | `PARTIAL` | `NOT_YET_TESTED` | 部分实现,待真实环境具备房间资源后完整测试 | `NOT_APPLICABLE` | +| **07** | `POST /rest/gateway/list` | `N/A` | `N/A` | `N/A` | `INTENTIONALLY_OUT_OF_SCOPE` | `NOT_YET_TESTED` | 网关级运维接口,由厂商后台维护,非学员住宿业务范围 | `PROHIBITED_FROM_DEMO` | +| **08** | `POST /rest/gateway/refresh-online-status` | `N/A` | `N/A` | `N/A` | `INTENTIONALLY_OUT_OF_SCOPE` | `NOT_YET_TESTED` | 网关级运维接口,非学员培训管理范围 | `PROHIBITED_FROM_DEMO` | +| **09** | `POST /rest/gateway/query-online-status` | `N/A` | `N/A` | `N/A` | `INTENTIONALLY_OUT_OF_SCOPE` | `NOT_YET_TESTED` | 网关级运维接口,非学员培训管理范围 | `PROHIBITED_FROM_DEMO` | +| **10** | `POST /rest/doorlock/list` | `DmsDoorLockClient` | `listDoorLocks` | `N/A` (集成探测) | `IMPLEMENTED` | `REAL_LIVE_EMPTY_DATA` | 真实外网 HTTP 200,返回 JSON 结构符合契约,挂载门锁数为 0 (`LOCK=0`) | `LIVE_API_BUT_NO_REAL_RESOURCE_DATA` | +| **11** | `POST /rest/doorlock/query-lock-battery` | `N/A` | `N/A` | `N/A` | `NOT_IMPLEMENTED` | `NOT_YET_TESTED` | 批量电池与信号查询,本期暂未接入 | `NOT_APPLICABLE` | +| **12** | `POST /rest/doorlock/remote-unlock` | `N/A` | `N/A` | `N/A` | `INTENTIONALLY_OUT_OF_SCOPE` | `SECURITY_PROHIBITED` | 系统安全红线绝对禁止远程开锁,未配置客户端亦严禁调用 | `PROHIBITED_FROM_DEMO` | +| **13** | `POST /rest/doorlock/query-operation-status` | `DmsOperationStatusClient` | `queryStatus` | `GET /train/access/operations/{doorAuthId}` | `IMPLEMENTED` | `MOCK_ONLY` | 本地 MockServer 状态机测试通过;真实外网因无真实 operationId 待硬件划拨 | `MOCK_SIMULATION_REQUIRED` | +| **14** | `POST /rest/doorlock/online-password-key/create` | `DmsPasswordClient` | `createOnlinePassword` | `POST /train/access/auth/{authId}/issue` | `IMPLEMENTED` | `MOCK_ONLY` | Mock 测试通过,返回模拟 operationId;真实环境因无测试硬件阻断写操作调用 | `MOCK_SIMULATION_REQUIRED` | +| **15** | `POST /rest/doorlock/online-password/delete` | `DmsPasswordClient` | `deleteOnlinePassword` | `POST /train/access/auth/{authId}/revoke` | `IMPLEMENTED` | `MOCK_ONLY` | Mock 测试通过;真实环境未对未知设备发起真实撤销调用 | `MOCK_SIMULATION_REQUIRED` | +| **16** | `POST /rest/doorlock/offline-password/create` | `N/A` | `N/A` | `N/A` | `NOT_IMPLEMENTED` | `NOT_YET_TESTED` | 离线密码算法申请,本期网络门锁采用在线密码策略 | `NOT_APPLICABLE` | +| **17** | `POST /rest/doorlock/offline-password-key/create`| `N/A` | `N/A` | `N/A` | `NOT_IMPLEMENTED` | `NOT_YET_TESTED` | 离线密码钥匙生成,本期暂未接入 | `NOT_APPLICABLE` | +| **18** | `POST /rest/doorlock/online-card/create` | `N/A` | `N/A` | `N/A` | `NOT_IMPLEMENTED` | `NOT_YET_TESTED` | 在线卡片下发,本期优先下发在线时效密码 | `NOT_APPLICABLE` | +| **19** | `POST /rest/doorlock/online-card/delete` | `N/A` | `N/A` | `N/A` | `NOT_IMPLEMENTED` | `NOT_YET_TESTED` | 在线卡片删除,本期暂未接入 | `NOT_APPLICABLE` | +| **20** | `POST /rest/doorlock/qrcode/create` | `N/A` | `N/A` | `N/A` | `NOT_IMPLEMENTED` | `NOT_YET_TESTED` | 二维码/手机钥匙生成,本期暂未接入 | `NOT_APPLICABLE` | +| **21** | `POST /rest/qrcode/delete` | `N/A` | `N/A` | `N/A` | `NOT_IMPLEMENTED` | `NOT_YET_TESTED` | 二维码/手机钥匙注销,本期暂未接入 | `NOT_APPLICABLE` | +| **22** | `POST /rest/doorlock/offline-card/create` | `N/A` | `N/A` | `N/A` | `INTENTIONALLY_OUT_OF_SCOPE` | `NOT_YET_TESTED` | 需现场物理读卡器DLL发卡,非本期网络远程开锁范围 | `PROHIBITED_FROM_DEMO` | +| **23** | `POST /rest/lock/unlock-record/list` | `N/A` | `N/A` | `N/A` | `NOT_IMPLEMENTED` | `NOT_YET_TESTED` | 开门流水记录拉取,本期暂未集成 | `NOT_APPLICABLE` | +| **24** | `POST /rest/powerswitch/list` | `N/A` | `N/A` | `N/A` | `INTENTIONALLY_OUT_OF_SCOPE` | `NOT_YET_TESTED` | 取电开关硬件列表,非学员培训业务范围 | `PROHIBITED_FROM_DEMO` | +| **25** | `POST /rest/powerswitch/remote-poweron` | `N/A` | `N/A` | `N/A` | `INTENTIONALLY_OUT_OF_SCOPE` | `NOT_YET_TESTED` | 远程送电强电控制,非学员培训管理范围 | `PROHIBITED_FROM_DEMO` | +| **26** | `POST /rest/powerswitch/remote-poweroff` | `N/A` | `N/A` | `N/A` | `INTENTIONALLY_OUT_OF_SCOPE` | `NOT_YET_TESTED` | 远程断电强电控制,非学员培训管理范围 | `PROHIBITED_FROM_DEMO` | +| **27** | `POST /rest/powerswitch/query-operation-status` | `N/A` | `N/A` | `N/A` | `INTENTIONALLY_OUT_OF_SCOPE` | `NOT_YET_TESTED` | 取电开关操作状态轮询,非学员培训管理范围 | `PROHIBITED_FROM_DEMO` | + +--- + +## 4. 统计汇总与客观边界说明 + +### 4.1 甲方接口实现与范围分布 +- **`CLIENT_PROVIDED_API_COUNT`**:**27 个** +- **`DMS_VENDOR_API_COUNT`**:**27 个** +- **`RAILWAYSYSTEM_IMPLEMENTED_CLIENT_API_COUNT`**:**8 个**(Token, Building, Floor, Room, Lock, Password create, Password delete, Query op status) +- **`RAILWAYSYSTEM_PARTIAL_CLIENT_API_COUNT`**:**1 个**(Room get) +- **`RAILWAYSYSTEM_NOT_IMPLEMENTED_CLIENT_API_COUNT`**:**9 个**(Logout, Lock battery, Offline pwd x2, Online card x2, QR x2, Unlock record) +- **`RAILWAYSYSTEM_OUT_OF_SCOPE_CLIENT_API_COUNT`**:**9 个**(Gateway x3, Remote unlock x1, Offline card x1, Powerswitch x4) +- **`CLIENT_CONTRACT_MISMATCH_COUNT`**:**0 个** + +### 4.2 真实运行验证状态分布 (`REAL_TEST_STATUS`) +- **`REAL_LIVE_WITH_DATA_COUNT`**:**0 个**(厂商测试环境无真实业务数据) +- **`REAL_LIVE_EMPTY_DATA_COUNT`**:**5 个**(Token, Building, Floor, Room, Lock) +- **`MOCK_ONLY_COUNT`**:**3 个**(在线密码下发、撤销、异步操作状态轮询) +- **`SECURITY_PROHIBITED_COUNT`**:**1 个**(远程开锁) +- **`NOT_YET_TESTED_COUNT`**:**18 个** diff --git a/docs/current/05A-CLIENT-PROVIDED-API-CATALOG.md b/docs/current/05A-CLIENT-PROVIDED-API-CATALOG.md new file mode 100644 index 000000000..7f8415272 --- /dev/null +++ b/docs/current/05A-CLIENT-PROVIDED-API-CATALOG.md @@ -0,0 +1,74 @@ +# 05A - 甲方提供外部接口总账 (Client-Provided API Catalog) + +> **契约来源定义 (Task A & Task E)**: +> 1. 本文档为**甲方(沈阳房建公寓段)向本项目提供的完整原始接口契约总账**; +> 2. 严格区分契约来源与实际服务提供方: +> - **`CONTRACT_SOURCE = CLIENT_PROVIDED`**(甲方正式提供交付的原始技术契约); +> - **`SERVICE_PROVIDER = DMS_VENDOR`**(由第三方门锁/物联网平台厂商运营托管); +> 3. 任何敏感口令、密钥、Token 及手机号示例均已脱敏处理为 ``。 + +--- + +## 1. 契约统计概览 (Catalog Summary) + +- **原始接口声明总数 (`RAW_ENDPOINT_DECLARATION_COUNT`)**:**30 处** +- **去重后唯一接口总数 (`UNIQUE_CLIENT_PROVIDED_API_COUNT`)**:**27 个**(以 `METHOD + PATH` 为联合主键) +- **文档重复引用次数 (`DUPLICATE_REFERENCE_COUNT`)**:**3 次** + - 说明:`POST /rest/doorlock/query-operation-status`(查询操作结果)在甲方原始文档中分别于“门锁管理”、“下发在线密码”、“删除在线密码”、“下发/删除在线卡片” 4 个业务章节重复声明引用; +- **托管服务提供商 (`DMS_VENDOR_API_COUNT`)**:**27 个**(100% 由 DMS 物联网平台厂商承载运营)。 + +--- + +## 2. 甲方提供接口全量清单 (`CLIENT_PROVIDED_API`) + +| 序号 (API_ID) | 业务分类 (CATEGORY) | 接口名称 (NAME) | 请求方式 (METHOD) | 契约路径 (PATH) | 契约来源 (CONTRACT_SOURCE) | 服务提供商 (SERVICE_PROVIDER) | 读写属性 (READ_OR_MUTATION) | 请求参数要素 (DOCUMENTED_REQUEST) | 响应关键字段 (DOCUMENTED_RESPONSE) | +| :---: | :--- | :--- | :---: | :--- | :---: | :---: | :---: | :--- | :--- | +| **API-01** | 登录鉴权 | 平台登录 | `POST` | `/public/rest/third-party-app/token/get` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `READ` | `{"appid": "", "appsecret": ""}` | `success, token, expiresIn, message` | +| **API-02** | 登录鉴权 | 退出登录 | `POST` | `/public/rest/security/logout` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `MUTATION` | `{}` (Token置于Cookie/URL) | `success` | +| **API-03** | 区域管理 | 获取楼栋列表 | `POST` | `/rest/place/building/list` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `READ` | `{"building": "", "offset": 0, "limit": 100}` | `success, rows: [{id, name, parentId, building, type, ...}], total` | +| **API-04** | 区域管理 | 获取楼层列表 | `POST` | `/rest/place/floor/list` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `READ` | `{"building": "", "floor": "", "offset": 0, "limit": 100}` | `success, rows: [{id, name, parentId, building, floor, ...}], total` | +| **API-05** | 区域管理 | 获取房间列表 | `POST` | `/rest/place/room/list` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `READ` | `{"building": "", "floor": "", "room": "", "offset": 0, "limit": 100}` | `success, rows: [{id, name, parentId, building, floor, room, ...}], total` | +| **API-06** | 区域管理 | 获取房间id | `POST` | `/rest/place/room/get` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `READ` | `{"building": "", "floor": "", "room": ""}` | `success, data: {id, projectId, building, floor, room}` | +| **API-07** | 网关管理 | 获取网关列表 | `POST` | `/rest/gateway/list` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `READ` | `{"offset": 0, "limit": 100}` | `success, rows: [{id, projectId, hardwareId, ...}], total` | +| **API-08** | 网关管理 | 刷新网关状态 | `POST` | `/rest/gateway/refresh-online-status` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `MUTATION` | `{"id": , "hardwareId": ""}` | `success, data: {operationId, requestType, timeoutSeconds, ...}` | +| **API-09** | 网关管理 | 查询网关状态 | `POST` | `/rest/gateway/query-online-status` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `READ` | `{"operationId": "", "hardwareId": ""}` | `success, data: {operationStatus, operationId, hardwareId, ...}` | +| **API-10** | 门锁管理 | 获取门锁列表 | `POST` | `/rest/doorlock/list` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `READ` | `{"placeId": , "offset": 0, "limit": 100}` | `success, rows: [{id, hardwareId, building, floor, battery, signal, ...}], total` | +| **API-11** | 门锁管理 | 查询门锁电池和信号状态 | `POST` | `/rest/doorlock/query-lock-battery` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `READ` | `{"roomIds": []}` | `success, data: {"": [{id, roomId, battery, signal, ...}]}` | +| **API-12** | 门锁管理 | 远程开锁 | `POST` | `/rest/doorlock/remote-unlock` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `MUTATION` | `{"lockId": , "hardwareId": "", "canOpenAntilock": true}` | `success, data: {operation: {operationId, requestType: 5, ...}}` | +| **API-13** | 门锁管理 | 查询操作结果 | `POST` | `/rest/doorlock/query-operation-status` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `READ` | `{"requestType": , "operationId": "", "hardwareId": ""}` | `success, data: {operationStatus, requestType, operationId, ...}` | +| **API-14** | 钥匙管理 | 下发在线密码 | `POST` | `/rest/doorlock/online-password-key/create` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `MUTATION` | `{"lockId": , "validStart": , "validUntil": , "password": "", "subType": 4, ...}` | `success, data: {id, lockId, operationId, typeStr: "Online Password", ...}` | +| **API-15** | 钥匙管理 | 删除在线密码 | `POST` | `/rest/doorlock/online-password/delete` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `MUTATION` | `{"id": }` | `success, data: {id, lockId, operationId, ...}` | +| **API-16** | 钥匙管理 | 申请离线密码 | `POST` | `/rest/doorlock/offline-password/create` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `MUTATION` | `{"lockId": , "validStart": , "validUntil": , "subType": 4}` | `success, data: {"password": ""}` | +| **API-17** | 钥匙管理 | 生成离线密码钥匙 | `POST` | `/rest/doorlock/offline-password-key/create` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `MUTATION` | `{"lockId": , "holder": "", "validStart": , "validUntil": , "password": ""}` | `success, data: {id, lockId, typeStr: "Offline Password", ...}` | +| **API-18** | 钥匙管理 | 下发在线卡片 | `POST` | `/rest/doorlock/online-card/create` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `MUTATION` | `{"lockId": , "validStart": , "validUntil": , "cardNumber": "", "subType": 4, ...}` | `success, data: {id, lockId, operationId, typeStr: "Online Card", ...}` | +| **API-19** | 钥匙管理 | 删除在线卡片 | `POST` | `/rest/doorlock/online-card/delete` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `MUTATION` | `{"id": }` | `success, data: {id, lockId, operationId, typeStr: "Online Card", ...}` | +| **API-20** | 钥匙管理 | 生成二维码/手机钥匙 | `POST` | `/rest/doorlock/qrcode/create` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `MUTATION` | `{"lockId": , "validStart": , "validUntil": , "phoneCountry": "+86", "phoneNumber": ""}` | `success, data: {id, lockId, cardNumber, ...}` | +| **API-21** | 钥匙管理 | 注销二维码/手机钥匙 | `POST` | `/rest/qrcode/delete` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `MUTATION` | `{"id": }` | `success` | +| **API-22** | 钥匙管理 | 生成离线卡片钥匙 | `POST` | `/rest/doorlock/offline-card/create` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `MUTATION` | `{"lockId": , "validStart": , "validUntil": , "cardNumber": "", "offlineCardType": 2}` | `success, data: {id, lockId, typeStr: "Offline Card", ...}` | +| **API-23** | 开门记录 | 获取开门记录列表 | `POST` | `/rest/lock/unlock-record/list` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `READ` | `{"room": "", "offset": 0, "limit": 10, "typeList": [6]}` | `success, rows: [{id, lockId, password, userName, typeStr, ...}], total` | +| **API-24** | 取电开关 | 获取取电开关列表 | `POST` | `/rest/powerswitch/list` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `READ` | `{"offset": 0, "limit": 20}` | `success, rows: [{id, projectId, hardwareId, ...}], total` | +| **API-25** | 取电开关 | 取电开关远程送电 | `POST` | `/rest/powerswitch/remote-poweron` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `MUTATION` | `{"id": , "hardwareId": ""}` | `success, data: {operation: {operationId, requestType: 1, ...}}` | +| **API-26** | 取电开关 | 取电开关远程断电 | `POST` | `/rest/powerswitch/remote-poweroff` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `MUTATION` | `{"id": , "hardwareId": ""}` | `success, data: {operation: {operationId, requestType: 2, ...}}` | +| **API-27** | 取电开关 | 查询断送电结果 | `POST` | `/rest/powerswitch/query-operation-status` | `CLIENT_PROVIDED` | `DMS_VENDOR` | `READ` | `{"requestType": , "operationId": "", "hardwareId": ""}` | `success, data: {operationStatus, resultDetails: {powerStatus, powerType}}` | + +--- + +## 3. 文档重复声明关系映射 (Duplicate Reference Mapping) + +在甲方原始文档中,`POST /rest/doorlock/query-operation-status` 在不同章节中重复出现 3 次,其语义与调用契约如下: + +| 重复声明序号 | 所在原始文档章节 | 声明接口名称 | 契约路径 | 对应统一主条目 | 去重后处理策略 | +| :---: | :--- | :--- | :--- | :--- | :--- | +| **Dup-01** | 钥匙管理接口 - 在线密码 | 查询下发在线密码结果 | `POST /rest/doorlock/query-operation-status` | `API-13` (查询操作结果) | 契约路径完全一致,参数 `requestType=1`,已作为子用例归入 API-13 | +| **Dup-02** | 钥匙管理接口 - 在线密码 | 查询删除在线密码结果 | `POST /rest/doorlock/query-operation-status` | `API-13` (查询操作结果) | 契约路径完全一致,参数 `requestType=1`,已作为子用例归入 API-13 | +| **Dup-03** | 钥匙管理接口 - 在线卡片 | 查询下发或删除在线卡片结果 | `POST /rest/doorlock/query-operation-status` | `API-13` (查询操作结果) | 契约路径完全一致,参数 `requestType=1`,已作为子用例归入 API-13 | + +--- + +## 4. 敏感凭据保护审计 (Security & Redaction Compliance) + +- **APPID / SECRET**:甲方原始文档包含的凭据已全部替换为 ``; +- **TOKEN**:示例 Token 已全部替换为 ``; +- **手机号与联系方式**:示例手机号已全部替换为 ``; +- **明文测试密码**:文档示例中的密码已全部替换为 ``; +- **结论**:本文件 100% 符合脱敏规范,无任何敏感信息泄漏。 diff --git a/docs/current/CLEAN_DEMO_DATABASE_SPEC.md b/docs/current/CLEAN_DEMO_DATABASE_SPEC.md index ba00eedc7..10f46ec90 100644 --- a/docs/current/CLEAN_DEMO_DATABASE_SPEC.md +++ b/docs/current/CLEAN_DEMO_DATABASE_SPEC.md @@ -64,7 +64,7 @@ | 表分类 | 预期表数量 | 表名清单摘要 | | :--- | :---: | :--- | -| **培训业务核心表 (`train_*`)** | **21 张** | `train_teacher`, `train_student`, `train_course`, `train_classroom_info`, `train_training_site`, `train_plan`, `train_plan_course`, `train_enrollment`, `train_lesson`, `train_student_checkin`, `train_class_report`, `train_dormitory_info`, `train_accommodation`, `train_score_info`, `train_study_duration`, `train_resource`, `train_course_resource`, `train_electronic_board`, `train_external_resource_mapping`, `train_dorm_auth`, `train_external_operation` | +| **培训业务核心表 (`train_*`)** | **21 张核心 + 2 张扩展** | 核心 21 表: `train_teacher`, `train_student`, `train_course`, `train_resource`, `train_course_resource`, `train_classroom_info`, `train_training_site`, `train_electronic_board`, `train_dormitory_info`, `train_class_plan`, `train_plan_course`, `train_enrollment`, `train_lesson`, `train_accommodation`, `train_dorm_auth`, `train_class_report`, `train_student_checkin`, `train_score_item`, `train_student_score`, `train_study_duration`, `train_student_portrait`;扩展 2 表: `train_external_resource_mapping`, `train_external_operation` | | **若依系统底座表 (`sys_*`)** | **15 张** | `sys_user`, `sys_dept`, `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_*`)** | **2 张** | `gen_table`, `gen_table_column` | | **Quartz 调度表 (`qrtz_*`)** | **11 张** | `qrtz_job_details`, `qrtz_triggers`, `qrtz_simple_triggers`, `qrtz_cron_triggers`, `qrtz_simprop_triggers`, `qrtz_blob_triggers`, `qrtz_calendars`, `qrtz_paused_trigger_grps`, `qrtz_fired_triggers`, `qrtz_scheduler_state`, `qrtz_locks` |