Skip to content

Mode Alignment Audit

MooreFoss edited this page May 7, 2026 · 1 revision

模式对齐审查记录

本文档用于记录 todo.md 各阶段的可核查证据,避免只凭记忆或测试代理信号标记任务完成。

阶段 0 基线(2026-05-07)

Git 基线

命令 结果
git status -sb ## dev...origin/dev [ahead 3]
git status --porcelain 无输出,工作区无未提交改动
git fetch origin 成功,无输出
git rev-list --left-right --count origin/dev...HEAD 0 3
git rev-list --left-right --count origin/main...dev 0 21

git log --oneline --decorate --max-count=20 --all

c3ee6e1 (HEAD -> dev) 优化成绩加载速度
f8d8ceb 修复希冀作业加载逻辑
8a4f2c0 优化界面体验
f60f6b2 (origin/dev) 优化成绩界面
9ea29e2 将希冀作业添加进首页代办区
f40fc5d chore: auto-format Kotlin code
876abbe refactor shared api package layout
f073f2f 优化希冀作业拉取与详情展示
33100dc Merge branch 'main' into dev
cafcff2 调整希冀作业拉取策略
90276d7 fix(cgyy): fall back when purpose types fail
8151a15 perf(judge): enrich assignments without blocking UI
7bd6253 perf(judge): parallelize local assignment queries
d4de6f4 perf(judge): parallelize relay assignment queries
fc14ab0 feat(auth): expose connection mode on login
e69386d chore: ignore local Serena workspace
f10b647 chore: auto-format Kotlin code
4234c33 Add Judge assignments integration
f008579 Replace grade query with BUAA score source
8c9ce7f fix: address grade feature review feedback

已阅读文档

  • docs/Architecture-Overview.md
  • docs/Module-Shared.md
  • docs/Module-Server.md
  • docs/Module-ComposeApp.md
  • docs/API-Contracts.md
  • docs/Testing-and-Quality.md
  • docs/Development-Workflow.md

模块清单

模块 shared/API 入口 server 入口 composeApp 入口
首页 聚合调用各 feature API 依赖各业务路由 HomeScreen.kt, HomeTodo.kt, HomeBootstrapCoordinator.kt
认证/连接模式 AuthApi.kt, ConnectionRuntime.kt, ApiFactory.kt AuthRoutes.kt, AuthService.kt, JwtAuth.kt, SessionManager.kt App.kt, AuthViewModel.kt, LoginScreen.kt, ConnectionModeSelectionScreen.kt
课表 ScheduleApi.kt, LocalScheduleApi.kt ScheduleRoutes.kt, ScheduleService.kt ScheduleViewModel.kt, ScheduleScreen.kt, CourseDetailScreen.kt
考试 ScheduleApi.kt 中考试相关 DTO/调用 ExamRoutes.kt, ExamService.kt ExamViewModel.kt, ExamScreen.kt
成绩 GradeApi.kt, LocalGradeApi.kt GradeRoutes.kt, GradeService.kt GradeViewModel.kt, GradeScreen.kt
空教室 ClassroomApi.kt, LocalClassroomApi.kt ClassroomRoutes.kt, ClassroomClient.kt ClassroomViewModel.kt, ClassroomQueryScreen.kt
BYKC BykcApi.kt, LocalBykcApi.kt, BykcCourseFilterStore.kt BykcRoutes.kt, BykcService.kt, BykcClient.kt BykcViewModel.kt, BykcHomeScreen.kt, BykcCoursesScreen.kt, BykcCourseDetailScreen.kt, BykcChosenCoursesScreen.kt, BykcStatisticsScreen.kt
课堂签到 SigninApi.kt, LocalSigninApi.kt SigninRoutes.kt, SigninService.kt, SigninClient.kt SigninViewModel.kt, SigninScreen.kt
CGYY CgyyApi.kt, LocalCgyyApi.kt, CgyyReservationFormStore.kt CgyyRoutes.kt, CgyyService.kt, CgyyZhjsClient.kt CgyyViewModel.kt, CgyyHomeScreen.kt, CgyyReservePickerScreen.kt, CgyyReserveFormScreen.kt, CgyyOrdersScreen.kt, CgyyLockCodeScreen.kt
SPOC SpocApi.kt, LocalSpocApi.kt, LocalSpocSupport.kt SpocRoutes.kt, SpocService.kt, SpocClient.kt SpocViewModel.kt, SpocAssignmentsScreen.kt, SpocAssignmentDetailScreen.kt
Judge/希冀 JudgeApi.kt, LocalJudgeApi.kt JudgeRoutes.kt, JudgeService.kt, JudgeClient.kt JudgeViewModel.kt, JudgeAssignmentsScreen.kt, JudgeAssignmentDetailScreen.kt
评教 EvaluationService.kt, LocalEvaluationService.kt EvaluationRoutes.kt, EvaluationService.kt, EvaluationClient.kt EvaluationViewModel.kt, EvaluationScreen.kt
YGDK YgdkApi.kt, LocalYgdkApi.kt YgdkRoutes.kt, YgdkService.kt, YgdkClient.kt YgdkViewModel.kt, YgdkHomeScreen.kt, YgdkClockinFormScreen.kt
设置/关于/个人 UserServiceBackend, CredentialStore.kt, UpdateService.kt UserRoutes.kt, UserService.kt, AppVersionRoutes.kt SettingsScreen.kt, OtherScreens.kt, UserInfoScreen.kt, Sidebar.kt
更新检查 UpdateService.kt, NetworkUtils.kt AppVersionRoutes.kt, AppVersionService.kt App.kt 更新弹窗与入口状态机

阶段 0 结论

  • 当前执行分支是 dev,本地有 3 个未推送提交,dev 相对 origin/main 有 21 个提交。
  • 工作区在阶段 0 开始时无未提交改动。
  • 指定文档已按当前代码阅读,模块清单覆盖 todo.md 要求的全部模块。

阶段 1 模式对齐审查(2026-05-07)

平台与分发边界

  • Web/Wasm 平台只暴露 SERVER_RELAYshared/src/wasmJsMain/kotlin/cn/edu/ubaa/Platform.wasmJs.ktshared/src/jsMain/kotlin/cn/edu/ubaa/Platform.js.kt 返回 supportsLocalConnectionModes() = false
  • Android、iOS、JVM 支持 DIRECTWEBVPNSERVER_RELAY:对应平台 supportsLocalConnectionModes() = true
  • DefaultApiFactoryDIRECTWEBVPN 统一分发到 Local* backend,对 SERVER_RELAY 分发到 Relay* backend;本地 WebVPN 通过 localUpstreamUrl() 将上游 URL 包装为 d.buaa.edu.cn
  • ConnectionRuntime.switchMode() 会调用 resetSession(),清理 token、clientId、本地会话、本地 Cookie、共享 HttpClient、Judge 缓存、学期缓存,并关闭自动登录。

对齐表

模块 SERVER_RELAY 行为 DIRECT 行为 WEBVPN 行为 客户端 UI 期望 差异/风险 是否需要修复
首页 聚合各 ViewModel 的 relay 结果 聚合各 ViewModel 的 local 结果 同 direct,本地 URL 经 WebVPN 包装 首页待办不关心模式,只消费各模块状态 Judge 摘要初始为 UNKNOWN 时必须仍可进入待办/列表 已修复 Judge 默认过滤
认证/连接模式 RelayAuthServiceBackend/api/v1/auth/*,使用 token 与 clientId LocalAuthServiceBackend 走 SSO/UC,本地 Cookie 和本地会话 同 direct,SSO/UC URL 走 WebVPN 包装 切换模式后重新 preload,不复用旧登录态 shared 少了服务端 auth_lock_timeout 提示映射 已修复并补 NetworkUtilsTest
课表 /api/v1/schedule/* LocalScheduleApiBackend 调 BYXT app 接口 同 direct,经 localUpstreamUrl() term/week/today/exam DTO 一致 未发现模式特有 UI 假设
考试 ScheduleApi.getExamArrangement()/api/v1/exam/list LocalScheduleApiBackend.getExamArrangement() 调 BYXT 同 direct ExamViewModel 只消费 ExamArrangementData API 入口在 ScheduleApi,server route 独立为 exam
成绩 /api/v1/grade/list,异常统一为 grade_error LocalGradeApiBackend 使用 BUAA score 页面,也映射 grade_error 同 direct GradeViewModel 只消费 GradeData 和统一错误 grade_error 当前 server/shared 已一致
空教室 /api/v1/classroom/query LocalClassroomApiBackend 走 app.buaa.edu.cn 同 direct 查询参数 xqid/date 和 DTO 一致 未发现差异
BYKC /api/v1/bykc/*,选择/退选/签到走 server LocalBykcApiBackend 直连 BYKC 接口 同 direct 分页、详情、已选、统计、报名状态一致 有副作用操作需浏览器阶段只读或谨慎验证
课堂签到 /api/v1/signin/today/api/v1/signin/do LocalSigninApiBackend 直连 iClass 同 direct 今日课程和签到响应 DTO 一致 签到是副作用操作,阶段 2 需只读或确认风险
CGYY CgyyService.getPurposeTypes() 请求失败或解析为空时返回静态类型 LocalCgyyApiBackend.getPurposeTypes() 同样 fallback 静态类型 同 direct 预约类型下拉必须有可选项 已知 direct fallback 风险已对齐 否,已由现有测试覆盖
SPOC /api/v1/spoc/assignments 和详情 LocalSpocApiBackend 直连 SPOC 同 direct 列表/详情分离,待办消费摘要 未发现模式对齐差异
Judge/希冀 /api/v1/judge/assignments 现在只返回 raw summary,详情走单个或批量详情接口 LocalJudgeApiBackend.getAssignments() 同样只返回 raw summary 同 direct,Judge URL 和 Cookie 适配 WebVPN 列表先显示轻量摘要,后台补详情;默认未完成过滤不能隐藏 UNKNOWN 初始列表不再产生 historicalCutoffCourseIds,旧的课程跳过优化不会在列表阶段更新;过期隐藏依赖后台详情补齐 已修复,风险记录待后续浏览器验证
评教 /api/v1/evaluation/list/submit LocalEvaluationServiceBackend 直连评教系统 同 direct 列表与提交结果 DTO 一致 提交有副作用,阶段 2 需谨慎
YGDK /api/v1/ygdk/* LocalYgdkApiBackend 直连阳光打卡 同 direct 概览、记录、提交 DTO 一致 打卡提交有副作用,阶段 2 需只读或确认风险
设置/关于/个人 /api/v1/user/info,设置页只切换模式 LocalUserServiceBackend 读取 UC 用户信息 同 direct 切换模式必须清空旧会话但保留记住的账号密码 现有 ConnectionRuntimeTest 覆盖 token/clientId/session/autologin;代码检查覆盖 Judge/term/cache 清理
更新检查 匿名 /api/v1/app/version 仍使用 server relay 版本接口 同 direct App 启动时可显示更新弹窗 与连接模式无业务耦合

已修复问题

  1. shared 端补齐 auth_lock_timeout 用户提示映射,与 server/src/main/kotlin/cn/edu/ubaa/auth/api/UserFacingErrors.kt 对齐。
  2. server relay Judge 列表去掉同步详情加载,JudgeService.getAssignments() 只用 JudgeAssignmentRaw.toSummary() 返回轻量摘要。
  3. direct/WebVPN Judge 列表同样去掉同步详情加载,LocalJudgeApiBackend.getAssignments() 只返回轻量摘要。
  4. Judge UI 默认未完成过滤将 UNKNOWN 视为未完成,避免轻量摘要在详情补齐前被隐藏。

当前验证证据

命令 结果
.\gradlew.bat :server:test --tests "cn.edu.ubaa.judge.JudgeServiceTest" 通过
.\gradlew.bat :shared:jvmTest --tests "cn.edu.ubaa.api.LocalJudgeApiBackendTest" 通过
.\gradlew.bat :composeApp:jvmTest --tests "cn.edu.ubaa.ui.JudgeViewModelTest" 通过
.\gradlew.bat :shared:jvmTest --tests "cn.edu.ubaa.api.NetworkUtilsTest" --tests "cn.edu.ubaa.api.ConnectionRuntimeTest" --tests "cn.edu.ubaa.api.ApiFactoryDispatchTest" --tests "cn.edu.ubaa.api.LocalCgyyApiBackendTest" --tests "cn.edu.ubaa.api.LocalJudgeApiBackendTest" 通过

阶段 1 结论

  • SERVER_RELAYDIRECT/WEBVPN 的分发边界清晰,Web/Wasm 平台只进入 SERVER_RELAY
  • 已知 CGYY fallback 已在 direct 与 server relay 对齐。
  • 已知 Judge 初始列表性能问题已在 server relay 与 direct/WebVPN 同步修复为轻量摘要优先。
  • 仍需在阶段 2 用真实 Wasm 页面确认 Judge 轻量摘要、详情后台补齐和首页待办的组合行为。

阶段 2 本地浏览器验证(进行中,2026-05-07)

环境与入口

项目 结果
GET http://127.0.0.1:5432/health/live 200 OKstatus=up
GET http://127.0.0.1:5432/health/ready 200 OKstatus=ready,Redis up
GET http://localhost:8080/ 200 OK,Wasm 页面标题为 UBAA
Playwright 会话 ubaa-phase2,已登录后执行真实浏览器覆盖
主要日志 output/phase2/server-memurai.log.playwright-cli/console-2026-05-06T18-51-34-903Z.log

说明:Compose/Wasm 控件在多处不能用普通 DOM selector 命中,实际覆盖使用 Playwright 坐标点击、快照和截图确认。登录凭据只从 local.properties 读取用于本地登录,不写入文档。

浏览器覆盖矩阵

模块 操作 期望 实际 证据 状态
首页 刷新已登录页面,等待待办后台加载 今日课表、研讨室、SPOC、Judge 待办可见 先出现后台加载中,随后出现近期待办,Judge 待办显示截止时间 output/phase2/current-home-refresh.png;日志中 /api/v1/schedule/today/api/v1/spoc/assignments/api/v1/judge/assignments 通过
认证/连接模式 已登录状态刷新、进入设置 session 状态可恢复,Web/Wasm 仅显示服务器中转模式 /api/v1/auth/status 返回 200,设置页显示当前模式为服务器中转模式 output/phase2/current-settings.png 通过
课表 进入课表、点击下一周、返回 周视图可加载并支持周切换 第 10 周课程网格加载;下一周请求成功后可返回 output/phase2/current-schedule.png;日志中 /api/v1/schedule/week 通过
考试 进入考试查询、打开学期菜单 空数据态可见,学期下拉可打开 显示暂无考试安排;学期菜单列出多个学期 output/phase2/current-exam.pngoutput/phase2/current-exam-term-menu.png 部分通过:菜单关闭/选择在 Playwright 坐标下不稳定
成绩 进入成绩查询、点击学期切换并返回 成绩概览和课程列表可加载 显示 GPA、加权平均分、本学期课程列表,学期切换后可返回 output/phase2/current-grade.png;日志中多次 /api/v1/grade/list 通过
BYKC 进入博雅课程、打开我的课程 只读查看已选课程,不触发签到/退选 已选课程列表加载,未点击自主签到等副作用按钮 output/phase2/current-bykc.pngoutput/phase2/current-bykc-my.png 通过
空教室 进入空教室查询 校区、日期、楼栋、空闲矩阵可见 学院路三号楼空闲教室矩阵加载 output/phase2/current-classroom-2.png;日志中 /api/v1/classroom/query 通过
SPOC 进入列表、打开作业详情 列表和详情分离,返回导航可用 列表显示课程分组、提交状态、截止时间;详情显示提交信息和作业内容 output/phase2/current-spoc.pngoutput/phase2/current-spoc-detail.png 通过
Judge/希冀 进入列表、打开作业详情 轻量摘要先显示,后台详情补齐后仍可进入详情 首页待办和列表均显示未提交 Judge 作业;详情页显示题目明细、进度和截止时间 output/phase2/current-judge.pngoutput/phase2/current-judge-detail.png;日志中 /api/v1/judge/assignments 先返回,随后详情批量/单项请求 通过,记录到 504 降级风险
课堂签到 进入课程签到 今日课程或空数据态可见,不触发签到 当前账号显示今日无课程安排,刷新按钮可见,未执行签到 output/phase2/current-signin.png 通过
CGYY/研讨室 进入预约、选择空闲时段、进入表单但不提交 站点、日期、房间时段和预约类型可用 预约矩阵加载;进入表单后可见预约类型按钮和提交按钮,未点击提交 output/phase2/current-cgyy-picker.pngoutput/phase2/current-cgyy-form.png;日志中 /api/v1/cgyy/purpose-types 通过
YGDK 进入阳光打卡 概览和记录可只读查看,不新增打卡 显示本学期认定次数、本周打卡和历史记录,未点击新增打卡 output/phase2/current-ygdk.png 通过
评教 进入自动评教 列表或空数据态可见,不提交评教 显示暂无评教课程和重试按钮,未提交 output/phase2/current-evaluation.png 通过
设置/关于/个人 侧边栏进入设置、关于、我的 设置、关于、个人信息页可打开并返回 设置显示连接模式;关于显示版本和项目入口;我的显示已脱敏个人字段 output/phase2/current-menu.pngoutput/phase2/current-settings.pngoutput/phase2/current-about.pngoutput/phase2/current-profile.png 通过
更新检查 页面加载和刷新 启动时调用版本接口,不阻塞登录状态恢复 /api/v1/app/version 返回 200,页面继续恢复 session .playwright-cli/console-2026-05-06T18-51-34-903Z.logoutput/phase2/server-memurai.log 通过

受控错误态补充

使用 Playwright route 对只读业务接口返回受控 503,再从真实 Wasm 页面进入对应模块。路由已在验证后清除,output/phase2/current-home-restored.png 确认首页恢复正常。

模块 Mock 路由 浏览器错误态 证据
首页 schedule/todaysignin/todayspoc/assignmentsjudge/assignmentsbykc/courses/chosencgyy/orders 今日课表失败卡片、待办区部分来源失败提示 output/phase2/current-home-error.png
课表 **/api/v1/schedule/** 加载失败: 服务暂时不可用,请稍后重试 output/phase2/current-schedule-error.png
考试 **/api/v1/exam/list** 加载失败: 服务暂时不可用,请稍后重试 output/phase2/current-exam-error.png
成绩 **/api/v1/grade/list** 加载失败: 服务暂时不可用,请稍后重试 output/phase2/current-grade-error.png
BYKC **/api/v1/bykc/** 我的课程页显示加载失败和重试 output/phase2/current-bykc-error.png
空教室 **/api/v1/classroom/query** 查询失败: 服务暂时不可用,请稍后重试 output/phase2/current-classroom-error.png
SPOC **/api/v1/spoc/** 列表页显示服务暂不可用和重试 output/phase2/current-spoc-error.png
Judge/希冀 **/api/v1/judge/** 列表页显示服务暂不可用和重试 output/phase2/current-judge-error.png
课堂签到 **/api/v1/signin/** 今日签到页显示服务暂不可用和刷新 output/phase2/current-signin-error.png
CGYY/研讨室 **/api/v1/cgyy/** 预约页显示服务暂不可用和重试 output/phase2/current-cgyy-error.png
YGDK **/api/v1/ygdk/** 首页显示服务暂不可用和重试,未执行新增打卡 output/phase2/current-ygdk-error.png
评教 **/api/v1/evaluation/** 自动评教页显示服务暂不可用和重试 output/phase2/current-evaluation-error.png
个人信息 **/api/v1/user/info** 修复后显示服务暂不可用和重试,不再停留在无限加载 output/phase2/current-profile-error.png

错误态覆盖期间发现 MyScreen/api/v1/user/info 失败后只显示无限加载。已新增 AuthViewModelInitializeAppTest.ensureUserInfoLoaded failure exposes profile error and clears loading,并在 AuthViewModel/MyScreen 中加入个人信息专用 loading/error 状态与重试入口。

待补覆盖

  • 考试学期菜单仍存在自动化交互阻塞:output/phase2/current-exam-term-selected.pngcurrent-exam-term-keyboard.png 显示菜单可打开,但 Playwright locator、坐标点击和键盘 Enter 均不能选择条目;locator 日志显示 canvas 拦截 popup 按钮事件。该问题需继续判断是自动化命中测试限制还是 Wasm 用户可见交互缺陷。
  • SPOC/Judge 排序筛选、搜索框仍需在菜单命中问题解决后复核。
  • 有副作用的提交类操作(BYKC 签到/退选、课堂签到、CGYY 提交预约、YGDK 新增打卡、评教提交)均未执行,只做只读验证。

阶段 2 当前结论

  • 本地后端、Redis 与 Wasm dev server 可用。
  • 首页和主要业务模块的真实浏览器只读流程已覆盖,重点 Judge 轻量列表、首页待办和详情补齐组合行为已确认可用。
  • 受控错误态已覆盖并修复个人信息错误态无限加载问题。
  • 阶段 2 尚未整体完成,不能在 todo.md 标记全阶段完成;下一步应定位并解决 Compose/Wasm 下拉/筛选菜单交互阻塞。

Clone this wiki locally