[CLAUDE] Docs: Session 17 wrap-up — PE Workflow V2 end-to-end consolidation
User chốt MD wrap-up Session 17 (13 commit từc847dc0→de0f38d) — 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:
@ -715,7 +715,89 @@ CREATE TABLE PurchaseEvaluationDepartmentOpinions (
|
||||
CREATE UNIQUE INDEX IX_PEDeptOpinions_PEId_Kind ON PurchaseEvaluationDepartmentOpinions (PurchaseEvaluationId, Kind);
|
||||
```
|
||||
|
||||
## 14. Liên quan
|
||||
## 14. ApprovalWorkflow V2 schema (Migration 22-24, Session 17 — 3 bảng mới + 2 column)
|
||||
|
||||
Schema riêng song song WorkflowDefinition V1 (Mig 21) — pin per phiếu PE.
|
||||
V1 vẫn giữ cho phiếu cũ; V2 mới là active cho phiếu tạo từ Session 17 trở đi.
|
||||
|
||||
### Core (3 bảng):
|
||||
|
||||
```
|
||||
ApprovalWorkflows
|
||||
├── Id (PK), Code, Version (UNIQUE Code+Version)
|
||||
├── ApplicableType (1=DuyetNcc, 2=DuyetNccPhuongAn, 3=Contract)
|
||||
├── Name, Description, IsActive, ActivatedAt
|
||||
└── (audit) CreatedAt, UpdatedAt, CreatedBy, UpdatedBy
|
||||
|
||||
ApprovalWorkflowSteps (FK Cascade ApprovalWorkflowId, FK Restrict DepartmentId)
|
||||
├── Id (PK), ApprovalWorkflowId, Order (1-based, sort key — KHÔNG phải position)
|
||||
├── Name (vd "Phòng A"), DepartmentId? (hint)
|
||||
└── INDEX (ApprovalWorkflowId, Order) + INDEX DepartmentId
|
||||
|
||||
ApprovalWorkflowLevels (FK Cascade ApprovalWorkflowStepId, FK Restrict ApproverUserId)
|
||||
├── Id (PK), ApprovalWorkflowStepId, Order (1/2/3 trong Step)
|
||||
├── Name? (vd "Cấp 1"), ApproverUserId (1 NV cụ thể)
|
||||
└── INDEX (ApprovalWorkflowStepId, Order) + INDEX ApproverUserId
|
||||
```
|
||||
|
||||
**Convention quan trọng:** nhiều `ApprovalWorkflowLevel` rows cùng `Order` trong cùng Step = **same Cấp với N approvers** (OR-of-N). Ví dụ Cấp 1 có 2 NV: 2 row Level cùng `Order=1` khác `ApproverUserId`.
|
||||
|
||||
### Pin V2 vào PE (Mig 23-24):
|
||||
|
||||
```
|
||||
PurchaseEvaluations (column mới)
|
||||
├── ApprovalWorkflowId Guid? (FK Restrict ApprovalWorkflows) — pin lúc create
|
||||
└── CurrentApprovalLevelOrder int? — track Cấp đang chờ duyệt (1/2/3)
|
||||
```
|
||||
|
||||
Combined với `CurrentWorkflowStepIndex int?` (Mig 21) để track full state V2:
|
||||
- `CurrentWorkflowStepIndex` = 0-based index của Step (sau khi sort by `Order`)
|
||||
- `CurrentApprovalLevelOrder` = `Order` của Cấp đang chờ trong Step đó
|
||||
|
||||
Service iterate: `steps[CurrentStepIndex].Levels.Where(l => l.Order == CurrentLevelOrder)` → list approvers, match `actor.Id ∈ ApproverUserId`.
|
||||
|
||||
### Match approver V2 (khác V1):
|
||||
|
||||
| Schema | Match logic | Approver type |
|
||||
|---|---|---|
|
||||
| V1 (Mig 21) | `actor.Dept == step.Dept && actor.PositionLevel >= step.PositionLevel` OR Approvers Role/User explicit | Group qua Dept+Level |
|
||||
| V2 (Mig 22-24) | `actor.Id == any level.ApproverUserId where level.Order == currentLevelOrder` | NV cụ thể 1-1 |
|
||||
|
||||
### State transitions (V2 + V1 cùng):
|
||||
|
||||
```
|
||||
DangSoanThao ──Drafter trình──► ChoDuyet (idx=0, levelOrder=1 nếu V2)
|
||||
TraLai ──Drafter sửa+gửi lại──► ChoDuyet (idx=0, levelOrder=1) — chạy LẠI từ đầu
|
||||
ChoDuyet ──Approver duyệt cấp──► ChoDuyet (advance levelOrder hoặc idx)
|
||||
──Approver Trả lại──► TraLai (clear pointers)
|
||||
──Approver Từ chối──► TuChoi (terminal khoá)
|
||||
──last step+level done──► DaDuyet (terminal)
|
||||
```
|
||||
|
||||
### Service branch theo schema pin:
|
||||
|
||||
```csharp
|
||||
// PurchaseEvaluationWorkflowService.TransitionAsync (Mig 24 wire)
|
||||
if (evaluation.ApprovalWorkflowId is Guid awId)
|
||||
await ApproveV2Async(...) // iterate ApprovalWorkflowSteps + Levels match ApproverUserId
|
||||
else
|
||||
await ApproveV1LegacyAsync(...) // iterate WorkflowSteps match Dept+PositionLevel
|
||||
```
|
||||
|
||||
### Designer constraints (FE Validator + BE Validator):
|
||||
|
||||
- Tối đa 3 Cấp/Bước (`Order ∈ {1,2,3}`)
|
||||
- Sequential gating: `1` → `1+2` → `1+2+3` (không cho `2` nếu thiếu `1`, không `1+3` nếu thiếu `2`)
|
||||
- No duplicate `(Order, ApproverUserId)` cùng Step (1 NV không thêm 2 lần cùng Cấp)
|
||||
- Mỗi Cấp có N NV (OR-of-N)
|
||||
- Đổi Phòng → clear toàn bộ approvers (NV cũ có thể không thuộc Phòng mới)
|
||||
|
||||
### Pending Session 18+:
|
||||
|
||||
- Contract V2 wire (Mig 25): mirror PE pattern — thêm `Contract.ApprovalWorkflowId` + `CurrentApprovalLevelOrder`
|
||||
- Drop legacy V1: sau khi không còn phiếu pin `WorkflowDefinitionId` → drop `WorkflowDefinitions` + `WorkflowSteps` + `WorkflowStepApprovers` + drop deprecated columns `RejectedAtStepIndex` / `RejectedFromPhase`
|
||||
|
||||
## 15. Liên quan
|
||||
|
||||
- [`database-guide.md`](database-guide.md) — conventions + migration workflow + cheatsheet đầy đủ
|
||||
- [`../architecture.md`](../architecture.md) — layered architecture + data flow
|
||||
|
||||
Reference in New Issue
Block a user