Skip to content

软件详细设计说明书

1. 文档信息

  • 文档名称:AUBB(Academic Unified Builder Bench)软件详细设计说明书
  • 版本:v1.2
  • 状态:设计基线
  • 更新日期:2026-04-14
  • 编写依据:SRS v4.1、概要设计说明书 v1.2、模块地图、API 设计草案
  • 参考标准:IEEE 1016-2009

2. 代码仓与目录建议

text
seproject/
  frontend/
    platform-web/
  backend/
    pom.xml
    common/
    platform-api/
    judge-worker/
  infra/
    docker/
    sql/
    grafana/
    gojudge/
  docs/

2.1 Maven 多模块建议

模块作用
backend/common公共枚举、错误码、工具类、基类、事件模型
backend/platform-api对外 REST API、认证、核心业务模块
backend/judge-worker运行 / 评测消息消费、go-judge 适配、结果回写

3. 前端详细设计

3.1 路由结构

路由前缀页面权限
/login登录页匿名
/student/courses学员课程列表学员
/student/courses/:courseId/tasks/:taskId学员任务详情学员
/student/courses/:courseId/tasks/:taskId/ide学员在线 IDE学员
/teacher/courses教师课程列表教师 / 助教
/teacher/courses/:courseId/tasks/new任务创建页教师
/teacher/courses/:courseId/tasks/:taskId/languages任务语言 / 用例配置页教师
/teacher/submissions/:submissionId提交详情与批改页教师 / 助教
/admin/config平台配置管理员
/admin/users用户与组织管理管理员
/admin/audit审计日志管理员 / 运维

3.2 状态管理模块

Store负责状态
authStore当前用户、角色、登录态、菜单权限
courseStore课程列表、课程详情、成员、资源
taskStore任务详情、提交规则、语言配置、Rubric、测试用例
ideStore工作区文件树、当前语言、活动文件、编辑脏状态、保存状态
runStore试运行输入、运行历史、stdout / stderr、运行状态
submissionStore正式提交列表、当前提交、评测状态
gradeStore批改记录、成绩单、复核状态
adminStore平台配置、用户、组织、审计统计

3.3 在线 IDE 页面布局

  • 左侧:文件树、模板工程说明、文件新建 / 重命名 / 删除入口。
  • 中部:基于 Monaco Editor 的多标签页编辑区。
  • 下方:运行控制台,展示标准输出、标准错误、资源摘要和最近运行记录。
  • 右侧:任务说明、样例、提交限制、当前评测状态和正式提交入口。

3.4 页面交互规则

  • 文件编辑采用 2 秒防抖自动保存,并支持手动保存。
  • 点击“运行”前先将当前编辑缓冲区同步到工作区。
  • 点击“正式提交”时,若存在未保存改动,先触发强制保存并在成功后固化快照。
  • 运行结果与正式评测结果分别展示,视觉和文案必须显式区分。

4. 后端详细设计

4.1 部署单元

服务技术栈责任
platform-apiSpring Boot 3、Spring MVC、Spring Security、MyBatis-Plus对外 API、权限、事务、业务编排
judge-workerSpring Boot 3、Spring Data Redis、定时调度消费运行 / 评测消息、调用 go-judge、归一化结果

4.2 包结构设计

text
com.seproject.platform
  ├─ config
  ├─ common
  │   ├─ enums
  │   ├─ exception
  │   ├─ response
  │   └─ util
  ├─ security
  │   ├─ filter
  │   ├─ handler
  │   ├─ service
  │   └─ context
  ├─ modules
  │   ├─ auth
  │   ├─ admin
  │   ├─ course
  │   ├─ task
  │   ├─ ide
  │   ├─ submission
  │   ├─ judge
  │   ├─ grade
  │   ├─ notification
  │   └─ analytics
  └─ integration
      ├─ storage
      ├─ gojudge
      ├─ keycloak
      └─ redisstream

4.3 模块内部分层

每个业务模块统一采用如下结构:

text
modules/task/
  controller/
  dto/
  vo/
  app/
  domain/
  mapper/
  entity/
  convert/
层次职责说明
controller接口定义、参数接收、响应输出只做协议转换,不承载业务逻辑
dto / vo入参与出参模型与数据库实体分离
app应用服务编排事务、调用领域服务、发布消息
domain领域服务核心规则、状态流转、权限判定
mapperMyBatis Mapper数据访问
entity持久化对象对应数据库表
convertMapStruct 转换器DTO / Entity / VO 映射

4.4 请求处理链路

text
Nginx
  -> Spring Security FilterChain
  -> Login/User Context Filter
  -> Controller
  -> Application Service
  -> Domain Service
  -> Mapper
  -> PostgreSQL / Redis / S3 / Redis Stream

4.5 认证与权限设计

4.5.1 Spring Security 过滤链

  • 匿名放行:/api/v1/auth/login/api/v1/auth/logout、健康检查、静态资源。
  • 认证入口:基于用户名密码登录后签发 JWT,客户端通过 Authorization: Bearer <token> 传递访问令牌。
  • 令牌校验:API 侧使用 Spring Security Resource Server 校验 JWT 签名、有效期和声明。
  • CSRF:当前治理接口使用 Bearer Token,无需依赖 CSRF Token。

4.5.2 权限模型

  • 平台治理权限:学校/学院/课程/班级管理员通过 JWT 中的 authority 与应用层作用域校验联合控制。
  • 课程级权限:教师、助教、学员通过 course_members 关系在业务层二次校验。
  • 数据级权限:提交、成绩、工作区等资源进入应用服务后再次检查归属关系。

4.5.3 统一认证扩展

  • 若启用 Keycloak,则采用 OIDC code flow。
  • user_identities 维护平台用户与外部身份主体的映射。
  • 外部身份登录成功后,仍要回填平台内角色与组织信息,不直接信任外部系统的课程权限。

4.6 数据访问设计

4.6.1 ORM / Mapper 策略

  • 简单单表 CRUD:优先使用 MyBatis-Plus。
  • 多表联查、聚合统计、分页筛选:使用 MyBatis XML 自定义 SQL。
  • 禁止 Controller 直接调用 Mapper,必须经由 Application Service / Domain Service。

4.6.2 数据转换策略

  • 请求体 DTO 只用于接口层。
  • 数据库表对应 Entity
  • 页面或接口返回统一输出 VO
  • DTO / Entity / VO 转换使用 MapStruct,避免手写大量样板代码。

4.7 事务设计

场景事务边界说明
创建课程CourseAppService#createCourse创建课程、负责人关系、审计记录一次提交
发布任务TaskAppService#publishTask任务状态变更、版本留痕、校验配置一致提交
保存工作区IdeWorkspaceAppService#saveFiles文件 upsert、版本递增在单事务内完成
正式提交SubmissionAppService#createSubmission先固化快照,再写提交记录和审计,最后发消息
发布成绩GradeAppService#publishGrade成绩状态变更、通知事件、审计记录一次提交

事务规则:

  • 外部调用 go-judge、S3 上传、Redis Stream 发消息不应长时间占用数据库事务。
  • 需要消息投递的场景采用“本地事务成功后发送消息”的方式,失败由补偿任务处理。
  • 重评、批量导入等接口必须支持幂等键或显式去重条件。

4.8 Redis 设计

4.8.1 Key 规划

Key 模式作用
jwt:blacklist:*预留的令牌撤销扩展位,当前版本未启用
cache:platform-config平台配置缓存
cache:course:{courseId}课程基础信息缓存
rate:login:{username}登录失败计数
lock:submission:{taskId}:{userId}同一任务提交互斥锁

4.8.2 Stream 规划

Stream消息类型消费组
stream:sandbox-run试运行任务judge-worker
stream:submission-judge正式评测任务judge-worker
stream:notification通知发送任务notify-workerplatform-api

消费规则:

  • 使用消费者组保证多实例并发消费。
  • Worker 启动时扫描 pending list,对长时间未确认消息做恢复。
  • 死信消息进入 stream:dead-letter,供后台人工处理。

4.9 定时任务设计

定时任务实现方式作用
任务自动关闭@Scheduled到达截止时间后关闭任务
草稿压缩清理@Scheduled清理旧工作区版本
缓存文件清理@Scheduled清理 go-judge 缓存产物
审计归档@Scheduled转储或清理历史日志
消息补偿@Scheduled重试失败通知或未确认评测消息

4.10 审计与异常设计

  • 关键操作审计通过 AuditLogAppService 统一写入。
  • 统一异常处理使用 @RestControllerAdvice,映射为稳定错误码。
  • 所有请求日志必须带 requestId;登录、提交、评测、成绩链路增加 userIdcourseIdtaskIdsubmissionId

5. 关键模块详细设计

5.1 认证与访问令牌

5.1.1 登录流程

  1. AuthController#login 接收用户名 / 密码。
  2. AuthAppService 调用 UserMapper 查询用户。
  3. 校验账号状态、密码哈希、失败次数与锁定时间。
  4. 认证成功后由服务端签发 JWT,并返回给客户端。
  5. AuditLogAppService 记录登录结果。

5.1.2 关键类建议

类名作用
SecurityConfigSecurity 过滤链配置
JwtTokenService访问令牌签发与解析
CurrentUserService获取当前登录用户上下文
AuthAppService登录、退出、令牌相关编排

5.2 平台治理模块

  • PlatformConfigAppService 负责当前平台配置读取与即时更新。
  • OrgUnitAppService 负责学校/学院/课程/班级组织树维护和层级校验。
  • UserAppService 负责用户导入、作用域身份变更、账号状态管理。
  • 导入接口采用“先解析 Excel -> 行级校验 -> 批量写库 -> 输出结果报告”的处理模式。

5.3 课程与任务模块

5.3.1 课程管理

  • 创建课程时自动写入负责人成员关系。
  • 邀请码生成规则在 InviteCodeDomainService 中集中维护。
  • 课程归档后禁止新提交,但保留查询历史成绩和提交记录。

5.3.2 任务管理

  • 任务编辑分为草稿保存和发布两个动作。
  • 发布前必须校验开放时间、截止时间、评分模式、语言配置和测试用例完整性。
  • 编程任务至少存在一个默认 task_language_profile

5.4 IDE 工作区模块

5.4.1 工作区初始化

  • 学员首次进入 IDE 时,按 task_starter_files 初始化 ide_workspaceside_workspace_files
  • 若任务支持多语言,则按默认语言初始化模板文件。

5.4.2 工作区保存

  • 前端每次提交文件变更时调用 /ide/workspaces/{id}/files
  • IdeWorkspaceAppService 执行文件级 upsert,并递增 version_no
  • 保存失败时写入 save_failed 状态,供前端恢复提示。

5.4.3 工作区快照

  • 试运行和正式提交都必须先生成快照。
  • 快照一经生成不可修改,只能追加新快照。
  • 快照文件保存到对象存储,数据库仅存元数据与哈希。

5.5 在线运行模块

5.5.1 运行创建

  • IdeRunController 接收运行请求。
  • RunAppService 检查任务开放窗口、语言配置与工作区归属。
  • 创建 sandbox_runs 记录后写入 stream:sandbox-run

5.5.2 运行回写

  • judge-worker 消费消息,调用 go-judge 执行。
  • 结果映射为 sandbox_runs.statusstdout_textstderr_textcompile_outputtime_msmemory_kb
  • 试运行结果不进入成绩计算,不改变 submissions 状态。

5.6 正式提交模块

5.6.1 提交受理

  • SubmissionAppService 依次校验课程成员、任务状态、截止时间、提交次数、文件大小。
  • 保存工作区快照。
  • 写入 submissionssubmission_files
  • 写入审计日志。
  • 提交 submission.accepted 消息至 stream:submission-judge

5.6.2 并发控制

  • 同一学员同一任务的正式提交在受理阶段加 Redis 分布式锁。
  • 受理失败不扣减提交次数。
  • 若快照已写入但提交未落库,补偿任务应清理孤儿快照。

5.7 判题中心

5.7.1 go-judge 适配器设计

类名作用
GoJudgeClient调用 go-judge REST API
CompileCommandBuilder根据语言模板构造编译请求
RunCommandBuilder构造用例执行请求
JudgeResultNormalizer将原始结果转为平台统一结构

5.7.2 评测流程

  1. Worker 读取 submission.accepted 消息。
  2. 查询提交快照、语言配置和隐藏用例。
  3. 对编译型语言先执行编译,取回缓存 fileId
  4. 逐个隐藏用例执行,累计得分和测试点结果。
  5. 归一化结果写入 judge_runs
  6. 更新 submissions.current_judge_run_id 和状态。
  7. 投递通知消息。

5.7.3 重评

  • 重评不覆盖旧记录,而是创建新的 judge_runs
  • 最新成功评测结果写回 submissions.current_judge_run_id
  • 所有重评动作必须写审计日志。

5.8 批改与成绩模块

5.8.1 人工批改

  • ReviewAppService 保存评语、Rubric 快照和人工分。
  • 一次提交允许多次批改记录,默认最新一条为当前有效记录。

5.8.2 成绩生成

  • GradeAppService 根据自动分、人工分和权重生成最终成绩。
  • 未完成必要批改时,不允许发布成绩。
  • 撤回成绩只改变显示状态,不删除历史记录。

5.9 通知与公告模块

  • 站内通知优先同步写库,异步扩展消息通道。
  • 公告由管理员发布,按组织或课程范围投递。
  • 同一业务事件 5 分钟内默认不重复发送同类通知。

6. 核心数据结构

6.1 工作区文件节点

java
public record WorkspaceFileNode(
    String path,
    String kind,
    String language,
    String content,
    String hash,
    Boolean readonly
) {}

6.2 试运行任务载荷

java
public record RunJobPayload(
    String runId,
    String workspaceId,
    String taskId,
    String userId,
    String languageProfileId,
    String stdin,
    List<WorkspaceFilePayload> files,
    ResourceLimitPayload limits
) {}

6.3 正式评测任务载荷

java
public record JudgeJobPayload(
    String judgeRunId,
    String submissionId,
    String snapshotId,
    String languageProfileId,
    List<String> testcaseIds,
    Boolean useCompileCache
) {}

6.4 归一化测试点结果

java
public record NormalizedCaseResult(
    String testcaseId,
    String verdict,
    BigDecimal score,
    Integer timeMs,
    Integer memoryKb,
    String stdoutPreview,
    String stderrPreview
) {}

7. 状态机设计

7.1 工作区保存状态机

当前状态事件下一状态
ready编辑文件dirty
dirty开始保存saving
saving保存成功ready
saving保存失败save_failed
save_failed用户重试saving

7.2 运行会话状态机

当前状态事件下一状态
queuedWorker 开始执行running
running运行成功success
running超时timeout
running编译失败 / 运行失败 / 系统失败failed

7.3 提交状态机

当前状态事件下一状态
accepted投递评测队列queued
queued开始评测evaluating
evaluating评测成功evaluated
evaluating评测超时 / 失败failed
failed重新评测queued

7.4 成绩状态机

当前状态事件下一状态
pending生成成绩unpublished
unpublished发布published
published撤回withdrawn
withdrawn再次发布published

8. 异常处理设计

异常场景处理策略
登录失败次数超限锁定账号,返回统一错误码,写入审计
工作区自动保存失败保留最近成功版本,前端提示用户手动保存或重试
提交超时或超过次数拒绝受理,不创建正式提交记录
对象存储快照写入失败回滚事务并返回可重试错误
Redis Stream 投递失败写入告警并由补偿任务重试
go-judge 返回编译 / 运行错误归一化为运行结果或评测结果,不抛给前端原始沙箱字段
编译缓存清理失败记录告警并由后台清理任务补偿
成绩发布时批改缺失阻止发布并提示缺少人工评分或权重配置

9. 定时任务与异步任务

任务触发方式作用
任务自动关闭@Scheduled到达截止时间后关闭任务
工作区草稿压缩@Scheduled清理旧版本草稿,保留最近可恢复版本
在线运行消费Redis Stream 消费组消费试运行队列并写回 sandbox_runs
正式评测消费Redis Stream 消费组消费提交队列并写回 judge_runs
缓存文件清理@Scheduled清理 go-judge 缓存产物和过期文件
通知补发@Scheduled补发失败通知
数据归档@Scheduled清理过期通知、归档历史日志

10. 日志与审计点

  • 登录、退出、失败登录、密码修改
  • 用户导入、角色调整、平台配置发布
  • 课程创建、任务发布、语言配置变更、任务关闭
  • 工作区运行、正式提交、重评、成绩发布、成绩撤回
  • 导出成绩、导出提交、导出审计日志

11. 与编码直接相关的约束

  • 所有接口 DTO 必须独立定义,禁止直接暴露 Entity。
  • 所有状态流转必须通过 Application Service 或 Domain Service 封装,不允许在 Controller 中直接改状态。
  • Mapper 仅负责持久化,不承载业务判断。
  • 文件上传和快照固化统一走对象存储适配器,禁止业务模块直接访问本地磁盘。
  • 所有 go-judge 原始响应必须先归一化,再返回给前端或写入正式结果表。
  • 正式提交一旦创建,其对应快照不得被修改或覆盖。