Commit Graph

7 Commits

Author SHA1 Message Date
ef394f8067 [CLAUDE] Api+App: Chunk B — PATCH /menus/{key} + DTO extend isVisible/displayLabel
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m49s
Session 20 turn 7 Chunk B. BE API cho admin Ẩn/Hiện + Đổi tên menu fe-user.

DTO (MenuDtos.cs):
  - MenuNodeDto +IsVisible bool +DisplayLabel string?
  - MenuItemDto +IsVisible bool +DisplayLabel string?

GetMyMenuTreeQueryHandler:
  - Pass m.IsVisible + m.DisplayLabel vào MenuNodeDto record
  - KHÔNG filter IsVisible server-side (FE 2 app tự filter — fe-admin
    render hết, fe-user filter ẩn). Lý do: 1 endpoint serve cả 2 FE.

ListMenuItemsQueryHandler: +IsVisible +DisplayLabel trong Select projection.

NEW UpdateMenuItemCommand + Validator + Handler (PermissionFeatures.cs):
  - Body: { Key, IsVisible, DisplayLabel? }
  - Validator: Key required + max 50, DisplayLabel max 200
  - Handler: load MenuItem by Key (NotFoundException nếu missing), set
    IsVisible + DisplayLabel (whitespace → null normalize), SaveChangesAsync

MenusController +PATCH /api/menus/{key}:
  - [Authorize(Policy = "Permissions.Update")] — reuse policy admin matrix
  - Body: UpdateMenuItemRequest { IsVisible, DisplayLabel? }
  - Send UpdateMenuItemCommand qua MediatR
  - Return 204 NoContent

Verify:
- dotnet build SolutionErp.slnx — 0 err (1 warn cũ DocxRenderer không liên quan)

Pending Chunk C: FE Admin MenuVisibilityPage
Pending Chunk D: FE Layout fe-user filter + render displayLabel
Pending Chunk E: Docs S20 turn 7

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:32:25 +07:00
7783bd6005 [CLAUDE] App: menu tree inheritance mo rong Pe_* + PeWf_*
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m54s
GetMyMenuTreeQuery truoc chi inherit Contracts (Ct_*) va Workflows
(Wf_*). Extend 2 root moi PurchaseEvaluations (Pe_*) + PeWorkflows
(PeWf_*) de admin co PurchaseEvaluations.Read auto thay 2 group Pe_* +
6 leaf (Danh sach/Thao tac/Duyet x 2 type) + 2 PeWf_* leaf admin designer
UI, khong can add per-subitem permission row.

Verify bug: /menus/me cho admin hien chi root 'PurchaseEvaluations'
+ 'PeWorkflows' nhung khong co Pe_DuyetNcc group / Pe_DuyetNccPhuongAn
group children du DB co 12 row (sqlcmd confirm). Root cause: hardcoded
2 inherit roots trong BuildChildren switch.

Fix: expand switch cover 4 inherit roots. Propagate nextInherit xuong
tat ca descendants.
2026-04-24 11:03:07 +07:00
072ad6d014 [CLAUDE] App+Api+FE-Admin: RolesPage CRUD (/system/roles)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m58s
User feedback: /system/roles trỏ tới placeholder "chưa được build" — build
trang quản lý 12 role mặc định + custom role admin tự thêm.

## BE — PermissionFeatures.cs

3 command mới:
- 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. KHÔNG đổi
  Name (Identity FK trong UserRoles + WorkflowStepApprover.AssignmentValue
  + [Authorize(Roles="...")] attr — đổi = data corruption widespread)
- DeleteRoleCommand — block 2 trường hợp:
  * Role thuộc AppRoles.All hardcoded (workflow guard reference)
  * Còn user assigned (UserManager.GetUsersInRoleAsync count > 0)

ValidationException reference fully-qualified để tránh ambiguous với
FluentValidation.ValidationException.

## BE — RolesController

3 endpoint mới (POST/PUT/DELETE) — Authorize Admin role.

## FE — RolesPage

Table list 12 + custom roles với 5 column (Mã code / Mã viết tắt / Tên
đầy đủ / Loại badge / Ngày tạo) + actions Edit/Delete:
- Edit dialog: chỉ ShortName + Description editable, Name disabled với
  hint "Không đổi được sau khi tạo"
- Delete: block với toast nếu role mặc định (HARDCODED_ROLES set check
  client-side trước khi gọi BE — UX faster, BE vẫn double-check)
- Create dialog: 3 field Name (regex pattern HTML5) + ShortName + Description
- Banner amber warning về Mã code FK constraint
- Loại badge: Mặc định (slate) vs Tùy chỉnh (brand)

## FE — App.tsx

+ import RolesPage + route /system/roles → RolesPage.

## Build

- BE: dotnet build pass (0 error)
- fe-admin: tsc + vite pass (13.88s)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 14:57:36 +07:00
330d529c92 [CLAUDE] Domain+App+Infra: Role ShortName + User Department/Position + 13 demo users (migration 11)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m53s
User feedback: chi tiết hóa Users/Phòng ban + gán roles. Roles label
tiếng Việt có Mã (ShortName) + Tên đầy đủ (Description).

## Entity changes

### Role (Domain/Identity/Role.cs)
+ ShortName (max 50)  — Mã viết tắt VN: QTV/BOD/CCM/PRO/FIN/...
+ Description (đã có) — Tên đầy đủ VN
- Identity Name = code English giữ nguyên (FK + [Authorize] attr)

### User (Domain/Identity/User.cs)
+ DepartmentId Guid? FK Departments (Restrict — không xóa dept nếu user reference)
+ Position string? max 200 — chức vụ free text

## Migration 11: AddRoleShortNameAndUserDepartment

3-file rule. Apply LocalDB OK. DB total: 36 tables (không tăng — chỉ
thêm cột vào existing).

## Seed VN labels (12 roles)

| Code | ShortName | Description |
|---|---|---|
| Admin | QTV | Quản trị viên hệ thống |
| Drafter | NV.PB | Nhân viên phòng ban (soạn thảo 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 |

SeedRolesAsync idempotent + backfill (existing role thiếu ShortName/
Description → update).

## Seed 13 demo users

Default password: User@123456 (warn log để rotate prod). Coverage full
org chart:
- bod.huynh (Tổng GĐ — Director, BOD dept)
- bod.le (Phó GĐ NĐUQ — AuthorizedSigner, BOD dept)
- pm.nguyen (PM FLOCK 01 — ProjectManager, PM dept)
- ccm.tran (TPB CCM — CostControl + DeptManager, CCM dept)
- pro.pham (TPB PRO — Procurement + DeptManager, PRO dept)
- fin.do, act.vu, equ.bui, hra.dang (TPB respective dept)
- qs.hoang, qs.ngo (Drafter — QS dept)
- nv.cao, nv.dinh (Drafter — PRO/FIN dept)

Idempotent (skip nếu email đã tồn tại).

## DTOs + Commands updated

- RoleDto + ShortName field
- UserDto + DepartmentId/DepartmentName/Position
- CreateUserCommand + DepartmentId/Position params (defaults null)
- UpdateUserCommand + DepartmentId/Position
- ListUsersQueryHandler load dept names denormalize per page
- UpdateUserCommandHandler set UpdatedAt

## Note

FE updates (UsersPage dept dropdown + role label VN) ở commit kế tiếp.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 14:24:12 +07:00
f216169039 [CLAUDE] FE-Admin+Domain+Infra+App: Workflows tab → sidebar menu items
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m37s
User request: 7 tab trong /system/workflows thành menu items riêng.

Domain:
- MenuKeys.WorkflowTypeLeaf(code) helper — `Wf_<TypeCode>` pattern

Infrastructure (DbInitializer):
- Seed 7 leaves dưới Workflows group (order 95..101), label matches
  ContractType (HĐ Thầu phụ / Giao khoán / NCC / Dịch vụ / Mua bán /
  Nguyên tắc NCC / Nguyên tắc Dịch vụ). Idempotent.

Application (GetMyMenuTreeQuery):
- Generalized inherit-perm logic: descendants of Contracts AND Workflows
  inherit parent CanRead flag. Single Workflows.Read grant → all 7
  Wf_* leaves visible; no per-leaf permission rows needed.

FE Layout (admin):
- resolvePath: Wf_<Code> → /system/workflows/<code>. Ct_* still hidden
  on admin side.

FE App.tsx:
- New route /system/workflows/:typeCode?

FE WorkflowsPage:
- Removed horizontal tab bar; type selection now comes từ URL param.
- Landing view (no param): 3-col grid card per type với active version
  badge — so admin có visual overview khi click top-level Workflows
  group without selecting a type.
- TYPE_CODE_TO_INT map drives URL→int conversion.

Result: click `Quy trình HĐ > HĐ Mua bán` trong sidebar → opens
/system/workflows/MuaBan directly với designer scoped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 09:49:42 +07:00
48e91fe7ca [CLAUDE] Domain+Infra+App+FE-Admin: per-ContractType nested sidebar menu
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m48s
User request: mỗi loại HĐ có menu riêng với 3 action Danh sách /
Thao tác / Duyệt.

Sidebar giờ 3-level under "Hợp đồng":
  Hợp đồng (group, expandable)
  ├── HĐ Thầu phụ (sub-group)
  │   ├── Danh sách → /contracts?type=1
  │   ├── Thao tác  → /contracts/new?type=1
  │   └── Duyệt      → /contracts?type=1&pendingMe=1
  ├── HĐ Giao khoán (sub-group)
  ├── HĐ NCC / Dịch vụ / Mua bán / Nguyên tắc NCC / Nguyên tắc DV
  └── ... (7 types × 4 = 28 new menu items)

BE:
- MenuKeys.cs: ContractTypeCodes array + helpers ContractTypeGroup/
  List/Create/Pending → key format Ct_<TypeCode>[_<Action>]
- DbInitializer.SeedMenuTreeAsync: loop seeds 28 entries under Contracts
- GetMyMenuTreeQuery.BuildChildren: descendants of `Contracts` inherit
  parent permission (avoid adding 28 rows to Permissions table per role)

FE:
- Layout.tsx recursive: MenuNodeRenderer dispatches group vs leaf by
  depth; nested groups collapsed by default (top-level expanded).
  Deeper levels get smaller padding/text + left border guide.
- Pattern-based resolvePath: Ct_<Type>_<Action> → URL with query.
- Contract type code → int map (matches Domain ContractType enum).
- ContractsListPage reads ?type + ?pendingMe, filters client-side.
  Header title + description reflect active filter. "← Tất cả loại"
  quick-reset button.
- ContractCreatePage new cho admin (copy từ fe-user), pre-select type
  từ ?type URL param.
- App.tsx route /contracts/new → ContractCreatePage.

Pure navigation UX; no new permissions needed. Admin + any role with
Contracts.Read see full menu; leaves click-through to filtered views.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 22:25:00 +07:00
54d6c9ba52 [CLAUDE] Phase1.2: CRUD Master + Permission Matrix + FE admin pages
Backend:
- Domain/Master: Supplier (+ SupplierType 5 loai), Project, Department (AuditableEntity)
- Domain/Identity: MenuItem, Permission, MenuKeys const (12 menu)
- EF Configurations voi unique Code + query filter IsDeleted
- DbSets + IApplicationDbContext interface update
- Application: PagedResult + PagedRequest generic
- Application/Master CQRS CRUD 3 entity (Create/Update/Delete/Get/List voi paging search sort)
- Application/Permissions: GetMyMenuTree (union OR role, filter tree), ListMenuItems, ListPermissionsByRole, UpsertPermission (guard admin khong tu giam quyen), ListRoles
- Api/Authorization: MenuPermissionRequirement + Handler (Admin bypass, query DB)
- Program.cs: register 48 policy {menu}.{action} tu MenuKeys x Actions
- Api/Controllers: Suppliers, Projects, Departments, Menus, Roles, Permissions
- DbInitializer: seed 12 menu + admin full CRUD permissions
- Migration AddMasterData + AddPermissions

Frontend (fe-admin):
- Types: menuKeys.ts const, menu.ts (MenuNode/Role/Permission), master.ts (Supplier/Project/Department + SupplierType const-object)
- AuthContext: load menu from /menus/me, cache localStorage, refreshMenu()
- usePermission hook + PermissionGuard component (wrap button)
- UI kit them: Dialog (modal overlay), Textarea, Select
- Generic: DataTable (column config, sortable, loading, empty) + Pagination
- PageHeader component
- apiError helper extract message tu ProblemDetails
- Layout rewrite: render menu dong tu AuthContext.menu (MenuGroup collapsible + NavLink + lucide icon map)
- Pages: master/Suppliers, master/Projects, master/Departments (CRUD + search + sort + paging + Dialog form)
- Page system/Permissions: ma tran Role x MenuKey x CRUD checkbox (tick tu dong PUT upsert)
- App.tsx them 4 route moi

Bug fix:
- MenuPermissionHandler: EF expression tree khong support switch expression -> tach switch ra ngoai AnyAsync
- TS erasableSyntaxOnly khong cho enum -> SupplierType const-object pattern (typeof[keyof])

E2E verified via Vite proxy:
- GET /menus/me -> 6 root + 6 child nodes (12 menus)
- GET /roles -> 12 roles
- POST/GET/PUT/DELETE /suppliers -> full CRUD, soft delete OK
- tsc -b fe-admin pass

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