[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
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:
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
140
docs/changelog/sessions/2026-04-24-chot-session-3-pe-polish.md
Normal file
140
docs/changelog/sessions/2026-04-24-chot-session-3-pe-polish.md
Normal 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).
|
||||
135
docs/gotchas.md
135
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 <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` 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)
|
||||
|
||||
Reference in New Issue
Block a user