[CLAUDE] Domain+Infra+App+FE: dynamic workflow policy per ContractType
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m42s

Đọc QT-TP-NCC.docx: quy trình 9 bước chỉ áp dụng cho Thầu phụ/NCC/Tổ đội.
Dịch vụ/Mua bán/Nguyên tắc bypass CCM. Thay hardcoded dict bằng policy
registry.

Domain — WorkflowPolicy.cs:
- Record WorkflowPolicy { Name, Description, Transitions, PhaseSla,
  ActivePhases } — pure data, testable.
- WorkflowPolicies.Standard: 9-phase full (Thầu phụ/Giao khoán/NCC)
- WorkflowPolicies.SkipCcm: 7-phase (Dịch vụ/Mua bán/Nguyên tắc)
- WorkflowPolicyRegistry.For(type) map ContractType → policy
- WorkflowPolicyRegistry.ForContract(c) override nếu BypassProcurement
  AndCCM=true (instance-level escape hatch)

Infrastructure — ContractWorkflowService:
- Xóa hardcoded Transitions/PhaseSla dicts → load từ policy.ForContract
- TransitionAsync: validate qua policy.Transitions thay vì dict local
- Error message include policy.Name để debug dễ hơn
- GetPhaseSla trả SLA từ Standard policy (fallback — SLA hiện tại giống
  nhau giữa 2 policy)

Application — ContractDetailDto:
- Field mới `Workflow: WorkflowSummaryDto { PolicyName, Description,
  ActivePhases, NextPhases }` — FE dùng để render nút chuyển phase
  dynamic + timeline card.
- BuildWorkflowSummary helper trong ContractFeatures.

FE (both apps):
- Type WorkflowSummary + ContractDetail.workflow
- ContractDetailPage xóa hardcoded NEXT_PHASES — dùng
  c.workflow.nextPhases từ BE (single source of truth)
- WorkflowSummaryCard: timeline của ActivePhases với check/current/
  future states + policy name/description ở header
- Card hiển thị trong sidebar, phía trên "Lịch sử duyệt"

Docs:
- gotchas.md #21 marked RESOLVED (NEXT_PHASES sync không còn cần)

Foundation: sau này admin có thể edit policy qua UI khi chuyển sang DB-
backed policy — nhưng API contract (WorkflowSummaryDto) đã stable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-04-21 21:46:31 +07:00
parent e45909712b
commit cae4d84830
11 changed files with 342 additions and 88 deletions

View File

@ -156,13 +156,11 @@ Mỗi migration tạo: `{name}.cs` + `{name}.Designer.cs` + `ApplicationDbContex
**Fix:** Check `if (contract.MaHopDong is null)` trước khi gen. Đã implement trong `ContractWorkflowService.TransitionAsync`.
### 21. BE adjacency vs FE NEXT_PHASES sync
### 21. ~~BE adjacency vs FE NEXT_PHASES sync~~ (RESOLVED)
**Triệu chứng:** FE hiển thị nút chuyển phase, click → BE 403.
**Đã xử lý:** FE không còn hardcode `NEXT_PHASES` nữa. BE expose `contract.workflow.nextPhases` trong `ContractDetailDto` từ `WorkflowPolicyRegistry.ForContract(contract)`. FE render dynamic từ đó — single source of truth.
**Nguyên nhân:** FE `NEXT_PHASES` map phải khớp BE `Transitions` dict.
**Fix:** Khi đổi adjacency BE → sync FE `src/pages/contracts/ContractDetailPage.tsx` ngay lập tức (cả 2 app).
Nếu đổi policy BE: chỉ cần update `WorkflowPolicies.Standard` hoặc `WorkflowPolicies.SkipCcm` trong `Domain/Contracts/WorkflowPolicy.cs`. FE tự reflect.
### 22. Race condition gen mã HĐ khi 2 user cùng transition tới DangDongDau