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.
 
 
 

6.9 KiB

RIASEC 职业兴趣测评 API(功能版本 V35,Flyway V34__riasec_assessment.sql)

基于 RIASEC 理论的自研题库,仅供职业兴趣探索参考,不构成心理或职业诊断。

  • 题库:72 道(R/I/A/S/E/C 各 12),SELF_AUTHORED,reverseScored 恒为 false
  • 每次答卷:后端从六维中各随机抽取 5 道,共 30 道并持久化,刷新页面不重新抽题
  • 量表:LIKERT_5 = 1 完全不感兴趣 … 5 非常感兴趣
  • 计分:rawScore = 5 道之和,maxScore = 25,percentage = rawScore/25×100(HALF_UP, scale=2)
  • 排序:percentage DESC,同分按维度字母升序;前三位组成 primaryCode
  • 结果:仅 RIASEC 六维聚合分 + 排名 + 探索方向,不存储原始答案
  • 探索方向:career-direction-v0.1,仅"可能感兴趣的职业探索方向"
  • 只读/脱敏:不写 candidate_dimension_scores;结果/审计不含原始题面、答案、手机号、邮箱、JWT

权限

接口 STUDENT COMPANY ADMIN 未登录
测评类型 GET /assessments/types 200 200 200 401
题目 GET /assessments/{type}/questions 200 200 200 401
创建答卷 POST /assessments/attempts 200 403 403 401
答卷详情/保存/提交/结果 仅本人 403 403 401
我的历史 GET /assessments/me 仅本人 403 403 401

身份一律从 JWT 获取,不接受 userId 参数。

错误码(97xx)

code 含义 HTTP
9701 ASSESSMENT_TYPE_NOT_FOUND 404
9702 ASSESSMENT_ATTEMPT_NOT_FOUND 404
9703 ASSESSMENT_ATTEMPT_INVALID_STATE 409
9705 ASSESSMENT_ANSWER_INVALID 400
9706 ASSESSMENT_INCOMPLETE 400
9707 ASSESSMENT_CONCURRENT_UPDATE 409
9708 ASSESSMENT_DUPLICATE_ACTIVE 409
9709 ASSESSMENT_IDEMPOTENCY_CONFLICT 409

重复提交不抛错,直接幂等返回成功(9704 预留,未使用)。

接口

GET /api/v1/assessments/types

返回全部 ACTIVE 测评定义(typeCode、displayName、description、instructions、scaleType、questionCount=72、attemptQuestionCount=30、minPerDimension=5、questionSetVersion、rulesVersion)。

GET /api/v1/assessments/HOLLAND_RIASEC/questions

返回指定测评的 ACTIVE 题目(按 position;类型非 ACTIVE 或不存在 → 404/9701)。对外隐藏 dimension、reverseScored、source、questionVersion、questionCode,仅返回:

{ "id": 301, "position": 1, "stem": "我对使用手工工具制作物品感兴趣。", "scaleType": "LIKERT_5" }

不返回 questionCode:题目内部编码(如 R01)前缀携带维度信息,一律不外露,前端不得用于推导 R/I/A/S/E/C 维度;维度归属仅由服务端计分使用。

POST /api/v1/assessments/attempts

仅 STUDENT 且类型须为 ACTIVE(INACTIVE/不存在 → 404/9701)。请求:{ "typeCode": "HOLLAND_RIASEC", "idempotencyKey": "uuid" } 返回 attemptId、status、totalQuestions(30)、answeredCount、completionRate、questionSetVersion、version、本次 30 道题。不返回 samplingSeed。

抽题严格约束:六维各恰好 5 道、总数严格 30;任一维度 ACTIVE 题不足 5 道或六维不齐 → 拒绝创建(400),不静默减题。

单活跃答卷(并发原子):同一学生同一类型同时最多一份 DRAFT/IN_PROGRESS。由数据库唯一约束 uk_assessment_attempts_active 原子兜底:

  • 竞争失败的并发创建请求返回 409/9708(不得返回 500);
  • 同一 idempotencyKey 的并发重放返回已创建的原 attempt(幂等 200,同一 attemptId);
  • 仅数据库靠唯一约束判定归属,服务端不再复用被污染的 Hibernate Session 查询, 写入与冲突判定分别使用独立事务/REQUIRES_NEW,创建外层显式 READ_COMMITTED 以读取已提交数据。
  • 答完提交(COMPLETED)后释放 active_key,允许重新测评。

GET /api/v1/assessments/attempts/{attemptId}

仅本人。返回 30 道题(固定 position)、已保存答案、answeredCount、completionRate、version、当前状态。

PATCH /api/v1/assessments/attempts/{attemptId}/answers

请求:{ "version": 2, "answers": [ { "questionId": 301, "value": 4 } ] } 支持单题/批量;同题重复保存 upsert;同一请求内同题不得重复出现(重复 → 400/9705);value 1-5;题目必须属于本答卷;版本冲突 409/9707;首次保存后状态置 IN_PROGRESS。

POST /api/v1/assessments/attempts/{attemptId}/submit

  • answeredCount < 30 → 400/9706
  • 30 题(每维各 5)→ COMPLETED,生成结果,写审计,返回结果
  • 重复提交 → 200 返回原结果,不重复生成结果与审计
  • 不写入候选人评分表

GET /api/v1/assessments/attempts/{attemptId}/result

答卷 COMPLETED 后返回:

{
  "attemptId": 101,
  "typeCode": "HOLLAND_RIASEC",
  "status": "COMPLETED",
  "primaryCode": "SIC",
  "primaryType": "S",
  "dimensionScores": [ { "dimension": "S", "score": 88.00, "answeredCount": 5 } ],
  "typeRanking": ["S", "I", "C", "R", "A", "E"],
  "answeredCount": 30,
  "completionRate": 100.00,
  "questionSetVersion": "riasec-self-v0.2",
  "rulesVersion": "riasec-scoring-v0.1",
  "generatedAt": "2026-08-28T16:00:00",
  "disclaimer": "本结果仅供职业兴趣探索参考,不构成心理或职业诊断。",
  "explorationDirections": ["教育辅导", "用户运营", "客户成功", "职业咨询"]
}

不返回 studentUserId、phone、email、password、原始答案、企业信息、其他用户信息。

越权:答卷题目、已保存答案与结果均仅本人(STUDENT)可读;COMPANY / ADMIN 越权访问一律 403/2002。(来源:权限矩阵)

GET /api/v1/assessments/me?page=0&size=20

分页返回当前学生的答卷与结果概要。

数据库(V34__riasec_assessment.sql,新增 6 张表)

  • assessment_definitions:测评定义(HOLLAND_RIASEC)
  • assessment_questions:72 题,UNIQUE(definition_id, question_code)、UNIQUE(definition_id, position)、CHECK(dimension IN R/I/A/S/E/C)、CHECK(reverse_scored IN 0,1)
  • assessment_attempts:答卷主记录,@Version 乐观锁,UNIQUE(student_user_id, idempotency_key)、UNIQUE(active_key)(单活跃原子约束,DRAFT/IN_PROGRESS 非空,终态置 NULL)、CHECK(status IN DRAFT/IN_PROGRESS/COMPLETED/EXPIRED)
  • assessment_attempt_questions:本次抽中的 30 题,UNIQUE(attempt_id, question_id)、UNIQUE(attempt_id, position)
  • assessment_answers:答案,answer_value 1-5(CHECK),UNIQUE(attempt_id, question_id)(API 层字段仍为 value)
  • assessment_results:结果,attempt_id 唯一(幂等)。

dimension_scores_text / type_ranking_text 使用 TEXT 保存 JSON 字符串,兼容 MySQL 8 与 H2 MODE=MySQL。答案列使用 answer_value(避免 H2 保留字 value,该列名在 MySQL 与 H2 MODE=MySQL 下均兼容)。