79ef8da9f4ca2f7c70220db15608f0d411157327
157 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 79ef8da9f4 |
[CLAUDE] PurchaseEvaluation: ngan sach goi thau theo Excel anh Kiet - bang tong hop 2 block + nhap theo role PRO/CCM + xoa module Budget cu (Mig 50)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m31s
- Mig 50 ReplaceBudgetModuleWithPeWorkItemBudgets: bang moi PeWorkItemBudgets (1 record/cap Du an x Hang muc, UNIQUE filtered [IsDeleted]=0) + drop 5 bang Budget cu + PE/Contracts drop BudgetId + backfill BudgetManualAmount->BudgetPeriodAmount TRUOC DropColumn (phieu UAT giu so) + DELETE menu/permission Bg_* IN-list children-first
- BE: PUT {id}/budget/pro (role Procurement) + {id}/budget/ccm (role CostControl, Adjustment cho phep AM) fail-closed Forbidden-truoc-side-effect + EnsureTrackedAsync race-safe (catch unique -> re-fetch winner, loi khac rethrow) + auto-create record khi tao phieu + budgetSummary DTO (luy ke trinh-truoc/chon-thau-truoc/de-xuat-ky-nay + full fallback du-tru-PRO + canEdit flags) + submit-guard (3) doi predicate BudgetPeriodAmount -> "chua nhap Ngan sach ky nay" + PATCH budget-adjust absolute-set 2 field moi + Contract GIU BudgetManual* (HD nhap tay khong doi) + ke thua HD map BudgetPeriodAmount
- FE x2 app SHA256 identical: bang "TONG HOP NGAN SACH TRINH KY" block A (full dam + ban hanh + V0 hieu chinh + du tru PRO + ghi chu, editable theo canEditPro/canEditCcm) + block B 9 dong cong thuc Excel (5=1+3, 6=2+4, 7=full-5, 8 tu nhap default 7, 9=4+8) + to mau vuot ngan sach #C00000 / am do / red-soft row8>row7 + "Chua chon" khi count=0 + banner phieu chua gan Hang muc + o "Ngan sach ky nay" o create/header + XOA pages/components/types budgets + routes + menuKeys + Layout staticMap 4-place
- Tests: +22 PeWorkItemBudgetTests (auto-create x3, ensure/race x2, authz matrix PRO x5 + CCM x3, budgetSummary aggregates x5, adjust x4) - 14 BudgetPolicyTests xoa theo module - 1 test via-BudgetId -> 263 PASS (45 Domain + 218 Infra, 0 fail)
- database-agent advise adopted: khong FK vat ly PE/Contracts->Budgets (DropColumn khong can DropForeignKey) + DropIndex truoc DropColumn (SQL 5074) + IN-list thay LIKE Bg_% (underscore wildcard + miss root) + khong Serializable wrap (nested-tx conflict codegen)
- Reviewer PASS-with-minor 0 blocker (verdict-first survived); 2 minor da sua truoc commit (comment adjustMut absolute-set + dead key budgetId); note: F4 approver-edit-budget UI entry tam drafter-only, BE van cho approver scope - cho UAT anh Kiet
- Scaffold-bug caught: EF tu sinh RenameColumn BudgetManualAmount->ExpectedRemainingAmount (SAI semantics) -> thay bang Add+UPDATE+Drop
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|||
| 6db195dd42 |
[CLAUDE] PurchaseEvaluation: go han hanh dong "Tu choi" - chi con Duyet hoac Tra lai (UAT anh Kiet S60 14:14)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m30s
- Domain policy: xoa MOI transition -> TuChoi o ca 4 policy (NccOnly + NccWithPlan + ForV2Schema + FromDefinition) -> NextPhases het tra TuChoi, nut FE tu bien mat - Service guard S60: chan targetPhase=TuChoi moi caller ke ca Admin (dung truoc moi branch — spec bo han, khong escape hatch); message huong dan dung Tra lai / Xoa nhap - FE x2 app: filter phong thu next.filter(p != TuChoi) PeWorkflowPanel (SHA256 identical); dialog/isCancel giu dead-safe de flip lai de - Enum TuChoi + phieu TuChoi cu + tab filter "Tu choi" GIU display (data cu render binh thuong) - SlaExpiryJob chi dung Contract — PE khong auto-TuChoi, khong anh huong - Tests spec-change cung commit: Domain flip BothPolicies_TuChoi_RemovedFromAllTransitions_S60 + NEW V2SchemaPolicy fact; Infra NEW TargetTuChoi_WithRejectDecision_Throws_TuChoiRemoved_S60 (guard #45 test cu giu nguyen PASS — van dung truoc) - Test 254 -> 256 PASS (59 Domain + 197 Infra) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
|||
| 37122f0f64 |
[CLAUDE] PurchaseEvaluation: rang buoc du 4 thong tin muc 3 moi gui duyet + bypass nguoi soan trong chuoi duyet (UAT anh Kiet S60)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m38s
- Rename muc 3: "Chon NCC / TP thang thau" -> "Don vi NCC/TP duoc chon" (anh Kiet chot chu) x2 app + wording phu nhat quan - Guard gui duyet du CA 4 (anh chot): don vi duoc chon + gia chao thau >0 + ngan sach (Budget link HOAC nhap tay) + bang so sanh dinh kem + BE ConflictException gop moi muc thieu 1 lan, ap ca Admin (TransitionAsync submit branch) + FE pre-check missingForApproval cung predicate -> disable nut + tooltip liet ke du (computeGiaChaoThau extract single-source) - Bypass drafter-in-chain (luat GENERIC theo cap, anh chot): V2-only, BUOC DAU only - nguoi soan la approver cap k -> auto qua Cap 1..k khi gui + Audit 3 tang: Approval row AutoApprove per cap + LevelOpinion CHI slot chinh chu (khong gan chu ky NV bi skip) + Changelog + Pointer: k<max -> Cap k+1; het buoc -> Buoc 2 Cap 1; workflow 1 buoc -> terminal DaDuyet + TraLai resubmit ap lai idempotent (opinion UPSERT) - Tests: +14 PeSubmitGuardAndBypassTests (240 -> 254 PASS) - Reviewer die mid-run (gotcha #53 class) -> em main self-gate evidence-checklist PASS 0 blocker Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
|||
| 9c330d26c4 |
[CLAUDE] PurchaseEvaluation: UAT dot 2 - an Tra lai/Tu choi khi tu duyet phieu minh soan + quick-add NCC ngay form + NCC go-tim sort A-Z + upload nhieu file 1 lan
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m25s
- PeWorkflowPanel x2: nguoi duyet == nguoi soan (drafterUserId == currentUser.id) -> an ca "Tra lai" + "Tu choi" (anh chot: tra cho chinh minh vo nghia, huy phieu = nho cap khac tu choi / xoa phieu Nhap). - SuppliersController: POST tao NCC mo cho moi user dang nhap (anh chot - nghiep vu di thau phat sinh NTP moi lien tuc); PUT/DELETE van khoa Admin+CatalogManager (S57). - PeDetailTabs AddSupplierDialog x2: Select -> SearchableSelect (go-tim bo dau, sort A-Z theo ma) + nut "+ NCC moi" quick-create (Ma/Ten/Loai/SDT/Email) -> POST /suppliers -> auto-select vao phieu. - Upload file bao gia + bang so sanh x2: input multiple + upload tuan tu tung file (UAT "moi lan chi chon duoc 1 file"). - SHA256 mirror x2 app, build tsc+vite x2 PASS, BE 0 err, test 240/240 PASS local. |
|||
| c869d2617d |
[CLAUDE] PurchaseEvaluation: rename 71 WorkItems theo format PMH anh Kiet FDC chot (MAT-n/SUB-n/MEP-SUB-n/MEP-EQU-n + ten "STT nhom ten") + FE sort numeric
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m33s
- anh Kiet 16:59: "MA CV gom chu MEP-SUB-1 roi ten 1 MEP Sub MEP (Full) - dung kieu vay". - DbInitializer seed tuples 71 ma moi (VT->MAT, TP->SUB, MEP-0n->MEP-SUB-n, TB->MEP-EQU-n). - scripts/s59-rename-workitems-pmh.sql DA CHAY prod + LocalDB Dev TRUOC push (UPDATE giu Id, 71/71, OLD-CODES=0, verify JSON qua API prod tieng Viet nguyen ven). - FE x2 app (SHA256 mirror): PeWorkspaceCreateView + PeHeaderForm sort numeric-aware (ma khong pad -> string-sort loan "10"<"2") + tree Panel 1 workItemName numeric:true. - scripts/master-import-data.generated.md sync 71 dong W| + note mapping. |
|||
| bbd1554f74 |
[CLAUDE] Infra: WorkItems chi giu dung 71 ma PMH cong ty gui (chi Tra Sol chot) - go seed 15 demo + wipe prod 86->71
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m31s
- DbInitializer: XOA block seed 15 WorkItems demo (Phan tho/Hoan thien/Co dien/Khac - DAO-MONG, SON-NUOC, TRAT-TUONG... "ma anh tu de ra") -> nguon duy nhat = SeedRealMasterDataAsync 71 ma PMH (VT-01..16 + TP-01..30 + MEP-01..09 + TB-01..16). - scripts/s59-wipe-demo-workitems.sql DA CHAY prod + LocalDB Dev: 86 -> 71, demo categories bien mat, doi chieu 71/71 khop bang PMH cong ty gui tung dong. - An toan: PE=0 (Run #273 wipe) -> khong phieu nao tro WorkItemId demo. |
|||
| 6c5fd26428 |
[CLAUDE] Infra: tạm ẩn HRM/Văn phòng số/Cá nhân khỏi user thường + Danh mục xuống cuối sidebar (S58)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m24s
Anh yêu cầu (screenshot eoffice): ẩn các tính năng chưa golive + thu hồi phân quyền user thường; nhóm Danh mục đưa xuống cuối. - NEW RevokeTemporarilyHiddenModulesAsync (chạy cuối seed pipeline): set 4 cờ CRUD=false cho MỌI role TRỪ Admin trên keys Hrm* (gồm Hrm_Config*) + Off* (gồm Off_ChamCong thuộc Cá nhân) + Personal. Giữ row (không xóa) — flip lại nhanh khi golive. Menu tự ẩn cả 2 app (GetMyMenuTree lọc CanRead). - SeedAllRolesReviewReadPermissionsAsync: thu hẹp grant scope còn Master/Catalogs/Pe_* (bỏ Hrm/Off/Personal — không re-grant cái vừa revoke). - Menu "Danh mục" (Master) Order 20→80 — cuối vùng nghiệp vụ, trước System 90. Main upsert tự re-set Order trên DB cũ (idempotent sẵn). - KHÔNG đụng: Pe_* (sếp cần all-role) + Master/Catalogs CanRead (flow PE cần xem master data) + Admin (quản trị) + IsVisible layer (Menu eOffice toggle). Runtime-proof Dev: MasterOrder=80 · NonAdminHrmOffPersonalCanRead=0 · AdminHrmOffCanRead=28 · NonAdminPeCanCreate=120 · NonAdminMasterCanRead=48. Build 0/0, test 240 PASS. Lưu ý mức che: menu + permission matrix; URL gõ trực tiếp chưa chặn (FE không PermissionGuard per-route — chấp nhận "tạm ẩn"). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
|||
| 5998163642 |
[CLAUDE] Infra: fix lock-demo-user prod NO-OP — union 20 UAT-matrix email + DemoUserPassword 12 ký tự (S58)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m43s
Run #381 cicd phát hiện LockDemoSampleUsersAsync NO-OP trên prod: 14 email named-person là population Dev-only. Root cause sâu: DemoUserPassword 11 ký tự < prod RequiredLength=12 → CreateAsync silent-fail mọi startup từ trước tới giờ (luôn cả nv.cao/nv.truong IT pool — root cause helpdesk inert S56 — và 5 real staff thiếu account). Fix (anh chốt 3 quyết định qua AskUserQuestion): - Union 20 email UAT-matrix prod thật (act/equ/fin/hra/pm/qs × nv/pp/tp + bod.1/2, tạo tay 05-13) vào lock list — exact-email only, KHÔNG pattern (binh.le@ là người thật sát scheme demo). - DemoUserPassword User@123456 → User@1234567 (12 ký tự, thỏa policy prod) → startup tới trên prod sẽ TẠO named-person (rồi lock ngay cùng startup) + nv.cao/nv.truong ACTIVE (helpdesk sống lại) + 5 real staff. - GIỮ ACTIVE: nv.test (creds cicd smoke-verify) + chuong.phan@solution.com.vn (typo domain nhưng có thể login thật anh Chương — xác nhận rồi dọn sau). Trade-off deadline 15:00: ship trước, test-specialist viết guard test sau (test-after justify — list-data fix, logic lock không đổi). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
|||
| dd117b749c |
[CLAUDE] PurchaseEvaluation: PE gắn Hạng mục công việc (Mig 49) + mở quyền Pe all-role + menu Cá nhân + khóa 14 demo user
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m24s
Sếp chốt deadline 15:00 (Zalo 11:02-11:17): flow tạo phiếu chọn quy trình → dự án → HẠNG MỤC → NCC/TP; phiếu dạng «Dự án – Hạng mục»; all-user thấy Duyệt NCC + master config; clear data cũ. - Mig 49 AddWorkItemToPurchaseEvaluation: PE.WorkItemId Guid? loose-Guid + index (KHÔNG FK vật lý — convention PE, database-agent design). Validator NotEmpty (create) + FK-guard AnyAsync(IsActive) → Conflict + UpdateDraft NULL-SAFE (client không gửi → giữ, chống null-hóa bug-class S42). 3 projection ListItemDto LEFT-join WorkItems. - FE ×2 app: PeWorkspaceCreateView select «c. Hạng mục *» + PeHeaderForm (load existing + PUT gửi lại, SHA256 IDENTICAL) + PeDetailTabs (header «Dự án – Hạng mục» + FormRow + inline khóa) + types. Route reuse /catalogs/work-items. - Perm: SeedAllRolesReviewReadPermissionsAsync extend Pe_* 11 key (factory — Pe leaf không nằm All) CanRead+CanCreate upgrade-only mọi role; PeWf_*/AwV2 GIỮ Admin. HRM/Office/Master/Catalogs CanRead (S57). Master write-lock Admin,CatalogManager ×3 controller. - Menu «Cá nhân» (Personal root 30, mirror Puro) + Chấm công re-parent + HrmConfig→Master + parentBackfill idempotent + admin bỏ ẩn Master (đảo S29). - LockDemoSampleUsersAsync: khóa 14/16 sample (GIỮ nv.cao+nv.truong IT-pool + catalog.manager) — ungated idempotent, IsActive=0+Lockout+SecurityStamp rotate. - Tests +12 PeWorkItemGuardTests (validator/FK-guard/null-safe) → 240 PASS. npm ×2 + BE 0W/0E. - Excel (3) đối chiếu: 62/71/3 identical S55 — no data change. - Gate: em main evidence-checklist (2 reviewer-spawn die-0-byte — resume-kill; backstop 12 guard-test + authz-key/role-string/Mig-49 evidence-lệnh). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
|||
| a20cde89fb |
[CLAUDE] App: golive harden — LeaveBalance concurrency + ItTicket authz-order + DocxRenderer + Travel/Vehicle tests
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m19s
Pre-golive verification (S56) surfaced 4 issues; all fixed + verified (228 test pass, 0 build warning). #3 LeaveBalance lost-update (DB11 concurrency): terminal-approve deduction was an in-memory read-modify-write (UsedDays += NumDays) under a bare SaveChanges, so two concurrent terminal approvals of the same (user,type,year) lost an update. Fix: atomic server-side ExecuteUpdateAsync (UsedDays = UsedDays + n) inside an explicit Serializable transaction (matches the codegen/Proposal/TravelVehicle convention; serializes the auto-create-row race too). Exactly-once guard (Status != DaGuiDuyet) intact. No migration. #5 ItTicket reassign existence-oracle: AssignItTicketHandler checked ticket-NotFound before the Admin-OR-dept-IT Forbidden guard. Reordered so authorization runs first -> fail-closed (a non-IT/non-admin caller gets Forbidden for any ticketId, existent or not). #6 DocxRenderer CS8602: null-guard MainDocumentPart + Document with clear exceptions (cleared 2 build warnings -> 0). #4 Travel/Vehicle ApproveV2: added smoke tests (Submit->Approve terminal + outsider-Forbidden) — previously zero coverage. Tests 216 -> 228 (+12). database-agent DB-layer review PASS; em-main cross-stack review clean (reviewer workflow stage did not emit StructuredOutput -> em-main covered the cross-stack review by reading every diff). Bundles agent-memory harvest (S56). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
|||
| 69cb3937bb |
[CLAUDE] Master: nạp master data thật từ Excel (62 dự án + 71 hạng mục + 3 NCC) + Project +4 cột (Mig 48)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m33s
Nạp master data công ty từ file Excel 'HẠNG MỤC CÔNG VIỆC DỰ ÁN': - 62 Projects (Mã + Năm; tên/CĐT/địa điểm/gói thầu cho ~6 dự án có chi tiết) - 71 WorkItems: Vật tư 16 · Thầu phụ 30 · MEP 9 · Thiết bị 16 - 3 Suppliers (TRUONGGIANG/TANPHU/TGN) Mig 48 AddProjectMasterFields: Project +4 cột nullable (Year/Investor/Location/Package) + ProjectFeatures DTO/Create/Update + ProjectsPage form ×2 app (SHA256 mirror). SeedRealMasterDataAsync per-code idempotent, UNGATED → reaches prod (coexist demo). FLOCK01 collision → skip (demo wins). Verify: build 0-err · test 216 PASS · runtime Dev proof (data landed, Investor col populates). Provenance: scripts/master-import-data.generated.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
|||
| ca4b60277b |
[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>
|
|||
| dbf66489a9 |
[CLAUDE] Office: P11-D ItTicket admin reassign-UI + P11-E AttendanceReport menu-key
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m21s
Task C - ItTicket admin reassign-UI (fe-admin only):
- Per-card reassign dialog on ItTicketsPage kanban (admin override of round-robin auto-assign).
- Reuses existing PUT /it-tickets/{id}/assign (Admin-only) + GET /users picker. No new BE endpoint.
- fe-admin intentionally diverges from fe-user (read-only) — admin-management action.
Task D - AttendanceReport menu-key (P11-E promote, no migration):
- MenuKeys.OffAttendanceReport 'Báo cáo chấm công' leaf under Văn phòng số (order 8), Admin-perm auto via All[].
- DbInitializer idempotent seed + fe-admin menuKeys.ts/Layout staticMap -> existing /attendance/report route.
Pipeline: implementer-backend -> implementer-frontend -> reviewer (PASS, 0 issues). dotnet+npm builds clean. Tests 203 (unchanged - no new BE logic/schema).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|||
| 44b9e542fb |
[CLAUDE] Infra: gotcha #57 EXT Master filtered-unique Department/Supplier/Project (Mig 47)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m15s
Extend gotcha #57 filtered-unique fix to 3 Master catalogs (4th/5th/6th cumulative after Holiday Mig 43 S45 + HRM x3 Mig 45 S51). Root cause: app-level dup-check db.X.AnyAsync(Code==req) runs through HasQueryFilter(!IsDeleted) so it ignores soft-deleted rows, but the bare .IsUnique() DB index counted them -> admin delete+re-add same Code = reachable 500. Fix aligns index with query filter via .HasFilter("[IsDeleted] = 0"). - Department/Project/Supplier Configuration: unique Code index + .HasFilter (Supplier Type index untouched) - Mig 47 FilterMasterCatalogUniqueIndexesByIsDeleted (Up: 3x DropIndex+CreateIndex filtered; Down reversible) - test-before MasterCatalogFilteredUniqueTests (3 RED->GREEN, delete+re-add same Code) - Tests 200 -> 203 (58 Domain + 145 Infra) Pipeline: test-specialist -> implementer-backend -> reviewer (PASS, 0 issues). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
|||
| dcf76f8a9f |
[CLAUDE] Office: P11-D ItTicket auto-assign round-robin + SLA timer (Wave 2, Mig 46)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m17s
Mig 46 AddSlaFieldsToItTicket (SlaDueAt/SlaWarnedSent/SlaBreached). CreateItTicketHandler: round-robin least-loaded assign cho IT staff (dept Code=IT, tie-break Id) + SlaDueAt theo Priority (Urgent 4h/High 8h/Medium 24h/Low 72h). ItTicketSlaJob background (breach+warning notify, KHONG auto-transition). PUT /{id}/assign admin override. DbInitializer seed dept IT + 2 sample staff (nv.cao/nv.truong). FE ItTicketsPage +MaTicket+assignee+SLA badge (2 app SHA256 mirror). +9 test (191->200). Self-review PASS (seed<->query dept-code verified; em main solo review do session-limit kill reviewer-spawn).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|||
| 6a664298fa |
[CLAUDE] Office: P11-E AttendanceReport+Excel+OtPolicy + P11-F MaTicket codegen (Wave 1)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m10s
P11-F: MaTicket gen-on-create qua WorkflowAppCodeGen (IT/2026/NNN Serializable atomic, kanban no-workflow). P11-E: GetAttendanceReportQuery monthly aggregate (day-type weekday/weekend/holiday OT x OtPolicy multiplier in-memory) + AttendanceReportExcelExporter (ClosedXML) + 2 endpoint Admin-only + fe-admin AttendanceReportPage. Migration-free. +5 test (186->191). reviewer PASS (gotcha #44 role-string verified, 0 blocker). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
|||
| 30a99aa03f |
[CLAUDE] Hrm: P11-C Vehicle+Driver catalogs (Mig 44) + gotcha #57 filtered-unique 3 HRM catalog (Mig 45)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m18s
P11-C: extend HrmConfigs +2 kind (Vehicle/Driver) declarative. Mig 44 AddVehicleAndDriverCatalogs (2 table filtered-unique Code, tables 91->93). Domain entity + EF config (filtered day-1) + 2 DbSet + HrmConfigFeatures Region5/6 CRUD + Controller +2 route-group (GET public / write Roles=Admin) + MenuKeys +2 +All (auto Admin perm) + DbInitializer 2 menu leaf + idempotent seed 2 veh/2 drv. FE declarative KIND_CONFIG +2 kind x2 app (SHA256 mirror) + 4-place (types/page/menuKeys/Layout staticMap), :kind-driven no new route. gotcha #57 (bundled; OtPolicy missed in backlog, caught via grep) - Mig 45 FilterHrmCatalogUniqueIndexesByIsDeleted: LeaveType+ShiftPattern+OtPolicy bare .IsUnique() -> .HasFilter([IsDeleted]=0) (recreate-on-soft-deleted-slot 500 fix, mirror Holiday Mig 43). Tests +5 HrmConfigFilteredUniqueTests (181->186 PASS) test-before RED->GREEN. Reviewer caught FE<->BE Driver required-field mismatch -> fixed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
|||
| 0c5a014ebe |
[CLAUDE] Infra: Mig 43 filter Holiday UNIQUE (Year,Date) by IsDeleted (S45)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m19s
Fix drift surfaced by S45 Holiday coverage tests: DB UNIQUE (Year,Date) was unfiltered while handler checks !IsDeleted -> recreating a holiday on a soft-deleted slot threw DbUpdateException(500). Add .HasFilter("[IsDeleted] = 0") matching the 13x project filtered-unique pattern (Catalogs/Contract/PE/Proposal/Budget/WorkflowApps). Soft-deleted slot now reusable per app intent. Flipped Case 7 to assert success-on-reuse. 181 test PASS.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|||
| 82d7fcff4d |
[CLAUDE] Workflow: LeaveBalance business logic — trừ phép khi duyệt + số dư (Phase 11 P11-B)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m8s
Số dư phép theo (User × LeaveType × Year) + trừ tự động khi đơn nghỉ duyệt cuối. Policy: cho phép vượt số dư (âm) + cảnh báo (anh main chốt), tích hợp vào trang đơn nghỉ. Schema (Mig 42 AddLeaveBalances — pure additive, 1 bảng): - LeaveBalance: UserId + LeaveTypeId + Year + EntitledDays + UsedDays + AdjustmentDays. UNIQUE (UserId,LeaveTypeId,Year), FK LeaveType Restrict, decimal(5,2). Remaining = Entitled + Adjustment − Used (computed, không store). Deduction hook (ApproveLeaveRequestHandler nhánh terminal DaDuyet — exactly-once): - Upsert LeaveBalance(RequesterUserId, LeaveTypeId, StartDate.Year), auto-create từ LeaveType.DaysPerYear, UsedDays += NumDays. Guard Status!=DaGuiDuyet chặn re-approve. FK invariant guard (em main thêm sau test reveal FK risk): - Create + UpdateDraft validate LeaveTypeId tồn tại (AnyAsync) → ConflictException. Đóng cửa vào — bogus type không thể tới deduction FK insert (tránh 500 kẹt đơn). CQRS LeaveBalanceFeatures.cs: GetMy (self, lazy merge active LeaveType) + GetUser (admin) + AdjustLeaveBalance (admin upsert carry-over). Controller [Authorize] + admin Roles=Admin. Embed: GetLeaveRequestByIdHandler trả balance NGƯỜI TẠO (approver xem thấy đúng). FE: WorkflowAppDetailPage ×2 — block "Số dư phép" + cảnh báo vượt khi kind=leave (SHA256 identical). Tests (+11, 130→154 PASS): deduction single/multi-level/accumulate/negative-allowed/ reject-return-no-deduct + lazy-merge + adjust upsert + Create guard bogus→Conflict. Cũng repair 2 test S42 terminal FK-fail (template BuildLeave +seed LeaveType). Verify: build 0 error · 154 test · FE ×2 · reviewer Max PASS (deduction exactly-once + FK invariant fully closed, 2 minor concurrency/comment defer). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
|||
| 75df04ec82 |
[CLAUDE] Workflow: fix workflow picker 2 bug (P11-A Max re-review) + SetWorkflow endpoint
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m5s
Double-check chất lượng P11-A ở Max (agents trước chạy High + truncate 3×) → phát hiện 2 bug THẬT trong workflow-picker FE của WorkflowAppDetailPage (core approve/reject/return ĐÚNG, chỉ sub-flow chọn quy trình hỏng): Bug #1 (HIGH) — pinWorkflow PUT /{id} chỉ gửi {approvalWorkflowId} → UpdateDraft validator (Reason NotEmpty, NumDays>0...) fail → 400. Nút "Lưu quy trình" vỡ. Bug #2 (HIGH) — fetch workflow expect flat array nhưng endpoint trả AwAdminOverviewDto {types:[...]} → picker rỗng/crash. FE copy nhầm pattern hỏng của ProposalCreatePage thay vì PE/Contract proven. Fix: - BE: thêm endpoint chuyên dụng PUT /{id}/workflow + Set{Module}WorkflowCommand/Handler cho 4 module — chỉ set ApprovalWorkflowId trên draft Nhap/TraLai (verify ApplicableType per module), KHÔNG validate field khác. Single-responsibility, bulletproof. - FE: sửa fetch mirror PE/Contract (data.types.find(t=>t.applicableType===X)?.history .filter(isUserSelectable)) + pin gọi endpoint mới. fe-admin+fe-user SHA256 identical. - Test: +3 SetWorkflow (happy no-status-change / wrong ApplicableType Conflict / submitted guard) → 141→144 PASS. Verify: BE build 0 error · 144 test PASS · FE build ×2 · SHA256 identical. Bonus phát hiện: ProposalCreatePage (S37) có bug #2 có sẵn (latent, chưa exercise UAT) → flag spawn task riêng, KHÔNG fix trong commit này. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
|||
| e7b66cd52b |
[CLAUDE] Workflow: wire ApproveV2 + LevelOpinions cho 4 WorkflowApps module (Phase 11 P11-A)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m6s
Wire full approval workflow V2 cho Leave/OT/Travel/Vehicle — cookie-cutter
mirror Proposal (Mig 38). Trước đây skeleton Phase 1 (Create+List), giờ
ApproveV2 advance-level + UPSERT LevelOpinion + atomic codegen.
Schema (Mig 41 WireWorkflowAppsApprovalV2 — 84→89 tables, pure additive):
- 4 bảng {Leave,Ot,Travel,Vehicle}LevelOpinions (UNIQUE composite + Cascade
parent + Restrict Level — mirror ProposalLevelOpinion)
- 1 bảng WorkflowAppCodeSequences (shared atomic MaDonTu, Prefix-keyed)
- 4 cột RejectedFromStatus (smart return tracking)
- enum ApprovalWorkflowApplicableType.TravelRequest = 9
Application (LeaveOt + TravelVehicle ApprovalFeatures.cs — 30 handler):
- GetById detail (Include LevelOpinions + JOIN Step/Level) · UpdateDraft
- Submit (gen MaDonTu + DaGuiDuyet + level=1, verify ApplicableType per module)
- Approve (verify actor==ApproverUserId OR Admin, UPSERT opinion latest-write-wins,
advance level OR terminal DaDuyet, empty comment → placeholder)
- Reject (→TuChoi) · Return (→TraLai + RejectedFromStatus)
Api: 4 controller +6 route mỗi cái (GET/{id}, PUT/{id}, submit/approve/reject/return)
Infra: DbInitializer seed 4 workflow V2 mẫu (QT-NP/OT/CT/XE-V2-001) → UAT test ngay
FE: WorkflowAppDetailPage.tsx declarative 4-kind (fe-admin+fe-user SHA256 identical)
— workflow status + opinion timeline + action buttons; gỡ banner skeleton + row nav
Tests: +11 WorkflowAppApproveV2Tests (130→141 PASS) — state machine + UPSERT
invariant + guards + codegen + forbidden + placeholder (Leave full + Ot smoke)
Verify: build 0 error · 141 test PASS · FE build ×2 · reviewer checklist
(ApplicableType per-module + cross-module DbSet + [Authorize] — no copy-paste bug)
Known-minor (unreachable): Reject/Return actor-check skip nếu CurrentApprovalLevelOrder
null — nhưng DaGuiDuyet luôn có set (defer hardening).
ItTicket KHÔNG đụng (kanban, no workflow V2).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|||
| e54a22de0c |
[CLAUDE] Domain+App+Infra+Api+FE-Admin+FE-User: S38 G-O4+G-O5+G-O6+G-P1+G-H3 SKELETON full-stack
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m53s
Phase 10.3-10.4 SKELETON 5 plan combo finish — Mig 39+40 + BE skeleton 7 module + FE 2 app SHA256 IDENTICAL + 11 menu key. UAT visible end-to-end. ⚠️ SKELETON Phase 1 trade-off rõ: - Status flat 5-state WorkflowAppStatus enum share Leave/OT/Travel/Vehicle - ApproveV2 workflow advance DEFER Phase 11 (Drafter Create OK, Approve flow chưa wire) - LevelOpinions per-module DEFER Phase 11 - LeaveBalance calc + Auto-assign + SLA timer DEFER Phase 11 - CodeGen atomic + MaDonTu/MaTicket gen DEFER Phase 11 - Vehicle catalog + Driver catalog DEFER Phase 11 (free text VehicleLicense) - ItTicketComments thread DEFER Phase 11 (free text Resolution field) Mig 39 (em main solo): 5 entity Workflow Apps schema - LeaveRequest (G-O4, FK LeaveType Hrm Mig 35, ApplicableType=5) - OtRequest (G-O4, FK OtPolicy optional, ApplicableType=6) - TravelRequest (G-O4, reuse ApplicableType=4 Proposal) - VehicleBooking (G-O5, free text vehicle, ApplicableType=7) - ItTicket (G-O6, NO workflow V2 — kanban status flow) Mig 40 (em main solo): Attendance entity (G-P1) - GPS lat/long check-in/out + Source enum Web/Mobile/Device - UNIQUE composite (UserId, AttendanceDate) - WorkHours computed simple diff (NO OtPolicy multiplier yet) BE CQRS (em main solo, single mega ~1100 LOC): - WorkflowAppsFeatures.cs 7 region (5 module Create+List + Attendance CheckIn/Out/GetMonth + HrDashboard) - 7 Controller: /api/leave-requests + /ot-requests + /travel-requests + /vehicle-bookings + /it-tickets + /attendances + /hr/dashboard - Class-level [Authorize] any authenticated - 13 endpoint total FE 2 app (em main solo fallback gotcha #53 risk): - types/workflowApps.ts × 2 SHA256 IDENTICAL 77470e182a15de88 (all DTOs + Status badge) - WorkflowAppsListPage.tsx × 2 IDENTICAL 58139d0301a60ddf — generic declarative KIND_CONFIG handles 4 module (Leave/OT/Travel/Vehicle) - ItTicketsPage.tsx × 2 IDENTICAL d3062de2f54c794c — kanban 5 status column - MyAttendancePage.tsx × 2 IDENTICAL 86da48ae147db012 — GPS check-in/out + tháng calendar - HrmDashboardPage.tsx × 2 IDENTICAL d9c6c12a5a8694f8 — 4 KPI card + gender ratio + status breakdown - Pattern 16-bis 9× cumulative (App.tsx +4 routes + menuKeys +8 const + Layout staticMap +7 entry) - 7 amber banner "Skeleton Phase 1 — full feature Phase 11" rõ ràng UAT Menu seed: +11 const + SeedMenuTreeAsync 8 row (Off_DonTu sub-group + 3 leaf + Off_DatXe + Off_ItTicket + Off_ChamCong + Hrm_Dashboard). DbInitializer Sample workflow seed DEFER (workflows V2 already seeded từ S29+S37 reuse — admin clone tạo riêng per ApplicableType=5/6/7). Verify: - dotnet build PASS 0 error 2 pre-existing warning - dotnet test 130/130 PASS baseline preserve - npm build × 2 PASS clean - SHA256 verify 5 file × 2 app all IDENTICAL Plan G-* progress 11/11 ✅ (100% COMPLETE): ✅ G-H1 (S33) + G-O1 (S34) + G-H2 (S35) + G-O2 (S36) + G-O3 (S37) + ✅ G-O4 + G-O5 + G-O6 + G-P1 + G-H3 (S38 skeleton) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| de1c378279 |
[CLAUDE] Domain+App+Infra+Api+FE-Admin+FE-User: S37 Mig 37 enum + Plan G-O3 Đề xuất full-stack
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m53s
Phase 10.3 G-O3 Đề xuất (Proposal) — Mig 37 enum extend +5 values + Mig 38 Proposal schema + BE CQRS 8 endpoint + FE 2 app SHA256 IDENTICAL. Mig 37 (em main solo): extend ApprovalWorkflowApplicableType enum +5 values ProposalGeneral=4 / LeaveRequest=5 / OtRequest=6 / VehicleBooking=7 / ItTicket=8 cookie-cutter Mig 22 pattern (Up/Down empty — enum mức Domain). Mig 38 (em main solo): 4 entity Proposal (Code DX/YYYY/NNN) + ProposalAttachment + ProposalLevelOpinion (UNIQUE composite PEId+LevelId mirror PE Mig 26) + ProposalCodeSequence (Prefix PK atomic seq). 4 EF Config + 2 DbContext mod. BE CQRS (em main solo ~700 LOC ProposalFeatures.cs sau Implementer truncate phase exploration gotcha #53 5th + 529 Overload): - 4 Header handler (List paged + GetById detail + Create + UpdateDraft owner-OR-admin) - 4 Workflow handler (Submit gen MaDeXuat atomic + Approve UPSERT LevelOpinion advance + Reject + Return) - SERIALIZABLE transaction CodeGen - DTOs nested LevelOpinion với Step+Level metadata JOIN ProposalsController 8 endpoint /api/proposals (List/GetById/Create/Update/Submit/Approve/Reject/Return) class-level [Authorize] + handler-level owner-OR-admin guard. DbInitializer: SeedSampleProposalWorkflowV2Async ~40 LOC seed QT-DX-V2-001 IsUserSelectable=true NOT gated DemoSeed per gotcha #51. SeedMenuTreeAsync +4 row (Off_DeXuat sub-group + 3 leaf). FE 2 app (em main solo + Implementer 529 fail fallback): - types/proposal.ts × 2 SHA256 IDENTICAL 95607052ff1138f2 - ProposalsListPage.tsx × 2 IDENTICAL 603f0d9cf74cd09a — table 6 cột + Status badge + filter - ProposalCreatePage.tsx × 2 IDENTICAL 6aed3a76563dd576 — Form Header card - ProposalDetailPage.tsx × 2 IDENTICAL 3dc229ea8dcc9bc0 — 3 Section + WorkflowActions - Pattern 16-bis 8× cumulative (App.tsx + menuKeys + Layout staticMap 3 entry) Verify: - dotnet build PASS 0 error 2 warning pre-existing DocxRenderer - dotnet test 130/130 PASS baseline preserve - npm build × 2 PASS (fe-admin 14.72s + fe-user 6.40s) - SHA256 verify 4 file × 2 app all IDENTICAL Pattern reinforced cumulative S37: - Pattern 12-bis cross-module mirror 11× (PE V2 → Proposal V2 ApproveV2) - Pattern 16-bis 4-place mirror cross-app 8× - gotcha #53 5th occurrence Implementer mid-exploration truncation + 529 Overload 1× — em main solo fallback proven Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| f45090b654 |
[CLAUDE] Domain+App+Infra+Api+FE-Admin+FE-User: S36 Plan G-O2 Phòng họp Mig 36 + BE CRUD + FE 2 app
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m55s
Phase 10.2 G-O2 Phòng họp BookingCalendar — Mig 36 schema + BE CQRS + FE 2 app mirror cookie-cutter G-H2 HrmConfig pattern. Standalone không depend workflow. BE schema (Mig 36 — em main solo Step 4): - 4 Domain new: MeetingRoom catalog + MeetingBooking header + MeetingBookingAttendee join table N-to-N (NOT JSON per Investigator verdict) + Enums (MeetingBookingStatus 3-state: Confirmed/Cancelled/Completed) - 3 EF Config: UNIQUE Code + composite index (RoomId, StartAt) range query + UNIQUE composite (BookingId, UserId) join - FK strategy: Room→Restrict (preserve history) + Booking→Cascade attendees + User→Restrict (denorm FullName+Email tránh cascade wipe) - Mig 36 3-file rule + ApplicationDbContextModelSnapshot updated + apply Dev+Design DB BE CQRS (~584 LOC — Implementer Case 2): - MeetingFeatures.cs 479 LOC 9 handler: 4 Room CRUD + 5 Booking (List + GetById + Create + Update + Cancel) - SERIALIZABLE transaction overlap check via EXISTS query — throw 409 Conflict "Phòng đã được đặt trong khoảng thời gian này" - MeetingRoomsController 49 LOC + MeetingBookingsController 56 LOC — class-level [Authorize] + Roles="Admin" for write - Application.csproj +Microsoft.EntityFrameworkCore.Relational package (em main fix IsolationLevel overload — Implementer gotcha #53 4th truncation diagnose mid-task) - MenuKeys.cs +4 const (Off_PhongHop sub-group + View/Manage/Book leaf) - DbInitializer +SeedMeetingRoomsAsync 4 sample (PH-A Phòng họp lớn cap=20 + PH-B cap=8 + PHG-501 Giám đốc cap=6 + ONL-1 Online Zoom cap=50) — NOT gated DemoSeed per gotcha #51 INFRASTRUCTURE seed FE 2 app (~1770 LOC × 2 — Implementer Case 2): - types/meeting.ts × 2 SHA256 IDENTICAL (ce0ad9c6d017cde2) — DTO interface mirror - MeetingCalendarPage.tsx × 2 SHA256 IDENTICAL (d6d160ae1e4f2285) ~530 LOC — custom HTML 7-day grid 8h-20h slot, NO FullCalendar dep (~80 KB bundle saved per Investigator verdict alternative) - MeetingRoomsPage.tsx × 2 SHA256 IDENTICAL (ba35a7ef379a5e9c) ~270 LOC — admin catalog CRUD table + Dialog - 4-place mirror Pattern 16-bis 7× cumulative: types + page + App.tsx route + menuKeys + Layout staticMap 3 entry (gotcha #50 silent sidebar drop prevention) Verify: - dotnet build SolutionErp.slnx PASS 0 error 2 pre-existing DocxRenderer warning - dotnet test 130/130 PASS baseline preserve (58 Domain + 72 Infra) - npm build × 2 app PASS 0 TS error (fe-admin 16.91s bundle 1490 KB / fe-user 8.56s bundle 1404 KB, +23 KB gzip both) Pattern reinforced cumulative S36: - Pattern 12-bis cross-module mirror 10× (PE → Contract V2 → Hrm → Office) - Pattern 16-bis 4-place mirror cross-app 7× - Smart Friend Implementer truncation gotcha #53 4th — mitigation tight brief WORK (FE 2 app no truncation, BE truncate diagnose mid only) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 909655c40d |
[CLAUDE] App+Api: S35 Plan G-H2 Task 3 — HrmConfig BE CRUD 16 endpoint cookie-cutter
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m43s
Pattern 12-bis cumulative 3× (S29 Plan B + Chunk C + S35 G-H2). Mega scaffold mirror
Master/Catalogs/CatalogsFeatures.cs 334 LOC pattern → SolutionErp.Application/Hrm/
HrmConfigFeatures.cs 439 LOC. 4 region cookie-cutter cho 4 HRM catalog (LeaveTypes +
Holidays + ShiftPatterns + OtPolicies). 16 endpoint qua HrmConfigsController.cs 137 LOC.
## Scope (Implementer Case 2 ~25K spawn)
- HrmConfigFeatures.cs 4 region × (DTO + List + Create cmd/validator/handler + Update cmd/validator/handler + Delete cmd/handler) = 4 DTO + 4 List query + 4 Create + 4 Update + 4 Delete handler
- HrmConfigsController.cs URL `/api/hrm-configs/{kind}` × {leave-types, holidays, shifts, ot-policies} × 4 verb = 16 endpoint
- Authorization: Class `[Authorize]` + write `[Authorize(Roles="Admin")]` 12 attribute (4 × 3 write verb) mirror Catalogs precedent
- Conflict check: 8 AnyAsync IsDeleted (4 Create + 4 Update với composite Year+Date Holiday exclude-self via `x.Id != req.Id`)
- Validator: 8 AbstractValidator + 44 RuleFor — MaxLength match EF source-of-truth (Smart Friend Implementer caught spec drift, aligned)
- HRM entities NO HasQueryFilter (4 vs 9 file Master have it) — explicit `.Where(!IsDeleted)` in List/Conflict-check queries
## Build + Test verify
- dotnet build PASS 0 err (2 pre-existing DocxRenderer warning unrelated)
- dotnet test 130/130 PASS preserve (BE-only, no FE/test touch)
- FE files NOT touched (defer Task 4 G-H2 FE Admin next chunk)
- EF Config + DbInitializer + IApplicationDbContext: S34 done, no re-touch
## Pre-commit Reviewer Smart Friend 8× clean cumulative
S22+S25+S29×2+S33×2+S35×2 (FE forms + BE CRUD)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 07b3f3b284 |
[CLAUDE] Domain+App+Infra+FE-Admin+FE-User: S34 Plan 4 G-H2 Mig 35 schema foundation
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m30s
Phase 10.2 G-H2 Cấu hình HRM — 4 catalog lookup foundation deploy (BE CRUD +
FE forms DEFER S35 cho clean handoff).
Mig 35 `AddHrmConfigs` — 4 table mới:
- LeaveTypes (Code unique + Name + DaysPerYear decimal(5,2) + IsPaid +
RequiresAttachment) — 5 sample seed (ANNUAL 12d + SICK 30d + MATERNITY 180d
+ COMPASSIONATE 3d + UNPAID 0d)
- Holidays (Year + Date UNIQUE composite + Name + IsRecurring + IsPaid) —
10 sample VN 2026 (Tết Dương + 5 Tết Nguyên đán placeholder + Giỗ tổ +
30/4 + 1/5 + 2/9 + Quốc khánh)
- ShiftPatterns (Code unique + Name + StartTime/EndTime TimeOnly + BreakMinutes +
WorkDays comma string) — 3 sample (HC 8-17 T2-T6 + CA1 6-14 T2-T7 + CA2 14-22)
- OtPolicies (Code unique + 3 Multiplier decimal(4,2) + 3 MaxHours int) —
1 sample STANDARD (1.5x/2.0x/3.0x weekday/weekend/holiday + 4h/40h/200h cap
Luật Lao động VN 2019)
Files:
- Domain/Hrm/{LeaveType,Holiday,ShiftPattern,OtPolicy}.cs (4 entity AuditableEntity)
- Infrastructure/Persistence/Configurations/{LeaveType,Holiday,ShiftPattern,OtPolicy}Configuration.cs (4 EF Config UNIQUE indexes)
- IApplicationDbContext + ApplicationDbContext +4 DbSet
- Migrations/20260527075940_AddHrmConfigs.{cs,Designer.cs} + Snapshot updated (3-file rule)
- DbInitializer.SeedHrmConfigsAsync ~120 LOC seed sample (NOT gated DemoSeed per gotcha #51)
- MenuKeys.cs +HrmConfig sub-group + 4 leaf (LeaveTypes/Holidays/Shifts/OtPolicies) Order=2 dưới Hrm
- DbInitializer.SeedMenuTreeAsync +5 entry (sub-group + 4 leaf)
- fe-admin + fe-user menuKeys.ts +5 const mirror BE (Pattern 16-bis sync)
Verify:
- dotnet build PASS (2 warn DocxRenderer baseline, 0 error)
- dotnet test 130/130 PASS baseline preserve
- Mig 35 applied LocalDB SolutionErp_Dev — verified via dotnet ef database update
- 4 catalog table created + 5+10+3+1 = 19 sample row seed
Defer S35:
- Task 2 BE CQRS 4 catalog CRUD (16 endpoint) — Implementer Case 2 cookie-cutter
- Task 4 FE 2 app 4 catalog page (list/create/edit dialog) — Implementer Case 2
Cumulative S34 mig: 34 → 35 (+1). Tables 67 → 71 (+4). Menu keys 64 → 69 (+5).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| e506cd8135 |
[CLAUDE] App+Api: S34 Plan 3 Item 3 BE 5 satellite CRUD scaffold (15 endpoint)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m36s
Phase 1.5 Item 3 BE — Implementer Case 2 cookie-cutter 5-entity scaffold
mirror parent EmployeeProfile CRUD pattern (Pattern 12-ter NEW saved).
New file: Application/Hrm/EmployeeSatelliteFeatures.cs (621 LOC):
- 5 region (#region {EntityName}) — WorkHistory/Education/FamilyRelation/Skill/Document
- Each region: Create/Update/Delete Command + Validator + Handler
- Verify parent EmployeeProfile.Exists pattern AnyAsync(!IsDeleted)
- Soft delete IsDeleted=true + DeletedAt=UtcNow + DeletedBy=currentUser
- Validator nullable enum IsInEnum().When(HasValue) pattern
Modified file: Api/Controllers/EmployeesController.cs (70 → 234 LOC, +15 endpoint):
- 5 region × 3 verb (POST/PUT/DELETE) = 15 satellite endpoint
- Path per satellite:
- /api/employees/{id}/work-history
- /api/employees/{id}/education
- /api/employees/{id}/family-relations
- /api/employees/{id}/skills
- /api/employees/{id}/documents
- Per-action policy: Hrm_HoSo.Create/Update/Delete (override class-level Read)
- BadRequest guard: id != cmd.{EmployeeProfileId|Id} → "ID không khớp"
Document satellite metadata-only — file upload IFileStorage body wire defer S35.
Verify:
- dotnet build PASS (2 warn DocxRenderer baseline, 0 error)
- dotnet test 130/130 PASS (58 Domain + 72 Infra baseline preserve, no test add)
- Endpoints count: ~154 → 169 (+15)
- LOC delta: +785 BE (621 features + 164 controller)
Pattern 12-ter NEW (Implementer MEMORY): 5× satellite CRUD scaffold cookie-cutter
within-module (different from Pattern 12-bis cross-module mirror). Reusable
cho future N-satellite parent (vd Contract attachments, PE quotes, Budget details).
Defer S35:
- FE inline edit forms 5 satellite section (~1.5h em main solo)
- Test bundle satellite CRUD (~30 phút Implementer Case 3)
- IFileStorage Document body upload wire (multipart form-data)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 61e9ce5b3b |
[CLAUDE] Domain+App+Api+Tests+FE-Admin+FE-User: S34 Plan 3 Phase 1.5 batch 4 item
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m48s
Phase 1.5 backlog G-H1 EmployeeProfile hardening batch (Items 6+2+1+4 of 6). Item 6 — menuKeys FE drift sync × 2 app: - fe-admin add: Catalogs + 4 Catalog leaves + Workflows + Budgets + Bg_List/Create/Pending (10 key) - fe-user add: Budgets + Bg_List/Create/Pending + ApprovalWorkflowsV2 + 2 AwV2 leaf + MenuVisibility + Workflows (8 key) - Cả 2 file giờ identical mirror BE MenuKeys.cs (28 key cumulative) Item 2 — UpdateEmployeeProfileCommand bool→bool? safe partial update: - 3 field IsCommunistParty/IsYouthUnion/IsTradeUnion → bool? - Handler: HasValue check, null = giữ giá trị cũ (Reviewer minor #(b) S33 fixed) - FE không bắt buộc gửi 3 field every PUT — tránh accidental reset Item 1 — EmployeesController per-action policy (gotcha #44 mitigation): - Class-level [Authorize(Policy = "Hrm_HoSo.Read")] — non-admin thiếu Read → 403 - POST [Authorize(Policy = "Hrm_HoSo.Create")] - PUT [Authorize(Policy = "Hrm_HoSo.Update")] - DELETE [Authorize(Policy = "Hrm_HoSo.Delete")] Item 4 — Test bundle Phase 1.5 (+10 [Fact], baseline 120 → 130/130 PASS): - EmployeeCodeGeneratorTests (3 [Fact]) — atomic SERIALIZABLE NV/YYYY/NNNN + first call + sequential increment + year boundary preserve old year - CreateEmployeeProfileCommandTests (4 [Fact]) — Create handler edge case + first profile + duplicate UserId Conflict + soft-deleted Conflict-restore + UserNotFound NotFoundException - ListEmployeesQueryTests (3 [Fact]) — filter + paging logic + status filter + departmentId filter + search by EmployeeCode partial Implementer Case 3 test gen caught spec mismatch (allow new after soft-delete vs throws Conflict-restore) — chose CODE source of truth + renamed test documenting discriminator message branch. Em main verify behavior correct (admin UX khôi phục thay vì tạo mới — explicit flow defer Phase 1.5+). Verify: - dotnet build PASS (2 warn DocxRenderer baseline, 0 error) - dotnet test 130/130 PASS (58 Domain + 72 Infra = +10) - 4 endpoint /api/employees policy wired (gotcha #44 active mitigation) - 4 MEMORY agent updated post-spawn (CICD Run #238 + Implementer test bundle) Deferred Phase 1.5 next batch: - Item 3 Satellite CRUD endpoints (WorkHistory/Education/FamilyRelation/Skill/ Document) + FE inline edit forms — heavy ~2-3h - Item 5 UAT smoke non-admin role verify silent 403 catch — defer post-deploy Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| ea440da990 |
[CLAUDE] Domain+App+Api+Infra+FE-Admin+FE-User: S34 Plan 2 G-O1 Danh bạ nội bộ
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m46s
Phase 10.2 Văn phòng số — Internal Directory (1 endpoint reuse Users + EmployeeProfiles + Departments, FE card grid avatar/dept/email/phone/Ext). BE Task 1+2 (em main solo): - Application/Office/DirectoryFeatures.cs — GetDirectoryQuery + DirectoryItemDto 12 field LEFT JOIN Users.IsActive + Departments + EmployeeProfiles - Api/Controllers/DirectoryController.cs — GET /api/directory?search=&departmentId= class-level [Authorize] (mọi authenticated NV tra cứu danh bạ nội bộ) - MenuKeys.cs +Off+OffDanhBa const + All[] update - DbInitializer.SeedMenuTreeAsync Off Order=29 + OffDanhBa Order=1 dưới Off FE Task 3 (Implementer Case 2 Pattern 16-bis 4-place mirror cross-app — 5×): - types/directory.ts SHA256 7349d9f64e78 × 2 app IDENTICAL - pages/office/InternalDirectoryPage.tsx SHA256 2aa7e0eed2c8 × 2 app IDENTICAL Card grid responsive 1/2/3/4 col + filter dept dropdown + search input Avatar 14×14 initials gradient PALETTE 6 màu (Pattern 14 Tailwind JIT) EmployeeCode badge + Department emerald badge + email mailto + phone tel Internal phone Ext: amber badge + empty/loading state Vietnamese 100% - App.tsx route /directory × 2 app - lib/menuKeys.ts Off+OffDanhBa const × 2 app - components/Layout.tsx resolvePath staticMap Off_DanhBa:/directory × 2 app (gotcha #50 — 5 places mirror crossapp DON'T MISS) Verify: - dotnet build PASS (2 warn DocxRenderer existing, 0 error) - dotnet test 120/120 PASS (58 Domain + 62 Infra baseline preserve) - npm build × 2 app PASS 0 TS err (fe-admin 1436KB / fe-user 1350KB) Implementer MEMORY Pattern 16-bis reinforced 5× cumulative (S29 Plan CA HF1 + S29 Plan B Chunk D + S33 Plan B G-H1 Task 5 + S34 Plan G-O1 Task 3). Endpoint smoke pending CICD post-deploy Stage 4 (Run #XXX expected ~3m30s). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 0e191deea5 |
[CLAUDE] Domain+App+Api+Infra: Plan B G-H1 Task 4+6 — Hrm CQRS 5 endpoint + Permission menu
Phase 10.1 G-H1 Phase 2 — Task 4 (BE CQRS + REST endpoint) + Task 6
(Permission menu seed) cumulative. Foundation BE side complete cho Hồ sơ
Nhân sự module — FE Task 5 + Reviewer Task 7 + CICD verify next.
## Task 4 — BE CQRS + Controller (3 file new, Implementer Case 2)
src/Backend/SolutionErp.Application/Hrm/EmployeeFeatures.cs (~450 LOC):
- CreateEmployeeProfileCommand + Validator + Handler
- Verify User.Id exists qua UserManager.FindByIdAsync
- UNIQUE 1-1 check: throw ConflictException nếu User đã có EmployeeProfile
- EmployeeCode auto-gen qua IEmployeeCodeGenerator (NV/{YYYY}/{Seq:D4})
- 50+ field assignment từ Command record
- UpdateEmployeeProfileCommand + Validator + Handler (mutable fields, UserId+EmployeeCode immutable)
- DeleteEmployeeProfileCommand + Handler (soft delete IsDeleted=true)
- GetEmployeeProfileQuery + Handler (Include 5 satellite collection)
- ListEmployeesQuery + Handler (paged + JOIN Users+Departments, filter Status/DepartmentId/Search)
src/Backend/SolutionErp.Application/Hrm/Dtos/EmployeeDtos.cs (~110 LOC):
- EmployeeProfileListItemDto (Id, EmployeeCode, UserId, FullName/Email/Department JOIN, Status, Phone, HireDate)
- EmployeeProfileDetailDto (full 50+ field + 5 satellite collection)
- 5 satellite DTO: EmployeeWorkHistoryDto + EmployeeEducationDto +
EmployeeFamilyRelationDto + EmployeeSkillDto + EmployeeDocumentDto
src/Backend/SolutionErp.Api/Controllers/EmployeesController.cs (~70 LOC):
- 5 REST endpoint: GET list / GET detail / POST / PUT / DELETE
- Class-level [Authorize] only Phase 1 (per-action policy Hrm_HoSo_View/Create/
Edit/Delete defer Phase 1.5 per Reviewer recommend)
- Route prefix /api/employees
## Task 6 — Permission menu Hrm_HoSo* (em main solo, 2 file mod)
src/Backend/SolutionErp.Domain/Identity/MenuKeys.cs (+10 LOC):
- +2 const: Hrm root group + HrmHoSo leaf
- Update All[] array → SeedAdminPermissionsAsync auto-grant Admin role CRUD
src/Backend/SolutionErp.Infrastructure/Persistence/DbInitializer.cs (+4 LOC):
- SeedMenuTreeAsync +2 entry:
- (Hrm, "Nhân sự", null, 28, "UserCircle") — root group
- (HrmHoSo, "Hồ sơ Nhân sự", Hrm, 1, "ContactRound") — leaf
- Order=28 between Budgets=27 và Contracts=30+ (no collision)
- INFRASTRUCTURE menu seed (NOT gated DemoSeed:Disabled — em main verified
outside gate block per gotcha #51 lesson, mirror Plan B Task 3b
SeedDemoEmployeeProfilesAsync placement)
## Reviewer ae752c0 verdict: PASS Smart Friend 6× clean
- 0 critical, 0 major, 3 minor defer Phase 1.5 (per-action policy + bool
partial update + IDateTimeProvider injection)
- Cumulative Smart Friend track: S22 #44 + S25 #48 + S29 Plan CA ≥12 + S29
Plan B ApplicableType + S33 Plan C BW clean + S33 Plan B Phase 2 clean
- gotcha #51 INFRASTRUCTURE seed gate compliance: ✓
- gotcha #50 Layout staticMap mirror: ✓ (Task 5 commit next)
## Verify
- dotnet build: 0 err 0 warn (1.72s)
- dotnet test: 120/120 PASS baseline preserved
- Endpoint claim verified grep 0 mock marker, 5 mediator.Send real
Pattern 12-bis cross-module entity cookie-cutter mirror PE→Hrm reinforced 4×
cumulative (S29 Plan B Contract Chunk C + S33 Task 3 entity scaffold + Task
3b seed + Task 4 CQRS).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 48a99e14e7 |
[CLAUDE] Domain+App+Infra: Plan B G-H1 Mig 34 EmployeeProfile + seed 30 demo
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m38s
Phase 10.1 G-H1 Hồ sơ Nhân sự Foundation — port từ NamGroup CT_NHANSU
(1675 NV, 10 bảng TblNhanVien*) sau anh main chốt S32 4 quyết định
(scope FULL 11 module + DB single schema dbo + reuse Workflow V2 +
chunk per-module Plan riêng). G-H1 CRITICAL FIRST vì depend by 8/11
module Phase 10 sau (Đề xuất/Đơn từ/OT/Đặt xe/Ticket/Dashboard NS/
Chấm công đều cần EmployeeProfile data).
Investigator pre-flight (a103d20) audit NamGroup confirm:
- Main TblNhanVien 105 cols (drop 35 cols duplicate User/UX legacy)
- 5 satellite Phase 10.1 (defer 3 HĐLĐ Plan H2): WorkHistory + Education
+ FamilyRelation + Skill polymorphic Kind + Document
- 6 enum thay catalog FK (Gender/MaritalStatus/EmployeeStatus/...)
- DiaChi dual-write FK + freetext lesson Plan C NamGroup 1675 NV drift
Em main 4 decision chốt:
1. 5 satellite Phase 10.1 (defer 3 HĐLĐ Plan H2)
2. Skill polymorphic Kind enum (gộp 3 NamGroup table)
3. DiaChi 6 FK Province/District/Ward declare nullable + freetext dual-write
ngày đầu (FK constraint defer G-H2 khi catalog scaffold — Implementer
smart decision documented EmployeeProfile.cs comment line 14-17)
4. MaNhanVien format NV/{YYYY}/{Seq:D4} atomic Serializable reset/year
Implementer Case 2 (a8f4567) Pattern 12-bis cross-module mirror PE → Hrm
cookie-cutter scaffold 17 file mới + 4 modified + 3-file mig rule:
Domain (8 file SolutionErp.Domain.Hrm):
- EmployeeProfile.cs (main ~70 cols inherit AuditableEntity, 1-1 UNIQUE User)
- EmployeeWorkHistory.cs + EmployeeEducation.cs + EmployeeFamilyRelation.cs
- EmployeeSkill.cs (polymorphic Kind=Computer/Language/Other)
- EmployeeDocument.cs (IdCard/Passport/Degree/Certificate/LaborContract/Other)
- EmployeeCodeSequence.cs (PK string Prefix, NOT BaseEntity Id Guid)
- Enums.cs (10 enum gọn 1 file)
Application (1 file):
- IEmployeeCodeGenerator.cs interface (mirror IContractCodeGenerator)
Infrastructure (8 file):
- EmployeeCodeGenerator.cs impl IsolationLevel.Serializable transaction
- 7 EF Configuration file (HasIndex UNIQUE UserId/EmployeeCode/Phone +
HasMaxLength + HasColumnType decimal(18,2) + FK Cascade satellite)
- DependencyInjection.cs (M): register IEmployeeCodeGenerator → impl
Persistence (3 file modified + 2 new mig + 1 snapshot):
- IApplicationDbContext.cs (M): +7 DbSet<EmployeeProfile/...>
- ApplicationDbContext.cs (M): +7 DbSet impl
- ApplicationDbContextModelSnapshot.cs (M): EF auto-update
- 20260526110207_AddEmployeeProfiles.cs (NEW, EF auto-gen)
- 20260526110207_AddEmployeeProfiles.Designer.cs (NEW, EF auto-gen)
DbInitializer.cs (M, em main solo Task 3b ~90 LOC):
- using SolutionErp.Domain.Hrm import added
- SeedDemoEmployeeProfilesAsync method appended (end of class)
- Register call after SeedDemoUsersAsync line 88 (depend user exist first)
- NOT gated DemoSeed:Disabled flag (infrastructure data per gotcha #51 lesson)
- 30 demo profile mirror 30 user @solutions.com.vn + sequential code
NV/{YYYY}/0001..0030 + placeholder masked CMND/BHXH/Bank (bro UAT update
qua FE Page Task 5) + EmployeeCodeSequence row LastSeq=30 → production
gen tiếp 0031+
Verify:
- dotnet build: 0 err 2 unrelated warn DocxRenderer (2.49s + 7.86s rebuild)
- dotnet ef database update _Dev: Mig 34 applied (top of __EFMigrationsHistory)
- dotnet test: **120/120 PASS** baseline preserved (no test add Phase 10
test-after per §7 UAT mode — test bundle defer Task 4+5+6 done)
Stats target Phase 10 end: 33→42 mig (+9 Mig 34-42), 60→85 tables (+25),
~148→250 endpoint (+100), 38→60 FE pages (+22). Current after this commit:
33→34 mig + 60→66 tables + endpoint/FE unchanged (G-H1 Task 4+5 next).
Pattern reusable cross-project:
- Pattern 12-bis cross-module entity cookie-cutter mirror reinforced 3×
(S29 Plan B Contract V2 + S33 Plan B G-H1 EmployeeProfile)
- Infrastructure seed OUT of DemoSeed gate (gotcha #51 lesson, mirror Mig 32
SeedSampleContractWorkflowV2)
- DiaChi dual-write FK + freetext từ ngày đầu (NamGroup 1675 NV drift lesson)
Pending Plan B G-H1 Phase 2 (chờ anh main signal kick off):
- Task 4 — Implementer BE CQRS handler + 6 endpoint controller
- Task 5 — Implementer FE 2 app EmployeesPage 3-panel + 6 section tabs
- Task 6 — Em main Permission menu Hrm_HoSo* seed
- Task 7 — Reviewer pre-commit + CICD post-deploy verify
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 38f1c4d2d9 |
[CLAUDE] Infra: Plan B Hotfix CICD — SeedSampleContractWorkflowV2 OUT of DemoSeed gate
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m32s
CICD Monitor post-deploy verify (Run #231 SUCCESS) caught CRITICAL: SeedSampleContractWorkflowV2Async nested inside `if (!demoSeedDisabled)` branch → prod has DemoSeed:Disabled=true (Plan T S23 t10) → seed SKIP → QT-HD-V2-001 KHÔNG tồn tại prod → Drafter Workspace dropdown V2 EMPTY → V2 contract path BLOCKED end-to-end UAT. Fix: PROMOTE SeedSampleContractWorkflowV2 ra ngoài DemoSeed gate. Lý do architectural: - Sample workflow là INFRASTRUCTURE config (như Roles + Departments + Catalogs) - KHÔNG phải demo data wipeable - Production cần để Drafter create V2 contract - Admin có thể edit/delete/disable qua Designer sau seed (idempotent skip) Pattern lesson reusable cross-project: phân biệt INFRASTRUCTURE seed (always run) vs DEMO seed (gated by flag). Bảng phân loại: - INFRASTRUCTURE always: Roles, Departments, Catalogs, MenuTree, AdminPerms, Templates - DEMO gated: DemoUsers (30 sample, Plan T disabled prod), DemoContracts, DemoPE, SampleWorkflows - INFRASTRUCTURE NEW post-S29: SampleContractWorkflowV2 (cần cho V2 path work) Verify: - dotnet build PASS 0 err - Mig 32 + Mig 33 prod đã apply (Run #231 success) - Sample seed sẽ chạy on next IIS recycle post-push - Idempotent: skip nếu QT-HD-V2-001 already exists (rare race admin tự seed Designer trước) Post-deploy expect: - ApprovalWorkflows table +1 row Code=QT-HD-V2-001 ApplicableType=3 IsActive=1 IsUserSelectable=1 - Drafter login fe-user → /contracts/new → Workspace dropdown "Quy trình duyệt V2" có 1 option CICD Monitor ROI: caught BEFORE bro UAT 401/empty dropdown experience. Smart Friend guard pattern proven 4× cumulative S22 #44 + S25 #48 + S29 Plan B Reviewer ApplicableType + S29 Plan B CICD DemoSeed gate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 3e92584238 |
[CLAUDE] App: Plan B Hotfix Reviewer — CreateContractCommand validate ApplicableType=Contract
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m30s
Reviewer pre-push verify (agentId ace4799) catch MAJOR security gap: CreateContractCommand thiếu validation guard rằng ApprovalWorkflowId pin phải có ApplicableType=Contract(3). Attacker forge POST body với V2 PE workflow ID (ApplicableType=1/2 DuyetNcc) → contract pin sai workflow type → Service ApproveV2Async sẽ run pattern PE workflow trên Contract entity → behavior nondeterministic + audit log nhầm. Fix: Mirror PE pattern PurchaseEvaluationFeatures.cs:62-77. Validation block thêm vào CreateContractCommandHandler.Handle sau activeWfId query: 1. Load aw entity by Id (throw NotFound nếu invalid Guid) 2. Verify aw.ApplicableType == Contract(3) (throw Conflict nếu mismatch) Defense-in-depth: FE Workspace dropdown (Chunk D |
|||
| 48f6d22b3d |
[CLAUDE] App: Plan B Chunk E2 — ContractDetailDto +ApprovalWorkflowId + LevelOpinions[] populate
Mirror PE PeDetailBundle pattern. Expose V2 workflow state cho FE Section 5
Chunk E3 (Implementer pending) render dynamic LevelOpinionsSectionV2.
Changes:
- ContractDtos.cs:
- ContractDetailDto +3 fields (default null backward compat):
- Guid? ApprovalWorkflowId (V2 pin)
- int? CurrentApprovalLevelOrder
- List<ContractLevelOpinionDto>? LevelOpinions
- NEW record ContractLevelOpinionDto (mirror PE 12 fields)
- ContractFeatures.cs GetContractQueryHandler:
- Load LevelOpinions via 3-step JOIN (ContractLevelOpinions + ApprovalWorkflowLevels.Include(Step) + Users)
- Map to ContractLevelOpinionDto với StepOrder/Name + LevelOrder/Name + Approver/SignedBy resolve
- OrderBy StepOrder + LevelOrder
- Null fallback Comment "" (CS8604 silence)
- Empty list khi V2 pin nhưng KHÔNG có opinion (workflow start lúc Drafter trình)
- Skip load nếu V1 (ApprovalWorkflowId null) → null marker FE detect
FE Chunk E3 sẽ:
- Detect V2 mode qua `bundle.approvalWorkflowId != null`
- Fetch ApprovalFlow shape via existing /api/approval-workflows-v2/{ApprovalWorkflowId}
- Render Section 5 dynamic forEach Step → forEach Level → 1 OpinionBox với opinion data from LevelOpinions[]
Verify:
- dotnet build PASS 0 err, 0 warn (clean)
- dotnet test 111/111 PASS — 0 regression
- V1 legacy contract Detail unchanged (ApprovalWorkflowId=null + LevelOpinions=null)
Plan B chain status (8/9 chunks done):
- A1
|
|||
| ef2330871d |
[CLAUDE] App: Plan B Chunk E1 — CreateContractCommand +ApprovalWorkflowId V2 pin field
Mirror PE CreatePurchaseEvaluationCommand pattern. Drafter pick V2 workflow qua Workspace Select dropdown (Chunk D FE Implementer running parallel) → ApprovalWorkflowId pin lúc create. Fallback V1 auto activeWfId nếu null (7 prod contract giữ behavior). Changes: - CreateContractCommand record +Guid? ApprovalWorkflowId = null (optional) - Handler line 96 wire entity.ApprovalWorkflowId = request.ApprovalWorkflowId - Both V1 + V2 fields persist (Service ApproveV2Async branch dispatch theo V2 first) Verify: - dotnet build PASS 0 err - Backward compat: existing caller (KHÔNG pass ApprovalWorkflowId) → fallback null - V1 contract path UNCHANGED Plan B chain status: - A1 |
|||
| 1f199b01a5 |
[CLAUDE] Infra: Plan B Chunk B2 — UPSERT ContractLevelOpinion + ResolveActorFullName helper
Replace TODO marker trong Chunk B |
|||
| 26c98d3c11 |
[CLAUDE] Domain+App+Infra: Plan B Chunk C — Mig 33 ContractLevelOpinions cookie-cutter mirror PE Mig 26
- Domain/Contracts/ContractLevelOpinion.cs (NEW entity mirror PE — AuditableEntity, 4 field core + 2 nav) - Domain/Contracts/Contract.cs (+LevelOpinions nav collection) - Migrations/20260522052240_AddContractLevelOpinions.cs (3-file rule: .cs + .Designer.cs + Snapshot) - Configurations/ContractLevelOpinionConfiguration.cs (NEW separate file, mirror PE pattern) - IApplicationDbContext.cs + ApplicationDbContext.cs (+DbSet<ContractLevelOpinion>) UNIQUE composite (ContractId, ApprovalWorkflowLevelId) — 1 row per HĐ × Level. FK Cascade Contract + Restrict ApprovalWorkflowLevel. SignedByUserId KHÔNG nav (denorm SignedByFullName tránh cascade khi xoá user). Mirror PE Mig 26 pattern (S19 2026-05-09) EXACT — UPSERT row khi Approver duyệt qua Service ApproveV2Async (Plan B Chunk B em main |
|||
| 138469db4e |
[CLAUDE] Infra+App: Plan B Chunk B — Service ApproveV2Async branch + gen mã HĐ adapt
Mirror PE PurchaseEvaluationWorkflowService.cs:ApproveV2Async (line 446-634).
V1 legacy giữ behavior cũ — 7 prod contract chạy nhánh này. V2 mới pin
ApprovalWorkflowId chạy ApproveV2Async helper.
Changes:
- ContractWorkflowService.cs:
- TransitionAsync +skipToFinal=false param F2 (Mig 31 Plan K mirror PE)
- Drafter trình init CurrentApprovalLevelOrder=1 nếu V2 schema pin
- APPROVE STEP branch V2/V1 dispatch theo ApprovalWorkflowId
- +ApproveV2Async helper ~150 LOC (mirror PE pattern):
- Load AW.Steps.Levels OR-of-N
- Match approver actor.Id ∈ pendingLevelGroup.ApproverUserId
- Add ContractApproval row + enrich comment skipPrefix
- skipToFinal F2: AllowApproverSkipToFinal guard + advance pointer last
- Advance level/step normal
- Terminal: gen mã HĐ RG-001 + Phase=DaPhatHanh (khác PE just DaDuyet)
- IContractWorkflowService.cs: TransitionAsync +skipToFinal=false param
- ContractFeatures.cs: caller TransitionAsync use named arg ct: ct (skip optional)
TODO Chunk C: UPSERT ContractLevelOpinion (table chưa tồn tại — Mig 33
sẽ scaffold + entity + EF config). Block UPSERT add ở đây sau Chunk C done.
Verify:
- dotnet build SolutionErp.slnx PASS 0 err, 2 pre-existing DocxRenderer warn
- dotnet test 111/111 PASS (58 Domain + 53 Infra) — 0 regression
- V1 legacy path UNCHANGED (7 prod contract giữ behavior)
Plan B chain (6 chunks):
- A1
|
|||
| a85e437478 |
[CLAUDE] Infra: Plan B Chunk A2 — Mig 32 Contract V2 schema + Configuration + Seed sample workflow
Cookie-cutter mirror PE Mig 23+24 GỘP thành 1 Mig 32 (ADD 2 column +
FK + IX). Mirror Mig 26 pattern cho FK Restrict.
Files added/modified:
- Migrations/20260522051059_AddApprovalWorkflowToContract.cs (3-file rule ✅)
- Migrations/20260522051059_AddApprovalWorkflowToContract.Designer.cs
- Migrations/ApplicationDbContextModelSnapshot.cs (updated)
- Configurations/ContractConfiguration.cs (+HasIndex + FK Restrict ApprovalWorkflows)
- Persistence/DbInitializer.cs (SeedSampleContractWorkflowV2 idempotent QT-HD-V2-001)
Mig 32 Up():
- ADD COLUMN Contracts.ApprovalWorkflowId Guid? NULL
- ADD COLUMN Contracts.CurrentApprovalLevelOrder int? NULL
- ADD INDEX IX_Contracts_ApprovalWorkflowId (filtered NOT NULL)
- ADD FK FK_Contracts_ApprovalWorkflows_ApprovalWorkflowId Restrict
Seed sample workflow (UAT smoke + admin Designer default):
- Code: QT-HD-V2-001 Name: "Quy trình duyệt HĐ mẫu UAT V2"
- ApplicableType: 3 (Contract) IsActive: true IsUserSelectable: true
- 1 Step "Bước 1 - Phòng CCM" + 1 Level + Approver Lê Văn Bình CCM
- Idempotent: skip nếu Code+Version existing
V1 coexist: 7 prod contract giữ WorkflowDefinitionId; V2 mới pin
ApprovalWorkflowId. Service ApproveV2Async (Chunk B em main) sẽ branch.
Verify (Implementer):
- dotnet build SolutionErp.slnx PASS 0 err (em main WIP stashed for verify)
- dotnet ef database update Dev PASS (Mig 32 applied)
- 3-file rule Mig: mig.cs + Designer.cs + Snapshot.cs
Plan B chain (6 chunks):
- A1
|
|||
| 58898e8fbe |
[CLAUDE] Domain: Plan B Chunk A1 — Contract +2 fields V2 (ApprovalWorkflowId + CurrentApprovalLevelOrder)
Mirror PE Mig 22-24 pattern. V1+V2 coexist (7 V1 contract giữ WorkflowDefinitionId, V2 mới pin ApprovalWorkflowId). Fields added: - ApprovalWorkflowId Guid? — pin schema mới ApprovalWorkflowsV2 - CurrentApprovalLevelOrder int? — Cấp đang chờ duyệt (1/2/3) trong Step Service ApproveV2Async branch (Chunk B) sẽ dispatch: - if (contract.ApprovalWorkflowId is Guid awId) ApproveV2Async - else ApproveV1Legacy (giữ behavior 7 V1 contract) Verify: - dotnet build SolutionErp.slnx PASS 0 err, 2 pre-existing DocxRenderer warn - No migration (Chunk A2 sẽ scaffold Mig 32) Plan B chain (6 chunks): - A1 (this) Entity +2 fields (em main) - A2 Mig 32 schema (Implementer Case 2 cookie-cutter) - B Service ApproveV2Async branch (em main critical ~200 LOC) - C Mig 33 ContractLevelOpinions (Implementer) - D FE Workspace V2 (Implementer) - E FE Section 5 LevelOpinionsV2 (Implementer) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 68bceddabb |
[CLAUDE] Infra: Plan CA Chunk D2 hotfix — Password ≥12 chars cho catalog.manager (S22+2 policy)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m31s
Reviewer spawn pre-push verify catch CRITICAL bug Chunk D |
|||
| 4a592cfadb |
[CLAUDE] Infra: Plan CA Chunk D — Seed demo user catalog.manager + role CatalogManager
DbInitializer.cs SeedDemoUsersAsync array thêm 1 entry: - Email: catalog.manager@solutions.com.vn (password default User@123456 per SeedDemoUsersAsync logic) - FullName: "NV Quản lý Danh mục" - Dept: PRO (Cung ứng) - Position: "Nhân viên Quản lý Danh mục Dùng chung" - Roles: [AppRoles.CatalogManager] Cấp 1 demo user mặc định để bro UAT login fe-user verify 9 menu danh mục (Master + Suppliers + Projects + Departments + Catalogs + 4 sub-catalogs). Admin có thể tạo thêm user gán role CatalogManager qua /system/users + /system/permissions Matrix tự reflect 9 menu key. Verify: - dotnet build SolutionErp.slnx PASS 0 err, 2 pre-existing DocxRenderer warn - Idempotent: SeedDemoUsersAsync skip nếu user existing email - DbInitializer chạy mỗi lần API startup → demo user auto-seed lên prod sau deploy Plan CA wrap (4 chunk): - A |
|||
| 80d39a06fb |
[CLAUDE] Domain+Infra: Plan CA Chunk A — Add role CatalogManager + seed 9 menu CRUD
- AppRoles.cs +CatalogManager const + update All array (6 LOC)
- DbInitializer.cs RoleLabels +CatalogManager ("DM", "Nhân viên Quản lý danh mục")
- DbInitializer.cs +SeedCatalogManagerPermissionsAsync() method ~50 LOC
- Wire seed call vào SeedAdminPermissionsAsync chain (idempotent, mirror SeedPePermissionDefaults pattern)
Permission scope: 9 menu key CRUD all true
- Master (root) + Suppliers + Projects + Departments
- Catalogs (root) + CatalogUnits + CatalogMaterials + CatalogServices + CatalogWorkItems
Verify:
- dotnet build SolutionErp.slnx PASS 0 err, 2 pre-existing DocxRenderer warn
- Idempotent: skip per-(role,menuKey) existing row
- 0 FE touch (Chunk B Implementer parallel commit
|
|||
| 2bf01184ca |
[CLAUDE] App+FE-User+FE-Admin: Plan AG4 — bổ sung Drafter + Department vào PE List card
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m27s
Anh UAT 2026-05-21: PE card danh sách thiếu người tạo + phòng ban tạo. Bổ sung 4 field qua BE JOIN Users + Departments LEFT (cả 2 nullable theo PE entity). BE — 4 file: - PurchaseEvaluationDtos.cs: +4 fields DrafterUserId/DrafterName/DepartmentId/DepartmentName - PurchaseEvaluationFeatures.cs ListHandler: JOIN Users + Departments LEFT, projection +4 - PurchaseEvaluationFeatures.cs InboxHandler: mirror JOIN + projection +4 - CreateContractFromEvaluationFeatures.cs ListApproved: mirror JOIN + projection +4 FE — 4 file × 2 app mirror: - types/purchaseEvaluation.ts: PeListItem +4 fields - pages/pe/PurchaseEvaluationsListPage.tsx: PE card render thêm dòng "👤 {drafterName} · {departmentName}" giữa Mã phiếu và Supplier. Conditional: chỉ render khi có ít nhất 1 field. Verify: - dotnet build clean 0 err - dotnet test SolutionErp.slnx 111/111 PASS (58 Domain + 53 Infra) — no regression - npm build fe-user PASS 0 TS err 1290.31 KB (gzip 336.79 KB) 1907 modules - npm build fe-admin PASS 0 TS err 1401.66 KB (gzip 357.30 KB) 1926 modules - 2 FE PE List file SHA256 IDENTICAL C6996194... (mirror §3.9) - KHÔNG Mig (chỉ DTO + projection extend) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 9ea62be6a7 |
[CLAUDE] PurchaseEvaluation: Plan AE — fix Changelog UserName 9 sites (Budget Adjust + 8 preventive)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m25s
Bro UAT 2026-05-19 post-S25 Plan AD: "Điều chỉnh ngân sách" entry trong Lịch sử thay đổi show "Hệ thống" thay vì tên user thật (Phan Văn Chương / NV CCM). Audit phát hiện systemic bug — 9 Changelog.Add sites trong PE features MISSING UserName field, FE fallback "Hệ thống" toàn bộ. Fix Plan AE — preventive batch (8 sites khác chắc chắn bro sẽ phát hiện sau): PurchaseEvaluationFeatures.cs (4 sites): - line 120 Tạo phiếu - line 149 Hạng mục mặc định - line 228 Cập nhật thông tin phiếu (UpdateDraft) - line 379 Điều chỉnh ngân sách (Budget Adjust) — bro feedback chính PurchaseEvaluationDetailFeatures.cs (5 sites): - line 167 Thêm hạng mục (Detail Insert) - line 225 Cập nhật hạng mục (Detail Update) - line 257 Xóa hạng mục (Detail Delete) - line 317 Cập nhật báo giá (Quote Update — inside if block, 16-space indent) - line 342 Thêm báo giá (Quote Insert) - line 377 Xóa báo giá (Quote Delete) - line 416 Chọn NCC trúng thầu (Select Winner) Pattern: `UserName = currentUser.FullName ?? currentUser.Email` — ICurrentUser đã có FullName + Email từ JWT claims, KHÔNG cần inject userManager mới. Verify: - dotnet build clean 0 err 2 warn (pre-existing DocxRenderer) - dotnet test 111/111 PASS Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| a734bf2b8b |
[CLAUDE] PurchaseEvaluation: Plan AC — fix Lịch sử duyệt panel show Trả lại + Duyệt vượt cấp
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m27s
Bro UAT 2026-05-19 screenshot: panel "Lịch sử duyệt" KHÔNG show Return mode events (Bro Trả lại từ Phan Văn Chương → Trà missing) + KHÔNG distinct event Duyệt vượt cấp (skipToFinal F2). Root cause: - PurchaseEvaluationApprovals.Add() chỉ ở Approve branch (line 472 V2 + 660 V1) - Reject branch line 75-103 NEVER adds Approval row — chỉ log Changelog - skipToFinal advance branch line 532-572 dùng existing line 472 row nhưng comment KHÔNG distinct "vượt cấp" semantic vs approve thường Fix Plan AC: 1. BE Service.cs Reject branch (line 75-103): capture pre-call Step/Level trước ApplyReturnModeAsync mutate pointer, add Approval row sau khi mutate: Decision=Reject + FromPhase + ToPhase=evaluation.Phase + Comment carry from-position + mode summary. Cover cả Trả lại (TraLai+pointer-mode) + Từ chối (TuChoi terminal). 2. BE Service.cs line 472 Approve branch: enrich Comment với prefix "[Duyệt vượt cấp tới Cấp cuối]" khi skipToFinal=true để Lịch sử duyệt distinguish vượt cấp với approve thường. 3. FE PeDetailTabs.tsx × 2 app ApprovalsTab: add Decision badge phân biệt Approve (emerald) / Trả lại (amber) / Từ chối (rose). Vì 3/4 mode Trả lại (OneLevel/OneStep/Assignee) giữ Phase=ChoDuyet → fromPhase→toPhase badge giống Approve. Decision badge bù visual phân biệt. Verify: - dotnet build clean 0 err 2 warn (pre-existing DocxRenderer) - dotnet test 111/111 PASS - npm build × fe-user + fe-admin PASS 0 TS err Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| cdfd54212c |
[CLAUDE] PurchaseEvaluation: Plan AB Chunk A — fix Changelog visibility Bug 1 Budget Adjust + Bug 2 Return Mode
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Failing after 1m6s
- BE ApplyReturnModeAsync 4 mode add Changelog.Add() common path (refactor Drafter early return) - FE PeDetailTabs.tsx HistoryTab filter extend cover Header+ngân sách (B1) + Workflow+Trả lại (B2) - FE empty placeholder + comment update reflect new filter scope - Mirror 2 app §3.9 Bug 1: Budget Adjust handler đã log (Header+Update) nhưng FE filter strict TraLai-only Bug 2: Return mode Service không log Changelog — chỉ approval phase transition Verify: - Build clean 0 err - npm build × 2 app pass 0 TS err - 111 test baseline preserve (UAT skip test-after defer) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| ee776d5745 |
[CLAUDE] Domain+App+Api+FE-User+FE-Admin: Plan AA Chunk A - BE IsUserSelectable filter + menu seed Pe_DuyetNcc_WfView + sidebar widen w-72 xl:w-80 + revert Plan U truncate
BE changes:
- MenuKeys.cs +helper PurchaseEvaluationWorkflowView(typeCode) => "Pe_{typeCode}_WfView"
- DbInitializer.cs SeedMenuTreeAsync:
- tree.Add LuongDuyet (Order=2 first child) cho 2 type PE
- INSERT-only loop -> INSERT-OR-UPDATE-Order (shift existing prod rows Order+1)
- Idempotent: skip nếu Order match, UPDATE nếu mismatch
- DbInitializer.cs SeedPurchaseEvaluationPermissionDefaultsAsync +WfView leaf cho 7 role Read
- ApprovalWorkflowV2AdminFeatures.cs GetAwAdminOverviewQuery +IsUserSelectable bool? = null
+ handler conditional Where(d => d.IsUserSelectable == ius)
- ApprovalWorkflowsV2Controller.cs Overview signature +[FromQuery] bool? isUserSelectable
pass-through to mediator (gotcha #44 fix preserved class-level [Authorize] bare)
FE Layout changes (mirror 2 app rule §3.9):
- fe-user resolvePath regex (List|Create|Pending|WfView) + route
/purchase-evaluations/workflow-matrix?type=N
- fe-user + fe-admin sidebar w-60 xl:w-72 -> w-72 xl:w-80 (+48/+32px gain)
- Revert Plan U S23 t11 truncate × 5 sites (3 fe-user MenuGroup+MenuLeaf+StaticLeaf
+ 2 fe-admin MenuGroup+MenuLeaf). Keep min-w-0 flex-1 + shrink-0 + title
tooltip (no harm). Bro request hiển thị đầy đủ label custom Mig 27 dài.
Why:
- User UAT request 2026-05-15: thêm menu "Luồng duyệt" trên Danh sách hiển thị
ma trận phân quyền workflow V2 admin Designer ghim ra cho user xem trước khi
tạo phiếu. Filter IsUserSelectable=true (Mig 25).
- Sidebar Plan U S23 t11 truncate hiển thị "..." → bro muốn full label.
Widen sidebar +32-48px + bỏ truncate cho phép wrap natural khi cực dài.
Verify:
- dotnet build SolutionErp.slnx PASS clean 0 err 2 warn pre-existing DocxRenderer
- Investigator Pre-A confirm gotcha #44 đã fix permanent từ 2026-05-08
- Reviewer cumulative PASS 0 critical / 0 major / 0 minor blocker
Pending Chunk B: FE WorkflowMatrixViewPage.tsx ~215 LOC + types + App.tsx route.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 0b97840674 |
[CLAUDE] Infra Api: Chunk T — Disable auto re-seed demo data qua DemoSeed:Disabled flag (appsettings)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m22s
Bro UAT post-Plan R+S phát hiện: 4 phiếu [DEMO]-A/B + 2 V1 workflows + 1
V2 sample TỰ ĐỘNG RE-SEED sau BE deploy commits Plan P+Q+R+S → IIS recycle
→ DbInitializer.InitializeAsync auto-seed lại 5 demo seed methods.
Plan T fix root cause: Config flag `DemoSeed:Disabled` trong
appsettings.json (production default true) → DbInitializer check flag →
skip 5 demo seed methods.
Note: appsettings.Production.json bị .gitignore (chứa secrets prod), nên
em set flag mặc định trong appsettings.json (commit qua git) — production
inherit true. Dev override false trong appsettings.Development.json để
test fresh demo seed local.
Methods SKIP khi DemoSeed:Disabled=true:
1. SeedWorkflowDefinitionsAsync (V1 PE workflow QT-DN-A v1 + QT-DN-B v1)
2. SeedPurchaseEvaluationWorkflowsAsync (V1 PE workflow extended)
3. SeedDemoContractsAsync ([DEMO] HĐ 7-type sample)
4. SeedDemoPurchaseEvaluationsAsync ([DEMO] PE 4 sample with V1 pin)
5. SeedSampleApprovalWorkflowsV2Async (V2 sample mẫu UAT type B)
Methods KEEP (luôn chạy):
- SeedRoles + SeedAdmin + SeedDepartments + SeedDemoUsers (30 UAT users)
- SeedMenuTree + SeedAdminPermissions + SeedDemoMasterData (Supplier/Project)
- SeedContractTemplates + SeedCatalogs + BackfillContractCodes
- BackfillUserEmailDomain (Phase 6 rebrand migration helper)
Files changed:
- src/Backend/SolutionErp.Infrastructure/Persistence/DbInitializer.cs:
+ using Microsoft.Extensions.Configuration
+ Read DemoSeed:Disabled flag từ IConfiguration
+ Log "DemoSeed:Disabled=true — skip ..." khi flag true
+ Wrap 5 method seed conditional `if (!demoSeedDisabled) { ... }`
- src/Backend/SolutionErp.Api/appsettings.json:
+ "DemoSeed": { "Disabled": true } + comment narrative
- src/Backend/SolutionErp.Api/appsettings.Development.json:
+ "DemoSeed": { "Disabled": false } override cho dev
Workflow expected sau deploy:
1. CI deploy commit T → IIS recycle app pool
2. BE startup → DbInitializer reads DemoSeed:Disabled=true
3. Skip 5 demo seed methods → DB state preserved
4. Bro UAT clean slate hoàn toàn — Designer setup workflow mới from scratch
Pending T5: Final DELETE current state (4 PE + 2 V1 + 1 V2 mẫu UAT) sau
deploy applied flag. T6 verify no re-seed loop sau re-deploy.
Verify:
- dotnet build SolutionErp.slnx clean (0 err, 2 warn pre-existing)
- dotnet test SolutionErp.slnx **111/111 PASS** unchanged
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 1727bd5cd9 |
[CLAUDE] Api Docs: Chunk P1+P3 — HOTFIX Controller TransitionPeBody record missing 3 fields (ROOT CAUSE F1+F2 fail)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m23s
CICD Monitor Run #202 Plan O verify catch CRITICAL caveat: PurchaseEvaluationsController.cs:267 `TransitionPeBody` record CHỈ có 3 fields (TargetPhase, Decision, Comment) — MISSING 3 fields có trong Command record `TransitionPurchaseEvaluationCommand`: - ReturnMode (F1 mode Trả lại) - ReturnTargetUserId (F1 Assignee target) - SkipToFinal (F2 duyệt thẳng Cấp cuối) Mediator.Send line 70 cũng drop 3 field. → FE × 2 app SEND ĐÚNG 7 fields qua `api.post(/transitions)` body (Investigator audit confirm wire OK) → ASP.NET Core deserialization silently DROP 3 fields ở Controller layer → Handler nhận ReturnMode=null + SkipToFinal=false → fallback default Drafter mode + F2 không trigger. Bug present 2 NGÀY PROD từ Mig 28 deploy 2026-05-13 — gây TẤT CẢ F1+F2 wire fail từ FE side. Plan N (S23 t4) + Plan O (S23 t5) fix 5 lookup sites discrimination NHƯNG controller body record bug block flow TRƯỚC KHI đến lookup site. Em main + Reviewer + Implementer + Investigator all MISS bug này xuyên 4 plan vì: 1. Mig 28 Command extend 3 fields (S21 t4) nhưng Controller body NOT extended 2. Plan K K2 add `skipToFinal` 8th param Service nhưng Controller NOT extended 3. Bug silent — no error, no compile fail, no test fail, FE call OK, BE return 204 nhưng handler nhận default args → wrong behavior Plan P fix BE-only ~10 LOC 1 file `PurchaseEvaluationsController.cs`: 1. Add `using SolutionErp.Application.PurchaseEvaluations.Services` cho WorkflowReturnMode enum import (line ~7) 2. Extend `TransitionPeBody` record line 267 thêm 3 fields default: ```csharp public record TransitionPeBody( PurchaseEvaluationPhase TargetPhase, ApprovalDecision Decision, string? Comment, WorkflowReturnMode? ReturnMode = null, Guid? ReturnTargetUserId = null, bool SkipToFinal = false); ``` 3. Update `mediator.Send` line 70 pass 7 fields: ```csharp await mediator.Send(new TransitionPurchaseEvaluationCommand( id, body.TargetPhase, body.Decision, body.Comment, body.ReturnMode, body.ReturnTargetUserId, body.SkipToFinal), ct); ``` Investigator (FE wire audit) verify: - fe-user/src/components/pe/PeWorkflowPanel.tsx:113-124 + fe-admin mirror — api.post send ĐẦY ĐỦ 7 fields qua body - KHÔNG cần fix FE - Mig 28/31 Domain test đã cover handler logic — không cần test mới Verify: - dotnet build SolutionErp.slnx clean (0 err, 2 warn pre-existing DocxRenderer) - dotnet test SolutionErp.slnx **111/111 PASS** unchanged (no regression) Docs update: - docs/STATUS.md Last updated S23 t6 - docs/HANDOFF.md TL;DR S23 t6 ngắn gọn - .claude/agent-memory/cicd-monitor/MEMORY.md drift (Run #202 entry pre-existing) Pattern reinforced cross-project: - Controller body record MUST mirror Command record fields khi Command thêm optional params. Silent drop bug class — không test/build catch được. - Investigator pre-flight audit FE wire trước khi fix BE (Plan P scope verify) tránh em main fix sai assumption. Pending: CICD Monitor verify Plan P deploy + UAT test bro real. Pending Bug 2 F2 đến Phan Văn Chương: verify workflow v14 DB structure sau khi Plan P unblock F2 flow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |