[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.
This commit is contained in:
pqhuy1987
2026-05-08 16:40:49 +07:00
parent de0f38dd25
commit 8680f4c849
8 changed files with 411 additions and 19 deletions

View File

@ -362,6 +362,90 @@ transition cho mọi phase trung gian (trước chỉ DangSoanThao→TuChoi).
- Phase TraLai = 98 (Domain enum từ S11+++++++) orphan, KHÔNG wire (user
Session 14 chốt không cần phase trung gian).
## Phase 9+ done (Mig 21 — Session 16) — Drastic refactor flat workflow
Bỏ phase enum legacy 2-9. Dùng `ChoDuyet=10` đơn nhất + `CurrentWorkflowStepIndex` tracking flat. WorkflowStep + DepartmentId/PositionLevel. Service iterate steps `OrderBy Order` advance pointer per approve. Match approver: actor.Dept+PositionLevel OR Approvers Role/User. 9677 test pass (drop 19 N-stage/2-stage legacy). Phase legacy 2-6 + 98 deprecated giữ enum cho data . Reject về DangSoanThao + RejectedAtStepIndex jump-back resume.
## Phase 9+ done (Mig 22-24 — Session 17) — V2 schema riêng + state machine 5 trạng thái
**Spec change (Session 17):** schema riêng `ApprovalWorkflowsV2` (3 bảng) song song V1 (Mig 21 vẫn live). Cấu trúc: Quy trình > Bước (Phòng) > Cấp (N NV cụ thể qua `ApproverUserId`). PE Service wire xong, Contract V2 chưa (defer Session 18+).
### State machine 5 trạng thái (mirror Contract sẽ áp dụng tương tự)
```
Nháp (DangSoanThao) ──Drafter trình──► Đã gửi duyệt (ChoDuyet)
Trả lại (TraLai=98) ──Drafter sửa+gửi lại──► Đã gửi duyệt (chạy LẠI từ Cấp 1 Bước 1)
Đã gửi duyệt ──advance level/step──► Đã gửi duyệt
──last cấp last bước done──► Đã duyệt (DaDuyet, terminal)
──Approver Trả lại──► Trả lại
──Approver Từ chối──► Từ chối (TuChoi, terminal)
```
Khác Mig 21 (Session 16): Trả lại = Phase RIÊNG, KHÔNG revert DangSoanThao + KHÔNG jump-back. Drafter từ TraLai gửi lại = entry point thứ 2 mirror DangSoanThao. `RejectedAtStepIndex/RejectedFromPhase` deprecated (giữ DB column data cũ).
### Service branch theo schema pin
```csharp
// PurchaseEvaluationWorkflowService.TransitionAsync (gotcha #42)
if (evaluation.ApprovalWorkflowId is Guid awId)
await ApproveV2Async(...) // V2: iterate AW.Steps + Levels match ApproverUserId
else
await ApproveV1LegacyAsync(...) // V1: iterate WorkflowSteps match Dept+PositionLevel
```
### Match approver V2 — KHÁC V1
| Schema | Approver type | Match logic |
|---|---|---|
| V1 (Mig 21) | Group qua Dept+PositionLevel | actor.Dept == step.Dept AND actor.PositionLevel >= step.PositionLevel |
| V2 (Mig 22-24) | NV cụ thể 1-1 | actor.Id == any level.ApproverUserId where level.Order == currentLevelOrder |
| Cả 2 | Role-based fallback | Approvers explicit Kind=Role match actor.Roles |
| Cả 2 | Admin bypass | actorRoles.Contains("Admin") → skip mọi check |
### Pin V2 (Mig 23-24)
```csharp
public class PurchaseEvaluation : AuditableEntity
{
public Guid? WorkflowDefinitionId { get; set; } // V1 legacy (Mig 21)
public Guid? ApprovalWorkflowId { get; set; } // V2 mới (Mig 23) — pin lúc create
public int? CurrentWorkflowStepIndex { get; set; } // 0-based index Step (post-sort by Order)
public int? CurrentApprovalLevelOrder { get; set; } // 1/2/3 Cấp đang chờ (Mig 24)
// ...
}
```
### Designer V2 constraints
- Tối đa 3 Cấp/Bước (Order ∈ {1,2,3})
- Sequential gating: 1 / 1+2 / 1+2+3 (chặn 2 hoặc 1+3)
- Mỗi Cấp có N NV (multiple Level rows cùng Order = same Cấp, OR-of-N)
- 3 section cố định C1/C2/C3 trong UI, button "+ Thêm NV" mỗi cấp
- C2 disabled khi C1 empty, C3 disabled khi C2 empty
- Filter NV theo Phòng đã chọn (đổi Phòng → clear approvers)
- Validator BE: `HaveSequentialOrders` + `HaveNoDuplicateApproverInSameLevel`
### FE UX V2-aware
- Banner emerald "Đến lượt bạn" / 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
- Button "Trả lại" + "Từ chối" enabled cho mọi user (BE không gating reject theo cấp)
- Inbox V2-aware (`ResolveV2InboxIdsAsync` precompute IDs khớp actor.Id ∈ Cấp hiện tại)
- 2 dropdown filter "Quy trình" + "Trạng thái" (chỉ ở Duyệt, không Danh sách)
- Panel 3 thay 4 phase cards bằng flow workflow thực tế: Bước (icon ✓/●/○) → Cấp với label "đang chờ"/"đã duyệt"
### DTO mới Session 17
- `PurchaseEvaluationCurrentApprovalDto` — Cấp hiện tại + N approvers (cho banner + button gating)
- `PurchaseEvaluationApprovalFlowDto` — full Steps/Levels tree với Status Done/Current/Pending (cho Panel 3 render)
### Defer Session 18+
- Contract V2 wire (Mig 25) — mirror PE Mig 23-24 pattern
- Phân quyền strict V2 (hiện loose UAT — mọi authenticated user thấy phiếu V2)
- Drop legacy V1 sau khi không còn phiếu pin → drop tables WorkflowDefinitions/Steps/Approvers + drop deprecated columns RejectedAtStepIndex/RejectedFromPhase
- Test Domain ApproveV2Async + match logic (defer khi có sample data UAT)
## Tier 4+ (còn thiếu / future)
- [ ] Warning notification 20% SLA (`SlaWarningSent` flag đã có)