f21c55d04a3a07f43cb9607652dfaaa447629f55
117 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| f21c55d04a |
[CLAUDE] PurchaseEvaluation: bang NCC tham gia table-fixed + width tung cot (UAT vong 3 - "them file giao dien bi thay doi khong can xung")
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Has been cancelled
- Bang NCC trong HangMucCard dung auto-layout -> cell File (chip ten file dai) phinh, bop doc cot NCC tung chu. Fix: table-fixed + w-% tung cot (NCC 24 / SDT 9 / Email 14 / DKTT 14 / File 22 / So tien 12 / action w-10) + min-w-[860px] (panel hep -> scroll ngang qua wrapper overflow-x-auto thay vi bop nat) + email span block truncate. - Chip file/email truncate san - kich hoat khi cell khoa width. - SHA256 mirror x2 app IDENTICAL, build tsc+vite x2 PASS. |
|||
| 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. |
|||
| faed59f4c4 |
[CLAUDE] FE-Admin+FE-User: UX form tao phieu theo UAT feedback - combobox go-de-loc (Hang muc + Du an) + auto dia diem + dieu khoan da dong
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m31s
- NEW ui/SearchableSelect: combobox tu render, go loc theo label, match BO DAU tieng Viet (go "be tong" trung "Be tong"), keyboard arrows/Enter/Esc, clear (x), style mirror ui/Input density S55. Khong them lib ngoai. - PeWorkspaceCreateView + PeHeaderForm: Hang muc + Du an doi Select -> SearchableSelect (UAT: "nen co loc de tu danh chu" / "nen co tu go chu" - 70+ muc kho do). - Auto dia diem (UAT "dia chi nen tu auto"): chon Du an tu dien diaDiem tu Project.Location (S55), chi ghi de khi user chua go tay (track lastAutoLoc ref). - Dieu khoan thanh toan nhap tay: Input 1 dong -> Textarea 3 dong (UAT "khong cho xuong dong?") o CreateView + PeDetailTabs inline-edit; render detail da pre-wrap san. - SHA256 mirror x2 app (4 file IDENTICAL), build tsc+vite x2 PASS. |
|||
| 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. |
|||
| 3ebaf84531 |
[CLAUDE] PurchaseEvaluation: gop Ten goi thau = chon Hang muc cong viec (anh Kiet FDC chot 14:06) - 1 select set ca workItemId + tenGoiThau, phieu cu giu-nguyen null-safe, SHA256 mirror x2 app (S58)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m24s
|
|||
| ea793a43fa |
[CLAUDE] FE-Admin+FE-User: brand-accent polish x2 app - stripe dinh app + logo zone tint + PageHeader accent bar + thead brand (S58, anh yeu cau trang tri ro hon)
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Has been cancelled
|
|||
| 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> |
|||
| 7feb53ee20 |
[CLAUDE] FE-Admin: redesign Phase 1 — density-first design system (NAMGROUP-ref, giữ brand)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m24s
Tham khảo NAMGROUP density conventions, GIỮ brand #1F7DC1 + Be Vietnam Pro. - index.css: density heading ladder (semibold, drop font-bold) + .label-eyebrow util - 6 UI primitives (Button/Input/Label/Select/Textarea/Dialog): text-xs font-semibold, py-1.5 ≤36px, rounded-lg, brand focus-ring - 6 shell (DataTable sticky-thead+RowActions/Layout brand-rail/TopBar/PageHeader/PhaseBadge/EmptyState) - DashboardPage flagship: KPI cards + brand-tinted icon chips + uppercase labels Visual-only — functionality unchanged (Button variant/size keys stable 51 call-sites, props/forwardRef intact). build 0 TS err. reviewer PASS 0 blocker (2 minor slate-400 hint a11y defer). fe-admin only (fe-user mirror = Phase 3). Dashboard live-visual blocked by dev auth-rig → xem live sau deploy. 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>
|
|||
| 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> |
|||
| 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> |
|||
| 021674a66a |
[CLAUDE] FE-Admin+FE-User: S35 Plan G-H2 Task 4 — HrmConfigsPage declarative 4 catalog × 2 app
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m37s
Pattern 12-bis × 16-bis cookie-cutter cumulative 9× (Smart Friend Implementer catch).
Single page declarative KIND_CONFIG Record + URL `:kind` param + 4 sub-tab mirror
Master/Catalogs/CatalogsPage.tsx 321 LOC pattern. 4 catalog HRM (LeaveTypes/Holidays/
Shifts/OtPolicies) wire BE 16 endpoint /api/hrm-configs/{kind} từ commit `909655c`.
## Scope (Implementer Case 2 ~25K spawn)
- types/hrm-config.ts (NEW 98 LOC × 2 app SHA256 IDENTICAL `228917e5fac2cdc6`)
- HrmConfigsPage.tsx (NEW ~470 LOC × 2 app SHA256 IDENTICAL `6378fbc71ff90260`)
- App.tsx +3 LOC × 2 app (route + Navigate redirect default `/hrm/configs` → `leave-types`)
- Layout.tsx staticMap +6 LOC × 2 app — Pattern 16-bis 4-place enforcement
(em main spec line 24 GAP — Smart Friend Implementer caught + fixed proactive)
## 4 kind FieldDef declarative
- leave-types: code/name/daysPerYear/isPaid/requiresAttachment/description
- holidays: year/date/name/isRecurring/isPaid/description
- shifts: code/name/startTime/endTime/breakMinutes/workDays(multiselect-weekday)/description
- ot-policies: code/name/multiplier×3/maxHours×3/description
## Pattern 16-bis 4-place mirror Pattern 16-bis 6× cumulative
- types/hrm-config.ts (place 1)
- pages/hrm/HrmConfigsPage.tsx (place 2)
- App.tsx routes (place 3)
- Layout.tsx staticMap (place 4 — em main MISS, Implementer caught via gotcha #50 prior knowledge)
## Verify
- npm build × 2 PASS (fe-admin 14.33s + fe-user 744ms, 0 TS error)
- SHA256 IDENTICAL × 2 NEW pair (types + page)
- Reviewer pre-commit PASS Cat A-D clean (5K token tight scope no truncation)
- gotcha #50 silent sidebar drop prevention — Pattern 16-bis discipline reinforced
- Smart Friend 9× clean cumulative S22+S25+S29×2+S33×2+S35×3
## Multi-agent ROI S35 chunk 3 ~30K
- Implementer Case 2 declarative single-page mega + spec gap catch
- Reviewer tight 5K verdict Cat A-D PASS
## State delta S35 cumulative
- 0 mig add (Mig 35 schema S34)
- 0 BE endpoint add (16 endpoint commit `909655c`)
- +1 FE page (HrmConfigsPage) × 2 app routes
- Pattern 12-bis cumulative 3× + Pattern 16-bis 6× + Pattern 12-ter 6× (FE forms)
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> |
|||
| 9616ae219c |
[CLAUDE] FE-Admin+FE-User: Plan B G-H1 Task 5 — EmployeesPage 2-panel + EmployeeCreatePage cookie-cutter mirror
Phase 10.1 G-H1 Phase 2 Task 5 — FE 2 app cookie-cutter mirror PE pattern.
Phase 1 ULTRA-MINIMAL scope (Implementer afdc812 scaffold):
- 2-panel ListPage (filter left + list+detail right, KHÔNG 3-panel vì Hrm
no workflow)
- 6-section inline collapsible detail (Cơ bản/Công tác/Đào tạo/Thân nhân/
Kỹ năng/Hồ sơ) — NO separate DetailTabs component file
- CreatePage Header form minimal (UserId picker + Status + DateOfBirth +
Gender + Phone + HireDate + Nationality)
- Display read-only Phase 1 satellite (no inline edit — defer Phase 1.5)
## Files (6 new + 6 modified × 2 app = 12)
### NEW (3 × 2 app, SHA256 IDENTICAL cross-app mirror)
| File | LOC | SHA256 prefix |
|------|----:|---|
| `fe-{admin,user}/src/types/employee.ts` | 283 | CCFC70666568 |
| `fe-{admin,user}/src/pages/hrm/EmployeesListPage.tsx` | 417 | DC859C897C5C |
| `fe-{admin,user}/src/pages/hrm/EmployeeCreatePage.tsx` | 178 | C796F25D01AC |
10 const-object enum mirror BE Domain.Hrm.Enums + DTOs:
- EmployeeStatus/Gender/MaritalStatus/EmployeeType/DegreeLevel/
EducationMode/GradeLevel/FamilyRelationKind/SkillKind/EmployeeDocumentType
- EmployeeListItem + EmployeeDetail + 5 satellite DTO type
### MODIFIED (3 × 2 app)
- `fe-{admin,user}/src/lib/menuKeys.ts` — +Hrm + HrmHoSo const
- `fe-{admin,user}/src/components/Layout.tsx` — +Hrm_HoSo:'/employees' staticMap
(LESSON Plan CA Hotfix 1 gotcha #50: page route mới phải thêm staticMap
entry cùng commit, else silent sidebar drop)
- `fe-{admin,user}/src/App.tsx` — +2 route /employees + /employees/new
## Pattern reinforcement
- **Pattern 16-bis 4-place mirror cross-app** reinforced 4× cumulative (S29
Plan CA HF1 + S29 Plan B Chunk D + S33 Task 5 admin + S33 Task 5 user).
Comment header trong Layout.tsx ghi explicit Plan CA Hotfix 1 #50 lesson.
- **Pattern 12-bis cross-module entity FE port PE → Hrm** reinforced 4× (Plan
B Chunk C Mig 33 + G-H1 Task 4 BE + Task 5 FE types mirror PE types/page
structure mirror PE 2-panel scope-down 3→2 panel).
## Reviewer ae752c0 verdict: PASS (commit
|
|||
| 14feb6955d |
[CLAUDE] FE-Admin+FE-User: Plan B Chunk E3 — ContractDetailPage Section 5 LevelOpinionsV2 dynamic
Em main solo sau Implementer E3 stuck mid-task. Minimum viable mirror PE Section 5 LevelOpinionsSectionV2 pattern. V2 contract pin ApprovalWorkflowId → render dynamic Section 5 với opinion data UPSERT từ Service ApproveV2Async (Plan B Chunk B2 |
|||
| c995f42e0d |
[CLAUDE] FE-Admin+FE-User: Plan CA Chunk C — Sidebar filter 2 app (admin HIDE + user SHOW)
fe-admin/src/components/Layout.tsx: - Add ADMIN_HIDDEN_MASTER_KEYS Set với 9 menu key danh mục - Extend isAdminHidden predicate: hide Ct_* + ADMIN_HIDDEN_MASTER_KEYS - Master/Suppliers/Projects/Departments/Catalogs/4 sub-catalogs giờ ẩn khỏi admin sidebar fe-user/src/components/Layout.tsx: - Remove `Master, Suppliers, Projects, Departments` khỏi USER_HIDDEN_KEYS - Catalogs (root + 4 leaf) auto-visible qua tree-inherit từ Master - Giữ ẩn `System, Users, Roles, Permissions, Forms, Reports` (admin tools) Verify: - npm run build × 2 app PASS 0 TS err - fe-admin bundle `index-BQidGwKU.js` 1,404 KB gz 357 KB (rotate) - fe-user bundle `index-Co8LTtad.js` 1,317 KB gz 342 KB (rotate) - Pattern 5 (mirror 2 app §3.9) applied — cùng 1 plan touch 2 file Layout Plan CA chain: - Chunk A |
|||
| 506cada86b |
[CLAUDE] FE-User FE-Admin: Plan AF — userMap fallback resolve historical entries pre-Plan AE
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m23s
Bro UAT 2026-05-19 post-Plan AE: phiếu cũ entries vẫn show "Hệ thống" thay
vì user name. Plan AE chỉ forward fix — entries CŨ pre-deploy có
userName="" empty, FE fallback "Hệ thống".
Fix Plan AF — Option A bro chốt (FE fallback lookup, no DB write):
ApprovalsTab + HistoryTab build userMap useMemo từ PeDetailBundle data
có sẵn (KHÔNG cần extra fetch /api/users admin permission):
- ev.drafterUserId + ev.drafterName
- ev.approvals[].approverUserId + approverName
- ev.approvalFlow.steps[].levels[].approvers[].userId + fullName
- ev.levelOpinions[].signedByUserId + signedByFullName
- ev.departmentOpinions[].userId + userName
resolveUserName / resolveActorName helper:
1. Trust entry.userName nếu non-empty
2. Lookup userMap qua entry.userId
3. Fallback 'Hệ thống' nếu không match
Cover gần hết users tham gia phiếu (drafter + approver + signer). Edge
case: user edit phiếu nhưng KHÔNG xuất hiện trong workflow → vẫn fallback.
Pattern reusable: synthetic data recovery cho audit trail từ embedded
domain data sources, no extra API contract change.
Mirror 2 app §3.9 identical logic.
Verify:
- npm build × fe-user PASS 0 TS err (9.12s)
- npm build × fe-admin PASS 0 TS err (8.91s)
- BE unchanged from
|
|||
| 0aaf2df04a |
[CLAUDE] FE-User FE-Admin: Plan AD — Lịch sử duyệt redesign drop phase badges + next-target hint
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m24s
Bro UAT 2026-05-19 post-Plan AC2 deploy: phase badges "Đã gửi duyệt →
Đã gửi duyệt" gây nhầm (Reject event nhìn giống Approve, không rõ gửi
duyệt cho ai).
Fix Plan AD — Option A bro chốt:
1. DROP fromPhase→toPhase badges entirely khỏi ApprovalsTab — redundant
visual noise khi 3/4 mode return giữ Phase=ChoDuyet, và misleading cho
user thấy "Đã gửi duyệt → Đã gửi duyệt" lặp lại.
2. ADD next-target hint parse từ comment via helper extractNextTargetHint():
Approve patterns:
- Comment "sang Cấp X" → "→ Cấp X"
- Comment "sang Bước X" → "→ Bước X (Cấp 1)"
- Comment "[Duyệt vượt cấp tới Cấp cuối]" → "→ Vượt cấp tới Cấp cuối"
- toPhase=DaDuyet(20) → "→ Đã duyệt hoàn tất"
Reject patterns:
- Comment "không lùi được" → "→ Không lùi được"
- Comment "Người chỉ định" + Bước/Cấp → "→ Trả về Người chỉ định (Bước X Cấp Y)"
- Comment "Người soạn thảo"/"Drafter" → "→ Trả về Người soạn thảo"
- Comment "Trả về 1 Cấp"/"Trả về Cấp X" → "→ Lùi về Cấp X" / "→ Lùi 1 Cấp"
- Comment "Trả về 1 Bước"/"Trả về Bước X" → "→ Lùi về Bước X" / "→ Lùi 1 Bước"
- toPhase=TuChoi(99) → "→ Từ chối hoàn toàn"
3. Layout cleaner: [Decision badge] [Next-target hint] flex-wrap min-w-0 +
timestamp shrink-0 right. Comment + actor stays below.
4. Cleanup import: drop unused PurchaseEvaluationPhaseColor (no longer
needed after dropping phase badges). Keep PurchaseEvaluationPhaseLabel
(still used at line 157+ for InfoTab phase label).
Mirror 2 app §3.9 identical logic.
Verify:
- npm build × fe-user + fe-admin PASS 0 TS err
- BE/test unchanged from
|
|||
| 25837b6220 |
[CLAUDE] FE-User FE-Admin: Plan AC2 — FE merge view recover historical Reject events PE cũ
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m22s
Bro UAT 2026-05-19 phản hồi sau Plan AC deploy: phiếu cũ PE/2026/A/032 vẫn KHÔNG show events Trả lại pre-deploy (Bro test trả lại Phan Văn Chương → Trà từ TRƯỚC |
|||
| 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> |
|||
| ee0902ac13 |
[CLAUDE] FE-User FE-Admin: Plan AA wrap fix - sidebar label dài wrap về đầu hàng + text smaller
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m25s
UAT feedback 2026-05-15 sau Run #213 deploy: bro screenshot sidebar label custom Mig 27 dài "1. Duyệt Nhà Cung Cấp - Thầu phụ (NCC -TP)" wrap 2 dòng, dòng 2 "(NCC -TP)" indent SAU icon thay vì về đầu hàng. Root cause: flex container [items-center, gap-2] + inner span chứa Icon + label text → text wraps within INNER span (đã indent past icon area). Pattern phù hợp cho 1-dòng label, KHÔNG phù hợp khi multi-line. Fix pattern (3 sites fe-user + 2 sites fe-admin mirror rule §3.9): - MenuGroup button: flex → relative block + inline-block icon + inline text + absolute ChevronDown right. Text wrap về left edge button (under icon). - MenuLeaf NavLink: flex → block + inline-block icon + inline text. - StaticLeaf NavLink (fe-user only): mirror MenuLeaf pattern. Smaller text: - text-[13px] → text-[12px] (medium label group + leaf) - text-sm (14px) → text-[12px] (MenuLeaf top level) - text-[12px] → text-[11px] (MenuLeaf deep level) - leading-snug (1.375) compact 2-line height Icon adjust: -mt-0.5 align with inline text baseline. Button px-3 pr-7: pad right 28px reserve cho absolute ChevronDown (KHÔNG bị đẩy xuống khi label wrap). Verify: - npm run build fe-user PASS clean 432ms - npm run build fe-admin PASS clean 494ms Em main solo CSS polish < 30 min (criteria #6 REFUSE Implementer). 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>
|
|||
| 86d8806afc |
[CLAUDE] FE-Admin FE-User: Chunk U — Sidebar truncate long label + tooltip (Mig 27 DisplayLabel dài wrap fix)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m30s
Bro UAT screenshot 2026-05-15: Submenu "1. Duyệt Nhà Cung Cấp - Thầu phụ
(NCC -TP)" trong sidebar fe-user wrap 2 dòng (label dài ~50 chars vs
sidebar w-60 = 240px chỉ fit ~25 chars).
Root: Admin đã set DisplayLabel custom qua Mig 27 (S20 t7 Menu eOffice
admin page) — `MenuItems.Pe_DuyetNcc` DisplayLabel = "1. Duyệt Nhà Cung
Cấp - Thầu phụ (NCC -TP)" (Label gốc = "Duyệt NCC" ngắn). FE render
{effectiveLabel(node)} thẳng vào span flex KHÔNG có truncate.
Fix Plan U mirror 2 app (rule §3.9):
3 nơi render label trong fe-user/Layout.tsx + 2 nơi mirror fe-admin:
1. MenuNodeRenderer button (accordion toggle):
```diff
- <span className="flex items-center gap-2">
+ <span className="flex min-w-0 flex-1 items-center gap-2">
- <Icon className="h-4 w-4" />
- {effectiveLabel(node)}
+ <Icon className="h-4 w-4 shrink-0" />
+ <span className="truncate" title={effectiveLabel(node)}>{effectiveLabel(node)}</span>
</span>
- <ChevronDown ... transition />
+ <ChevronDown ... shrink-0 ... transition />
```
2. MenuLeaf NavLink:
```diff
- <NavLink to={path} className={cn('flex items-center gap-2.5...')}>
+ <NavLink to={path} title={effectiveLabel(node)} className={cn('flex min-w-0 items-center gap-2.5...')}>
- <Icon className={cn(isDeep ? 'h-3.5 w-3.5' : 'h-4 w-4')} />
- {effectiveLabel(node)}
+ <Icon className={cn('shrink-0', isDeep ? 'h-3.5 w-3.5' : 'h-4 w-4')} />
+ <span className="truncate">{effectiveLabel(node)}</span>
</NavLink>
```
3. StaticLeaf NavLink (fe-user only — Hộp thư static entry):
Pattern tương tự MenuLeaf
fe-admin dùng `node.label` thay vì `effectiveLabel(node)` (admin sidebar
luôn show Label gốc, KHÔNG đụng DisplayLabel per S20 t7 Q2=b).
Pattern key:
- `min-w-0 flex-1` trên flex parent — cần thiết để truncate child shrink
- `shrink-0` trên Icon + ChevronDown — giữ size không co
- `truncate` (Tailwind = overflow-hidden text-ellipsis whitespace-nowrap) trên span text
- `title={label}` tooltip hover show full label nếu user cần đọc đầy đủ
Verify:
- npm run build fe-user PASS 16.79s clean
- npm run build fe-admin PASS 8.16s clean
- 0 TS error
KHÔNG đụng BE. Admin tự control DisplayLabel qua Mig 27 Menu eOffice page
— Plan U chỉ ensure FE render gracefully với label dài (truncate +
tooltip hover) thay vì wrap broken visual.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 108268a2e2 |
[CLAUDE] FE-Admin FE-User: Chunk Q — Fix layout banner F3 violet mx-5 inset gap khiến button "+ Thêm hạng mục" lệch
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m15s
Bro UAT screenshot 2026-05-15 sau Plan O+P deploy: PE/2026/A/025 Phase=ChoDuyet actor NV Test có F3 AllowApproverEditDetails=TRUE — banner violet "Bạn được phép chỉnh sửa Hạng mục / NCC / Báo giá" render ĐÚNG nhưng layout: ``` [Section padding px-5 = 20px] [Banner mx-5 inset 20px both sides] ← gap 20px right edge [ItemsTab header flex justify-between] [text "1 hạng mục..."] [Button "+ Thêm hạng mục"] ``` Banner mx-5 đẩy inset 20px khỏi Section padding x-5 → tạo gap visual 20px bên phải banner. Phía dưới gap đó là button right-aligned (full Section width) → trông button "lệch" so với banner end + có khoảng trắng phía trên. Fix mirror 2 app (rule §3.9): ```diff - <div className="mx-5 mt-2 rounded border border-violet-200 bg-violet-50 px-3 py-2 text-[11px] text-violet-800"> + <div className="mb-3 rounded border border-violet-200 bg-violet-50 px-3 py-2 text-[11px] text-violet-800"> ``` - `mx-5` → drop (banner full Section padding width) - `mt-2` → `mb-3` (consistent spacing với ItemsTab header `mb-3` style) Visual sau fix: ``` [Section padding px-5] [Banner full width] [ItemsTab header: text + button align Section right edge] ``` Button "+ Thêm hạng mục" align cùng phải edge với banner. KHÔNG còn gap visual. Files (2 mirror): - fe-user/src/components/pe/PeDetailTabs.tsx:218-223 - fe-admin/src/components/pe/PeDetailTabs.tsx:213-218 Verify: - npm run build fe-user PASS clean (0 TS err, 7.67s) - npm run build fe-admin PASS clean (0 TS err, 7.50s) KHÔNG đụng BE. KHÔNG đụng logic. CSS layout polish only. Pending: bro UAT verify layout fix + Plan P CICD Monitor verify F1+F2 wire (spawn earlier, vẫn running). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 508b17a43c |
[CLAUDE] FE-Admin FE-User: Chunk M3 — Rename Phase=TraLai display label "Trả lại" → "Cần chỉnh sửa lại"
Plan M Chunk M3 — UAT disconnect fix: bro UAT phát hiện label "Trả lại" + "Bản nháp" không phân biệt rõ với end-user → rename Phase=TraLai (98) display label sang "Cần chỉnh sửa lại" để self-descriptive. Scope HẸP — chỉ status display reference (KHÔNG đụng action verb): - types/purchaseEvaluation.ts × 2 app: PurchaseEvaluationPhaseLabel[98] + PeDisplayStatusLabel.TraLai = 2 const map rename - components/pe/PeWorkflowPanel.tsx × 2 app: 2 inline literal hardcode trong F1 dialog tooltip `Phase → "..."` + confirm message `Phiếu sẽ về "..."` — status reference, KHÔNG phải action verb KHÔNG đụng: - Action button label `← Trả lại` (verb, giữ nguyên) - F1 mode picker label `Trả về Người soạn thảo` (4 mode action, giữ nguyên) - Comments narrative giữ rationale dev (rule §6.5) - types/contracts.ts + types/budget.ts Phase 98 'Trả lại' — module Contract + Budget khác PE, ngoài scope M3 Mirror 2 app rule §3.9 strict applied. Verify: - npm run build fe-admin PASS clean (0 TS err, 9.40s) - npm run build fe-user PASS clean (0 TS err, 6.92s) Diff: +4/-4 LOC × 4 file = 8 LOC total Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| f212f04365 |
[CLAUDE] FE-Admin FE-User: Chunk L3 — Fix Trả lại dialog default mode = first available F1 (mode đang gửi duyệt)
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Failing after 48s
Bro UAT S23 t2 catch screenshot: tick AllowReturnToAssignee + untick AllowReturnToDrafter cho slot Approver → user click "Trả lại" → dialog mở với default state `returnMode=Drafter` (S17 backward compat fallback). Radio Drafter HIDDEN vì allowReturnToDrafter=false → user thấy radio Assignee đã pick + Bùi Lê Thủy Trà từ dropdown → click Xác nhận → BE receive `returnMode: 4` (Drafter từ initial state) → throw "Cấp Approver hiện tại không bật mode 'Drafter'. Liên hệ Admin Designer". Bro intent: "cho duyệt trong muốn cho trả lại trong mode đang gửi duyệt chứ ko phải draft, draft chỉ khi trả lại cho người soạn thôi" — 3 F1 modes (OneLevel/OneStep/ Assignee) là "trả lại trong mode đang gửi duyệt" (Phase=ChoDuyet lùi pointer); Drafter mode = trả về Người soạn (Phase=TraLai), CHỈ default khi không có F1 nào. Fix FE × 2 app PeWorkflowPanel.tsx (mirror rule §3.9): - Import useEffect - useEffect khi target=TraLai → compute first available F1 mode: - allowReturnOneLevel ? OneLevel - : allowReturnOneStep ? OneStep - : allowReturnToAssignee ? Assignee - : Drafter (fallback) - setReturnMode(firstAvailable) → Dialog mở với mode đúng selected → user click Xác nhận → BE receive correct mode → ApplyReturnModeAsync check correct flag → PASS. Pattern lesson saved: dialog initial state phải compute từ permission flags KHÔNG hardcode default — admin có thể disable mọi mode khác Drafter, hoặc ngược lại enable F1 only. Verify: - npm run build × 2 app pass (0 TS err) - Bundle hash rotate × 2 app Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 10ddc8761b |
[CLAUDE] FE-Admin FE-User: Chunk L2 — Fix F4 BudgetAdjustSection bypass readOnly khi Approver scope (menu Duyệt)
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Failing after 1m1s
Bro UAT S23 t2 catch: "Đã stick cho edit trong luồng duyệt nhưng trong menu duyệt -> vẫn không edit đc ngân sách". Investigator audit root cause: - BudgetAdjustSection canAdjust = !readOnly && (...) — `!readOnly` short-circuit block F4 logic - Menu Duyệt route truyền readOnly=true xuống PeDetailTabs → button "Điều chỉnh" hidden dù admin đã tick AllowApproverEditBudget cho slot + actor match - F3 wire ItemsTab ĐÚNG via `itemsReadOnly = readOnly && !approverEditMode` pattern bypass — F4 không follow same pattern Refactor canAdjust × 2 app (rule §3.9 mirror): ``` - canAdjust = !readOnly && (isAdmin || (isDrafter && isDrafterPhase) || isApproverChoDuyet) + canAdjust = isAdmin + || (!readOnly && isDrafter && isDrafterPhase) + || isApproverChoDuyet ``` → F4 Approver scope (Mig 30) BYPASS readOnly: - Admin: bypass readOnly (full quyền) - Drafter (Nháp/TraLai): chỉ Workspace (readOnly=false) - Approver ChoDuyet + flag tick + actor match: bypass readOnly → button "Điều chỉnh" visible trong menu Duyệt Mirror F3 pattern (itemsReadOnly line 118). F4 wire S22+5 ban đầu miss BYPASS pattern — fixed S23 t2. Verify: - npm run build × 2 app pass (0 TS err, bundle hash rotated) - Bro UAT verify: tick F4 → vào menu Duyệt → click "Điều chỉnh ngân sách" → modal open editable Pattern lesson saved memory: per-NV admin opt-in flag wire RULE — FE bypass readOnly khi flag tick + actor match + phase match (mirror F3 itemsReadOnly). F4 BudgetAdjustSection retroactive fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| f3db9e6cc0 |
[CLAUDE] PurchaseEvaluation: Chunk L1 — Fix F2 skipToFinal semantic: skip pointer tới NV cuối (KHÔNG terminate DaDuyet)
Bro UAT S23 t2 catch: Plan K K2 implement F2 SAI semantic — set Phase=DaDuyet terminal auto-approve. Bro intent: "Duyệt thẳng đến CEO, bỏ qua các bước khác chứ ko phải chuyển sang đã duyệt." Refactor Service.cs ApproveV2Async F2 branch: - Resolve lastStepIdx = steps.Count - 1, lastLevelMaxOrder = max(LevelOrder) trong Step cuối - Advance pointer: CurrentWorkflowStepIndex = lastStepIdx + CurrentApprovalLevelOrder = lastLevelMaxOrder - Phase GIỮ NGUYÊN ChoDuyet — NV cuối (CEO/last approver) vẫn cần ký thật để tiến DaDuyet - Audit log "Approver skip thẳng tới Bước X Cấp Y (NV cuối) — bỏ qua các Bước/Cấp trung gian" - Guard no-op: actor đã ở slot cuối → fall through advance logic (normal → DaDuyet) (KHÔNG double-advance khi skipToFinal=true ngay slot cuối) - Reset SLA 7d cho NV cuối nhận lại FE × 2 app PeWorkflowPanel.tsx (mirror rule §3.9): - Description text update: "Phiếu sẽ skip tới NV cuối (CEO/cấp ký cuối) — NV cuối vẫn cần duyệt thật để hoàn tất." - Amber warning update: "Bỏ qua mọi Cấp/Bước trung gian, phiếu chuyển thẳng tới NV cuối. NV cuối vẫn phải ký duyệt thật để phiếu thành 'Đã duyệt'." Verify: - dotnet build production projects clean (0 err, 2 pre-existing warn) - npm run build × 2 app pass Pattern lesson saved memory: Service skipToFinal semantic = advance pointer NOT terminate. K7 tests TODO update: 3 Approver F2 tests assert pointer moved to last slot, NOT Phase=DaDuyet. Defer test fix sau UAT confirm UX. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| ebe2469470 |
[CLAUDE] FE-Admin FE-User: Chunk E — K6 Workspace DROP Drafter checkbox + ADD Approver toggle (Mig 31 F2 refactor)
Plan K Chunk E mirror 2 app rule §3.9. Refactor F2 UX flow:
DROP fe-admin + fe-user Workspace Drafter checkbox:
- PeDetailTabs.tsx Workspace action bar: REMOVE "Gửi thẳng Cấp cuối (skip trung gian)"
violet label + state skipToFinal + allowSkipToFinal lookup + skipToFinal payload
- submitForApproval mutation signature simplify: opts: { skipToFinal: boolean } → void
- Confirm dialog text + button label drop skipToFinal conditional
ADD fe-admin + fe-user Approver toggle trong PeWorkflowPanel dialog:
- State skipToFinalApprover default false
- Visible khi Approve forward (NOT Cancel + NOT SendBack) + currentLevelOptions?.allowApproverSkipToFinal
- Checkbox violet panel với description "Phiếu sẽ tiến thẳng tới Đã duyệt (terminal)"
- Amber warning khi checked: "Hành động KHÔNG quay lại được"
- Mutation payload +skipToFinal: !isReject && skipToFinalApprover
- onSuccess reset state
Type ApprovalWorkflowOptions × 2 app: +allowApproverSkipToFinal: boolean (7th)
Type PeDetailBundle × 2 app: REMOVE drafterAllowSkipToFinal field + comment Mig 29+30+31
UX design Dialog approach (consistent với Trả lại Mode picker pattern):
- Skip thẳng Cấp cuối = destructive action → confirm dialog amber warning
- Mirror Mig 28 Trả lại 4 mode picker UX consistency
- Em main solo K6 per UX flow decision criteria
Per bro decision Plan K S23 t1: "Chỗ cấu hình cho phép skip → duyệt thẳng cho phép
trong trạng thái đang duyệt" + "Tất cả đều cấu hình ngay trong chỗ setup quy trình duyệt".
Verify:
- npm run build × 2 app pass clean (0 TS err)
- Pre-existing warnings unchanged (chunk size + INEFFECTIVE_DYNAMIC_IMPORT)
- Bundle hash rotated × 2 app
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| b04a11a62f |
[CLAUDE] FE-PE: S22+5 Chunk B — Designer checkbox +AllowApproverEditBudget per slot + Section read flag (mirror 2 app)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m23s
FE Admin Designer (ApprovalWorkflowsV2Page.tsx): - LevelDto + EditLevelEntry +allowApproverEditBudget - copyFromDefinition + makeDefaultLevelEntry propagate default false - POST body include allowApproverEditBudget cho mỗi Level slot - NEW checkbox UI per Level inline panel: "Cho phép chỉnh sửa Section ngân sách lúc đang duyệt" (col-span-2, mirror pattern allowApproverEditDetails Mig 29) FE Types mirror 2 app: - fe-admin + fe-user `ApprovalWorkflowOptions` +allowApproverEditBudget FE BudgetAdjustSection refactor (mirror 2 app): - Trước: isApproverChoDuyet = phase ChoDuyet + actor in approvers - Sau: isApproverChoDuyet = phase ChoDuyet + actor in approvers + currentLevelOptions.allowApproverEditBudget=true (per slot opt-in) - Drafter scope Nháp/Trả lại unchanged - Admin bypass unchanged UX impact: - Admin Designer phải tick checkbox cho NV slot mới được edit ngân sách lúc duyệt - Nếu KHÔNG tick → button "Điều chỉnh" trong Section 5 KHÔNG hiện cho approver - Drafter vẫn edit bình thường khi phiếu Nháp/Trả lại Verify: - npm run build fe-admin — 569ms pass - npm run build fe-user — 528ms pass Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 30d51c89bb |
[CLAUDE] FE-PE: S22+4 Chunk B — Attachment preview dialog + View button + Section "Điều chỉnh ngân sách" (mirror 2 app)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m26s
Feature 1 (FE attachment preview):
- NEW component `AttachmentPreviewDialog.tsx` (shared 2 app):
* Fetch BE `/view` endpoint as blob → object URL (bearer auth qua axios)
* Render iframe (PDF) hoặc img (image) trong Dialog size=lg
* Helper `isPreviewable(fileName)` check ext PDF/PNG/JPG/JPEG/WEBP/GIF
- Update `SupplierAttachmentsCell` (per-NCC quote files):
* Click filename KHÔNG còn trigger download — chuyển sang explicit buttons
* Eye violet button "Xem trước" khi previewable
* Download brand button cạnh bên (always visible)
- Update `GeneralAttachmentsSection` (bảng so sánh general):
* Same pattern: Eye + Download split buttons
- Word/Excel (.doc/.docx/.xls/.xlsx) → download-only (UAT users mở local Office)
- Mirror fe-admin + fe-user (rule §3.9)
Feature 2 (Section "Điều chỉnh ngân sách"):
- NEW component `BudgetAdjustSection` in PeDetailTabs (mirror 2 app)
- Section 5 cuối Detail view sau "4. Ý kiến cấp duyệt"
- canAdjust 3 scope:
* Admin → bypass
* Drafter của phiếu + Phase DangSoanThao/TraLai
* Approver currentLevel (match approvalFlow.approvers) + Phase ChoDuyet
- 2 mode edit: Select Budget link OR Manual amount + name
- Banner amber khi Approver điều chỉnh trong duyệt (audit notice)
- Save → PATCH /api/purchase-evaluations/{id}/budget-adjust (Chunk A BE)
- History display defer S22+5 (changelogs fetch separate endpoint, không có
trong PeDetailBundle — UAT user xem Panel 3 "Lịch sử thay đổi")
Verify:
- npm run build fe-admin — 577ms pass
- npm run build fe-user — 550ms pass
- dotnet test SolutionErp.slnx — 104/104 PASS regression-free
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 40f64c6b32 |
[CLAUDE] PE-Workflow: UAT S22+1 — disable cả 3 button khi không quyền + BE guard
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m29s
User UAT feedback: "Nếu đã không được quyền thao tác thì ko được quyền thao tác hết tất cả các hành động" — trước đây chỉ "Duyệt" disabled, "Trả lại" + "Từ chối" vẫn enabled (design intent S17 cũ). FE 2 app mirror (PeWorkflowPanel.tsx): - `isDisabled = blockedByV2Level` (drop `isForwardApprove &&` qualifier) - Tooltip update "mới thao tác được (Duyệt / Trả lại / Từ chối)" - Comment refresh ghi UAT S22+1 spec + cross-ref BE EnsureCanRejectV2Async BE defense-in-depth (PurchaseEvaluationWorkflowService.cs): - Helper mới `EnsureCanRejectV2Async` mirror FE actorInV2Level logic: Skip silent khi admin/V1/non-ChoDuyet/no actor/no pointer. Throw ForbiddenException khi V2 + ChoDuyet + actor != currentLevel.ApproverUserId. - Invoke ở top Reject branch (cover cả TuChoi + Trả lại sub-branches). - Chặn request forge: non-approver gọi PATCH /transitions direct sẽ 403. Test (test-before §7 — security guard critical algorithm): - ReturnMode tests existing 7/7 vẫn PASS (a2.Id = currentLevel approver, guard accept) - +1 NEW test `Reject_NonApprover_V2_Throws_ForbiddenException` — outsider Drafter role gọi Reject phiếu V2 → throw + Phase không mutate Verify: - dotnet test SolutionErp.slnx — 104/104 PASS (+1 guard regression) Δ: 103 → 104 - npm run build × 2 app — pass (482ms + 583ms) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 5ccb2a7057 |
[CLAUDE] FE-PE: S21 t5 Chunk C — eOffice read currentLevelOptions + drafterAllowSkipToFinal (per-NV) mirror 2 app
Types refactor `fe-{admin,user}/src/types/purchaseEvaluation.ts`:
- `ApprovalWorkflowOptions` REMOVE allowDrafterSkipToFinal (F2 đã move per-User).
Còn 5 flag (F1 4 mode + F3 EditDetails).
- `PeDetailBundle`:
- RENAME `workflowOptions` → `currentLevelOptions` (clearer semantic per-slot)
- ADD `drafterAllowSkipToFinal: boolean` (BE resolve từ DrafterUserId → User entity)
PeWorkflowPanel.tsx (mirror 2 app):
- RENAME local var `wfOptions` → `levelOptions`
- READ `evaluation.currentLevelOptions` (Cấp hiện tại)
- 4 mode radio render conditional theo levelOptions.allowReturnXxx (unchanged
logic, just rename source)
PeDetailTabs.tsx (mirror 2 app):
- F3 approverEditMode: READ `evaluation.currentLevelOptions?.allowApproverEditDetails`
thay vì workflowOptions.allowApproverEditDetails (semantic per-NV slot)
- F2 allowSkipToFinal: READ `evaluation.drafterAllowSkipToFinal` thay vì
workflowOptions.allowDrafterSkipToFinal (semantic per-Drafter user)
Backward compat verified:
- Phiếu cũ trước Mig 29 vẫn return currentLevelOptions populated (BE backfill
Mig 29 đã copy 5 Allow* per Level)
- drafterAllowSkipToFinal: BE backfill chỉ TRUE cho user từng Drafter PE link
workflow.AllowDrafterSkipToFinal=true (preserve admin config S21 t4)
- Phiếu V1 legacy: currentLevelOptions=null → FE fallback chỉ Drafter mode
Verify:
- npm run build × 2 app pass (fe-user 450ms + fe-admin 439ms, cache hot)
- 0 TS6 err, warning chunk size pre-existing
Pending Chunk D: Docs (schema-diagram §14 update + STATUS + HANDOFF + session log).
Note: User Management page chưa có F2 checkbox UX (defer commit sau khi admin
UAT request — BE field đã có, FE chỉ cần thêm 1 toggle vào UserEdit dialog).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| d27caafcf5 |
[CLAUDE] FE-PE: Chunk D — eOffice Trả lại modes + Skip CEO + Approver edit Section 2 (F1+F2+F3) mirror 2 app
Types (fe-{admin,user}/src/types/purchaseEvaluation.ts):
- ApprovalWorkflowOptions type (6 boolean Allow* flag)
- WorkflowReturnMode const-object {OneLevel,OneStep,Assignee,Drafter}
- PeDetailBundle +workflowOptions field (null nếu V1 legacy)
PeWorkflowPanel.tsx F1 (mirror 2 app):
- State returnMode + returnTargetUserId thêm vào transition mutation payload
- Dialog Trả lại render radio list 1-4 mode enabled theo workflowOptions:
• Trả về 1 Cấp trước (lùi pointer trong cùng Bước, peer review)
• Trả về 1 Bước trước (Cấp cuối Bước trước nhận lại)
• Trả về Người chỉ định (pick từ dropdown NV đã ký levelOpinions)
• Trả về Người soạn thảo (default Drafter S17 fallback)
- Banner amber rounded box dưới radio list mô tả hành vi mode chọn
- onSuccess reset returnMode về Drafter + returnTargetUserId null
PeDetailTabs.tsx F2 (mirror 2 app):
- State skipToFinal + allowSkipToFinal (từ workflowOptions)
- submitForApproval mutationFn accept opts.skipToFinal → POST body
- Workspace action bar: thêm checkbox violet "Gửi thẳng Cấp cuối (skip trung gian)"
hiển thị conditional theo allowSkipToFinal + canSubmitForApproval
- Confirm dialog message dynamic: "Gửi thẳng" warning vs default tuần tự
- Button label dynamic: "Lưu & Gửi thẳng CẤP CUỐI →" vs "Lưu & Gửi Duyệt →"
PeDetailTabs.tsx F3 (mirror 2 app):
- useAuth import + compute approverEditMode (phase=ChoDuyet +
workflow.AllowApproverEditDetails + actor match currentApproval.approvers)
- itemsReadOnly = readOnly && !approverEditMode → ItemsTab nhận
- Banner violet "ⓘ Bạn được phép chỉnh sửa Hạng mục/NCC/Báo giá" khi
approverEditMode + readOnly (Duyệt menu) — UX nhắc về quyền extended
InfoTab + NccSelectorRow + BudgetFieldRow GIỮ strict isEditablePhase (KHÔNG
trong F3 scope — Header section + Section 3 winner KHÔNG cho Approver edit).
Verify:
- npm run build × 2 app pass (fe-user 7.52s, fe-admin 499ms cached)
- 0 TS6 err, warning chunk size pre-existing
- BE Chunk B đã accept skipToFinal + returnMode + returnTargetUserId trong
TransitionPurchaseEvaluationCommand → wire E2E complete
Pending Chunk E: Docs schema-diagram §14 update + STATUS + HANDOFF + session log.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 4b29d00716 |
[CLAUDE] FE-PE: Chunk B — Fix button "Trả lại" gửi decision=Approve thay vì Reject (gotcha #45) mirror 2 app
Bug pattern: button "← Trả lại" trong PeWorkflowPanel.tsx hiển thị đúng label
(L205-207 isSendBack include TraLai) NHƯNG payload `isReject` (L64-66) thiếu
nhánh TraLai → gửi decision=1 (Approve) thay vì 2 (Reject) khi target=TraLai
(98). BE Service vào APPROVE STEP → ApproveV2Async UPSERT opinion "đã duyệt"
+ advance Cấp tiếp theo. User UAT thấy: "Trả về nhưng hệ thống vẫn duyệt".
Inconsistency thứ 2: dialog `isSendBack` (L247-248) cũng thiếu nhánh TraLai
→ dialog title fallback `✓ Duyệt → Trả lại` + KHÔNG hiển thị amber warning.
Fix 3 chỗ × 2 app (fe-user + fe-admin, rule §3.9 mirror):
1. `isReject` payload — thêm nhánh `target=TraLai && phase!=TraLai`
2. dialog `isSendBack` — thêm nhánh TraLai + guard phase != TraLai
3. Comments document context bug + cross-ref BE guard Chunk A
Sync với BE guard (Chunk A `de00887` `PurchaseEvaluationWorkflowService.cs`):
- BE throw ConflictException khi target ∈ {TraLai, TuChoi} && decision != Reject
- 2 phía cùng đúng → no payload mismatch
Verify:
- npm run build × 2 app pass (fe-user 17.91s, fe-admin 6.71s, 0 TS6 err)
- Warning chunk size pre-existing (NOT introduced)
Pending Chunk C: docs gotcha #45 + STATUS + HANDOFF + session log.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 6e338f745e |
[CLAUDE] FE: Responsive cho laptop màn hình nhỏ — sidebar slim + Section/HangMucCard padding tighter + workspace 2-panel breakpoint
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m13s
User Session 20 turn 11: "giao diện hiện tại chưa đáp ứng tốt cho laptop màn hình nhỏ -> Căn chỉnh lại nhé." Pain points trên laptop 1280-1366px viewport (fe-user content panel 1280-288=992px hoặc fe-admin workspace 2-panel content còn ~672px): - Sidebar 288px chiếm nhiều - PE Workspace list panel 320px = thừa - Section padding px-5 + HangMucCard p-3 cộng gộp tốn ~16-20px mỗi cell - Inline NCC table 7 cột bị compressed FE-only mirror fe-admin + fe-user. Targeted fixes (no breaking change): ### 1. Sidebar slim — w-60 (240px) lg/xl giảm xuống → bump xl:w-72 - fe-admin Layout aside: `w-72` → `w-60 xl:w-72` - fe-user Layout aside: `w-72` → `w-60 xl:w-72` - Trên màn ≥xl (1280px+) → giữ 288px như cũ - Trên màn <xl (laptop nhỏ) → 240px, save 48px cho content ### 2. PE Workspace 2-panel list breakpoint - `lg:grid-cols-[320px_1fr]` → `lg:grid-cols-[260px_1fr] xl:grid-cols-[320px_1fr]` - Trên lg (1024-1279): list 260px (đủ pick) → content +60px - Trên xl+ (1280+): list 320px như cũ - Save total: ~60px cho NCC table render ### 3. Section + HangMucCard padding responsive - Section component `<section className="px-5 py-4">` → `px-3 py-3 sm:px-5 sm:py-4` (xs/sm: tighter 12px each side, save 16px width) - HangMucCard header `flex items-start gap-3 ... p-3` → `flex flex-wrap items-start gap-2 ... p-2 sm:gap-3 sm:p-3` → +flex-wrap: stat "Số tiền NS" wrap xuống dòng khi container hẹp - HangMucCard expand panel `p-3` → `p-2 sm:p-3` Net width gain trên laptop 1366px (typical): - Sidebar slim: +48px - Workspace list: +60px - Section padding: +16px - HangMucCard padding: +8px Total ~+132px cho NCC table area render comfortable thêm 1-2 cột KHÔNG đụng dialog widths, schema BE, hoặc semantic breakpoints lớn. Verify: - npm run build × fe-admin pass - npm run build × fe-user pass Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 66551db4d8 |
[CLAUDE] FE-PE: AddSupplierDialog auto-fill từ master khi chọn NCC
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m0s
User Session 20 turn 10: chọn NCC từ dropdown master → auto-load các field
đã có sẵn (contactPerson/phone/email/note) vào form, đỡ phải nhập tay lại.
FE-only mirror fe-admin + fe-user.
AddSupplierDialog dropdown "NCC (master)" onChange:
- Lookup suppliers.data find(s => s.id === selectedId) → master row
- setForm prev → ghi đè 4 field:
* contactName ← picked.contactPerson ?? ''
* contactPhone ← picked.phone ?? ''
* contactEmail ← picked.email ?? ''
* note ← picked.note ?? ''
- KHÔNG đụng displayName / paymentTermText / thanhTien (manual cho user)
- Hint "✓ Đã tự điền từ Master — bạn có thể sửa lại nếu cần." text-[10px]
text-emerald-600 dưới dropdown khi đã chọn supplier
Mapping master Supplier → PE.Supplier fields (skip address vì không có
field tương ứng — có thể nhét vào note nếu user cần, manual).
User vẫn override các field auto-fill được sau đó (input bình thường).
Đổi supplier giữa lúc đã chỉnh tay → re-fill từ master mới (mặc định ghi đè).
Verify:
- npm run build × fe-admin pass
- npm run build × fe-user pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 83aae8ea64 |
[CLAUDE] FE-PE: Winner NCC revert badge → icon ✓ đậm + hover transition
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m50s
User Session 20 turn 9: bỏ badge "🏆 Trúng thầu" emerald-600 rounded-full text-white, revert về icon stick ✓ prefix như cũ nhưng: - Đậm hơn: text-base font-bold text-emerald-700 - Tên NCC khi winner: text-emerald-900 đậm - Row hover transition: hover:bg-emerald-200/70 (winner) + hover:bg-white/80 hover:shadow-sm (non-winner palette) - Transition smooth qua `transition` class NCC row visual khi winner: - border-l-emerald-500 (giữ) - bg-emerald-100/70 (giữ) - font-semibold + shadow-sm + ring-1 ring-inset ring-emerald-300 (giữ) - +hover:bg-emerald-200/70 (mới — sáng lên hover) - Prefix ✓ text-base font-bold emerald-700 (đậm hơn icon cũ) - Tên NCC text-emerald-900 (đậm hơn slate-900 mặc định) NCC row non-winner: - palette cycle (blue/purple/sky/teal/pink) giữ - +hover:bg-white/80 hover:shadow-sm (mới — nổi nhẹ khi hover) Mirror fe-admin + fe-user. Verify: - npm run build × fe-admin pass - npm run build × fe-user pass Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 3ec7b5a1b0 |
[CLAUDE] FE-PE: AddSupplier +Số tiền inline + NCC 5-màu palette + Winner 🏆 nổi bật
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m8s
User Session 20 turn 8 yêu cầu chuỗi UX NCC grid:
1. Thêm NCC dialog cho nhập luôn Số tiền báo giá cho hạng mục
2. Số tiền hiện ra cột so sánh hạng mục (đã có sẵn cột "Số tiền")
3. Trang trí 3+ NCC khác nhau 3+ màu khác nhau
4. NCC được chọn (winner) nổi bật hơn
FE-only mirror fe-admin + fe-user.
### AddSupplierDialog — sequential POST tạo NCC + Quote
- Thêm prop `detailId?: string` (truyền từ HangMucCard call site)
- Form state +`thanhTien: 0`
- showQuote = !!detailId — chỉ render input "Số tiền báo giá" khi gọi từ
HangMucCard (call site khác giữ behavior cũ tạo NCC only)
- Mutation 2 step:
1. POST /purchase-evaluations/{id}/suppliers → response {id} (BE controller
PurchaseEvaluationsController.AddSupplier trả Ok(new {id = newId}))
2. Nếu detailId + thanhTien > 0 → POST /quotes với purchaseEvaluationDetailId
+ purchaseEvaluationSupplierId (newSupplierRowId) + thanhTien
- Toast: "Đã thêm NCC + báo giá" (có quote) hoặc "Đã thêm NCC" (no quote)
- Section input "Số tiền" trong card brand-50/40 + VND format suffix đ + hint
"Để trống / 0 → chỉ tạo NCC, chưa báo giá. Sửa lại sau bằng cách click số
tiền trong bảng."
- HangMucCard pass detailId={detail.id} khi mount AddSupplierDialog
### NCC row 5-màu cycle palette
- NEW const NCC_PALETTES (literal Tailwind class strings để JIT scan):
blue / purple / sky / teal / pink (border-l-4 colored + bg subtle 50/40)
- Loop ev.suppliers.map((s, idx) → palette = NCC_PALETTES[idx % 5]
- Tr className: `align-top border-l-4` + palette (non-winner) hoặc winner
override
### Winner highlight nổi bật
- Tr non-winner: cycle palette (5 màu)
- Tr winner override:
- border-l-emerald-500 (thay vì palette stripe)
- bg-emerald-100/70 (đậm hơn 50/60 cũ)
- font-semibold + shadow-sm
- ring-1 ring-inset ring-emerald-300 (viền trong cho ô nổi)
- NCC name cell: badge inline-flex rounded-full bg-emerald-600 text-white
text-[9px] font-bold uppercase "🏆 Trúng thầu" (thay icon ✓ cũ)
- Note text bumped lên text-amber-700 (chút đậm hơn 600 cũ cho visible khi
winner bg đậm hơn)
KHÔNG đụng schema BE. 2 endpoint sẵn (POST /suppliers + POST /quotes) chain.
Verify:
- npm run build × fe-admin pass
- npm run build × fe-user pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 059bfcbe38 |
[CLAUDE] FE-Admin+Domain: Chunk C — MenuVisibilityPage + menu key + seed
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Has been cancelled
Session 20 turn 7 Chunk C. FE Admin page quản lý Ẩn/Hiện + Đổi tên menu
cho fe-user (eOffice). Admin sidebar fe-admin LUÔN dùng Tên gốc — page này
KHÔNG đụng admin navigation (user Q2=b).
Domain MenuKeys.cs:
+const MenuVisibility = "MenuVisibility"
All[] thêm MenuVisibility (giữa Permissions + Workflows)
DbInitializer SeedMenuTreeAsync:
+leaf (MenuVisibility, "Menu eOffice", System, 94, "Eye")
Workflows shift Order 94 → 95
Idempotent — chỉ INSERT nếu chưa có trong DB
Manual seed Mig 27 LocalDB Dev: INSERT MenuItems + Permissions cho Admin role
FE Admin:
- types/menu.ts: MenuItem/MenuNode +isVisible bool +displayLabel string|null
- lib/menuKeys.ts: +MenuVisibility const
- components/Layout.tsx resolver +MenuVisibility → /system/menu-visibility
- App.tsx +Route + import MenuVisibilityPage
NEW pages/system/MenuVisibilityPage.tsx (~210 LOC):
- PageHeader + 4 StatCard (Tổng / Hiển thị / Đã ẩn / Đã đổi tên)
- Search input (key | label | displayLabel)
- Table: Key (mono + parentKey ↳) | Tên gốc | Input "Tên hiển thị" inline
(placeholder "Mặc định: ...") | Toggle Hiển thị/Ẩn (emerald/amber) |
Lưu (khi dirty) / Khôi phục (khi đã custom)
- PATCH /menus/{key} body { isVisible, displayLabel } — trim whitespace,
empty string → null
- onSuccess: invalidate ['menus', 'all'] + ['my-menu'] + clear draft entry
- "Khôi phục mặc định" button: PATCH isVisible=true, displayLabel=null
- Footer hint: nhắc admin sidebar luôn dùng Tên gốc, đổi tên áp eOffice
Verify:
- npm run build × fe-admin pass
Pending Chunk D: FE Layout fe-user filter !isVisible + render displayLabel
Pending Chunk E: Docs S20 turn 7
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| f568945069 |
[CLAUDE] FE-PE: Manual budget "Nhập tay" — drop Tên field, format VND
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m12s
User Session 20 turn 6 screenshot: chế độ "Nhập tay (không link)" Section 2
b. Ngân sách vẫn còn input "Tên (vd Tạm tính T11/2025)" cùng số tiền. User
chỉ cần nhập số tiền — bỏ Tên + áp VND format consistent.
3 file × 2 app = 6 file FE update:
- PeDetailTabs.tsx BudgetFieldRow (Section 2 detail editor)
- PeWorkspaceCreateView.tsx (workspace mode "new")
- PeHeaderForm.tsx (Create/Edit header page)
Mỗi file:
- Drop Input "Tên ngân sách" UI khỏi manual mode (state field giữ '' để
backward compat — BE save luôn null)
- Manual mode UI giờ chỉ 1 input số tiền (max-w-xs):
* type="text" inputMode="numeric" + value={formatVndInput(amount)}
* onChange={parseVnd} strip non-digit → number
* Suffix "đ" tuyệt đối inset-y-0 right-3
* Hint "VND — nhập số, tự format dấu chấm ngàn (vd 1.000.000)"
- Helpers parseVnd + formatVndInput inline mỗi file (mirror PeDetailTabs)
PeDetailTabs BudgetFieldRow cleanup:
- Drop state manualName + setManualName
- Drop manualName từ dirty check
- Save payload: budgetManualName: null luôn (không phụ thuộc state)
- Hủy thay đổi: drop reset manualName line
Read-only display (legacy data) giữ ev.budgetManualName nếu data cũ có tên
(đoạn render khi !canEdit) — không xóa hiển thị, chỉ ẩn input UI.
BE schema KHÔNG đụng — endpoint PUT /pe/:id vẫn nhận budgetManualName field,
chỉ FE luôn gửi null.
Verify:
- npm run build × fe-admin pass
- npm run build × fe-user pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 169459e66f |
[CLAUDE] FE-PE: NCC cell button visual + Hạng mục header gộp 1 ô Ngân sách + DetailDialog rút gọn
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m0s
User Session 20 turn 5: 2 yêu cầu UX rõ ràng chỗ nhập tiền.
FE-only mirror fe-admin + fe-user.
1. NCC grid cell "Số tiền" → button visual rõ ràng cho user biết là chỗ nhập:
- Trước: <td onClick> trông như text cell (chỉ hover bg → user không
biết click được)
- Sau: <button> trong td:
* Empty (chưa nhập): border-dashed border-slate-300 bg-slate-50
text-slate-400 + label "+ Nhập số tiền" + hover brand
* Filled: border-solid border-slate-300 bg-white font-semibold + số tiền
+ suffix " đ" + hover brand
* Winner: border-emerald-300 bg-emerald-50 text-emerald-700
- Read-only mode: hiển thị <div> số tiền (không button)
- Drop `cellHover` var không còn dùng
2. Hạng mục header gộp 3 stat (KL / ĐG ngân sách / Thành tiền NS) → 1 ô
"Số tiền ngân sách" lớn hơn (text-base font-semibold + suffix đ):
- Trước: 3 columns hiển thị KL + ĐG + TT (kỹ thuật, user không cần thấy)
- Sau: 1 column "Số tiền ngân sách: X đ" — duy nhất số quan trọng
- "NS link Δ" comparison column giữ (nếu có Budget link FYI)
3. DetailDialog rút gọn 11 input → 3 input chính:
- Trước: groupCode + groupName + itemCode + noiDung + donViTinh +
KL ngân sách + KL thi công + đơn giá + thành tiền auto + ghi chú (10
input grid 3 cols)
- Sau: Tên hạng mục (noiDung) + Số tiền ngân sách (VND format + suffix
đ + hint) + Ghi chú (3 input vertical)
- Helper setBudgetAmount: user nhập 1 số → set cả donGia + thanhTien
(KL=1 ngầm). BE giữ schema 3 field backward compat.
- Form state default đổi: groupCode="01" groupName="Hạng mục chính"
donViTinh="gói" KL=1 (consistent với Chunk A BE seed)
- Drop updateAndRecalc helper (không còn auto-calc KL × ĐG)
KHÔNG đụng schema BE.
Verify:
- npm run build × fe-admin pass
- npm run build × fe-user pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 17c5f14e20 |
[CLAUDE] FE-PE: NCC table SĐT+Email rõ ràng + validate format + Số tiền format VND
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m0s
User Session 20 turn 4: NCC info cơ bản (SĐT + Email), ràng buộc format,
input tiền VND format dấu chấm 1.000.000.
FE-only mirror fe-admin + fe-user.
1. Helpers cấu hình ở top file (gần fmtMoney):
- parseVnd(s): strip non-digit → number (0 nếu rỗng)
- formatVndInput(n): n.toLocaleString('vi-VN') hoặc '' khi n=0
- PHONE_RE /^0\d{9,10}$/ — VN bắt đầu 0, 10-11 digits sau strip space/dash/dot
- EMAIL_RE /^[^\s@]+@[^\s@]+\.[^\s@]+$/
- isValidPhone(s) / isValidEmail(s) — empty OK (optional)
2. NCC inline table HangMucCard — bỏ cột "Liên hệ" tổng hợp (ContactName +
Phone + Email gộp), thay bằng 2 cột riêng:
Trước: NCC | Liên hệ | Điều khoản TT | File báo giá | Số tiền | Action
Sau: NCC | SĐT | Email | Điều khoản TT | File báo giá | Số tiền | Action
SĐT cell font-mono (đọc số rõ); Email cell truncate + title hover full.
3. AddSupplierDialog + EditSupplierDialog — validate phone + email:
- Input type="tel" / type="email" + inputMode + placeholder example
- border-red-300 khi invalid + dòng error text [10px] mt-0.5 red-600
- Disable nút Lưu/Thêm khi hasError = phoneError || emailError
- ContactName + DisplayName + Note + PaymentTermText giữ (optional fields,
backward compat — user nói "cơ bản thôi" áp cho display, dialog giữ
đầy đủ field tránh churn schema)
4. QuoteDialog "Số tiền" input format VND:
- type="text" inputMode="numeric" thay vì type="number" (để format dấu
chấm ngàn không phá bởi browser number parser)
- value={formatVndInput(form.thanhTien)} → display "1.000.000"
- onChange={parseVnd(e.target.value)} → strip non-digit → state raw number
- Suffix span "đ" tuyệt đối inset-y-0 right-3 pointer-events-none
- Hint dưới input: "VND — nhập số, tự format dấu chấm ngàn (vd 1.000.000)"
- Class font-mono text-right pr-12 (chừa chỗ suffix)
Verify:
- npm run build × fe-admin pass
- npm run build × fe-user pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| e03314e2e7 |
[CLAUDE] FE-PE: NCC table 1 cột "Số tiền" + QuoteDialog 1 input đơn giản hóa
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m11s
User Session 20 turn 3: "Tạm thời chỉ cần nhập số tiền vào là đc, không cần
3 cột có VAT / ko VAT / tổng. 2 cột kia ẩn đi, chỉ 1 cột nhập tiền duy nhất."
FE-only mirror fe-admin + fe-user:
NCC inline table HangMucCard — bỏ 2 th + 2 td:
Trước: NCC | Liên hệ | Điều khoản TT | File báo giá | ĐG chưa VAT | ĐG có VAT | Thành tiền | Action
Sau: NCC | Liên hệ | Điều khoản TT | File báo giá | Số tiền | Action
QuoteDialog — đơn giản hóa form:
Trước: 3 input (Đơn giá chưa VAT / ĐG có VAT / Thành tiền auto-calc) + Ghi chú
+ display khoiLuong info
Sau: 1 input "Số tiền" (autoFocus) — map thẳng vào thanhTien field
Schema BE giữ nguyên (bgVat / chuaVat / note vẫn POST):
- Row mới: bgVat=0, chuaVat=0, note=''
- Existing: giữ giá trị cũ
Bỏ prop khoiLuong (không dùng — không còn auto-calc thanhTien = chuaVat × khoiLuong)
Bỏ updateAndRecalc helper
KHÔNG đụng schema BE — endpoint POST /purchase-evaluations/{id}/quotes giữ
nguyên payload shape, chỉ FE rút gọn input mặt người dùng nhập.
Verify:
- npm run build × fe-admin pass
- npm run build × fe-user pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| c4ece8071f |
[CLAUDE] FE-PE: Section Ý kiến revise — ô vuông cards grid-cols-2 + counter Cấp đúng semantic
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m11s
User feedback Session 20 turn 2:
1. "Chỗ ý kiến vẫn hiển thị ô vuông như trước nhé" — revert visual về cards
grid-cols-2 mirror S19 (Chunk C cũ dùng vertical list inline không phải
ô vuông như trước).
2. "Số bước duyệt khác số người duyệt trong 1 bước, check lại" — counter cũ
`{opinions.length}/{totalApprovers}` sai semantic vì OR-of-N (mỗi Cấp chỉ
cần 1 NV ký, không cần ký tất cả NV). totalApprovers đếm tổng NV gây hiểu
lầm.
Fix (FE-only mirror fe-admin + fe-user):
- StepOpinionsBox body chuyển từ `space-y-2` (vertical list) sang
`grid grid-cols-1 md:grid-cols-2 gap-3` — mỗi opinion = 1 card đầy đủ
border-emerald-200 + bg-white + p-3 (mirror visual S19 LevelOpinionBox).
- StepOpinionEntry restore styling đầy đủ:
- Header: "Cấp N — Tên NV" font-semibold + admin override badge amber +
"✓ Đã duyệt" emerald rounded-full badge
- Body: comment text-sm
- Footer: signedAt border-t separator (như S19)
- Counter mới: `{signedLevels}/{totalLevels} cấp đã duyệt · {totalApprovers}
NV tham gia` — đếm Cấp distinct (Set unique levelOrder) thay vì count NV.
Tooltip giải thích "OR-of-N" cho user hiểu.
- KHÔNG đụng schema Mig 26 (vẫn UPSERT 1 row / Level qua Service).
Verify:
- npm run build × fe-admin pass
- npm run build × fe-user pass
- Test pass mặc định skip (Q4 UAT iteration)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| f2f01f4765 |
[CLAUDE] FE-PE: Chunk C — Section Ý kiến gộp đồng cấp cùng Phòng (1 box / Step)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m54s
Restructure Section 5 (rename Section 4 sau Chunk B) "Ý kiến cấp duyệt".
User Session 20 Q3=a: gộp các comment đồng cấp cùng Phòng → 1 ô / bước
(dù bước có nhiều người), CHỈ hiển thị comment của NV đã duyệt.
Trước (Mig 26 S19 LevelOpinionsSectionV2):
forEach step → grid-cols-2 cho forEach Level × forEach Approver → 1 box / NV
Hiển thị cả NV chưa duyệt với placeholder "— chưa duyệt"
Sau (Chunk C):
forEach step → 1 StepOpinionsBox (đại diện Phòng)
Box body: filter opinions có stepOrder == step.order
→ sort theo levelOrder asc, signedAt asc
→ render StepOpinionEntry per signed opinion
NV chưa duyệt KHÔNG hiển thị
Header box: "Bước N — Tên · {dept badge} · X/Y đã duyệt"
FE (mirror fe-admin + fe-user):
- LevelOpinionsSectionV2 forEach step → StepOpinionsBox (replace grid-cols-2)
- StepOpinionsBox: header phòng + body list signed opinions
- StepOpinionEntry: tên NV + Cấp badge + Admin override badge nếu có
+ timestamp + comment
- Drop LevelOpinionBox function (per-NV pattern bỏ)
- KHÔNG đụng schema Mig 26 (PE Service ApproveV2Async UPSERT giữ 1 row /
Level — chỉ FE re-group render)
Verify:
- npm run build × fe-admin pass · fe-user pass
- Test pass mặc định skip (Phase 9 UAT iteration, Q4 user public luôn)
Pending Chunk D: Docs S20 changelog + STATUS + HANDOFF
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 2bba851135 |
[CLAUDE] FE-PE: Chunk B — NCC nested expand dưới Hạng mục, bỏ Section 4 riêng
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Has been cancelled
Restructure ItemsTab → nested cards (tầng 1 = hạng mục, tầng 2 = NCC tham
gia + báo giá inline). Replace bảng matrix grid (hạng mục × NCC) cũ — user
Session 20 yêu cầu UX nested cho 1 hạng mục demo.
FE (mirror fe-admin + fe-user):
- ItemsTab giờ render list HangMucCard (1 card / 1 hạng mục)
- HangMucCard mới: header info hạng mục + expand panel default OPEN
- Expand panel: NCC inline table columns:
NCC | Liên hệ | Điều khoản TT | File báo giá | ĐG chưa VAT | ĐG có VAT | Thành tiền | Action
- Quote click cell → QuoteDialog cũ (reuse)
- NCC button: + Thêm NCC (AddSupplierDialog) / ✏ Sửa (EditSupplierDialog) / ✓ Winner / 🗑 Xóa
- Budget Δ compute per-card (KHÔNG tfoot tổng — 1 hạng mục)
- Bỏ Section 4 "NCC tham gia" cũ trong main render — gộp vào Section 2
- Drop function SuppliersTab (dead code) — giữ AddSupplierDialog +
EditSupplierDialog + SupplierAttachmentsCell cho HangMucCard reuse
Section layout mới (4 section):
1. Thông tin gói thầu
2. Hạng mục + Báo giá NCC (nested)
3. Chọn NCC / TP thắng thầu
4. Ý kiến cấp duyệt
Verify:
- npm run build × fe-admin pass (warning chunk size, không liên quan)
- npm run build × fe-user pass
- Test pass mặc định skip (Phase 9 UAT iteration, Q4 user public luôn)
Pending Chunk C: Section 5 (rename 4) gộp đồng cấp cùng Phòng — 1 box / Step
Pending Chunk D: Docs S20 changelog + STATUS + HANDOFF
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|