# 评分治理 API(Candidate Scoring Governance) > 规则版本 `candidate-scoring-v0.1` · 基础路径 `/api/v1` > 为求职者评分提供申诉、审核、回滚、审计基础能力;**不改已验收评分接口与引擎规则**。 ## 回滚语义 回滚 = ① 记录回滚前快照(`candidate_scoring_snapshot_history`);② 按**当前数据**确定性重算(复用 `CandidateScoringCalculator`);③ 写入 `candidate_dimension_scores` 新版本;④ 记录回滚后快照;⑤ 申诉状态置 `ROLLED_BACK`;⑥ 写申诉历史与审计。**不恢复旧分数**——是"批准申诉后的确定性重新计算"。 ## 接口(9 个接口落在 8 个路径,OpenAPI 87 → 95) | # | 接口 | 方法 | 角色 | |---|---|---|---| | 1 | `/profile/me/candidate-scoring/appeals` | POST | STUDENT 本人(提交申诉) | | 2 | `/profile/me/candidate-scoring/appeals` | GET | STUDENT 本人(我的列表) | | 3 | `/profile/me/candidate-scoring/appeals/{appealId}` | GET | 本人 / ADMIN | | 4 | `/profile/me/candidate-scoring/appeals/{appealId}/cancel` | POST | STUDENT 本人(撤销,仅 PENDING) | | 5 | `/admin/candidate-scoring/appeals` | GET | ADMIN | | 6 | `/admin/candidate-scoring/appeals/{appealId}/decision` | POST | ADMIN | | 7 | `/admin/candidate-scoring/appeals/{appealId}/rollback` | POST | ADMIN | | 8 | `/admin/candidate-scoring/appeals/{appealId}/history` | GET | 本人(脱敏)/ ADMIN(全量) | | 9 | `/admin/candidate-scoring/snapshots/{candidateUserId}/{dimension}/{period}/history` | GET | ADMIN | ## 请求/响应 - `CreateAppealRequest`:`dimension`(8 枚举)、`period`(yyyy-MM)、`reason`(必填,缺 → 8604)、`idempotencyKey`(可选)。 - `AppealDecisionRequest`:`decision`(APPROVE/REJECT)、`reason`(REJECT 必填 → 8604)。 - `AppealResponse`:appealId、candidateId、dimension、period、status、reason、decision、decisionReason、reviewerId(学生端不返回)、reviewedAt、rollbackAt、scoreAtAppeal、snapshotVersionAtAppeal、rulesVersion、createdAt、updatedAt。 - 历史项:`actorRole`(STUDENT/ADMIN,学生端可见);`actorUserId`(**仅 ADMIN**)。 - 快照审计项:回滚前后 `score/version/rulesVersion` 完整变化(仅 ADMIN)。 ## 权限矩阵 | 接口 | 未登录 | STUDENT | COMPANY | ADMIN | |---|---|---|---|---| | 申诉 1–4 | 401 | ✅ 本人 | 403 | 403 | | 历史(8) | 401 | ✅ 本人(脱敏) | 403 | ✅ 全量 | | admin 5/6/7/9 | 401 | 403 | 403 | ✅ | 身份一律取自 JWT;学生仅能访问自己的申诉;COMPANY 全 403/2002;ADMIN 的 `candidateUserId` 路径参数仅 ADMIN 可用。 ## 状态机 ``` PENDING ──> APPROVED ──> ROLLED_BACK(终态) │ └────────────> REJECTED(终态) └────────────> CANCELLED(终态) ``` ## 并发与幂等 - `active_key = {candidate}:{dimension}:{period}` 唯一约束保护 PENDING/APPROVED;终态清空 active_key 允许重新提交。 - 同 idempotencyKey 同请求体 → 200 幂等;不同请求体 → **409/8607**;并发创建唯一冲突 → **409/8602**。 - 审核 `@Version` 乐观锁,并发冲突 → 409/8606。 - 回滚限流 `candidate_scoring_rollback_limits` + `SELECT ... FOR UPDATE` 悲观锁;每学生每自然年 ≤3 次,第 4 次 **409/8605**;重复回滚幂等 200。 ## 错误码(新增 86xx) | code | HTTP | 含义 | |---|---|---| | 8601 | 404 | 申诉不存在 | | 8602 | 409 | 同维度+周期已有活跃申诉 | | 8603 | 409 | 申诉已决定 | | 8604 | 400 | 缺少理由 | | 8605 | 409 | 年度回滚次数超限(3) | | 8606 | 409 | 非法状态流转 / 并发冲突 | | 8607 | 409 | 幂等键冲突(请求体不同) | ## 脱敏 学生端响应不返回:reviewerId、actorUserId、phone、email、passwordHash、resumeUrl、内部评分日志。ADMIN 可见 reviewerId 与 actorUserId。