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.
 
 
 

14 KiB

入职清单与公司知识介绍 API(N04)

状态:后端实现完成,待真实 MySQL 8.4 / Docker 黑盒验收。

数据库迁移:V38__onboarding_checklist_and_company_knowledge.sql、V39__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 角色的账号访问。
  • COMPANY 接口不接受 companyId;服务端从 JWT 用户解析其所属企业,避免跨企业写入。
  • ADMIN 没有 onboarding 专属管理接口;调用 STUDENT/COMPANY 接口时按非目标角色返回 403/2002。
  • 学生访问企业清单或知识不要求先有 Offer 或投递记录,但目标企业必须存在。
  • 企业条目不存在或属于其他企业时统一返回 404/9701,不泄露其他企业数据。

3. 入职清单语义

3.1 通用项与自定义项合并

有效清单由以下两部分组成:

  1. 所有活动通用项 source=STANDARD;V39 固定写入 12 条。
  2. 当前企业所有活动自定义项 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/9705。
  • 重复提交相同 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/9703。

幂等重试:

  • 同一企业、同一 idempotencyKey、同标题/说明/分类/排序/必填值:返回首次创建的条目。
  • 同一企业、同一 key、请求语义不同:返回 409/9704。
  • 不同企业可使用相同 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/9702。软删除:

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/9706。
  • 已有内容与提交内容相同且未传版本时按幂等读取处理;内容不同但未传版本返回 400/1001。

5. 错误码

HTTP code 含义 前端处理
400 1001 参数、枚举、长度、HTML、缺少必填字段 展示字段错误,不自动重试
401 401 未登录或 Token 无效 清理登录态并重新登录
403 2002 角色不匹配、无所属企业或无权限 不重试,切换到正确角色
404 5001 企业不存在或 COMPANY 无绑定企业 检查 companyId 或企业绑定状态
404 9701 清单项不存在、跨企业或不属于有效清单 刷新清单后重新选择条目
409 9702 企业清单项版本过期 重新 GET /company/checklist-items,使用新版本重试
409 9703 活动自定义项达到 50 条上限 禁用新增,提示先软删除或复用现有项
409 9704 幂等键已用于不同请求体 更换幂等键,或确认原请求后读取原条目
409 9705 学生完成状态版本过期 重新读取有效清单并使用新 progressVersion
409 9706 公司知识版本过期 重新读取企业知识配置并使用新 version

401 由安全过滤器返回裸 JSON,没有统一 ApiResponse.requestId:

{"code": 401, "message": "not authenticated", "timestamp": ""}

其他错误示例:

{
  "code": 9704,
  "message": "idempotency key conflict: request body differs",
  "data": null,
  "requestId": "req-9704",
  "timestamp": "2026-09-17T01:30:00Z"
}

6. 前端推荐流程

学生端:

  1. 登录后调用 GET /onboarding/companies/{companyId}/checklist。
  2. 使用响应的 itemId 和 progressVersion 调用完成状态接口。
  3. 收到 9705 时重新读取清单,避免覆盖其他设备的新状态。
  4. 调用 GET /onboarding/companies/{companyId}/knowledge 展示企业介绍与评价摘要。
  5. 当 reviewSummary.state=EMPTY/INSUFFICIENT 时,不展示平均值、分布和维度均值。

企业端:

  1. 登录后调用 GET /onboarding/company/checklist-items 获取当前版本。
  2. 新增时生成稳定 idempotencyKey 并保存到重试请求中。
  3. 更新或删除前使用最新 version,冲突后重新拉取列表。
  4. 调用 GET /onboarding/company/knowledge 获取配置版本,再使用 PUT 保存。
  5. 收到 9703 时停止自动新增;收到 9704 时不要复用旧请求体。