[CLAUDE] Docs: S51 P11-C Vehicle+Driver + gotcha #57 (3 HRM catalog) closeout
STATUS/HANDOFF S51 (Mig 43->45, tables 91->92, test 181->186, bundle Cg9mvltU/YgqDvsqr, P11-C DONE) + gotchas #57 ext (2->3 HRM catalog Mig 45 + Master ext backlog Mig 46 worktree) + session log 2026-06-08-S51. Agent-memory flush (impl-be/fe + test + cicd + investigator self-write; reviewer em-main proxy [return truncated gotcha #53]). CI-skip (docs/.md only). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -1044,7 +1044,7 @@ for h in resp.points: # ← .points không phải iterable trực tiếp
|
||||
|
||||
---
|
||||
|
||||
### 57. Soft-delete entity + UNIQUE index PHẢI filter `[IsDeleted] = 0` (Session 45)
|
||||
### 57. Soft-delete entity + UNIQUE index PHẢI filter `[IsDeleted] = 0` (Session 45, ext S51)
|
||||
|
||||
**Triệu chứng:** Entity soft-delete (AuditableEntity) có UNIQUE index trên business key (Code / composite). Handler check trùng đã loại soft-deleted (`AnyAsync(x => x.Key == k && !x.IsDeleted)`) → định cho phép reuse slot. NHƯNG nếu DB UNIQUE index KHÔNG filter → xoá (soft) 1 row rồi tạo lại cùng key → handler PASS app-check nhưng `SaveChangesAsync` ném `DbUpdateException` (SQL Server 2627 / SQLite Error 19) → HTTP **500** (không phải Conflict sạch hay insert OK). Reachable thật: admin xoá nhầm 1 ngày lễ / mã catalog rồi nhập lại đúng.
|
||||
|
||||
@ -1052,7 +1052,9 @@ for h in resp.points: # ← .points không phải iterable trực tiếp
|
||||
|
||||
**Fix:** EF config filtered index — `e.HasIndex(x => x.Key).IsUnique().HasFilter("[IsDeleted] = 0")` (composite: `new { x.A, x.B }`). Migration DropIndex + CreateIndex(filter). SQL Server + SQLite test đều honor (bracket-quote + partial index OK).
|
||||
|
||||
**Đã áp 13× sẵn:** Catalogs ×4, Contract/PE/Proposal/Budget/WorkflowApps code-unique. **Fixed S45:** Holiday `(Year,Date)` Mig 43. ⚠️ **CÒN unfiltered (backlog test-before):** `LeaveTypeConfiguration.cs` Code + `ShiftPatternConfiguration.cs` Code — cùng bug class.
|
||||
**Đã áp sẵn:** Catalogs ×4, Contract/PE/Proposal/Budget/WorkflowApps code-unique. **Fixed S45:** Holiday `(Year,Date)` Mig 43. **Fixed S51 (Mig 45 `FilterHrmCatalogUniqueIndexesByIsDeleted`):** LeaveType + ShiftPattern + **OtPolicy** Code = **3 HRM catalog** (OtPolicy bị BỎ SÓT khỏi backlog "2 catalog" — bắt được khi grep TOÀN BỘ config). Vehicle/Driver (Mig 44) filtered day-1. ✅ test-before `HrmConfigFilteredUniqueTests.cs` (5 case, RED→GREEN).
|
||||
|
||||
⚠️ **EXT backlog (worktree session S51, Mig 46):** **FIX 3 (Master)** `Department`/`Supplier`/`Project` Code — CONFIRMED-reachable: AuditableEntity + GLOBAL `HasQueryFilter(!IsDeleted)` auto-ẩn soft-deleted khỏi Create check → check PASS → unfiltered index ném 500 (nghịch lý: global filter LÀM lộ bug, ngược HRM cần manual `!IsDeleted`). **SKIP 3** (audit-verified KHÔNG reachable): ContractClause (no CRUD handler — chỉ DbSet), MeetingRoom (Delete set `IsActive=false` NOT IsDeleted), EmployeeProfile (Create chặn reuse by-design — UserId ConflictException "Cần khôi phục" + EmployeeCode auto-gen atomic). Mọi bare-unique khác = composite junction / nullable-code đã `IS NOT NULL` filter / no-soft-delete.
|
||||
|
||||
**References:** Mig 43 `FilterHolidayUniqueIndexByIsDeleted` · `HolidayConfiguration.cs` · `HrmConfigHolidayTests.cs` Case 7 · surfaced bởi test-specialist Gap1 S45.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user