wal: flush 20260729T2300
This commit is contained in:
@ -0,0 +1,40 @@
|
||||
# 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.md`
|
||||
> Luật lượt này: BE-only · 0 mig · KHÔNG commit/push/slnx · KHÔNG viết test (đợt-2) · KHÔNG đụng `fe-*/` · KHÔNG đụng Reject `:49-66` (O-A) · KHÔNG đụng `ContractSigningPlan*` (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-442` là `PhaseActorRoles` của inbox — call-site THỨ 4 của nhánh phase, không phải của `GetEligiblePhases`)*
|
||||
|
||||
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)` + `isDraftPhase` S89)
|
||||
- PE inbox admin phase liệt tường minh: `PurchaseEvaluationFeatures.cs:731-742` (+ `ChoDuyet` `:740`)
|
||||
- PE `v2InboxIds` rỗng cho admin: `PurchaseEvaluationFeatures.cs:746-748`
|
||||
- PE `ResolveV2InboxIdsAsync` in-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:44` `b.HasQueryFilter(x => !x.IsDeleted)` ⇒ `db.Contracts` mặc-định ĐÃ loại HĐ xóa mềm ⇒ inbox + list + `ResolveV2InboxIdsAsync` tự an-toàn, KHÔNG cần `.Where(!IsDeleted)` tay (khác HRM).
|
||||
- `Contract.cs:23/40/46` có đủ `ApprovalWorkflowId` / `CurrentWorkflowStepIndex` / `CurrentApprovalLevelOrder`; `:16` `DrafterUserId`.
|
||||
- `BaseEntity.CreatedBy` kiểu **`Guid?`** (không phải string) ⇒ so trực tiếp với `actorUserId`.
|
||||
- `grep tests/` cho `ContractV2Pipeline|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.
|
||||
|
||||
---
|
||||
Reference in New Issue
Block a user