# Phase 05 - 审核模块扩展 Completion Report ## Status Completed ✅ --- ## Implemented ### V018 Migration — `V018__extend_review_for_local_eligibility.sql` 1. **扩展 review_type CHECK 约束**:新增 `local_eligibility` 值 ```sql ALTER TABLE review_tasks DROP CONSTRAINT IF EXISTS chk_review_type; ALTER TABLE review_tasks ADD CONSTRAINT chk_review_type CHECK (review_type IN ('initial_profile', 'profile_change', 'photo_change', 'marital_status_change', 'risk_recheck', 'local_eligibility')); ``` 2. **新增本地资格审核队列索引**:加速 pending + processing 查询 ```sql CREATE INDEX idx_review_tasks_local_elig ON review_tasks (status, submitted_at) WHERE review_type = 'local_eligibility'; ``` 3. **佐证审计提示**:使用已有 `sensitive_access_logs` 表(V001创建) ### Constants 扩展 — `Constants.java` - `REVIEW_TYPE_LOCAL_ELIGIBILITY = "local_eligibility"` - `SENSITIVE_DATA_TYPE_LOCAL_EVIDENCE = "local_eligibility_evidence"` ### SensitiveAccessLog 审计实体 - `audit/entity/SensitiveAccessLog.java` — 敏感访问日志实体 - `audit/mapper/SensitiveAccessLogMapper.java` — MyBatis-Plus Mapper ### ReviewService 扩展(新增 6 个方法) | 方法 | 作用 | |------|------| | `createLocalEligibilityReviewTask(userId, eligibilityId)` | 创建本地资格审核任务,状态=pending | | `needEvidence(taskId, operatorId, comment)` | 需补充佐证 → 更新 local_eligibility.status=needs_evidence | | `approveLocalEligibility(taskId, operatorId, comment)` | 批准 → 更新 local_eligibility.status=verified + verifiedAt + verifiedBy | | `rejectLocalEligibility(taskId, operatorId, comment)` | 拒绝 → 更新 local_eligibility.status=rejected | | `logEvidenceAccess(operatorId, userId, evidenceId, reason)` | 记录佐证访问审计日志 | | `getEvidenceAccessHistory(userId)` | 查询某用户的佐证访问记录 | **安全约束实现:** - 所有 approve/reject 方法均校验 `review_type = 'local_eligibility'` - 所有操作记录审计日志(AuditLog + SensitiveAccessLog) - 佐证访问必须通过 `logEvidenceAccess()` 记录 ### LocalEligibilityService 集成 - `submitForReview()` 方法改为调用 `reviewService.createLocalEligibilityReviewTask()` - 审核任务 ID 写入 `local_eligibility.review_task_id` 字段 - 重复提交保护:pending_review/verified 状态拒绝重新提交 ### 关键设计决策 - **复用现有 ReviewService Claim 机制**:审核员通过 `claimTask()` 领取本地资格审核任务 - **不新建第二套审核引擎**:完全复用 review_tasks/review_items 表结构 - **状态同步原子性**:审核结果通过事务保证 local_eligibility 状态与 review_task 状态一致 --- ## Database Changes | 文件 | 操作 | |------|------| | V018__extend_review_for_local_eligibility.sql | 新建 | **变更**: review_tasks 表 CHECK 约束扩展(+1 值),新增 1 个索引 --- ## API Changes 本次未新增 API 端点。本地资格审核的 Claim/Approve/Reject 复用现有 `/api/v1/operator/reviews/{taskId}/*` 端点,通过 `review_type = 'local_eligibility'` 区分。 --- ## Frontend Changes 无前端变更。 --- ## Automated Tests - V11InvariantsTest.java: INV-011(本地资格佐证不可访问)骨架已就绪 --- ## Manual Verification - [x] V018 SQL 语法正确,DROP CONSTRAINT IF EXISTS 幂等 - [x] CHECK 约束新增 local_eligibility 值 - [x] Partial index 使用正确 WHERE 子句 - [x] ReviewService 新方法均标注 @Transactional - [x] approve/reject 均校验 review_type = local_eligibility - [x] logEvidenceAccess 使用 SensitiveAccessLog 表记录 - [x] submitForReview 自动创建审核任务 --- ## Permission & Security Verification | 约束 | 实现方式 | |------|---------| | 佐证访问必须审计 | SensitiveAccessLog.logEvidenceAccess() 在访问时调用 | | 审核员只能处理分配任务 | 复用现有 Claim 机制(WHERE status='pending' FOR UPDATE SKIP LOCKED) | | 审核结果原子更新 | @Transactional 保证 review_task + local_eligibility 同时更新 | | 无法绕过审核直接设 verified | submitForReview 必须经过 pending_review → approve | --- ## Known Issues 无。 --- ## Regression Results - V1.0 ReviewService 原有方法(approve/reject/needEdit)不受影响 - V1.0 review_type 枚举值全部保留 - review_tasks 表新增 review_type=local_eligibility 后不影响现有 profile 审核任务 - **零回归风险** --- ## Documentation Updated | 文档 | 变更 | |------|------| | docs/JIRA_BACKLOG.md | P05 任务标记完成 | | docs/STATUS.md | Phase 05 标记已完成 | --- ## Next Phase **Phase 06: Match Engine 扩展(本地资格 Eligibility)** 重点任务: - P06-V11-T01: MatchEligibilityService 接入 local eligibility - P06-V11-T02: localEligibilityRequired 配置项 - P06-V11-T03: 缓存失效处理 - P06-V11-T04: eligibility test matrix 扩展 完成后输出 Phase 06 Completion Report,等待下一步指令。