Files
solution-erp/docs/HANDOFF.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

502 lines
36 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# HANDOFF — Brief 5 phút cho session tiếp theo
**Last updated:** 2026-05-07 23:59 (Session S10-11+++++++ wrap-up — **PE Workspace UX overhaul đầy đủ. 23 commit. 83 test pass. UAT iteration mode active từ S11.**)
## TL;DR Session S10-11+++++++ (07/05 — PE Workspace UX overhaul đầy đủ)
User UAT live mode iterate liên tục. Áp rule [`feedback_uat_skip_verify`](../../../../Users/pqhuy/.claude/projects/D--Dropbox-CONG-VIEC-SOLUTION/memory/feedback_uat_skip_verify.md) skip dotnet test sau mỗi chunk, push ngay. Lesson hotfix CI `0ae3fe2`: rename/remove → BẮT BUỘC `npm run build` trước commit.
**11 batch deliverable** (23 commit total — xem STATUS Recently Done row đầu tiên cho narrative đầy đủ):
- **B1** PE Thao tác 2-panel workspace (S10)
- **B2** Migration 17 manual budget fields PE + HĐ (S11)
- **B3** BudgetFieldRow inline editor Section 2.b
- **B4** InfoTab inline edit Section 1 + PeListPanel pencil hover
- **B5** Workspace "new" sectioned create view 5 sections
- **B6** Danh sách view disable toàn bộ tương tác
- **B7** Workspace "new" lock Loại quy trình + payment preset Select
- **B8** PE display status meta (Bản nháp / Đã gửi duyệt / Trả lại / Đã duyệt / Từ chối)
- **B9** Phase TraLai = 98 + pencil always visible + edit gating
- **B10** Hotfix CI TS errors (forcedPhase rename + unused import)
- **B11** PE detail polish — NCC selector dropdown + Section 3 winner protect + Bottom action bar Lưu/Gửi Duyệt
## Stats sau wrap-up
| | Trước S10 | Sau S11+++++++ |
|---|---:|---:|
| BE LOC | ~14400 | ~14850 (+450 — Mig 17 + Domain TraLai + App CQRS) |
| Migrations | 16 | **17** (+1 Mig 17) |
| DB columns mới | — | +4 (PE+HĐ × Name+Amount manual budget) |
| FE pages | 31 | **32** (+1 Workspace 2-panel) |
| FE components mới | — | +5 (PeListPanel, PeHeaderForm, PeWorkspaceCreateView, BudgetFieldRow, NccSelectorRow inline) |
| PE phase enum | 8 | **9** (+TraLai = 98) |
| PE display status | — | **5** (gom phase chi tiết) |
| Tests | 83 | 83 (no test added — UAT iteration, áp rule §7 test-after defer) |
| Commits S10-S11+++++++ | — | **+23** |
## ⚠️ CẢNH BÁO Session 12+
1. **Workflow transition vào TraLai** — Domain enum đã có (98), FE label/color/badge sẵn. NHƯNG chưa wire button "← Trả lại" trong PeWorkflowPanel approver view + workflow service BE chưa transition logic vào TraLai. Khi UAT cần → thêm: button "Trả lại" trong Chuyển tiếp (hoặc Reject Dialog), workflow rule `Decision=3 (TraLai)` set phase=TraLai + ghi `RejectedFromPhase`. FE đã ready accept hiển thị TraLai phase.
2. **"Đã gửi duyệt" multi-phase filter** — display status "Đã gửi duyệt" gom 5 phase trung gian (ChoPurchasing/ChoDuAn/ChoCCM/ChoCEODuyetPA/ChoCEODuyetNCC). BE chưa hỗ trợ multi-phase param trong list endpoint → FE filter dropdown ẩn option này (chỉ exact-match Bản nháp/Đã duyệt/Từ chối). TODO: BE thêm `?phases=2,3,4,5,6` query param hoặc derive `displayStatus` field.
3. **`feedback_uat_skip_verify` exception** — khi commit có **rename/remove**, BẮT BUỘC `npm run build` 1 lần trước push (lesson hotfix `0ae3fe2`). Chỉ skip verify khi pure ADD (props, JSX, new file).
4. **Workspace + Danh sách + Duyệt** matrix:
- Workspace (Pe_*_Create): 2-panel, Section 5 disabled, edit only Bản nháp+Trả lại, pencil bright/disabled, bottom bar 2 nút Lưu/Gửi Duyệt
- Danh sách (Pe_*_List): 3-panel, **readOnly=true** toàn bộ (no edit/transition)
- Duyệt (Pe_*_Pending): 3-panel, PeDetailTabs readOnly + PeWorkflowPanel có Chuyển tiếp + Section 5 nhập opinion (chỗ này hiện vẫn disabled do code path cũ — verify nếu UAT user cần sign opinions ở đây)
5. **Mig 17 columns nullable** — backward compat OK. Cả 2 (BudgetId + manual fields) cùng null acceptable. Validation BE chưa XOR.
6. **CreateContractFromEvaluation carry-forward** manual fields PE→HĐ — đã wire. Verify UAT.
7. **CI deploy status** — sau hotfix `0ae3fe2` các run từ commit `4c0625c` trở đi sẽ xanh + deploy. User UAT live trên prod ngay sau push.
## TL;DR Session 11++ housekeeping (07/05 — InfoTab inline edit + pencil hover)
User feedback after BudgetFieldRow: muốn thêm nút edit kế bên row trong Panel 1 list, click sáng nội dung Section 1 lên cho sửa header inline.
-**InfoTab inline edit** — display mode + button "✎ Sửa" góc phải Section 1. Editing mode: card border brand-200 + 4 input (Tên / Dự án locked / Địa điểm / Mô tả / Payment) + Save (PUT /pe/:id) / Hủy.
-**PeListPanel pencil hover** — icon absolute right-2 top-2 mỗi row, group-hover opacity-100. Click → callback onEditClick(id).
-**URL flag `?editHeader=1`** — set bởi pencil click → autoEditHeader prop chain xuống PeDetailTabs → InfoTab tự open editing mode mount-time.
-**fe-admin** Chunk 1 (`5a89dd2`) · **fe-user mirror** Chunk 2 (this).
**Defer (chưa làm):** Refactor workspace "new" mode wrap PeHeaderForm trong sectioned layout giống detail view (5 sections visible). PeHeaderForm hiện tại single-card đủ dùng — chỉ làm thêm khi user feedback rõ.
## TL;DR Session 11+ housekeeping (07/05 — inline budget editor)
User feedback after Session 11: muốn toggle + 2 fields hiển thị trực tiếp trong Section 2 "b. Ngân sách" của PeDetailTabs, không chỉ ở "Sửa header" page. Empty values cứ empty.
-**BudgetFieldRow component** (~125 LOC) thay FormRow tĩnh cũ ở `b. Ngân sách`. canEdit=`!readOnly && isDraft`. Save dùng existing PUT endpoint (KHÔNG cần BE thay đổi).
-**fe-admin** Chunk 1 (commit `19712d8`) · **fe-user mirror** Chunk 2 (commit `d5c6f12`).
-**Verify**: 2 build pass + 0 TS error.
UX:
- **Workspace + Danh sách + isDraft** → editable inline: toggle + Select OR 2 input + nút Lưu khi dirty
- **Duyệt + !isDraft** → display only (link card / manual values / "—" empty)
- **Empty state**: hiển thị "—" thay vì "(chưa link)" verbose (per user)
## TL;DR Session 11 (07/05 — Migration 17 manual budget fields)
**Output session 11** — UX improvement cho user nhập ngân sách không cần Budget entity approved:
-**Migration 17** `AddManualBudgetFieldsToPeAndContract` — 4 ALTER (PE + HĐ × BudgetManualName nvarchar(200) + BudgetManualAmount decimal(18,2)). Applied LocalDB OK. Mirror logic PE ↔ HĐ (Q3 user chốt).
-**BE** Domain 2 entity (PE + Contract) +2 property + EF config HasMaxLength/HasPrecision. App CQRS Create/Update commands + DTO + Validator + diff log + carry-forward CreateContractFromEvaluation pe→contract.
-**FE** Toggle checkbox "Nhập tay (không link)" cạnh Label Ngân sách trong 4 chỗ: PeHeaderForm (workspace + /new page wrap), ContractCreatePage NewForm + EditForm. Khi ON: hide Select, show 2 input field grid 2-col (Tên + Số tiền formatted VND). Khi OFF (default): Select Budget approved cũ. Auto-detect manual mode khi load existing có manual data + !budgetId. Display fallback ở PeDetailTabs Section 1 "b. Ngân sách" + Contract EditForm read-only branch.
-**5 chunk per-commit** (build + 83 test pass mỗi chunk): C1 Domain+Infra Migration 17 (`ecd5f7e`) · C2 App CQRS (`0f7901c`) · C3 FE-Admin (`bab5031`) · C4 FE-User mirror (`14f8d9d`) · C5 Docs (current).
**Validation Q2 chốt:** cả BudgetId + manual fields có thể cùng null (PE/HĐ chưa có ngân sách gì). KHÔNG XOR enforce — BE prefer link nếu có (Phase=DaDuyet guarantee), manual fallback only.
**KHÔNG đụng:** Budget entity / Phase=DaDuyet validation (giữ invariant "PE/HĐ link Budget approved only"). Manual fields chỉ là note/display, KHÔNG join với Budget.Details cho per-row comparison ở PE matrix Section 4 (cột "So với ngân sách" vẫn require ev.budgetId — không có detail rows để compare).
## ⚠️ CẢNH BÁO session tiếp (Session 12+)
1. **UAT manual budget flow** — toggle ON/OFF + save + reload + verify auto-detect mode. Đặc biệt edit existing PE/HĐ có manual data → toggle phải auto-checked. Edit existing có Budget link → toggle auto-unchecked.
2. **Section 4 PE matrix "So với ngân sách"** vẫn require Budget link — manual amount KHÔNG render comparison column. Document giới hạn này nếu UAT thắc mắc.
3. **`docs/database/schema-diagram.md`** chưa cập nhật count 16→17 migration + 4 column mới. Defer cho audit định kỳ 2026-06-01 (per §6.4 cron) — nhỏ enough không phải selective rewrite.
4. **CreateContractFromEvaluation** đã carry forward manual fields PE→Contract. Verify khi UAT: PE có manual budget → tạo HĐ từ phiếu → HĐ inherit luôn.
5. **No new test added** (rule §7 — feature mới = test-after, soak UAT 2-3 tuần ổn → viết happy path).
6. **Schema fields nullable** — không phá HĐ/PE cũ (legacy null OK). Backward compatible.
## TL;DR Session 10 (07/05 — PE workspace 2-panel)
**Output session 10** — restructure leaf "Thao tác" PE từ page Create header riêng sang workspace 2-panel mirror HĐ Thầu phụ pattern:
-**Spec chốt 5 câu trước code** — Q1 Panel 2 chỉ data entry (KHÔNG Workflow/Approvals/History); Panel 1 pure picker (no inline edit/delete); Q2 mirror HĐ Thầu phụ (sticky "+ Thêm mới" + new→edit Panel 2); Q3 leaf "Danh sách" + "Duyệt" giữ 3-panel hiện tại; Q4 route mới `/workspace`; Q5 Section 5 Ý kiến 4PB disable trong workspace (nhập khi duyệt).
-**Chunk 1 fe-admin** (commit `ee0d360`) — 3 file mới: `PeListPanel.tsx` (~180 LOC pure picker reuse-able + sticky "+ Thêm mới"), `PeHeaderForm.tsx` (~210 LOC extract header form từ CreatePage), `PurchaseEvaluationWorkspacePage.tsx` (~120 LOC 2-panel `[320px_1fr]`). 3 file sửa: `PeDetailTabs.tsx` thêm prop `mode?: 'detail' \| 'workspace'` + Section 5 hint amber khi workspace + force `opinionsReadOnly`. `Layout.tsx` resolver `Pe_*_Create``/workspace?type=N`. `App.tsx` route mới.
-**Chunk 2 fe-user mirror** (commit `ecf3c59`) — 6 file y hệt content (rule §3.9 duplicate có chủ đích).
-**Verify**: 2 build pass + dotnet test 83 vẫn pass mỗi chunk.
**KHÔNG đụng BE / migration / schema / endpoint.** Route `/new` cũ giữ tồn tại cho deep-link "Sửa header" button.
## ⚠️ CẢNH BÁO session tiếp (Session 11+)
1. **UAT live workspace** với anh Kiệt + 2-3 user — feature mới UX khác (page Create cũ thành Dialog implicit qua sticky button + transition new→edit auto).
2. **Section 5 Ý kiến 4PB hint banner amber** ở workspace mode chỉ là text gợi ý — KHÔNG block. User vẫn thấy existing opinions read-only. Nếu UAT thấy confused → có thể đổi thành collapsible section.
3. **Mobile: workspace KHÔNG có fallback** — màn hình `<lg` (< 1024px) Panel 2 ẩn (lg:block). Cần test mobile redirect `/purchase-evaluations/:id` nếu UAT phát hiện. Hiện chỉ admin desktop dùng workspace.
4. **Pe_*_Pending vẫn /purchase-evaluations?pendingMe=1** leaf "Duyệt" 3-panel (giữ Panel 3 Workflow + readOnly Section 5 cho phép sign). UAT verify Drafter trình TPB duyệt thấy Section 5 enable đúng.
5. **PE WorkflowPanel duplicate ở 2 chỗ** leaf "Danh sách" + "Duyệt" Panel 3 (3-panel). KHÔNG "Thao tác" workspace. Verify route resolver active state highlight đúng (queryMatches helper từ session 3).
6. **Sửa header trong workspace** vẫn navigate sang `/new?id=` (button "Sửa header" trong PeDetailTabs). Chưa wire inline edit qua Dialog. Nếu UAT yêu cầu thêm prop `onEditHeader` cho PeDetailTabs trigger Dialog reuse `PeHeaderForm`.
## Housekeeping today (sau Session 9)
- **Audit định kỳ 2026-05** combined skill + doc drift (commit `7dc0233`). 5 drift patch (count 7783 + 5255 bảng), 1 skill content patch (contract-workflow Phase 9 cross-ref). KHÔNG tạo skill mới. Log `docs/changelog/skill-audit-2026-05.md`.
- **Optional polish — fe-user Inbox PE section** (commit `332a90f`). useQuery `/purchase-evaluations/inbox` + Panel 1 chia 2 section sticky header ( + PE). PE click navigate page riêng.
- **User Manual 7 file rewrite compact** (commit `16c2c9c`). User feedback "ko cần quá đầy đủ chi tiết, cho end-user họ làm". Bỏ field validation table + error troubleshoot table + FAQ chi tiết. Giữ tổng quan ngắn + numbered steps đơn giản. ~86 KB / 7 file ( ~123 KB 30%). Setup `package.json` + `npm install docx@9.5.0` + `npm run gen:all`. Lần sau sửa: edit `_gen-*.js` run gen:all.
**Cron audit định kỳ:** Claude SDK CronCreate auto-expire 7 days KHÔNG fit monthly cadence. User cần setup OS Task Scheduler `.bat` script ping API hoặc manual trigger mỗi đầu tháng. Lần kế: 2026-06-01.
**User Manual style rule (mới chốt session này):** end-user docs BỎ field/error tables, FAQ chi tiết, phím tắt GIỮ tổng quan ngắn + numbered steps + note/warn/tip critical. Phân biệt với rule §6.5 (KHÔNG cắt narrative) đây rule cho audience end-user, không phải agent dev đọc rationale.
## TL;DR Session 9 (04/05 — Chunk E-bis sau Session 8)
**Output session 9** đóng tất cả Chunk E-bis defer từ session 8:
- **FE PE WorkflowPanel** Section "Tiến trình duyệt 2-cấp phòng ban" group by phase × dept, highlight amber chờ TPB confirm, badge fuchsia bypass (cả fe-admin + fe-user).
- **FE UsersPage UserManager** Column "Bypass" + button ShieldCheck toggle CanBypassReview, badge fuchsia khi enabled. UserDto thêm field.
- **HĐ 2-stage logic** `ContractWorkflowService` thêm UserManager DI + mirror logic từ PE service. `ContractDepartmentApprovalFeatures.cs` List query. Endpoint `GET /contracts/{id}/department-approvals`. FE `WorkflowHistoryPanel` section mới.
- **Budget 2-stage logic** `TransitionBudgetCommandHandler` thêm INotificationService + IDateTime DI + 2-stage. `BudgetDepartmentApprovalFeatures.cs` + endpoint + FE `BudgetWorkflowPanel` section.
- **6 test PE 2-stage** `IdentityFixture` setup full Identity stack (DbContext SQLite + AddIdentityCore + AddRoles<Role>) reusable. 6 scenario: NV_Review_Blocks / TPB_Confirm_Allows / NV_Bypass / Admin_Skip / Reject_Sets / Resume_Jumps_Back.
-**Verify**: Build pass + 83 test pass mỗi commit (54 Domain + 29 Infra: 17 codegen + 6 PE WF Application + 6 PE 2-stage).
-**5 commit pushed** Gitea (E2 → E6).
## ⚠️ CẢNH BÁO session tiếp (Session 10+)
1. **UAT live ngay** với anh Kiệt + 2-3 user — feature 2-stage đầy đủ cả 3 module + UX.
2. **Tests Contract + Budget 2-stage skipped** — logic identical PE (cùng pattern, cùng entity shape). Pattern `PeTwoStageApprovalTests` reusable nếu UAT phát hiện regression riêng.
3. **Bypass toggle audit** — chưa log Changelog khi admin toggle CanBypassReview. Audit qua Identity standard column UpdatedAt only. Có thể cần thêm audit row riêng nếu UAT yêu cầu.
4. **Notify TPB cùng dept** dùng `UserManager.GetRolesAsync` filter `DeptManager` — verify production có user role DeptManager đúng (data already seeded).
5. **fe-user KHÔNG có UsersPage** — admin-only function. Bypass toggle chỉ ở fe-admin.
6. **3 endpoint mới List dept-approvals** PE/HĐ/Budget cùng pattern, reuse policy authz `*Read`.
7. **Cron audit định kỳ 2026-05-01** vẫn EMPTY (`No scheduled jobs`). Có thể recreate khi user yêu cầu.
## TL;DR Session 8 (04/05 — code lớn, 5 commit per-chunk)
## TL;DR Session 8 (04/05 — code lớn, 5 commit per-chunk)
**Output session 8** — đóng bug anh Kiệt + thêm 3 ràng buộc workflow:
-**Migration 16** `AddTwoStageDeptApprovalAndSmartReject` — 4 ALTER (3 RejectedFromPhase int + Users.CanBypassReview bit) + 3 CREATE TABLE (`Contract/PE/Budget DepartmentApprovals` UNIQUE (TargetId, Phase, Dept, Stage)) + 12 indexes.
-**Lock edit** 17 handler thêm guard Phase != DangSoanThao (Contract Detail × 15 qua helper, PE Detail × 5 qua helper mới, Budget Detail × 3 inline).
-**Smart reject + Resume** 3 module — Reject = lưu phase nguồn + force về DangSoanThao. Resume = jump straight tới phase đã reject (skip phase trung gian, bypass policy guard).
-**PE 2-stage logic** trong `PurchaseEvaluationWorkflowService` — TPB/CanBypass → Confirm; NV → Review only, BLOCK transition cho đến khi TPB confirm.
-**3 endpoint mới**: `GET /pe/{id}/department-approvals` (List), `PATCH /users/{id}/bypass-review` (toggle), Notify TPB cùng dept khi NV review.
-**Verify**: Build + 77 test pass mỗi commit. Migration applied LocalDB OK. Schema verified.
-**6 commit pushed** (2 docs S7 + 5 code S8).
## ⚠️ CẢNH BÁO session tiếp (Session 9+)
1. **Bug fix anh Kiệt** chỉ áp PE workflow. **HĐ + Budget 2-stage scope DEFER** cho khi UAT PE OK.
2. **FE Workflow Panel chưa update** — workflow vẫn block đúng (BE), nhưng UX chưa hiển thị 2-stage progress. User test sẽ thấy phase không đổi mà không hiểu tại sao "stuck". Phải UAT với hint cho user trước khi code FE.
3. **FE UserManager toggle CanBypassReview chưa làm** — tạm thời SET qua HTTP PATCH:
```
PATCH /api/users/{userId}/bypass-review
Authorization: Bearer <admin>
{ "canBypassReview": true }
```
4. **Test thực tế bug fix flow**:
- Login `phuong.nguyen` (NV.PRO, role=Procurement, DeptId=PRO) tạo phiếu PE type A
- Trình DangSoanThao → ChoPurchasing
- phuong.nguyen click Duyệt phase ChoPurchasing → expect: phase KHÔNG đổi, có row Stage=Review
- `tra.bui` (TPB.PRO, role=DeptManager) click Duyệt → expect: phase chuyển ChoCCM
5. **Notify TPB cùng dept** dùng `UserManager.GetRolesAsync` filter `DeptManager`. Best effort, fail OK.
6. **Cron audit định kỳ 2026-05-01** đã quá hạn 3 ngày, vẫn EMPTY runtime. Cần manual trigger.
7. **Smart reject test**: Reject phase ChoCCM → DangSoanThao + RejectedFromPhase=ChoCCM. Drafter sửa Detail + trình lại → jump straight tới ChoCCM (skip ChoPurchasing).
8. **Lock edit test**: HĐ ở Phase=DangGopY → cố sửa Detail → expect 409 Conflict "đã trình duyệt, không thể chỉnh sửa".
## TL;DR Session 6 (30/04 — không code, chỉ docs)
**Output session 6** — pure docs work, không thay đổi code/test:
- ✅ **Compact 3 file core**: STATUS -27%, HANDOFF -32%, migration-todos -35% (-288 dòng tổng). Archive 51 row Recently Done Phase 0-7 → `changelog/recently-done-archive-2026-04.md`.
- ✅ **Refresh 3 skill stale**: `form-engine` (Phase 2 MVP → Tier 3 feature-complete), `permission-matrix` (12 menu → ~60 + inheritance roots), `ef-core-migration` (24 DbSet → 52 bảng).
- ✅ **Rule mới §7 Timing test**: 1 bảng 5-row compact — feature mới = test-after, bug = test-before, critical algorithm = test-before, spec change = update test cũ, skip 5 loại.
- ✅ **Rule mới §6.4 Audit + compact MD định kỳ**: cadence + checklist + anti-pattern. Cross-ref §9.4 skill audit. KHÔNG rewrite toàn bộ.
- ✅ **77 test vẫn pass** (Domain 54 + Infra 23). 0 thay đổi code.
- ✅ **Cron 2026-05-01 fire mai** — combined audit (skill + doc drift) theo §6.4 + §9.4.
**Session 5 (29/04)** đóng gần hết feature gap + bật test gate:
### 🎯 Headline outcomes
- ✅ **Budget feature-complete** — FE 3-panel pages cả 2 app, BE đã sẵn từ session 4
- ✅ **PE/HD ↔ Budget integration** — form select Budget filter Phase=DaDuyet + Project, cột "So với ngân sách" ở PE matrix với delta indicator
- ✅ **PE Detail UI restructure** match form chính thức PHIẾU TRÌNH KÝ (4 section đánh số)
- ✅ **PE Workflow Designer admin UI** `/system/pe-workflows/:typeCode` versioned với clone/edit/+Role/+User
- ✅ **Ý kiến 4 phòng ban** — migration 15 + section sign-off 2x2 grid (Phê duyệt/CCM/MuaHàng/SM-PM)
- ✅ **Tests Phase 1-2** — 71 unit test pass + CI gate fail-fast (Domain policy + Infra code generator)
**Session 4 (28/04)** đã có:
### A. Module Ngân sách (Budget) BE — migration 14, +4 bảng, +11 endpoint
- 4 entity: `Budget` (Header) + `BudgetDetail` (flat row) + `BudgetApproval` (history) + `BudgetChangelog` (audit log).
- Enum `BudgetPhase` 5 state (DangSoanThao→ChoCCM→ChoCEO→DaDuyet + TuChoi).
- `BudgetPolicy.Default` hardcoded simple 3-step (Drafter→CCM→CEO) — chưa versioned (TODO khi user cần admin config UI).
- Mã `NS-YYYYMM-XXXX` Random.Shared (chưa atomic — TODO khi format chính thức).
- Link nullable: `Contract.BudgetId?` + `PE.BudgetId?` đã có FK + index, FE chưa wire form.
- Menu seed `Budgets` root + 3 leaf (Bg_List/Bg_Create/Bg_Pending) order=27 icon Wallet.
- Application: 11 CQRS handler ~340 LOC (Create/UpdateDraft/Transition/List/GetDetail/Delete + Detail CRUD auto-recompute TongNganSach + ListChangelogs).
- Api: `BudgetsController` 11 endpoint REST.
- **FE chưa làm — Priority 0 session 5.**
### B. 14 demo user Solutions thật
- PRO 5 (TPB tra.bui + 4 NV) + CCM 7 (TPB ngocanh.huynh + 6 NV) + ISO 1 (chau.le) + CEO 1 (huy.duong).
- Pwd `User@123456`. Reconcile pattern (gotcha #38 4-field rename).
- Tổng 30 user (16 sample cũ giữ + 14 Solutions thật mới).
**Tổng cumulative:** 52 DB tables, ~128 endpoints, 15 migrations, **41 gotchas (+3 CI fixes)**,
**77 unit test (+6 PE WF Application)**, 11+ commit session 5 push lên Gitea.
### 🆕 CI/CD optimize (29/04 tối)
- ✅ **Manual checkout bypass github.com** — fix #108/#109 transient TCP timeout 21s. Run #110 pass.
- ✅ **Path filter docs-only skip** — `paths-ignore` trong on:push, commit MD-only KHÔNG trigger CI (verify `512880c` → no run #113).
- ⏸️ **npm junction cache** — thử ở #111 fail `tsc not found`, rollback. Cần debug session sau (gotcha #40 doc rồi).
- ✅ **Tests Phase 3 mini (PE Workflow Designer)** — 6 test versioning logic. Total 77.
## ⚠️ CẢNH BÁO session tiếp (Session 7+)
1. **CI test gate active** — code → `dotnet test SolutionErp.slnx` local → commit → push. Test fail = NO deploy. Workflow user §7 rules.md.
2. **Timing test rule live (§7)**: feature mới = test-after, bug = test-before BẮT BUỘC, critical algorithm = test-before merge, spec change = update test cũ + code chung commit.
3. **Doc audit cadence live (§6.4)**: cuối phase compact, đầu tháng cron audit, KHÔNG rewrite toàn bộ. Cron fire **mai (2026-05-01)** — combined skill + doc drift theo checklist.
4. **Login email** `admin@solutionerp.local` / `Admin@123456` — domain default chưa đổi sang `@solutions.com.vn` (chỉ demo user rebrand).
5. **Chưa xóa binding cũ `.huypham.vn`** — vẫn fallback. Sau verify stable → `.\migrate-domains.ps1 -RemoveOld -SkipCert` trên VPS.
6. **win-acme scheduled task "unhealthy"** — fix trước cert expire 2026-06-18.
7. **Export phiếu PDF/Excel PE** — pending vô thời hạn (user nói không quan trọng).
8. **3 feature mới chưa test** (PE Opinion Upsert / Budget validate / Contract BudgetId carry) — đợi UAT phát sinh bug → áp rule §7 (regression test before fix). Hoặc soak 2-3 tuần ổn → viết happy path.
9. **G-084:** VPS shared VietReport — mọi reverse proxy mới phải `127.0.0.1` + bind loopback IPv4 explicit.
## ⭐ Skills (.claude/skills/) — PHẢI dùng khi task khớp
| Domain (3) | Ops (3) |
|---|---|
| `contract-workflow` — state machine + versioned WF | `dependency-audit-erp` — npm/dotnet CVE scan |
| `form-engine` — render docx/xlsx + PDF | `ef-core-migration` — EF migration + 3-file rule |
| `permission-matrix` — role × menu × CRUD | `iis-deploy-runbook` — 3 site IIS + win-acme + runner |
**Audit cron:** `0 9 1 * *` (9:00 AM ngày 1 mỗi tháng). Workflow: `docs/rules.md §9.4`. Lần kế: **2026-05-01**.
**Quy tắc:** KHÔNG bulk-clone repo skill 3rd party. Chỉ skill PROJECT-SPECIFIC. Đầy đủ: `docs/rules.md §9`.
## Ở đâu rồi?
| Phase | Trạng thái |
|---|---|
| 0 Draft | ✅ Done |
| 1 Alpha Core (foundation + đợt 2 CRUD + Permission) | ✅ Done |
| 2 Form Engine MVP + iter 2 (upload UI + .doc auto-convert + PDF export) | ✅ Done |
| 3 Workflow MVP (9 phase + code gen) + iter 2 (SLA job + attachment + notify) | ✅ Done |
| 4 Report MVP (Dashboard + Excel) + user-specific dashboard | ✅ Done |
| 5 Prep + 5.1 Security + Users Mgmt | ✅ Done |
| **5 Deploy prod** (3 domain HTTPS live) | ✅ Done |
| **Tier 3 (Attach + Realtime + Form builder + PDF + Versioned WF + Nested menu + Permission 3-panel)** | ✅ Done |
| **Skill governance** (6 skill project-level + audit cron 1/tháng) | ✅ Done |
| **3-panel List/Inbox/Thao tác + sidebar accordion + UserDashboard** | ✅ Done |
| **4-bảng data model** (Header + 7 Details + Workflow + Changelog audit) | ✅ Done |
| **Mã HĐ gen tại Create + backfill legacy** | ✅ Done |
| **4 master catalogs** (Units/Materials/Services/WorkItems) + datalist autocomplete | ✅ Done |
| **Roles VN labels (ShortName)** + Users dept/position + 13 demo users | ✅ Done |
| **RolesPage CRUD** `/system/roles` + custom role admin | ✅ Done |
| **7 demo HĐ varied phases** + details + comments + approvals workflow | ✅ Done |
| **User-kind approver runtime guard** + Warning 20% SLA | ✅ Done |
| **Edit detail row inline** (7 typed Update commands + EditRowDialog) | ✅ Done |
| **Master expand 15 NCC + 8 Project** + backfill demo HĐ diverse | ✅ Done |
| **Deps audit script** (`scripts/deps-audit.ps1`) | ✅ Done |
| **Module Duyệt NCC (tiền-HĐ) E2E** — 10 bảng + 2 workflow + Kế thừa HĐ | ✅ Done |
| **PE polish iter 2** — flat layout + per-NCC attachments + readOnly Duyệt + email rebrand | ✅ Done |
| **Domain rebrand huypham.vn → solutions.com.vn** — 3 subdomain + cert + CORS + FE bundle | ✅ Done |
| **Module Ngân sách BE + 30 user** — 4 bảng + 11 endpoint + workflow simple | ✅ Done (S4) |
| **Module Ngân sách FE** — 3-panel pages + Detail tabs + Workflow Panel cả 2 app | ✅ Done (S5) |
| **PE/Contract → Budget integration** — form Select + cột "So với ngân sách" PE matrix | ✅ Done (S5) |
| **PE Workflow designer admin UI** `/system/pe-workflows/:typeCode` | ✅ Done (S5) |
| **Ý kiến 4 phòng ban PE** — migration 15 + section sign-off 2x2 grid | ✅ Done (S5) |
| **Tests Phase 1-2 + CI gate** — 71 test (Domain policy + Infra code generator) | ✅ Done (S5) |
| **CI manual checkout bypass github.com + Path filter docs-only skip** | ✅ Done (S5) |
| **Tests Phase 3 mini** — 6 test PE Workflow Designer versioning (total 77) | ✅ Done (S5) |
| **Export phiếu PDF/Excel PE** — `IDocumentConverter` + template | 📝 Pending (không quan trọng) |
| **Tests Phase 3 full** — Application handlers (UpsertOpinion + Budget link validation, cần UserManager setup) | 📝 Pending |
| **Tests Phase 4-5** — API smoke + FE Vitest | 📝 Pending (làm khi cần) |
| **npm cache CI optimize** (debug junction Move-Item issue #40) | 📝 Pending |
| 9+ Post-launch (E-signature, Bravo/SAP, Mobile, AI) | 📝 Future |
## Run nhanh
```powershell
# Terminal 1 — API (auto seed 12 role + 9 dept + 5 supplier + 3 project + 8 template + 7 workflow definition + 28 ContractType menu + 7 workflow menu)
dotnet run --project src\Backend\SolutionErp.Api
# Terminal 2 — Admin FE
cd fe-admin && npm run dev # → http://localhost:8082
# Terminal 3 — User FE
cd fe-user && npm run dev # → http://localhost:8080
```
Login: `admin@solutionerp.local` / `Admin@123456`
## Quick sanity-check
**Admin (:8082):**
- `/dashboard` → "Của tôi" row 4 card + KPI cards + charts
- `/contracts` → list toàn bộ, filter phase/supplier/project
- `/contracts/new?type=5` → tạo HĐ Mua bán, pre-select type từ URL
- `/contracts/{id}` → timeline + action dialog + attachments drag-drop + WorkflowSummaryCard
- `/system/workflows` → 7-card landing (Thầu phụ/Giao khoán/NCC/Dịch vụ/Mua bán/NguyenTacNcc/NguyenTacDv)
- `/system/workflows/MuaBan` → DefinitionCard active + history + "Tạo phiên bản mới" modal với Steps + Approvers (+Role / +User)
- `/system/permissions` → 3-panel layout (Role list | Menu×CRUD matrix | Granted stats)
- `/system/users` → Users CRUD + assign roles
- `/forms` → upload .docx/.xlsx + render dialog Form↔JSON + Tải PDF
**User (:8080):**
- `/inbox?type=5` → HĐ Mua bán chờ role mình
- `/my-contracts?type=2` → HĐ Thầu phụ của tôi
- `/contracts/new?type=3` → tạo HĐ NCC
- Sidebar nested: 📄 Hợp đồng → expand 7 type → expand "HĐ Mua bán" → Danh sách / Thao tác / Duyệt
**Realtime check:**
- Login 2 tab (admin + user) → user tạo comment / transition → admin nhận toast + bell +1
## Cần làm kế tiếp
### 🔥 Priority 0 — Session 6 (Ops + UAT focus)
Đa số feature gap đã đóng. Còn lại chủ yếu Ops/UAT + optional polish.
**A. Hard blockers (chờ user / ops):**
1. **UAT thật 1 tuần với 2-3 user** — Drafter (QS/NV.PB) + CCM + BOD ghi bug/friction
2. **SMTP config** → bật Email outbox (BLOCKED chờ user cấp host/user/pass)
3. **Rotate credentials** — admin + 30 demo + SA + vrapp + JWT secret
4. **Schedule SQL backup daily** — `scripts/backup-sql.ps1` chưa schedule Task Scheduler
**B. PE feature gap còn lại:**
- **Export phiếu PDF/Excel** PE — pending (user nói không quan trọng lắm). Khi cần: tái dùng `IDocumentConverter` + template `PE-TrinhDuyet.docx`.
**C. Optional polish (làm khi UAT phát sinh):**
- Budget MaNganSach atomic sequence — chốt format → migration `AddBudgetCodeSequences` mirror Contract/PE
- Budget versioned workflow — admin config UI thay hardcoded `BudgetPolicy.Default`
- Payment terms PE tách field — JSON blob → 6 column riêng
- Auto-map PE Details → Contract per-type Details khi gen HĐ
- Matrix Quotes bulk paste từ Excel
- fe-user Inbox thêm section "Phiếu Duyệt NCC chờ tôi"
**D. Tests Phase 3-5 (làm khi gặp bug recurring để justify ROI):**
- Phase 3 — Application handler tests (CQRS + EF InMemory) ~15 test
- Phase 4 — API smoke tests (WebApplicationFactory) ~7 test
- Phase 5 — FE Vitest cho lib utility (queryMatches, fmtMoney) ~10 test
**Đã xong session 5 (check STATUS Recently Done):**
- ~~Module Ngân sách FE — 3-panel pages cả 2 app~~ ✅
- ~~PE/Contract → Budget integration + cột "So với ngân sách"~~ ✅
- ~~PE Detail UI restructure 4 section đánh số~~ ✅
- ~~PE Workflow Designer admin UI~~ ✅
- ~~Ý kiến 4 phòng ban (migration 15)~~ ✅
- ~~Tests Phase 1-2 + CI gate (71 test)~~ ✅
### A. Hard blockers (chờ user / ops)
1. **UAT thật 1 tuần với 2-3 user** — hard requirement từ roadmap. Kiến nghị:
- User A: Drafter (QS/NV.PB) — tạo 3 HĐ mỗi type, đi hết 9 phase
- User B: CCM — duyệt phase 6
- User C: BOD — duyệt phase 7
- Ghi bug / friction / đề xuất → backlog iter 2
2. **SMTP config** để bật Email outbox:
```json
"Email": {
"Host": "smtp.gmail.com",
"Port": 587,
"Username": "...",
"Password": "...",
"From": "noreply@solutionerp.local"
}
```
Khi có → thêm `MailKit`, `IEmailSender`, hook vào `NotificationService.CreateAsync` ngay trước khi enqueue realtime push.
3. **Rotate credentials** — SA SQL password, vrapp password, JWT secret prod, Gitea runner registration token
4. **Schedule SQL backup** — `schtasks /create /tn "SolutionErp Backup" /tr "powershell -File C:\...\scripts\backup-sql.ps1" /sc DAILY /st 03:00`
### A1. Định kỳ — Skill audit
**Cadence:** Mỗi đầu tháng (4 tuần). Lần audit kế tiếp: **2026-05-01**.
Workflow xem `docs/rules.md §9.4`. Tóm tắt:
1. Cross-check 6 skill hiện có với STATUS / gotchas / migration-todos
2. Check repo nguồn 3rd party (alirezarezvani/claude-skills) có gì mới
3. Update / archive / add skill nếu cần
4. Log vào `docs/changelog/skill-audit-2026-05.md`
Trigger: user nói "audit skill" hoặc tự chạy đầu Phase mới.
### B. Polish iterations (optional — khi UAT phát sinh)
- **Roles CRUD** — admin tạo custom role ngoài 12 hardcoded (`Domain.Identity.AppRoles`)
- **User-kind approver runtime** — data model `WorkflowStepApprover.Kind=User` + `AssignmentValue=userId` đã có, chỉ cần:
```csharp
// ContractWorkflowService.TransitionAsync (bổ sung):
var userApprovers = step.Approvers.Where(a => a.Kind == ApproverKind.User)
.Select(a => Guid.Parse(a.AssignmentValue));
if (userApprovers.Any() && !userApprovers.Contains(actorUserId))
throw new ForbiddenException();
```
- **Grant `Workflows.Read` cho non-admin role** trong PermissionsPage → menu Wf_* auto-visible (inheritance đã có)
- **Warning notification 20% SLA** — job emit khi `SlaDeadline - now < sla * 0.2 && !SlaWarningSent`, set flag
- **Reject → DangSoanThao E2E test** với 3 role khác nhau
- **Deps scan CI** — `dotnet list package --vulnerable` + `npm audit --audit-level=high`
### C. Non-goals / parked
- E-signature (VNPT CA / FPT CA) — Phase 6
- Bravo/SAP import NCC — Phase 6
- Mobile app — Phase 6
- AI OCR scan HĐ — Phase 6+
## Lưu ý kỹ thuật quan trọng
**Đọc [`gotchas.md`](gotchas.md) (41 bẫy) trước khi:**
- Thêm package mới → .NET 10 compat (MediatR 14 fail → dùng 12.4.1)
- Debug TS enum error → dùng const-object pattern (`erasableSyntaxOnly`)
- Expression tree lỗi → tách switch ra ngoài LINQ
- Deploy Windows Feature (WebSockets, etc.) → unlock section ở applicationHost (gotcha #25)
- Workflow transition 403 → check `Contract.WorkflowDefinitionId` pin đúng không
- Migration lỗi → 3 file đầy đủ (Designer + Migration + Snapshot)
## Versioned workflow — quick ref
`Contract.WorkflowDefinitionId` pin tại Create. `ContractWorkflowService.LoadAsync` resolve order: pinned def → admin override → hardcoded Registry.For(type). Invariant: HĐ cũ giữ policy cũ qua FK Restrict. Detail: [`workflow-contract.md §7bis`](workflow-contract.md).
## File đang active
Cấu trúc thư mục + file map: [`PROJECT-MAP.md`](PROJECT-MAP.md). Git state: `git log --oneline -10`.
## Credentials + URLs
```
admin@solutionerp.local / Admin@123456 ← Admin (QTV)
Demo users — 30 user (User@123456):
── 16 sample @solutionerp.local (giữ cho test legacy) ──
bod.huynh, bod.le Tổng GĐ + Phó GĐ NĐUQ
pm.nguyen GĐ Dự án FLOCK 01 (PM)
ccm.tran, pro.pham, fin.do TPB CCM/PRO/FIN
act.vu, equ.bui, hra.dang Kế toán trưởng / TPB EQU / TPB HRA
qs.hoang, qs.ngo QS công trường (NV.PB)
nv.cao, nv.dinh, nv.truong NV Cung ứng/Tài chính/CCM (NV.PB)
bod.tran, pm.le Bonus NĐUQ + PM thứ 2
── 14 Solutions thật @solutions.com.vn (session 4) ──
PRO 5: tra.bui (TPB) + phuong.nguyen, binh.lethanh, danh.huynh, dat.tran (NV)
CCM 7: ngocanh.huynh (TPB) + ha.dao, cuong.do, long.le, ha.nguyen,
dung.nguyen, anh.nguyen (NV)
ISO 1: chau.le
CEO 1: huy.duong
⚠ Rotate ALL passwords trước UAT thật
```
- API prod: https://api.solutions.com.vn — `/health/live`, `/health/ready`
- Admin FE prod: https://admin.solutions.com.vn
- User FE prod: https://eoffice.solutions.com.vn
- API dev: http://localhost:5443 — `/swagger` (Dev only)
- Admin FE dev: http://localhost:8082
- User FE dev: http://localhost:8080
- SQL dev: `(localdb)\MSSQLLocalDB` / `SolutionErp_Dev`
- SQL prod: `.\SQLEXPRESS` / `SolutionErp` / `vrapp` (⚠ rotate)
## Đánh giá nhanh
**Tốt:**
- 3 domain HTTPS prod live, CI/CD xanh
- Tier 3 feature-complete: attachment, realtime, form builder (upload + DynamicForm + PDF), versioned workflow (admin-configurable per ContractType, pin per contract), nested menu per type, 3-panel permissions
- Clean-arch 3-project split đúng cho 2 cross-cutting service (realtime + document-converter)
- 26 gotchas tích lũy, 8 session log, 40 docs agent onboard nhanh
- Invariant critical: " giữ quy trình " guaranteed by pinning (reference-based immutability, không snapshot copy)
**Rủi ro còn:**
- UAT thật chưa chạy thể phát hiện edge case missing
- SMTP chưa notification chỉ in-app (toast + bell), không email
- User-kind approver chưa enable guard runtime (designer cho pick, nhưng transition dùng Role fall-back)
- Credentials chưa rotate
- SQL backup chưa schedule Task Scheduler