Files
solution-erp/docs/changelog/sessions/2026-05-07-2359-pe-workspace-ux-overhaul.md
pqhuy1987 6e7a6db4e8 [CLAUDE] Docs+Skill: chốt Session S10-11+++++++ wrap-up — PE Workspace UX overhaul
Tổng hợp 23 commit từ `b7a153e` (post Session 9+) → `4c0625c` (last) thành
1 wrap-up entry. KHÔNG cắt narrative cũ — thêm 1 row đầu STATUS + 1 TL;DR
prepend HANDOFF + 1 block migration-todos + 1 session log mới (rule §6.5).

Files:
  ~ docs/STATUS.md
    - Last updated S10-11+++++++ wrap-up + Phase summary 16→17 mig + 5 display
      status + 8→9 phase enum (TraLai)
    + Recently Done: 1 row tổng hợp 11 batch deliverable (B1-B11) với commit
      SHA range, narrative đầy đủ context per §6.5 KEEP rule
  ~ docs/HANDOFF.md
    - Last updated + TL;DR Session S10-11+++++++ prepend với 11 batch summary
    + Stats table cumulative (BE LOC +450, Mig 17, FE pages 31→32, +5 component
      mới, +1 phase TraLai, +5 display status, 23 commit)
    + 7 cảnh báo Session 12+ (TraLai workflow transition pending, multi-phase
      filter, opinion sign Duyệt mode, UAT skip-verify exception, Workspace
      vs Danh sách vs Duyệt matrix, Mig 17 backward compat, CI deploy status)
  ~ docs/changelog/migration-todos.md
    + Session S10-11+++++++ done block với 11 task tick + commit SHA references
    + 3 defer task cho Session 12+ (TraLai workflow, multi-phase filter, opinion sign)
  + docs/changelog/sessions/2026-05-07-2359-pe-workspace-ux-overhaul.md
    Session log đầy đủ (11 batch chi tiết + bug log + docs updates checklist
    + stats cumulative + Plan organization hierarchy)
  ~ .claude/skills/ef-core-migration/SKILL.md
    - "16 migration" → "17 migration" header
    + Row 17 `AddManualBudgetFieldsToPeAndContract` table entry
    - Total: 55 bảng giữ nguyên (+4 cột không thêm bảng) + note clarification
    ~ Phase 7 pending PaymentTermFields cập nhật note (Workspace UI đã thay
      Select preset, BE schema giữ nvarchar(max), defer migration tách field)

Defer cho cron audit 2026-06-01:
  - contract-workflow/SKILL.md TraLai phase note (chờ wire workflow xong)
  - schema-diagram.md §15 Mig 17 +4 columns (small, không drift major)
  - gotchas count update (KHÔNG add vì TS strict CI fail là process issue,
    addressed via memory rule, không phải code-bug pattern)

Memory updated trước đó (commit không có vì memory ở ngoài repo):
  - feedback_uat_skip_verify.md: thêm exception "rename/remove → BẮT BUỘC
    npm run build" + lesson hotfix CI 0ae3fe2

Verify: `dotnet test` 83 pass · git log clean · branch up-to-date sau push.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:24:53 +07:00

13 KiB

Session 2026-05-07 (S10 → S11+++++++) — PE Workspace UX overhaul đầy đủ

Dev: Claude Duration: ~1 ngày (07/05 toàn ngày iterate) Base commit: b7a153e (sau Session 9+ housekeeping) Final commit: 4c0625c Total commits: 23

Bối cảnh

User chuyển sang UAT iteration mode (test live trên prod sau mỗi push). Áp rule mới feedback_uat_skip_verify (memory) — skip dotnet test + npm build sau mỗi chunk, push ngay. Lesson hotfix CI giữa session: rename/remove → BẮT BUỘC build trước commit.

Toàn session focus 1 module: PurchaseEvaluation (PE) — Module Duyệt NCC. Refactor end-to-end UX cho Drafter + Workspace mode + Display status meta + thêm phase mới.

11 batch deliverable (chi tiết)

B1 (S10) — PE Thao tác 2-panel workspace (4 commit)

User chỉ thị restructure leaf "Thao tác" Pe_*_Create từ page Create header riêng /new → workspace 2-panel mirror HĐ Thầu phụ ContractCreatePage pattern.

5 câu chốt spec trước code:

  • Q1: Panel 2 KHÔNG render Workflow/Approvals/History; Panel 1 = pure picker (no inline edit/delete)
  • Q2: Mirror HĐ Thầu phụ pattern (sticky "+ Thêm mới" + Panel 2 transition new→edit)
  • Q3: Leaf "Danh sách" + "Duyệt" GIỮ 3-panel
  • Q4: Route mới /purchase-evaluations/workspace?type={1|2}
  • Q5: Section 5 Ý kiến 4PB DISABLE trong workspace

Commits:

  • ee0d360 — fe-admin: 3 file mới (PeListPanel ~180 LOC + PeHeaderForm ~210 LOC + PurchaseEvaluationWorkspacePage ~120 LOC) + 3 sửa (PeDetailTabs add mode prop, Layout resolver, App.tsx route)
  • ecf3c59 — fe-user mirror y hệt 6 file
  • 7e3cfa5 — Docs (STATUS + HANDOFF + session log)
  • d04bd88 — Tick migration-todos

B2 (S11) — Migration 17 manual budget fields PE + HĐ (5 commit)

User feedback: Budget Select chỉ Phase=DaDuyet → user phải break flow tạo Budget approved trước. Solution: toggle "Nhập tay" + 2 input field fallback (Tên text + Số tiền number) lưu trên entity, KHÔNG cần Budget entity. Mirror logic PE ↔ HĐ.

Migration 17 AddManualBudgetFieldsToPeAndContract:

  • PurchaseEvaluations.BudgetManualName nvarchar(200) NULL
  • PurchaseEvaluations.BudgetManualAmount decimal(18,2) NULL
  • Contracts.BudgetManualName nvarchar(200) NULL
  • Contracts.BudgetManualAmount decimal(18,2) NULL

3-file rule per ef-core-migration skill. Validation Q2: cả 2 cùng null OK, KHÔNG XOR.

Commits: ecd5f7e (Domain+Infra Mig 17) → 0f7901c (App CQRS) → bab5031 (FE-Admin) → 14f8d9d (FE-User mirror) → bf17740 (Docs).

B3 (S11+) — BudgetFieldRow inline editor Section 2.b (3 commit)

Section 2 "b. Ngân sách" thay FormRow tĩnh → editable component (toggle + Select OR 2 input + Save dirty + Hủy). canEdit cho cả 3 view (Workspace/Danh sách/Duyệt mode), readOnly chỉ display. Empty state hiện "—" thay "(chưa link)" verbose.

Commits: 19712d8 (fe-admin) → d5c6f12 (fe-user mirror) → 7f38c02 (Docs).

B4 (S11++) — InfoTab inline edit Section 1 + PeListPanel pencil hover (3 commit)

Section 1 InfoTab "✎ Sửa" button → flip display↔inputs (Tên/Địa điểm/Mô tả/Payment editable, Dự án locked). PeListPanel pencil icon group-hover absolute right + URL ?editHeader=1 chain → autoEditHeader prop trigger mount-time edit.

Commits: 5a89dd2 (fe-admin) → 27b291c (fe-user mirror) → cb0598d (Docs).

B5 (S11+++) — Workspace "new" sectioned create view (1 commit)

PeWorkspaceCreateView.tsx ~230 LOC layout 5 sections giống PeDetailTabs visual. S1 + S2.b editable, S3-5 LockedHint "Lưu phiếu trước". POST trigger create. Replace PeHeaderForm trong workspace mode='new'.

Commit: 66fa469.

B6 (S11++++) — Danh sách disable toàn bộ tương tác (2 commit)

User: "Pe_*_List Danh sách disable toàn bộ tương tác, chỉ show thông tin." PurchaseEvaluationsListPage readOnly={true} hardcoded cho PeDetailTabs + readOnly={!pendingMe} cho PeWorkflowPanel (List view → ẩn Chuyển tiếp + show hint "Vào menu Duyệt"; Pending vẫn approve được).

PeWorkflowPanel thêm prop readOnly hide Chuyển tiếp section + Dialog.

Commits: 7dfeb1a (fe-admin + Pe Workflow Panel) → a1665ee (fe-user mirror).

B7 (S11+++++) — Lock Loại quy trình + payment preset Select (1 commit)

User annotation screenshot: 1) Loại quy trình lock theo URL ?type=N (vào menu nào → loại đó). 2) Điều khoản TT đổi Textarea (JSON code-style) → Select 8 preset Việt + "Khác (nhập tay)" → text input fallback.

Commit: 18ebfa1.

B8 (S11++++++) — PE Display status meta (1 commit)

PeDisplayStatus enum gom phase chi tiết thành 4-5 trạng thái UI:

  • BanNhap = DangSoanThao
  • DaGuiDuyet = bất kỳ phase trung gian (ChoPurchasing/ChoDuAn/ChoCCM/ChoCEODuyetPA/ChoCEODuyetNCC)
  • TraLai (sau khi B9 thêm phase)
  • DaDuyet = DaDuyet
  • TuChoi = TuChoi

getPeDisplayStatus() helper. Workflow timeline Panel 3 vẫn giữ phase chi tiết. Workspace forced filter Bản nháp.

Commit: 0c5db13.

B9 (S11+++++++) — Phase TraLai + pencil always visible + edit gating (1 commit)

User: "Thêm trạng thái Trả lại" + "Pencil hiện luôn, sáng khi editable, xám khi không, edit cho 2 status: Đang soạn thảo + Trả lại".

BE Domain: PurchaseEvaluationPhase enum thêm TraLai = 98 (giữa DaDuyet=7 + TuChoi=99). Comment "approver trả về Drafter sửa, vẫn cho edit, khác TuChoi".

FE:

  • Label "Trả lại" + color yellow (bg-yellow-100)
  • Display status PeDisplayStatus.TraLai separate
  • isEditablePhase(phase) helper: chỉ DangSoanThao + TraLai
  • PeListPanel pencil bỏ opacity-0 group-hover:opacity-100 → LUÔN visible
  • Color logic: editable ? text-brand-600 cursor-pointer : text-slate-300 cursor-not-allowed
  • Click guard: editable && onEditClick(p.id)
  • Workspace editableOnly prop (filter client-side cả 2 phase, BE chưa hỗ trợ multi-phase param)
  • PeDetailTabs InfoTab/BudgetFieldRow canEdit = !readOnly && isEditablePhase(ev.phase)

Commit: d15398f.

B10 (hotfix CI) — TS strict errors (1 commit)

CI run #125 + #126 fail (red Gitea Actions) do skip-verify push 2 commit B7+B8 có TS strict errors:

  • PeListPanel.tsx:41 — Property 'forcedPhase' does not exist (renamed to editableOnly ở type def nhưng quên xóa khỏi destructuring args list) → TS2304/TS2339
  • PeWorkspaceCreateView.tsx:20PurchaseEvaluationType declared but never read (sau khi đổi <Select> Loại quy trình → <Input disabled> chỉ dùng Label, không cần enum value) → TS6133

Fix: destructuring rename + bỏ unused import.

Lesson learned: UAT skip-verify áp được khi pure ADD (props/JSX/new file). Khi rename/remove → BẮT BUỘC npm run build 1 lần trước commit. Update memory feedback_uat_skip_verify.md thêm exception.

Commit: 0ae3fe2.

B11 (last) — PE detail polish + bottom action bar (1 commit)

User annotation 4 chỉnh sửa cho PE detail Section 2 + 3:

  1. a. NCC/TP được chọnNccSelectorRow component Select dropdown từ ev.suppliers (Section 3 list). Wire POST /purchase-evaluations/:id/select-winner endpoint hiện có. Disable khi suppliers empty + hint "Thêm NCC ở Section 3 trước".
  2. c. Giá chào thầu text rõ hơn: chưa chọn NCC → "(chọn NCC/TP ở (a) trước)" / quotes=0 → "(chưa nhập báo giá ở Section 4)" / quotes>0 → số tiền.
  3. Section 3 row khi isWinner (= ev.selectedSupplierId === s.supplierId) → ẩn ✏ + 🗑 buttons (chỉ giữ ✓ active emerald state).
  4. Bottom action bar workspace mode + canEditPhase + !readOnly: 2 nút "Lưu (đóng)" (= onBack, các thay đổi đã auto-save inline) + "Lưu & Gửi Duyệt →" (confirm dialog → POST /transitions với targetPhase = first nextPhase skip TuChoi/TraLai → workflow chuyển từ Bản nháp/Trả lại → Đã gửi duyệt (ChoPurchasing) → toast + onBack đóng workspace).

Commit: 4c0625c.

E2E verified

  • dotnet test SolutionErp.slnx — 83/83 pass (54 Domain + 29 Infra) — KHÔNG regression
  • dotnet build SolutionErp.slnx — 0 errors, 2 warnings (pre-existing DocxRenderer null-deref)
  • dotnet ef database update — Mig 17 applied LocalDB OK
  • npm run build fe-admin + fe-user pass (verified after hotfix 0ae3fe2)
  • Push gitea OK — sau hotfix các CI run xanh + deploy
  • 🔄 Manual UAT — defer cho user thử live (per UAT mode rule)

Bug + Fix log

# Issue Fix Commit
1 TS2304/TS2339 forcedPhase rename quên destructuring Rename + remove forcedPhase, arg 0ae3fe2
2 TS6133 PurchaseEvaluationType unused import Remove import 0ae3fe2
3 fe-user Edit chunk fail "File has not been read yet" (Tool gating) Re-read file rồi Edit lại inline (B7+)

Docs updates

  • STATUS.md — Recently Done thêm 1 row wrap-up (KHÔNG cắt narrative cũ per §6.5)
  • HANDOFF.md — TL;DR Session S10-11+++++++ prepend + 7 cảnh báo Session 12+
  • migration-todos.md — Session S10-11+++++++ block + 11 task tick
  • Session log (file này)
  • Memory: feedback_uat_skip_verify.md updated với hotfix CI lesson + exception "rename/remove → BẮT BUỘC build verify"
  • ⏸️ Skill ef-core-migration/SKILL.md — Migration 17 row sẽ add session sau (cron audit 2026-06-01)
  • ⏸️ Skill contract-workflow/SKILL.md — TraLai phase note sẽ add nếu UAT cần workflow transition
  • ⏸️ schema-diagram.md — Mig 17 +4 columns note sẽ add cron audit 2026-06-01
  • gotchas.md — KHÔNG add (TS strict CI fail là process issue, addressed via memory rule, không phải code-bug pattern)
  • rules.md — KHÔNG add (UAT skip verify là per-session preference, ở memory không phải project-wide rule)

Stats cumulative (sau wrap-up)

Trước S10 Sau S11+++++++ Diff
BE LOC ~14400 ~14850 +450
API endpoints ~133 ~133 0
Migrations 16 17 +1
DB columns mới +4 +4
FE pages 31 32 +1
FE components mới +5 (PeListPanel, PeHeaderForm, PeWorkspaceCreateView, BudgetFieldRow inline, NccSelectorRow inline) +5
PE phase enum 8 9 +1 (TraLai)
PE display status meta 5 +5 (gom phase chi tiết)
Tests 83 83 0 (UAT iter — test-after defer per §7)
Docs ~54 ~55 +1 (session log này)
Commits (after S9+) +23 +23

Plan organization sau session (xem chính ở STATUS Recently Done + migration-todos)

Plan cha: Phase 9 active — UAT
├── Plan con A: Hard blockers (chờ user/ops) — 6 task pending
│   ├── UAT thật 1 tuần với 2-3 user
│   ├── SMTP config → Email outbox
│   ├── Rotate credentials
│   ├── Schedule SQL backup daily
│   ├── Remove binding cũ .huypham.vn
│   └── win-acme scheduled task fix
├── Plan con B: PE Workspace UX overhaul ✅ DONE this session (B1-B11)
├── Plan con C: Manual budget fields ✅ DONE this session (B2)
├── Plan con D: Display status meta + TraLai phase ✅ DONE this session (B8 + B9)
├── Plan con E: Optional polish (UAT-driven) — 5 task pending
│   ├── Budget MaNganSach atomic seq
│   ├── Budget versioned workflow
│   ├── Payment terms PE tách field (đã thay Select preset workspace, BE field giữ JSON)
│   ├── Auto-map PE Details → Contract Details khi gen HĐ
│   └── Matrix Quotes bulk paste Excel
├── Plan con F: Tests Phase 3-5 — 3 sub-pending
│   ├── Phase 3 — Application handler tests ~15 test
│   ├── Phase 4 — API smoke tests ~7 test
│   └── Phase 5 — FE Vitest cho lib utility ~10 test
└── Plan con G: Defer cho Session 12+ (cần explicit UAT trigger)
    ├── Workflow transition vào TraLai (BE workflow service wire button "Trả lại")
    ├── BE multi-phase filter param (cho display status "Đã gửi duyệt" precision)
    └── Section 5 Opinion sign trong Duyệt mode (verify nếu UAT cần)

Handoff

UAT iteration mode active. User test live + báo lại nếu cần điều chỉnh. Phase 9 còn lại = Hard blockers chờ user/ops + Optional polish UAT-driven.

Cron audit kế: 2026-06-01 (~25 ngày). Lúc đó sẽ:

  • Run combined skill + doc drift audit theo §6.4 + §9.4
  • Update ef-core-migration/SKILL.md Migration 17 row + total tests
  • Update contract-workflow/SKILL.md TraLai phase note (nếu wire workflow xong)
  • Update schema-diagram.md §15 Mig 17 +4 columns
  • Update gotchas count (nếu phát sinh thêm)