[CLAUDE] Docs: chốt session 2026-04-23 tối — UAT-ready 100%
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m48s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m48s
5 commit feature work session 2 (072ad6d→bcdc007) — clear hết task pending high-impact, sẵn sàng UAT. ## Session log mới `docs/changelog/sessions/2026-04-23-2200-roles-demo-pending-cleanup.md` ~270 dòng — outcome A→G (RolesPage + 7 demo HĐ + User-kind guard + Warning SLA + Edit detail + Master expand + Deps script), stats, architectural notes, next priority. ## STATUS.md - Last updated 2026-04-23 22:30 — UAT-ready 100% - Header phase: "Pending tasks cleared — UAT-ready" - 5 Recently Done row mới (RolesPage, demo HĐ, user-kind+SLA, edit detail+deps, master expand+backfill) - Cumulative table thêm cột "+RolesPg+Demo+Pending": - LOC ~7800 → ~8800 - Endpoints ~80 → ~93 - FE pages ~22 → ~23 (RolesPage) - Scripts 4 → 5 (deps-audit.ps1) - Demo data 5+3 → 15+8+7+13+4 (NCC/Project/HĐ/User/Catalogs) - Commits ~47 → ~52 - Session log link mới - Skills count = 14 file ## HANDOFF.md - TL;DR cập nhật: UAT-ready 100%, demo data đầy đủ inventory - Phase table thêm 6 row Done (RolesPage, demo HĐ, user-kind+SLA, edit detail, master expand, deps script) - Git state 8 commit gần nhất ## migration-todos.md - Section "Session 2026-04-23 (tối)" với 8 ticked checkbox + commit refs - 3 Roles CRUD checkbox legacy → ticked với commit072ad6dref Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -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
|
||||
|
||||
@ -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 <hạng mục/SP/CV/...>"
|
||||
- 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
|
||||
Reference in New Issue
Block a user