Files
solution-erp/docs/changelog/sessions/2026-04-23-2200-roles-demo-pending-cleanup.md
pqhuy1987 a7ea6ad3d6
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m48s
[CLAUDE] Docs: chốt session 2026-04-23 tối — UAT-ready 100%
5 commit feature work session 2 (072ad6dbcdc007) — 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 commit 072ad6d ref

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 16:07:20 +07:00

10 KiB
Raw Blame History

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 (072ad6dbcdc007), 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 072ad6dbcdc007

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