Files
solution-erp/docs/changelog/sessions/2026-04-23-1500-toolkit-data-roles.md
pqhuy1987 ff5e35f279
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m47s
[CLAUDE] Docs: chốt session 2026-04-23 chiều — toolkit + 4-bảng + master + roles VN
11 commit feature work (b75448eae59cfe) → docs sync.

## STATUS.md

- Last updated 2026-04-23 16:00
- Phase header: Tier 3 + 4-bảng + master catalogs + roles VN
- 7 Recently Done row mới (3-panel layout, 4-bảng overhaul, Thao tác
  2-panel, Mã HĐ gen Create, master catalogs, roles VN demo users)
- Cumulative table thêm cột "+Toolkit/Catalogs/Roles" (DB 36, endpoints
  ~80, migrations 11, commits ~47)
- Session log link mới
- Skill list count = 13 file

## HANDOFF.md

- TL;DR cập nhật: 36 tables, 80 endpoints, 11 migrations
- Phase table thêm 5 row Done (3-panel, 4-bảng, mã HĐ, master, roles)
- Git state 18 commit gần nhất
- Credentials block thêm 13 demo user (User@123456) — warn rotate trước UAT

## migration-todos.md

Section "Session 2026-04-23 (chiều)" với 14 ticked checkbox + commit refs.

## schema-diagram.md

- Header: 24 → 36 bảng
- Migration table thêm row 9-11 (highlighted)
- Section 8bis mới: chi tiết 7 Details + ContractChangelogs + 4 Catalogs +
  Role.ShortName + User.DepartmentId/Position

## Session log mới

`docs/changelog/sessions/2026-04-23-1500-toolkit-data-roles.md` (~270
dòng) — outcome A→I, stats cumulative, 6 architectural decisions, next
session priority.

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

11 KiB
Raw Blame History

Session 2026-04-23 ~15:00 — Toolkit + 4-bảng overhaul + master data + roles VN

Focus: Sang phiên 2 trong ngày — UX redesign toàn bộ surface HĐ (3-panel List/Detail/Workflow + Inbox + Thao tác), data model overhaul 4-bảng (Header/Details/Workflow/Changelog), master catalogs cho Details, chi tiết Users/Departments/Roles VN.

11 commit (b75448eae59cfe), 2 migration (9 + 10 + 11), DB 24→36 bảng.

Outcomes

A. 3-panel layout cho List/Inbox (UX) ✓

  • MyContractsPage (fe-user): lg:grid-cols-[320px_1fr_360px] — Panel 1 List + search + filter | Panel 2 Detail content | Panel 3 Workflow + Lịch sử duyệt
  • ContractsListPage (fe-admin): same pattern + Pagination compact
  • InboxPage (fe-user): same + 4 StatPill inline (Cần xử lý / Sắp QH / Quá hạn / Giá trị) + vai trò amber banner
  • URL state ?id= selected — bookmarkable, refresh giữ
  • Mobile fallback (<lg): click row → fullpage /contracts/:id
  • Components reuse: ContractDetailContent + WorkflowHistoryPanel
  • Commits: b75448e, 89c7e88

B. Sidebar accordion cho 7 loại HĐ ✓

  • Chỉ 1 group Ct_<Code> expand cùng lúc (accordion)
  • Auto-expand theo URL ?type=X qua useEffect + AccordionContext
  • Highlight active group: bg-slate-50 + text-slate-900
  • Commit: 7ea3957

C. Tách "Tổng quan" → /dashboard riêng (fix bug trùng /inbox) ✓

  • UserDashboardPage mới: 5-card "Của tôi" (DraftsInProgress / Pending / DueSoon / Overdue / TotalValue) + section HĐ gần đây
  • Layout resolvePath: Dashboard → /dashboard (không trùng Hộp thư)
  • App route: / redirect → /dashboard
  • Commit: d326e80

D. Data model 4-bảng overhaul (Tier 3 follow-up) ✓

User decision Option B: bảng riêng cho mỗi loại HĐ.

Migration 9 — AddContractDetailsAndChangelog:

  • 7 Details bảng: ThauPhuDetails, GiaoKhoanDetails, NhaCungCapDetails, DichVuDetails, MuaBanDetails, NguyenTacNccDetails, NguyenTacDvDetails
    • Common base: ContractId FK Cascade, Order, ThanhTien decimal(18,2), GhiChu, audit fields
    • Schema chuyên biệt per loại HĐ (vd MuaBan có ThueVAT, NguyenTac có DonGiaToiThieu/ToiDa)
  • 1 ContractChangelogs bảng — unified audit log:
    • EntityType enum: Contract | Detail | Workflow | Comment | Attachment
    • Action enum: Insert | Update | Delete | Transition
    • PhaseAtChange + UserName denormalize + FieldChangesJson + ContextNote
  • DB 24 → 32 bảng

IChangelogService (App + Infra):

  • 5 method: LogContractChange / LogDetailChange / LogWorkflowTransition / LogCommentAdded / LogAttachment
  • Wired vào: CreateContract + UpdateContractDraft (with diff) + AddComment + Upload/Delete Attachment + ContractWorkflowService.Transition

CQRS + API:

  • GetContractDetailsQuery dispatch theo Type → bundle 7 lists
  • 7 typed AddXxxDetailCommand handler (Insert + log changelog)
  • DeleteContractDetailCommand generic (dispatch theo Type)
  • ListContractChangelogsQuery (read-only, desc CreatedAt, top 200)
  • 9 endpoints mới ContractsController

Commits: 70810e1, 71c035d, e684455

E. FE Panel 2 — tabs → 7/3 grid layout (UX iter 2) ✓

Iter 1 (b3762af): Tabs Tổng quan / Chi tiết / Lịch sử Iter 2 (ad0652d): Bỏ tabs, hiển thị flat:

  • Tổng quan content (Info + Comments + Attachments) ở trên
  • Bên dưới grid 7-3: [Chi tiết Tab] [Lịch sử Changelog Tab]

ContractDetailsTab:

  • 7 table renderers per type (HEADERS_BY_TYPE + DeleteBtn)
  • AddRowForm với FIELDS_BY_TYPE (5-7 field per type)
  • buildPayload auto compute thanhTien (SL × DonGia × (1+VAT/100) cho MuaBan)
  • canEdit chỉ khi Phase=DangSoanThao

ContractChangelogsTab:

  • Render unified timeline desc CreatedAt
  • Icon + tone color theo EntityType
  • Expandable detail row hiển thị FieldChangesJson (Cũ → Mới)

F. "Thao tác" — 2-panel + Edit/Xóa hover + Mở fullpage ✓

ContractCreatePage rewrite:

  • 2-panel: Panel 1 List HĐ theo type + button "+ Thêm mới" cuối | Panel 2 Header form (new/edit) + Chi tiết section
  • URL state: ?type / ?id / ?mode=new
  • Empty state khi chưa chọn
  • Action buttons hover row: Edit ✏ + Xóa 🗑 (luôn hiện, mờ khi Phase != DangSoanThao + tooltip "Chỉ sửa được khi Đang soạn thảo")
  • ContractDetailsPreview cho create mode — show table headers + lock icon + disabled add button (user thấy structure trước khi tạo Header)

Commits: 8c4b4da, ec0c983, 501b4de, 7f26ff9, 39031ca

G. Mã HĐ gen ngay tại Create + backfill ✓

User feedback: HĐ phải có mã ngay khi tạo, không đợi DangDongDau.

  • CreateContractCommandHandler: gen mã trước khi db.Contracts.Add — GenerateAsync chạy SERIALIZABLE riêng, entity chưa tracked nên không bị save kèm
  • TransitionAsync giữ defensive if (MaHopDong is null) gen cho legacy
  • BackfillContractCodesAsync trong DbInitializer — chạy 1 lần startup, idempotent (count NULL → skip nếu 0), log success/failed

Commit: 51449d6

H. 4 master catalogs cho Details (migration 10) ✓

User feedback: thêm Master Data cho phần Chi tiết.

Domain entities (4 mới):

  • UnitOfMeasure (UnitsOfMeasure) — m2, kg, ngc, ...
  • MaterialItem (MaterialItems) — Code, Name, Category (NhomSP), DefaultUnit, Specification, OriginCountry, IsActive
  • ServiceItem (ServiceItems) — vận chuyển, bảo trì, tư vấn, ...
  • WorkItem (WorkItems) — đào móng, đổ bê tông, xây tường, ...

Common pattern: AuditableEntity, Code unique, Category index, IsActive.

Migration 10 — AddMasterCatalogs: DB 32 → 36 bảng.

Seed defaults idempotent:

  • 20 UnitsOfMeasure (m2/m3/kg/tan/l/cai/bo/goi/ngc/h/ca/...)
  • 15 MaterialItems demo (xi măng PCB40, cát vàng, đá 1x2, thép D10, ...)
  • 10 ServiceItems demo (vận chuyển, bảo trì, tư vấn, kiểm định, ...)
  • 15 WorkItems demo (đào móng, đổ bê tông, xây tường, lát gạch, ...)

CQRS: CatalogsFeatures.cs (~290 dòng) — 4 catalog × 5 handlers (List + Create + Update + Delete + unique code guard).

Controller: 13 endpoints — GET open cho mọi role (autocomplete); POST/PUT/DELETE Admin role only.

Menu mới (5):

  • Catalogs group "Danh mục chi tiết" dưới Master
  • 4 leaves: Đơn vị tính / Vật tư SP / Dịch vụ / Hạng mục công việc

FE Admin CatalogsPage: 1 page generic, URL /master/catalogs/:kind, 4 sub-tabs (units/materials/services/work-items), per-kind FIELDS config, form Dialog với input/textarea/checkbox.

FE Details Add form datalist autocomplete:

  • Fetch 4 catalogs qua TanStack Query (cache 'catalogs')
  • HTML5 <datalist> per relevant field (donViTinh/maSP/tenSP/hangMuc/...)
  • Smart-fill: user pick code → autofill name + defaultUnit (sibling fields) qua handleFieldChange

Commits: e27c547, 16e24ed

I. Roles VN labels + Users dept/position + 13 demo users (migration 11) ✓

Entity changes:

  • Role + ShortName (max 50) — Mã viết tắt VN
  • User + DepartmentId Guid? FK Departments (Restrict) + Position

Migration 11 — AddRoleShortNameAndUserDepartment: thêm cột, không table mới. DB vẫn 36 bảng.

12 roles VN labels (idempotent backfill nếu existing role thiếu):

Code Short Description
Admin QTV Quản trị viên hệ thống
Drafter NV.PB Nhân viên phòng ban (soạn HĐ)
DeptManager TPB Trưởng phòng ban
ProjectManager PM Giám đốc dự án
Procurement PRO Phòng Cung ứng
CostControl CCM Phòng Kiểm soát chi phí
Finance FIN Phòng Tài chính
Accounting ACT Phòng Kế toán
Equipment EQU Phòng Thiết bị
Director BOD Ban Giám đốc
AuthorizedSigner NĐUQ Người được Ủy quyền ký HĐ
HrAdmin HRA Phòng Nhân sự - Hành chính

Identity Name = code English giữ nguyên (FK + [Authorize] attr). Chỉ thêm 2 cột display VN.

13 Demo users seed (password User@123456):

  • bod.huynh + bod.le (BOD)
  • pm.nguyen (PM)
  • TPB cho CCM/PRO/FIN/ACT/EQU/HRA (6 user)
  • qs.hoang + qs.ngo (QS Drafter)
  • nv.cao + nv.dinh (PRO/FIN Drafter)

FE Admin updates:

  • types/users.ts: RoleShortName + RoleLabel + roleDisplayName helper
  • UsersPage: column Phòng ban + Chức vụ, badge Vai trò = ShortName (tooltip full label), Edit dialog mới (dept/position/active), Create dialog 2-col grid + dropdown Phòng ban, Roles checkbox "ShortName — Full Label"
  • PermissionsPage Panel 1: 2-line per role (ShortName semibold + Description small)

Commits: 330d529, ae59cfe

Stats cumulative

Trước session Sau session Δ
BE LOC ~4800 ~7800 +3000
DB tables 24 36 +12 (7 details + 1 changelog + 4 catalogs)
Migrations 8 11 +3 (Migration 9/10/11)
API endpoints ~50 ~80 +30 (details CRUD + catalogs CRUD + changelogs)
FE pages ~20 ~22 +2 (UserDashboardPage + CatalogsPage)
FE components many many+ +ContractDetailContent/WorkflowHistoryPanel/ContractDetailsTab/ContractChangelogsTab/ContractDetailsPreview
Commits session này 22 b75448eae59cfe

Architectural decisions

  1. Option B per-type Details (vs single bảng + JSON): chuẩn schema, strict typing, TS strict mode FE bắt typo. Trade-off: 7 bảng riêng + nhiều handler lặp pattern. Worth.

  2. ContractChangelogs unified — 1 bảng audit cho mọi entity HĐ (Contract/Detail/Workflow/Comment/Attachment), KHÁC ContractApprovals (workflow-only, dùng cho guard). View layer cho user đọc lịch sử.

  3. Mã HĐ gen tại Create (vs DangDongDau) — trade-off: gap trong sequence khi reject, nhưng user có mã ngay từ đầu để reference.

  4. Datalist HTML5 native autocomplete (vs library combobox) — đủ cho MVP, không add dependency, smart-fill qua handleFieldChange.

  5. Identity Name English giữ nguyên + thêm ShortName/Description VN — không break FK, không cần data migration; FE/BE display layer convert qua dict mapping.

  6. Per-type bảng Details không có User-level approver runtime guard yet — data model WorkflowStepApprover.Kind=User đã có, nhưng transition guard v1 chỉ check Role-kind. Iter sau enable.

Next session priority

  1. UAT 2-3 user thật — hard requirement
  2. Email outbox (chờ SMTP config)
  3. Rotate creds (SA/vrapp/JWT/admin)
  4. SQL backup Task Scheduler
  5. Roles CRUD admin (custom role ngoài 12 hardcoded)
  6. User-kind approver runtime guard
  7. PermissionsPage: grant Workflows.Read non-admin → Wf_* visible
  8. Update docs (sẽ làm trong commit chốt session này)

Cron audit fire 2026-05-01

Cron task solution-erp-skill-audit-monthly sẽ chạy tự động đầu tháng sau — log vào docs/changelog/skill-audit-2026-05.md + commit auto.