Session 15 (2026-05-07) docs update: STATUS.md: - Last updated Session 15 (1 commit `835cc7f` tooltip + working tree drastic refactor revert) - Recently Done row Session 15 chi tiết (diagnose + plan drastic + attempt 12 file edits + REVERT decision) HANDOFF.md: - TL;DR Session 15 prepend với 2 phần: Diagnose tooltip + Drastic refactor DEFER decision - 4 cảnh báo Session 16+: Drastic refactor pending (8-10h dedicated hoặc fallback Approach Y), Task 2 sample seed pending, schema-diagram defer cron audit, Hard blockers giữ nguyên migration-todos.md: - Phase 9 + Session 15 block với 1 task done (tooltip) + 1 defer (drastic refactor) + memory entry note - Defer Session 16+ list Session log NEW `2026-05-07-2600-tooltip-defer-drastic.md`: - Bối cảnh user UAT báo button silent disabled - Phần 1 — Diagnose tooltip (root cause + fix UX + "trùng ID" KHÔNG phải bug FE) - Phần 2 — Plan drastic refactor flat workflow → DEFER: * User spec mới (Phòng × Cấp × Users[] flat) * Plan 6 chunk + estimate scope realistic ~8-10h * Attempt 12 file working tree edits → REVERT decision * Memory entry capture decision rule - Plan organization sau S15 (defer queue) Memory entry NEW `feedback_drastic_refactor_scope.md`: - Quy tắc: drastic refactor cần dedicated session, scope conservative 2x buffer - Anti-patterns mid-session big refactor + commit broken state - Defer pattern (revert working tree → document → memory entry → surface trade-off cho user) - Cross-ref `feedback_per_chunk_commit.md` discipline 🎉 Session 15 wrap-up. Cumulative since session start (13h17): 16 commit (1 button removal + 6 PE N-stage + 5 Contract N-stage + 1 3-button + 1 Session 14 wrap-up + 1 tooltip + 1 Session 15 wrap-up). Verify: dotnet test 96 pass + working tree clean. Defer Session 16+ priority order: 1. Drastic refactor flat workflow (dedicated session ~8-10h) OR fallback Approach Y (FE flat UI 5 phòng, 1-2h) 2. Task 2 sample data seed N-stage 3. Hard blockers Ops (UAT, SMTP, etc.) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
54 KiB
HANDOFF — Brief 5 phút cho session tiếp theo
Last updated: 2026-05-07 (Session 15 — Tooltip diagnose "Lưu & Gửi Duyệt" silent disabled (commit 835cc7f). Plan drastic refactor flat workflow user chốt → attempt 12 file edits Domain/Configurations, realize scope ~8-10h vượt session, REVERT clean. State 96 test pass, 20 mig.)
TL;DR Session 15 (07/05 — Tooltip diagnose + drastic refactor DEFER)
User UAT live screenshot báo button "Lưu & Gửi Duyệt" KHÔNG hoạt động + suy đoán "trùng ID" giữa các phiếu.
Diagnose (commit 835cc7f):
- Root cause: button silent disabled khi
evaluation.workflow.nextPhaseskhông có forward phase (chỉ TuChoi/TraLai). Cause khả năng: workflow definition pinned thiếu adjacent step →policy.NextPhasesFrom(DangSoanThao)return empty. - Improvement: tooltip + dialog hiển thị reason rõ ràng:
submitDisabledReasontext: "Phiếu đã ở phase X — chỉ Bản nháp/Trả lại mới sửa+gửi" / "Workflow không có phase tiếp theo từ X. Liên hệ admin kiểm tra cấu hình"- Button title attribute → hover show reason hoặc forward phase label
- Dialog confirm show forward phase explicit ("Sẽ chuyển sang Chờ Purchasing")
- Mirror fe-admin + fe-user. Build pass cả 2. KHÔNG đụng BE — chỉ FE diagnostic UX.
- "Trùng ID" KHÔNG phải bug FE —
PurchaseEvaluationWorkspacePageURL state đúng, mỗi PE row unique GUID + MaPhieu. Suy đoán user do button silent.
Plan drastic refactor → DEFER:
User confirm "bỏ phase enum hoàn toàn, dùng ChoDuyet=10 đơn nhất + currentStepIndex tracking" — refactor workflow từ phase-based + InnerStep nested model sang flat WorkflowStep model (mỗi step = Phòng × Cấp + Approvers users).
Edit working tree 12 files (Domain entities + EF Configurations + DbContext):
- Phase enum +ChoDuyet=10, legacy values 2-6 deprecated
- WorkflowStep +DepartmentId, +PositionLevel
- Drop class WorkflowStepInnerStep + nav (PE + Contract)
- PE/Contract +CurrentWorkflowStepIndex int?, +RejectedAtStepIndex int?
- *DepartmentApproval drop InnerStepId column
- EF Configurations: drop InnerStep config + nav, restore simple unique non-filtered
- DbContext: drop DbSet × 2
Reality check scope realistic ~8-10h:
- Domain + EF + DbContext (~50min) ✓ done in working tree
- PolicyRegistry rewrite PE+Contract (~45min)
- App CQRS DTOs rewrite (~45min)
- Service rewrite PE+Contract (~2-3h)
- Tests rewrite — drop 12 N-stage tests + update remaining (~1.5h)
- Migration 21 + LocalDB apply + verify (~30min)
- FE Designer rewrite (~1.5h)
- FE PeWorkflowPanel + workflow timeline (~1h)
- Docs/Skill update (~45min)
Vượt session boundary + risk session deep ~30 commits → REVERT working tree về 835cc7f clean state. Test 96 pass intact.
Decision memorized: add memory feedback_drastic_refactor_scope.md — drastic refactor cần dedicated session, scope estimation conservative (2x buffer), tránh mid-session big refactor.
⚠️ CẢNH BÁO Session 16+
- Drastic refactor flat workflow chưa làm — DEFER với plan chi tiết. Khi resume:
- Plan kỹ 6 chunk per-commit
- Buffer 2x estimate (~16h thực tế)
- Tests rewrite biggest risk
- Hoặc fall back Approach Y (FE Designer flat UI giới hạn 5 phòng) ROI 1-2h nếu user OK trade-off
- Task 2 sample data seed N-stage vẫn pending (block trên DesignTime vs Runtime DB gotcha + DbInitializer seed flow)
- schema-diagram §17-19 Mig 18-20 vẫn defer cron audit 2026-06-01
- Hard blockers Ops giữ nguyên 6 task
TL;DR Session 14 (07/05 — PE 3-button approval workflow)
User chỉ thị thay 2-button approval (Duyệt + Reject mơ hồ) bằng 3 hành động rõ ràng cho approver:
- Duyệt = forward phase tiếp theo (decision=Approve)
- Trả lại = về DangSoanThao + Drafter sửa (decision=Reject + target=DangSoanThao). Smart reject pattern Mig 16 + clear N-stage rows + Drafter resume jump-back tới phase đã reject.
- Từ chối = phase=TuChoi (decision=Reject + target=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/ChoDuAn/ChoCCM/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:if (decision == Reject) { if (target != TuChoi) { // Trả lại RejectedFromPhase = fromPhase target = DangSoanThao // force clear N-stage rows tại fromPhase } // else target=TuChoi: giữ nguyên, KHÔNG set RejectedFromPhase, KHÔNG clear } - FE PeWorkflowPanel (admin + user mirror): render 3 button rõ:
- "✓ Duyệt → " brand
- "← Trả lại (về Drafter sửa)" red khi
target=DangSoanThao && fromPhase != DangSoanThao - "✗ Hủy / Từ chối" red khi
target=TuChoi - Decision logic FE:
isReject = target=TuChoi || isSendBack
- Dialog confirm: title rõ theo loại, Cancel case warning đỏ "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 update + add 1:
- rename
Reject_Sets_RejectedFromPhase_And_Forces_DangSoanThao→Reject_To_DangSoanThao_Sets_RejectedFromPhase_TraLai(change target TuChoi→DangSoanThao) - NEW
Reject_To_TuChoi_Locks_Permanently_No_RejectedFromPhase(Phase=TuChoi + RejectedFromPhase null) - update
NStage_Reject_Clears_InnerStep_Rows_At_Phasetarget → DangSoanThao
- rename
- 95 → 96 test pass (+1 Từ chối).
Task 2 sample seed in-progress (defer Session 15+):
- Phát hiện gotcha:
DesignTimeDbContextFactoryhardcodedSolutionErp_Designconnection —dotnet ef database updatetừ session 12-13 thực ra apply lên_DesignDB, KHÔNG phải_Devruntime DB. Khi user run API → DbInitializer auto-MigrateAsync apply lên_Dev. - Đã apply Mig 9-20 lên
SolutionErp_Devquadotnet ef database update --connection. - Start API để DbInitializer auto-seed 30 demo user. API exit 255 sớm khi log buffer full (~100 lines) — seeding dở dang (chỉ seed Roles, chưa Users).
- Defer Task 2 cho session sau. Cần: user manual
dotnet runAPI 1 lần hoàn thành seed, hoặc Claude resume với output redirect to file.
⚠️ CẢNH BÁO Session 15+
-
Phase TraLai = 98 (orphan) — Domain enum đã có từ S11+++++++ nhưng KHÔNG dùng (user chốt Session 14 không cần phase trung gian, chỉ DangSoanThao + TuChoi). Để giữ enum không phá nhưng ko wire vào policy → orphan. Có thể remove migration sau (không gây hại).
-
Task 2 sample seed pending: 2 việc:
- Update
Users.PositionLevel(1=NV, 2=PP, 3=TP) cho 30 demo user đã seed (mapping email pattern:tpb./ccm./pro./fin./act./equ./hra.→ 3 (TP),pp.*→ 2 (PP),nv./qs./else → 1 (NV),bod./pm./admin./huy.duong/chau.le→ null) - INSERT N-stage WorkflowDefinition v2 cho DuyetNcc với InnerSteps (PRO + CCM × 3 cấp NV/PP/TP)
- Update
-
DesignTime vs Runtime DB distinction: dev có 2 DB:
SolutionErp_Design—dotnet ef migrations add/update(DesignTimeDbContextFactory hardcode)SolutionErp_Dev— runtime API (appsettings.Development.json) Khi muốn apply migrations lên Dev:dotnet ef database update --connection "...SolutionErp_Dev..."hoặcdotnet runAPI (DbInitializer auto-MigrateAsync).
-
Budget N-stage defer — chưa wire vì Budget chưa có versioned WorkflowDefinition. Cần migration
AddBudgetVersionedWorkflow+AddBudgetWorkflowInnerSteps. User quyết riêng (feature mở rộng module lớn). -
schema-diagram §17-19 Mig 18-20 chưa update — defer cron audit 2026-06-01.
TL;DR Session 13 (07/05 — Mirror N-stage workflow sang Contract)
User chỉ thị mirror N-stage từ PE (Mig 18+19) sang Contract. Budget defer (cần migration AddBudgetVersionedWorkflow trước — hardcoded BudgetPolicy.Default chưa có WorkflowDefinition entity).
5 chunk per-commit (Chunk E skipped — WorkflowsController auto-bind record qua [FromBody]):
- Chunk A (
951ffa3) DomainWorkflowStepInnerStep+ nav WorkflowStep.InnerSteps + ALTER ContractDeptApproval.InnerStepId + EF config + Migration 20 GỘP 1 (CREATE TABLE + ALTER + DropIndex old + Recreate filtered legacy/N-stage) - Chunk B (
04cf2a0) Application CQRS DTO/Input/Validator/Handler mirror PE Chunk B (default null backward compat) - Chunk C (
e247b67) ContractWorkflowService refactor — load InnerSteps eager + reject clear N-stage rows + dept block split hasInnerSteps→N-stage / else→legacy 2-stage - Chunk D (
7c0772a) ContractNStageApprovalTests 6 test mirror PE + helper SeedWorkflowDefinitionAsync 2 step adjacent + FakeChangelogService + FakeContractCodeGenerator stubs. 89→95 test pass - Chunk E SKIP — auto-bind no code change
- Chunk F (current) FE WorkflowsPage Designer extend InnerSteps sub-section mirror PeWorkflowsPage + Docs
Verify: dotnet build pass + dotnet ef database update Mig 20 LocalDB applied + dotnet test 95 pass + npm build fe-admin pass.
Cumulative sau Session 13:
| Trước S13 | Sau S13 | |
|---|---|---|
| BE LOC | ~15300 | ~15700 (+400) |
| Migrations | 19 | 20 (+Mig 20) |
| DB tables | 56 | 57 (+1 WorkflowStepInnerSteps) |
| DB columns mới | — | +1 (ContractDeptApproval.InnerStepId) |
| API endpoints | ~134 | ~134 (no change — auto-bind) |
| FE pages | 32 | 32 (extend existing WorkflowsPage) |
| Tests | 89 | 95 (+6 Contract N-stage) |
| Commits | (after S12) | +5 (A→F per-chunk, E skipped) |
⚠️ CẢNH BÁO Session 14+
-
Budget N-stage defer — Budget chưa có versioned WorkflowDefinition entity (hardcoded
BudgetPolicy.Default). Để mirror N-stage Budget cần migrationAddBudgetVersionedWorkflowtrước (4 bảngBudgetWorkflowDefinitions/Steps/StepApprovers/InnerSteps+Budget.WorkflowDefinitionId?). Defer cho user quyết riêng — feature mở rộng module Budget lớn. -
PE-only deploy first — Contract N-stage giờ đã có nhưng PE đã được test trước. UAT cả 2 module song song để verify pattern reusable.
-
Sample data N-stage — pending (Task 2). Khi user yêu cầu sẽ seed PositionLevel cho 30 demo user + 1 N-stage workflow definition active cho DuyetNcc + 1 cho ContractType (ví dụ HopDongThauPhu).
-
TraLai BE wire — pending (Task 4). Phase TraLai = 98 enum đã có ở Session S11+++++++ FE side, nhưng BE workflow service chưa wire button "Trả lại" cho approver. Khi user yêu cầu sẽ thêm decision
SendBack(or reuse Reject với target=TraLai) + Service logic + FE button trong Workflow Panel. -
schema-diagram §17 Mig 20 chưa update — defer cron audit 2026-06-01.
-
Skill ef-core-migration Mig 20 row chưa add — defer cron audit.
-
Skill contract-workflow N-stage cross-ref chưa add — defer cron audit.
TL;DR Session 12 (07/05 — N-stage workflow approval per phase × dept × cấp)
User yêu cầu mở rộng từ 2-stage Mig 16 sang N-stage cấu hình động: 1 phase (WorkflowStep cha) có thể cấu hình chuỗi InnerSteps con theo Department × PositionLevel sequential. Mỗi phòng có NV → PP → TP duyệt thứ tự, có thể bypass cùng dept khi role cao + CanBypassReview.
6 câu spec defaults chốt:
- Q1 enum
PositionLevel { NhanVien=1, PhoPhong=2, TruongPhong=3 }+User.PositionLevel int? - Q2 Sequential pure (Order asc, mỗi inner step = 1 cấp duyệt)
- Q3 TP có CanBypassReview → skip NV+PP cùng dept (audit IsBypassed=true cho cấp dưới)
- Q4 Smart reject về DangSoanThao + RejectedFromPhase + clear N-stage rows tại phase reject
- Q5 PE first (Contract+Budget mirror sau khi PE stable UAT)
- Q6(a) Designer UI 1 sub-section "Cấp duyệt nhỏ trong phòng" drag-list per step
6 chunk per-commit:
- Chunk A (
13ab533) Domain + Migration 18 — enum PositionLevel + entity InnerStep + ALTER User.PositionLevel + ALTER PEDeptApproval.InnerStepId + EF config Cascade/Restrict + 3-file rule - Chunk B (
0e56bd0) Application CQRS DTO — extend PeWorkflowStepDto + InnerStepDto + Validator + Handler atomic batch + UserDto +PositionLevel + SetUserPositionLevelCommand (default null backward compat existing PeWorkflowAdminTests) - Chunk C (
0c62e24) Service N-stage logic + Migration 19 filtered unique (drop UNIQUE Mig 16 → recreateWHERE InnerStepId IS NULLlegacy + newWHERE InnerStepId IS NOT NULLN-stage). Refactor TransitionAsync: load InnerSteps eager + reject clear rows + hasInnerSteps→N-stage / else→legacy 2-stage. Match firstPending Order asc, exact match upsert 1 row, bypass batch upsert NV+PP+TP audit IsBypassed - Chunk D (
3d76c6b) 6 test PE N-stage (FirstInner blocks / 3-level sequential pass / TP bypass skips / wrong dept 403 / reject clears rows / legacy fallback no inner). IdentityFixture extend +positionLevel arg. Helper SeedWorkflowDefinitionAsync 2 step adjacent. 83→89 test pass - Chunk E (
83ffabd) APIPATCH /users/{id}/position-levelmirror SetBypassReview - Chunk F (current) FE-Admin types/users.ts +positionLevel + PositionLevel const + Label/Short. PeWorkflowsPage Designer + sub-section InnerSteps drag-list { Phòng × Cấp + required } + button "+ Thêm cấp duyệt" emerald + departmentsList query + payload include. UsersPage column "Cấp" badge + cycle button. KHÔNG đụng fe-user (admin-only). Docs/Skill update.
Verify: dotnet build pass + dotnet ef database update Mig 18+19 LocalDB applied + dotnet test 89 pass + npm build fe-admin pass.
Cumulative sau Session 12:
| Trước S12 | Sau S12 | |
|---|---|---|
| BE LOC | ~14850 | ~15300 (+450 — Domain enum + entity + EF config + Service N-stage + App CQRS) |
| Migrations | 17 | 19 (+Mig 18 + Mig 19) |
| DB tables | 55 | 56 (+1 PEWorkflowStepInnerSteps) |
| DB columns mới | — | +2 (User.PositionLevel + PEDeptApproval.InnerStepId) |
| API endpoints | ~133 | ~134 (+1 PATCH /users/{id}/position-level) |
| FE pages | 32 | 32 (no change — extend existing 2 page) |
| Tests | 83 | 89 (+6 N-stage PE) |
| Commits | (after S11+++) | +6 (A→F per-chunk) |
⚠️ CẢNH BÁO Session 13+
-
N-stage chỉ áp PE first — Contract + Budget vẫn 2-stage Mig 16 cũ. Mirror sau khi UAT PE 2-3 tuần ổn (giữ pattern, lặp lại Domain entity + Service logic + Tests).
-
User.PositionLevel chưa seed cho 30 demo user hiện có — admin phải set tay qua UsersPage cycle button. Hoặc seed migration sau (mapping Position text → PositionLevel int).
-
Designer InnerSteps optional — workflow definition KHÔNG có InnerSteps fallback logic 2-stage Mig 16 cũ. Backward compat 100%. Khi muốn enable N-stage cho 1 phase: clone version + add inner steps + Save.
-
Bypass kế thừa cùng dept only — TP với CanBypassReview chỉ skip NV+PP CÙNG dept của TP. KHÔNG cross-dept (NV.A bypass không skip NV.B).
-
Reset N-stage rows khi reject — clear chỉ rows tại phase reject. Phase trung gian khác vẫn giữ approvals nếu có. Resume sẽ jump tới RejectedFromPhase + cần re-approve N-stage tại phase đó.
-
Wrong-level error message — đã localize "phòng X cấp Y không khớp". UAT user cần feedback nếu confused.
-
schema-diagram §15 Mig 18 + §16 Mig 19 chưa update — defer cho audit cron 2026-06-01 (small drift, không major).
-
Skill
ef-core-migrationMig 18+19 row chưa add — defer audit 2026-06-01.
TL;DR Session phase 2 (08/05 — B12-B14 polish iterate sau wrap-up 6e7a6db)
User UAT live tiếp tục, áp rule strict verify khi rename/remove (lesson hotfix CI 0ae3fe2).
- B12 (
378c993) PE detail polish 5 changes:- "Lưu" no-close (chỉ toast + invalidate sync, KHÔNG đóng workspace)
- "Xóa phiếu" red bottom button CHỈ Bản nháp (soft-delete IsDeleted=true)
- Bỏ header bar workspace mode "Sửa header"/"Xóa"/"Đóng" (chuyển hết xuống bottom action bar)
- Section 4 column header:
s.supplierName(master NCC name) thaydisplayName - Section 3 row chặn xóa NCC khi đã có quotes + tooltip "xóa báo giá trước"
- B13 (
e320027) InfoTab auto re-edit + pencil active visual:- useEffect watch
[autoEdit, canEdit, ev.id, ...]→ re-trigger edit khi pencil click phiếu khác - Sync values từ ev mới (tránh stale state)
- Pencil "sáng lên" active state (
bg-brand-100 + ring) khieditingRowId === p.id
- useEffect watch
- B14 (
d2306b8) QuoteDialog + winner column highlight + loading feedback:- Bỏ checkbox "Chọn NCC này cho hạng mục" (consolidate winner ở Section 2.a)
- Winner column Section 4 matrix LUÔN xanh emerald (header
✓prefix + cells full column) - QuoteDialog full overlay loading + spinner khi save có delay
- NccSelectorRow inline spinner "Đang chọn NCC + sync cột giá Section 4…"
Verify: npm run build × 2 app pass · dotnet test 83 pass (KHÔNG regression). Push gitea OK.
⚠️ CẢNH BÁO Session 12+ (cập nhật)
Bổ sung từ wrap-up trước (xem TL;DR S10-11+++++++ phía dưới):
-
isSelectedper-quote BE field — vẫn còn trong API payload nhưng UI ẩn. Nếu sau này muốn cho user chọn winner per-item (khác với winner per-phiếu) → re-enable checkbox QuoteDialog. Hiện tại chỉ gửiexisting?.isSelected ?? falseđể giữ legacy data nếu có. -
Section 4 cell winner highlight dùng
ev.selectedSupplierId === s.supplierId(per-supplier check). Nếu BE workflow có multi-winner per-item (ít khả năng), cần điều chỉnh logic. -
Loading overlay QuoteDialog chỉ áp QuoteDialog. Các dialog khác (AddSupplierDialog/EditSupplierDialog/DetailDialog) chỉ có button text feedback. Nếu UAT thấy delay → mở rộng pattern overlay sang các dialog khác.
-
InfoTab re-edit useEffect deps include 4 ev fields (tenGoiThau/diaDiem/moTa/paymentTerms). Có thể trigger re-set values nếu BE cập nhật ev (vd auto-save từ chỗ khác). Trade-off: chấp nhận để sync state. Nếu UAT thấy "values mất" → debug deps.
TL;DR Session S10-11+++++++ (07/05 — PE Workspace UX overhaul đầy đủ)
User UAT live mode iterate liên tục. Áp rule feedback_uat_skip_verify skip dotnet test sau mỗi chunk, push ngay. Lesson hotfix CI 0ae3fe2: rename/remove → BẮT BUỘC npm run build trước commit.
11 batch deliverable (23 commit total — xem STATUS Recently Done row đầu tiên cho narrative đầy đủ):
- B1 PE Thao tác 2-panel workspace (S10)
- B2 Migration 17 manual budget fields PE + HĐ (S11)
- B3 BudgetFieldRow inline editor Section 2.b
- B4 InfoTab inline edit Section 1 + PeListPanel pencil hover
- B5 Workspace "new" sectioned create view 5 sections
- B6 Danh sách view disable toàn bộ tương tác
- B7 Workspace "new" lock Loại quy trình + payment preset Select
- B8 PE display status meta (Bản nháp / Đã gửi duyệt / Trả lại / Đã duyệt / Từ chối)
- B9 Phase TraLai = 98 + pencil always visible + edit gating
- B10 Hotfix CI TS errors (forcedPhase rename + unused import)
- B11 PE detail polish — NCC selector dropdown + Section 3 winner protect + Bottom action bar Lưu/Gửi Duyệt
Stats sau wrap-up
| Trước S10 | Sau S11+++++++ | |
|---|---|---|
| BE LOC | ~14400 | ~14850 (+450 — Mig 17 + Domain TraLai + App CQRS) |
| Migrations | 16 | 17 (+1 Mig 17) |
| DB columns mới | — | +4 (PE+HĐ × Name+Amount manual budget) |
| FE pages | 31 | 32 (+1 Workspace 2-panel) |
| FE components mới | — | +5 (PeListPanel, PeHeaderForm, PeWorkspaceCreateView, BudgetFieldRow, NccSelectorRow inline) |
| PE phase enum | 8 | 9 (+TraLai = 98) |
| PE display status | — | 5 (gom phase chi tiết) |
| Tests | 83 | 83 (no test added — UAT iteration, áp rule §7 test-after defer) |
| Commits S10-S11+++++++ | — | +23 |
⚠️ CẢNH BÁO Session 12+
-
Workflow transition vào TraLai — Domain enum đã có (98), FE label/color/badge sẵn. NHƯNG chưa wire button "← Trả lại" trong PeWorkflowPanel approver view + workflow service BE chưa transition logic vào TraLai. Khi UAT cần → thêm: button "Trả lại" trong Chuyển tiếp (hoặc Reject Dialog), workflow rule
Decision=3 (TraLai)set phase=TraLai + ghiRejectedFromPhase. FE đã ready accept hiển thị TraLai phase. -
"Đã gửi duyệt" multi-phase filter — display status "Đã gửi duyệt" gom 5 phase trung gian (ChoPurchasing/ChoDuAn/ChoCCM/ChoCEODuyetPA/ChoCEODuyetNCC). BE chưa hỗ trợ multi-phase param trong list endpoint → FE filter dropdown ẩn option này (chỉ exact-match Bản nháp/Đã duyệt/Từ chối). TODO: BE thêm
?phases=2,3,4,5,6query param hoặc derivedisplayStatusfield. -
feedback_uat_skip_verifyexception — khi commit có rename/remove, BẮT BUỘCnpm run build1 lần trước push (lesson hotfix0ae3fe2). Chỉ skip verify khi pure ADD (props, JSX, new file). -
Workspace + Danh sách + Duyệt matrix:
- Workspace (Pe_*_Create): 2-panel, Section 5 disabled, edit only Bản nháp+Trả lại, pencil bright/disabled, bottom bar 2 nút Lưu/Gửi Duyệt
- Danh sách (Pe_*_List): 3-panel, readOnly=true toàn bộ (no edit/transition)
- Duyệt (Pe_*_Pending): 3-panel, PeDetailTabs readOnly + PeWorkflowPanel có Chuyển tiếp + Section 5 nhập opinion (chỗ này hiện vẫn disabled do code path cũ — verify nếu UAT user cần sign opinions ở đây)
-
Mig 17 columns nullable — backward compat OK. Cả 2 (BudgetId + manual fields) cùng null acceptable. Validation BE chưa XOR.
-
CreateContractFromEvaluation carry-forward manual fields PE→HĐ — đã wire. Verify UAT.
-
CI deploy status — sau hotfix
0ae3fe2các run từ commit4c0625ctrở đi sẽ xanh + deploy. User UAT live trên prod ngay sau push.
TL;DR Session 11++ housekeeping (07/05 — InfoTab inline edit + pencil hover)
User feedback after BudgetFieldRow: muốn thêm nút edit kế bên row trong Panel 1 list, click sáng nội dung Section 1 lên cho sửa header inline.
- ✅ InfoTab inline edit — display mode + button "✎ Sửa" góc phải Section 1. Editing mode: card border brand-200 + 4 input (Tên / Dự án locked / Địa điểm / Mô tả / Payment) + Save (PUT /pe/:id) / Hủy.
- ✅ PeListPanel pencil hover — icon absolute right-2 top-2 mỗi row, group-hover opacity-100. Click → callback onEditClick(id).
- ✅ URL flag
?editHeader=1— set bởi pencil click → autoEditHeader prop chain xuống PeDetailTabs → InfoTab tự open editing mode mount-time. - ✅ fe-admin Chunk 1 (
5a89dd2) · fe-user mirror Chunk 2 (this).
Defer (chưa làm): Refactor workspace "new" mode wrap PeHeaderForm trong sectioned layout giống detail view (5 sections visible). PeHeaderForm hiện tại single-card đủ dùng — chỉ làm thêm khi user feedback rõ.
TL;DR Session 11+ housekeeping (07/05 — inline budget editor)
User feedback after Session 11: muốn toggle + 2 fields hiển thị trực tiếp trong Section 2 "b. Ngân sách" của PeDetailTabs, không chỉ ở "Sửa header" page. Empty values cứ empty.
- ✅ BudgetFieldRow component (~125 LOC) thay FormRow tĩnh cũ ở
b. Ngân sách. canEdit=!readOnly && isDraft. Save dùng existing PUT endpoint (KHÔNG cần BE thay đổi). - ✅ fe-admin Chunk 1 (commit
19712d8) · fe-user mirror Chunk 2 (commitd5c6f12). - ✅ Verify: 2 build pass + 0 TS error.
UX:
- Workspace + Danh sách + isDraft → editable inline: toggle + Select OR 2 input + nút Lưu khi dirty
- Duyệt + !isDraft → display only (link card / manual values / "—" empty)
- Empty state: hiển thị "—" thay vì "(chưa link)" verbose (per user)
TL;DR Session 11 (07/05 — Migration 17 manual budget fields)
Output session 11 — UX improvement cho user nhập ngân sách không cần Budget entity approved:
- ✅ Migration 17
AddManualBudgetFieldsToPeAndContract— 4 ALTER (PE + HĐ × BudgetManualName nvarchar(200) + BudgetManualAmount decimal(18,2)). Applied LocalDB OK. Mirror logic PE ↔ HĐ (Q3 user chốt). - ✅ BE Domain 2 entity (PE + Contract) +2 property + EF config HasMaxLength/HasPrecision. App CQRS Create/Update commands + DTO + Validator + diff log + carry-forward CreateContractFromEvaluation pe→contract.
- ✅ FE Toggle checkbox "Nhập tay (không link)" cạnh Label Ngân sách trong 4 chỗ: PeHeaderForm (workspace + /new page wrap), ContractCreatePage NewForm + EditForm. Khi ON: hide Select, show 2 input field grid 2-col (Tên + Số tiền formatted VND). Khi OFF (default): Select Budget approved cũ. Auto-detect manual mode khi load existing có manual data + !budgetId. Display fallback ở PeDetailTabs Section 1 "b. Ngân sách" + Contract EditForm read-only branch.
- ✅ 5 chunk per-commit (build + 83 test pass mỗi chunk): C1 Domain+Infra Migration 17 (
ecd5f7e) · C2 App CQRS (0f7901c) · C3 FE-Admin (bab5031) · C4 FE-User mirror (14f8d9d) · C5 Docs (current).
Validation Q2 chốt: cả BudgetId + manual fields có thể cùng null (PE/HĐ chưa có ngân sách gì). KHÔNG XOR enforce — BE prefer link nếu có (Phase=DaDuyet guarantee), manual fallback only.
KHÔNG đụng: Budget entity / Phase=DaDuyet validation (giữ invariant "PE/HĐ link Budget approved only"). Manual fields chỉ là note/display, KHÔNG join với Budget.Details cho per-row comparison ở PE matrix Section 4 (cột "So với ngân sách" vẫn require ev.budgetId — không có detail rows để compare).
⚠️ CẢNH BÁO session tiếp (Session 12+)
- UAT manual budget flow — toggle ON/OFF + save + reload + verify auto-detect mode. Đặc biệt edit existing PE/HĐ có manual data → toggle phải auto-checked. Edit existing có Budget link → toggle auto-unchecked.
- Section 4 PE matrix "So với ngân sách" vẫn require Budget link — manual amount KHÔNG render comparison column. Document giới hạn này nếu UAT thắc mắc.
docs/database/schema-diagram.mdchưa cập nhật count 16→17 migration + 4 column mới. Defer cho audit định kỳ 2026-06-01 (per §6.4 cron) — nhỏ enough không phải selective rewrite.- CreateContractFromEvaluation đã carry forward manual fields PE→Contract. Verify khi UAT: PE có manual budget → tạo HĐ từ phiếu → HĐ inherit luôn.
- No new test added (rule §7 — feature mới = test-after, soak UAT 2-3 tuần ổn → viết happy path).
- Schema fields nullable — không phá HĐ/PE cũ (legacy null OK). Backward compatible.
TL;DR Session 10 (07/05 — PE workspace 2-panel)
Output session 10 — restructure leaf "Thao tác" PE từ page Create header riêng sang workspace 2-panel mirror HĐ Thầu phụ pattern:
- ✅ Spec chốt 5 câu trước code — Q1 Panel 2 chỉ data entry (KHÔNG Workflow/Approvals/History); Panel 1 pure picker (no inline edit/delete); Q2 mirror HĐ Thầu phụ (sticky "+ Thêm mới" + new→edit Panel 2); Q3 leaf "Danh sách" + "Duyệt" giữ 3-panel hiện tại; Q4 route mới
/workspace; Q5 Section 5 Ý kiến 4PB disable trong workspace (nhập khi duyệt). - ✅ Chunk 1 fe-admin (commit
ee0d360) — 3 file mới:PeListPanel.tsx(~180 LOC pure picker reuse-able + sticky "+ Thêm mới"),PeHeaderForm.tsx(~210 LOC extract header form từ CreatePage),PurchaseEvaluationWorkspacePage.tsx(~120 LOC 2-panel[320px_1fr]). 3 file sửa:PeDetailTabs.tsxthêm propmode?: 'detail' \| 'workspace'+ Section 5 hint amber khi workspace + forceopinionsReadOnly.Layout.tsxresolverPe_*_Create→/workspace?type=N.App.tsxroute mới. - ✅ Chunk 2 fe-user mirror (commit
ecf3c59) — 6 file y hệt content (rule §3.9 duplicate có chủ đích). - ✅ Verify: 2 build pass + dotnet test 83 vẫn pass mỗi chunk.
KHÔNG đụng BE / migration / schema / endpoint. Route /new cũ giữ tồn tại cho deep-link "Sửa header" button.
⚠️ CẢNH BÁO session tiếp (Session 11+)
- UAT live workspace với anh Kiệt + 2-3 user — feature mới UX khác (page Create cũ thành Dialog implicit qua sticky button + transition new→edit auto).
- Section 5 Ý kiến 4PB hint banner amber ở workspace mode chỉ là text gợi ý — KHÔNG block. User vẫn thấy existing opinions read-only. Nếu UAT thấy confused → có thể đổi thành collapsible section.
- Mobile: workspace KHÔNG có fallback — màn hình
<lg(< 1024px) Panel 2 ẩn (lg:block). Cần test mobile redirect →/purchase-evaluations/:idnếu UAT phát hiện. Hiện chỉ admin desktop dùng workspace. - Pe_*_Pending vẫn /purchase-evaluations?pendingMe=1 — leaf "Duyệt" 3-panel (giữ Panel 3 Workflow + readOnly Section 5 cho phép sign). UAT verify Drafter trình → TPB duyệt thấy Section 5 enable đúng.
- PE WorkflowPanel duplicate ở 2 chỗ — leaf "Danh sách" + "Duyệt" Panel 3 (3-panel). KHÔNG có ở "Thao tác" workspace. Verify route resolver active state highlight đúng (queryMatches helper từ session 3).
- Sửa header trong workspace — vẫn navigate sang
/new?id=(button "Sửa header" trong PeDetailTabs). Chưa wire inline edit qua Dialog. Nếu UAT yêu cầu → thêm proponEditHeadercho PeDetailTabs trigger Dialog reusePeHeaderForm.
Housekeeping today (sau Session 9)
- ✅ Audit định kỳ 2026-05 — combined skill + doc drift (commit
7dc0233). 5 drift patch (count 77→83 + 52→55 bảng), 1 skill content patch (contract-workflow Phase 9 cross-ref). KHÔNG tạo skill mới. Logdocs/changelog/skill-audit-2026-05.md. - ✅ Optional polish — fe-user Inbox PE section (commit
332a90f). useQuery/purchase-evaluations/inbox+ Panel 1 chia 2 section sticky header (HĐ + PE). PE click → navigate page riêng. - ✅ User Manual 7 file rewrite compact (commit
16c2c9c). User feedback "ko cần quá đầy đủ chi tiết, cho end-user họ làm". Bỏ field validation table + error troubleshoot table + FAQ chi tiết. Giữ tổng quan ngắn + numbered steps đơn giản. ~86 KB / 7 file (cũ ~123 KB ↓30%). Setuppackage.json+npm install docx@9.5.0+npm run gen:all. Lần sau sửa: edit_gen-*.js→ run gen:all.
Cron audit định kỳ: Claude SDK CronCreate auto-expire 7 days → KHÔNG fit monthly cadence. User cần setup OS Task Scheduler .bat script ping API hoặc manual trigger mỗi đầu tháng. Lần kế: 2026-06-01.
User Manual style rule (mới chốt session này): end-user docs BỎ field/error tables, FAQ chi tiết, phím tắt — GIỮ tổng quan ngắn + numbered steps + note/warn/tip critical. Phân biệt với rule §6.5 (KHÔNG cắt narrative) — đây là rule cho audience end-user, không phải agent dev đọc rationale.
TL;DR Session 9 (04/05 — Chunk E-bis sau Session 8)
Output session 9 — đóng tất cả Chunk E-bis defer từ session 8:
- ✅ FE PE WorkflowPanel — Section "Tiến trình duyệt 2-cấp phòng ban" group by phase × dept, highlight amber chờ TPB confirm, badge fuchsia bypass (cả fe-admin + fe-user).
- ✅ FE UsersPage UserManager — Column "Bypass" + button ShieldCheck toggle CanBypassReview, badge fuchsia khi enabled. UserDto thêm field.
- ✅ HĐ 2-stage logic —
ContractWorkflowServicethêm UserManager DI + mirror logic từ PE service.ContractDepartmentApprovalFeatures.csList query. EndpointGET /contracts/{id}/department-approvals. FEWorkflowHistoryPanelsection mới. - ✅ Budget 2-stage logic —
TransitionBudgetCommandHandlerthêm INotificationService + IDateTime DI + 2-stage.BudgetDepartmentApprovalFeatures.cs+ endpoint + FEBudgetWorkflowPanelsection. - ✅ 6 test PE 2-stage —
IdentityFixturesetup full Identity stack (DbContext SQLite + AddIdentityCore + AddRoles) reusable. 6 scenario: NV_Review_Blocks / TPB_Confirm_Allows / NV_Bypass / Admin_Skip / Reject_Sets / Resume_Jumps_Back. - ✅ Verify: Build pass + 83 test pass mỗi commit (54 Domain + 29 Infra: 17 codegen + 6 PE WF Application + 6 PE 2-stage).
- ✅ 5 commit pushed Gitea (E2 → E6).
⚠️ CẢNH BÁO session tiếp (Session 10+)
- UAT live ngay với anh Kiệt + 2-3 user — feature 2-stage đầy đủ cả 3 module + UX.
- Tests Contract + Budget 2-stage skipped — logic identical PE (cùng pattern, cùng entity shape). Pattern
PeTwoStageApprovalTestsreusable nếu UAT phát hiện regression riêng. - Bypass toggle audit — chưa log Changelog khi admin toggle CanBypassReview. Audit qua Identity standard column UpdatedAt only. Có thể cần thêm audit row riêng nếu UAT yêu cầu.
- Notify TPB cùng dept dùng
UserManager.GetRolesAsyncfilterDeptManager— verify production có user role DeptManager đúng (data already seeded). - fe-user KHÔNG có UsersPage — admin-only function. Bypass toggle chỉ ở fe-admin.
- 3 endpoint mới List dept-approvals PE/HĐ/Budget cùng pattern, reuse policy authz
*Read. - Cron audit định kỳ 2026-05-01 vẫn EMPTY (
No scheduled jobs). Có thể recreate khi user yêu cầu.
TL;DR Session 8 (04/05 — code lớn, 5 commit per-chunk)
TL;DR Session 8 (04/05 — code lớn, 5 commit per-chunk)
Output session 8 — đóng bug anh Kiệt + thêm 3 ràng buộc workflow:
- ✅ Migration 16
AddTwoStageDeptApprovalAndSmartReject— 4 ALTER (3 RejectedFromPhase int + Users.CanBypassReview bit) + 3 CREATE TABLE (Contract/PE/Budget DepartmentApprovalsUNIQUE (TargetId, Phase, Dept, Stage)) + 12 indexes. - ✅ Lock edit 17 handler thêm guard Phase != DangSoanThao (Contract Detail × 15 qua helper, PE Detail × 5 qua helper mới, Budget Detail × 3 inline).
- ✅ Smart reject + Resume 3 module — Reject = lưu phase nguồn + force về DangSoanThao. Resume = jump straight tới phase đã reject (skip phase trung gian, bypass policy guard).
- ✅ PE 2-stage logic trong
PurchaseEvaluationWorkflowService— TPB/CanBypass → Confirm; NV → Review only, BLOCK transition cho đến khi TPB confirm. - ✅ 3 endpoint mới:
GET /pe/{id}/department-approvals(List),PATCH /users/{id}/bypass-review(toggle), Notify TPB cùng dept khi NV review. - ✅ Verify: Build + 77 test pass mỗi commit. Migration applied LocalDB OK. Schema verified.
- ✅ 6 commit pushed (2 docs S7 + 5 code S8).
⚠️ CẢNH BÁO session tiếp (Session 9+)
- Bug fix anh Kiệt chỉ áp PE workflow. HĐ + Budget 2-stage scope DEFER cho khi UAT PE OK.
- FE Workflow Panel chưa update — workflow vẫn block đúng (BE), nhưng UX chưa hiển thị 2-stage progress. User test sẽ thấy phase không đổi mà không hiểu tại sao "stuck". Phải UAT với hint cho user trước khi code FE.
- FE UserManager toggle CanBypassReview chưa làm — tạm thời SET qua HTTP PATCH:
PATCH /api/users/{userId}/bypass-review Authorization: Bearer <admin> { "canBypassReview": true } - Test thực tế bug fix flow:
- Login
phuong.nguyen(NV.PRO, role=Procurement, DeptId=PRO) tạo phiếu PE type A - Trình DangSoanThao → ChoPurchasing
- phuong.nguyen click Duyệt phase ChoPurchasing → expect: phase KHÔNG đổi, có row Stage=Review
tra.bui(TPB.PRO, role=DeptManager) click Duyệt → expect: phase chuyển ChoCCM
- Login
- Notify TPB cùng dept dùng
UserManager.GetRolesAsyncfilterDeptManager. Best effort, fail OK. - Cron audit định kỳ 2026-05-01 đã quá hạn 3 ngày, vẫn EMPTY runtime. Cần manual trigger.
- Smart reject test: Reject phase ChoCCM → DangSoanThao + RejectedFromPhase=ChoCCM. Drafter sửa Detail + trình lại → jump straight tới ChoCCM (skip ChoPurchasing).
- Lock edit test: HĐ ở Phase=DangGopY → cố sửa Detail → expect 409 Conflict "đã trình duyệt, không thể chỉnh sửa".
TL;DR Session 6 (30/04 — không code, chỉ docs)
Output session 6 — pure docs work, không thay đổi code/test:
- ✅ Compact 3 file core: STATUS -27%, HANDOFF -32%, migration-todos -35% (-288 dòng tổng). Archive 51 row Recently Done Phase 0-7 →
changelog/recently-done-archive-2026-04.md. - ✅ Refresh 3 skill stale:
form-engine(Phase 2 MVP → Tier 3 feature-complete),permission-matrix(12 menu → ~60 + inheritance roots),ef-core-migration(24 DbSet → 52 bảng). - ✅ Rule mới §7 Timing test: 1 bảng 5-row compact — feature mới = test-after, bug = test-before, critical algorithm = test-before, spec change = update test cũ, skip 5 loại.
- ✅ Rule mới §6.4 Audit + compact MD định kỳ: cadence + checklist + anti-pattern. Cross-ref §9.4 skill audit. KHÔNG rewrite toàn bộ.
- ✅ 77 test vẫn pass (Domain 54 + Infra 23). 0 thay đổi code.
- ✅ Cron 2026-05-01 fire mai — combined audit (skill + doc drift) theo §6.4 + §9.4.
Session 5 (29/04) đóng gần hết feature gap + bật test gate:
🎯 Headline outcomes
- ✅ Budget feature-complete — FE 3-panel pages cả 2 app, BE đã sẵn từ session 4
- ✅ PE/HD ↔ Budget integration — form select Budget filter Phase=DaDuyet + Project, cột "So với ngân sách" ở PE matrix với delta indicator
- ✅ PE Detail UI restructure match form chính thức PHIẾU TRÌNH KÝ (4 section đánh số)
- ✅ PE Workflow Designer admin UI
/system/pe-workflows/:typeCodeversioned với clone/edit/+Role/+User - ✅ Ý kiến 4 phòng ban — migration 15 + section sign-off 2x2 grid (Phê duyệt/CCM/MuaHàng/SM-PM)
- ✅ Tests Phase 1-2 — 71 unit test pass + CI gate fail-fast (Domain policy + Infra code generator)
Session 4 (28/04) đã có:
A. Module Ngân sách (Budget) BE — migration 14, +4 bảng, +11 endpoint
- 4 entity:
Budget(Header) +BudgetDetail(flat row) +BudgetApproval(history) +BudgetChangelog(audit log). - Enum
BudgetPhase5 state (DangSoanThao→ChoCCM→ChoCEO→DaDuyet + TuChoi). BudgetPolicy.Defaulthardcoded simple 3-step (Drafter→CCM→CEO) — chưa versioned (TODO khi user cần admin config UI).- Mã
NS-YYYYMM-XXXXRandom.Shared (chưa atomic — TODO khi format chính thức). - Link nullable:
Contract.BudgetId?+PE.BudgetId?đã có FK + index, FE chưa wire form. - Menu seed
Budgetsroot + 3 leaf (Bg_List/Bg_Create/Bg_Pending) order=27 icon Wallet. - Application: 11 CQRS handler ~340 LOC (Create/UpdateDraft/Transition/List/GetDetail/Delete + Detail CRUD auto-recompute TongNganSach + ListChangelogs).
- Api:
BudgetsController11 endpoint REST. - FE chưa làm — Priority 0 session 5.
B. 14 demo user Solutions thật
- PRO 5 (TPB tra.bui + 4 NV) + CCM 7 (TPB ngocanh.huynh + 6 NV) + ISO 1 (chau.le) + CEO 1 (huy.duong).
- Pwd
User@123456. Reconcile pattern (gotcha #38 4-field rename). - Tổng 30 user (16 sample cũ giữ + 14 Solutions thật mới).
Tổng cumulative: 52 DB tables, ~128 endpoints, 15 migrations, 41 gotchas (+3 CI fixes), 77 unit test (+6 PE WF Application), 11+ commit session 5 push lên Gitea.
🆕 CI/CD optimize (29/04 tối)
- ✅ Manual checkout bypass github.com — fix #108/#109 transient TCP timeout 21s. Run #110 pass.
- ✅ Path filter docs-only skip —
paths-ignoretrong on:push, commit MD-only KHÔNG trigger CI (verify512880c→ no run #113). - ⏸️ npm junction cache — thử ở #111 fail
tsc not found, rollback. Cần debug session sau (gotcha #40 doc rồi). - ✅ Tests Phase 3 mini (PE Workflow Designer) — 6 test versioning logic. Total 77.
⚠️ CẢNH BÁO session tiếp (Session 7+)
- CI test gate active — code →
dotnet test SolutionErp.slnxlocal → commit → push. Test fail = NO deploy. Workflow user §7 rules.md. - Timing test rule live (§7): feature mới = test-after, bug = test-before BẮT BUỘC, critical algorithm = test-before merge, spec change = update test cũ + code chung commit.
- Doc audit cadence live (§6.4): cuối phase compact, đầu tháng cron audit, KHÔNG rewrite toàn bộ. Cron fire mai (2026-05-01) — combined skill + doc drift theo checklist.
- Login email
admin@solutionerp.local/Admin@123456— domain default chưa đổi sang@solutions.com.vn(chỉ demo user rebrand). - Chưa xóa binding cũ
.huypham.vn— vẫn fallback. Sau verify stable →.\migrate-domains.ps1 -RemoveOld -SkipCerttrên VPS. - win-acme scheduled task "unhealthy" — fix trước cert expire 2026-06-18.
- Export phiếu PDF/Excel PE — pending vô thời hạn (user nói không quan trọng).
- 3 feature mới chưa test (PE Opinion Upsert / Budget validate / Contract BudgetId carry) — đợi UAT phát sinh bug → áp rule §7 (regression test before fix). Hoặc soak 2-3 tuần ổn → viết happy path.
- G-084: VPS shared VietReport — mọi reverse proxy mới phải
127.0.0.1+ bind loopback IPv4 explicit.
⭐ Skills (.claude/skills/) — PHẢI dùng khi task khớp
| Domain (3) | Ops (3) |
|---|---|
contract-workflow — state machine + versioned WF |
dependency-audit-erp — npm/dotnet CVE scan |
form-engine — render docx/xlsx + PDF |
ef-core-migration — EF migration + 3-file rule |
permission-matrix — role × menu × CRUD |
iis-deploy-runbook — 3 site IIS + win-acme + runner |
Audit cron: 0 9 1 * * (9:00 AM ngày 1 mỗi tháng). Workflow: docs/rules.md §9.4. Lần kế: 2026-05-01.
Quy tắc: KHÔNG bulk-clone repo skill 3rd party. Chỉ skill PROJECT-SPECIFIC. Đầy đủ: docs/rules.md §9.
Ở đâu rồi?
| Phase | Trạng thái |
|---|---|
| 0 Draft | ✅ Done |
| 1 Alpha Core (foundation + đợt 2 CRUD + Permission) | ✅ Done |
| 2 Form Engine MVP + iter 2 (upload UI + .doc auto-convert + PDF export) | ✅ Done |
| 3 Workflow MVP (9 phase + code gen) + iter 2 (SLA job + attachment + notify) | ✅ Done |
| 4 Report MVP (Dashboard + Excel) + user-specific dashboard | ✅ Done |
| 5 Prep + 5.1 Security + Users Mgmt | ✅ Done |
| 5 Deploy prod (3 domain HTTPS live) | ✅ Done |
| Tier 3 (Attach + Realtime + Form builder + PDF + Versioned WF + Nested menu + Permission 3-panel) | ✅ Done |
| Skill governance (6 skill project-level + audit cron 1/tháng) | ✅ Done |
| 3-panel List/Inbox/Thao tác + sidebar accordion + UserDashboard | ✅ Done |
| 4-bảng data model (Header + 7 Details + Workflow + Changelog audit) | ✅ Done |
| Mã HĐ gen tại Create + backfill legacy | ✅ Done |
| 4 master catalogs (Units/Materials/Services/WorkItems) + datalist autocomplete | ✅ Done |
| Roles VN labels (ShortName) + Users dept/position + 13 demo users | ✅ Done |
RolesPage CRUD /system/roles + custom role admin |
✅ Done |
| 7 demo HĐ varied phases + details + comments + approvals workflow | ✅ Done |
| User-kind approver runtime guard + Warning 20% SLA | ✅ Done |
| Edit detail row inline (7 typed Update commands + EditRowDialog) | ✅ Done |
| Master expand 15 NCC + 8 Project + backfill demo HĐ diverse | ✅ Done |
Deps audit script (scripts/deps-audit.ps1) |
✅ Done |
| Module Duyệt NCC (tiền-HĐ) E2E — 10 bảng + 2 workflow + Kế thừa HĐ | ✅ Done |
| PE polish iter 2 — flat layout + per-NCC attachments + readOnly Duyệt + email rebrand | ✅ Done |
| Domain rebrand huypham.vn → solutions.com.vn — 3 subdomain + cert + CORS + FE bundle | ✅ Done |
| Module Ngân sách BE + 30 user — 4 bảng + 11 endpoint + workflow simple | ✅ Done (S4) |
| Module Ngân sách FE — 3-panel pages + Detail tabs + Workflow Panel cả 2 app | ✅ Done (S5) |
| PE/Contract → Budget integration — form Select + cột "So với ngân sách" PE matrix | ✅ Done (S5) |
PE Workflow designer admin UI /system/pe-workflows/:typeCode |
✅ Done (S5) |
| Ý kiến 4 phòng ban PE — migration 15 + section sign-off 2x2 grid | ✅ Done (S5) |
| Tests Phase 1-2 + CI gate — 71 test (Domain policy + Infra code generator) | ✅ Done (S5) |
| CI manual checkout bypass github.com + Path filter docs-only skip | ✅ Done (S5) |
| Tests Phase 3 mini — 6 test PE Workflow Designer versioning (total 77) | ✅ Done (S5) |
Export phiếu PDF/Excel PE — IDocumentConverter + template |
📝 Pending (không quan trọng) |
| Tests Phase 3 full — Application handlers (UpsertOpinion + Budget link validation, cần UserManager setup) | 📝 Pending |
| Tests Phase 4-5 — API smoke + FE Vitest | 📝 Pending (làm khi cần) |
| npm cache CI optimize (debug junction Move-Item issue #40) | 📝 Pending |
| 9+ Post-launch (E-signature, Bravo/SAP, Mobile, AI) | 📝 Future |
Run nhanh
# Terminal 1 — API (auto seed 12 role + 9 dept + 5 supplier + 3 project + 8 template + 7 workflow definition + 28 ContractType menu + 7 workflow menu)
dotnet run --project src\Backend\SolutionErp.Api
# Terminal 2 — Admin FE
cd fe-admin && npm run dev # → http://localhost:8082
# Terminal 3 — User FE
cd fe-user && npm run dev # → http://localhost:8080
Login: admin@solutionerp.local / Admin@123456
Quick sanity-check
Admin (:8082):
/dashboard→ "Của tôi" row 4 card + KPI cards + charts/contracts→ list toàn bộ, filter phase/supplier/project/contracts/new?type=5→ tạo HĐ Mua bán, pre-select type từ URL/contracts/{id}→ timeline + action dialog + attachments drag-drop + WorkflowSummaryCard/system/workflows→ 7-card landing (Thầu phụ/Giao khoán/NCC/Dịch vụ/Mua bán/NguyenTacNcc/NguyenTacDv)/system/workflows/MuaBan→ DefinitionCard active + history + "Tạo phiên bản mới" modal với Steps + Approvers (+Role / +User)/system/permissions→ 3-panel layout (Role list | Menu×CRUD matrix | Granted stats)/system/users→ Users CRUD + assign roles/forms→ upload .docx/.xlsx + render dialog Form↔JSON + Tải PDF
User (:8080):
/inbox?type=5→ HĐ Mua bán chờ role mình/my-contracts?type=2→ HĐ Thầu phụ của tôi/contracts/new?type=3→ tạo HĐ NCC- Sidebar nested: 📄 Hợp đồng → expand 7 type → expand "HĐ Mua bán" → Danh sách / Thao tác / Duyệt
Realtime check:
- Login 2 tab (admin + user) → user tạo comment / transition → admin nhận toast + bell +1
Cần làm kế tiếp
🔥 Priority 0 — Session 6 (Ops + UAT focus)
Đa số feature gap đã đóng. Còn lại chủ yếu Ops/UAT + optional polish.
A. Hard blockers (chờ user / ops):
- UAT thật 1 tuần với 2-3 user — Drafter (QS/NV.PB) + CCM + BOD ghi bug/friction
- SMTP config → bật Email outbox (BLOCKED chờ user cấp host/user/pass)
- Rotate credentials — admin + 30 demo + SA + vrapp + JWT secret
- Schedule SQL backup daily —
scripts/backup-sql.ps1chưa schedule Task Scheduler
B. PE feature gap còn lại:
- Export phiếu PDF/Excel PE — pending (user nói không quan trọng lắm). Khi cần: tái dùng
IDocumentConverter+ templatePE-TrinhDuyet.docx.
C. Optional polish (làm khi UAT phát sinh):
- Budget MaNganSach atomic sequence — chốt format → migration
AddBudgetCodeSequencesmirror Contract/PE - Budget versioned workflow — admin config UI thay hardcoded
BudgetPolicy.Default - Payment terms PE tách field — JSON blob → 6 column riêng
- Auto-map PE Details → Contract per-type Details khi gen HĐ
- Matrix Quotes bulk paste từ Excel
- fe-user Inbox thêm section "Phiếu Duyệt NCC chờ tôi"
D. Tests Phase 3-5 (làm khi gặp bug recurring để justify ROI):
- Phase 3 — Application handler tests (CQRS + EF InMemory) ~15 test
- Phase 4 — API smoke tests (WebApplicationFactory) ~7 test
- Phase 5 — FE Vitest cho lib utility (queryMatches, fmtMoney) ~10 test
Đã xong session 5 (check STATUS Recently Done):
Module Ngân sách FE — 3-panel pages cả 2 app✅PE/Contract → Budget integration + cột "So với ngân sách"✅PE Detail UI restructure 4 section đánh số✅PE Workflow Designer admin UI✅Ý kiến 4 phòng ban (migration 15)✅Tests Phase 1-2 + CI gate (71 test)✅
A. Hard blockers (chờ user / ops)
- UAT thật 1 tuần với 2-3 user — hard requirement từ roadmap. Kiến nghị:
- User A: Drafter (QS/NV.PB) — tạo 3 HĐ mỗi type, đi hết 9 phase
- User B: CCM — duyệt phase 6
- User C: BOD — duyệt phase 7
- Ghi bug / friction / đề xuất → backlog iter 2
- SMTP config để bật Email outbox:
Khi có → thêm
"Email": { "Host": "smtp.gmail.com", "Port": 587, "Username": "...", "Password": "...", "From": "noreply@solutionerp.local" }MailKit,IEmailSender, hook vàoNotificationService.CreateAsyncngay trước khi enqueue realtime push. - Rotate credentials — SA SQL password, vrapp password, JWT secret prod, Gitea runner registration token
- Schedule SQL backup —
schtasks /create /tn "SolutionErp Backup" /tr "powershell -File C:\...\scripts\backup-sql.ps1" /sc DAILY /st 03:00
A1. Định kỳ — Skill audit
Cadence: Mỗi đầu tháng (4 tuần). Lần audit kế tiếp: 2026-05-01.
Workflow xem docs/rules.md §9.4. Tóm tắt:
- Cross-check 6 skill hiện có với STATUS / gotchas / migration-todos
- Check repo nguồn 3rd party (alirezarezvani/claude-skills) có gì mới
- Update / archive / add skill nếu cần
- Log vào
docs/changelog/skill-audit-2026-05.md
Trigger: user nói "audit skill" hoặc tự chạy đầu Phase mới.
B. Polish iterations (optional — khi UAT phát sinh)
- Roles CRUD — admin tạo custom role ngoài 12 hardcoded (
Domain.Identity.AppRoles) - User-kind approver runtime — data model
WorkflowStepApprover.Kind=User+AssignmentValue=userIdđã có, chỉ cần:// ContractWorkflowService.TransitionAsync (bổ sung): var userApprovers = step.Approvers.Where(a => a.Kind == ApproverKind.User) .Select(a => Guid.Parse(a.AssignmentValue)); if (userApprovers.Any() && !userApprovers.Contains(actorUserId)) throw new ForbiddenException(); - Grant
Workflows.Readcho non-admin role trong PermissionsPage → menu Wf_* auto-visible (inheritance đã có) - Warning notification 20% SLA — job emit khi
SlaDeadline - now < sla * 0.2 && !SlaWarningSent, set flag - Reject → DangSoanThao E2E test với 3 role khác nhau
- Deps scan CI —
dotnet list package --vulnerable+npm audit --audit-level=high
C. Non-goals / parked
- E-signature (VNPT CA / FPT CA) — Phase 6
- Bravo/SAP import NCC — Phase 6
- Mobile app — Phase 6
- AI OCR scan HĐ — Phase 6+
Lưu ý kỹ thuật quan trọng
Đọc gotchas.md (41 bẫy) trước khi:
- Thêm package mới → .NET 10 compat (MediatR 14 fail → dùng 12.4.1)
- Debug TS enum error → dùng const-object pattern (
erasableSyntaxOnly) - Expression tree lỗi → tách switch ra ngoài LINQ
- Deploy Windows Feature (WebSockets, etc.) → unlock section ở applicationHost (gotcha #25)
- Workflow transition 403 → check
Contract.WorkflowDefinitionIdpin đúng không - Migration lỗi → 3 file đầy đủ (Designer + Migration + Snapshot)
Versioned workflow — quick ref
Contract.WorkflowDefinitionId pin tại Create. ContractWorkflowService.LoadAsync resolve order: pinned def → admin override → hardcoded Registry.For(type). Invariant: HĐ cũ giữ policy cũ qua FK Restrict. Detail: workflow-contract.md §7bis.
File đang active
Cấu trúc thư mục + file map: PROJECT-MAP.md. Git state: git log --oneline -10.
Credentials + URLs
admin@solutionerp.local / Admin@123456 ← Admin (QTV)
Demo users — 30 user (User@123456):
── 16 sample @solutionerp.local (giữ cho test legacy) ──
bod.huynh, bod.le Tổng GĐ + Phó GĐ NĐUQ
pm.nguyen GĐ Dự án FLOCK 01 (PM)
ccm.tran, pro.pham, fin.do TPB CCM/PRO/FIN
act.vu, equ.bui, hra.dang Kế toán trưởng / TPB EQU / TPB HRA
qs.hoang, qs.ngo QS công trường (NV.PB)
nv.cao, nv.dinh, nv.truong NV Cung ứng/Tài chính/CCM (NV.PB)
bod.tran, pm.le Bonus NĐUQ + PM thứ 2
── 14 Solutions thật @solutions.com.vn (session 4) ──
PRO 5: tra.bui (TPB) + phuong.nguyen, binh.lethanh, danh.huynh, dat.tran (NV)
CCM 7: ngocanh.huynh (TPB) + ha.dao, cuong.do, long.le, ha.nguyen,
dung.nguyen, anh.nguyen (NV)
ISO 1: chau.le
CEO 1: huy.duong
⚠ Rotate ALL passwords trước UAT thật
- API prod: https://api.solutions.com.vn —
/health/live,/health/ready - Admin FE prod: https://admin.solutions.com.vn
- User FE prod: https://eoffice.solutions.com.vn
- API dev: http://localhost:5443 —
/swagger(Dev only) - Admin FE dev: http://localhost:8082
- User FE dev: http://localhost:8080
- SQL dev:
(localdb)\MSSQLLocalDB/SolutionErp_Dev - SQL prod:
.\SQLEXPRESS/SolutionErp/vrapp(⚠️ rotate)
Đánh giá nhanh
Tốt:
- 3 domain HTTPS prod live, CI/CD xanh
- Tier 3 feature-complete: attachment, realtime, form builder (upload + DynamicForm + PDF), versioned workflow (admin-configurable per ContractType, pin per contract), nested menu per type, 3-panel permissions
- Clean-arch 3-project split đúng cho 2 cross-cutting service (realtime + document-converter)
- 26 gotchas tích lũy, 8 session log, 40 docs — agent onboard nhanh
- Invariant critical: "HĐ cũ giữ quy trình cũ" guaranteed by pinning (reference-based immutability, không snapshot copy)
Rủi ro còn:
- UAT thật chưa chạy → có thể phát hiện edge case missing
- SMTP chưa có → notification chỉ in-app (toast + bell), không email
- User-kind approver chưa enable guard runtime (designer cho pick, nhưng transition dùng Role fall-back)
- Credentials chưa rotate
- SQL backup chưa schedule Task Scheduler