[CLAUDE] Docs: chot session 3 — PE polish iter 2 + domain rebrand + 5 gotcha moi
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m55s

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.
This commit is contained in:
pqhuy1987
2026-04-25 00:37:30 +07:00
parent a336997cfe
commit e65578a821
6 changed files with 348 additions and 46 deletions

View File

@ -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)

View File

@ -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_<code>`, có thể cần extend cover `Pe_<code>`).
### C. Edge case chưa test

View File

@ -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).

View File

@ -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 <NavLink to={path} className={isActive ? 'active' : ''}>...</NavLink>
}
```
### 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`
`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)