# 求职者评分卡 API ## 概述 求职者评价聚合与评分卡模块,提供求职者(STUDENT)查看自己的评价聚合数据、评分趋势和百分位排名。 ## 权限 - 未登录:HTTP 401(code=401) - STUDENT:HTTP 200 - COMPANY:HTTP 403(code=2002) - ADMIN:HTTP 403(code=2002) 所有接口只允许当前登录的 STUDENT 查询自己的数据,不接受通过 URL 参数查询其他用户。 ## 接口列表 ### 1. GET /api/v1/profile/me/candidate-score-card 查询求职者评分卡。 **响应示例(有数据):** ```json { "code": 200, "message": "ok", "data": { "candidateId": 10001, "status": "OK", "overallScore": null, "sampleCount": 3, "feedbackSummary": { "totalCount": 3, "averageRating": 4.33, "ratingDistribution": { "1": 0, "2": 0, "3": 1, "4": 0, "5": 2 }, "tags": [ {"name": "沟通良好", "count": 2} ] }, "matchSignals": { "candidateInterestScore": { "average": 82.50, "sampleCount": 2 }, "hrSuitabilityScore": { "average": 76.00, "sampleCount": 1 } }, "unsupportedDimensions": [ "EDUCATION", "INTERNSHIP", "ABILITY", "COMPLIANCE", "STABILITY", "GROWTH", "INTEGRITY", "ACTIVITY" ], "generatedAt": "2026-08-14T12:00:00Z" } } ``` **响应示例(无数据):** ```json { "code": 200, "message": "ok", "data": { "candidateId": 10001, "status": "INSUFFICIENT_DATA", "overallScore": null, "sampleCount": 0, "feedbackSummary": { "totalCount": 0, "averageRating": null, "ratingDistribution": { "1": 0, "2": 0, "3": 0, "4": 0, "5": 0 }, "tags": [] }, "matchSignals": { "candidateInterestScore": {"average": null, "sampleCount": 0}, "hrSuitabilityScore": {"average": null, "sampleCount": 0} }, "unsupportedDimensions": [ "EDUCATION", "INTERNSHIP", "ABILITY", "COMPLIANCE", "STABILITY", "GROWTH", "INTEGRITY", "ACTIVITY" ], "generatedAt": "2026-08-14T12:00:00Z" } } ``` **错误响应:** - 未登录:401(code=401) - 非 STUDENT:403(code=2002) ### 2. GET /api/v1/profile/me/candidate-score-trend 查询评分趋势。 **参数:** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | months | int | 否 | 6 | 统计月数,范围 1-24 | **响应示例:** ```json { "code": 200, "message": "ok", "data": { "candidateId": 10001, "months": 6, "items": [ { "month": "2026-03", "feedbackCount": 2, "averageRating": 4.50, "ratingScore": 90.00 } ] } } ``` **错误响应:** - 未登录:401(code=401) - 非 STUDENT:403(code=2002) - months < 1 或 > 24:400(code=1001) **说明:** - 趋势时间范围:`months=6` 表示当前月份和前 5 个自然月,起始时间使用当前月份的第一天 - 按 `candidate_feedback.created_at` 的年月分组,结果按 `yyyy-MM` 升序 - `ratingScore = averageRating / 5 * 100`,保留两位小数 - 无数据时返回 `items: []`(没有数据的月份不返回空月份条目) ### 3. GET /api/v1/profile/me/candidate-percentile 查询评分百分位。 **响应示例(有数据):** ```json { "code": 200, "message": "ok", "data": { "candidateId": 10001, "status": "OK", "scoreType": "FEEDBACK_RATING", "score": 86.67, "percentile": 72.50, "cohortSize": 38, "sampleCount": 3, "minimumSampleCount": 3 } } ``` **响应示例(样本不足):** ```json { "code": 200, "message": "ok", "data": { "candidateId": 10001, "status": "INSUFFICIENT_DATA", "scoreType": "FEEDBACK_RATING", "score": null, "percentile": null, "cohortSize": 0, "sampleCount": 1, "minimumSampleCount": 3 } } ``` **错误响应:** - 未登录:401(code=401) - 非 STUDENT:403(code=2002) ## 百分位计算公式 **cohort 定义:** - `candidate_feedback` 按 `student_user_id` 分组 - `COUNT(*) >= 3` 的求职者进入 cohort **score 计算:** - `score = AVG(rating) / 5 * 100` **百分位计算:** - `percentile = COUNT(other.score < current.score) / (cohortSize - 1) * 100` - 只统计严格低于当前分数的求职者 - 最高分为 100.00 - 最低分为 0.00 - 同分不互相计入 - 使用 BigDecimal,保留两位小数,HALF_UP **INSUFFICIENT_DATA 条件:** - 当前用户反馈数 < 3 - cohort 总人数 < 2 ## 不支持的评分维度 当前评分卡仅覆盖基于反馈的评分聚合,以下 8 个维度尚未实现,始终返回为 `unsupportedDimensions`: - EDUCATION(教育背景) - INTERNSHIP(实习经历) - ABILITY(能力评分) - COMPLIANCE(合规性) - STABILITY(稳定性) - GROWTH(成长潜力) - INTEGRITY(诚信评分) - ACTIVITY(求职活跃度) `overallScore` 在 8 个维度全部实现前固定为 `null`。 ## 数据来源 | 数据 | 来源表 | |------|--------| | 反馈总数、平均评分、评分分布 | candidate_feedback | | 标签聚合 | candidate_feedback.tags(JSON) | | 求职者意愿分、HR 适配分 | application_match_records | | 趋势 | candidate_feedback.created_at | | 百分位 | candidate_feedback 全量聚合 | ## null 字段策略 项目全局配置 `spring.jackson.default-property-inclusion=non_null`,null 字段默认不序列化。 以下关键字段使用 `@JsonInclude(JsonInclude.Include.ALWAYS)` 标注,无数据时仍显式返回 `null`: - `overallScore`(评分卡) - `averageRating`(feedbackSummary) - `candidateInterestScore.average`(匹配信号) - `hrSuitabilityScore.average`(匹配信号) - `score`(百分位) - `percentile`(百分位) ## 查询次数 评分卡三个接口的实际 SQL 查询次数: | 接口 | 查询次数 | 说明 | |------|----------|------| | GET /profile/me/candidate-score-card | 4 条 SQL | 1 反馈摘要(COUNT+AVG合并) + 1 评分分布 + 1 标签 + 2 匹配信号(candidateInterestScore + hrSuitabilityScore) | | GET /profile/me/candidate-score-trend | 1 条 SQL | 按月聚合趋势 | | GET /profile/me/candidate-percentile | 3 条 SQL | cohort 人数 + 当前分数 + 排名(仅当样本>=3 且 cohort>=2 时执行全部 3 条) | 所有查询均针对单个 `studentUserId`,无 N+1 问题。 ## 数据脱敏 - 不返回 `candidate_feedback.content` - 不返回 `companyUserId` - 不返回 `applicationId` - 不返回其他求职者的任何数据 - 不暴露内部审核字段