You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

13 KiB

四维能力测评 API 设计文档(V36 设计锁定版)

状态:设计已锁定,待编码。功能版本 V36。题库为自研工作情境题;本版不接入候选评分引擎、不向企业开放结果。题目统计质量门槛保留为后续试测工作,不阻塞本版功能实现。

0. 产品来源摘要(func.xlsx,已确认)

  • 功能名:能力测评(4维度) = 逻辑 / 沟通 / 执行 / 学习 能力四维测评(功能详细清单 D24/F24、求职端功能详情 B24/C24、企业端功能详情)。
  • 目标:了解自己目前的能力短板在哪里(G24)。
  • 结果展示:四维能力测试 → 能力雷达图 + 短板提示(F24)。
  • 限时:测评限时 30 分钟,超时强制提交(G24)。
  • 完成率:测评完成率 ≥ 70%(H24,中途退出保存进度的判定)。
  • 质量:测评区分度 ≥ 0.4(H24/H52,为非功能质量门槛)。
  • 能力测评评分(F1.2):基于四维得分 → 能力综合分,「让企业看到我的能力测评结果」;未测评显示「待测评」(G52)。
  • 成长信号:学习能力/成长速度潜力分(F55/G55)。

1. 功能范围与非目标

范围内(第一版 V36):

  • 四维能力测评的题型目录、创建答卷、答题保存、进度恢复、提交、结果查询。
  • 结果含四维分、综合分、最低维度短板提示、雷达图数据、题目解析与有效期状态。

非目标(V36 默认不做,除非负责人确认):

  • 不接入 Candidate Scoring / 不写 candidate_dimension_scores(ABILITY 保持 PENDING)。
  • 不提供企业查看学生能力测评结果的接口。
  • 不做岗位推荐、AI 路径建议、开放题或 AI 自动评分。
  • 不做定时器批量改写结果有效期;结果是否过期在读取或新建答卷时由后端按 valid_until 动态判断。

2. 四个能力维度的正式名称与编码

编码(Code) 名称 说明
LOGIC 逻辑能力 逻辑/推理/分析
COMMUNICATION 沟通能力 表达/协作/共情
EXECUTION 执行能力 行动/落地/结果导向
LEARNING 学习能力 学习/成长/适应

编码和结果字段按上表锁定。

3. 题库来源、题目数量、题目版本

  • 题目来源:自研(SELF_AUTHORED),不复制商用量表。
  • 锁定题库文件:docs/ability-question-bank-v0.1.json。迁移种子、题库测试和题目版本必须以该文件为唯一权威来源,禁止在 SQL 或 Java 中自行改写题干、选项、答案键、分值或解析。
  • 题库总量:每维 12 题,共 48 题;每次答卷从每个维度分层随机抽取 6 题,共 24 题。
  • 题型:单选题、情境判断题、排序题;允许选项部分得分,不采用开放题。
  • 题目版本:ability-v0.1。每题必须保留 difficulty、discrimination、version 字段;前两项允许在首版种子数据中为空,试测后回填。

4. 是否固定题目或分层随机抽题

  • 采用分层随机抽题:从每维 ACTIVE 题库随机抽取 6 题,并把题目集合、顺序、题目版本和题目快照持久化;刷新、恢复和重复读取均不得重新抽题。
  • 新建或重测答卷均重新抽取本次 24 题;不得向前端返回内部维度、答案键、评分规则或题目版本。

5. 单次答题数量与完成条件

  • 单次题量固定为 4 维 × 6 = 24 题。
  • 必须回答 24/24 才能提交;任何未完成答卷均返回 ABILITY_INCOMPLETE,不得依据 70% 生成正式结果。
  • 产品“完成率 ≥ 70%”仅用于过程进度展示,不构成提交门槛。

6. 题型与计分规则

  • 每题均为后端判分的工作情境题。每个选项对应 0、1、2 或 4 分;选项及其得分、标准答案键、评分规则和解析均只保存在后端。
  • 每维原始分为该维 6 题得分之和,维度百分制分数为 rawScore / 24 × 100;保留两位小数,使用 HALF_UP。
  • 综合分为四维百分制得分的等权平均;只有四维均完成 6 题时才生成综合分。
  • 短板取最低维度;若最低分并列,返回全部并列维度。结果页同时返回每道题解析,但仅限答卷提交后由本人读取。

7. 中途保存和恢复规则

  • 保存答案对 (attempt, question) upsert;同请求内同题重复 → 校验拒绝。
  • 获取答卷恢复:固定题目顺序 + 已答值;刷新不重抽题。
  • 未答完可退出,下次 GET 恢复;与 RIASEC 一致(active 答卷阻塞重测)。

8. 答卷状态机

锁定状态机:

DRAFT → IN_PROGRESS → COMPLETED
IN_PROGRESS --(超过 expires_at 且未提交)--> EXPIRED
  • 创建答卷仅进入 DRAFT,不开始计时。
  • 第一次成功保存答案时,后端一次性设置 started_at=now、expires_at=started_at+30分钟,并转为 IN_PROGRESS。
  • 后续保存、读取、提交均由后端校验 expires_at;超时未答完 24 题时,原子标记为 EXPIRED,不生成结果、不可继续答题或提交。
  • DRAFT 没有倒计时;同一学生同一类型始终至多存在一份 DRAFT/IN_PROGRESS 活跃答卷。

9. 重测和历史保留规则

  • 历史答卷和结果永久保留,不删除。
  • 完成时写入 valid_until = completed_at + 7天。在 valid_until 前为当前有效结果;到期后结果仍可查询,但 validityStatus=EXPIRED 且仅作为历史结果。
  • 不设置“历史最高分”。当前结果只取最近一次已完成且仍有效的结果,避免用户通过反复答题刷取最高分。
  • 有效结果存在期间禁止重测;结果到期后方可创建下一份答卷。
  • 每名学生滚动 90 天内最多完成 3 次测评;未完成而超时的 EXPIRED 答卷不计入该完成次数。

10. 提交幂等与并发策略

  • 唯一键:(student_user_id, idempotency_key) 幂等;active_key(学生+类型+ACTIVE)保证同类型最多 1 份活跃答卷(复用 V35 已验证方案)。
  • 提交原子化:DRAFT/IN_PROGRESS → COMPLETED 的批量更新返回行数;仅行数=1 者生成结果+写审计;并发只产生 1 条 result + 1 条提交审计;重复提交幂等返回原结果。
  • 提交并发无 500(沿用 V35 REQUIRES_NEW + READ_COMMITTED 修复)。
  • 创建时先校验当前有效结果是否存在,再校验 90 天完成次数;两类限制须有对应错误码,不能误报为活跃答卷冲突。

11. 权限矩阵

接口 未登录 STUDENT COMPANY ADMIN
类型列表 401 200 200 200
创建 / 答卷 / 保存 / 提交 / 结果 / 历史 401 仅本人 403/2002 403/2002
  • 身份一律 JWT/SecurityContext,不接受 userId 参数。
  • 第一版不提供企业查看能力结果接口;能力综合分写入评分引擎与企业侧结果展示均为后续独立评审事项。

12. 错误码

  • V35 RIASEC 已占用 9701–9709(97xx)。V36 使用独立区间 9801–9811(能力测评),避免复用冲突:
    • 9801 ABILITY_TYPE_NOT_FOUND、9802 ABILITY_ATTEMPT_NOT_FOUND、9803 ABILITY_ATTEMPT_INVALID_STATE、9805 ABILITY_ANSWER_INVALID、9806 ABILITY_INCOMPLETE、9807 ABILITY_CONCURRENT_UPDATE、9808 ABILITY_DUPLICATE_ACTIVE、9809 ABILITY_IDEMPOTENCY_CONFLICT。
  • 9810 ABILITY_RETAKE_COOLDOWN(409):当前仍存在有效完成结果,尚不可重测。
  • 9811 ABILITY_RETAKE_LIMIT(429):滚动 90 天内已完成 3 次。
  • 复用 1001/2001/2002;超时答卷读取、保存或提交统一按 9803 ABILITY_ATTEMPT_INVALID_STATE 处理。

13. DTO 与接口字段

接口采用独立 /abilities/** 命名空间(最终 7 个接口):

GET  /abilities/types
POST /abilities/attempts
GET  /abilities/attempts/{attemptId}
PATCH /abilities/attempts/{attemptId}/answers
POST /abilities/attempts/{attemptId}/submit
GET  /abilities/attempts/{attemptId}/result
GET  /abilities/me?page&size

V36 不提供 GET /abilities/{type}/questions;题目只在创建答卷后通过 GET /abilities/attempts/{attemptId} 返回。

  • 题目响应隐藏 dimension/questionCode/competencyTag/source/reverseScored/questionVersion/answerKey/scoringRule(不泄露能力维度语义与计分内部字段)。
  • 结果响应(白名单):attemptId/typeCode/status/validityStatus/validUntil/dimensionScores[{code,score,answeredCount}]/overallScore/weaknesses/radar/answeredCount/completionRate/questionFeedback[{questionId,selectedOption,explanation}]/disclaimer。不含答案键、选项得分、studentUserId、phone、email、password。

14. 数据库表、索引、唯一约束、外键

采用独立 ability_* 六表,避免与 V35 RIASEC 的题型、判分方式和生命周期耦合:

ability_definitions        type_code UNIQUE; status; scale_type; question_count; attempt_question_count; min_per_dimension; question_set_version; rules_version
ability_questions          UNIQUE(definition_id, question_code), UNIQUE(definition_id, position), CHECK(dimension IN LOGIC/COMMUNICATION/EXECUTION/LEARNING), item_type/options_json/answer_key_json/scoring_rule_json/explanation/difficulty/discrimination/version
ability_attempts           UNIQUE(student_user_id, idempotency_key), UNIQUE(active_key), @Version, CHECK(status IN DRAFT/IN_PROGRESS/COMPLETED/EXPIRED)
ability_attempt_questions  UNIQUE(attempt_id, question_id), UNIQUE(attempt_id, position), question_version/question_snapshot_json
ability_answers            UNIQUE(attempt_id, question_id), selected_option/awarded_score/answered_at
ability_results            UNIQUE(attempt_id)(幂等)
  • 外键:attempt→definitions/users(CASCADE)、attempt_question/answer→attempt(CASCADE)+question、result→attempt(CASCADE)。题目快照用于保证题库后续修订或停用后,历史答卷和提交后的解析仍按当时版本展示与计分。
  • 索引:(student_user_id, created_at)、active_key 唯一、status 等。
  • 时间相关字段:started_at/expires_at/submitted_at/completed_at;结果含 valid_until。active_key 仅在 DRAFT/IN_PROGRESS 非空,进入 COMPLETED/EXPIRED 后置空。

15. 脱敏要求

  • 题目响应不泄露维度与内部编码;结果不返回原始答案、手机号、邮箱、password、JWT、他人信息。
  • 不保存不必要的题面;审计不含题面/答案/PII。

16. 审计要求

  • 写入 ABILITY_ATTEMPT_CREATED / ABILITY_ATTEMPT_SUBMITTED。
  • details 仅允许 attemptId/typeCode/status/answeredCount/questionSetVersion/rulesVersion/requestId/timestamp;禁止题面、答案、手机号、邮箱、JWT。

17. 是否写入 candidate_dimension_scores

  • V36 第一版不写 candidate_dimension_scores,ABILITY 维度维持 PENDING;不提供企业端能力测评结果接口。
  • 将能力综合分写入评分引擎、企业端查看结果均为后续独立评审事项。

18. OpenAPI 增量

  • 基线 134 paths / 168 operations。
  • 固定 +7 paths / +7 operations(/abilities/** 7 端点:类型/创建/详情/保存/提交/结果/我的历史)→ 141 paths / 175 operations;V36 不提供 GET /abilities/{type}/questions。运行时 OpenAPI 必须与静态一致。

19. MockMvc、集成测试和 MySQL 黑盒验收方案

  • 测试类(镜像 RIASEC):
    • AbilityAssessmentCatalogTest、AbilityAssessmentResultComputerTest、AbilityAssessmentAttemptServiceTest、AbilityAssessmentControllerTest、AbilityAssessmentPersistenceIntegrationTest(含并发创建/并发提交)、种子/迁移测试。
  • 覆盖:创建、幂等重放、同 key 同/异请求、活跃重复、有效结果冷却、90 天完成上限、中途保存、首次保存起算、恢复同一题、30 分钟超时、非法/跨答卷题 ID、未答完提交、重复提交、并发创建/提交、STUDENT/COMPANY/ADMIN/匿名权限、结果和题目解析脱敏、业务表无异常写入、Flyway、外键/唯一约束。
  • MySQL 黑盒:健康 200、Flyway 最新成功、运行时/静态 OpenAPI 一致、表/约束/数据核验、并发无 500、审计脱敏、队列归零、candidate_dimension_scores 行数不变、V31–V35 回归。

20. 回滚与兼容方案

  • 不修改 V1–V35 表与语义;V36 迁移为附加新表 V35__ability_assessment.sql(当前最新 Flyway 为 V34,下一编号为 V35;功能版本仍标 V36)。
  • 回滚:删除 V36 迁移即可,不影响 V35 及既有数据。
  • 使用独立 /abilities/** 命名空间与独立 ability_* 表,回滚不会影响 V35 RIASEC。

21. 试测与上线声明

  • 首版 48 题必须在后续试测中统计难度、选项分布与区分度;区分度低于 0.4 或存在明显歧义的题目应修改、停用或替换。
  • 当前未定义试测样本量和正式上线统计门槛,因此本版不得宣称题库已完成心理测量学验证。
  • 结果页必须声明:本测评反映当前工作情境答题表现,用于自我了解和能力提升参考;不构成职业资格、正式招聘结论或永久能力标签。

本设计已由负责人确认,可进入 V36 编码;试测统计口径为后续运营与题库质量治理工作,不阻塞本版实现。