Commit Graph

310 Commits

Author SHA1 Message Date
14f8d9d808 [CLAUDE] FE-User: PE + HĐ toggle "Nhập tay" + 2 fields manual budget mirror fe-admin
Chunk 4/5 — mirror y hệt Chunk 3 sang fe-user (rule §3.9 duplicate có chủ đích).

Files:
  ~ fe-user/src/types/purchaseEvaluation.ts — PeDetailBundle +2 field
  ~ fe-user/src/types/contracts.ts — ContractDetail +2 field
  ~ fe-user/src/components/pe/PeHeaderForm.tsx (copy từ fe-admin)
  ~ fe-user/src/components/pe/PeDetailTabs.tsx — Section "b. Ngân sách"
    fallback display khi !ev.budget + có manual data
  ~ fe-user/src/pages/pe/PurchaseEvaluationCreatePage.tsx (copy refactor wrap)
  ~ fe-user/src/pages/contracts/ContractCreatePage.tsx — toggle pattern cho
    NewContractForm + EditContractForm (giống fe-admin)

Verify: npm run build fe-user pass · 1904 modules · 0 TS error.

Next: Chunk 5 docs + push.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 12:40:29 +07:00
bab503189a [CLAUDE] FE-Admin: PE + HĐ toggle "Nhập tay" + 2 fields manual budget (Mig 17)
Chunk 3/5 — UI cho manual budget fallback Mig 17. Toggle checkbox "Nhập tay
(không link)" cạnh Label Ngân sách. Khi ON: hide Select Budget, show 2 input
field grid 2-col (Tên tham chiếu text + Số tiền number formatted VND).

Files sửa:
  ~ fe-admin/src/types/purchaseEvaluation.ts — PeDetailBundle +2 field
  ~ fe-admin/src/types/contracts.ts — ContractDetail +2 field
  ~ fe-admin/src/components/pe/PeHeaderForm.tsx — toggle + 2 input + payload
    conditional (manual mode → clear budgetId, link mode → clear manual). Auto-
    detect manual mode khi load existing PE có manual data + !budgetId.
  ~ fe-admin/src/components/pe/PeDetailTabs.tsx — Section 2 "b. Ngân sách"
    fallback display khi !ev.budget + có manual data: render text "Tên · Số tiền"
    + badge "nhập tay" thay vì "(chưa link)".
  ~ fe-admin/src/pages/pe/PurchaseEvaluationCreatePage.tsx — refactor wrap
    PeHeaderForm để DRY (auto-inherit toggle pattern, không drift). 222 LOC → 30 LOC.
  ~ fe-admin/src/pages/contracts/ContractCreatePage.tsx — apply same toggle
    pattern cho cả NewContractForm + EditContractForm. EditForm thêm read-only
    display branch khi !isDraft + có manual data.

Verify: npm run build fe-admin pass · 1922 modules · không TS error.

Next: Chunk 4 fe-user mirror (PeHeaderForm + PeDetailTabs + ContractCreatePage
+ types).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 12:37:42 +07:00
0f7901c19f [CLAUDE] App: PE + Contract Create/Update commands + DTO add manual budget fields
Chunk 2/5 — wire 2 field mới (BudgetManualName + BudgetManualAmount) qua tất cả
CQRS commands + handlers + DTOs cho cả PE và HĐ. Mirror logic per Q3 user.

Files sửa:
  ~ Application/PurchaseEvaluations/PurchaseEvaluationFeatures.cs
    - CreatePurchaseEvaluationCommand record +2 param
    - Validator: MaximumLength(200) + GreaterThanOrEqualTo(0)
    - Handler: wire entity
    - UpdatePurchaseEvaluationDraftCommand record +2 param + handler wire
    - GetPurchaseEvaluationQuery → DTO mapping +2 field
  ~ Application/PurchaseEvaluations/Dtos/PurchaseEvaluationDtos.cs
    - PurchaseEvaluationDetailBundleDto +2 field (BudgetManualName/Amount)
  ~ Application/PurchaseEvaluations/CreateContractFromEvaluationFeatures.cs
    - Carry forward pe.BudgetManualName/Amount → contract khi gen HĐ từ phiếu
  ~ Application/Contracts/ContractFeatures.cs
    - CreateContractCommand record +2 param + Validator + Handler
    - UpdateContractDraftCommand record +2 param + Handler (diff log thêm 2 field)
    - ContractDetailDto mapping +2 field
  ~ Application/Contracts/Dtos/ContractDtos.cs
    - ContractDetailDto +2 field

Validation Q2 chốt: cả 2 cùng null OK. Manual amount có thể null hoặc >= 0.
KHÔNG XOR với BudgetId (BE prefer link BudgetId nếu set, manual fallback only).

Controllers KHÔNG đụng (FromBody bind JSON → record record optional fields gen
auto null cho legacy callers — backward compat).

Verify: dotnet build pass · dotnet test SolutionErp.slnx 83 pass.

Next: Chunk 3 FE-Admin toggle + 2 fields PeHeaderForm + ContractHeaderForm.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 12:34:00 +07:00
ecd5f7e9d9 [CLAUDE] Domain+Infra: Migration 17 — manual budget fields cho PE + HĐ
Chunk 1/5 — DB schema + Domain layer cho fallback "user nhập số tiền ngân sách
tay khi chưa link Budget entity" (UAT request 2026-05-07). Áp cho cả PE + HĐ
(mirror logic per user Q3 chốt).

Migration 17 `AddManualBudgetFieldsToPeAndContract` — 4 ALTER:
  - PurchaseEvaluations.BudgetManualName  nvarchar(200) NULL
  - PurchaseEvaluations.BudgetManualAmount decimal(18,2) NULL
  - Contracts.BudgetManualName            nvarchar(200) NULL
  - Contracts.BudgetManualAmount          decimal(18,2) NULL

Validation Q2: cả 2 cùng null OK (PE/HĐ chưa có ngân sách gì cả). KHÔNG XOR
với BudgetId — tạm thời cho phép cả 2 cùng có (BE prefer BudgetId nếu set vì
có Phase=DaDuyet guarantee, manual chỉ là fallback hiển thị/note).

Files:
  ~ Domain/PurchaseEvaluations/PurchaseEvaluation.cs — 2 property mới
  ~ Domain/Contracts/Contract.cs — 2 property mới
  ~ Infrastructure/Persistence/Configurations/PurchaseEvaluationConfiguration.cs
    — HasMaxLength(200) + HasPrecision(18,2)
  ~ Infrastructure/Persistence/Configurations/ContractConfiguration.cs — same
  + Migration 17 .cs + .Designer.cs (3-file rule per ef-core-migration skill)
  ~ ApplicationDbContextModelSnapshot.cs (auto-overwrite)

Verify:
  - dotnet ef migrations add → 3 file gen sạch (4 AddColumn Up + 4 DropColumn Down)
  - dotnet ef database update → applied LocalDB OK
  - dotnet test SolutionErp.slnx → 83 pass (54 Domain + 29 Infra) — không regression

Next: Chunk 2 App CQRS Create/Update commands + DTO + AutoMapper.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 12:30:59 +07:00
d04bd88fbe [CLAUDE] Docs: tick migration-todos Phase 9 — Session 10 PE workspace 2-panel
Add Session 10 done block với 4 task tick (Chunk 1 fe-admin / Chunk 2 fe-user
mirror / Chunk 3 docs / Verify), reference 3 commit SHA. Phase 9 active
section nối tiếp Session 9+ housekeeping pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 10:40:55 +07:00
7e3cfa580a [CLAUDE] Docs: chốt session 10 — PE Thao tác 2-panel workspace + session log
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m19s
Chunk 3/3 — close session log + STATUS Recently Done + HANDOFF TL;DR Session 10
+ cảnh báo Session 11+. KHÔNG update skill (per §9.5 anti-pattern: không drift
đáng audit, chỉ FE refactor pure).

Files:
  ~ docs/STATUS.md        — Last updated + Recently Done row + FE pages 31→32
  ~ docs/HANDOFF.md       — TL;DR Session 10 prepend + 6 cảnh báo + giữ S9 narrative
  + docs/changelog/sessions/2026-05-07-2100-pe-workspace-2panel.md

Validation per §6.5: KHÔNG cắt narrative cũ, KHÔNG paraphrase. Chỉ thêm row
mới + section TL;DR mới phía trên các section cũ.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 10:40:09 +07:00
ecf3c5945b [CLAUDE] FE-User: PE Thao tác 2-panel workspace mirror fe-admin
Chunk 2/3 — mirror y hệt Chunk 1 sang fe-user (rule §3.9 duplicate có chủ đích
giữa 2 app — copy + sync tay khi breaking).

Files (cùng diff Chunk 1, content identical):
  + fe-user/src/components/pe/PeListPanel.tsx
  + fe-user/src/components/pe/PeHeaderForm.tsx
  + fe-user/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx
  ~ fe-user/src/components/pe/PeDetailTabs.tsx — add mode prop + Section 5 hint
  ~ fe-user/src/components/Layout.tsx — resolver Pe_*_Create map workspace
  ~ fe-user/src/App.tsx — route /purchase-evaluations/workspace

Verify: npm run build (fe-user) pass. dotnet test 83 không bị ảnh hưởng (đã
verify Chunk 1).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 10:37:52 +07:00
ee0d3608e7 [CLAUDE] FE-Admin: PE Thao tác 2-panel workspace + Panel 1 read-only picker + Section 5 disabled
Chunk 1/3 — restructure leaf "Thao tác" (Pe_*_Create) từ page tạo header riêng
sang workspace 2-panel mirror pattern HĐ Thầu phụ ContractCreatePage:
  Panel 1 (320px): list pure picker (KHÔNG inline edit/delete per Q1 user) +
                   sticky "+ Thêm mới" bottom button.
  Panel 2 (1fr):   empty state | mode=new <PeHeaderForm> | <PeDetailTabs
                   mode="workspace"> (5 section, Section 5 Ý kiến 4PB DISABLED
                   per Q5 user — nhập ở leaf "Duyệt").

Workflow Panel + Approvals + History KHÔNG render trong workspace (Q1) — chỉ
hiện ở leaf "Danh sách" + "Duyệt" giữ nguyên 3-panel hiện tại (Q3).

URL: /purchase-evaluations/workspace?type={1|2}[&id=...][&mode=new][&q=][&phase=]
Menu resolver Pe_*_Create: /purchase-evaluations/new?type=N → /workspace?type=N.
Route mới /workspace; route /new giữ tồn tại cho deep-link "Sửa header" button.

Files:
  + fe-admin/src/components/pe/PeListPanel.tsx (~180 LOC) — pure picker reuseable
  + fe-admin/src/components/pe/PeHeaderForm.tsx (~210 LOC) — extract header form
  + fe-admin/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx (~120 LOC)
  ~ fe-admin/src/components/pe/PeDetailTabs.tsx — add mode prop + Section 5 hint
  ~ fe-admin/src/components/Layout.tsx — resolver Pe_*_Create map workspace
  ~ fe-admin/src/App.tsx — route /purchase-evaluations/workspace

Verify: npm run build pass · dotnet test 83 vẫn pass (54 Domain + 29 Infra).
fe-user mirror = Chunk 2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 10:36:06 +07:00
b7a153e45a [CLAUDE] Docs: chốt session 9+ housekeeping log + STATUS+HANDOFF+migration-todos update
Session log mới `2026-05-04-1900-chot-session-9-plus-housekeeping.md`:
chốt 4 commit Session 9+ post-Session-9 (Audit 2026-05 + Inbox PE +
Housekeeping docs + User Manual 7 file rewrite). Full narrative
+ context + lessons + stats + cảnh báo session 10+.

STATUS Recently Done +1 row mới (User Manual rewrite 16c2c9c) +
Phase header refresh "Session 9+ chốt" + "7 file User Manual ~86 KB
compact end-user style".

HANDOFF Housekeeping section +1 mục User Manual rewrite + thêm note
"User Manual style rule mới chốt session này": phân biệt với §6.5
(end-user docs vs dev docs).

migration-todos thêm section "Session 9+ housekeeping done" với 3
task tick (audit + Inbox PE + User Manual).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 20:44:28 +07:00
16c2c9c79e [CLAUDE] Docs: User Manual 7 file rewrite compact cho end-user
User feedback: "ko cần quá đầy đủ chi tiết, cho end-user họ làm".

Rewrite 7 generator scripts theo style end-user friendly:
- Bỏ field validation table 5 cột (Tên field / Kiểu / Bắt buộc / Validation / Ví dụ)
- Bỏ error troubleshoot table 3 cột (Lỗi / Nguyên nhân / Cách xử lý)
- Bỏ FAQ chi tiết 8 câu (giữ 1 chương "Khi gặp lỗi" 4-5 bullet)
- Bỏ phím tắt table
- Giữ: tổng quan ngắn, numbered steps đơn giản, note/warn/tip chỉ khi critical

7 file generator (đã refactor dùng _helpers.js shared):
- _gen-user-01: Bắt đầu (login + đổi pwd + hồ sơ + dashboard + sidebar + chuông)
- _gen-user-02: Hợp đồng (7 loại + tạo + sửa + xóa + đính kèm + comment)
- _gen-user-03: Duyệt Workflow (9 phase + 2-stage NV/TPB + reject + resume)
- _gen-user-04: Phiếu Duyệt NCC (PE) (A/B + matrix báo giá + winner + 4PB + tạo HĐ)
- _gen-user-05: Ngân sách (tạo + hạng mục + WF 3-step + liên kết HĐ/PE)
- _gen-user-06: Cheatsheet 7 loại HĐ (mỗi loại 1 page: use case + field + format mã)
- _gen-admin-02: Quản lý Users-Roles (tạo + role + reset + lock + bypass review S9)

Setup: package.json + npm install docx@9.5.0 + script "gen:all".

Output sizes:
- 01: 12.1 KB (cũ 21.7 KB → giảm ~44%)
- 02: 12.4 KB
- 03: 12.2 KB
- 04: 12.4 KB
- 05: 12.0 KB
- 06: 12.8 KB
- admin-02: 12.7 KB
- Tổng ~86 KB cho 7 file đầy đủ chức năng cốt lõi.

Note: ContractType label "Phương án" → "Giải pháp" (đã rebrand session 3).
2-stage dept approval mention ở Phần 03 + admin-02 (Migration 16 Session 8/9).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 17:06:01 +07:00
bdd175c07b [CLAUDE] Docs: housekeeping reflect audit 2026-05 + Inbox PE section done
STATUS Recently Done +2 row mới (audit 7dc0233 + Inbox PE 332a90f),
section F audit định kỳ tick 2026-05-01 done + ghi cron Claude SDK
KHÔNG fit monthly cadence (auto-expire 7d) → user setup OS Task
Scheduler nếu cần auto-remind. Next audit 2026-06-01 manual.

HANDOFF +1 section "Housekeeping today" tóm tắt 2 commit hôm nay sau
Session 9 close. Cảnh báo cron limitation ngắn cho session sau.

migration-todos Phase 9 §C tick "fe-user Inbox PE section" done với
commit hash + summary 1 line. 5 optional polish khác giữ pending.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 15:59:49 +07:00
332a90f601 [CLAUDE] FE-User: Inbox thêm section Phiếu Duyệt NCC chờ tôi
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m31s
Optional polish (HANDOFF §C — "khi UAT phát sinh"). Drafter + TPB sẽ thấy
HĐ + Phiếu PE pending cùng InboxPage thay vì phải vào /purchase-evaluations
riêng.

Changes:
- useQuery thứ 2 cho /purchase-evaluations/inbox (endpoint đã sẵn)
- peRows filter theo search query (mã / tên gói thầu / project)
- Stats overdue/dueSoon đếm cả PE rows. totalValue chỉ HĐ (PE không có giá trị).
- Panel 1 chia 2 section sticky header:
  - "Hợp đồng (N)" — giữ behavior cũ, click → inline detail Panel 2
  - "Phiếu Duyệt NCC (M)" — click → navigate /purchase-evaluations/:id
    (page riêng, không inline vì PE entity shape khác Contract)
- EmptyState mới: "Không có HĐ hoặc Phiếu Duyệt NCC nào chờ"

Note: chỉ fe-user (đối tượng dùng Inbox), fe-admin có /system/inbox riêng
nếu cần — defer.

Build: fe-user pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 15:57:24 +07:00
7dc0233f08 [CLAUDE] Docs+Skill: audit định kỳ 2026-05 — 6 file patch + 1 log page
Combined audit (skill staleness + doc drift) theo §6.4 + §9.4. Cron 2026-05-01 trễ 4 ngày (cron empty), chạy manual 2026-05-04 sau Session 9 close Chunk E-bis.

Drift patched (Phase 1 — count cross-check):
- docs/CLAUDE.md:70    52 bảng → 55 bảng (+§14 DepartmentApprovals Mig 16)
- docs/rules.md:368    Phase 8 active — 77 test → Phase 9 — 83 test
- docs/architecture.md:329, 365   77 test → 83 test (2 chỗ)
- .claude/skills/ef-core-migration/SKILL.md:52    77 test → 83 test + ghi 6 PE 2-stage S9
- .claude/skills/dependency-audit-erp/SKILL.md:153    26+ bẫy → 41 bẫy

Skill content patch (Phase 2 — staleness):
- contract-workflow: thêm "Phase 9 cross-ref (Mig 16)" block + section "Phase 9 done" (2-stage dept approval + smart reject + lock edit + CanBypassReview)
  → KHÔNG tạo skill 2-stage riêng (§9.5 anti-pattern "viết skill chỉ để có thêm")

KEEP per §6.5 (không cắt narrative):
- docs/rules.md:328 "52 bảng" example minh họa rule §6.5
- docs/changelog/migration-todos.md:152, 196 historical session record
- 9 session log mention 77/52 — snapshot lịch sử

Total patches: 6 file ~+30 / ~12 lines, KHÔNG rewrite, đáp ứng 3 câu validation §6.5.

Audit log: docs/changelog/skill-audit-2026-05.md (1 page max per cadence).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 15:53:51 +07:00
b431c8f68d [CLAUDE] Docs: Chunk E7 — chốt session 9 Chunk E-bis complete
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m7s
- STATUS: Recently Done +1 row session 9 (5 commit per-chunk + 83 test). Phase 9
  header update count 77→83. Section E (Chunk E-bis) tick toàn bộ done.
- HANDOFF: TL;DR session 9 + Cảnh báo session 10. Giữ session 8 narrative cũ.
- migration-todos: Phase 9 +1 section "Session 9 done" với 5 task tick. Pending
  Chunk E-bis tick chuyển done.
- CLAUDE.md (root + docs): test count 77 → 83 (54 Domain + 29 Infra:
  17 codegen + 6 PE WF Application + 6 PE 2-stage approval).
- Session log mới: 2026-05-04-1700-chot-session-9-chunk-e-bis-complete.md
  (full narrative + lessons + stats theo §6.5 KEEP rule).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:56:38 +07:00
8353fe87c0 [CLAUDE] Tests: Chunk E6 — 6 test 2-stage approval (PE) + IdentityFixture helper
Đóng "Tests Phase 3 mini cần UserManager DI helper" defer từ session 8.

IdentityFixture (Common/IdentityFixture.cs):
- Setup ServiceProvider với Identity stack đầy đủ:
  - DbContext SQLite shared connection
  - AddIdentityCore<User> + AddRoles<Role> + AddEntityFrameworkStores
- Single shared scope cho fixture lifetime → DbContext + UserManager đồng instance
- Helper CreateUserAsync(email, name, deptId, roles, canBypassReview)
- Note: dùng Role custom (không phải IdentityRole<Guid>) để match
  ApplicationDbContext : IdentityDbContext<User, Role, Guid>

6 test PE 2-stage logic (Services/PeTwoStageApprovalTests.cs):
- NV_Review_Blocks_Phase_Transition (đóng bug anh Kiệt — chính xác)
- TPB_Confirm_After_NV_Review_Allows_Transition (happy path 2-stage)
- NV_With_BypassReview_Allows_Transition_With_IsBypassed_True (bypass NV)
- Admin_Skips_TwoStage_Logic_Entirely (admin bypass)
- Reject_Sets_RejectedFromPhase_And_Forces_DangSoanThao (smart reject)
- Resume_After_Reject_Jumps_Back_To_RejectedPhase (jump-back logic)

Stub FakeNotificationService — best effort path không cần verify.

Note: tests cho Contract + Budget 2-stage skip — logic identical PE, ROI thấp.
Pattern PeTwoStageApprovalTests reusable nếu cần test riêng tương lai.

Total: 54 Domain + 29 Infra (17 codegen + 6 PE WF Application + 6 PE 2-stage)
= **83 test pass** (+6 mới).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:52:43 +07:00
1fc439b978 [CLAUDE] App+Api+FE: Chunk E5 — Budget 2-stage dept approval (mirror PE/Contract)
Budget complete the trifecta — đồng bộ pattern 2-stage cho 3 module
(Contract + PE + Budget) cùng UX cho user khi UAT.

BE App:
- TransitionBudgetCommandHandler thêm INotificationService + IDateTime DI
- Mirror logic 2-stage từ ContractWorkflowService:
  - actor.DepartmentId != null + KHÔNG admin/system + KHÔNG resume
    - DeptManager (TPB) hoặc CanBypassReview → Stage=Confirm
    - Else (NV) → Stage=Review only, BLOCK transition
  - Upsert BudgetDepartmentApproval (UNIQUE BudgetId+Phase+Dept+Stage)
  - Block khi !hasConfirm: insert Approval + Changelog + Notify TPB → return early
- BudgetDepartmentApprovalFeatures.cs (List query mirror PE/Contract)

Api:
- BudgetsController endpoint GET /budgets/{id}/department-approvals

FE (cả fe-admin + fe-user):
- types/budget.ts thêm ApprovalStage const + BudgetDepartmentApproval type
- BudgetWorkflowPanel section "Tiến trình duyệt 2-cấp phòng ban":
  - Group by phase × dept, show Review NV + Confirm TPB
  - Highlight amber "chờ TPB confirm" + badge fuchsia bypass

Note: low-priority cho Budget (ít user duyệt budget per dept) nhưng giữ
consistent UX 3 module.

Build: BE pass + FE pass cả 2 + 77 test pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:46:56 +07:00
b6f5a16420 [CLAUDE] Infra+App+Api+FE: Chunk E4 — HĐ 2-stage dept approval (mirror PE)
Mở rộng 2-stage logic từ PE sang Contract workflow (Migration 16 đã có schema):

BE Service:
- ContractWorkflowService thêm UserManager<User> DI
- Mirror logic 2-stage từ PurchaseEvaluationWorkflowService.TransitionAsync
  Sau policy guard, trước gen mã HĐ:
  - User.DepartmentId != null + actor không admin/system + KHÔNG resume
    - DeptManager (TPB) → Stage=Confirm trực tiếp
    - CanBypassReview=true → Stage=Confirm + IsBypassed=true
    - Else (NV) → Stage=Review only, BLOCK transition
  - Insert ContractDepartmentApproval row (UPSERT theo UNIQUE)
  - Block transition khi chưa có Stage=Confirm:
    - Insert ContractApproval (FromPhase=ToPhase=fromPhase, [Review NV] comment)
    - Insert ContractChangelog "đã review, chờ TPB confirm"
    - Notify TPB cùng dept (UserManager filter DeptManager role)
    - Return early — phase KHÔNG đổi

App + Api:
- ContractDepartmentApprovalFeatures.cs (List query mirror PE)
- ContractsController endpoint GET /contracts/{id}/department-approvals

FE (cả fe-admin + fe-user):
- types/contracts.ts thêm ApprovalStage const + ContractDepartmentApproval type
- WorkflowHistoryPanel section "Tiến trình duyệt 2-cấp phòng ban":
  - Group by phase × dept, show Review NV + Confirm TPB
  - Highlight amber "chờ TPB confirm" khi current phase có Review chưa Confirm
  - Badge fuchsia "bypass" khi NV.CanBypassReview=true
  - Insert giữa WorkflowSummaryCard và Lịch sử duyệt
- Mirror cả 2 app (rule §3.9)

Use case mirror PE: HĐ ở phase DangGopY (P.CCM) — nv.cao (NV) duyệt thì
phase KHÔNG đổi (Review only), chờ ccm.tran (TPB) confirm mới sang DangXetDuyet.

Build: BE pass + FE pass cả 2 + 77 test pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:43:05 +07:00
4380bdc075 [CLAUDE] App+FE-Admin: Chunk E3 — UserManager toggle CanBypassReview
Admin UI bật/tắt CanBypassReview per user (Migration 16):
- BE: UserDto thêm field CanBypassReview (List + Get queries)
- FE: User type thêm canBypassReview field
- UsersPage: column "Bypass" badge fuchsia khi true + button toggle ShieldCheck
  (icon highlight fuchsia khi enabled, slate khi disabled)
- bypassMut PATCH /users/{id}/bypass-review { canBypassReview: !current }

Use case: phòng ban không có TPB hoặc TPB ủy quyền cho 1 NV cụ thể —
NV được Stage=Confirm trực tiếp (skip Stage Review), IsBypassed=true ghi audit.

Endpoint backend đã có sẵn ở Chunk E1 (commit 3c49316). Chỉ wire FE.

fe-user KHÔNG có UsersPage (admin-only function) — chỉ update fe-admin.

Build: BE pass + FE-admin pass + 77 test pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:38:09 +07:00
f8eebd57d1 [CLAUDE] FE-Admin+FE-User: Chunk E2 — 2-stage dept approval timeline panel (PE)
FE Workflow Panel hiển thị progress 2-cấp duyệt phòng ban (Migration 16):
- Section "Tiến trình duyệt 2-cấp phòng ban" trong PeWorkflowPanel
- Group rows by Phase × Department, show Stage Review NV + Confirm TPB
- Highlight amber "chờ TPB confirm" khi current phase có Review nhưng chưa Confirm
- Badge fuchsia "bypass" khi NV được CanBypassReview
- useQuery fetch endpoint GET /pe/{id}/department-approvals
- Invalidate query sau transition để refresh ngay

Type mới: ApprovalStage const + PeDepartmentApproval DTO trong types/purchaseEvaluation.ts.

User flow anh Kiệt test:
- phuong.nguyen (NV.PRO) Duyệt phase ChoPurchasing
  → row Review xuất hiện, panel hiển thị " chờ TPB confirm" (amber)
- tra.bui (TPB.PRO, DeptManager) Duyệt
  → row Confirm xuất hiện (emerald) + phase chuyển sang ChoCCM

2 file đồng bộ giữa fe-admin + fe-user (rule §3.9 duplicate có chủ đích).

Build: cả 2 FE pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:35:34 +07:00
d206e14550 [CLAUDE] Docs+Skill: chốt session 8 ending — patch count drift + skill refresh
Session 8 ending workflow theo template (kết thúc lúc ~13:00).

Patch drift count post Migration 16:
- docs/architecture.md §1: "(dbo schema, 19 bảng)" → 55 bảng
  (drift cũ session 6 chưa fix, giờ fix luôn)
- docs/database/schema-diagram.md §8 Migration history: thêm row 16
  AddTwoStageDeptApprovalAndSmartReject + Tổng 52 → 55 bảng
- .claude/skills/ef-core-migration/SKILL.md: 15→16 migration history,
  52→55 tables, description + code pointers + related links
- .claude/skills/README.md: ef-core-migration row "13 migration" → 16,
  gotchas count "32 bẫy" → 41 (drift cũ chưa fix)

Memory entry mới (cross-session pattern):
- feedback_per_chunk_commit.md: rule per-chunk commit cho big-feature
  (>500 LOC, multi-layer). Bài học S8 — 5 commit A-B-C-D-E thay vì
  1 monolithic. MEMORY.md index +1 entry (6 total).

Skip (intentional, theo §6.5 KHÔNG cố sửa):
- docs/gotchas.md: KHÔNG có gotcha mới đáng note (S8 dùng pattern
  đã proven, không có bug pitfall mới)
- docs/database/database-guide.md: KHÔNG có migration table chi tiết,
  chỉ conventions. Skip.
- contract-workflow + permission-matrix skills: KHÔNG touch (PE module
  only, contract policy chưa đổi, permission không liên quan bypass-review)

Verify:
- 77 unit test vẫn pass (54 Domain + 23 Infra)
- Build pass

Total session 8 cumulative: 6 commit (5 code A-B-C-D-E1 + 1 docs ending).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:02:22 +07:00
3c4931687a [CLAUDE] App+Api+Docs: Chunk E1 — List endpoint + Bypass-review + Notify TPB + chốt session 8
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m15s
3 endpoint mới + Notify TPB + Docs update để chốt session 8.

Application:
- PurchaseEvaluationDepartmentApprovalFeatures.cs (NEW):
  * ListPeDepartmentApprovalsQuery + DTO PeDepartmentApprovalDto
  * Join Departments (lấy Name) + lookup Users.FullName denorm cho FE timeline
- UserFeatures.cs: SetUserBypassReviewCommand + Handler dùng UserManager.UpdateAsync
- IApplicationDbContext: thêm DbSet<User> Users + DbSet<Role> Roles (cần cho lookup)

Api:
- PurchaseEvaluationsController: GET /api/purchase-evaluations/{id}/department-approvals
- UsersController: PATCH /api/users/{id}/bypass-review (Authorize Users.Update)

Infra:
- PurchaseEvaluationWorkflowService: notify TPB cùng dept khi NV review.
  Query db.Users.Where(DeptId match + IsActive) → UserManager.GetRolesAsync
  filter DeptManager → notifications.NotifyAsync. Best effort fail non-critical.

Docs:
- STATUS.md: Recently Done thêm row session 8 + Phase header update
  count 52→55 tables, 15→16 migrations, 128→131 endpoints
- HANDOFF.md: TL;DR session 8 + 8 cảnh báo session 9 (FE chưa làm,
  test flow anh Kiệt, smart reject test, lock edit test, ...)
- migration-todos.md: Phase 9 done section đầy đủ 3 ràng buộc + pending Chunk E-bis
- CLAUDE.md: count 52→55 + migration 16 description
- session log: 2026-05-04-1230-chot-session-8-2-stage-dept-approval.md (full report)

Verify final:
- Build pass 0 warning 0 error
- 77 unit test pass (54 Domain + 23 Infra)
- Migration 16 applied LocalDB OK + schema verified

Total session 8 cumulative: 5 commit per-chunk:
- 5fe61cc (A: Migration 16 schema)
- 14f3c9f (B: Lock edit guards 17 handler)
- 9747f8c (C: Smart reject + Resume 3 module)
- a532ba6 (D: PE 2-stage logic)
- (current E1: List + Notify + Bypass + Docs)

Pending Chunk E-bis (defer cho session 9 sau UAT PE):
- FE Workflow Panel hiển thị 2-stage timeline
- FE UserManager toggle CanBypassReview
- HĐ + Budget 2-stage extension
- Tests Phase 3 mini cho 2-stage Service-layer logic

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 12:42:47 +07:00
a532ba6fc3 [CLAUDE] Infra: Chunk D — PE 2-stage dept approval (đóng bug anh Kiệt báo)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m22s
Ràng buộc 3 (Phase 9) scope tối giản: chỉ PE workflow trước. Đóng bug
"NV duyệt được hết phase" anh Kiệt báo trong chat FDC.

Logic 2-stage trong PurchaseEvaluationWorkflowService.TransitionAsync,
chèn sau policy guard, trước phase transition:

1. Detect approving phase với role thuộc phòng ban:
   - decision == Approve
   - target != DangSoanThao && != TuChoi
   - Không reject + không resume + không admin/system
   - actorUserId != null + actor.DepartmentId != null

2. Stage detection:
   - DeptManager (TPB) → Stage=Confirm trực tiếp (TPB tự confirm được)
   - User.CanBypassReview=true → Stage=Confirm + IsBypassed=true (NV bypass)
   - Else (NV thường) → Stage=Review only

3. Upsert PurchaseEvaluationDepartmentApproval row:
   - UNIQUE (PEId, PhaseAtApproval, DepartmentId, Stage) đảm bảo 1 row
   - UPDATE in-place khi user click Duyệt lần 2 (đổi comment)
   - ApproverRoleSnapshot: "TPB" / "NV(bypass)" / "NV" denorm cho audit

4. Check Stage=Confirm tồn tại cho (PEId, fromPhase, deptId):
   - hasConfirm = vừa insert Stage=Confirm OR đã có sẵn
   - !hasConfirm → BLOCK phase transition:
     * Insert PEApproval row (FromPhase=ToPhase=fromPhase, Decision=Approve,
       Comment="[Review NV] ...") để track audit
     * Insert Changelog "NV X đã review phase Y, chờ TPB confirm"
     * Return early — Phase KHÔNG đổi
   - hasConfirm → tiếp tục normal phase transition logic

5. Skip 2-stage hoàn toàn khi:
   - Decision=Reject (smart reject Chunk C đã handle)
   - Resume after reject (target đã pinned)
   - Admin role hoặc System (auto-approve)
   - actorUserId == null hoặc actor.DepartmentId == null

Bug fix verified theo flow anh Kiệt:
- User long.chau (NV.PRO, role=Procurement, DepartmentId=PRO) tạo phiếu
- long.chau click Duyệt phase ChoPurchasing → ChoCCM:
  - actor.DepartmentId=PRO → 2-stage logic active
  - role=Procurement, không có DeptManager → Stage=Review
  - hasConfirm=false → BLOCK transition
  - Insert PEDeptApproval(PE, ChoPurchasing, PRO, Review)
  - Phase giữ nguyên ChoPurchasing
- TPB.PRO (tra.bui có role DeptManager + DeptId=PRO) click Duyệt:
  - role=DeptManager → Stage=Confirm
  - hasConfirm=true (vừa insert) → ALLOW transition
  - Phase chuyển ChoPurchasing → ChoCCM
- NV CCM lặp pattern tương tự ở phase ChoCCM
- Cuối cùng CEO/AuthSigner duyệt ChoCEODuyetNCC → DaDuyet (CEO không thuộc
  dept cụ thể nên bypass 2-stage)

Pending Chunk E:
- TODO notify TPB cùng dept khi NV review (best effort, chưa implement)
- List endpoint GET /api/purchase-evaluations/{id}/department-approvals
  cho FE hiển thị progress 2-stage
- UserManager API PATCH /api/users/{id}/bypass-review
- FE Workflow Panel update + UserManager toggle

HĐ + Budget 2-stage scope sẽ làm sau khi PE verify UAT (per default chốt
trước đó).

Verify:
- Build pass (2 warning DocxRenderer cũ)
- 77 unit test pass — Domain policy chưa đụng

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 12:26:18 +07:00
9747f8cbf5 [CLAUDE] Infra+App: Chunk C — Smart reject + Resume after reject (3 module)
Ràng buộc 2 (Phase 9): khi reject, trả về Drafter (DangSoanThao) + lưu phase
nguồn. Drafter sửa lại + trình lại → quay về phase đã reject (skip phase
trung gian).

Logic flow:

1. Reject (Decision=Reject):
   - entity.RejectedFromPhase = currentPhase  // snapshot phase đang reject
   - targetPhase override = DangSoanThao       // force về Drafter
   - Approval row: FromPhase=X, ToPhase=DangSoanThao, Decision=Reject
   - Notification cho Drafter

2. Resume after reject (Decision=Approve, fromPhase=DangSoanThao,
   RejectedFromPhase != null):
   - targetPhase override = entity.RejectedFromPhase!.Value
   - entity.RejectedFromPhase = null  // clear field
   - Skip policy guard (Drafter có quyền trình lại sau khi sửa)
   - Approval row: FromPhase=DangSoanThao, ToPhase=ResumePhase, Decision=Approve

3. Normal transition (chưa reject hoặc đã clear):
   - Logic cũ giữ nguyên — policy guard check + transition

Pattern unified cho 3 module:
- ContractWorkflowService.TransitionAsync: 2 case detect + override
- PurchaseEvaluationWorkflowService.TransitionAsync: tương tự
- TransitionBudgetCommandHandler.Handle: tương tự (Budget không có service riêng,
  logic ở handler)

Files:
- src/Backend/SolutionErp.Infrastructure/Services/ContractWorkflowService.cs
- src/Backend/SolutionErp.Infrastructure/Services/PurchaseEvaluationWorkflowService.cs
- src/Backend/SolutionErp.Application/Budgets/BudgetFeatures.cs

Verify:
- Build pass (2 warning DocxRenderer cũ, không liên quan)
- 77 unit test pass — Domain policy không đổi, tests giữ nguyên

Note: Approval history giờ track đầy đủ cycle reject→sửa→resume:
  Approval 1: DangGopY → DangSoanThao, Decision=Reject (CCM reject)
  Approval 2: DangSoanThao → DangGopY, Decision=Approve (Drafter resume)

UI có thể detect "đã từng reject" qua RejectedFromPhase != null hoặc
qua Approval history (Decision=Reject row gần nhất). Hiển thị banner
đỏ "Phiếu đã bị reject từ phase X, lý do: Y" cho Drafter.

Smart reject hoàn tất Ràng buộc 2. Còn Ràng buộc 3 (2-stage dept approval)
ở Chunk D.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 12:20:21 +07:00
14f3c9f817 [CLAUDE] App: Chunk B — Lock edit guards (Phase != DangSoanThao) cho 17 handler
Ràng buộc 1 (Phase 9): khi đã trình duyệt → KHÔNG sửa được Header + Detail
+ Quote nữa. Phải reject để Drafter sửa lại.

Pattern dùng: extend helper EnsureContractType + tạo helper PurchaseEvaluationDraftGuard
mới cho PE + inline guard cho Budget. Single source of truth cho mỗi module.

Handlers added Phase guard (17 total):

Contract module (15) — qua EnsureContractType helper:
- 7 Add*DetailHandler (ThauPhu/GiaoKhoan/NhaCungCap/DichVu/MuaBan/NguyenTacNcc/NguyenTacDv)
- 7 Update*DetailHandler (cùng 7 type)
- DeleteContractDetailHandler (inline guard)

PE module (5) — qua PurchaseEvaluationDraftGuard helper mới:
- AddPurchaseEvaluationDetail
- UpdatePurchaseEvaluationDetail
- DeletePurchaseEvaluationDetail
- UpsertPurchaseEvaluationQuote
- DeletePurchaseEvaluationQuote

Budget module (3) — inline guard:
- AddBudgetDetail
- UpdateBudgetDetail (refactor: load Budget thay vì FirstOrDefault sau Detail
  load → bỏ null check không cần)
- DeleteBudgetDetail (refactor: tương tự)

KHÔNG lock (intentional):
- ContractComment (cần được trong DangGopY phase 3)
- ContractAttachment Upload/Delete (Drafter scan ký ở DangInKy phase 5)
- PE OpinionUpsert (Ý kiến 4 PB là sign-off, có thể nhập sau khi trình)
- PE Attachment (báo giá NCC upload xuyên suốt workflow)

Verify:
- Build pass (2 warning DocxRenderer cũ)
- 77 unit test pass (54 Domain + 23 Infra) — domain policy không đổi

Smart reject (ràng buộc 2) + 2-stage dept approval (ràng buộc 3) làm ở
Chunk C + D. WorkflowService transition guard chưa update.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 12:15:07 +07:00
5c200978cb [CLAUDE] Domain+Infra: Migration 16 — 2-stage dept approval + smart reject schema
Chunk A của feature 2-stage department approval (Phase 9). 3 ràng buộc gộp
1 migration để rollback atomic.

Schema changes:

1. Smart reject (3 ALTER):
   - Contracts.RejectedFromPhase int NULL
   - PurchaseEvaluations.RejectedFromPhase int NULL
   - Budgets.RejectedFromPhase int NULL
   Lưu phase nguồn khi reject để Drafter trình lại quay về đúng phase
   (skip phase trung gian đã duyệt) thay vì đi tuần tự từ DangSoanThao.

2. Bypass per-user (1 ALTER):
   - Users.CanBypassReview bit NOT NULL DEFAULT 0
   Khi true → NV được duyệt thay TPB (skip Stage Review, đẩy thẳng
   Stage Confirm). Audit qua DepartmentApproval.IsBypassed=true.

3. 2-stage dept approval (3 CREATE TABLE):
   - ContractDepartmentApprovals
   - PurchaseEvaluationDepartmentApprovals
   - BudgetDepartmentApprovals

   Schema (chung):
   - Id, *Id FK Cascade, PhaseAtApproval int, DepartmentId FK
   - Stage enum (1=Review NV, 2=Confirm TPB)
   - ApproverUserId, ApproverRoleSnapshot, Comment, ApprovedAt
   - IsBypassed bit (mark NV bypass)
   - AuditableEntity (CreatedAt/By/UpdatedAt/By/IsDeleted/...)

   Indexes:
   - UNIQUE (TargetId, PhaseAtApproval, DepartmentId, Stage)
   - Single: TargetId, DepartmentId, ApproverUserId

Files:
- Domain: 4 entity update (Contract/PE/Budget/User add field) + 1 enum mới
  ApprovalStage + 3 entity DepartmentApproval mới
- Infrastructure: 3 EntityConfiguration update + 1 file mới
  DepartmentApprovalsConfiguration với 3 config classes
- IApplicationDbContext: thêm 3 DbSet
- ApplicationDbContext: thêm 3 DbSet
- Migration 16: 3 file (.cs + Designer.cs + Snapshot.cs) — 3-file rule

Verify:
- Build pass (2 warning DocxRenderer cũ, không liên quan)
- 77 unit test pass (54 Domain + 23 Infra) — Domain policy chưa update,
  test pass nguyên không regression

Note: KHÔNG khác PurchaseEvaluationDepartmentOpinion (Migration 15) —
Opinion là sign-off block "Ý kiến 4 phòng ban" trên header phiếu.
DepartmentApproval mới là 2-stage approval workflow per phase.

Tổng sau Migration 16: 55 bảng (52+3), 16 migration. Chunk B-E sẽ implement
Application + FE + Tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 12:11:53 +07:00
dfb43fcbc6 [CLAUDE] Docs: chốt template session prompts (start + end) — iterate qua 5 AI
User dùng 2 prompt fixed cho mọi session SOLUTION_ERP:
- MỞ ĐẦU: LOAD context (5 mục — đọc MD core, list skill, verify test,
  check audit cadence, sub-rule consolidate)
- KẾT THÚC: UPDATE MD + commit (5 mục — update MD đã đổi, note skill,
  verify test count tăng, add memory entry nếu cần, sub-rule consolidate)

Iterate workflow:
- v1: đề xuất ban đầu (typo + 4 mục giống nhau Mở đầu vs Kết thúc)
- v2: tách action verb LOAD vs WRITE
- v3-v4: refine wording, fix typo, bỏ câu thừa
- v5 final: fix "thei"→"theo", "end từ"→"kết thúc lúc", "vào vào"→"vào"

Bài học: prompt template iterate cross-AI (5 AI cùng review) ra version
robust hơn 1 AI duy nhất. Template lưu 3 chỗ:
1. docs/_templates/session-prompts.md (canonical project)
2. memory/reference_session_prompts.md (cross-session pointer)
3. MEMORY.md index (session sau auto-load nhận diện trigger)

File: docs/_templates/session-prompts.md (NEW, docs-only → CI skip)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 03:04:12 +07:00
2675a3a674 [CLAUDE] Docs: rule §6.5 consolidate KEEP vs CUT + restore narrative migration-todos
Bài học session 6: compact -288 dòng nhanh nhưng paraphrase + collapse mất
narrative tích lũy qua sessions. User feedback: "viết MD gọn lại tý là mất
mẹ luôn tính cách cũ". Docs đọc 6 tháng sau như machine output.

Changes:
1. docs/rules.md §6.5 mới — Consolidate MD đúng cách (KEEP vs CUT):
   - KEEP cấm cắt: narrative, rationale, gotcha context, anecdote, "decision why"
   - CUT được: duplicate cross-ref, list>30 row archive, phase>1 tháng collapse
   - CẤM: paraphrase, summary đoạn có narrative, "đẹp hóa" bằng cắt
   - Decision tree + Validation 3 câu sau consolidate

2. docs/changelog/migration-todos.md restore Phase 6-7 nguyên văn từ b874743:
   - Phase 6 iter 1 (10 task chi tiết: Migration 12, Domain 2 enum, Application
     CQRS ~900 LOC, PurchaseEvaluationWorkflowService, Controller 17 endpoint,
     FE 2 app, Kế thừa HĐ guard, Migration 13 atomic seq, Demo PE seed)
   - Phase 6 iter 2 (8 task UX polish: rename Phương Án→Giải pháp, menu
     inheritance #35, accordion mutex, queryMatches #34, flat layout, per-NCC
     attachment, readOnly mode, email rebrand #38)
   - Domain rebrand 4 task chi tiết (gotcha #30 ASCII-only, 18 file repo,
     CI/CD auto rebuild, "Old fallback chưa remove" rationale)
   - Phase 7 PE feature gap A/B/C/D/E section đầy đủ:
     A. 3 task PE feature gap với file path + Option A/B reasoning
     B. 4 optional polish carry over Phase 9
     C. 6 ops task carry over Phase 9 hard blockers
     D. Budget BE 7 task chi tiết (Migration 14, ~340 LOC, 11 endpoint, 14 demo)
     E. 4 pending migration với rationale "khi nào cần"
   - Tick [x] task đã DONE S5 (PE WF Designer + Ý kiến 4 PB) + giữ [ ] chưa làm

Net change migration-todos: 136 → 217 (+81 dòng narrative)

Files: docs/rules.md + docs/changelog/migration-todos.md (docs-only → CI skip)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 01:56:29 +07:00
2abbc1d867 [CLAUDE] Docs+Skill: chốt session 6 — 3 skill refresh + 2 rule audit định kỳ
Pure docs work — 0 thay đổi code/test. 77 test vẫn pass (Domain 54 + Infra 23).

3 skill refresh stale (audit định kỳ §6.4 + §9.4 phát hiện):
- form-engine: "Phase 2 MVP missing PDF + form builder" → "Tier 3 feature-complete"
  + bỏ section duplicate "Gen mã HĐ chưa implement" (đã DONE Phase 3+6)
- permission-matrix: 12 menu cũ → ~60 menu key (Bg_*/Pe_*/PeWf_*/Catalogs)
  + inheritance roots 4 group + Budgets KHÔNG inherit (gotcha #35)
- ef-core-migration: "24 DbSet" → "52 bảng (15 migration)"

2 rule mới chốt:
- rules.md §6.4 — Audit + compact MD định kỳ (cadence + checklist + anti-pattern)
  Triết lý: KHÔNG rewrite toàn bộ. Compact + patch drift.
  Cron solution-erp-skill-audit-monthly mở rộng scope (skill + doc drift combined)
- rules.md §9.4 mở rộng cross-ref §6.4

Update STATUS Session 7+ priority + HANDOFF cảnh báo session 7 + migration-todos
Phase 9 Session 6 done sub.

Cron 2026-05-01 fire mai → combined audit theo checklist §6.4 + §9.4.

Session log đầy đủ: docs/changelog/sessions/2026-04-30-chot-session-6-md-audit-compact.md

Commit MD-only → CI skip (path filter gotcha #41).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 01:18:51 +07:00
f24acb699a [CLAUDE] Docs: compact 3 file core (-273 dòng tổng)
STATUS.md (-52 dòng, -27%): archive 51 row Recently Done Phase 0-7 cũ
  → changelog/recently-done-archive-2026-04.md (file mới)
  Giữ 12 row mới nhất Phase 8/Session 5 + pointer archive.

HANDOFF.md (-147 dòng, -32%): bỏ 3 section duplicate
  - Versioned workflow quick ref → cross-ref workflow-contract.md §7bis
  - File đang active (90 dòng tree) → cross-ref PROJECT-MAP.md
  - Git state snapshot stale → cross-ref `git log --oneline -10`

migration-todos.md (-74 dòng, -35%): collapse Phase 6 iter 1+2 + Phase 7
  done parts thành 4 dòng paragraph. Giữ Phase 8/9 active + skill audit.

Quy tắc compact (rules.md §6 implicit):
  - Recently Done > 30 row → archive cũ vào changelog/recently-done-archive-{YYYY-MM}.md
  - Phase done >= 1 tháng → collapse thành 1 paragraph + cross-ref session log
  - Section duplicate file khác → cross-ref thay vì copy

Commit MD-only → CI skip (path filter gotcha #41).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 01:10:03 +07:00
d2298fa614 [CLAUDE] Docs: chốt rule timing unit test (1 bảng 5-row compact)
- rules.md §7: thêm section "Khi nào viết test — timing rule"
  4 case (feature mới/bug fix/critical algorithm/spec change) + 1 skip list
- CLAUDE.md root: 1 dòng quick reference timing rule
- User confirm pattern Phase 1-8 (test-after pragmatic) là default cho solo dev
- Test-before BẮT BUỘC chỉ khi: bug fix (regression test) + critical algorithm
- Spec change KHÔNG ngừng test — update test cũ + code, commit chung

Commit MD-only → CI skip (path filter gotcha #41), 0s deploy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 00:40:24 +07:00
b874743081 [CLAUDE] Docs+Tests: chốt final session 5 — 77 test (Phase 3 mini PE WF) + 3 gotcha CI + 8 doc updates
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m21s
Final close session 5 — bao gồm:

==== Tests Phase 3 mini (NEW) ====
tests/SolutionErp.Infrastructure.Tests/Application/PeWorkflowAdminTests.cs
- 6 test CreatePeWorkflowDefinitionCommandHandler:
  - First version → IsActive=true, Version=1, ActivatedAt set
  - Second version same Code → auto-increment v2 + deactivate v1 (atomic)
  - Different EvaluationType (A vs B) → independent active state
  - Persists steps ordered by Order field
  - Persists approvers per step
  - Third version → v1 + v2 deactivate, v3 active

Total tests: 71 → 77 pass / ~2s (54 Domain + 23 Infra).
Skip Phase 3 full (UpsertOpinion + Budget link validation) — cần
Identity UserManager DI helper, defer session sau.

==== 3 gotcha CI mới (#39 #40 #41) ====
- #39 act_runner github.com TCP timeout 21s → manual checkout fix (run #108/#109 fail, #110 pass)
- #40 npm junction cache `tsc not found` after Move-Item — rolled back, hypothesis nested junctions
  trong node_modules disrupt .bin/ paths. TODO debug session sau với robocopy hoặc act_runner cache.host
- #41 Gitea Actions paths-ignore behavior — workflow file change vẫn trigger (correct), commit
  MD-only skip 100% (verify 512880c → no run #113)
+ Checklist debug bug mới items 18-20 referencing 3 gotcha trên.

==== Doc updates (8 file) ====
- STATUS.md: header Phase 8 update + 3 row Recently Done CI fixes + cumulative test 71→77
- HANDOFF.md: TL;DR + CI optimize section + Phase status + gotcha count 38→41
- migration-todos.md: Phase 8 §E updated với Phase 3 mini done + CI fixes
- rules.md §7 Testing: rewrite full — stack + test pyramid + quy tắc bổ sung mỗi feature +
  workflow user end-of-task (`dotnet test` local trước push) + CI gate behavior
- architecture.md §11: update test pyramid + phased priority + CI optimization sub-section
  (3 fix manual checkout / path filter / npm cache rollback) + tốc độ deploy table
- gotchas.md: + #39 #40 #41 đầy đủ (triệu chứng + nguyên nhân + fix + reference)
- ef-core-migration SKILL: Phase 8 update note thêm CI fixes + 77 test
- CLAUDE.md root: test count 71→77 + folder structure + CI/CD pipeline 3 fix section
- memory project_solution_erp.md: session 5 summary + workflow user mới
- session log 2026-04-29-2300-chot-final-ci-tests-gotchas.md (NEW — 9 section detail)

==== Skill audit cron ====
`solution-erp-skill-audit-monthly` next fire 2026-05-01 (2 ngày sau).
Cron survives across sessions (setup commit b904a25). Khi fire sẽ:
- Cross-check 6 skill với STATUS/gotchas/migration-todos
- Auto-refresh stale + đề xuất add/archive cho human approve
- Log vào docs/changelog/skill-audit-2026-05.md
- ABORT nếu repo dirty

==== Verify ====
- dotnet test SolutionErp.slnx → 77 pass / ~2s (54 Domain + 23 Infra)
- git status clean sau commit này
- CI: commit này chứa code (test + workflow) → trigger CI test gate

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 23:43:42 +07:00
512880c5cb [CLAUDE] Docs: STATUS — note CI path filter live (test docs-only commit skip)
Test path filter on:push:paths-ignore — commit này CHỈ touch docs/STATUS.md.
Expected: Gitea Actions KHÔNG trigger run mới.
Verify bằng cách check Actions UI sau ~30s — vẫn ở run #112 (a21790d).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 18:39:44 +07:00
a21790d58d [CLAUDE] CICD: rollback npm junction cache (giữ path filter), fix #111 fail tsc not found
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m0s
Run #111 (commit 29eb5d9) FAIL với `'tsc' is not recognized` ở step Build fe-admin.
Symptoms confusing:
- VPS check: cache dir C:\npm-cache-erp\ chưa có (cold)
- Log: KHÔNG có Write-Host "cache MISS" hay "added 239 packages"
- Timing: 1.6s từ end-of-BE-build → start-of-fe-admin-build (impossible cho npm install 49s)
- Test gate (Domain 54 + Infra 17) PASS nên không phải code regression

Khả năng cao: junction Move-Item disrupted node_modules .bin/ structure HOẶC
act_runner PowerShell stream capture có quirk với cache MISS branch. Cần debug
riêng — không nên block deploy chính.

Decision:
- Rollback npm cache logic về fresh install như cũ (49s + 33s)
- GIỮ path filter on:push:paths-ignore (đây mới là win lớn nhất — 100% saving cho MD-only commit)
- Document gotcha cho session sau (sẽ thử robocopy thay vì junction, hoặc dùng act_runner cache server local)

Path filter behavior (giữ lại):
- Commit chỉ docs/MD/skill/gitignore → SKIP CI hoàn toàn (~196s/commit saved)
- Commit code OR cùng commit có code+docs → vẫn trigger (đúng)

Verify dotnet test local: 71 pass / 1s (BE không thay đổi).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 18:34:04 +07:00
29eb5d99a0 [CLAUDE] CICD: path filter docs-only + npm junction cache (Option C optimize ~2/3 deploy time)
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Failing after 59s
Optimize CI/CD theo Option C bàn trong chat:

==== Path filter (saving 100% time cho commit MD-only) ====
on: push: paths-ignore mới — skip CI khi commit chỉ docs/skill/MD/gitignore.
- 'docs/**'
- '**/*.md'
- '.claude/skills/**'
- '.gitignore'
- 'scripts/**.md'

Commit 'Docs: chốt session' và similar sẽ KHÔNG trigger workflow → save 196s/commit.
Nếu cùng commit thay đổi cả MD + code → vẫn trigger (đúng behavior expected).
Workflow file `.gitea/workflows/**` chính NÓ thì không trong paths-ignore →
vẫn trigger khi sửa CI config (an toàn).

==== npm junction cache (saving ~70-80s code commit) ====
Replace Build fe-admin + fe-user steps với cache-aware version.

Strategy:
- Cache key = SHA256(package.json) 16-char prefix → đổi deps = miss → fresh
- Cache stored: C:\npm-cache-erp\<app>\<hash>\node_modules (ngoài workspace)
- Junction `fe-admin\node_modules → cache` (instant, không file copy)
- Lần đầu (cold): 49s + 33s = 82s (như cũ)
- Lần sau (warm): mklink instant + skip npm install → ~3s + 3s = 6s (saving ~76s)

Safety:
- Trước Deploy: convert junction → nothing (cmd /c rmdir /q chỉ remove ref,
  không follow target). Tránh trường hợp act_runner cleanup workspace
  follow junction + delete cache.
- Pruning: keep top 5 cache per app (~250MB × 5 × 2 = 2.5GB max disk usage).
  Stale evicted FIFO theo LastWriteTime DESC.

Vite 8 rolldown native binding gotcha (#20) vẫn respect: cache install trên
runner Windows nên rolldown binding match → reuse được.

==== Expected ====
- Commit MD-only: 0s CI (skip hoàn toàn)
- Commit code lần đầu sau cache miss (vd npm update): ~3min (như cũ)
- Commit code thường (cache hit): ~120s = 2 phút (giảm 38%)

Verify dotnet test local: 71 pass / 2s (BE không thay đổi).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 18:24:09 +07:00
14b7d18ecc [CLAUDE] CICD: bỏ uses: actions/* — manual git checkout từ Gitea (fix #108/#109 fail)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m16s
Vấn đề persistent (run #108#109 đều fail trong 21-22s):
  Get "https://github.com/actions/checkout/info/refs?service=git-upload-pack":
    dial tcp 20.205.243.166:443: connectex: connection failed/timeout

act_runner v0.2.13 mỗi run đều `git fetch` actions/checkout từ github.com
để check update — VPS network → github.com TCP timeout 21s liên tục →
toàn job fail TRƯỚC khi tới test gate.

Fix: thay actions ngoài bằng native shell, eliminate github.com dependency.

- Replace `uses: actions/checkout@v4` → manual `git init` + `git fetch`
  từ Gitea internal network (luôn ổn định, không qua public internet)
  - Auth: github.token (act_runner cũng dùng tên này) — tự sẵn per job
  - Fetch by ref (branch) thay vì SHA, depth=30 đủ buffer nếu main commit
    thêm trong lúc job pickup
  - Checkout đúng commit SHA của event push
  - Log 1-line để confirm checkout đúng

- Replace `uses: actions/upload-artifact@v4` (cũng phụ thuộc github.com)
  → step "List test results" local. TRX file vẫn save trong workspace
  test-results/, đọc qua runner workspace nếu cần debug.

Test gate giữ nguyên (Domain + Infra). dotnet test local 71 pass / 2s.

Long-term option (nếu Gitea Actions thêm hỗ trợ): config `github_mirror`
trong gitea-runner config.yaml để mirror github.com → Gitea internal,
hoặc pre-cache actions/* repos vào runner cache dir.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 16:21:12 +07:00
26075c40f3 [CLAUDE] CICD: re-trigger deploy after transient github.com network timeout (commit 52999f3)
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Failing after 21s
Run #108 failed in 22s với:
  Get "https://github.com/actions/checkout/info/refs?service=git-upload-pack":
  dial tcp 20.205.243.166:443: connectex: A connection attempt failed
  because the connected party did not properly respond...

Network từ VPS → github.com bị timeout transient lúc act_runner clone
`actions/checkout@v4` source. Test gate chưa kịp chạy.

Verify network giờ đã ok (TcpTestSucceeded: True) + dotnet test local
71 pass / 2s. Empty commit để re-trigger CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 16:13:45 +07:00
52999f33fa [CLAUDE] Docs: chốt session 5 — Budget FE + PE feature complete + Tests Phase 1-2 + CI gate
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Failing after 22s
Session 5 (29/04) — 6 commit feature + 1 chốt MD này.

==== Stats sau session 5 ====
- 52 DB tables (+1 PEDeptOpinions)
- 15 migrations (+`AddPurchaseEvaluationDepartmentOpinions`)
- ~128 API endpoints (+4)
- ~31 FE pages (+5 Budget + 1 PeWorkflowsPage)
- 71 unit test pass (54 Domain + 17 Infra) — CI gate live, fail → no deploy
- ~13050 BE LOC (+1300)
- 30 demo user, 38 gotchas, 6 skill (no change)

==== MD touched ====
- STATUS.md: header Phase 8 + 6 row Recently Done session 5 + cumulative cột S5 + In Progress S6 (Hard blockers + Optional polish + Tests Phase 3-5 + Ops)
- HANDOFF.md: TL;DR 6 milestone S5 + Cảnh báo S6 (CI test gate workflow mới) + Priority 0 S6 (UAT + Ops focus) + Phase status table cập nhật
- migration-todos.md: Phase 8 done với A/B/C/D/E (FE Budget / PE-HD integration / PE WF Designer / Ý kiến 4 PB / Tests Phase 1-2) + Phase 9 active (UAT + Ops + carry over)
- architecture.md: §11 Testing strategy mới (test pyramid bottom-heavy + stack + CI gate + phased priority + quy tắc bổ sung mỗi feature)
- database/schema-diagram.md: Migration 15 row + total 52 tables + §13 PE Department Opinion (1 bảng UNIQUE PEId+Kind + Upsert behavior + SQL DDL)
- ef-core-migration SKILL: migration 15 entry + 52 tables total + Phase 8 update note
- CLAUDE.md (root): modules table + Tests row + scope `Tests` + Tests section mới + count update 15/52
- docs/CLAUDE.md: 7 module bullet + ERD 52 bảng + Roadmap Phase 8 done + Phase 9 active S6
- memory project_solution_erp.md: Phase 8 summary + Session 6 priority + workflow user mới (dotnet test → commit → push)
- session log 2026-04-29-chot-session-5-budget-fe-pe-tests.md (NEW — 10+ section detail)

==== Verify ====
- dotnet test SolutionErp.slnx → 71 pass / 2s
- git status clean sau commit này

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 13:50:54 +07:00
df5988b7a9 [CLAUDE] Tests Phase 2: Code generator format + sequence tests (SQLite in-memory)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m16s
Phase 2 — chống regression code generator. 17 test mới integration với
DB thật (SQLite in-memory) tổng cộng 71 test pass < 3 giây.

Test project:
- tests/SolutionErp.Infrastructure.Tests/ (xUnit + FluentAssertions + EF SQLite 10)
- ProjectReference SolutionErp.Infrastructure (transitively get Application + Domain)
- Added vào SolutionErp.slnx

Test fixtures:
- Common/SqliteDbFixture.cs:
  - SQLite ":memory:" + shared connection + EnsureCreated() từ DbContext model
  - TestApplicationDbContext subclass — override OnModelCreating replace
    'nvarchar(max)' → 'TEXT' (SQLite không support max keyword)
  - FixedDateTime stub IDateTime cho deterministic year boundary test

Test files:
- Services/ContractCodeGeneratorTests.cs (10 test):
  - Format per ContractType (5 type × Project scope) — RG-001 spec
  - Framework HĐ (NguyenTacNCC + NguyenTacDV) → year scope thay vì project
  - Sequence increment per prefix (3 calls → /01, /02, /03)
  - Different prefixes (project / supplier) → independent sequences
  - Year change (2026 → 2027) → reset sequence vì prefix khác
  - PersistsSequenceRow LastSeq verification
- Services/PurchaseEvaluationCodeGeneratorTests.cs (7 test):
  - Format A/B (DuyetNcc → 'A', DuyetNccPhuongAn → 'B')
  - Seq là 3-digit padded (001..012)
  - Type A và B sequence độc lập trong cùng năm
  - Year boundary reset cả A và B

CI gate update (.gitea/workflows/deploy.yml):
- Step "Run integration tests (Infrastructure)" thêm sau Domain tests
- TRX log saved riêng (infra-tests.trx)
- Cả 2 step đều exit non-zero → no deploy

Verify local:
- dotnet test SolutionErp.slnx → Total tests: 71 (54 Domain + 17 Infra) / Passed: 71 / 2.1s
- dotnet build SolutionErp.slnx → 0 error

Phase 3+ pending:
- Application handler tests (CQRS) với EF InMemory hoặc SQLite (~1 ngày)
- API smoke tests qua WebApplicationFactory (~0.5 ngày)
- FE Vitest cho lib utility (~0.5 ngày)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 13:29:06 +07:00
d3f9346840 [CLAUDE] Tests Phase 1: Domain unit tests + CI gate (xUnit + FluentAssertions)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m25s
Phase 1 (MVP) — chống regression Workflow state machine. 54 test pure
function (no DB / IO), all pass < 7 giây.

Test project:
- tests/SolutionErp.Domain.Tests/ (xUnit 2.9.3 + FluentAssertions 7.2 — pin trước v8 commercial license)
- ProjectReference SolutionErp.Domain
- Added vào SolutionErp.slnx folder /tests/

Test files:
- Contracts/WorkflowPolicyTests.cs (~17 test):
  - Standard policy 9-phase: role transitions, CCM check, BOD signing, terminal
  - SkipCcm policy 7-phase: bypass CCM verify, no DangKiemTraCCM transition
  - Registry: DefaultPolicyName per ContractType (7 type), bypass flag override
  - FromDefinition versioned: build từ ordered steps + reject path + TuChoi auto-add + UserKindApprover populate UserTransitions
- PurchaseEvaluations/PurchaseEvaluationPolicyTests.cs (~17 test):
  - NccOnly (A) 3-step: skip ChoDuAn + ChoCEODuyetPA, CCM đẩy thẳng CEO duyệt NCC
  - NccWithPlan (B) 5-step: có ChoDuAn (PM) + ChoCEODuyetPA (Director) trước
  - Reject path cả 2 quy trình về DangSoanThao
  - Registry mapping per PEType
- Budgets/BudgetPolicyTests.cs (~13 test):
  - Default 3-step (Drafter→CCM→CEO) role guard
  - Reject paths về DangSoanThao
  - DaDuyet + TuChoi terminal (no NextPhases)
  - SLA spec 5d/3d/2d cho 3 phase đầu

CI gate (.gitea/workflows/deploy.yml):
- Step "Run unit tests (Domain)" thêm TRƯỚC build/publish/deploy
- Test fail (LASTEXITCODE != 0) → exit → KHÔNG deploy
- TRX log saved + upload artifact (continue-on-error nếu Gitea runner thiếu actions/upload-artifact)

Verify local:
- dotnet test tests/SolutionErp.Domain.Tests → Total tests: 54 / Passed: 54 / 6.4s
- dotnet build SolutionErp.slnx (full solution incl. test project) → 0 error

Phase 2-5 pending (xem plan ở chat):
- Code generator atomic concurrency tests (Infra)
- DbInitializer reconcile drift tests (Infra)
- Application handler smoke tests (CQRS) với EF InMemory
- API smoke tests qua WebApplicationFactory
- FE Vitest cho lib utility (queryMatches, fmtMoney)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 13:19:15 +07:00
5d94bb449a [CLAUDE] PE: Workflow designer admin UI + Ý kiến 4 phòng ban (P1 Session 5)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m51s
==== Task 1: PE Workflow Designer admin ====

BE (mirror Contract WorkflowAdminFeatures pattern):
- Application/PurchaseEvaluations/PeWorkflowAdminFeatures.cs ~250 LOC:
  - GetPeWorkflowAdminOverviewQuery → list 2 EvaluationType (DuyetNcc / DuyetNccPhuongAn) với Active + History versions + count phiếu đang dùng
  - CreatePeWorkflowDefinitionCommand + Validator: auto-increment Version per Code, deactivate Active cũ trong cùng EvaluationType (1 active per type invariant)
  - DTOs: PeWorkflowStepApproverDto / PeWorkflowStepDto / PeWorkflowDefinitionDto / PeWorkflowTypeSummaryDto / PeWorkflowAdminOverviewDto
  - Phase validation 1..7 (state thường, không bao gồm 99=TuChoi)
- Api/Controllers/PeWorkflowsController.cs: 2 endpoint GET /api/pe-workflows + POST. Reuse policy "Workflows.Read" + "Workflows.Create" (admin chung quyền cho cả 2 nhóm WF).

FE:
- pages/system/PeWorkflowsPage.tsx ~500 LOC mirror WorkflowsPage:
  - Landing 2-card grid khi /system/pe-workflows (chưa pick type)
  - TypePanel khi /system/pe-workflows/:typeCode (DuyetNcc / DuyetNccPhuongAn)
  - DefinitionCard read-only view với active badge + version + steps + approvers (Role/User chip)
  - PeWorkflowDesigner dialog: clone từ existing, edit Code/Name/Description, add/remove steps, +Role / +User approvers per step, save → version mới + deactivate cũ
- App.tsx route /system/pe-workflows + /system/pe-workflows/:typeCode
- Layout đã có resolver PeWf_<Code> → /system/pe-workflows/<code> từ session 3

==== Task 2: Ý kiến 4 phòng ban PE ====

Domain:
- PurchaseEvaluationDepartmentOpinion entity (AuditableEntity) — PEId + Kind + Opinion text + SignedAt + UserId + UserName denorm
- PeDepartmentKind enum (PheDuyet / Ccm / MuaHang / SmPm)
- PE entity + collection navigation DepartmentOpinions

Infrastructure:
- PurchaseEvaluationDepartmentOpinionConfiguration EF: UNIQUE(PEId, Kind) — max 1 row per phòng ban per phiếu (UPDATE in-place)
- ApplicationDbContext + IApplicationDbContext DbSet
- Migration 15 AddPurchaseEvaluationDepartmentOpinions (15 migration total / 52 DB tables)

Application:
- PeDepartmentOpinionFeatures.cs: UpsertPeDepartmentOpinionCommand (sign=true → set SignedAt+UserId, sign=false chỉ lưu text giữ chữ ký cũ) + DeletePeDepartmentOpinionCommand
- DTO bundle update: + DepartmentOpinions list trong PurchaseEvaluationDetailBundleDto
- GetPurchaseEvaluationQueryHandler load DepartmentOpinions + KindLabel resolution

API:
- POST /api/purchase-evaluations/{id}/opinions (upsert)
- DELETE /api/purchase-evaluations/{id}/opinions/{kind}

FE:
- types/purchaseEvaluation.ts: + PeDepartmentKind enum + PeDepartmentKindLabel + PeDepartmentOpinion type + departmentOpinions vào bundle
- PeDetailTabs Section "5. Ý kiến 4 phòng ban (sign-off)" — 2x2 grid OpinionBox per kind:
  - Read mode (readOnly menu Duyệt): hiển thị text + chữ ký
  - Edit mode: textarea + 2 button "Lưu text" / "Lưu & Ký"
  - Badge "Đã ký" emerald + tên người ký + ngày khi signedAt != null

==== Task 3: User seed verify ====

Seed `SeedDemoUsersAsync` đã match đúng user list authoritative (5 PRO TPB+NV / 7 CCM TPB+NV / 1 ISO / 1 CEO) từ prior commit. DbInitializer reconcile sẽ tự sync khi API restart. Typo trong list user (soluttions / trương) đã fixed sensibly trong seed.

==== Build verify ====
- dotnet build clean (0 error)
- fe-admin TS build pass (1 module mới PeWorkflowsPage)
- fe-user TS build pass (PE detail mirror)

Total: 8 file mới (BE 4 + FE 1 + Migration 2 + 1 Domain) + 13 file modified.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 11:17:14 +07:00
7e36241db9 [CLAUDE] FE PE: restructure InfoTab theo spec PHIẾU TRÌNH KÝ CHỌN TP/NCC
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m3s
Match form chính thức 4 section đánh số:

1. Thông tin gói thầu — chỉ a. Tên gói thầu + b. Dự án (Địa điểm + Mô tả compact bên dưới nếu có).

2. Chọn NCC / TP — đúng a/b/c/d:
   a. NCC/TP được chọn — selectedSupplierName badge xanh
   b. Ngân sách — link Budget với mã + tên + tổng
   c. Giá chào thầu — tự compute = sum quotes của winner supplier (filter quotes.purchaseEvaluationSupplierId === winnerRowId)
   d. Bản so sánh — embed GeneralAttachmentsSection (attachments không gắn supplier-row, purpose=ComparisonTable)
   + ĐKTT + HĐ kế thừa link bonus
   + Banner emerald 'Tạo HĐ từ phiếu' khi DaDuyet + chưa có Contract

3. NCC/TP tham gia — section riêng giữ table 5 cột (NCC/Liên hệ/ĐKTT/File/Action — nhiều info hơn spec table 3 cột, useful cho UX web).

4. Hạng mục + Báo giá — matrix với cột 'NS link · Δ' + footer aggregate (giữ nguyên).

Side change:
- FormRow helper mới (label 176px + value flex) thay cho dl grid 2-col cũ — match style form giấy
- Drop Field helper cũ (now unused)
- InfoTab signature đổi: bỏ readOnly param (chỉ display, action move sang ChonNccSection)

TS build pass cả 2 app. Mirror fe-user identical.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 11:02:45 +07:00
61e5d4d503 [CLAUDE] PE+Contract+Budget integration — link Budget vào PE/HĐ + cột So với ngân sách
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m51s
BE wire BudgetId nullable FK qua command + DTO bundle:
- Budgets.Dtos: + BudgetSummaryDto (compact header snapshot, không kèm Details — gọi /budgets/{id} riêng nếu cần đối chiếu chi tiết)
- PurchaseEvaluations.Dtos: + BudgetId? + Budget? BudgetSummaryDto vào PurchaseEvaluationDetailBundleDto
- Contracts.Dtos: + BudgetId? + Budget? BudgetSummaryDto vào ContractDetailDto
- CreatePE + UpdatePEDraft + handlers: + BudgetId? param + validate (cùng Project + Phase=DaDuyet) + persist
- CreateContract + UpdateContractDraft + handlers: + BudgetId? param + validate + persist + log diff
- GetPE + GetContract handlers: load BudgetSummary nếu có link
- CreateContractFromEvaluation: carry forward pe.BudgetId → contract.BudgetId (nếu phiếu PE đã link)

FE PE (cả 2 app):
- types/purchaseEvaluation.ts: + BudgetSummary type + budgetId/budget vào PeDetailBundle
- PurchaseEvaluationCreatePage: thêm Select 'Ngân sách' filter Phase=DaDuyet + Project match (BE-side filter qua /budgets?projectId=&phase=4). Disabled khi chưa pick Project. Edit mode preserve.
- PeDetailTabs InfoTab: hiển thị Budget link với mã + tên + tổng (clickable → /budgets?id=)
- PeDetailTabs ItemsTab: thêm cột 'NS link · Δ' chỉ hiện khi ev.budgetId. Match per-row qua key groupCode|itemCode → fetch /budgets/{id} riêng. Footer aggregate row 'Tổng' + delta indicator (xanh dưới / đỏ vượt / xám khớp). No-match cell hiện '—'.

FE Contract (cả 2 app):
- types/contracts.ts: + ContractBudgetSummary + budgetId/budget vào ContractDetail
- ContractCreatePage HeaderForm: thêm Budget Select sau FormFields, useEffect reset khi đổi project
- ContractCreatePage EditForm: Select khi isDraft / read-only link card khi !isDraft

TS build pass cả 2 app + dotnet build clean. No new migration (BudgetId? nullable FK đã có từ migration 14).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 16:41:11 +07:00
df12fb19c8 [CLAUDE] FE-Admin+FE-User: Module Ngân sách (Budget) FE — 3-panel List + Create + Detail tabs + Workflow timeline
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m59s
Mirror pattern PE 3-panel cho 2 app (admin + user):

- types/budget.ts (BudgetPhase 5-state enum + label/color, BudgetListItem, BudgetDetailRow, BudgetApproval, BudgetWorkflowSummary, BudgetChangelog, BudgetDetailBundle, BudgetDetailBody)
- components/budgets/BudgetDetailTabs.tsx — flat render Section "Thông tin" Header + Section "Hạng mục" table CRUD inline (Add/Edit/Delete dialog với auto-compute ThanhTien = KL × DonGia). Export BudgetApprovalsSection + BudgetHistorySection cho Panel 3 reuse.
- components/budgets/BudgetWorkflowPanel.tsx — Panel 3 timeline activePhases + nextPhases buttons (Approve/Reject color coding) + Dialog xác nhận có comment + sub-section Approvals + Changelog.
- pages/budgets/BudgetsListPage.tsx — 3-panel [340px_1fr_360px] với search + filter Phase + filter NamNganSach. ?phase=Pending alias FE filter 2 phase ChoCCM/ChoCEO. SlaTimer per row + readOnly mode khi pendingMe.
- pages/budgets/BudgetCreatePage.tsx — form Header (TenNganSach/Năm/Dự án/Phòng ban/Mô tả). Edit mode khóa Project+Department.
- App.tsx routes /budgets, /budgets/new, /budgets/:id cả 2 app
- Layout.tsx menu resolver Bg_List → /budgets, Bg_Create → /budgets/new, Bg_Pending → /budgets?phase=Pending. NavLink active dùng queryMatches helper (gotcha #34 — không conflict Bg_List vs Bg_Pending cùng pathname).

TS build: cả fe-admin + fe-user pass clean (1918 + 1901 modules).
BE: dùng 11 endpoint Budgets từ migration 14 (Phase 7 BE đã deploy commit a05c57b).

Tổng FE: +12 file (5 fe-admin + 5 fe-user + 2 mod App/Layout × 2). ~1100 LOC TSX.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 16:25:22 +07:00
e0b4e7f096 [CLAUDE] Docs: chốt session 4 — Budget BE module + 14 Solutions users
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m53s
- STATUS.md: header Phase 7 + 3 row Recently Done (Budget BE / 14 users / Docs cleanup) + cumulative cột mới (51 tables / 14 mig / ~124 endpoints)
- HANDOFF.md: TL;DR session 4 (2 milestone Budget BE + 14 users) + Cảnh báo session 5 + Priority 0 (FE Budget + PE/HD integration + PE feature gap) + Credentials 30 user
- migration-todos.md: Phase 7 thêm section D Budget done + Phase 8 mới (FE Budget pages + integration) + pending migrations Budget
- architecture.md: §10 Budget module mới (ERD + state machine + auto-recompute + integration roadmap)
- database/schema-diagram.md: migration history rows 13+14 + §12 Budget ERD chi tiết
- ef-core-migration SKILL: migration 14 entry + Phase 8 pending Budget refinement
- CLAUDE.md root + docs: modules table thêm Budget row + scope Budget + count 51 bảng / 14 mig
- Session log 2026-04-28-chot-session-4-budget.md (10+ section detailed)

Stats: 51 tables (+4 Budget), 14 migrations (+AddBudgets), ~124 endpoints (+11 Budget),
30 demo user (16 sample + 14 Solutions thật), 38 gotchas, ~340 LOC Budget CQRS.
FE Budget pages chưa làm — Priority 0 session 5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 12:36:31 +07:00
a05c57b081 [CLAUDE] Domain+App+Api: Module Ngan sach (Budget) - 4 bang + workflow simple
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m11s
User request: 'Them cho tao 4 bang luu ve ngan sach: Header / Chi tiet
/ Quy trinh duyet / Lich su thay doi'.

Domain (5 file + 1 enum):
 - Budget (header) — Aggregate root, AuditableEntity. Field: MaNganSach,
   TenNganSach, Description, NamNganSach, ProjectId FK, DepartmentId?,
   DrafterUserId, Phase (BudgetPhase 5-state), TongNganSach (sum auto
   tu Details), SlaDeadline, SlaWarningSent.
 - BudgetDetail — flat row pattern (GroupCode/GroupName + Item +
   KhoiLuong/DonGia/ThanhTien). 18,4 precision KhoiLuong, 18,2 money.
 - BudgetApproval — workflow history (FromPhase/ToPhase/Decision/Comment)
 - BudgetChangelog — audit log unified (EntityType: Header/Detail/Workflow)
 - BudgetPhase enum 5 state: DangSoanThao(1) → ChoCCM(2) → ChoCEO(3) →
   DaDuyet(4) | TuChoi(99)
 - BudgetPolicy hardcoded (no versioned WF, simple default per user
   confirm 'tam thoi don gian'): Drafter/DeptManager → CCM → CEO/
   AuthorizedSigner. Reject path back to DangSoanThao.

Migration 14 AddBudgets:
 - 4 bang moi: Budgets + BudgetDetails + BudgetApprovals + BudgetChangelogs
 - Index: Phase+IsDeleted, ProjectId, NamNganSach, SlaDeadline,
   MaNganSach unique filtered. Cascade delete child.
 - +2 cot FK ngoai bang (per user 'lien ket ca 3'):
   * Contracts.BudgetId Guid? + index
   * PurchaseEvaluations.BudgetId Guid? + index
   Cho phep doi chieu chi phi HD/PE vs ngan sach goi thau.

Application CQRS (BudgetFeatures.cs ~340 line):
 - CreateBudget + UpdateBudgetDraft + TransitionBudget + ListBudgets
   (filter Phase/Project/Year + search + paging) + GetBudget bundle
   (Header + Details + Approvals + Workflow summary)
 - DeleteBudget (only DangSoanThao/TuChoi)
 - AddBudgetDetail + UpdateBudgetDetail + DeleteBudgetDetail (auto
   recompute TongNganSach = sum Details.ThanhTien)
 - ListBudgetChangelogs

Api: BudgetsController 11 endpoint REST /api/budgets:
 - GET /  /{id}  /{id}/changelogs
 - POST /  /{id}/transitions  /{id}/details
 - PUT /{id}  /{id}/details/{detailId}
 - DELETE /{id}  /{id}/details/{detailId}

DbContext + IApplicationDbContext: 4 DbSet new (Budgets/Details/
Approvals/Changelogs).

MenuKeys + DbInitializer: 4 menu key (Budgets root + Bg_List/Create/
Pending leaves) seed dau order=27 'Ngan sach' icon Wallet. Auto-grant
admin permission via SeedAdminPermissionsAsync (MenuKeys.All).

MaNganSach format don gian 'NS-YYYYMM-NNNN' Random.Shared (chua atomic
sequence - user said 'tam thoi chua co').

Workflow chua versioned, hardcode BudgetPolicy.Default. Tuong lai admin
config qua UI: them BudgetWorkflowDefinition tables tuong tu PE.
2026-04-28 11:37:45 +07:00
8097892d20 [CLAUDE] Infra: them 14 demo users Solutions company (PRO 5 + CCM 7 + ISO 1 + CEO 1)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m11s
User cung cap danh sach nhan vien thuc te. Add vao SeedDemoUsersAsync,
idempotent (FindByEmail trong reconcile pattern). Pass = User@123456
(matching demo pattern, policy 12 char + digit + lower + upper + special).

PRO (5):
 - tra.bui — Bui Le Thuy Tra — TP Cung ung (Procurement+DeptManager)
 - phuong.nguyen — Nguyen Thi Bich Phuong (Procurement+Drafter)
 - thanh.lethanh — Le Thanh Binh (Procurement+Drafter)
 - long.chau — Chau Ta Kim Long (Procurement+Drafter)
 - duy.nguyen — Nguyen Van Duy (Procurement+Drafter)

CCM (7):
 - chuong.phan — Phan Van Chuong — TP Kiem soat Chi phi (CostControl+DeptManager)
 - binh.le — Le Van Binh (CostControl)
 - luu.tran — Tran Xuan Luu (CostControl)
 - nguyen.ho — Ho Thi Nu Nguyen (CostControl)
 - anh.nguyen — Nguyen Thi Kim Anh (CostControl)
 - tring.le — Le Tu Dang Trinh (CostControl) — giu literal user provided
 - truong.le — Le Tran Dang Truong (CostControl)

ISO (1):
 - long.nguyen — Nguyen Hoang Chanh Long — Dep HRA, role HrAdmin (dong dau HD)

CEO (1):
 - truong.nguyen — Nguyen Van Truong — Dep BOD, role Director (ASCII fix tu 'truong.nguyen' co dau)

Email typo fix:
 - 'phuong.nguyen@soluttions.com' → 'phuong.nguyen@solutions.com.vn'
 - 'truong.nguyen' co dau → 'truong.nguyen' ASCII (KHONG conflict voi truong.le CCM)

Reconcile pattern dam bao: neu user da exist (email collision), update
dept/position/role thay vi error. Pass khong overwrite cho existing user.
2026-04-28 10:51:56 +07:00
309dcd9768 [CLAUDE] Docs: chot final session 3 — audit MD + session log + minor fixes
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m58s
Audit toan bo MD theo yeu cau 'review cap nhat va tai cau truc'.

Minor fixes outdated:
 - docs/database/database-guide.md: header note '47 bang 13 migration' +
   redirect schema-diagram cho actual schema. Email demo +
   admin@solutions.com.vn (thay solutionerp.local).
 - docs/guides/runbook.md: reset-password email moi.

Session log moi: docs/changelog/sessions/2026-04-25-1430-chot-session-3-
final-cleanup.md
 - Cleanup outcomes: archive 2 raw + compact migration-todos -71% +
   compact STATUS In Progress -50% + update outdated refs.
 - Skill audit 6 skill: tat ca Active (3 skill da update voi PE/G-084
   cross-ref session truoc).
 - Stats session 3 cong don 3 phien 23-24-25: 47 DB tables, 13 migrations,
   ~113 endpoints, 38 gotchas, ~30 commits.
 - Priority 0 session 4: 3 PE feature gap (Designer UI, Y kien 4 phong
   ban, Export PDF) + Ops blockers.
 - Notes session 4: email moi, 3 domain prod, old fallback, G-084, SSH.
2026-04-25 23:40:11 +07:00
e71e0eba65 [CLAUDE] Docs: tai cau truc cleanup — archive raw, compact migration-todos, update CLAUDE+flows
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m53s
User request: 'review cap nhat va tai cau truc lai MD sao cho phu hop
voi hien tai, cac phan thua va da dieu chinh co the bo ra luon hoac
cap nhat lai'.

Cleanup highlights:
1. Archive 2 file Phase 0 raw dump → docs/_archive/ (forms-spec-raw 657
   line + workflow-raw 62 line). Update link reference 2 file goc.
2. Compact migration-todos.md 386 → 114 line (-71%). Collapse Phase 0-5
   + Tier 3 + Sessions detailed thanh 1 bang summary. Detail xem session
   logs. Phase 6 iter 1+2 + Phase 7 active checklist.
3. Compact STATUS.md In Progress: bo ~17 row  done (giu chỉ 5+ task
   pending: 3 PE feature gap + 4 optional polish + 2 Ops). Recently Done
   table giu day du history.
4. Update flows/README — tat ca 6 flow  Implemented + them PE row
   reference architecture.md §9.
5. Update docs/CLAUDE.md — project layout co PurchaseEvaluations, _archive,
   skills 6 (3 dom + 3 ops). Roadmap them Phase 6  + Phase 7 WIP. Lien
   he them prod URL solutions.com.vn + SSH config + login admin.
6. Skill ef-core-migration: 13 migration label.

Net delta: -800 line docs (chu yeu archive + collapse migration-todos).
2026-04-25 14:17:53 +07:00
e65578a821 [CLAUDE] Docs: chot session 3 — PE polish iter 2 + domain rebrand + 5 gotcha moi
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m55s
User request: 'Chot lai toan bo MD de sang session moi'.

Session 3 (2026-04-24) — ~15 commit feat/fix PE module + domain migration:
 - Domain 3 subdomain huypham.vn → solutions.com.vn E2E live
 - PE rename 'Phuong An' → 'Giai phap' + backfill DB
 - Menu tree inheritance extend Pe_*/PeWf_*
 - Accordion mutex Pe_* + sidebar w-72 + label nowrap
 - NavLink queryMatches (fix 2 leaf cung highlight)
 - PE detail flat layout: Panel 2 = 4 section, Panel 3 + approvals/history
 - Upload file dinh kem per-NCC (SupplierAttachmentsCell) + Bang so sanh tong
 - readOnly mode menu 'Duyet' (pendingMe=1)
 - HD move Lich su dieu chinh → Panel 3
 - Demo email rebrand @solutionerp.local → @solutions.com.vn + BackfillUserEmailDomain

Docs updated (6 file):
 - STATUS.md: +9 row Recently Done session 3. In Progress tick 10+ done. Phase
   hien tai = 'UX polish hoan thien, UAT-ready'.
 - HANDOFF.md: TL;DR session 3 summary. Priority 0 = 3 task MISSING cuoi
   (Designer UI, Y kien 4 phong ban, Export PDF). Login email moi.
 - gotchas.md: +5 entry (#34 NavLink query, #35 menu inheritance extend,
   #36 Vite env rebuild, #37 PS 5.1 ASCII, #38 Identity rename 4 field) +
   checklist debug +5 entry.
 - ef-core-migration SKILL: migration 13 AddPurchaseEvaluationCodeSequences
   + Phase 6 update section (ComparisonTable enum + BackfillUserEmail).
 - skills/README: ef-core-migration 13 migration label updated.
 - docs/changelog/sessions/2026-04-24-chot-session-3-pe-polish.md: session log
   15 commit + bugs + stats + next priorities session 4.

Memory project_solution_erp.md: Phase 6 iter 2 DONE. Domain rebrand DONE.
Session 4 priority 3 PE gap remaining.

Stats: 47 DB tables (+1 MaPhieu seq), ~113 endpoint (+3 PE attachments),
13 migrations, 38 gotchas, ~85 commits total.
2026-04-25 00:37:30 +07:00
a336997cfe [CLAUDE] PE: section Bang so sanh + rename demo email @solutions.com.vn
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m10s
PART A: Section 'Bang so sanh' (file tong ho so so sanh)

User request: 'theo them cho thong tin ve Bang so sanh, cho dinh kem
file so sanh tong len'.

BE:
 - PurchaseEvaluationAttachmentPurpose.ComparisonTable = 4 (new enum value)
   Backend validator IsInEnum pass, khong can migration (int column).

FE types (2 app):
 - PeAttachmentPurpose.ComparisonTable + Label '4: Bang so sanh'.

FE PeDetailTabs:
 - Them section thu 4 'Bang so sanh (file tong)' sau 'Hang muc + Bao gia'.
 - Component GeneralAttachmentsSection: upload KHONG truyen supplierRowId
   (BE luu NULL) → purpose=ComparisonTable default. Filter attachments
   co supplierRowId===null de render.
 - Card layout khac SupplierAttachmentsCell: full-width card + brand color
   + purpose chip + date. Upload button to hon ([+ Tai len bang so sanh]).
 - readOnly hide upload + delete, giu download.

PART B: Demo email rebrand @solutionerp.local → @solutions.com.vn

User request: 'tao nguoi dung demo theo email cua ben nay'.

BE DbInitializer:
 - Rename 18 email in source: AdminEmail const + 17 demo users
   (bod/pm/ccm/pro/fin/act/equ/hra/qs/nv) — keep password + role unchanged.
 - Them BackfillUserEmailDomainAsync (idempotent): scan user co email
   @solutionerp.local, rename sang @solutions.com.vn, update Email +
   NormalizedEmail + UserName + NormalizedUserName. Skip neu co conflict
   user da ton tai voi email moi. Chay truoc SeedAdmin de tranh tao
   duplicate admin.

Admin permission tao user da co san qua /system/users page.
Comment input khi duyet da co san o PeWorkflowPanel (Ghi chu tuy chon
Textarea) + ContractDetailContent (Yeu cau sua / Duyet tiep dialog).
2026-04-24 15:08:00 +07:00