10 changed files with 4485 additions and 1891 deletions
@ -0,0 +1,81 @@ |
|||
# W3 T7 Review: Onboarding End-to-End and Gap Tests |
|||
|
|||
## Verdict |
|||
|
|||
- **Spec compliance:** PASS |
|||
- **Task quality:** Approved |
|||
- **Overall:** PASS |
|||
- **Base:** `97b3b16` |
|||
- **Head:** `73afd87` |
|||
- **Blocking findings:** none |
|||
- **Cannot verify from this task alone:** real MySQL 8.4 execution remains a later verification-gate obligation. |
|||
|
|||
## Verification |
|||
|
|||
- Read `task-reviewer-prompt.md`, `writing-good-tests.md`, the T7 brief, execution contract, both onboarding specs, the full `97b3b16..73afd87` diff, and the complete changed test files where the diff output was truncated. |
|||
- Scope check: `git diff --name-only 97b3b16..73afd87` contains no `mydreamjob-server/src/main/**` files. The T7 implementation scope is limited to three test files plus workflow/review artifacts. |
|||
- Ran `OnboardingEndToEndIntegrationTest,CompanyKnowledgeServiceTest,OnboardingRepositoryIntegrationTest`: `Tests run: 30, Failures: 0, Errors: 0, Skipped: 0`, `BUILD SUCCESS`. |
|||
- Ran `Onboarding*Test,CompanyKnowledge*Test`: `Tests run: 96, Failures: 0, Errors: 0, Skipped: 0`, `BUILD SUCCESS`. |
|||
- Ran `OnboardingEndToEndIntegrationTest` with JUnit random method ordering: `Tests run: 7, Failures: 0, Errors: 0, Skipped: 0`, `BUILD SUCCESS`. |
|||
- Scoped `git diff --check 97b3b16..73afd87 -- <three T7 test files>` passed. Range-wide `git diff --check` reports two pre-existing blank lines at EOF in `W2-T4.md` and `W2-T5.md`, outside T7. |
|||
|
|||
## Spec Compliance |
|||
|
|||
- All nine distinct onboarding paths are exercised through the full Spring context, MockMvc, JWT filter, H2 `MODE=MySQL`, repositories, and DTO serialization: `OnboardingEndToEndIntegrationTest.java:82-212`. |
|||
- Student fallback and merged-company behavior are covered: standard-only after soft deletion, `customized=false`, merged standard/company items, source values, completion count, and rate (`:135-167`, `:202-208`). |
|||
- Student absolute-state completion behavior is covered end to end: first completion, idempotent replay with a stale version, cancellation clearing `completedAt`, stale-version conflict, persisted row count, and unchanged state after conflict (`:214-264`). |
|||
- Company checklist behavior is covered end to end: list, create, idempotent replay, request-hash conflict, 50-active-item boundary, update, soft delete, repeated delete, cross-company update/delete isolation, and state preservation (`:266-364`). |
|||
- Company knowledge behavior is covered across `BASIC_ONLY`, `CONFIGURED`, `EMPTY`, exact two-review `INSUFFICIENT`, and `SUFFICIENT`, including absence of aggregates below three reviews (`:366-441`). |
|||
- Public-review filtering excludes `HIDDEN` and non-public moderation states from counts, tags, ratings, and dimension aggregates. Repository coverage is explicit at `OnboardingRepositoryIntegrationTest.java:267-301`; the E2E flow also adds hidden/pending records before asserting the visible totals and aggregates (`OnboardingEndToEndIntegrationTest.java:410-440`). |
|||
- Anonymous 401, wrong-role 403, and missing-company/item 404 paths are covered across the endpoint families, with database-state assertions after failures (`OnboardingEndToEndIntegrationTest.java:443-543`). |
|||
- Response privacy checks run for every success and error response and cover owner/student IDs, moderation reason, request/content/identity hashes, IP/User-Agent, password/token fields, phone, email, and idempotency keys (`OnboardingEndToEndIntegrationTest.java:545-577`). |
|||
- The focused service tests cover the exact two-review threshold, all eight dimension summaries, deterministic tag top-ten limiting, and recursively quoted JSON tags (`CompanyKnowledgeServiceTest.java:292-358`). |
|||
|
|||
## Test Falsifiability |
|||
|
|||
- The E2E tests assert externally observable HTTP status, response JSON, persisted row state, and cross-company ownership effects. They would fail for incorrect routing, authorization, fallback, merging, version handling, soft-delete behavior, or aggregate filtering. |
|||
- The threshold tests independently assert the absence of aggregates at zero, one, and two public reviews, and their presence at three. A change to the threshold or query filtering would fail them. |
|||
- The repository test independently verifies `PUBLISHED` plus approved moderation filtering and excludes `HIDDEN` records from all aggregate queries. A filter regression would fail the counts, tags, and dimension sample assertions. |
|||
- The privacy helper checks serialized response bodies rather than trusting service DTO construction alone. |
|||
- The randomized-order E2E run passed without reliance on wall-clock precision, external services, or test-order state. |
|||
|
|||
## Strengths |
|||
|
|||
- The new E2E test uses the real application context and persistence layer, not mocked controllers or repositories. |
|||
- Error-path state preservation is asserted at the database level, not only through HTTP status codes. |
|||
- The coverage combines a broad endpoint contract flow with focused service/repository tests for threshold, tag, and moderation-filter edge cases. |
|||
- No production files were changed; the task stayed within the intended test-hardening scope. |
|||
|
|||
## Issues |
|||
|
|||
### Critical (Must Fix) |
|||
|
|||
None. |
|||
|
|||
### Important (Should Fix) |
|||
|
|||
None. |
|||
|
|||
### Minor (Nice to Have) |
|||
|
|||
- `OnboardingEndToEndIntegrationTest.java:82-212` combines success checks for all nine endpoints into one long flow. It is correct, but a failure gives a broad diagnosis surface. Splitting the endpoint families into smaller E2E tests would improve failure isolation without changing behavior. |
|||
- `OnboardingEndToEndIntegrationTest.java:559-576` checks sensitive fields with raw serialized-string substrings. It covers the named fields in the current contract, but a recursive JSON field-name check would be more robust if DTO serialization changes or sensitive data is nested under a renamed field. |
|||
- Tag top-ten limiting and recursively quoted JSON parsing are covered at the service layer (`CompanyKnowledgeServiceTest.java:314-358`), while the E2E flow only exercises the three-tag sufficient case (`OnboardingEndToEndIntegrationTest.java:425-434`). This is acceptable for T7 because the focused behavior is covered, but retaining an HTTP-level edge case would provide broader integration evidence. |
|||
- Non-T7 range artifact: `git diff --check 97b3b16..73afd87` reports blank lines at EOF in `W2-T4.md:94` and `W2-T5.md:75`. The three T7 test files themselves pass `git diff --check`. |
|||
|
|||
## Residual Verification Warning |
|||
|
|||
- Real MySQL 8.4 behavior has not been run in this environment. H2 `MODE=MySQL` passed; MySQL/Docker black-box verification remains owned by the later verification gate. |
|||
- The prior T6 observation about knowledge-service lock-timeout/deadlock exception mapping remains outside T7 and was not modified here. |
|||
|
|||
## Assessment |
|||
|
|||
**Task quality:** Approved |
|||
|
|||
**Reasoning:** The T7 additions provide real full-context coverage for all nine endpoints, the required fallback, idempotency, concurrency-conflict, threshold, filtering, authorization, privacy, and state-preservation behaviors. The focused and full required suites, plus randomized ordering, all pass, and no production files were changed. |
|||
|
|||
Controller receipt command when `ssf` is available: |
|||
|
|||
```bash |
|||
ssf execution review changes/n04-onboard --wave W3 --base 97b3b16 --head 73afd87 --report changes/n04-onboard/.superpowers/sdd/reviews/W3-T7.md --verdict pass |
|||
``` |
|||
@ -0,0 +1,433 @@ |
|||
# 入职清单与公司知识介绍 API(N04) |
|||
|
|||
> 状态:后端实现完成,待真实 MySQL 8.4 / Docker 黑盒验收。 |
|||
> |
|||
> 数据库迁移:`V38__onboarding_checklist_and_company_knowledge.sql`、`V39__onboarding_standard_checklist_seed.sql`。 |
|||
|
|||
## 1. Base URL 与认证 |
|||
|
|||
本地 Base URL: |
|||
|
|||
```text |
|||
http://127.0.0.1:8080/api/v1 |
|||
``` |
|||
|
|||
所有 `/onboarding/**` 接口都要求登录,并携带: |
|||
|
|||
```http |
|||
Authorization: Bearer <accessToken> |
|||
Content-Type: application/json |
|||
X-Request-Id: <optional-trace-id> |
|||
``` |
|||
|
|||
细粒度角色和所有权在 Service 层校验。除 401 外,接口统一返回 `ApiResponse`: |
|||
|
|||
```json |
|||
{ |
|||
"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` 固定为: |
|||
|
|||
```text |
|||
DOCUMENT | ADMIN | EQUIPMENT | TRAINING | LOGISTICS | OTHER |
|||
``` |
|||
|
|||
### 3.2 学生读取有效清单 |
|||
|
|||
```http |
|||
GET /api/v1/onboarding/companies/10/checklist |
|||
Authorization: Bearer <studentAccessToken> |
|||
``` |
|||
|
|||
响应: |
|||
|
|||
```json |
|||
{ |
|||
"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 更新完成状态 |
|||
|
|||
请求使用绝对状态,而不是切换: |
|||
|
|||
```http |
|||
PUT /api/v1/onboarding/companies/10/checklist/items/501/completion |
|||
Authorization: Bearer <studentAccessToken> |
|||
|
|||
{"completed": true, "version": 0} |
|||
``` |
|||
|
|||
响应: |
|||
|
|||
```json |
|||
{ |
|||
"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 企业创建自定义项 |
|||
|
|||
```http |
|||
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`: |
|||
|
|||
```json |
|||
{ |
|||
"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 企业查询、更新与软删除 |
|||
|
|||
查询本企业全部条目: |
|||
|
|||
```http |
|||
GET /api/v1/onboarding/company/checklist-items |
|||
Authorization: Bearer <companyAccessToken> |
|||
``` |
|||
|
|||
响应包含活动与软删除条目,不返回通用项和其他企业项。更新请求: |
|||
|
|||
```http |
|||
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`。软删除: |
|||
|
|||
```http |
|||
DELETE /api/v1/onboarding/company/checklist-items/501?version=1 |
|||
Authorization: Bearer <companyAccessToken> |
|||
``` |
|||
|
|||
首次删除必须使用当前版本,系统只将 `active=false`,不物理删除。重复删除已非活动条目保持幂等成功;接口仍要求携带 `version` 查询参数。 |
|||
|
|||
## 4. 公司知识介绍语义 |
|||
|
|||
### 4.1 学生读取与回退 |
|||
|
|||
```http |
|||
GET /api/v1/onboarding/companies/10/knowledge |
|||
Authorization: Bearer <studentAccessToken> |
|||
``` |
|||
|
|||
响应: |
|||
|
|||
```json |
|||
{ |
|||
"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 企业查询知识配置 |
|||
|
|||
```http |
|||
GET /api/v1/onboarding/company/knowledge |
|||
Authorization: Bearer <companyAccessToken> |
|||
``` |
|||
|
|||
未配置时: |
|||
|
|||
```json |
|||
{ |
|||
"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 企业创建或更新知识配置 |
|||
|
|||
```http |
|||
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`: |
|||
|
|||
```json |
|||
{"code": 401, "message": "not authenticated", "timestamp": ""} |
|||
``` |
|||
|
|||
其他错误示例: |
|||
|
|||
```json |
|||
{ |
|||
"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` 时不要复用旧请求体。 |
|||
File diff suppressed because it is too large
Loading…
Reference in new issue