14 KiB
入职清单与公司知识介绍 API(N04)
状态:后端实现完成,待真实 MySQL 8.4 / Docker 黑盒验收。
数据库迁移:
V50__onboarding_checklist_and_company_knowledge.sql、V51__onboarding_standard_checklist_seed.sql。
1. Base URL 与认证
本地 Base URL:
http://127.0.0.1:8080/api/v1
所有 /onboarding/** 接口都要求登录,并携带:
Authorization: Bearer <accessToken>
Content-Type: application/json
X-Request-Id: <optional-trace-id>
细粒度角色和所有权在 Service 层校验。除 401 外,接口统一返回 ApiResponse:
{
"code": 200,
"message": "ok",
"data": {},
"requestId": "req-...",
"timestamp": "2026-09-17T01:30:00Z"
}
2. 接口与权限总览
| # | Method | Path | 角色 | 说明 |
|---|---|---|---|---|
| 1 | GET | /onboarding/companies/{companyId}/checklist |
STUDENT | 读取有效清单、完成状态和完成率 |
| 2 | PUT | /onboarding/companies/{companyId}/checklist/items/{itemId}/completion |
STUDENT | 设置本人完成或未完成 |
| 3 | GET | /onboarding/companies/{companyId}/knowledge |
STUDENT | 读取企业资料、知识内容和公开评价摘要 |
| 4 | GET | /onboarding/company/checklist-items |
COMPANY | 查询本企业活动与软删除自定义项 |
| 5 | POST | /onboarding/company/checklist-items |
COMPANY | 创建本企业自定义项 |
| 6 | PUT | /onboarding/company/checklist-items/{itemId} |
COMPANY | 按版本更新本企业条目 |
| 7 | DELETE | /onboarding/company/checklist-items/{itemId}?version={version} |
COMPANY | 按版本软删除本企业条目 |
| 8 | GET | /onboarding/company/knowledge |
COMPANY | 查询本企业知识配置 |
| 9 | PUT | /onboarding/company/knowledge |
COMPANY | 创建或更新本企业知识配置 |
权限规则:
- STUDENT 接口只允许拥有 STUDENT 角色的账号访问。
- COMPANY 接口只允许拥有 COMPANY 角色且
companies.verified=true的账号访问;未认证企业统一返回403/5004,在读取或写入本企业清单、知识内容前拒绝。 - COMPANY 接口不接受
companyId;服务端从 JWT 用户解析其所属企业,避免跨企业写入。 - ADMIN 没有 onboarding 专属管理接口;调用 STUDENT/COMPANY 接口时按非目标角色返回
403/2002。 - 学生访问企业清单或知识不要求先有 Offer 或投递记录,但目标企业必须存在。
- 企业条目不存在或属于其他企业时统一返回
404/10501,不泄露其他企业数据。
3. 入职清单语义
3.1 通用项与自定义项合并
有效清单由以下两部分组成:
- 所有活动通用项
source=STANDARD;V51 固定写入 12 条。 - 当前企业所有活动自定义项
source=COMPANY。
合并结果按 sortOrder ASC, id ASC 稳定排序。企业没有活动自定义项时,customized=false,仍返回全部通用项。企业存在活动自定义项时,customized=true,返回通用项与企业项。
category 固定为:
DOCUMENT | ADMIN | EQUIPMENT | TRAINING | LOGISTICS | OTHER
证件材料 | 行政手续 | 办公设备 | 培训学习 | 到岗安排 | 其他
3.2 学生读取有效清单
GET /api/v1/onboarding/companies/10/checklist
Authorization: Bearer <studentAccessToken>
响应:
{
"code": 200,
"message": "ok",
"data": {
"companyId": 10,
"companyName": "示例科技",
"customized": true,
"totalItems": 13,
"completedItems": 1,
"completionRate": 7.7,
"items": [
{
"itemId": 101,
"source": "STANDARD",
"itemKey": "standard-id-card",
"title": "准备身份证件",
"description": "准备身份证原件或有效身份证明,用于入职登记。",
"category": "DOCUMENT",
"required": true,
"sortOrder": 100,
"active": true,
"completed": true,
"completedAt": "2026-09-17T09:00:00",
"progressVersion": 1
},
{
"itemId": 501,
"source": "COMPANY",
"itemKey": "company-10-8f1c",
"title": "领取门禁卡",
"description": "到行政前台领取门禁卡并完成权限激活。",
"category": "ADMIN",
"required": false,
"sortOrder": 1000,
"active": true,
"completed": false,
"completedAt": null,
"progressVersion": 0
}
]
},
"requestId": "req-onboarding-checklist",
"timestamp": "2026-09-17T01:30:00Z"
}
completionRate = round(completedItems * 100 / totalItems, 1);总数为 0 时返回 0.0。完成状态只属于当前 STUDENT。
3.3 更新完成状态
请求使用绝对状态,而不是切换:
PUT /api/v1/onboarding/companies/10/checklist/items/501/completion
Authorization: Bearer <studentAccessToken>
{"completed": true, "version": 0}
响应:
{
"code": 200,
"message": "ok",
"data": {
"itemId": 501,
"completed": true,
"completedAt": "2026-09-17T01:31:00Z",
"progressVersion": 1,
"totalItems": 13,
"completedItems": 2,
"completionRate": 15.4
},
"requestId": "req-onboarding-progress",
"timestamp": "2026-09-17T01:31:00Z"
}
版本规则:
- 首次保存某条目时可省略
version或传0。 - 已完成状态变化时必须传当前
progressVersion;过期返回409/10505。 - 重复提交相同
completed值保持幂等,不新增记录、不递增版本。 - 首次提交
completed=false不创建记录。 completed=false会清除completedAt。- 一名学生与一个清单项最多一条进度记录。
3.4 企业创建自定义项
POST /api/v1/onboarding/company/checklist-items
Authorization: Bearer <companyAccessToken>
{
"title": "领取门禁卡",
"description": "到行政前台领取门禁卡并完成权限激活。",
"category": "ADMIN",
"sortOrder": 1000,
"required": false,
"idempotencyKey": "company-10-access-card-20260917"
}
响应 data:
{
"itemId": 501,
"source": "COMPANY",
"itemKey": "company-10-8f1c",
"title": "领取门禁卡",
"description": "到行政前台领取门禁卡并完成权限激活。",
"category": "ADMIN",
"required": false,
"sortOrder": 1000,
"active": true,
"version": 0
}
约束:
title:必填,最多 120 字符。description:可选,最多 1000 字符。category:必填,仅允许固定枚举。sortOrder:可选,默认1000,范围0..9999。required:可选,默认false。idempotencyKey:可选,最多 64 字符;服务端会 trim,空串按未提供处理。- 活动自定义项上限为 50 条;达到上限返回
409/10503。
幂等重试:
- 同一企业、同一
idempotencyKey、同标题/说明/分类/排序/必填值:返回首次创建的条目。 - 同一企业、同一 key、请求语义不同:返回
409/10504。 - 不同企业可使用相同 key,互不冲突。
- 未传 key 时,每次请求创建新条目。
3.5 企业查询、更新与软删除
查询本企业全部条目:
GET /api/v1/onboarding/company/checklist-items
Authorization: Bearer <companyAccessToken>
响应包含活动与软删除条目,不返回通用项和其他企业项。更新请求:
PUT /api/v1/onboarding/company/checklist-items/501
Authorization: Bearer <companyAccessToken>
{
"title": "领取门禁卡并激活",
"description": "到行政前台领取门禁卡并完成权限激活。",
"category": "ADMIN",
"sortOrder": 900,
"required": true,
"active": true,
"version": 0
}
更新使用 version 乐观锁,成功递增版本;过期返回 409/10502。软删除:
DELETE /api/v1/onboarding/company/checklist-items/501?version=1
Authorization: Bearer <companyAccessToken>
首次删除必须使用当前版本,系统只将 active=false,不物理删除。重复删除已非活动条目保持幂等成功;接口仍要求携带 version 查询参数。
4. 公司知识介绍语义
4.1 学生读取与回退
GET /api/v1/onboarding/companies/10/knowledge
Authorization: Bearer <studentAccessToken>
响应:
{
"code": 200,
"message": "ok",
"data": {
"company": {
"id": 10,
"name": "示例科技",
"logoUrl": "https://cdn.example.com/company-10.png",
"description": "面向企业提供数据基础设施产品。",
"industry": "互联网",
"website": "https://example.com",
"address": "杭州市余杭区",
"verified": true
},
"knowledgeState": "CONFIGURED",
"knowledge": {
"culture": "以用户价值为中心,保持透明和长期主义。",
"workPolicies": "弹性上班;每周一、三线下办公。",
"onboardingGuide": "报到当天携带身份证件,联系行政同事完成入职登记。",
"updatedAt": "2026-09-17T01:33:00Z"
},
"reviewSummary": {
"state": "SUFFICIENT",
"totalReviews": 4,
"averageRating": 4.5,
"ratingDistribution": {
"rating1": 0,
"rating2": 0,
"rating3": 1,
"rating4": 1,
"rating5": 2
},
"topTags": ["发展空间", "同事友好"],
"dimensionSummary": {
"AUTHENTICITY": {"averageScore": 4.5, "sampleCount": 4, "dataState": "SUFFICIENT"},
"BENEFITS": {"averageScore": 4.3, "sampleCount": 4, "dataState": "SUFFICIENT"},
"SALARY_TRANSPARENCY": {"averageScore": 4.0, "sampleCount": 4, "dataState": "SUFFICIENT"},
"JD_CLARITY": {"averageScore": 4.6, "sampleCount": 4, "dataState": "SUFFICIENT"},
"GROWTH": {"averageScore": 4.4, "sampleCount": 4, "dataState": "SUFFICIENT"},
"TEAM_ATMOSPHERE": {"averageScore": 4.7, "sampleCount": 4, "dataState": "SUFFICIENT"},
"PROMOTION": {"averageScore": 4.1, "sampleCount": 4, "dataState": "SUFFICIENT"},
"WORK_LIFE_BALANCE": {"averageScore": 4.0, "sampleCount": 4, "dataState": "SUFFICIENT"}
}
}
},
"requestId": "req-company-overview",
"timestamp": "2026-09-17T01:34:00Z"
}
回退与状态:
- 企业无知识记录:仍返回企业基础资料,
knowledgeState=BASIC_ONLY,knowledge省略。 - 企业有知识记录:
knowledgeState=CONFIGURED,返回非空知识字段和updatedAt;学生公开读取响应不返回知识配置版本。 - 企业不存在:
404/5001。 - 响应白名单不包含
ownerUserId、用户 ID、手机号、邮箱、评价哈希或审核原因。
评价摘要只聚合企业全部岗位中 PUBLISHED 且审核状态为 AUTO_APPROVED/APPROVED 的评价:
reviewSummary.state |
条件 | 返回内容 |
|---|---|---|
EMPTY |
0 条 | state、totalReviews=0 |
INSUFFICIENT |
1–2 条 | state、真实 totalReviews;不返回均值、分布或维度汇总 |
SUFFICIENT |
至少 3 条 | 平均评分、评分分布、热门标签、八维汇总 |
热门标签最多 10 个;八个维度分别返回 sampleCount 和 dataState。维度的 dataState 使用同一 3 条阈值。
4.2 企业查询知识配置
GET /api/v1/onboarding/company/knowledge
Authorization: Bearer <companyAccessToken>
未配置时:
{
"code": 200,
"message": "ok",
"data": {
"configured": false,
"version": 0
},
"requestId": "req-company-knowledge",
"timestamp": "2026-09-17T01:33:00Z"
}
已配置时返回 configured=true、非空内容、updatedAt 和当前 version。空字段按 @JsonInclude(NON_NULL) 省略。
4.3 企业创建或更新知识配置
PUT /api/v1/onboarding/company/knowledge
Authorization: Bearer <companyAccessToken>
{
"culture": "以用户价值为中心,保持透明和长期主义。",
"workPolicies": "弹性上班;每周一、三线下办公。",
"onboardingGuide": "报到当天携带身份证件,联系行政同事完成入职登记。",
"version": 1
}
规则:
- 至少一个内容字段必须非空。
culture最多 2000 字符,workPolicies和onboardingGuide各最多 4000 字符。- 字段按纯文本处理,会 trim;包含 HTML 标签时返回
400/1001。 - 首次创建可以省略
version,创建后版本为0。 - 更新已有记录必须提交当前版本;版本过期返回
409/10506。 - 已有内容与提交内容相同且未传版本时按幂等读取处理;内容不同但未传版本返回
400/1001。
5. 错误码
| HTTP | code | 含义 | 前端处理 |
|---|---|---|---|
| 400 | 1001 | 参数、枚举、长度、HTML、缺少必填字段 | 展示字段错误,不自动重试 |
| 401 | 401 | 未登录或 Token 无效 | 清理登录态并重新登录 |
| 403 | 2002 | 角色不匹配、无所属企业或无权限 | 不重试,切换到正确角色 |
| 404 | 5001 | 企业不存在或 COMPANY 无绑定企业 | 检查 companyId 或企业绑定状态 |
| 404 | 10501 | 清单项不存在、跨企业或不属于有效清单 | 刷新清单后重新选择条目 |
| 409 | 10502 | 企业清单项版本过期 | 重新 GET /company/checklist-items,使用新版本重试 |
| 409 | 10503 | 活动自定义项达到 50 条上限 | 禁用新增,提示先软删除或复用现有项 |
| 409 | 10504 | 幂等键已用于不同请求体 | 更换幂等键,或确认原请求后读取原条目 |
| 409 | 10505 | 学生完成状态版本过期 | 重新读取有效清单并使用新 progressVersion |
| 409 | 10506 | 公司知识版本过期 | 重新读取企业知识配置并使用新 version |
401 由安全过滤器返回裸 JSON,没有统一 ApiResponse.requestId:
{"code": 401, "message": "not authenticated", "timestamp": ""}
其他错误示例:
{
"code": 10504,
"message": "idempotency key conflict: request body differs",
"data": null,
"requestId": "req-10504",
"timestamp": "2026-09-17T01:30:00Z"
}
6. 前端推荐流程
学生端:
- 登录后调用
GET /onboarding/companies/{companyId}/checklist。 - 使用响应的
itemId和progressVersion调用完成状态接口。 - 收到
10505时重新读取清单,避免覆盖其他设备的新状态。 - 调用
GET /onboarding/companies/{companyId}/knowledge展示企业介绍与评价摘要。 - 当
reviewSummary.state=EMPTY/INSUFFICIENT时,不展示平均值、分布和维度均值。
企业端:
- 登录后调用
GET /onboarding/company/checklist-items获取当前版本。 - 新增时生成稳定
idempotencyKey并保存到重试请求中。 - 更新或删除前使用最新
version,冲突后重新拉取列表。 - 调用
GET /onboarding/company/knowledge获取配置版本,再使用PUT保存。 - 收到
10503时停止自动新增;收到10504时不要复用旧请求体。