diff --git a/CLAUDE.md b/CLAUDE.md index d2588a6..ce6a882 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -50,7 +50,7 @@ Kiến trúc: **.NET 10 Clean Architecture + 2 React FE (admin + user) + SQL Ser - Audit fields: `CreatedAt`, `UpdatedAt`, `CreatedBy`, `UpdatedBy` (`BaseEntity`) - Soft delete: `IsDeleted`, `DeletedAt`, `DeletedBy` (`AuditableEntity`) - Migrations: `dotnet ef migrations add --project src/Backend/SolutionErp.Infrastructure --startup-project src/Backend/SolutionErp.Api` -- **Hiện có 21 migration → 55 bảng** (Phase 9+ — Mig 21 `RefactorWorkflowToFlatModel` DRASTIC REFACTOR Session 16. Bỏ phase enum legacy (2-9 + 98 deprecated giữ data cũ), dùng ChoDuyet=10 đơn nhất + CurrentWorkflowStepIndex tracking. Workflow flat list (Phòng × Cấp × Approvers). WorkflowStep + DepartmentId+PositionLevel. Drop InnerStep entities (Mig 18+20). Service rewrite iterate steps OrderBy Order, advance pointer per approve. Match approver Dept+PositionLevel OR Approvers Role/User. PE 3-button Duyệt forward / Trả lại smart-reject jump-back / Từ chối khoá phiếu) +- **Hiện có 22 migration → 58 bảng** (Phase 9+ — Mig 22 `AddApprovalWorkflowsV2` Session 17 schema mới UAT trước khi drop legacy: Quy trình > Bước (Phòng) > Cấp (NV cụ thể qua ApproverUserId — KHÔNG OR-of-many). Schema riêng `ApprovalWorkflows` + `ApprovalWorkflowSteps` + `ApprovalWorkflowLevels`. PE/Contract Service CHƯA wire — vẫn pin Mig 21 legacy. Mig 21 `RefactorWorkflowToFlatModel` DRASTIC REFACTOR Session 16. Phase enum simplify ChoDuyet=10 đơn nhất + CurrentWorkflowStepIndex tracking. Workflow flat list (Phòng × Cấp × Approvers). PE 3-button Duyệt/Trả lại/Từ chối) ### Modules diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index 2464671..e60e577 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -1,6 +1,70 @@ # HANDOFF — Brief 5 phút cho session tiếp theo -**Last updated:** 2026-05-08 (Session 16 — **🎯 DRASTIC REFACTOR DONE: flat workflow Phòng × Cấp + Mig 21 + Service rewrite + FE Designer rewrite. 2 commit Chunk A+B. 96 → 77 test pass (drop 19 legacy). Backward compat: legacy phase 2-9+98 enum giữ cho data cũ.**) +**Last updated:** 2026-05-08 (Session 17 — **🎯 SCHEMA MỚI ApprovalWorkflowsV2 + Menu "Duyệt NCC (Mới)" UAT. 4 commit. Schema riêng trên Mig 22. Cấu trúc Bước (Phòng) > Cấp (NV cụ thể qua ApproverUserId — KHÔNG OR-of-many). Chỉ admin Designer xong, Service PE/Contract chưa wire qua schema mới — UAT UIUX trước.**) + +## TL;DR Session 17 (08/05 — Schema mới UAT trước khi drop legacy) + +User chốt sau Session 16: schema flat Mig 21 vẫn không đúng intent. Yêu cầu **viết lại toàn bộ chỗ Quy trình Duyệt + thêm Menu mới "Duyệt NCC (Mới)"** với cấu trúc rõ ràng: + +``` +Mã Quy trình - Tên Quy trình + * Bước 1 - Phòng A + * Cấp 1 - NV X ← 1 user 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 = 1 NV chính xác, KHÔNG OR-of-many group Dept+PositionLevel/Role/User. + +**4 commit (3 chunk per-commit + docs):** + +### Chunk A (`c847dc0`) — Domain + EF + Mig 22 + Menu + +- Domain `ApprovalWorkflowsV2/ApprovalWorkflow.cs` — 3 entity (ApprovalWorkflow + Step + Level) + enum `ApprovalWorkflowApplicableType` (DuyetNcc=1 / DuyetNccPhuongAn=2 / Contract=3) +- EF `ApprovalWorkflowConfiguration.cs` — UNIQUE (Code, Version), FK Cascade Step→Workflow + Level→Step, FK Restrict Department + ApproverUserId +- ApplicationDbContext +3 DbSet +- **Migration 22** `AddApprovalWorkflowsV2` — 3 CREATE TABLE + 1 UNIQUE + 4 INDEX. Applied cả `_Design` + `_Dev` LocalDB +- DbInitializer SeedMenusAsync: +menu `ApprovalWorkflowsV2` root dưới System (icon Workflow) + leaf `AwV2_DuyetNcc` (icon FileCheck, label "Duyệt NCC (Mới)") +- MenuKeys.cs +2 const trong All array + +### Chunk B (`f6047d5`) — Application CQRS + API + +- `Application/ApprovalWorkflowsV2/ApprovalWorkflowV2AdminFeatures.cs`: + - `GetAwAdminOverviewQuery(ApplicableType?)` — load 3-level Include + dept/user names map + - `CreateAwDefinitionCommand` + Validator — auto-increment Version theo Code, deactivate active version cùng ApplicableType + - `DeleteAwDefinitionCommand` — UAT helper unconditional (chưa pin) + - DTO AwDefinition/AwStep/AwLevel + AwTypeSummary +- IApplicationDbContext +3 DbSet +- `Api/Controllers/ApprovalWorkflowsV2Controller` — route `/api/approval-workflows-v2`, GET ?applicableType=N | POST | DELETE/{id}, reuse policy `Workflows.Read` + `Workflows.Create` + +### Chunk C (`2781c7e`) — FE Designer + +- `fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx` (~480 LOC) + - Overview cards Active+History per ApplicableType + - DefinitionCard read-only: Bước (badge phòng emerald) → Cấp (badge violet C1/C2 + tên NV + email) + - Designer dialog: Mã/Tên/Mô tả + Add/Remove Step + reorder (chevron up/down) + Add/Remove Level + Select Phòng + Select NV duyệt + - Validate: mỗi Step ≥1 Level, mỗi Level phải có ApproverUserId + - Auto-assign code mặc định theo type: `QT-DN-V2-001` / `QT-DN-PA-V2-001` / `QT-HD-V2-001` +- Layout.tsx resolver +ApprovalWorkflowsV2 root → `/system/approval-workflows-v2`, +AwV2_ leaf → `/system/approval-workflows-v2/` +- App.tsx +2 route +- menuKeys.ts +2 const sync với BE + +### Chunk D — Docs (current) + +STATUS + HANDOFF + project_solution_erp.md memory. + +## ⚠️ Điều quan trọng cho Session 18+ + +1. **PE/Contract Service CHƯA wire** qua schema mới — vẫn pin `WorkflowDefinitionId` từ Mig 21 (legacy). Sau khi user UAT UIUX OK, Session sau cần: + - Thêm pinning `ApprovalWorkflowId` vào PE/Contract entity (nullable, song song WorkflowDefinitionId) + - Service rewrite: nếu pin V2 → iterate ApprovalWorkflowSteps OrderBy Order → ApprovalWorkflowLevels OrderBy Order → match `actor.Id == level.ApproverUserId` (chính xác 1-1) + - Migration data từ legacy → V2 (manual hoặc seed sample) + - Drop legacy WorkflowDefinition + WorkflowStep + Approver tables sau khi không phiếu nào pin +2. **Backward compat 100%** — schema mới chỉ thêm vào, không sửa cũ. Phiếu PE/Contract đang chạy không bị ảnh hưởng. +3. **77 test pass giữ nguyên** — không thêm test mới (Designer UI chưa critical, defer khi Service wire xong → test policy + match approver). + +--- ## TL;DR Session 16 (08/05 — Drastic refactor flat workflow EXECUTE) diff --git a/docs/STATUS.md b/docs/STATUS.md index 98ab6a3..40dd7f9 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -2,9 +2,9 @@ > **Update rule:** trước khi bắt đầu 1 task → ghi row vào `🔥 In Progress`. Xong → chuyển sang `✅ Recently Done`. -**Last updated:** 2026-05-08 (Session 16 — **🎯 DRASTIC REFACTOR: flat workflow Phòng × Cấp + Migration 21. Bỏ phase enum legacy 2-9, dùng `ChoDuyet=10` đơn nhất + `CurrentWorkflowStepIndex` tracking + `RejectedAtStepIndex` resume. WorkflowStep + DepartmentId/PositionLevel. Drop InnerStep entities (Mig 18+20 deprecated). Service rewrite PE + Contract. App CQRS DTOs simplified. Tests 96 → 77 (drop 19 N-stage/2-stage legacy). FE Designer rewrite flat UI. 2 commit Chunk A + B (`dbb0089`, `88a5be1`). Backward compat: legacy phase values 2-9 + 98 giữ enum cho data cũ.**) +**Last updated:** 2026-05-08 (Session 17 — **🎯 SCHEMA MỚI hoàn toàn `ApprovalWorkflowsV2` (Mig 22) + Menu mới "Duyệt NCC (Mới)" UAT trước khi drop legacy. User chốt sau Session 16: "Thấy vẫn không đúng, viết lại toàn bộ chỗ Quy trình Duyệt + thêm Menu mới". Cấu trúc Quy trình > Bước (Phòng) > Cấp (NV cụ thể qua ApproverUserId — KHÔNG OR-of-many như Mig 21). 4 commit Chunk A+B+C (`c847dc0`, `f6047d5`, `2781c7e`) + Chunk D docs.**) -## 📍 Phase hiện tại: **Phase 9 active — UAT** — **55 DB tables, 21 migrations, ~134 API endpoints, 32 FE pages. 77 unit test pass** (54 Domain + 23 Infra). 41 gotcha. 30 demo user. 6 skill. **5 PE display status** (Bản nháp / Đã gửi duyệt / Trả lại / Đã duyệt / Từ chối). **Phase enum simplified post-Mig 21**: DangSoanThao=1, ChoDuyet=10 (NEW generic), DaDuyet=7, TuChoi=99. Legacy 2-6 + 98 deprecated. **Flat workflow Mig 21**: WorkflowStep + DepartmentId+PositionLevel + Approvers. PE/Contract + CurrentWorkflowStepIndex/RejectedAtStepIndex tracking. Service iterate steps OrderBy Order, advance pointer per approve. Match approver Dept+PositionLevel (OR cùng cấp/dept). Hết step → DaDuyet/DaPhatHanh. +## 📍 Phase hiện tại: **Phase 9 active — UAT (workflow schema mới Mig 22 đợi user test)** — **58 DB tables (+3 Mig 22 ApprovalWorkflows + Steps + Levels), 22 migrations, ~137 API endpoints (+3 V2), 33 FE pages (+1 Designer V2). 77 unit test pass** (54 Domain + 23 Infra). 41 gotcha. 30 demo user. 6 skill. **5 PE display status** (Bản nháp / Đã gửi duyệt / Trả lại / Đã duyệt / Từ chối). **Phase enum simplified post-Mig 21**: DangSoanThao=1, ChoDuyet=10 (NEW generic), DaDuyet=7, TuChoi=99. Legacy 2-6 + 98 deprecated. **Workflow schemas đang đồng tồn tại**: (1) Mig 21 `WorkflowDefinition` flat — pin với PE/Contract đang chạy. (2) Mig 22 `ApprovalWorkflow` mới (UAT) — Bước (Phòng) > Cấp (NV ApproverUserId). Sau UAT → migrate data + drop legacy. ### 🌐 Production URLs @@ -61,6 +61,7 @@ | Ngày | Ai | Task | Commit | |---|---|---|---| +| 2026-05-08 | Claude | **🎯 SESSION 17 — Schema mới `ApprovalWorkflowsV2` (Mig 22) + Menu "Duyệt NCC (Mới)" UAT (3 commit per-chunk)** — User chốt sau Session 16 drastic refactor: "Thấy vẫn không đúng, viết lại toàn bộ chỗ Quy trình Duyệt + thêm 1 Menu chỗ quy trình duyệt nữa là Duyệt NCC (Mới)" với cấu trúc explicit `Mã Quy trình - Tên Quy trình / * Bước 1 - Phòng A / * Cấp 1 - NV X / * Cấp 2 - NV Y`. Schema riêng UAT trước khi drop legacy. Khác Mig 21: mỗi Cấp = 1 NV CỤ THỂ qua `ApproverUserId` (KHÔNG OR-of-many). **Chunk A (`c847dc0`)** Domain `ApprovalWorkflowsV2/ApprovalWorkflow.cs` — 3 entity (ApprovalWorkflow + Step + Level) + enum `ApprovalWorkflowApplicableType` (DuyetNcc/DuyetNccPhuongAn/Contract). EF `ApprovalWorkflowConfiguration.cs` 3 IEntityTypeConfiguration: ToTable + UNIQUE (Code, Version) + FK Cascade Step→Workflow + FK Cascade Level→Step + FK Restrict Department + FK Restrict User. ApplicationDbContext 3 DbSet. **Migration 22** `AddApprovalWorkflowsV2` — 3 CREATE TABLE + 1 UNIQUE + 4 INDEX, applied cả `_Design` + `_Dev` LocalDB. DbInitializer SeedMenusAsync +2 menu row (`ApprovalWorkflowsV2` root dưới System icon Workflow + `AwV2_DuyetNcc` leaf icon FileCheck). MenuKeys.cs +2 const + All array. **Chunk B (`f6047d5`)** Application `ApprovalWorkflowsV2/ApprovalWorkflowV2AdminFeatures.cs` — 3 handler (GetAwAdminOverviewQuery filter optional ApplicableType, CreateAwDefinitionCommand auto-increment Version + deactivate active version cùng type, DeleteAwDefinitionCommand UAT helper unconditional) + Validator child rules NotEmpty Levels + ApproverUserId required. DTO AwDefinition/AwStep/AwLevel + AwTypeSummary. IApplicationDbContext +3 DbSet. Api Controller `ApprovalWorkflowsV2Controller` — GET ?applicableType=N | POST | DELETE/{id}, reuse policy Workflows.Read/Workflows.Create. **Chunk C (`2781c7e`)** FE-Admin `ApprovalWorkflowsV2Page.tsx` (~480 LOC) Designer mới mirror PE pattern nhưng theo schema V2: Overview cards Active+History per ApplicableType, DefinitionCard read-only render Bước → Cấp với approver name + email, Designer dialog Mã/Tên/Mô tả + reorder Step/Level (chevron up/down), Add/Remove Step + Level, Select Phòng + Select NV duyệt, validate level required NV. Auto-assign code QT-DN-V2-001 / QT-DN-PA-V2-001 / QT-HD-V2-001. Layout.tsx resolver +ApprovalWorkflowsV2/AwV2_. App.tsx +2 route. menuKeys.ts +2 const sync BE. **KHÔNG đụng** PE/Contract Service (legacy WorkflowDefinition vẫn pin). Verify: dotnet build pass + 77 test pass (no regression) + npm build fe-admin pass. Backward compat 100% — schema mới chỉ thêm vào, không sửa cũ. **Next**: User UAT menu mới → confirm UX → Session sau migrate PE/Contract Service iterate ApprovalWorkflowSteps → drop legacy WorkflowDefinition. | `c847dc0` (A) · `f6047d5` (B) · `2781c7e` (C) · (current D docs) | | 2026-05-08 | Claude | **🎯 SESSION 16 — DRASTIC REFACTOR flat workflow Phòng × Cấp (Mig 21, 2 commit Chunk A+B)** — Resume từ Session 15 defer plan. User chốt "bỏ phase enum hoàn toàn, dùng ChoDuyet=10 đơn nhất + currentStepIndex tracking". Per memory `feedback_drastic_refactor_scope`: dedicated session với context fresh, scope conservative 2x buffer (~8-10h estimate, actual ~3h). **Chunk A (`dbb0089`)** — Domain enum simplify (DangSoanThao=1, ChoDuyet=10 NEW, DaDuyet=7, TuChoi=99; legacy 2-6 + 98 deprecated giữ cho data cũ). WorkflowStep + DepartmentId Guid? FK Restrict + PositionLevel int? (PE + Contract mirror). PE/Contract entity + CurrentWorkflowStepIndex int? + RejectedAtStepIndex int?. Drop class WorkflowStepInnerStep + nav (PE + Contract). Drop *DepartmentApproval.InnerStepId column. EF Configurations: drop InnerStep config + restore simple unique non-filtered (Mig 19/20 filtered split reverse). DbContext drop DbSet<*WorkflowStepInnerStep> × 2. **Migration 21** `RefactorWorkflowToFlatModel` GỘP: 4 ALTER cols (PE/Contract CurrentStepIndex+RejectedAtStepIndex) + 2 ALTER (WorkflowStep DeptId+PositionLevel) + DROP TABLE x 2 (PEWorkflowStepInnerSteps + WorkflowStepInnerSteps Mig 18+20) + DROP InnerStepId column x 2 (PE+Contract DeptApproval) + DROP filtered indexes x 2 + restore simple unique x 2. PE + Contract Service rewrite TransitionAsync: phase transitions DangSoanThao→ChoDuyet (Drafter trình init idx=0) / ChoDuyet→ChoDuyet (advance idx) / ChoDuyet→DaDuyet/DaPhatHanh (last step done) / ChoDuyet→DangSoanThao (Trả lại save RejectedAtStepIndex) / ChoDuyet→TuChoi (Từ chối khoá vĩnh viễn). Match approver: actor.Dept==step.Dept AND actor.PositionLevel>=step.PositionLevel (OR cùng cấp/dept) OR Approvers.Kind=User match OR Kind=Role match. Admin role bypass policy. Last step done → gen mã HĐ (Contract only). App CQRS WorkflowStepDto + WorkflowStepInput drop InnerStep, add DepartmentId/DepartmentName/PositionLevel (PE + Contract mirror). Tests rewrite: DROP `PeNStageApprovalTests.cs` (6) + `ContractNStageApprovalTests.cs` (6) + `PeTwoStageApprovalTests.cs` (7) — legacy N-stage/2-stage no longer applicable. UPDATE `PeWorkflowAdminTests` signature. **96 → 77 test pass** (-19 legacy). 3-file rule Mig 21 (.cs + Designer + Snapshot) commit đủ. **Chunk B (`88a5be1`)** — FE-Admin Designer rewrite (PeWorkflowsPage + WorkflowsPage): drop InnerStepDto + EditInnerStep types, drop PHASE_OPTIONS auto-assign ChoDuyet=10, StepDto + EditStep + departmentId/positionLevel, copyFromDefinition simplified, Designer step UI rewrite (Tên + Phòng Select + Cấp Select + SLA + Approvers Role/User optional fallback, drop entire InnerSteps sub-section), DefinitionCard view hiển thị badge Phòng emerald + Cấp NV/PP/TP violet, save payload phase=10. types/purchaseEvaluation.ts (fe-admin + fe-user mirror) + ChoDuyet=10 enum + label "Đang duyệt" + color amber. **Chunk C (FE PeWorkflowPanel) SKIP** — existing UI compatible (workflow.nextPhases driven by BE simplified policy), reuse 3-button Trả lại/Từ chối logic Session 14 hoạt động trên ChoDuyet phase tự động. **KHÔNG đụng** Service Notify pattern + Changelog pattern (giữ hành vi Mig 16). Verify: dotnet build pass + Mig 21 LocalDB applied + 77 test pass + npm build × 2 pass. Memory `feedback_drastic_refactor_scope.md` validated: dedicated session approach hoạt động đúng dự đoán. | `dbb0089` (A) · `88a5be1` (B) | | 2026-05-07 | Claude | **🎯 SESSION 15 — Tooltip diagnose "Lưu & Gửi Duyệt" + Plan drastic refactor flat workflow → DEFER** — User UAT live screenshot phiếu PE Bản nháp + báo "Lưu & Gửi Duyệt" KHÔNG hoạt động + suy đoán "trùng ID với phiếu khác". Chẩn đoán: button silent disabled khi `evaluation.workflow.nextPhases` không có forward phase (chỉ TuChoi/TraLai). FE chưa có visual feedback → user không biết. Improvement (commit `835cc7f`): compute `forwardPhase` once + add `submitDisabledReason` string giải thích reason (canEditPhase=false / readOnly / !forwardPhase với hint admin kiểm tra cấu hình quy trình) + button title attribute show reason hover hoặc forward phase label khi enabled + Dialog confirm show forward phase explicit "Sẽ chuyển sang Chờ Purchasing". Mirror fe-admin + fe-user. Build pass cả 2. **"Trùng ID" KHÔNG phải bug FE** — `PurchaseEvaluationWorkspacePage` URL state đúng (`+ Thêm mới` clear `id`, save set new), mỗi PE row unique GUID + MaPhieu. **Tiếp theo plan drastic refactor**: User chốt "bỏ phase enum hoàn toàn, dùng ChoDuyet=10 đơn nhất + currentStepIndex tracking" + workflow flat list (Phòng × Cấp × Users[]) thay InnerStep model. Surface 6 chunk plan + start Chunk A: edit Domain entities (Phase enum +ChoDuyet=10, WorkflowStep +DeptId/PositionLevel, drop InnerStep class+nav, PE/Contract +CurrentWorkflowStepIndex/RejectedAtStepIndex, *DeptApproval drop InnerStepId) + EF Configurations (drop InnerStep config + nav, restore simple unique non-filtered) + DbContext drop DbSets — 12 files trong working tree. Realize scope realistic ~8-10h (PolicyRegistry rewrite + 2 Service rewrite + App CQRS + 12 tests rewrite + Designer FE + Migration 21 + Docs) vượt session boundary + risk session context deep ~30 commits. **REVERT working tree** về `835cc7f` clean. Add memory `feedback_drastic_refactor_scope` decision rule: drastic refactor cần dedicated session, ước tính conservative (2x buffer), tránh mid-session big refactor. **Stats unchanged**: 96 test pass, 20 mig, 57 bảng. | `835cc7f` | | 2026-05-07 | Claude | **🎯 SESSION 14 — PE 3-button workflow Duyệt/Trả lại/Từ chối + Task 2 sample seed in-progress** — User chỉ thị thay 2-button approval bằng 3 hành động rõ ràng cho approver: **Duyệt** (forward), **Trả lại** (về DangSoanThao + Drafter sửa, smart reject Mig 16 + clear N-stage rows + Drafter resume jump-back), **Từ chối** (Phase=TuChoi, phiếu khoá vĩnh viễn 17 handler Mig 16 lock edit, Drafter phải tạo phiếu mới). 1 commit (`0d77698`): Domain `PurchaseEvaluationPolicy.cs` NccOnly + NccWithPlan thêm `(X → TuChoi)` transition cho mọi phase trung gian (ChoPurchasing/ChoCCM/ChoDuAn/ChoCEODuyetPA/ChoCEODuyetNCC) với roles của phase. FromDefinition expand: mỗi step (trừ DangSoanThao) thêm (step.Phase → TuChoi) với roles step. Service `PurchaseEvaluationWorkflowService.TransitionAsync` — Reject branch tách 2 case: target=TuChoi giữ nguyên (KHÔNG override + KHÔNG set RejectedFromPhase + KHÔNG clear N-stage); target khác (DangSoanThao) → smart reject (force DangSoanThao + RejectedFromPhase + clear N-stage). FE PeWorkflowPanel (admin + user mirror): render 3 button rõ ràng "✓ Duyệt → X" brand / "← Trả lại (về Drafter sửa)" red / "✗ Hủy / Từ chối" red. Decision logic: target=TuChoi || isSendBack → Reject (2), else Approve (1). Dialog confirm: title rõ + Cancel case warning red "phiếu sẽ bị khoá hoàn toàn" + SendBack case hint amber "Phiếu về DangSoanThao, Drafter sửa rồi trình lại — workflow tự jump tới phase này". Tests: rename `Reject_Sets_RejectedFromPhase_And_Forces_DangSoanThao` → `Reject_To_DangSoanThao_Sets_RejectedFromPhase_TraLai` (target từ TuChoi → DangSoanThao). NEW `Reject_To_TuChoi_Locks_Permanently_No_RejectedFromPhase`. Update `NStage_Reject_Clears_InnerStep_Rows_At_Phase` target → DangSoanThao. **95 → 96 test pass** (+1 Từ chối). **Task 2 sample seed in-progress**: dotnet ef database update applied Mig 9-20 lên LocalDB SolutionErp_Dev (trước đó chỉ Mig 1-8 vì DesignTimeDbContextFactory hardcoded SolutionErp_Design ≠ runtime SolutionErp_Dev — gotcha tooling distinction). API start để DbInitializer auto-seed 30 demo user nhưng exit 255 sớm khi log buffer full → seed dở dang. Defer Task 2 cho session sau (cần guidance: seed manual SQL hoặc manual API run + sample N-stage workflow def + Update PositionLevel cho 30 users existing). | `0d77698` |