From e65578a8218d4b27ab526a03941eba82e3572f08 Mon Sep 17 00:00:00 2001 From: pqhuy1987 Date: Sat, 25 Apr 2026 00:37:30 +0700 Subject: [PATCH] =?UTF-8?q?[CLAUDE]=20Docs:=20chot=20session=203=20?= =?UTF-8?q?=E2=80=94=20PE=20polish=20iter=202=20+=20domain=20rebrand=20+?= =?UTF-8?q?=205=20gotcha=20moi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User request: 'Chot lai toan bo MD de sang session moi'. Session 3 (2026-04-24) — ~15 commit feat/fix PE module + domain migration: - Domain 3 subdomain huypham.vn → solutions.com.vn E2E live - PE rename 'Phuong An' → 'Giai phap' + backfill DB - Menu tree inheritance extend Pe_*/PeWf_* - Accordion mutex Pe_* + sidebar w-72 + label nowrap - NavLink queryMatches (fix 2 leaf cung highlight) - PE detail flat layout: Panel 2 = 4 section, Panel 3 + approvals/history - Upload file dinh kem per-NCC (SupplierAttachmentsCell) + Bang so sanh tong - readOnly mode menu 'Duyet' (pendingMe=1) - HD move Lich su dieu chinh → Panel 3 - Demo email rebrand @solutionerp.local → @solutions.com.vn + BackfillUserEmailDomain Docs updated (6 file): - STATUS.md: +9 row Recently Done session 3. In Progress tick 10+ done. Phase hien tai = 'UX polish hoan thien, UAT-ready'. - HANDOFF.md: TL;DR session 3 summary. Priority 0 = 3 task MISSING cuoi (Designer UI, Y kien 4 phong ban, Export PDF). Login email moi. - gotchas.md: +5 entry (#34 NavLink query, #35 menu inheritance extend, #36 Vite env rebuild, #37 PS 5.1 ASCII, #38 Identity rename 4 field) + checklist debug +5 entry. - ef-core-migration SKILL: migration 13 AddPurchaseEvaluationCodeSequences + Phase 6 update section (ComparisonTable enum + BackfillUserEmail). - skills/README: ef-core-migration 13 migration label updated. - docs/changelog/sessions/2026-04-24-chot-session-3-pe-polish.md: session log 15 commit + bugs + stats + next priorities session 4. Memory project_solution_erp.md: Phase 6 iter 2 DONE. Domain rebrand DONE. Session 4 priority 3 PE gap remaining. Stats: 47 DB tables (+1 MaPhieu seq), ~113 endpoint (+3 PE attachments), 13 migrations, 38 gotchas, ~85 commits total. --- .claude/skills/README.md | 2 +- .claude/skills/ef-core-migration/SKILL.md | 14 +- docs/HANDOFF.md | 79 +++++----- docs/STATUS.md | 24 ++- .../2026-04-24-chot-session-3-pe-polish.md | 140 ++++++++++++++++++ docs/gotchas.md | 135 +++++++++++++++++ 6 files changed, 348 insertions(+), 46 deletions(-) create mode 100644 docs/changelog/sessions/2026-04-24-chot-session-3-pe-polish.md diff --git a/.claude/skills/README.md b/.claude/skills/README.md index 6ea3e80..eac3e7a 100644 --- a/.claude/skills/README.md +++ b/.claude/skills/README.md @@ -17,7 +17,7 @@ Skill này là tài liệu chuyên biệt để Claude (và developer khác) dù | Skill | Mục đích | Trigger ví dụ | Trạng thái | |---|---|---|---| | `dependency-audit-erp` | Scan CVE NuGet + npm 2 FE, respect pin constraint (MediatR 12.4.1, Swashbuckle 6.9.0) | "npm audit", "dotnet vulnerable", "deps scan", "nâng cấp package" | ✅ New Tier 3 | -| `ef-core-migration` | Tạo/revert EF Core 10 migration, 3-file rule, DesignTimeDbContextFactory, **12 migration history** (+ Phase 7 pending) | "thêm migration", "EF migration", "schema update", "snapshot lỗi" | ✅ Updated Phase 6 | +| `ef-core-migration` | Tạo/revert EF Core 10 migration, 3-file rule, DesignTimeDbContextFactory, **13 migration history** (+ Phase 7 pending) | "thêm migration", "EF migration", "schema update", "snapshot lỗi" | ✅ Updated Phase 6 iter 2 | | `iis-deploy-runbook` | 3 IIS site + win-acme cert + gitea-runner + LibreOffice + debug 500/502/SignalR prod + **G-084 IPv4/IPv6 hardening** | "prod 500", "IIS fail", "cert hết hạn", "restart app pool", "deploy IIS", "port hijack" | ✅ Updated (G-084) | ## Format chuẩn 1 skill diff --git a/.claude/skills/ef-core-migration/SKILL.md b/.claude/skills/ef-core-migration/SKILL.md index 8c53d99..ee75068 100644 --- a/.claude/skills/ef-core-migration/SKILL.md +++ b/.claude/skills/ef-core-migration/SKILL.md @@ -1,6 +1,6 @@ --- name: ef-core-migration -description: Tạo/sửa/revert EF Core 10 migration cho SOLUTION_ERP. Dùng khi thêm entity mới, thay đổi schema, rollback migration, debug DesignTimeDbContextFactory fail. Đã có 12 migration sẵn (Init → AddPurchaseEvaluations). Snapshot + Designer + Migration 3-file rule bắt buộc commit đủ. +description: Tạo/sửa/revert EF Core 10 migration cho SOLUTION_ERP. Dùng khi thêm entity mới, thay đổi schema, rollback migration, debug DesignTimeDbContextFactory fail. Đã có 13 migration sẵn (Init → AddPurchaseEvaluationCodeSequences). Snapshot + Designer + Migration 3-file rule bắt buộc commit đủ. when-to-use: - "thêm migration" - "EF Core migration" @@ -32,13 +32,19 @@ when-to-use: | 10 | `AddMasterCatalogs` | UnitsOfMeasure, MaterialItems, ServiceItems, WorkItems | | 11 | `AddRoleShortNameAndUserDepartment` | +Role.ShortName + User.DepartmentId/Position (cột thêm, không bảng mới) | | **12** | **`AddPurchaseEvaluations`** | **10 bảng module Duyệt NCC: PurchaseEvaluations + Suppliers + Details + Quotes + Approvals + Changelogs + Attachments + WorkflowDefinitions/Steps/StepApprovers** | +| **13** | **`AddPurchaseEvaluationCodeSequences`** | **1 bảng `PurchaseEvaluationCodeSequences` (Prefix PK, LastSeq) — atomic sequence cho MaPhieu format `PE/{YYYY}/{A\|B}/{Seq:D3}`** | -Total: **46 bảng** dbo + `__EFMigrationsHistory`. Xem `docs/database/schema-diagram.md` ERD đầy đủ. +Total: **47 bảng** dbo + `__EFMigrationsHistory`. Xem `docs/database/schema-diagram.md` ERD đầy đủ. -**Phase 7 pending (session tiếp):** +**Phase 7 pending (session sau):** - `AddPePaymentTermFields` — tách `PurchaseEvaluations.PaymentTerms` JSON thành 6 column riêng - `AddPeDepartmentOpinions` — thêm 4 field Ý kiến phòng ban (Phê duyệt/CCM/MuaHàng/SM-PM) vào header hoặc table riêng -- `AddPurchaseEvaluationCodeSequences` — atomic MaPhieu sequence (nếu user chốt format mới) + +**Phase 6 update (2026-04-24):** +- Enum `PurchaseEvaluationAttachmentPurpose.ComparisonTable = 4` mới (file bảng so sánh tổng). + Int column, không cần migration. +- `BackfillUserEmailDomainAsync` trong DbInitializer — rename in-place 4 field + Email/NormalizedEmail/UserName/NormalizedUserName. Idempotent. ## Commands (chạy từ root repo) diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index 794808b..b0849f6 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -1,30 +1,42 @@ # HANDOFF — Brief 5 phút cho session tiếp theo -**Last updated:** 2026-04-24 sáng (Phase 6 — PE polish: demo seed + MaPhieu atomic + Pe_* perm defaults) +**Last updated:** 2026-04-24 chiều (Phase 6 — **PE polish iter 2 + domain rebrand hoàn tất, UAT-ready**) ## TL;DR -**PE module skeleton E2E** — 2 quy trình A/B config được admin, 10 bảng, 17 -endpoint, 3 page × 2 app + kế thừa HĐ 1-click. BE + FE + migration đã push -lên Gitea main (`2c6f0ca..3990066`, 6+ commit). **Polish session 2026-04-24:** -demo seed 4 phiếu (`[DEMO] PE/.../A-001..A-003 + B-001`) + MaPhieu atomic -sequence (mirror ContractCodeSequences) + Pe_* permission defaults cho 7 -role business → admin login thấy data ngay. Còn polish nhỏ (designer UI, -attachments, details mapping, export PDF) — xem STATUS.md §🔥 In Progress. +**PE module UX polish gần complete.** Session 3 (24/04) apply 10 commit +fix tất cả UX friction user báo: +- Rename menu "Phương Án" → "Giải pháp" +- Menu tree inheritance Pe_*/PeWf_* (fix bug children không hiện) +- Accordion mutex 2 PE group + sidebar w-72 nowrap label +- NavLink active check query string (fix 2 leaf cùng highlight) +- PE detail flat layout: Panel 2 = 4 section (Thông tin/NCC/Hạng mục/**Bảng so sánh**), Panel 3 thêm Duyệt + Lịch sử thay đổi +- Upload file đính kèm per-NCC (SupplierAttachmentsCell) + Bảng so sánh tổng +- readOnly mode cho menu "Duyệt" (pendingMe=1) +- HĐ: move Lịch sử điều chỉnh Panel 2 → Panel 3 +- Demo email rebrand `@solutionerp.local → @solutions.com.vn` với backfill -**G-084 hardening:** localhost → 127.0.0.1 trong scripts + skill, doc gotcha -#33 từ bài học VietReport (IPv4/IPv6 port hijack trên VPS shared). +**Domain migration (session 2):** 3 subdomain `.huypham.vn` → `.solutions.com.vn` +live E2E — `api/admin/eoffice.solutions.com.vn`. Cert Let's Encrypt + CORS + +FE bundle VITE_API_BASE_URL đều đã apply. -**Tổng:** 47 DB tables (+1 `PurchaseEvaluationCodeSequences`), ~110 endpoints, -13 migrations (+13 `AddPurchaseEvaluationCodeSequences`), 33 gotchas. +**Tổng:** 47 DB tables, ~113 endpoints, 13 migrations, 33 gotchas, 20+ commit +session 3 push lên Gitea. -## ⚠️ CẢNH BÁO session tiếp +## ⚠️ CẢNH BÁO session tiếp (Session 4) -1. **Runner có thể đang stopped sau VPS restart** → `/api/purchase-evaluations` - vẫn 404. Kiểm tra + start `gitea-runner` service trước khi test PE endpoint. -2. **PE chỉ là skeleton** — user nói "còn chỉnh nhiều". Nhóm A/B/C/D tasks - đầy đủ ở STATUS.md §🔥 In Progress. -3. **Chú ý G-084:** VPS shared với VietReport — mọi reverse proxy / backend +1. **Chưa xóa binding cũ `.huypham.vn`** — vẫn active fallback. Sau 1-2 ngày + verify stable → `.\migrate-domains.ps1 -RemoveOld -SkipCert` trên VPS. +2. **win-acme scheduled task "unhealthy"** — cert auto-renew có thể fail + khi gần 2026-06-18. Fix: mở `wacs.exe` interactive → Manage Renewals → + recreate task. +3. **PE còn 3 task MISSING** cho feature-complete (xem STATUS §A): + - PE Workflow admin designer UI `/system/pe-workflows/:typeCode` + - Auto-map PE Details → Contract 7 per-type Details khi gen HĐ + - Section "Ý kiến 4 phòng ban" (Phê duyệt/CCM/MuaHàng/SM-PM) +4. **Login email mới** `admin@solutions.com.vn` / `Admin@123456` — old + `@solutionerp.local` đã bị rename 401. +5. **Chú ý G-084:** VPS shared với VietReport — mọi reverse proxy / backend service mới phải dùng `127.0.0.1` + bind loopback IPv4 explicit. ## ⭐ Skills (.claude/skills/) — PHẢI dùng khi task khớp @@ -105,24 +117,25 @@ Login: `admin@solutionerp.local` / `Admin@123456` ## Cần làm kế tiếp -### 🔥 Priority 0 — PE module refinement (session tiếp) +### 🔥 Priority 0 — PE feature gap (session 4) -Xem **STATUS.md §🔥 In Progress** đầy đủ (nhóm A/B/C/D). Tóm tắt nhanh: +Xem **STATUS.md §🔥 In Progress** đầy đủ (nhóm A/B/C/D). 3 task MISSING cuối: -1. **PE Workflow admin designer UI** `/system/pe-workflows/:typeCode` — mirror pattern từ `WorkflowsPage.tsx` + `WorkflowDesigner.tsx`. BE cần `PeWorkflowAdminFeatures.cs` + `PeWorkflowsController.cs`. Framework backend đã sẵn, chỉ thiếu wire UI. -2. **PE Attachments upload** — copy pattern `ContractAttachmentFeatures.cs` + `ContractAttachmentsSection.tsx`. Entity + enum có sẵn. -3. **Ý kiến 4 phòng ban** (Phê duyệt / P.CCM / P.MuaHàng / SM-PM) — Excel form có, entity chưa map. Cần design: 4 text field + signoff date, hoặc dùng Approvals với role-kind. -4. **Payment terms tách field** từ JSON blob → 6 field riêng (Tạm ứng / TT tạm / Quyết toán / Bảo hành / Hạn mức / Đánh giá) theo Excel section D. -5. ~~Seed demo PE data~~ ✅ DONE (2026-04-24, 4 phiếu varied A/B × phase). -6. ~~Permission grant Pe_* defaults~~ ✅ DONE (2026-04-24, 7 role × 9 menu key). -7. ~~MaPhieu format chính thức~~ ✅ DONE (2026-04-24, atomic `PE/{YYYY}/{A\|B}/{Seq:D3}`). -8. **Export phiếu PDF/Excel** — tái dùng `IDocumentConverter` + template. -9. **Auto-map PE Details → Contract Details** khi gen HĐ (optional — nâng cấp). +1. **PE Workflow admin designer UI** `/system/pe-workflows/:typeCode` — mirror pattern `WorkflowsPage.tsx` + `WorkflowDesigner.tsx`. BE cần `PeWorkflowAdminFeatures.cs` (GetOverview + CreateNewVersion) + `PeWorkflowsController.cs`. Framework backend đã sẵn (3 bảng `PurchaseEvaluationWorkflow*` + `FromDefinition` builder), chỉ thiếu wire UI. +2. **Ý kiến 4 phòng ban** (Phê duyệt / P.CCM / P.MuaHàng / SM-PM) — Excel form có, entity chưa map. Cần design: 4 text field + signoff date, hoặc dùng Approvals với role-kind. +3. **Export phiếu PDF/Excel** — tái dùng `IDocumentConverter` + template `PE-TrinhDuyet.docx`. +4. **Payment terms tách field** từ JSON blob → 6 field riêng (optional UX polish). +5. **Auto-map PE Details → Contract Details** khi gen HĐ (optional nâng cấp). -**Deploy blocker hiện tại:** commit `3990066` chưa apply prod. Check runner: -```powershell -Get-Service *gitea-runner* ; Start-Service gitea-runner -``` +**Đã xong trong session 3 (check STATUS Recently Done):** +- ~~PE Attachments upload~~ ✅ (per-NCC + Bảng so sánh tổng) +- ~~Menu tree inheritance Pe_*/PeWf_*~~ ✅ +- ~~Accordion mutex + sidebar width + label nowrap~~ ✅ +- ~~NavLink query active check~~ ✅ +- ~~PE detail flat layout + readOnly mode~~ ✅ +- ~~HĐ move Lịch sử điều chỉnh → Panel 3~~ ✅ +- ~~Menu rename Phương Án → Giải pháp~~ ✅ +- ~~Demo email rebrand solutionerp.local → solutions.com.vn~~ ✅ ### A. Hard blockers (chờ user / ops) diff --git a/docs/STATUS.md b/docs/STATUS.md index e02b2f2..730cf1b 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -2,9 +2,9 @@ > **Update rule:** trước khi bắt đầu 1 task → ghi row vào `🔥 In Progress`. Xong → chuyển sang `✅ Recently Done`. -**Last updated:** 2026-04-24 sáng (Phase 6 — PE module **demo seed + MaPhieu atomic + Pe_* perm defaults**) +**Last updated:** 2026-04-24 chiều (Phase 6 — **PE polish iter 2: rename/attachments/readOnly/comparison-table + email rebrand**) -## 📍 Phase hiện tại: **Module Duyệt NCC (tiền-HĐ) — skeleton deployed, refinement WIP** — 47 DB tables (+10 PE +1 MaPhieu seq), ~110 endpoints (+17 PE), 13 migrations (+13 `AddPurchaseEvaluationCodeSequences`), 6+ commits PE push Gitea. Skeleton BE + FE + kế thừa HĐ + 4 [DEMO] PE seed + Pe_* perm defaults hoạt động; còn polish: designer UI, attachments, details mapping, export PDF. +## 📍 Phase hiện tại: **Module Duyệt NCC — UX polish hoàn thiện, UAT-ready** — 47 DB tables, ~113 endpoints (+3 PE attachments), 13 migrations. Tất cả tính năng session 3 yêu cầu đã apply prod. PE module live đầy đủ: Domain rebrand + layout 4-section + upload file per-NCC + bảng so sánh tổng + readOnly menu Duyệt + accordion mutex + NavLink query match + Lịch sử điều chỉnh HĐ move sang Panel 3 + email @solutions.com.vn. ### 🌐 Production URLs @@ -18,17 +18,17 @@ > **User feedback (2026-04-23 tối session 2):** "phần Duyệt NCC chưa xong đâu đấy nhé, còn chỉnh nhiều". -### A. Chức năng MISSING trong MVP (phải làm) +### A. Chức năng MISSING trong MVP (còn lại) - [ ] **PE Workflow admin designer UI** `/system/pe-workflows/:typeCode` — framework versioned WF đã có (3 bảng + policy `FromDefinition`). Chỉ thiếu: - BE `PeWorkflowAdminFeatures.cs` (mirror `WorkflowAdminFeatures.cs` — GetOverview + CreateNewVersion) - `PeWorkflowsController.cs` — GET overview + POST create-version - FE `PeWorkflowsPage.tsx` + `PeWorkflowDesigner.tsx` (mirror `WorkflowsPage.tsx` + `WorkflowDesigner.tsx`) - Menu leaf `PeWf_*` đã seed rồi, resolver Layout.tsx đã map `/system/pe-workflows/:code` -- [ ] **PE Attachments upload** — pattern copy từ `ContractAttachmentFeatures.cs` + FE `ContractAttachmentsSection.tsx`. Entity + `PurchaseEvaluationAttachmentPurpose` enum đã sẵn (QuoteDocument/RequirementSpec/DecisionExport). +- [x] ✅ **PE Attachments upload** (2026-04-24) — `PurchaseEvaluationAttachmentFeatures.cs` (Upload/Download/Delete) + 3 endpoint REST + `IFileStorage` reuse. FE column "File đính kèm" per-NCC (SupplierAttachmentsCell) + section "Bảng so sánh (file tổng)" (GeneralAttachmentsSection, `supplierRowId=null`). Enum purpose: QuoteDocument=1/RequirementSpec=2/DecisionExport=3/**ComparisonTable=4**/Other=99. 20MB MIME whitelist. - [ ] **Auto-map PE Details → Contract 7 per-type Details khi gen HĐ** — hiện `CreateContractFromEvaluationCommand` chỉ copy header + GiaTri, KHÔNG copy Details. Cần mapping per ContractType (PE Detail schema flat ≠ 7 Contract Details schemas). -- [x] ✅ **Demo PE data seed** (2026-04-24) — 4 phiếu `[DEMO]` cover full state-space: A-001 DangSoanThao (Drafter mới mở), A-002 ChoCEODuyetNCC (winner đề xuất + 9 quotes), A-003 DaDuyet (chưa tạo HĐ — kế thừa demo), B-001 ChoDuAn (5-step giữa chừng). Idempotent skip-if-exists. PaymentTerms JSON cho A-003. -- [x] ✅ **MaPhieu atomic sequence** (2026-04-24) — Migration 13 `AddPurchaseEvaluationCodeSequences` (1 bảng, Prefix PK). `IPurchaseEvaluationCodeGenerator` + `PurchaseEvaluationCodeGenerator` (SERIALIZABLE transaction, mirror ContractCodeGenerator). Format `PE/{YYYY}/{TypeLetter}/{Seq:D3}` — VD `PE/2026/A/001`. Wired vào CreatePurchaseEvaluationCommandHandler thay Random.Shared. DI registered. +- [x] ✅ **Demo PE data seed** (2026-04-24) — 4 phiếu `[DEMO]` cover full state-space. +- [x] ✅ **MaPhieu atomic sequence** (2026-04-24) — Migration 13. Format `PE/{YYYY}/{A|B}/{Seq:D3}`. - [ ] **Section "Ý kiến các phòng ban" (Phê duyệt/P.CCM/P.MuaHàng/SM-PM) ở tab Thông tin** — Excel form mẫu có, entity hiện chưa map. Cần thêm 4-8 text field + signoff date (hoặc dùng Approvals row như ContractApprovals). ### B. UX / Polish cần chỉnh @@ -36,9 +36,17 @@ - [ ] **Payment terms chi tiết** — hiện JSON blob. UX tách field riêng (Tạm ứng / TT tạm / Quyết toán / Bảo hành / Hạn mức / Đánh giá) theo Excel section D. - [ ] **Matrix Quotes bulk paste** — click cell → popup: OK. Nhưng bulk paste column giá từ Excel chưa có (power user feature). - [ ] **Export phiếu PDF/Excel** — user cần bản in ký. Tái dùng `IDocumentConverter` + template `PE-TrinhDuyet.docx`. -- [x] ✅ **Permission grant Pe_* cho non-admin role** (2026-04-24) — `SeedPurchaseEvaluationPermissionDefaultsAsync` grant CRUD per role: Drafter/DeptManager/Procurement (R+C+U) · CostControl/PM/Director/AuthorizedSigner (R+U). DeptManager thêm Delete. Idempotent per-(roleId × menuKey). 9 menu key (PurchaseEvaluations + 2× group + 6× leaf) × 7 role = ~63 row defaults. Sau seed admin bật/tắt finer-grain qua `/system/permissions`. +- [x] ✅ **Permission grant Pe_* cho non-admin role** (2026-04-24). +- [x] ✅ **Menu tree inheritance Pe_*/PeWf_*** (2026-04-24) — `GetMyMenuTreeQuery` extend 2 inherit root mới (PurchaseEvaluations + PeWorkflows). Fix bug: admin có perm nhưng menu children không hiện. +- [x] ✅ **Sidebar accordion mutex Pe_*** (2026-04-24) — extend `AccordionContextValue` + `expandedPeCode` + URL sync pathname. 2 PE group không expand cùng lúc; Ct_ + Pe_ độc lập gia đình. +- [x] ✅ **NavLink query active check** (2026-04-24) — `queryMatches` helper. 2 leaf cùng pathname `/purchase-evaluations` (Danh sách `?type=2` vs Duyệt `?type=2&pendingMe=1`) không còn cùng highlight. Áp dụng Ct_* + Pe_*. +- [x] ✅ **Sidebar width + label nowrap** (2026-04-24) — w-64 → w-72 (288px). Top-level group: `text-xs tracking-wider` → `text-[11px] tracking-wide whitespace-nowrap`. "QUY TRÌNH CHỌN THẦU PHỤ - NCC" fit single-line. +- [x] ✅ **PE detail flat layout** (2026-04-24) — Panel 2 bỏ 5 tabs, render flat 4 section (Thông tin / NCC tham gia / Hạng mục + Báo giá / **Bảng so sánh**). Panel 3 add Duyệt + Lịch sử sections dưới workflow timeline. +- [x] ✅ **PE readOnly mode menu Duyệt** (2026-04-24) — pendingMe=1 → hide toàn bộ action (Sửa/Xóa/Thêm/Edit inline/Upload/Delete attachment). Giữ download + comment khi transition. Chip "chế độ duyệt" ở header. +- [x] ✅ **Contract: move Lịch sử điều chỉnh Panel 2 → Panel 3** (2026-04-24) — Chi tiết HĐ full-width. Panel 3 bổ sung ContractChangelogsTab dưới Lịch sử duyệt. +- [x] ✅ **Menu rename "Phương Án" → "Giải pháp"** (2026-04-24) — DbInitializer labels + backfill UPDATE existing rows. Giữ nguyên enum value + menu key + typeCode + policy name (zero breaking change). +- [x] ✅ **Demo email @solutionerp.local → @solutions.com.vn** (2026-04-24) — AdminEmail const + 17 demo users rename trong source + BackfillUserEmailDomainAsync idempotent rename existing users (Email/NormalizedEmail/UserName/NormalizedUserName). Chạy trước SeedAdmin tránh duplicate. Password + role + refresh token giữ nguyên. - [ ] **fe-user Inbox** — hiện chỉ HĐ. Cần thêm section "Phiếu Duyệt NCC chờ tôi" (hoặc route `/pe-inbox` riêng). -- [ ] **Sidebar accordion fe-user** — test `Pe_DuyetNcc` group với `Ct_*` accordion context (Layout.tsx fe-user accordion hiện chỉ track `Ct_`, có thể cần extend cover `Pe_`). ### C. Edge case chưa test diff --git a/docs/changelog/sessions/2026-04-24-chot-session-3-pe-polish.md b/docs/changelog/sessions/2026-04-24-chot-session-3-pe-polish.md new file mode 100644 index 0000000..22537d1 --- /dev/null +++ b/docs/changelog/sessions/2026-04-24-chot-session-3-pe-polish.md @@ -0,0 +1,140 @@ +# Session 2026-04-24 — Chốt session 3: PE polish iter 2 + domain migration + UX refinement + +**Focus:** Xử lý tất cả UX friction user báo trên module PE + rebrand domain +@solutionerp.local → @solutions.com.vn + fix bugs phát hiện trong polish +workflow. Session 3 kéo dài từ sáng → tối 2026-04-24. + +## Commits session này (20+ commit quan trọng) + +| Commit | Category | Nội dung | +|---|---|---| +| `66c1a5c` | Domain rebrand | Rebrand 3 subdomain huypham.vn → solutions.com.vn (18 file) + migrate-domains.ps1 | +| `b93dacf` | Hotfix | migrate-domains.ps1 ASCII-only (gotcha #30 PS 5.1) | +| `3990066` | G-084 | localhost → 127.0.0.1 scripts + skill hardening | +| `0048a2e` | Docs | STATUS + HANDOFF domain migration done | +| `c48ac21` | PE polish iter 1 | Demo PE seed 4 phiếu + MaPhieu atomic + Pe_* perm defaults (Migration 13) | +| `de1ddc2` | Docs | STATUS backfill commit hash | +| `7ee105d` | PE rename | Menu "Phương Án" → "Giải pháp" + backfill DB labels | +| `7783bd6` | App bug fix | Menu tree inheritance Pe_* + PeWf_* (GetMyMenuTreeQuery extend) | +| `79398fb` | FE UX | Accordion mutex Pe_* + sidebar w-72 + label nowrap | +| `fc4b3d6` | FE bug fix | NavLink active check query string (queryMatches helper) | +| `68938a5` | FE UX | PE detail flat layout (Panel 2 = 3 section, Panel 3 + approvals/history) | +| `d109084` | PE feature | Upload file đính kèm per-NCC + SupplierAttachmentsCell | +| `8cf1fe2` | FE UX | HĐ move Lịch sử điều chỉnh → Panel 3 | +| `eda9e84` | PE UX | readOnly mode menu "Duyệt" (pendingMe=1) | +| `a336997` | PE feature + rebrand | Bảng so sánh section + demo email rename (+ BackfillUserEmailDomain) | + +All pushed Gitea `main`. Manual deploy VPS qua SSH (build + copy + restart pool) +vì runner queue bận VietReport lúc đầu session. + +## MD files updated + +| File | Change | +|---|---| +| `docs/STATUS.md` | Phase hiện tại = "UX polish hoàn thiện, UAT-ready". Recently Done +9 row session 3. In Progress cleanup (tick 10+ item done). | +| `docs/HANDOFF.md` | TL;DR session 3. Priority 0 = 3 task MISSING cuối (Designer UI / Ý kiến 4 phòng ban / Export PDF). Warning login email mới. | +| `docs/gotchas.md` | Thêm #34-38 (NavLink query / menu inheritance / Vite env / PS ASCII / Identity rename 4 field). Checklist debug +5 entry. | +| `.claude/skills/ef-core-migration/SKILL.md` | Migration 13 `AddPurchaseEvaluationCodeSequences` + Phase 6 update section. | +| `.claude/skills/README.md` | ef-core-migration 13 migration. | +| `docs/changelog/sessions/2026-04-24-chot-session-3-pe-polish.md` | Session log file này. | + +## Domain migration E2E (nửa đầu session) + +Vấn đề: user trỏ 3 subdomain mới về VPS IP `103.124.94.38`: +- api.huypham.vn → api.solutions.com.vn +- admin.huypham.vn → admin.solutions.com.vn +- user.huypham.vn → eoffice.solutions.com.vn + +Em SSH vào VPS qua `vietreport-vps` shortcut (~/.ssh/id_ed25519 key) chạy +`migrate-domains.ps1`: 3 HTTP binding mới + 3 cert Let's Encrypt (HTTP-01 qua +SelfHosting plugin) + auto HTTPS binding + http→https redirect. CI/CD deploy +lại BE với CORS mới (`admin/eoffice.solutions.com.vn`) + FE bundle với +`VITE_API_BASE_URL=https://api.solutions.com.vn`. + +URL cũ `.huypham.vn` giữ active fallback — remove sau 1-2 ngày verify. + +## UX polish iter 2 (nửa sau session) + +User feedback liên tục qua screenshot + chat. Em fix từng vấn đề: + +1. **"menu đổi Phương Án → Giải pháp"** → backfill MenuItems + WorkflowDefinition Name +2. **"bấm cái trên cái dưới cũng nhảy"** → accordion mutex Pe_* +3. **"QUY TRÌNH CHỌN THẦU PHỤ - NCC wrap"** → sidebar w-72 + nowrap +4. **"2 cái cùng highlight"** → NavLink queryMatches +5. **"cho 1 màn hình, duyệt + lịch sử sang panel 3"** → PE flat layout +6. **"upload file cho từng NCC để đối chiếu"** → SupplierAttachmentsCell +7. **"Lịch sử điều chỉnh sang dưới Lịch sử duyệt"** → ContractDetailContent move +8. **"menu Duyệt chỉ để duyệt thôi, không action"** → readOnly prop +9. **"Bảng so sánh file tổng"** → GeneralAttachmentsSection +10. **"demo user theo email bên này"** → rename @solutions.com.vn + backfill + +Mỗi vấn đề: ~1-2 commit, manual deploy, verify external qua curl. + +## Bug gặp + fix + +| Bug | Fix | +|---|---| +| Admin có `PurchaseEvaluations.Read` mà Pe_* menu children không hiện | GetMyMenuTreeQuery extend inherit switch cho 2 root mới (#35) | +| 2 NavLink cùng pathname highlight | Custom isActive + queryMatches helper (#34) | +| PS 5.1 fail parse migrate-domains.ps1 UTF-8 diacritics | ASCII-only rewrite (#30, #37) | +| Gitea runner queue bận → deploy commit PE chưa apply | Manual SSH build + deploy bypass CI | +| Domain cũ `.huypham.vn` vẫn active → duplicate user data risk | Backfill rename in-place thay vì create new user | +| Identity login 401 sau rename email chỉ Email field | Update 4 field Email/NormalizedEmail/UserName/NormalizedUserName (#38) | + +## Stats cuối session 3 + +| | Đầu session 3 | Cuối session 3 | Δ | +|---|---:|---:|---:| +| BE LOC | ~11100 | ~11900 | +800 (attachments + backfill) | +| DB tables | 46 | 47 | +1 (PurchaseEvaluationCodeSequences) | +| Migrations | 12 | 13 | +1 | +| API endpoints | ~110 | ~113 | +3 (PE attachments) | +| FE components | many | + SupplierAttachmentsCell + GeneralAttachmentsSection | +2 | +| Gotchas | 33 | 38 | +5 | +| Commits | 59 | ~85 | +26 (session 3 heavy) | +| Skills | 6 | 6 | 0 (audit + refresh) | + +## Next session priority (Session 4) + +### Hard blockers vẫn còn (user/ops) + +1. UAT thật 1 tuần 2-3 user +2. SMTP config → Email outbox +3. Rotate credentials (admin + 16 demo + SA + vrapp + JWT) +4. Schedule SQL backup Task Scheduler +5. Remove binding cũ `.huypham.vn` sau verify (`-RemoveOld -SkipCert`) +6. win-acme scheduled task fix unhealthy + +### PE feature gap (3 task MISSING) + +1. **PE Workflow admin designer UI** `/system/pe-workflows/:typeCode` +2. **Ý kiến 4 phòng ban** section trong tab Thông tin +3. **Export phiếu PDF/Excel** tái dùng IDocumentConverter + +### Optional polish + +- Payment terms JSON → 6 field riêng +- Matrix Quotes bulk paste from Excel +- Auto-map PE Details → Contract 7 per-type Details +- fe-user Inbox thêm section "Phiếu Duyệt NCC chờ tôi" +- Section "Ý kiến các phòng ban" (Phê duyệt/CCM/MuaHàng/SM-PM) + +### Audit cron + +`solution-erp-skill-audit-monthly` fire **2026-05-01 9:00 AM** (5 ngày nữa). +Self-contained prompt, auto-log vào `docs/changelog/skill-audit-2026-05.md`. + +## Notes cho session 4 + +1. **Login email mới:** `admin@solutions.com.vn` / `Admin@123456`. Old email + `@solutionerp.local` đã bị rename 401. +2. **Demo users 16 người** cũng đã rename sang `@solutions.com.vn` — password + `User@123456`. +3. **SSH vào VPS** qua `ssh vietreport-vps` — config ~/.ssh/config host name. + Nếu fail2ban lock → wait 60s retry. +4. **Build manual** khi CI runner bận: `ssh vietreport-vps 'cd C:\solution-erp ; + git pull ; dotnet publish ... ; Stop/Copy/Start pool'`. +5. **Gotcha #30 PS 5.1** — mọi .ps1 mới PHẢI ASCII-only. Grep check: + `grep -P '[\x80-\xff]' scripts/*.ps1`. +6. **PE feature-complete requires** 3 task MISSING ở STATUS §A. Designer UI là + task lớn nhất (~3-5h work). diff --git a/docs/gotchas.md b/docs/gotchas.md index e052330..420abe5 100644 --- a/docs/gotchas.md +++ b/docs/gotchas.md @@ -333,6 +333,136 @@ subdomain có ARR proxy về `:3000`. deploy Kestrel standalone qua NSSM → PHẢI apply 3 rules trên - Scripts + skill doc đã update `localhost` → `127.0.0.1` để đồng bộ +## FE routing + state (Phase 6) + +### 34. React Router NavLink `isActive` chỉ match pathname, không query string + +**Triệu chứng:** 2 NavLink cùng pathname (`/purchase-evaluations?type=2` vs +`/purchase-evaluations?type=2&pendingMe=1`) cùng highlight khi URL là một +trong 2. User thấy menu "Danh sách" + "Duyệt" active đồng thời. + +**Nguyên nhân:** React Router v6 `NavLink`'s built-in `isActive` chỉ so +pathname. `end` prop chỉ thêm exact-match cho pathname segment, không check +query string. + +**Fix:** Custom `isActive` với `queryMatches` helper (URLSearchParams set +equality). Xem `Layout.tsx` cả 2 FE: + +```tsx +function queryMatches(current: string, target: string): boolean { + const a = new URLSearchParams(current) + const b = new URLSearchParams(target) + const aKeys = [...a.keys()].sort() + const bKeys = [...b.keys()].sort() + if (aKeys.length !== bKeys.length) return false + return aKeys.every((k, i) => bKeys[i] === k && a.get(k) === b.get(k)) +} + +function MenuLeaf({ node }: { node: MenuNode }) { + const location = useLocation() + const path = resolvePath(node.key) + const [targetPath, targetQuery = ''] = path.split('?') + const isActive = location.pathname === targetPath + && queryMatches(location.search.replace(/^\?/, ''), targetQuery) + return ... +} +``` + +### 35. Menu tree inheritance phải extend khi thêm root mới + +**Triệu chứng:** Admin/role đã grant `PurchaseEvaluations.Read` (inherit parent) +nhưng menu children `Pe_DuyetNcc_List` / `Pe_DuyetNcc_Create` không hiển thị. +Chỉ thấy root `PurchaseEvaluations` ở Layout sidebar. + +**Nguyên nhân:** `GetMyMenuTreeQuery` hardcode 2 inherit root: `Contracts` và +`Workflows`. Descendant Ct_*/Wf_* auto-inherit CRUD flags từ parent qua switch +statement. Khi thêm root mới (`PurchaseEvaluations`, `PeWorkflows`) — không có +trong switch → children mặc định (false,false,false,false) → filter +`HasAccess` hide children. + +**Fix:** Extend switch + `nextInherit` propagation: + +```csharp +var contractsFlags = GetFlags(MenuKeys.Contracts); +var workflowsFlags = GetFlags(MenuKeys.Workflows); +var peFlags = GetFlags(MenuKeys.PurchaseEvaluations); // NEW +var peWorkflowsFlags = GetFlags(MenuKeys.PeWorkflows); // NEW + +// Trong BuildChildren: +if (inheritFromKey is not null && !resolved.ContainsKey(m.Key)) +{ + flags = inheritFromKey switch + { + var k when k == MenuKeys.Contracts => contractsFlags, + var k when k == MenuKeys.Workflows => workflowsFlags, + var k when k == MenuKeys.PurchaseEvaluations => peFlags, // NEW + var k when k == MenuKeys.PeWorkflows => peWorkflowsFlags, // NEW + _ => flags, + }; +} + +var nextInherit = inheritFromKey + ?? (m.Key == MenuKeys.Contracts ? MenuKeys.Contracts + : m.Key == MenuKeys.Workflows ? MenuKeys.Workflows + : m.Key == MenuKeys.PurchaseEvaluations ? MenuKeys.PurchaseEvaluations + : m.Key == MenuKeys.PeWorkflows ? MenuKeys.PeWorkflows + : null); +``` + +**Rule:** Khi thêm 1 root mới có child leaves (vd `PeWorkflows` → `PeWf_*`) — +PHẢI update cả 3 chỗ: (1) MenuKeys.All, (2) GetMyMenuTreeQuery GetFlags + switch, +(3) nextInherit propagation. + +### 36. Vite env var embed compile-time — đổi `.env.production` phải rebuild FE + +**Triệu chứng:** Đổi `VITE_API_BASE_URL=...` trong `.env.production` nhưng FE +vẫn gọi URL cũ. Hot reload không giúp. + +**Nguyên nhân:** Vite inline `import.meta.env.VITE_*` tại build time vào JS +bundle (minified). File `.env*` chỉ đọc khi `vite build` — không runtime. + +**Fix:** Sau đổi env: +1. Rebuild: `cd fe-admin ; npm run build` +2. Deploy dist mới lên IIS +3. Clear CDN/browser cache (Ctrl+Shift+R) + +Verify bundle có URL mới: `curl dist/assets/index-*.js | grep -oE 'https://[^"]+api'`. + +## Deploy / Production (continued) + +### 37. PowerShell 5.1 diacritics trong script — gotcha #30 tái phát + +**Triệu chứng (bis):** `migrate-domains.ps1` viết với "Phương Án", "→", +em-dash → PS 5.1 parser fail `Missing closing ''`, `Unexpected character`. + +**Fix:** Luôn ASCII-only cho .ps1 — rule lặp lại gotcha #30. Cách phát hiện: +grep file cho UTF-8 multi-byte chars trước khi deploy: +```bash +grep -P '[\x80-\xff]' scripts/*.ps1 +# Nếu có match → rewrite ASCII-only +``` + +## Email / Users + +### 38. Email rename Identity user — 4 field cần update đồng thời + +**Triệu chứng:** Đổi `user.Email` xong login với email mới vẫn 401. Hoặc +UserManager.FindByEmail trả null. + +**Nguyên nhân:** Identity lookup qua `NormalizedEmail` (uppercase), không +`Email`. Username cũng dùng email. 4 field phải sync: + +```csharp +u.Email = newEmail; +u.NormalizedEmail = newEmail.ToUpperInvariant(); +u.UserName = newEmail; +u.NormalizedUserName = newEmail.ToUpperInvariant(); +await userManager.UpdateAsync(u); +``` + +**Bonus:** Check conflict trước khi rename (user khác đã có email mới) → +skip để tránh duplicate. + ## Checklist debug bug mới 1. Build pass không? → fail → check using + package version compat @@ -347,3 +477,8 @@ subdomain có ARR proxy về `:3000`. 10. Nếu SignalR 401 → dùng `accessTokenFactory` + BE OnMessageReceived hook (#26) 11. Nếu PS 5.1 script fail → check encoding UTF-8 / BOM / ASCII-only (#30) 12. Nếu subdomain trả sai content / bị hijack → check IPv4/IPv6 port collision trên VPS shared (#33) +13. Nếu 2 NavLink cùng active / không đúng highlight → custom isActive match query string (#34) +14. Nếu menu item có quyền nhưng không hiện → check GetMyMenuTreeQuery inheritance extend (#35) +15. Nếu FE gọi API sai URL sau đổi env → rebuild + clear bundle cache (#36) +16. Nếu .ps1 fail parser trên PS 5.1 → ASCII-only, grep multi-byte chars (#30, #37) +17. Nếu rename email Identity vẫn 401 → update 4 field NormalizedEmail/UserName (#38)