3.7 KiB
3.7 KiB
sub-implementer-backend-0 — W6 Đường ống HĐ V2 (view + inbox + vai-trình)
Run:
2026-07-29-S161-khkk-w6-duongong· Spec:.claude/workflows/runs/2026-07-29-S160-khkk-dryrun-plan/spec-wave-w6-duong-ong-hd-v2-29-07-2026.mdLuật lượt này: BE-only · 0 mig · KHÔNG commit/push/slnx · KHÔNG viết test (đợt-2) · KHÔNG đụngfe-*/· KHÔNG đụng Reject:49-66(O-A) · KHÔNG đụngContractSigningPlan*(KHKK W1-W3 đã ship). Ghi TỪNG MỤC trong lúc làm (chống #53).
§0 — ĐO TRƯỚC KHI SỬA (gate 5-anchor, đọc tươi 2026-07-29)
| Anchor (spec §③-A) | Đo thật | Khớp? | Nội dung |
|---|---|---|---|
ContractFeatures.cs:334-351 |
:334 internal static List<ContractPhase> GetEligiblePhases(IReadOnlyList<string> userRoles) … :351 return phases.ToList(); |
✅ | chữ ký CHỈ nhận role ⇒ không biết HĐ nào |
ContractFeatures.cs:421-430 |
:421 private static readonly Dictionary<ContractPhase, string[]> PhaseActorRoles = new() … :430 [DangDongDau] = [HrAdmin], |
✅ | 7 key, 0 key ChoDuyet |
ContractFeatures.cs:488-489 |
:488 if (!isDrafter && !isEligibleByRole) :489 throw new ForbiddenException("Bạn không có quyền xem HĐ này.") |
✅ | 403 detail |
ContractWorkflowService.cs:73-78 |
:73 if (!isAdmin && !isSystem :74 && !actorRoles.Contains(AppRoles.Drafter) :75 && !actorRoles.Contains(AppRoles.DeptManager)) :77-78 throw Forbidden "không đủ quyền trình duyệt HĐ." |
✅ | guard trình |
ContractsController.cs:38-40 |
:38 [HttpGet("inbox")] :39 Inbox(CancellationToken ct) :40 => Ok(await mediator.Send(new GetMyInboxQuery(), ct)); |
✅ | endpoint inbox |
Gate 5-anchor: PASS 5/5 content-exact.
3 call-site GetEligiblePhases (grep src/Backend, đủ 3 — risk C "sửa chỉ 1/3"):
ContractFeatures.cs:301—ListContractsQueryHandler(List)ContractFeatures.cs:381—ListDeletedContractsQueryHandler(ListDeleted,IgnoreQueryFilters().Where(IsDeleted))ContractFeatures.cs:486—GetContractQueryHandler(Detail)- (
:441-442làPhaseActorRolescủa inbox — call-site THỨ 4 của nhánh phase, không phải củaGetEligiblePhases)
Khuôn nguồn để mirror (đọc tươi):
- PE detail V2-approver:
PurchaseEvaluationFeatures.cs:886-898(AnyAsync(l => l.Step!.ApprovalWorkflowId == awId && l.ApproverUserId == uid)+isDraftPhaseS89) - PE inbox admin phase liệt tường minh:
PurchaseEvaluationFeatures.cs:731-742(+ChoDuyet:740) - PE
v2InboxIdsrỗng cho admin:PurchaseEvaluationFeatures.cs:746-748 - PE
ResolveV2InboxIdsAsyncin-memory join:PurchaseEvaluationFeatures.cs:817-852 - KHKK (chính tao viết W2):
ContractSigningPlanFeatures.cs:229-264(Resolve) +:275-283(ResolveUserApprovalWorkflowIdsAsync)
Nền tảng đã verify TRƯỚC khi code (chống bẫy "quên lọc IsDeleted" — risk C):
ContractConfiguration.cs:44b.HasQueryFilter(x => !x.IsDeleted)⇒db.Contractsmặc-định ĐÃ loại HĐ xóa mềm ⇒ inbox + list +ResolveV2InboxIdsAsynctự an-toàn, KHÔNG cần.Where(!IsDeleted)tay (khác HRM).Contract.cs:23/40/46có đủApprovalWorkflowId/CurrentWorkflowStepIndex/CurrentApprovalLevelOrder;:16DrafterUserId.BaseEntity.CreatedBykiểuGuid?(không phải string) ⇒ so trực tiếp vớiactorUserId.grep tests/choContractV2Pipeline|GetMyInboxQuery|ListContractsQuery|GetContractQuery= 0 hit ⇒ 3 handler này hiện KHÔNG có test cũ nào bám ⇒ sửa không thể phá test cũ qua đường assert; rủi ro duy nhất là compile + suite tổng.