Files
solution-erp/docs/changelog/sessions/2026-05-08-1100-pe-workflow-v2-end-to-end.md
pqhuy1987 8680f4c849 [CLAUDE] Docs: Session 17 wrap-up — PE Workflow V2 end-to-end consolidation
User chốt MD wrap-up Session 17 (13 commit từ c847dc0de0f38d) — PE
Workflow V2 schema + Service wire + UX iteration đầy đủ.

MD updates:
- STATUS.md — header counts (24 mig, 58 tables, 81 test, 43 gotcha) +
  Recently Done row consolidate Session 17 wrap-up (gộp 4 row iter cũ
  thành 1 row tổng, không cắt narrative quan trọng)
- HANDOFF.md — TL;DR Session 17 + Chunk E (Designer iter + State
  machine + Service wire + UX) + Pending Session 18+
- CLAUDE.md — count (22→24 mig, 77→81 test) + V2 schema overview
- changelog/migration-todos.md — section  Session 17 done với 7 task
  ticked + Defer Session 18+ explicit
- database/schema-diagram.md — §14 ApprovalWorkflow V2 schema (3 bảng
  + 2 column PE + state transitions + Service branch + Designer
  constraints + match approver V2 vs V1 table)
- gotchas.md — +#42 Dual schema branch + #43 Step.Order ≠ index 0-based
- skill contract-workflow — +section "Phase 9+ done Mig 22-24" với V2
  spec + Service branch + match logic table + Designer constraints +
  UX V2-aware + Defer Session 18+
- changelog/sessions/2026-05-08-1100-pe-workflow-v2-end-to-end.md (NEW)
  — full session log với 13 commit timeline + stats + gotchas + pending

Memory:
- project_solution_erp.md — entry Session 17 wrap-up đầy đủ (KHÔNG tạo
  file feedback mới — decisions specific cho project, không reusable
  cross-project per §9.5 anti-pattern)

Verify:
- 81 test pass (58 Domain + 23 Infra) — không thay đổi sau wrap-up
- 0 BE error
- 2 FE builds OK (đã verify ở các commit trước)
- Quy tắc consolidate §6.5: KHÔNG cắt narrative, chỉ phân tầng + remove
  duplicate. Session 17 row dài cố ý — cover full 13 commit context cho
  Session 18+ đọc lại.
2026-05-08 16:40:49 +07:00

126 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

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.

# 2026-05-08 (Session 17 wrap-up) — PE Workflow V2 schema + Service wire end-to-end
**13 commit** từ `c847dc0``de0f38d`. Resume từ Session 16 (drastic refactor flat Mig 21) — user phát hiện schema flat vẫn không đúng intent → yêu cầu schema riêng + Menu mới.
## Spec từ user
```
Mã Quy trình - Tên Quy trình
* Bước 1 - Phòng A
* Cấp 1 - NV X (1 NV cụ thể qua ApproverUserId)
* Cấp 2 - NV Y
* Bước 2 - Phòng B
* Cấp 1 - NV Z
```
Khác Mig 21: mỗi Cấp = NV CỤ THỂ qua `ApproverUserId`, KHÔNG group Dept+PositionLevel/Role/User.
## State machine 5 trạng thái (Option A user chốt diagram)
```
Nháp ──Drafter trình──► Đã gửi duyệt ──approve cấp cuối──► Đã duyệt (terminal)
├─ Trả lại ──────────► Trả lại
└─ Từ chối ──────────► Từ chối (terminal)
Trả lại ──Drafter sửa+gửi lại──► Đã gửi duyệt (chạy LẠI từ Cấp 1 Bước 1)
```
Trả lại = Phase RIÊNG (`TraLai=98`), KHÔNG revert DangSoanThao + KHÔNG jump-back. Drafter từ TraLai gửi lại = entry point thứ 2 mirror DangSoanThao → workflow chạy lại từ đầu.
## Migration 22-24 (3 mig mới)
| Mig | Tên | Nội dung |
|---|---|---|
| **22** | `AddApprovalWorkflowsV2` | 3 entity: ApprovalWorkflow + Step + Level + ApplicableType enum (DuyetNcc/DuyetNccPhuongAn/Contract). 3 CREATE TABLE + UNIQUE (Code, Version) + FK Cascade Step→Workflow + Level→Step + FK Restrict Department + ApproverUserId. Menu V2 seed |
| **23** | `AddApprovalWorkflowIdToPurchaseEvaluation` | PE.ApprovalWorkflowId Guid? FK Restrict — pin V2 lúc create |
| **24** | `AddCurrentApprovalLevelOrderToPe` | PE.CurrentApprovalLevelOrder int? — track Cấp đang chờ |
## 13 commit timeline
| # | Commit | Tóm tắt |
|---|---|---|
| 1 | `c847dc0` | Chunk A — Domain V2 + EF Config + Mig 22 + Menu seed |
| 2 | `f6047d5` | Chunk B — Application CQRS + API ApprovalWorkflowsV2Controller |
| 3 | `2781c7e` | Chunk C — FE Designer ~480 LOC `ApprovalWorkflowsV2Page.tsx` |
| 4 | `12daa7f` | Chunk D — Docs Schema mới |
| 5 | `9712778` | Designer iter 1 — lock 3 cấp/bước (sai intent) |
| 6 | `f3bea3c` | Designer iter 2 — đúng intent: max 3 cấp × N NV/cấp + sequential gating + filter Phòng + Validator BE strict |
| 7 | `ff21120` | State machine 5 trạng thái — TraLai Phase riêng. Policy + Service Reject branch → TraLai. 4 test mới TraLai entry. FE rename "Bản nháp" → "Nháp" |
| 8 | `d642fd3` | Docs STATUS Session 17 5 trạng thái |
| 9 | `0a40c65` | Mig 23 pin V2 vào PE + Workspace Select V2 |
| 10 | `b41484b` | Mig 24 + Service V2 wire `ApproveV2Async` + Synthetic Policy ForV2Schema |
| 11 | `d814429` | UX disable button non-approver + banner "Đến lượt bạn" / "Không phải lượt" + DTO CurrentApproval |
| 12 | `9e63e2d` `d250ae4` `74745a7` | List/Inbox V2-aware + 2 dropdown filter (chỉ ở Duyệt) |
| 13 | `ac41d5e` | SQL clean prod + test user `nv.test@solutions.com.vn` |
| — | `de0f38d` | Panel 3 flow render — bỏ phase cards, hiện Bước/Cấp với Status Done/Current/Pending |
## Service V2 wire — branch theo schema pin
```csharp
// PurchaseEvaluationWorkflowService.TransitionAsync (Mig 24)
if (evaluation.ApprovalWorkflowId is Guid awId)
await ApproveV2Async(...)
// Load AW.Steps + Levels Include 3-level
// Group Levels by Order = Cấp (OR-of-N approvers cùng cấp)
// Match actor.Id ∈ ApproverUserId
// Advance: levelOrder++ trong Step → idx++ + reset levelOrder=1 → DaDuyet
else
await ApproveV1LegacyAsync(...) // giữ logic Mig 21
```
## UX V2-aware
- Banner emerald "✓ Đến lượt bạn duyệt" / amber "⚠ Không phải lượt bạn — chỉ {NV X / Y} duyệt được"
- Button Duyệt forward `disabled` khi V2 + actor không trong Cấp + tooltip
- Trả lại + Từ chối vẫn enabled (BE không gating reject theo cấp)
- Inbox `ResolveV2InboxIdsAsync` precompute IDs khớp actor.Id
- 2 dropdown filter "Quy trình duyệt" + "Trạng thái" (chỉ ở Duyệt — Danh sách giữ 1 dropdown)
- Panel 3 thay 4 phase cards bằng flow workflow thực tế:
```
✓ Bước 1 — Phòng CCM
✓ Cấp 1 (đã duyệt) NV Test
● Cấp 2 (đang chờ) Phan Văn Chương ← highlight brand
○ Cấp 3 (chưa) Nguyễn Văn Trường
```
## Test setup prod
- SQL `clean-transactional-uat.sql` xóa 9 PE + 11 HĐ + 19 Notif + reset CodeSequences. Giữ master (Users=8, Suppliers=19, Projects=9, Departments=9, V1+V2 Workflows). Run via SSH VPS `.\SQLEXPRESS`.
- Test user `nv.test@solutions.com.vn` / `TestUser@123456` (Drafter, CCM, ID `881269c7-dbb5-4aad-a92c-08deace07898`) tạo qua API admin `POST /api/users`.
## Stats final Session 17
| | Trước | Sau |
|---|---|---|
| Migrations | 21 | **24** (+3) |
| DB tables | 55 | **58** (+3) |
| API endpoints | ~134 | **~140** (+5) |
| FE pages | 32 | **33** (+1) |
| Test pass | 77 | **81** (+4 TraLai entry point) |
| Gotchas | 41 | **43** (+2 dual schema + Step.Order ≠ index) |
## Gotchas mới (2)
- **#42 Dual schema V1 vs V2 — Service phải branch theo pin field**: phiếu pin V2 mà Service đọc `WorkflowDefinitionId` → match approver schema cũ → Forbidden. Fix: branch `if (ApprovalWorkflowId is Guid)` → `ApproveV2Async`.
- **#43 Step.Order ≠ index 0-based**: EF không thể query `Step.Order == idx + 1` thẳng. Cần precompute candidates EF + in-memory sort by Order + array index.
## Pending Session 18+
| Task | Estimate | Priority |
|---|---|---|
| Contract V2 wire (Mig 25) | 4-6h dedicated session | High (sau khi PE UAT confirm) |
| Phân quyền strict V2 | 2h | Medium |
| Drop legacy V1 + cleanup deprecated columns | Mig 26 cleanup, 2h | Low (chờ migrate hết phiếu cũ) |
| Test Domain ApproveV2Async + match logic | 3h | Medium |
| Budget V2 wire (Mig 27) | 4h dedicated | Low |
| Admin role bypass option C audit log | 2h | Low |
## Memory entry — không tạo mới
Session 17 decisions ghi đầy đủ vào `memory/project_solution_erp.md`. Pattern dual schema reusable nhưng quá specific cho project — không tạo `feedback_dual_schema_pattern.md` riêng (anti-pattern §9.5 "viết skill chỉ để có thêm" áp dụng cho memory).
## Skill update
`contract-workflow` skill +section "Phase 9+ done (Mig 22-24 — Session 17) — V2 schema riêng + state machine 5 trạng thái" — mention V2 cross-ref + Service branch + match logic V2 vs V1 table + Designer constraints.
KHÔNG tạo skill `pe-workflow-v2` mới — overlap với `contract-workflow` existing skill (cùng pattern state machine + versioned WF, khác schema).