[CLAUDE] Office: IT staff tự reassign ticket — authz Admin-OR-IT + capability endpoint (S54)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m17s

- BE: GetAssignableItStaffQuery {canReassign,staff} capability endpoint + AssignItTicketHandler authz Admin-OR-dept-IT (Forbidden) + assignee-must-IT (Conflict); controller /assign hạ [Authorize(Roles=Admin)]→[Authorize] (handler enforce fine-grained data-driven)
- FE: fe-admin + fe-user ItTicketsPage SHA256-identical (reverse S53 divergence), nút gate by canReassign, dropdown từ /assignable-staff (không /users)
- Test: +13 authz guard (203→216 PASS), reviewer PASS (role-string Admin chain-verified real)
- No migration (DepartmentId reuse), no menu change

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-06-08 16:12:14 +07:00
parent 18d397f095
commit ca4b60277b
13 changed files with 587 additions and 34 deletions

View File

@ -53,6 +53,7 @@ Test theo CODE (single source truth), document mismatch header comment + report.
## 📅 Recent activity (last 10 FIFO)
- **2026-06-08 (S54 ItTicket reassign authz test-before-merge SECURITY) [harvested by em main agent MEMORY write mis-landed, B2/B3]:** +13 test `tests/.../Application/ItTicketReassignAuthzTests.cs` **203→216 PASS** (58 Domain + Infra 145158, 0 fail). **GetAssignableItStaff (6):** AdminCanReassign=true + 2 IT-active ordered FullName (Cao<Truong) no KT/inactive leak · IT-stafftrue · non-IT non-admin (KT)→false + **empty staff (0-leak assert)** · dept-nullfalse+empty · inactive-IT-excluded · UserId nullUnauthorized. **AssignItTicket (7):** non-IT non-admin→**ForbiddenException** + side-effect `AssignedToUserId.Should().BeNull()` (no-mutation) · Admin+assigneeITsuccess · IT-staff+assigneeITsuccess · assigneeIT(KT)→**ConflictException** "Người được giao phải thuộc tổ IT." · assignee inactiveNotFound · ticket not foundNotFound · nullUnauthorized. **Pattern mới: authz-capability test = seed 2-dept (IT+KT) + fake `ICurrentUser` role/dept matrix; assert canReassign flag + Forbidden/Conflict guard; empty-staff = 0-leak.** Forbidden red-able **by-contrast** (case5 non-IT vs case7 IT-staff identical-setup chỉ khác caller-identity; rule cấm sửa prod để chứng minh RED). **No prod bug** handler-level data-dependent authz (caller-dept vs IT-dept) = CORRECT pattern, KHÔNG phải gotcha #44 silent-403 gap (Pattern 10 reflection-regression chỉ cho static `[Authorize(Policy)]`; data-driven authz PHẢI handler = enforcement point, test cover tại đó). Tag [s54, it-ticket-reassign, authz-capability, forbidden-conflict-guard, test-before-merge, 0-leak].
- **2026-06-08 (S52 P11-D Master gotcha #57 EXT) [test-before · 3 RED LIVE]:** +3 test `tests/.../Application/MasterCatalogFilteredUniqueTests.cs` (run `--filter MasterCatalogFilteredUnique` Failed 3/Passed 0). Department+Project+Supplier `.IsUnique()` BARE (Dept cfg:18 / Proj:19 / Supp:24) chưa `[IsDeleted]=0` cùng class gotcha #57. Mirror EXACT GROUP B HrmConfigFilteredUniqueTests: seed row `IsDeleted=true` slot Code="DUP1" `Create{Dept|Project|Supplier}CommandHandler(db)` cùng Code assert `NotThrowAsync` + active==1 + `IgnoreQueryFilters` all==2. **3 RED** = `DbUpdateException → SQLite Error 19 UNIQUE constraint failed: {Departments|Projects|Suppliers}.Code` (app-check `AnyAsync(Code==X)` chạy QUA HasQueryFilter loại soft-deleted PASS Add+SaveChanges DB UNIQUE bare đếm cả row xoá throw). NOT test lỗi REPORTED em main fix migration `.HasFilter` 3 config flip GREEN. ** all-count PHẢI `IgnoreQueryFilters()`** (khác HRM ref dùng raw `Count(Code==X)` trên DbSet đã HasQueryFilter trả 1 not 2 = sai; tôi sửa = active-count plain DbSet, all-count IgnoreQueryFilters). 3 handler clean `(IApplicationDbContext db)` 1-dep. KHÔNG đụng Configuration/Domain/migration. Tag [s52, p11-d, gotcha-57, master-catalog, filtered-unique, test-before, RED].
- **2026-06-08 (S52 P11-D Wave2 round-robin + SLA-due) [proxy by em main: agent killed session-limit trước MEMORY step]:** +9 test `ItTicketAssignSlaTests.cs` **200 PASS** (Infra 133142). **Round-robin:** seed Department Code="IT" + 2 user A/B `IsActive` trong IT + A 1 ticket Open Create assign **B** (load 0<1); tie A=B `ThenBy(Id)`; edge no-dept-IT / no-user-IT unassigned; user ngoài IT hoặc `IsActive=false` KHÔNG assign. **SLA-due:** Priority Urgent→+4h / High→+8h / Medium→+24h / Low→+72h (assert `e.SlaDueAt==CreatedAt+SlaWindow[priority]`). **Regression P11-F:** create vẫn gen `^IT/\d{4}/\d{3}$`. `ItTicketSlaJob` BackgroundService SKIP unit-test (breach-query inline, khó test trực tiếp REPORTED). Baseline 191→**200** (58 Domain + 142 Infra). Tag [s52, p11-d, round-robin, sla-due, regression].