diff --git a/.claude/agent-memory/implementer-backend/MEMORY.md b/.claude/agent-memory/implementer-backend/MEMORY.md index 0472327..3a70257 100644 --- a/.claude/agent-memory/implementer-backend/MEMORY.md +++ b/.claude/agent-memory/implementer-backend/MEMORY.md @@ -74,7 +74,9 @@ UI `disabled={!canX}` + BE helper `EnsureCanXAsync(id, userId)` throw 403 (NOT i ## 📅 Recent activity (FIFO — older → archive/git) -- **S?? P11-E+F Wave1 BE migration-FREE (4 file new + 3 edit, NO mig):** Case 1/2 deterministic ~98% em main. **P11-F** (2 LOC): `CreateItTicketHandler` set `e.MaTicket = WorkflowAppCodeGen.GenerateMaDonTuAsync(db,"IT",clock.Now.Year,clock,ct)` TRƯỚC `db.ItTickets.Add` — gen lúc Create (kanban no-workflow, khác Leave/OT gen lúc Submit). Helper = `internal static` cùng ns Office, gọi trực tiếp no-using. Format `IT/2026/001`. **P11-E** report chấm công: NEW `AttendanceReportFeatures.cs` (DTO 3 record EXACT + GetAttendanceReportHandler) + NEW `IAttendanceReportExcelExporter`(App/Reports/Services) + NEW Infra `AttendanceReportExcelExporter`(ClosedXML mirror ContractExcelExporter, sync `Export(dto)` no-DB) + DI scoped + Controller +2 endpoint `[Authorize(Roles=Admin)]`. **KEY gotcha day-type:** DayOfWeek+holidaySet KHÔNG EF-translate → `.ToListAsync()` rồi group/classify IN-MEMORY C#. **KEY gotcha type:** `Holiday.Date`=**DateOnly** KHÔNG DateTime (spec viết HashSet nhầm) → `HashSet` + so `DateOnly.FromDateTime(a.AttendanceDate.Date)`. OtPolicy active fallback 1.5/2.0/3.0. Day-type prio: holiday→weekend(Sat/Sun)→weekday. OtWeighted=Σ(cấp×hệ số). FullName denorm ưu tiên `Attendance.UserFullName` rồi User.FullName. DeptName LEFT JOIN. RenderResult=(Content,FileName,ContentType) ns Forms.Services. Controller inject exporter ctor. Build 0 err (2 pre-existing DocxRenderer warn). KHÔNG touch FE/test/mig/ItTicket-khác. Routes: GET `/api/attendances/report?year&month&departmentId` + `/report/excel`. Tag `[s??, p11-e-f, wave1, no-mig, day-type-in-memory, dateonly-holiday]`. +- **S52 P11-D Wave2 BE — ItTicket round-robin + SLA (Mig 46 `AddSlaFieldsToItTicket`, 3 AddColumn no-table) [proxy by em main: agent killed session-limit trước MEMORY step]:** Entity +SlaDueAt/SlaWarnedSent/SlaBreached. `CreateItTicketHandler`: `SlaWindow` static map (Urgent4/High8/Medium24/Low72h) **shared với `ItTicketSlaJob`** (single-source) → `e.SlaDueAt=CreatedAt+window`. Round-robin least-loaded: `db.Users.Where(DepartmentId==itDeptId && IsActive).OrderBy(db.ItTickets.Count(assigned && !Closed && !Resolved)).ThenBy(Id).First()` (itDept = `Departments.Code=="IT"`); no IT-staff → unassigned. NEW `ItTicketSlaJob:BackgroundService` mirror SlaExpiryJob (30s warmup/15min loop/scope) NHƯNG **KHÔNG auto-transition** — chỉ breach (SlaDueAt` sau SlaExpiryJob. `AssignItTicketCommand` + PUT `/{id}/assign` `[Authorize(Roles=Admin)]`. DTO +SlaDueAt/SlaBreached + projection. **DbInitializer `SeedItDepartmentStaffAsync` KEY ordering: PHẢI chạy SAU `SeedDemoUsersAsync`** (method đó reconcile 2 user dept về PRO/CCM mỗi boot → override về IT sau, end-state deterministic) + dept "IT" thứ 10 + gán nv.cao/nv.truong (sample user, idempotent). Build 0-err. Tag `[s52, p11-d, mig46, round-robin, sla-job, seed-ordering]`. + +- **S52 P11-E+F Wave1 BE migration-FREE (4 file new + 3 edit, NO mig):** Case 1/2 deterministic ~98% em main. **P11-F** (2 LOC): `CreateItTicketHandler` set `e.MaTicket = WorkflowAppCodeGen.GenerateMaDonTuAsync(db,"IT",clock.Now.Year,clock,ct)` TRƯỚC `db.ItTickets.Add` — gen lúc Create (kanban no-workflow, khác Leave/OT gen lúc Submit). Helper = `internal static` cùng ns Office, gọi trực tiếp no-using. Format `IT/2026/001`. **P11-E** report chấm công: NEW `AttendanceReportFeatures.cs` (DTO 3 record EXACT + GetAttendanceReportHandler) + NEW `IAttendanceReportExcelExporter`(App/Reports/Services) + NEW Infra `AttendanceReportExcelExporter`(ClosedXML mirror ContractExcelExporter, sync `Export(dto)` no-DB) + DI scoped + Controller +2 endpoint `[Authorize(Roles=Admin)]`. **KEY gotcha day-type:** DayOfWeek+holidaySet KHÔNG EF-translate → `.ToListAsync()` rồi group/classify IN-MEMORY C#. **KEY gotcha type:** `Holiday.Date`=**DateOnly** KHÔNG DateTime (spec viết HashSet nhầm) → `HashSet` + so `DateOnly.FromDateTime(a.AttendanceDate.Date)`. OtPolicy active fallback 1.5/2.0/3.0. Day-type prio: holiday→weekend(Sat/Sun)→weekday. OtWeighted=Σ(cấp×hệ số). FullName denorm ưu tiên `Attendance.UserFullName` rồi User.FullName. DeptName LEFT JOIN. RenderResult=(Content,FileName,ContentType) ns Forms.Services. Controller inject exporter ctor. Build 0 err (2 pre-existing DocxRenderer warn). KHÔNG touch FE/test/mig/ItTicket-khác. Routes: GET `/api/attendances/report?year&month&departmentId` + `/report/excel`. Tag `[s??, p11-e-f, wave1, no-mig, day-type-in-memory, dateonly-holiday]`. - **S51 P11-C HMW W1 — Vehicle+Driver catalogs HrmConfigs (Mig 44 `AddVehicleAndDriverCatalogs`, 9 add-point ~12 file/edit):** Pattern 12-bis catalog-mega 4th cumulative. 2 entity (`Vehicle`/`Driver`:AuditableEntity Domain/Hrm) + 2 EF config (mirror `HolidayConfiguration` filtered, NOT buggy bare LeaveType) + 2 DbSet (IAppDbContext+ApplicationDbContext) + Mig 3-file + HrmConfigFeatures Region5/6 (DTO+List/Create/Update/Delete CQRS mirror Region1 EXACT) + Controller +2 route group (8 endpoint, GET public + POST/PUT/DELETE `[Authorize(Roles=Admin)]`) + MenuKeys +2 const +All array + DbInitializer (menu 2 leaf + SeedHrmConfigsAsync guard&seed 2 veh+2 drv). **gotcha #57 KEY:** Code UNIQUE `.HasFilter("[IsDeleted]=0")` — Mig diff verified CLEAN 2 CreateTable + 2 filtered IX no drift. Validator MaxLength = em main schema (Code50/Name200/Plate20/Phone20/LicNum50/LicClass20/Desc500), SeatCount GreaterThanOrEqualTo(0). Admin perm AUTO-grant: `SeedAdminPermissionsAsync` + `Program.cs:78` both iterate `MenuKeys.All` → +All array = 8 policy + Admin row auto (no manual grant code). HRM no HasQueryFilter → `.Where(!IsDeleted)` manual. Applied BOTH DB. Build 0 err (2 pre-existing DocxRenderer warn). RAG/Qdrant DOWN → all Read/Grep on-disk. Spec deterministic ~98% em main → ACCEPT Case 1. KHÔNG touch FE/test/commit. Tag `[s51, p11-c, mig44, vehicle-driver, catalog-mega]`. - **S43 P11-B Wave 1 — LeaveBalance business logic (Mig 42 `AddLeaveBalances`, 7 file: 1 entity + 1 config + 2 DbSet edit + Mig 3-file + 1 hook edit + 1 Features + 1 Controller):** Case 1/3 deterministic ~98% em main spec. Pattern 12-ter-adjacent single-entity: entity `LeaveBalance:AuditableEntity` (UserId/LeaveTypeId/Year + EntitledDays/UsedDays/AdjustmentDays decimal(5,2), nav LeaveType). Config FK LeaveType WithMany() **Restrict** (catalog no cascade) + UNIQUE composite (UserId,LeaveTypeId,Year) + IX UserId. Mig diff CLEAN: 1 CreateTable + 3 IX, no drift. Applied BOTH DB (Dev `SolutionErp_Dev` + Design default). **Deduction hook:** insert in `ApproveLeaveRequestHandler` terminal else (DaDuyet branch) ONLY — UPSERT LeaveBalance, `bal.UsedDays += p.NumDays`, exactly-once guaranteed by early guard `Status != DaGuiDuyet throw`. OtRequest/Travel/Vehicle UNTOUCHED (only Leave has balance). CQRS `Application.Hrm`: DTO RemainingDays=Entitled+Adjustment−Used COMPUTED (not stored) + GetMy/GetUser lazy-merge (load active LeaveTypes + balances → in-memory merge, synth default when no row — KHÔNG EF LEFT JOIN translate) + AdjustLeaveBalanceCommand admin upsert (HasValue-gated). **Policy resolved:** HRM admin convention = `[Authorize(Roles="Admin")]` NOT menu policy (verified HrmConfigsController write endpoints) — used on GET-by-user + PUT /adjust; /my = `[Authorize]`. Controller injects IDateTime for year default `clock.Now.Year` (thin, no DateTime.Now hardcode). HRM no HasQueryFilter → `.Where(!IsDeleted)` manual everywhere. KHÔNG touch FE/test/commit. Build 0 err (2 pre-existing DocxRenderer warn). Tag `[s43, p11-b-w1, mig42, leave-balance, single-entity]`. diff --git a/.claude/agent-memory/test-specialist/MEMORY.md b/.claude/agent-memory/test-specialist/MEMORY.md index 5f0432f..d233bb6 100644 --- a/.claude/agent-memory/test-specialist/MEMORY.md +++ b/.claude/agent-memory/test-specialist/MEMORY.md @@ -53,6 +53,8 @@ Test theo CODE (single source truth), document mismatch header comment + report. ## 📅 Recent activity (last 10 FIFO) +- **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 133→142). **Round-robin:** seed Department Code="IT" + 2 user A/B `IsActive` trong IT + A có 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]. + - **2026-06-08 (S52 P11-E + P11-F WorkflowApps/Attendance test-after):** +5 test → **191 PASS** (Infra 128→133). 2 file `tests/.../Application/`: **ItTicketCodeGenTests** (3 — MaTicket regex `^IT/\d{4}/\d{3}$` + sequential 001→002 cùng prefix `IT/{year}` LastSeq++ + per-year-prefix 2027 reset 001) + **AttendanceReportTests** (2 — full aggregate day-type/weighted + DepartmentId filter). **⭐ Serializable-on-SQLite GOTCHA = NON-ISSUE (confirmed):** `WorkflowAppCodeGen.GenerateMaDonTuAsync` dùng `BeginTransactionAsync(IsolationLevel.Serializable)` chạy SẠCH trên SQLite — provider map isolation level gracefully (no throw), format+seq+per-year đều hold KHÔNG cần try/skip. Đã proven sẵn bởi WorkflowAppApproveV2Tests (DT/LR path). Handler `CreateItTicketHandler(db, cu, clock)` = 3 dep MediatR. **Day-type test pattern (P11-E core):** holiday check chạy TRƯỚC weekend/weekday → seed 2026-06-01 (thứ Hai) vào holidaySet → assert phân **Holiday** dù là weekday (override day-of-week). Holiday.Date=DateOnly → `BuildHoliday` dùng `DateOnly.FromDateTime`. OtWeighted = 2×1.5+3×2.0+1×3.0=12.0m. DepartmentId filter: seed 2 Department row + 2 user khác dept → query deptA chỉ trả 1 row (handler join Users `u.DepartmentId==deptId`, userMeta dùng `DefaultIfEmpty` nên dept row optional nhưng seed cho DepartmentName assert). No prod bug. **⚠️ MSBuild OOM** chạy full parallel → dùng `-maxcpucount:1 -p:BuildInParallel=false` (env resource, KHÔNG test fail). Tag [s52, p11-e, p11-f, codegen, day-type, serializable-sqlite-ok, test-after]. - **2026-06-08 (S51 P11-C HMW Wave2 filtered-unique gotcha #57):** +4 test `tests/.../Application/HrmConfigFilteredUniqueTests.cs` → **185 total = 183 PASS + 2 RED** (Infra 123→127). Mirror HolidayTests Case 7 (seed soft-deleted Code-slot → Create same Code → assert success + active==1 + all==2). **2 GREEN** Vehicle+Driver (Mig 44 config ĐÃ filtered → 2 catalog mới đúng). **2 RED INTENTIONAL = gotcha #57 REPRODUCED** (test-before): `CreateLeaveType_OnSoftDeletedCodeSlot...` → `SQLite Error 19 UNIQUE constraint failed: LeaveTypes.Code` + `CreateShift_OnSoftDeletedCodeSlot...` → `ShiftPatterns.Code` (bare `.IsUnique()` đếm cả row soft-deleted; handler app-check `!IsDeleted` PASS → Add+SaveChanges → DbUpdateException). NOT test lỗi — REPORTED em main fix Mig 45 `.HasFilter("[IsDeleted]=0")` cho 2 config → flip GREEN. **⚠️ Soft-delete trong test (giống Holiday):** AuditingInterceptor (prod soft-delete Deleted→Modified+IsDeleted=true) KHÔNG wire trong SqliteDbFixture → `Remove+SaveChanges` = HARD delete (không test được). PHẢI seed row `IsDeleted=true` thủ công để mô phỏng slot bị chiếm. Handlers chỉ cần IApplicationDbContext → `new CreateXxxHandler(db)`. Tag [s51, p11-c, gotcha-57, filtered-unique, test-before]. - **2026-05-30 (S42 P11-A Wave4):** +11 test `tests/.../Application/WorkflowAppApproveV2Tests.cs` → **141 PASS** (Infra 72→83). LeaveRequest 8 case full (Submit happy/guard×2, Approve advance/terminal/UPSERT-invariant/forbidden/empty-comment-placeholder, Reject→TuChoi, Return→TraLai+RejectedFromStatus) + OtRequest smoke (submit→approve single-level→DaDuyet). **No prod bug** — LeaveOt ApproveV2 wire correct, all PASS first run. **NEW Pattern:** WorkflowApps handlers = CQRS MediatR (KHÔNG service) → instantiate handler trực tiếp `new ApproveLeaveRequestHandler(db, AsUser(u), clock).Handle(cmd,ct)`, chỉ 3 dep (IApplicationDbContext + TestCurrentUser + FixedDateTime) — nhẹ hơn 6-dep Contract service. MaDonTu format "DT/LR/2026/001". Gap #4 (Workflow Apps) PARTIAL done — Travel/Vehicle mirror pending. ⚠️ Lesson: CWD drift (fe-user) → ghi MEMORY nhầm path, em main relocate. Verify CWD root trước Write memory. diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index 7660873..c8cc442 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -2,7 +2,28 @@ > **Tiering rule (S40):** giữ **2-3 session gần nhất**. Cũ hơn → `docs/changelog/sessions/`. Full brief history pre-S40 → `docs/_archive/HANDOFF-preS40-fullhistory.md`. -**Last updated:** 2026-06-08 (Session 51 — **P11-C Vehicle+Driver catalogs (Mig 44) + gotcha #57 ext 3 HRM catalog (Mig 45)**, HMW-mode ON product feature, deployed prod Run #371. 7-agent fan-out, reviewer caught Driver FE↔BE required-field contract mismatch → fixed. test 181→186, tables 91→92, bundle admin `Cg9mvltU`/user `YgqDvsqr`. ⚠️ RAG/Qdrant DOWN cả session (file-based fallback). gotcha #57 EXT Master (Department/Supplier/Project, Mig 46) → separate worktree session. Prev S50: Harness 1·2·3 verified-runtime.) +**Last updated:** 2026-06-08 (Session 52 — **Phase 11 product backlog ĐÓNG TRỌN (P11-D+E+F deployed prod)** + database-agent adopt. HMW-mode ON. 3 commit (`e9ee97f`+`6a66429`+`dcf76f8`). Test 186→**200**. Mig 46. Bundle admin `DYfjnpY0`/user `_3S0BPJ2` (deploy verified curl độc lập). ⚠️ **Session-limit hit giữa Wave 2** → recovery on-disk + em main solo FE + curl-self-verify. 🔴 database-agent CHỜ CLI restart. Prev S51: P11-C Vehicle+Driver.) + +--- + +## S52 (2026-06-08) — Phase 11 D+E+F close + database-agent adopt (HMW-mode ON · session-limit recovery · deployed prod) + +**User: `/session-start` → "Cả 3 (D+E+F)" → pivot "Adopt database-agent" → để em chạy. 3 commit deployed prod.** + +**Done (3 commit, deploy verified curl độc lập — no cicd-spawn do limit):** +- **database-agent adopt** (`e9ee97f`) — AI_INFRA broadcast `2026-06-08-Agent-database-codebase-agents`. Floor DB1–DB11 **READ-advisory** (impl-backend vẫn author) · skill `sql-database-assistant`+`ef-core-migration` · color OMIT · `store_memory` strip · DB11 vá S43 lost-update. **codebase-agent SKIP n-a** (investigator + csharp-lsp Windows no-op). Roster 10→**11**. **Nấc executed-file → CHỜ restart.** +- **Wave 1 (`6a66429`) P11-E+F migration-free:** P11-F MaTicket gen-on-Create (`IT/2026/NNN` Serializable). P11-E AttendanceReport monthly aggregate (OtPolicy multiplier, day-type in-memory) + Excel ClosedXML + fe-admin report page (download authed blob). reviewer PASS (gotcha #44 disarmed: decoy `"QTV"`=display-code). +5 test. +- **Wave 2 (`dcf76f8`) P11-D Mig 46:** round-robin least-loaded dept-"IT" (seed dept IT + nv.cao/nv.truong, ordering sau SeedDemoUsers) + SlaDueAt-by-Priority (4/8/24/72h) + `ItTicketSlaJob` (breach+warning, **no auto-transition**) + PUT /assign + FE badge 2-app SHA256 mirror. +9 test. em main self-review (limit). +- **Deploy verified:** admin `DYfjnpY0`/user `_3S0BPJ2` rotate · api 200 (Mig 46 applied) · /it-tickets+/assign+/attendances/report 401 wired. **Test 200 PASS** (58+142). + +**⚠️ Session-limit recovery lesson:** 3 agent killed mid-Wave-2 (FE/test/cicd, "resets 1:10pm"). Recovery: BE/test verify-on-disk (build 0-err + 200 test) · **em main solo FE redo** (gotcha #53-class fallback) · **curl-self-verify** deploy thay cicd-spawn. → **git/disk/prod = source-of-truth, KHÔNG agent return-message** (`feedback_implementer_truncation_mitigation`). + +**🔴 NEXT SESSION:** +- **🔴 RESTART CLI** → activate `database-agent` (registry load, no hot-reload) → spawn-test 1 task DB nhỏ (đọc schema `sys.tables` / introspect ItTicket) → upgrade executed-file → **verified-runtime**. adap-report nấc update. +- **Memory-proxy debt:** Wave 2 `implementer-backend` + `test-specialist` diaries KHÔNG update (killed trước MEMORY step) → em main proxy-append S52 learnings (round-robin dept-pool · SLA-window-shared-map · seed-ordering-sau-SeedDemoUsers · round-robin/SLA-due test pattern). **Đã proxy S52 closeout** (xem agent-memory). +- **H1/H2 monitor closeout SKIPPED S52** (session-limit) → next `/session-start` re-report tooling/harvest diff. +- **Follow-up minor:** ItTicket reassign-UI (endpoint `/assign` sẵn) · P11-E menu-key promote (hiện via button) · **gotcha #57 EXT Master = Mig 47** (Mig 46 đã dùng P11-D) · RAG re-index S42-S52 (AI_INFRA op, stale 05-29). +- **Product:** Phase 11 = DONE. Next = Phase 9 Ops (SMTP/creds/backup/UAT real-user) — anh main coordinate. --- diff --git a/docs/STATUS.md b/docs/STATUS.md index 058ea1f..707231e 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -3,7 +3,7 @@ > **Update rule:** trước khi bắt đầu 1 task → ghi row `🔥 In Progress`. Xong → `✅ Recently Done`. > **Tiering rule (S40):** chỉ giữ **state hiện tại + 3 session gần nhất** ở file này. Session cũ hơn → `docs/changelog/sessions/`. Full history pre-S40 → `docs/_archive/STATUS-preS40-fullhistory.md`. (Tránh over-context — xóa double, không cắt nội dung.) -**Last updated:** 2026-06-08 (Session 51 — **P11-C Vehicle+Driver catalogs + gotcha #57 ext**, HMW-mode ON, product feature): Mig 44 `AddVehicleAndDriverCatalogs` (2 catalog table, filtered-unique day-1) + Mig 45 `FilterHrmCatalogUniqueIndexesByIsDeleted` (3 HRM catalog LeaveType/ShiftPattern/**OtPolicy** — OtPolicy missed in "2 catalog" backlog, caught via grep). 7-agent fan-out: investigator recon → BE∥FE parallel → test-before (RED→GREEN) → reviewer (caught Driver FE↔BE required-field contract mismatch → fixed) → cicd. **Commit `30a99aa` → Gitea Run #371 PASS, deployed prod** (test 181→186, tables 91→92, bundle admin `Cg9mvltU`/user `YgqDvsqr`, 5 idx filtered live). gotcha #57 EXT (Department/Supplier/Project Master, Mig 46) → separate worktree session. ⚠️ RAG/Qdrant DOWN cả session (file-based fallback). Prev S50: Harness 1·2·3 verified-runtime.) +**Last updated:** 2026-06-08 (Session 52 — **Phase 11 product backlog ĐÓNG TRỌN: P11-D+E+F deployed prod** + database-agent adopt, HMW-mode ON): 3 commit — `e9ee97f` (database-agent DB1–DB11 read-advisory, roster 10→11, executed-file CHỜ restart) + `6a66429` Wave 1 (P11-E AttendanceReport+Excel+OtPolicy multiplier + P11-F MaTicket codegen, migration-free) + `dcf76f8` Wave 2 (P11-D ItTicket round-robin assign dept-IT + SLA timer, Mig 46). Test 186→**200**. Bundle admin `DYfjnpY0`/user `_3S0BPJ2` (cả 2 deploy verified curl độc lập — Wave 1 BE 401 wired + Wave 2 /assign 401 + Mig 46 applied health-200). ⚠️ **Session-limit hit giữa Wave 2** → recovery: BE/test verify-on-disk + em main solo FE redo + curl-self-verify thay cicd-spawn (multi-agent resilience, git/disk/prod = source-of-truth). RAG recovered (chunk 2416 rerank live) nhưng stale 05-29. Prev S51: P11-C Vehicle+Driver.) --- @@ -11,30 +11,30 @@ | Metric | Value | Note | |---|---|---| -| Migrations | **45** | +S51 Mig 44 `AddVehicleAndDriverCatalogs` + Mig 45 `FilterHrmCatalogUniqueIndexesByIsDeleted` | -| SQL tables | **92** | +2 S51 Vehicles + Drivers (cicd `sys.tables` ground-truth; narrative "91→93" = +1 drift, real 90+2=92) | -| API endpoints | **~249** | +8 S51 (hrm-configs vehicles/drivers × GET/POST/PUT/DELETE) | -| FE pages | **67** | HrmConfigsPage `:kind`-driven (P11-C +2 kind, no new page) | -| Menu keys | **~55** | +2 S51 `Hrm_Config_Vehicles`/`Drivers` (BE `MenuKeys` const + FE mirror) | -| Tests | **186 PASS** | 58 Domain + 128 Infra · 0 fail / 0 skip · +5 S51 `HrmConfigFilteredUniqueTests` (Vehicle/Driver/LeaveType/Shift/OtPolicy) | -| Gotchas | **57** | #57 soft-delete UNIQUE filter — S51 EXTENDED 3 HRM catalog (Mig 45) + ext backlog 3 Master (worktree) | -| User memory | **17** | (unchanged S51 — product feature session) | +| Migrations | **46** | +S52 Mig 46 `AddSlaFieldsToItTicket` (P11-D: 3 column SlaDueAt/SlaWarnedSent/SlaBreached vào ItTicket — KHÔNG bảng mới) | +| SQL tables | **92** | unchanged S52 (Mig 46 = AddColumn, no new table; cicd `sys.tables` ground-truth) | +| API endpoints | **~252** | +3 S52 (attendances/report + report/excel + it-tickets/{id}/assign) | +| FE pages | **68** | +1 S52 AttendanceReportPage (fe-admin); ItTicketsPage upgrade in-place (P11-D badge) | +| Menu keys | **~55** | unchanged S52 (report via button, ticket dùng menu sẵn — no new key) | +| Tests | **200 PASS** | 58 Domain + 142 Infra · 0 fail / 0 skip · +5 Wave1 (codegen+aggregate) +9 Wave2 (`ItTicketAssignSlaTests` round-robin/SLA-due) | +| Gotchas | **57** | unchanged S52 (#57 soft-delete UNIQUE filter; ext backlog 3 Master worktree still open) | +| User memory | **17** | (unchanged S52 — em main solo session, no new feedback entry) | | Skills | 6 | 3 domain + 3 ops | -| Sub-agents | **10** | Opus 4.8 1M · 8 product/quality (7 core + frontend-designer) + 2 monitor INFORM-only (tooling-auditor H1 + harvest-curator H2) | -| RAG chunks | **DOWN S51** | Qdrant 127.0.0.1:6333 refused cả session (`search_memory` ConnectError; `rag-infra.ps1 -Action ensure` = AI_INFRA op). S50 baseline 2415. SE file-based fallback. | +| Sub-agents | **11** | Opus 4.8 1M · 9 product/quality (7 core + frontend-designer + **database-agent S52** read-advisory) + 2 monitor INFORM-only (tooling-auditor H1 + harvest-curator H2). ⚠️ database-agent executed-file CHỜ CLI restart → verified-runtime | +| RAG chunks | **2416** | Recovered S52 (S51 Qdrant DOWN → nay alive, rerank live 0.9375). Stale `last_indexed 05-29` (S42-S52 via store_memory stopgap; full re-index = AI_INFRA op cần VOYAGE_API_KEY). | -**Bundle hash live (prod):** admin `Cg9mvltU` · user `YgqDvsqr` (Gitea Run #371, S51 — rotated from `DPPTx2Kw`/`CjoUEsoV` by P11-C). cicd-monitor PASS: test 186 · Mig 44+45 applied prod (5 `IX_*_Code` filtered `[IsDeleted]=0`) · health/smoke 200 ×4 · /hrm-configs/{vehicles,drivers} wired. -**Phase:** ✅ Phase 10 COMPLETE · 🔄 **Phase 11 IN PROGRESS** — P11-A/B/**C** DONE (deployed prod) · ⬜ P11-D/E/F pending · 🚫 Phase 9 Ops blocked (anh main coordinate). +**Bundle hash live (prod):** admin `DYfjnpY0` · user `_3S0BPJ2` (S52 — rotated by P11-D Wave 2, cả 2 app). Deploy verified curl độc lập (no cicd-spawn do session-limit): api health 200 (→ Mig 46 applied) · GET /it-tickets 401 + PUT /assign 401 (P11-D wired) · /attendances/report 401 (P11-E Wave 1) · cả 2 bundle rotate. +**Phase:** ✅ Phase 10 COMPLETE · ✅ **Phase 11 product backlog ĐÓNG TRỌN** — P11-A/B/C/**D/E/F** ALL DONE (deployed prod) · 🚫 Phase 9 Ops blocked (anh main coordinate). > ⚠️ **Count drift fixed S40:** endpoints ~223→**211**, FE pages 53→**65**, menu keys 85→**~53**. Tables **84 confirmed correct** (DbSet 77 + Identity 7). 3 số "khó fake" (mig/gotcha/git) luôn đúng. Cause: số "incremented mỗi session" over/under-count optimistic — re-ground định kỳ. --- -## 🔥 In Progress (S51) +## 🔥 In Progress (S52) | Task | Owner | Status | |---|---|---| -| _(none — S51 closed P11-C Vehicle+Driver (Mig 44) + gotcha #57 ext-to-3-HRM-catalog (Mig 45), deployed prod Run #371. **NEXT product (anh pick):** P11-D ItTicket SLA / P11-E AttendanceReport+OtPolicy multiplier / P11-F MaTicket / Phase 9 Ops. gotcha #57 EXT Master (Mig 46) running in worktree session.)_ | 👤 | ✅ | +| _(none — S52 ĐÓNG TRỌN Phase 11 product backlog (P11-D+E+F deployed prod) + database-agent adopt. **🔴 NEXT-FIRST: anh restart CLI** → activate database-agent (registry load) → spawn-test verified-runtime. **NEXT (anh pick):** Phase 9 Ops (SMTP/creds/backup/UAT real-user) · follow-up minor: ItTicket reassign-UI (endpoint `/assign` sẵn, UI defer) + P11-E menu-key promote (hiện via button) + gotcha #57 EXT Master = **Mig 47** (Mig 46 đã dùng cho P11-D).)_ | 👤 | ✅ | **S40 done:** ✅ Consolidation (`d2f52ba`) · ✅ Curate 4 agent MEMORY >25KB→<8.4KB (`78c9de3`) · ✅ RAG catch-up chunk S37-S40 (rerank 0.867) · ✅ **AI_INFRA bulletin 2026-05-29 adopt 4/4** (MỤC2 Tiered Memory Policy v1 `6f08d1f` + MỤC3 /session-start+/session-end slash commands `c8ff5e1`). ⏳ Full RAG re-index = AI_INFRA op (cần VOYAGE_API_KEY). @@ -44,6 +44,16 @@ ## ✅ Recently Done (newest on top — 3 session; cũ hơn → session logs) +### S52 (2026-06-08) — 🎉 Phase 11 product backlog ĐÓNG TRỌN (P11-D+E+F deployed) + database-agent adopt — HMW-mode ON, session-limit recovery +- **3 commit deployed prod:** `e9ee97f` (database-agent governance .md, CI-skip) + `6a66429` Wave 1 (P11-E+F code) + `dcf76f8` Wave 2 (P11-D, Mig 46). Test 186→191→**200**. Bundle admin `DYfjnpY0`/user `_3S0BPJ2` (cả 2 rotate; deploy verified curl độc lập — không cicd-spawn do limit). +- **🔌 database-agent adopt** (AI_INFRA broadcast `2026-06-08-Agent-database-codebase-agents`): floor DB1–DB11 **READ-advisory tier** (implementer-backend vẫn author file) · skill `sql-database-assistant`+`ef-core-migration` · color OMIT (8 standard hết → mirror monitor precedent) · `store_memory` strip · DB11 RowVersion tie-in vá S43 lost-update gap. **codebase-agent SKIP n-a** (investigator cover + csharp-lsp Windows no-op). Roster 10→**11**. Nấc executed-file → **🔴 CHỜ CLI restart** verified-runtime. adap-report 5-trường LOCK written. +- **P11-F MaTicket codegen** (Wave 1): `WorkflowAppCodeGen.GenerateMaDonTuAsync(db,"IT",clock.Now.Year,...)` gen-on-**Create** (kanban no-workflow, khác Leave/OT gen-on-Submit), `IT/2026/NNN` Serializable atomic. Migration-free. +- **P11-E AttendanceReport** (Wave 1): `GetAttendanceReportQuery` monthly aggregate (day-type weekday/weekend/holiday OT × OtPolicy multiplier, **classify in-memory** không EF-translate `.DayOfWeek`) + `AttendanceReportExcelExporter` (ClosedXML, sync no-DB) + 2 endpoint Admin-only + fe-admin `AttendanceReportPage` (download authed `api.get(blob)`). Migration-free. `Holiday.Date`=DateOnly (agent verify source-of-truth, không tin spec mù). +- **P11-D ItTicket assign+SLA** (Wave 2, **Mig 46** AddSlaFieldsToItTicket): round-robin least-loaded dept-"IT" (DbInitializer seed dept IT + 2 sample staff nv.cao/nv.truong, **ordering sau SeedDemoUsers** vì reconcile dept) + SlaDueAt theo Priority (Urgent4/High8/Medium24/Low72h) + `ItTicketSlaJob` (breach+warning notify, **KHÔNG auto-transition** — khác Contract) + PUT /assign admin override + FE badge 2-app SHA256 mirror. +- **⚠️ Session-limit hit giữa Wave 2** (3 agent killed: FE/test/cicd) → recovery (multi-agent resilience proof): Wave 2 BE/test verify-on-disk (build 0-err + 200 test) + **em main solo FE redo** (gotcha #53-class fallback) + **curl-self-verify** Wave 1+2 deploy thay cicd-spawn. Lesson: **git/disk/prod = source-of-truth, KHÔNG agent return-message**. +- **reviewer (Wave 1) PASS** — independent re-verify (build/test/tsc) + gotcha #44 role-string "Admin" disarmed (decoy `"QTV"`=display-code KHÔNG phải role-name). Wave 2 = **em main self-review** (seed↔query dept-code cross-check PASS, nv.cao/nv.truong tồn tại) do limit pressure. +- → session log `2026-06-08-S52-phase11-def-close-database-agent.md`. + ### S51 (2026-06-08) — ✅ P11-C Vehicle+Driver catalogs (Mig 44) + gotcha #57 ext 3 HRM catalog (Mig 45) — HMW fan-out, deployed prod - **Commit `30a99aa` → Gitea Run #371 PASS ~4m18s, verified prod.** HMW-mode ON, 7-agent fan-out: 🟦 recon → 🟨 BE ∥ 🟧 FE (parallel file-disjoint) → 🟪 test-before → 🟥 reviewer → 🟩 cicd. RAG/Qdrant DOWN cả session → ground-truth on-disk (đáng tin hơn stale RAG index 05-29). - **Mig 44 `AddVehicleAndDriverCatalogs`** — 2 catalog table (Vehicles + Drivers, `AuditableEntity`), filtered-unique Code day-1 (gotcha #57 từ đầu). Extend HrmConfigs declarative: BE Region 5/6 CRUD (mirror LeaveType) + Controller +2 route-group (8 endpoint, GET public / write Roles=Admin) + MenuKeys +2 +All (auto Admin perm) + DbInitializer idempotent seed 2 veh/2 drv. FE KIND_CONFIG +2 kind ×2 app (SHA256 mirror) + 4-place (types/page/menuKeys/Layout staticMap), `:kind`-driven (no new App.tsx route). Tables 91→**92** (cicd `sys.tables` ground-truth). @@ -143,11 +153,13 @@ ## 🎯 Next up -### 🔄 Phase 11 — Polish/wire skeleton (IN PROGRESS) -- ✅ **P11-A** wire ApproveV2 + LevelOpinions 4 module — **DONE S42** (Run #250, prod). +### ✅ Phase 11 — Polish/wire skeleton (COMPLETE S52) +- ✅ **P11-A** wire ApproveV2 + LevelOpinions 4 module — **DONE S42** (prod). - ✅ **P11-B** LeaveBalance business logic — **DONE S43** (Mig 42, prod). -- ✅ **P11-C** Vehicle+Driver catalog — **DONE S51** (Mig 44, Run #371, prod). HrmConfigs +2 kind declarative; VehicleBooking giữ free-text (FK link defer). -- ⬜ **P11-D** ItTicket auto-assign + SLA timer · **P11-E** AttendanceReport + Excel + OtPolicy multiplier · **P11-F** CodeGen atomic MaTicket (MaDonTu xong S42) +- ✅ **P11-C** Vehicle+Driver catalog — **DONE S51** (Mig 44/45, prod). +- ✅ **P11-D** ItTicket round-robin assign + SLA timer — **DONE S52** (Mig 46, `dcf76f8`, prod). Dept-IT pool + `ItTicketSlaJob` no-auto-transition. _Follow-up minor: reassign-UI defer (endpoint `/assign` sẵn)._ +- ✅ **P11-E** AttendanceReport + Excel + OtPolicy multiplier — **DONE S52** (`6a66429`, prod). Admin-only, weighted-OT-hours (no salary field → quy-đổi-giờ not pay, MVP). _Follow-up: menu-key promote (hiện via button)._ +- ✅ **P11-F** CodeGen atomic MaTicket — **DONE S52** (`6a66429`, prod). gen-on-Create `IT/2026/NNN`. ### 🔧 Maintenance backlog - RAG re-ingest `solution_erp` S42-S43 content (store_memory stopgap live; full re-index = AI_INFRA op) diff --git a/docs/changelog/sessions/2026-06-08-S52-phase11-def-close-database-agent.md b/docs/changelog/sessions/2026-06-08-S52-phase11-def-close-database-agent.md new file mode 100644 index 0000000..4121b02 --- /dev/null +++ b/docs/changelog/sessions/2026-06-08-S52-phase11-def-close-database-agent.md @@ -0,0 +1,66 @@ +# S52 (2026-06-08) — Phase 11 product backlog ĐÓNG TRỌN (P11-D+E+F) + database-agent adopt + +> HMW-mode ON · 3 commit deployed prod · session-limit recovery · em main + multi-agent fan-out. +> **User flow:** `/session-start` → chọn "Cả 3 (D+E+F)" → pivot "Adopt database-agent" → "để em chạy tiếp". + +## TL;DR +- **Phase 11 product backlog ĐÓNG TRỌN**: P11-D (ItTicket assign+SLA) + P11-E (AttendanceReport+Excel+OtPolicy) + P11-F (MaTicket codegen) — **deployed prod**. +- **database-agent adopt** (AI_INFRA broadcast) — roster 10→11, nấc executed-file, chờ CLI restart. +- Test **186 → 200 PASS**. Mig **45 → 46**. Bundle admin `DYfjnpY0` / user `_3S0BPJ2`. +- **⚠️ Session-limit hit giữa Wave 2** → recovery: verify-on-disk + em main solo FE + curl-self-verify. + +## 3 commit (deployed prod) +| Commit | Scope | CI | +|---|---|---| +| `e9ee97f` | database-agent governance (.md) | skip (docs-only) | +| `6a66429` | Wave 1 — P11-E AttendanceReport + P11-F MaTicket codegen | run + deploy | +| `dcf76f8` | Wave 2 — P11-D ItTicket round-robin + SLA timer (Mig 46) | run + deploy | + +## database-agent adopt (`e9ee97f`) +- AI_INFRA broadcast `2026-06-08-Agent-database-codebase-agents` (reviewer_gate PASS_WITH_FIXES, targets all-fit). Via `/adap-apply`. +- **database-agent** = floor DB1–DB11 (schema/query/migration-review/perf/concurrency). **Tailored READ-advisory tier** (SE `implementer-backend` vẫn author entity+config+migration cohesive 3-file → database-agent design/review/advise, KHÔNG author file). Skill `sql-database-assistant` + `ef-core-migration`. `color` OMIT (8 standard hết — mirror monitor precedent, tránh gotcha #37). `store_memory` strip. DB11 RowVersion = tie-in vá **S43 LeaveBalance lost-update gap**. +- **codebase-agent = SKIP n-a** (investigator-codebase cover grep/audit + `csharp-lsp` Windows no-op). +- Files: `.claude/agents/database-agent.md` + `agent-memory/database-agent/MEMORY.md` seed + `agents/README.md` roster 10→11 (5-điểm sync) + `adap-reports/2026-06-08-...md` (5-trường LOCK). +- **Nấc executed-file → 🔴 CHỜ CLI restart** verified-runtime (agent .md no hot-reload). + +## Wave 1 — P11-E + P11-F (migration-free, `6a66429`) +- **P11-F MaTicket:** `CreateItTicketHandler` set `e.MaTicket = WorkflowAppCodeGen.GenerateMaDonTuAsync(db,"IT",clock.Now.Year,clock,ct)` gen-on-**Create** (ItTicket = kanban no-workflow, khác Leave/OT gen-on-Submit). `IT/2026/NNN` Serializable atomic. +- **P11-E AttendanceReport:** `GetAttendanceReportQuery(Year,Month,DeptId?)` monthly aggregate. Day-type (weekday/weekend/holiday) classify **IN-MEMORY** (`.AsEnumerable()`, KHÔNG EF-translate `.DayOfWeek`). OtWeighted = OtWeekday×mWd + OtWeekend×mWe + OtHoliday×mHol (OtPolicy active, fallback 1.5/2.0/3.0). `Holiday.Date`=**DateOnly** (implementer verify source-of-truth, em spec ghi DateTime nhầm → agent tự sửa). `AttendanceReportExcelExporter` ClosedXML sync no-DB. 2 endpoint `[Authorize(Roles=Admin)]`. fe-admin `AttendanceReportPage` (download authed `api.get(blob)` qua interceptor + refresh-retry). +- **reviewer PASS** (independent re-verify build/test/tsc). **gotcha #44 disarmed:** `AppRoles.Admin="Admin"` khớp `[Authorize(Roles="Admin")]` + seeded role; decoy = `"QTV"` (DbInitializer display-code, KHÔNG phải role-name). FE `user.roles.includes('Admin')` khớp. +- +5 test (186→191). + +## Wave 2 — P11-D ItTicket assign + SLA (Mig 46, `dcf76f8`) +- **Mig 46** `AddSlaFieldsToItTicket` — 3 AddColumn (SlaDueAt/SlaWarnedSent/SlaBreached) vào ItTicket, **no new table** (tables stay 92). +- **Pool = department "IT"** (user chọn dept thay role): DbInitializer +dept thứ 10 + `SeedItDepartmentStaffAsync` gán nv.cao/nv.truong. **KEY ordering: PHẢI chạy SAU `SeedDemoUsersAsync`** (method đó reconcile 2 user dept về PRO/CCM mỗi boot → override về IT sau → end-state deterministic). +- **Round-robin least-loaded:** `Users.Where(DepartmentId==itDept && IsActive).OrderBy(open-ticket-count).ThenBy(Id).First()`. No IT-staff → unassigned. +- **SlaDueAt** = CreatedAt + `SlaWindow[priority]` (Urgent4/High8/Medium24/Low72h) — `SlaWindow` static map **shared** với job (single-source). +- **`ItTicketSlaJob`** BackgroundService mirror SlaExpiryJob NHƯNG **KHÔNG auto-transition** (ticket chỉ breach-flag + warning-notify assignee, idempotent qua guard). Khác Contract SLA (auto-approve transition). +- **PUT `/{id}/assign`** `[Authorize(Roles=Admin)]` admin override. FE ItTicketsPage +MaTicket+assignee+SLA badge (2 app SHA256 mirror, gỡ banner skeleton). Reassign-UI defer (endpoint sẵn). +- +9 test (191→**200**). + +## ⚠️ Session-limit recovery (multi-agent resilience case study) +- Giữa Wave 2, session-limit hit ("resets 1:10pm") → **3 background agent killed mid-task**: Wave 2 FE (26 tool-use, 0 file ghi), Wave 2 test (10 tool-use, file ghi xong), cicd Run A (6 tool-use, verdict mất). Wave 2 BE trước đó return TRUNCATED (gotcha #53) nhưng work xong. +- **Recovery (git/disk/prod = source-of-truth, KHÔNG agent return-message):** + 1. Wave 2 BE — verify-on-disk (git status + build 0-err + đọc handler/job/seed) → complete. + 2. Wave 2 test — file `ItTicketAssignSlaTests.cs` đã ghi → `dotnet test` = **200 PASS** → complete. + 3. Wave 1 deploy — cicd verdict mất → **curl prod độc lập**: api 200 + /attendances/report 401 + admin bundle rotate `CJcApLsI` + user unchanged → confirmed live. + 4. Wave 2 FE — 0 file ghi → **em main solo redo** (gotcha #53-class fallback): types ×2 + ItTicketsPage ×2 (copy SHA256) + build ×2 pass. + 5. Wave 2 review — **em main self-review** (limit pressure, no reviewer-spawn): seed↔query dept-code cross-check + nv.cao/nv.truong tồn tại + ItTicketSlaJob idempotent → PASS. + 6. Wave 2 deploy — **curl-self-verify**: api 200 (Mig 46) + /assign 401 + 2 bundle rotate. + +## Deploy verification (curl độc lập, no cicd-spawn) +- Wave 1: api 200 · /attendances/report 401 · admin `CJcApLsI` (rotate) · user `YgqDvsqr` (unchanged — đúng). +- Wave 2: api 200 (Mig 46 applied) · /it-tickets 401 · /assign 401 (new endpoint) · admin `DYfjnpY0` · user `_3S0BPJ2` (cả 2 rotate — đúng, cả 2 app đổi). + +## Lessons +- **Source-of-truth = git/disk/prod, KHÔNG agent return-message** — truncation/kill recovery dựa vào on-disk verify (`feedback_implementer_truncation_mitigation` reinforced). +- **Multi-agent resilience:** killed agents để lại work-on-disk recoverable; em main solo fallback cho phần dở (boundary cho phép gotcha #53-class). +- **Agent verify-source-of-truth > spec-mù:** implementer bắt `Holiday.Date`=DateOnly + exporter-sync = deviation đúng (em spec sai → agent tự sửa, tránh build-break). +- **reviewer decoy-hunting:** gotcha #44 role-string verify ground-truth (decoy "QTV") = giá trị reviewer độc lập. +- **Migration coordination:** worktree session "đang chạy" (S51 HANDOFF) thực tế KHÔNG active (git worktree list = main only) → P11-D tự do dùng Mig 46; gotcha #57 EXT Master = Mig 47 (rebase sau). + +## 🔴 NEXT SESSION +1. **RESTART CLI** → activate database-agent → spawn-test → verified-runtime. +2. H1/H2 monitor closeout SKIPPED (limit) → next /session-start re-report. +3. Follow-up minor: ItTicket reassign-UI · P11-E menu-key promote · gotcha #57 EXT Master Mig 47 · RAG re-index S42-S52 (AI_INFRA op). +4. Product: Phase 11 DONE → Phase 9 Ops (anh main coordinate).