轻松聘AI开发
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.
 
 
 

8.6 KiB

举报与屏蔽 API(V33)

版本:V33 实现版 状态:已编码实现,待黑盒验收 适用范围:举报、屏蔽、ADMIN 举报处理;仅允许对 MessagingService 增加屏蔽校验。 OpenAPI 117 → 125 paths(新增 8 path / 9 operation)。

1. 定位与边界

接口 / 模块 是否改动 关系
投递、Offer、面试、评分、治理、看板、匹配 不改 屏蔽不影响系统通知、投递、Offer、面试、评分、评价
MessagingService 仅改两方法 createOrGetDirectConversation、sendMessage 增加屏蔽校验
listMessages / getConversation / listConversations 不改 历史消息不删除,按现有权限读取
NotificationService 不改语义 复用,处理完成后向举报人发送通知,不新增 NotificationType 枚举
AI 自动审核 / 自动封禁 / 自动警告 / 公平性算法 不实现 本轮明确排除

2. 数据库(V33,三张表)

  • reports:举报单。(reporter_user_id, idempotency_key) 唯一;active_key 唯一;target_type 仅 USER/MESSAGE;status 仅 PENDING/RESOLVED/REJECTED;message_id 外键 ON DELETE SET NULL;reporter_user_id/reported_user_id 外键关联 users;@Version 乐观锁;evidence_urls 使用 TEXT 存 JSON 字符串(不采用 MySQL JSON 列)。
  • block_relations:(blocker_user_id, blocked_user_id) 唯一;禁止自己屏蔽自己;外键 ON DELETE CASCADE。
  • report_decision_history:report_id 外键 ON DELETE CASCADE;记录 from_status → to_status、操作人、角色、note。

约束强校验:target_type=USER 时 target_user_id 非空且 message_id 为空;target_type=MESSAGE 反之。

3. 举报接口

POST /reports           提交举报
GET  /reports/me        我的举报列表(status/page/size)
GET  /reports/{id}      举报详情(本人或 ADMIN)
  • 身份全取 JWT,不接受 userId/reporterId/reportedUserId 注入。
  • USER 举报:客户端传 targetUserId,服务端校验存在,targetUserId ≠ 本人,reportedUserId = targetUserId。
  • MESSAGE 举报:仅传 messageId,服务端校验存在 + 本人是会话参与者(无权返回 403/2002,不泄露消息是否存在),reportedUserId 从消息真实 sender 推导,禁止客户端覆盖。
  • 路由:/reports/me 必须在 /reports/{id} 之前注册,并有路由回归测试。

幂等与防重:

场景 行为
同 reporter + idempotencyKey + 相同请求体 返回原举报,200(不新增)
同 reporter + idempotencyKey + 不同请求体 409 / 9606
同 reporter + 同目标 + 同 category + 同 messageId/targetUserId + 已有 PENDING 409 / 9603
已 RESOLVED/REJECTED 不占用 active_key,允许重新提交

evidenceUrls 校验:最多 5 个、每个 ≤500 字符、仅 http/https;后端不主动请求/抓取 URL(防 SSRF)。

4. 屏蔽接口

PUT    /blocks/{blockedUserId}   屏蔽
DELETE /blocks/{blockedUserId}   解除屏蔽(幂等)
GET    /blocks/me                我的屏蔽列表(page/size)
  • 屏蔽自己 → 400 / 9608;目标不存在复用以有用户不存在错误码。
  • PUT 已存在返回 200 不新增;DELETE 不存在返回 200 不报错;GET 仅返回本人主动屏蔽的用户。
  • 响应不返回对方手机号/邮箱/密码/简历地址。
  • 屏蔽不影响系统通知、投递、Offer、面试、评分、评价。

5. MessagingService 屏蔽控制

  • createOrGetDirectConversation:若 A 屏蔽 B 或 B 屏蔽 A 任一方向存在,禁止新建 DIRECT 会话。
  • sendMessage:会话内任一方向存在屏蔽,禁止发送新消息。
  • 对外统一 403 / 2002 / "message cannot be sent",不返回“你已被屏蔽”,不泄露哪一方屏蔽了谁。
  • 内部审计记录 BLOCKED_SEND_PROHIBITED。
  • 屏蔽期间发送失败的消息直接丢弃,解除屏蔽后不补发。
  • listMessages、getConversation、listConversations 保持现有语义。

6. ADMIN 举报处理接口

GET  /admin/reports                    举报列表(status/targetType/category/page/size)
GET  /admin/reports/{id}               举报详情(含处理历史、脱敏证据 URL、MESSAGE 脱敏内容)
POST /admin/reports/{id}/decision      处理决定
  • 仅 ADMIN;COMPANY / STUDENT / 未登录分别 403 / 403 / 401。
  • decision 仅 RESOLVED / REJECTED;REJECTED 必填 note。
  • 仅 PENDING 可处理,重复 → 409 / 9604;非法流转 → 409 / 9605;乐观锁冲突 → 409 / 9605。
  • 处理不自动封禁、不删除消息、不修改投递/面试/评分状态。
  • 权限矩阵:
身份/场景 HTTP code
未登录 401 2001
COMPANY / STUDENT 403 2002
ADMIN 200 —
非本人非 ADMIN 查详情 403 2002
举报不存在 404 9601

7. 错误码

code 枚举 HTTP 说明
9601 REPORT_NOT_FOUND 404 举报不存在
9602 CANNOT_REPORT_SELF 400 不能举报自己
9603 REPORT_DUPLICATE 409 同目标同分类已有 PENDING
9604 ALREADY_DECIDED 409 重复决定
9605 INVALID_TRANSITION 409 非法流转 / 乐观锁冲突
9606 IDEMPOTENCY_CONFLICT 409 幂等键冲突(不同请求体)
9607 REASON_REQUIRED 400 理由缺失(注意复用 BAD_REQUEST 由校验层触发)
9608 CANNOT_BLOCK_SELF 400 不能屏蔽自己
9609 REPORT_RATE_LIMITED 429 举报频率超限
9610 BLOCKED_SEND_PROHIBITED 内部 仅内部审计/日志,HTTP 不直接暴露

复用:BAD_REQUEST(1001)、UNAUTHORIZED(2001)、FORBIDDEN(2002)、用户/消息不存在错误码。

8. 举报限流

  • 使用现有 Redis,不新增数据库表;仅限制 POST /reports。
  • 每用户默认每小时最多 10 次;key:report:rate:{userId}:{hour}。
  • 超限 → 429 / 9609,记录 REPORT_RATE_LIMITED 审计。
  • 不影响屏蔽、查询、ADMIN 处理接口;不实现自动封禁。

9. 通知闭环

  • 处理完成后向举报人发送一条通知,复用 NotificationService,不新增枚举。
  • type=REPORT_DECISION、businessType=REPORT、businessId=reportId、idempotencyKey=report-decision-{reportId}。
  • RESOLVED / REJECTED 均可通知;同一举报最多一条处理结果通知(幂等)。
  • 举报提交时不通知被举报人,不通知被举报人的联系方式。

10. 审计

新增 action:REPORT_CREATED、REPORT_DECIDED、BLOCK_CREATED、BLOCK_REMOVED、BLOCKED_SEND_PROHIBITED、REPORT_RATE_LIMITED。

details 仅含:reportId、userId、category、decision、targetType、messageId、requestId、timestamp。 禁止写入:phone、email、password、JWT、resumeUrl、消息全文、文件绝对路径、evidence 文件内容、数据库连接信息。

11. 并发与幂等

  • 举报:(reporter_user_id, idempotency_key) 唯一 + active_key 唯一 + 创建事务;并发重复仅一条成功,另一条 9603 或同幂等返回原记录。
  • 屏蔽:唯一约束保证并发 PUT 不产生重复关系;DELETE 幂等;屏蔽检查与发送消息在同一业务事务内。
  • 处理:@Version 乐观锁,冲突 409/9605。

12. 脱敏策略

  • 响应永不返回 phone、email、passwordHash、resumeUrl、JWT、消息全文、举报人内部 ID(非 ADMIN)。
  • MESSAGE 举报仅返回脱敏 messagePreview,不返回会话内其他敏感内容。
  • 对外屏蔽发送统一模糊错误,不泄露屏蔽关系方向。

13. OpenAPI 变化

  • 新增 8 path / 9 operation,117 → 125 paths。
  • 新 path:/reports、/reports/me、/reports/{id}、/blocks/{blockedUserId}(PUT+DELETE)、/blocks/me、/admin/reports、/admin/reports/{id}、/admin/reports/{id}/decision。
  • 声明:bearerAuth、请求/响应 DTO、USER/MESSAGE 枚举、PENDING/RESOLVED/REJECTED 枚举、400/401/403/404/409/429、屏蔽模糊错误、MESSAGE 需 messageId、USER 需 targetUserId。

14. 测试覆盖要点

  1. USER 举报;2. MESSAGE 举报;3. MESSAGE 发送者服务端推导;4. 无权访问 messageId;5. 举报自己;6. 不存在 targetUserId;7. evidenceUrls 校验;8. 幂等同请求体;9. 幂等不同请求体;10. PENDING 重复;11. ADMIN 决定;12. 重复决定;13. 决定历史;14. 屏蔽/解除;15. 重复屏蔽/解除;16. 屏蔽后禁止 DIRECT;17. 屏蔽后禁止发送;18. 历史消息可读;19. 失败消息不补发;20. 频率限制;21. 通知幂等;22. 权限矩阵;23. 脱敏;24. 乐观锁并发;25. 业务数据不删除;26. V33 迁移 H2(MODE=MySQL)/MySQL 兼容。