# sub-implementer-backend-1 — ĐỢT 1 (hạng mục F + schema F6)

> run `2026-07-27-S155-pe-delete-approver` · vai `implementer-backend` · spec canonical = `spec-pe-delete-approver.md` PHẦN II + checklist mục 1-2
> Ghi TRONG LÚC LÀM (bài học #53). Trạng thái cập nhật dần từ trên xuống.

## Phạm vi nhận (theo TASK)

| # | Mục | Trạng thái |
|---|---|---|
| 1 | `ApprovalWorkflowLevel += AllowApproverDelete` (F6) | ⏳ |
| 2 | Migration `AddPeAllowApproverDelete` (3-file rule) | ⏳ |
| 3 | F-10 vá comment sai `ApprovalWorkflow.cs:81-82` | ⏳ |
| 4 | F-1..F-4 + F-1a/b/c `UpdateAwDefinitionCommand` | ⏳ |
| 5 | F-5/F-5a hạng NỬA (bớt người / đổi ApproverUserId) | ⏳ |
| 6 | F-6 message 403 in GUID → tên người | ⏳ |

KHÔNG làm: nút xóa FE · menu · màn "Đã xóa" · F-9 usage-check DeleteAwDefinition · F-11 (FE) · F-7/F-8 (FE).

---

## PHẦN 0 — Khảo sát nền (đọc trước khi viết dòng nào)

Số đo lấy từ đĩa, KHÔNG lấy từ memoryPack:

| Sự kiện | Bằng chứng |
|---|---|
| 8 cờ Allow* per-Level hiện có (F1×4, F3, F4, F2, F5) | `src/Backend/SolutionErp.Domain/ApprovalWorkflowsV2/ApprovalWorkflow.cs:104-142` |
| EF `HasDefaultValue` cho từng cờ | `.../Configurations/ApprovalWorkflowConfiguration.cs:80-103` |
| KHÔNG tồn tại lệnh Update — admin V2 chỉ 4 việc | `ApprovalWorkflowV2AdminFeatures.cs` (Get :101 · Create :238 · SetUserSelectable :384 · Delete :404) |
| POST tự tăng Version + hạ IsActive mọi bản cùng type | `:325-328` · `:331-334` · new `ApprovalWorkflow{}` `:336` |
| 3 verb ghi controller đều `[Authorize(Policy="Workflows.Create")]`; class chỉ `[Authorize]` trần `:18` | `ApprovalWorkflowsV2Controller.cs:29 / :40 / :48` |
| Con trỏ LAI: StepIndex = INDEX list sort · LevelOrder = so GIÁ TRỊ | `PurchaseEvaluationWorkflowService.cs:686` · `:689-695` |
| 403 in GUID trần | `PurchaseEvaluationWorkflowService.cs:701-707` (`string.Join(", ", allowedUserIds)`) |

**🔴 Phát hiện MỚI (chưa có trong spec/memoryPack) — quyết định cài đặt F-5/F-5a phụ thuộc nó:**

1. **7 bảng LevelOpinion** FK `ApprovalWorkflowLevelId` chứ không phải 1 (PE + Contract + Proposal + Leave + Ot + Travel + VehicleBooking) — grep `ApprovalWorkflowLevelId` trong `Domain/` ra 7 entity. Chặn-lịch-sự chỉ soi PE ⇒ **vẫn nổ FK 547** khi workflow thuộc module Văn phòng số (khớp §F.3 blast-radius ≥6 module).
2. **CẢ 7 LevelOpinion đều là `AuditableEntity`** (không phải BaseEntity) — vd `PurchaseEvaluationLevelOpinion.cs`, `ProposalLevelOpinion.cs:16`. Hệ quả: `Remove()` một opinion **KHÔNG xoá cứng** — `AuditingInterceptor.cs` đổi `Deleted→Modified` ⇒ row Ở LẠI ⇒ **FK vẫn Restrict**. Muốn dọn rác phải `ExecuteDeleteAsync()` (bypass change-tracker).
3. **Chỉ PE + Contract có `HasQueryFilter(!IsDeleted)`**; Proposal/Leave/Ot/Travel/VehicleBooking **KHÔNG** có (grep `HasQueryFilter` toàn `Configurations/` = 16 hit, 0 hit cho 5 bảng Office). ⇒ F-5a "loại trừ opinion của phiếu đã IsDeleted" **phải viết `!p.IsDeleted` TƯỜNG MINH**, không được dựa global filter (dựa filter ⇒ đúng cho PE, SAI cho 5 module Office).
4. `Microsoft.EntityFrameworkCore.Relational 10.0.6` đã có trong `SolutionErp.Application.csproj:13` ⇒ `ExecuteDeleteAsync` dùng được ở tầng Application.

---
