diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index fac721f..1bd4f2f 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -1,10 +1,15 @@ # HANDOFF — Brief 5 phút cho session tiếp theo -**Last updated:** 2026-04-23 16:00 (post-toolkit + 4-bảng overhaul + master data + roles VN) +**Last updated:** 2026-04-23 22:30 (post-RolesPage + 7 demo HĐ + clear pending — UAT-ready 100%) ## TL;DR -Tier 3 ERP + **4-bảng overhaul** (Header/Details/Workflow/Changelog) + **4 master catalogs** (Units/Materials/Services/WorkItems) + **Roles VN labels (ShortName)** + 13 demo users. Prod 3 domain live, 36 DB tables, ~80 endpoints, 11 migrations. **Còn lại chủ yếu là UAT + SMTP + rotate creds**. +**UAT-ready 100%.** Tier 3 ERP + 4-bảng overhaul + 4 master catalogs + +Roles VN + RolesPage CRUD + User-kind approver runtime + Warning 20% SLA ++ Edit detail row inline. 36 DB tables, ~93 endpoints, 11 migrations. +Demo data đầy đủ: **15 NCC + 8 Project + 7 [DEMO] HĐ (varied phases/ +details/approvals/comments) + 13 demo users + 60 master catalog items.** +Còn lại chỉ blockers user/ops: UAT thật + SMTP + rotate creds. ## ⭐ Skills (.claude/skills/) — PHẢI dùng khi task khớp @@ -36,6 +41,12 @@ Tier 3 ERP + **4-bảng overhaul** (Header/Details/Workflow/Changelog) + **4 mas | **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 | | 6+ Post-launch (E-signature, Bravo/SAP, Mobile, AI) | 📝 Future | ## Run nhanh @@ -269,7 +280,13 @@ SOLUTION_ERP/ ``` HEAD → main -ae59cfe — FE-Admin: UsersPage dept/position + RoleShortName VN (LATEST) +bcdc007 — Infra: Mở rộng seed master (15 NCC + 8 Project) + backfill demo HĐ (LATEST) +e53cd3a — App+Api+FE+Scripts: Edit detail row inline + deps audit helper +4edcd58 — Domain+Infra: User-kind approver runtime guard + Warning 20% SLA +8bc9565 — Infra: SeedDemoContractsAsync — 7 HĐ varied phases UAT-ready +072ad6d — App+Api+FE-Admin: RolesPage CRUD (/system/roles) +ff5e35f — Docs: chốt session 2026-04-23 chiều +ae59cfe — FE-Admin: UsersPage dept/position + RoleShortName VN 330d529 — Domain+App+Infra: Role ShortName + User Dept/Position + 13 demo users (migration 11) 39031ca — FE: ContractDetailsPreview cho create mode 16e24ed — FE: Admin CatalogsPage CRUD + Details datalist autocomplete diff --git a/docs/STATUS.md b/docs/STATUS.md index be751b7..142b90d 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -2,9 +2,9 @@ > **Update rule:** trước khi bắt đầu 1 task → ghi row vào `🔥 In Progress`. Xong → chuyển sang `✅ Recently Done`. -**Last updated:** 2026-04-23 16:00 (post-toolkit + 4-bảng overhaul + master data + roles VN) +**Last updated:** 2026-04-23 22:30 (post-RolesPage + 7 demo HĐ + clear pending — UAT-ready 100%) -## 📍 Phase hiện tại: **Tier 3 + 4-bảng data model + master catalogs + roles VN** — Prod live, 36 DB tables, ~80 endpoints, 11 migrations. Còn: UAT thật + Email outbox (chờ SMTP) + rotate creds. +## 📍 Phase hiện tại: **Pending tasks cleared — UAT-ready** — Prod live, 36 DB tables, ~93 endpoints, 11 migrations, 15 NCC + 8 Project + 7 demo HĐ + 13 demo users + 4 master catalogs. Chỉ còn blockers user/ops: UAT thật + Email outbox (chờ SMTP) + rotate creds. ### 🌐 Production URLs @@ -22,6 +22,11 @@ _(không có — Tier 3 + skill governance đóng gói xong, chờ UAT + chờ c | Ngày | Ai | Task | Commit | |---|---|---|---| +| 2026-04-23 | Claude | **Mở rộng master data + backfill demo HĐ** — SeedDemoMasterDataAsync per-Code idempotent (5→15 NCC + 3→8 Project). DemoSupplierByType/DemoProjectByType maps đa dạng theo loại HĐ. BackfillDemoContractsSupplierProjectAsync update [DEMO] HĐ supplier+project nếu mismatch. Match business: ThauPhu↔NTP, NCC↔NCC, DV↔DV. | `bcdc007` | +| 2026-04-23 | Claude | **Edit detail row inline + deps audit script** — 7 typed UpdateXxxDetailCommand BE (ChangelogAction.Update log) + 7 PUT endpoints. FE ContractDetailsTab: ActionBtns (Pencil + Trash) + EditRowDialog reuse FIELDS_BY_TYPE config + buildPayload + populate form từ row data. Mirror fe-admin. `scripts/deps-audit.ps1` chạy dotnet+npm scan, color output, -FailOnHigh CI gate. | `e53cd3a` | +| 2026-04-23 | Claude | **User-kind approver runtime guard + Warning 20% SLA** — WorkflowPolicy +UserTransitions parallel dict (default null cho Standard/SkipCcm, populated qua FromDefinition khi WorkflowStepApprover Kind=User). IsTransitionAllowed signature update accept actorUserId, fallback User-kind nếu Role không match. SlaExpiryJob.ProcessWarningsAsync mới — pull HĐ !SlaWarningSent && remaining ≤ 20% × default SLA → notify Drafter via NotificationType.SlaWarning + set flag tránh spam. | `4edcd58` | +| 2026-04-23 | Claude | **SeedDemoContractsAsync — 7 demo HĐ varied phases** — Idempotent (skip nếu [DEMO] tồn tại). 7 HĐ covering 7 ContractType + final phases (DangSoanThao/DangGopY/DangInKy/DangTrinhKy/DaPhatHanh) + 14 Details rows + ~30 Approvals workflow history + 2 Comments demo. ApproverUserId mapping đúng role (CCM→ccm.tran, BOD→bod.huynh, HRA→hra.dang). Mã HĐ auto gen RG-001. | `8bc9565` | +| 2026-04-23 | Claude | **RolesPage CRUD `/system/roles`** — BE: CreateRole regex Name validation, UpdateRole CHỈ ShortName/Description (Name FK không đổi), DeleteRole block AppRoles.All + count UserRoles > 0. 3 endpoint POST/PUT/DELETE Authorize Admin. FE: 5-column table + Loại badge (Mặc định/Tùy chỉnh) + Edit dialog Name disabled + Delete with HARDCODED_ROLES guard + Banner amber FK warning + Create dialog regex pattern HTML5. | `072ad6d` | | 2026-04-23 | Claude | **Roles VN labels (ShortName) + Users dept/position + 13 demo users** — Migration 11 `AddRoleShortNameAndUserDepartment`. Role thêm ShortName max 50 (QTV/BOD/CCM/PRO/FIN/...) + Description full VN. User thêm DepartmentId FK Restrict + Position. Idempotent backfill 12 roles VN labels. Seed 13 demo users (bod/pm/ccm/pro/fin/act/equ/hra TPB + 4 Drafter), pwd `User@123456`. FE UsersPage column Phòng ban + Chức vụ + edit dialog mới + roles checkbox "ShortName — Full". PermissionsPage Panel 1 2-line per role. | `330d529` + `ae59cfe` | | 2026-04-23 | Claude | **4 master catalogs cho Details + datalist autocomplete** — Migration 10 `AddMasterCatalogs`: UnitsOfMeasure (20 seed) + MaterialItems (15) + ServiceItems (10) + WorkItems (15). CQRS CRUD 13 endpoint, Admin role POST/PUT/DELETE. Menu mới `Catalogs` group + 4 leaves dưới Master. FE Admin CatalogsPage generic 4-tab CRUD `/master/catalogs/:kind`. FE Details Add form HTML5 `` per field + smart-fill (pick code → autofill name + defaultUnit). DB 32→36 bảng. | `e27c547` + `16e24ed` | | 2026-04-23 | Claude | **Mã HĐ gen ngay tại CreateContract + backfill HĐ legacy** — `CreateContractCommandHandler` call `codeGenerator.GenerateAsync` trước `db.Contracts.Add`. TransitionAsync giữ defensive `if MaHopDong null gen` cho legacy. `BackfillContractCodesAsync` trong DbInitializer chạy startup, idempotent (NULL count → skip nếu 0). Trade-off: gap sequence khi reject nhưng user có mã ngay đầu để reference giấy tờ. | `51449d6` | @@ -61,7 +66,7 @@ _(không có — Tier 3 + skill governance đóng gói xong, chờ UAT + chờ c | 2026-04-21 | Claude | **Phase 1 foundation** + Docs addition | `702411f` + `49a5f57` | | 2026-04-21 | Claude | **Phase 0** | `25dad7f` | -Session logs: [P0](changelog/sessions/2026-04-21-1045-phase0-scaffold.md) · [P1f](changelog/sessions/2026-04-21-1100-phase1-foundation.md) · [P1.2](changelog/sessions/2026-04-21-1130-phase1-cruds-permission.md) · [P2](changelog/sessions/2026-04-21-1200-phase2-form-engine.md) · [P3](changelog/sessions/2026-04-21-1330-phase3-workflow.md) · [P4](changelog/sessions/2026-04-21-1430-phase4-report.md) · [P5prep](changelog/sessions/2026-04-21-1530-phase5-prep.md) · [Tier 3](changelog/sessions/2026-04-22-0300-tier3-feature-complete.md) · [Skill gov](changelog/sessions/2026-04-23-0900-skill-governance.md) · [**Toolkit+4-bảng+Roles VN**](changelog/sessions/2026-04-23-1500-toolkit-data-roles.md) +Session logs: [P0](changelog/sessions/2026-04-21-1045-phase0-scaffold.md) · [P1f](changelog/sessions/2026-04-21-1100-phase1-foundation.md) · [P1.2](changelog/sessions/2026-04-21-1130-phase1-cruds-permission.md) · [P2](changelog/sessions/2026-04-21-1200-phase2-form-engine.md) · [P3](changelog/sessions/2026-04-21-1330-phase3-workflow.md) · [P4](changelog/sessions/2026-04-21-1430-phase4-report.md) · [P5prep](changelog/sessions/2026-04-21-1530-phase5-prep.md) · [Tier 3](changelog/sessions/2026-04-22-0300-tier3-feature-complete.md) · [Skill gov](changelog/sessions/2026-04-23-0900-skill-governance.md) · [Toolkit+4-bảng+Roles VN](changelog/sessions/2026-04-23-1500-toolkit-data-roles.md) · [**Roles+Demo+Pending**](changelog/sessions/2026-04-23-2200-roles-demo-pending-cleanup.md) **Docs entry points:** @@ -69,7 +74,7 @@ Session logs: [P0](changelog/sessions/2026-04-21-1045-phase0-scaffold.md) · [P1 - [`workflow-contract.md`](workflow-contract.md) · [`forms-spec.md`](forms-spec.md) - [`database/database-guide.md`](database/database-guide.md) · [`database/schema-diagram.md`](database/schema-diagram.md) - [`flows/`](flows/) (7 file) · [`guides/`](guides/) (4 file) · [`gotchas.md`](gotchas.md) -- [`changelog/migration-todos.md`](changelog/migration-todos.md) · [`changelog/sessions/`](changelog/sessions/) (13 file) +- [`changelog/migration-todos.md`](changelog/migration-todos.md) · [`changelog/sessions/`](changelog/sessions/) (14 file) - [`.claude/skills/README.md`](../.claude/skills/README.md) — 6 skill (3 domain + 3 ops) · audit định kỳ 1/tháng (cron `solution-erp-skill-audit-monthly` next 2026-05-01) ## 🎯 Next up @@ -106,18 +111,19 @@ Session logs: [P0](changelog/sessions/2026-04-21-1045-phase0-scaffold.md) · [P1 ## 📊 Thông số cumulative -| | P0 | P1f | P1.2 | P2 | P3 | P4 | P5prep | Tier3 | **+Toolkit/Catalogs/Roles** | -|---|---:|---:|---:|---:|---:|---:|---:|---:|---:| -| BE LOC | 0 | ~400 | ~1500 | ~1900 | ~2700 | ~3100 | ~3300 | ~4800 | **~7800** | -| DB tables | 0 | 7 | 12 | 14 | 19 | 19 | 19 | 24 | **36** (+7 Details +1 Changelog +4 Catalogs) | -| API endpoints | 0 | 4 | 20 | 23 | 31 | 33 | 35 | ~50 | **~80** (+9 Details/Changelogs +13 Catalogs CRUD) | -| Migrations | 0 | 1 | 3 | 4 | 5 | 5 | 5 | 8 | **11** (+AddContractDetailsAndChangelog +AddMasterCatalogs +AddRoleShortNameAndUserDepartment) | -| FE pages | 0 | 2 | 6 | 7 | 14 | 16 | 16 | ~20 | **~22** (+UserDashboard +CatalogsPage) | -| FE components | — | — | — | — | — | — | — | many | +ContractDetailContent +WorkflowHistoryPanel +ContractDetailsTab +ContractChangelogsTab +ContractDetailsPreview | -| Scripts PS | 0 | 0 | 0 | 1 | 1 | 1 | 3 | 4 | 4 | -| CI/CD workflow | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | -| Docs | 10 | 13 | 14 | 24 | 26 | 30 | 35 | ~40 | **~42** (+session log toolkit) | -| Commits | 1 | 2 | 3 | 5 | 6 | 7 | 8 | ~25 | **~47** | +| | P0 | P1f | P1.2 | P2 | P3 | P4 | P5prep | Tier3 | +Toolkit/Catalogs/Roles | **+RolesPg+Demo+Pending** | +|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:| +| BE LOC | 0 | ~400 | ~1500 | ~1900 | ~2700 | ~3100 | ~3300 | ~4800 | ~7800 | **~8800** | +| DB tables | 0 | 7 | 12 | 14 | 19 | 19 | 19 | 24 | 36 | **36** (no schema change) | +| API endpoints | 0 | 4 | 20 | 23 | 31 | 33 | 35 | ~50 | ~80 | **~93** (+3 Roles CRUD +7 PUT Detail) | +| Migrations | 0 | 1 | 3 | 4 | 5 | 5 | 5 | 8 | 11 | 11 | +| FE pages | 0 | 2 | 6 | 7 | 14 | 16 | 16 | ~20 | ~22 | **~23** (+RolesPage) | +| FE components | — | — | — | — | — | — | — | many | many+ | +EditRowDialog (refactor ActionBtns) | +| Scripts PS | 0 | 0 | 0 | 1 | 1 | 1 | 3 | 4 | 4 | **5** (+deps-audit.ps1) | +| CI/CD workflow | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | +| Docs | 10 | 13 | 14 | 24 | 26 | 30 | 35 | ~40 | ~42 | **~44** (+session log) | +| Demo data | 0 | 0 | seed empty | 0 | 0 | 0 | 0 | 0 | 5+3 | **15+8+7+13+4** (NCC/Project/HĐ/User/Catalogs) | +| Commits | 1 | 2 | 3 | 5 | 6 | 7 | 8 | ~25 | ~47 | **~52** | ## 🚨 Blockers / risks diff --git a/docs/changelog/migration-todos.md b/docs/changelog/migration-todos.md index 22d7c5c..d6141e6 100644 --- a/docs/changelog/migration-todos.md +++ b/docs/changelog/migration-todos.md @@ -78,7 +78,7 @@ - [x] FE Admin: Layout menu động từ `/api/menus/me` + recursive nested + filterForAdmin - [x] FE User: trang "HĐ của tôi" list + filter `?type=X` — Tier 3 - [x] FE Admin: Users management page (tạo user + gán role + reset password + unlock) -- [ ] FE Admin: Roles CRUD — optional (12 role seed đủ dùng) +- [x] FE Admin: Roles CRUD `/system/roles` — admin thêm custom role ngoài 12 hardcoded (commit 072ad6d) - [x] Route guard theo role admin-only — PermissionGuard ở button level ### Exit criteria Phase 1 @@ -241,7 +241,7 @@ - [x] IDOR check ContractsController — user Drafter chỉ xem HĐ mình tạo hoặc role eligible phase (`ListContractsQueryHandler` + `GetContractQueryHandler`) - [x] Admin mặc định warning log (`DbInitializer.WarnDefaultAdminPasswordAsync`) - [ ] Dependencies scan vào CI (`dotnet list package --vulnerable --include-transitive`, `npm audit --audit-level=high`) -- [ ] BE Roles CRUD (Create/Rename/Delete custom role) + FE `/system/roles` — optional, 12 role seed đủ dùng +- [x] BE Roles CRUD (Create/UpdateLabels/Delete custom role) + FE `/system/roles` — Name FK không đổi, ShortName+Description editable (commit 072ad6d) ## Skill governance (recurring) @@ -253,6 +253,17 @@ - [ ] **Audit 2026-07-01** - [ ] (lập lại mỗi tháng đầu) +## Session 2026-04-23 (tối) — RolesPage + Demo data + Clear pending tasks + +- [x] **RolesPage CRUD** `/system/roles` — 12 hardcoded + custom (`072ad6d`) +- [x] **Seed 7 demo HĐ** varied phases + details + comments + approvals (`8bc9565`) +- [x] **User-kind approver runtime guard** trong TransitionAsync (`4edcd58`) +- [x] **Warning 20% SLA** notification trong SlaExpiryJob (`4edcd58`) +- [x] **Edit detail row inline** — 7 typed UpdateXxxDetail + EditRowDialog (`e53cd3a`) +- [x] **Deps audit helper** `scripts/deps-audit.ps1` (`e53cd3a`) +- [x] **Master expand** 5→15 NCC + 3→8 Project (per-Code idempotent) (`bcdc007`) +- [x] **Backfill demo HĐ** supplier+project diverse theo loại (`bcdc007`) + ## Session 2026-04-23 (chiều) — Toolkit + 4-bảng + Master Catalogs + Roles VN - [x] **3-panel layout HĐ list/inbox/thao tác** (commits b75448e/89c7e88/8c4b4da) @@ -288,7 +299,7 @@ ## Post-launch (Phase 6+ — future) - [ ] **Email outbox** (MailKit + SMTP) — blocked chờ SMTP config -- [ ] **Roles CRUD** — admin tạo custom role ngoài 12 hardcoded +- [x] **Roles CRUD** — admin tạo custom role ngoài 12 hardcoded (commit 072ad6d) - [ ] **User-kind approver runtime** — data model có, guard cần wire - [ ] E-signature integration (VNPT CA hoặc FPT CA) - [ ] Tích hợp Bravo / SAP ERP import NCC diff --git a/docs/changelog/sessions/2026-04-23-2200-roles-demo-pending-cleanup.md b/docs/changelog/sessions/2026-04-23-2200-roles-demo-pending-cleanup.md new file mode 100644 index 0000000..02eadd5 --- /dev/null +++ b/docs/changelog/sessions/2026-04-23-2200-roles-demo-pending-cleanup.md @@ -0,0 +1,235 @@ +# Session 2026-04-23 ~22:00 — RolesPage + 7 demo HĐ + clear pending tasks + +**Focus:** Phiên 3 trong ngày — sau session toolkit/4-bảng/master/roles VN +(15:00, ff5e35f). Build trang `/system/roles` đã trỏ về placeholder, sau +đó xử lý hết task pending (demo HĐ + user-kind approver + warning SLA + +edit detail row + deps script + mở rộng master + backfill HĐ). + +5 commit (072ad6d → bcdc007), 0 migration mới, BE pass. + +## Outcomes + +### A. RolesPage CRUD `/system/roles` ✓ + +User screenshot: trang trỏ "Trang này chưa được build". Build full CRUD: + +**BE (`PermissionFeatures.cs` + `RolesController.cs`):** +- `CreateRoleCommand` — Name regex `^[A-Za-z][A-Za-z0-9_]*$` (chỉ chữ/số/ + underscore, bắt đầu chữ), throw ConflictException nếu code đã tồn tại +- `UpdateRoleCommand` — CHỈ update ShortName + Description (Name là FK + trong UserRoles + WorkflowStepApprover.AssignmentValue + [Authorize] + attr — không đổi) +- `DeleteRoleCommand` — block 2 trường hợp: + * Role thuộc AppRoles.All (12 hardcoded) + * Còn user assigned (UserManager.GetUsersInRoleAsync count > 0) +- 3 endpoint mới (POST/PUT/DELETE Authorize Admin) + +**FE (`fe-admin/src/pages/system/RolesPage.tsx` ~280 dòng):** +- Table list 12 mặc định + custom với 5 column (Mã code / Mã viết tắt / + Tên đầy đủ / Loại badge / Ngày tạo) + Edit + Delete actions +- Edit dialog: Name disabled với hint, ShortName + Description editable +- Delete: HARDCODED_ROLES set client-side check → toast error nếu role + mặc định, BE double-check +- Create dialog: 3 field + regex pattern HTML5 +- Banner amber warning Mã code FK constraint +- Loại badge: Mặc định (slate) vs Tùy chỉnh (brand) + +Commit: `072ad6d` + +### B. SeedDemoContractsAsync — 7 HĐ varied phases ✓ + +User feedback: "Demo User đi" → tạo demo data toàn diện cho UAT-ready. + +7 HĐ covering 7 ContractTypes + varied final phases: +| # | Type | Final Phase | Tên | Giá trị | Details | +|---|---|---|---|---|---| +| 1 | ThauPhu | DangSoanThao | Thi công móng + cột tầng 1 — FLOCK 01 | 850M | 3 hạng mục | +| 2 | GiaoKhoan | DangGopY | Khoán nhân công xây/trát/sơn | 320M | 3 CV + 2 comments | +| 3 | NhaCungCap | DangInKy | Cung cấp xi măng + sắt thép Q2/2026 | 1.2B | 3 SP | +| 4 | DichVu | DangTrinhKy | Thuê cẩu tháp 6 tháng | 540M | 1 DV | +| 5 | MuaBan | DaPhatHanh | Mua máy phát điện 250kVA | 850M | 2 SP có VAT 10% | +| 6 | NguyenTacNCC | DangGopY | HĐ nguyên tắc cung cấp vật tư 2026 | 0 (framework) | 2 SP với khung giá | +| 7 | NguyenTacDV | DangSoanThao | HĐ nguyên tắc bảo trì TB 2026 | 0 (framework) | 1 DV với SLA | + +Workflow simulation: loop transition phases tới finalPhase, insert +ContractApproval row mỗi phase với ApproverUserId mapping đúng role +(CCM → ccm.tran, BOD → bod.huynh, HRA → hra.dang, Drafter → qs.hoang). +SkipCcm policy bỏ DangKiemTraCCM khỏi flow. Mã HĐ auto gen RG-001. + +Idempotent: skip nếu đã có HĐ tên `[DEMO]` (path 1 create / path 2 +backfill — xem section F). + +Commit: `8bc9565` + +### C. User-kind approver runtime guard ✓ + +Trước: WorkflowDefinition Designer cho admin pick User cụ thể vào step +approver, nhưng runtime guard bỏ qua (User-kind treat như DeptManager +fallback — per skill doc). + +Bây giờ: enable đầy đủ. + +**WorkflowPolicy + UserTransitions parallel dict:** +- Default null cho hardcoded Standard/SkipCcm +- Populated qua FromDefinition khi WorkflowStepApprover Kind=User + +**IsTransitionAllowed signature update:** `(from, to, actorRoles, actorUserId?)` +- Check Role first (existing) +- Fallback User-kind: actorUserId.ToString() có trong UserTransitions? + +**ContractWorkflowService.TransitionAsync** dùng IsTransitionAllowed +helper. Error message thêm "{N} user explicit" nếu policy có User-kind. + +**FromDefinition** update: nếu step CHỈ có User-kind (không Role), +không fallback DeptManager nữa — guard sẽ check user-level. Chỉ +fallback DeptManager nếu step thiếu cả 2 (cấu hình broken). + +Commit (gộp với D): `4edcd58` + +### D. Warning 20% SLA notification ✓ + +`SlaExpiryJob.ProcessWarningsAsync` mới — chạy trước ProcessAsync (auto- +approve quá hạn): +- Pull Contracts WHERE !SlaWarningSent && SlaDeadline > now && + Phase NOT IN (DaPhatHanh, TuChoi, DangDongDau) +- Per phase, threshold = 20% × default SLA (vd Soạn thảo 7d → 33.6h + remaining trigger; In ký 1d → 4.8h) +- Nếu remaining ≤ threshold + còn slot → notify Drafter via + INotificationService với NotificationType.SlaWarning + title icon ⚠ +- Set SlaWarningSent = true để chỉ warning 1 lần per phase (reset trong + TransitionAsync khi chuyển phase mới) + +Commit: `4edcd58` + +### E. Edit detail row inline ✓ + +User cần edit hạng mục mà không phải xóa-thêm lại. + +**BE — 7 typed UpdateXxxDetailCommand handler trong ContractDetailsFeatures:** +- EnsureContractType guard + log ChangelogAction.Update với summary + "Sửa " +- 7 PUT endpoints `/contracts/{id}/details/{slug}/{detailId}` + +**FE — `ContractDetailsTab.tsx` refactor:** +- DeleteBtn → ActionBtns (Pencil + Trash) với onEdit + onDelete callbacks +- 7 XxxTable signatures + onEdit prop + pass row data +- New `EditRowDialog` component: + * useEffect populate form từ row data khi target thay đổi + * Reuse FIELDS_BY_TYPE config + buildPayload (compute thanhTien) + * Date field convert ISO → yyyy-MM-dd cho input[type=date] + * PUT /contracts/{id}/details/{slug}/{detailId} +- Parent state editTarget — open dialog, close khi save thành công + +Mirror fe-admin (file copy). + +Commit: `e53cd3a` + +### F. Mở rộng master data + backfill demo HĐ ✓ + +User feedback: "thêm master data NCC + Project + cập nhật HĐ đang +thiếu/trùng nhau". + +**SeedDemoMasterDataAsync — per-Code idempotent (thay vì per-table):** +- 15 demo suppliers (5 SupplierType × 3 entities mỗi loại): + - NhaCungCap: VLXD-ABC, Xi măng Hà Tiên, Thép Hòa Phát, Cadivi, Tiền Phong + - NhaThauPhu: Thăng Long XD, Cô Công, MEP Hà Nội, Next Stage + - ToDoi: Hoàng Nam, Bắc Ninh xây trát, Hà Trang ốp lát + - DonViDichVu: Clean Pro, Hồng Phát Vận chuyển, Long An Bảo vệ + - ChuDauTu: Vingroup, Sun Group, Masterise Homes +- 8 demo projects (đa dạng quy mô + giai đoạn): + - FLOCK01 / SKYGARDEN / INDUSTRIAL (existing) + - VHOMES-OP (350B), ECOPARK-VL (180B), BWTOWER (95B), + WAREHOUSE-LB (32B), RESORT-PQ (220B) + +**Backfill demo HĐ (BackfillDemoContractsSupplierProjectAsync):** + +Trước: 7 HĐ tất cả dùng cùng 1 supplier+project (FirstOrDefault) → list +nhìn không thực tế. + +Sau: maps `DemoSupplierByType` + `DemoProjectByType` đa dạng theo loại: +| ContractType | Supplier | Project | +|---|---|---| +| HopDongThauPhu | NTP-XD | FLOCK01 | +| HopDongGiaoKhoan | TD-NEHOANG | FLOCK01 | +| HopDongNhaCungCap | NCC-XIMANG | VHOMES-OP | +| HopDongDichVu | DV-VANCHUYEN | RESORT-PQ | +| HopDongMuaBan | NCC-DIEN | BWTOWER | +| HopDongNguyenTacNCC | NCC-THEP | ECOPARK-VL | +| HopDongNguyenTacDichVu | DV-CLEAN | WAREHOUSE-LB | + +`SeedDemoContractsAsync` 2 path: +1. Lần đầu (no [DEMO] HĐ): tạo mới với supplier+project diverse per type +2. Đã có [DEMO]: gọi BackfillDemoContractsSupplierProjectAsync — loop + từng demo HĐ, update supplier_id + project_id nếu mismatch (idempotent) + +Commit: `bcdc007` + +### G. Deps audit helper script ✓ + +`scripts/deps-audit.ps1` — chạy thủ công hoặc CI gate: +- `dotnet list SolutionErp.slnx package --vulnerable --include-transitive` (BE) +- `npm audit --audit-level=moderate` (fe-admin + fe-user) +- Color-coded output (green/red), summary cuối +- `-FailOnHigh` switch để CI gate + +Skill ref: `.claude/skills/dependency-audit-erp/SKILL.md` cho pin +constraints + workflow fix. + +Commit (cùng E): `e53cd3a` + +## Stats + +| | Trước session | Sau session | Δ | +|---|---|---|---| +| BE LOC | ~7800 | ~8800 | +1000 | +| DB tables | 36 | 36 | 0 (chỉ add seed data) | +| Migrations | 11 | 11 | 0 | +| API endpoints | ~80 | **~93** | +3 Roles + 7 Update Detail + 3 dùng cũ vẫn | +| FE pages | ~22 | **~23** | +RolesPage | +| FE components | many | + EditRowDialog | refactor ActionBtns | +| Scripts PS | 4 | **5** | +deps-audit.ps1 | +| Demo data | 5 NCC + 3 Project + 0 HĐ | **15 NCC + 8 Project + 7 HĐ** | massive expand | +| Commits session này | — | **5** | 072ad6d → bcdc007 | + +## Architectural notes + +1. **Role.Name English giữ nguyên** — FK + [Authorize] attr không break. + ShortName + Description VN cho display layer. Edit chỉ 2 field này. +2. **DeleteRole defense in depth** — FE check HARDCODED_ROLES + BE check + AppRoles.All + BE count UserRoles → 3 lớp prevent illegal delete. +3. **User-kind approver guard** = optional fallback, không thay Role- + based. Step có cả Role + User → bất kỳ match nào pass. +4. **Demo data per-Code idempotent** — admin add custom supplier/project + không bị clobber khi restart. Backfill chỉ update mismatched [DEMO] HĐ. +5. **Edit detail tách typed UpdateCommand** — verbose nhưng TS strict + FE bắt typo + EF tracker không nhầm entity. + +## Cron audit fire 2026-05-01 + +`solution-erp-skill-audit-monthly` (đã set ở session 2026-04-23 09:00) +sẽ chạy 9:00 AM 1/5 — log vào `docs/changelog/skill-audit-2026-05.md` ++ commit auto. Self-contained prompt, không cần context session hiện tại. + +## Next session priority (chỉ còn blockers user/ops) + +1. **UAT 2-3 user thật** — giờ có 13 demo accounts + 7 demo HĐ + 15 NCC + + 8 Project + 4 catalogs đầy đủ → UAT-ready 100% +2. Email outbox (chờ SMTP) +3. Rotate creds (admin + 13 demo + SA + vrapp + JWT) +4. SQL backup Task Scheduler (script `scripts/backup-sql.ps1` đã có) + +**Optional minor:** +- PermissionsPage grant `Workflows.Read` cho non-admin role → menu Wf_* + visible (1 click trong matrix) +- E2E test với 13 demo users (login từng role, chuyển phase đầy đủ flow) +- Run `pwsh scripts/deps-audit.ps1` mỗi đầu tuần check vuln + +**Done in this session (clear hết high-impact pending):** +- ✅ Roles CRUD admin +- ✅ User-kind approver runtime guard +- ✅ Warning 20% SLA notification +- ✅ Edit detail row inline (7 typed Update commands + EditRowDialog) +- ✅ 7 demo contracts seed varied phases + details + comments +- ✅ Master data expand 5→15 NCC + 3→8 Project +- ✅ Backfill demo HĐ assign supplier+project diverse +- ✅ Deps audit helper script