Files
solution-erp/docs/changelog/sessions/2026-04-21-1130-phase1-cruds-permission.md
pqhuy1987 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

6.0 KiB
Raw Blame History

Session 2026-04-21 11:30 — Phase 1 đợt 2 complete

Dev: Claude (Opus 4.7) Duration: ~1h30m Base commit: 49a5f57 Commits: (sắp tạo — 1 commit lớn cho toàn bộ đợt 2)

Làm được

Chunk A — Backend Master data

  • Domain: Supplier (+ SupplierType enum 5 loại: NCC/NTP/TĐ/ĐVDV/CĐT), Project, Department — extend AuditableEntity
  • EF IEntityTypeConfiguration với unique index Code, query filter IsDeleted
  • DbSets trong ApplicationDbContext + IApplicationDbContext (thêm package Microsoft.EntityFrameworkCore vào Application)
  • Common/Models/PagedResult<T> + PagedRequest (page, pageSize 1-200, search, sortBy, sortDesc)
  • CQRS cho Supplier: CreateSupplierCommand + Validator + Handler, UpdateSupplierCommand, DeleteSupplierCommand (soft-delete qua AuditingInterceptor), GetSupplierQuery, ListSuppliersQuery (với filter Type)
  • CQRS cho Project + Department: gom vào 1 file mỗi entity (ProjectFeatures.cs, DepartmentFeatures.cs) — pattern giống Supplier nhưng compact
  • 3 Controller: SuppliersController, ProjectsController, DepartmentsController — full REST (list, get, create, update, delete)
  • Migration AddMasterData

Chunk B — Backend Permission system

  • Domain: MenuKeys const (12 menu key: Dashboard, Master, Suppliers, Projects, Departments, Contracts, Forms, Reports, System, Users, Roles, Permissions), MenuItem (Key PK, Label, ParentKey, Order, Icon), Permission (RoleId, MenuKey, CanRead/Create/Update/Delete)
  • EF configs + unique index (RoleId, MenuKey)
  • DTOs: MenuNodeDto (tree node có resolved CRUD), PermissionDto, RoleDto, MenuItemDto
  • GetMyMenuTreeQuery — resolve menu tree theo roles của user, union OR CRUD flags qua roles, filter chỉ trả về node có CanRead hoặc có child CanRead
  • ListMenuItemsQuery + ListPermissionsByRoleQuery + UpsertPermissionCommand (guard: admin không tự giảm quyền mình)
  • ListRolesQuery
  • Authorization handler MenuPermissionHandler : AuthorizationHandler<MenuPermissionRequirement> — check Admin bypass, query DB qua roleIds
  • Register 48 policy ({menu}.{action} cho 12 menu × 4 action) trong Program.cs
  • Controllers: MenusController (GET /me, GET /), RolesController, PermissionsController (Authorize policy Permissions.Read/Update)
  • Update DbInitializer: seed 12 menu items + default admin có full CRUD mọi menu
  • Migration AddPermissions

Chunk C — Frontend (fe-admin)

  • Types: menuKeys.ts const + menu.ts (MenuNode/MenuItem/Role/Permission) + master.ts (Supplier/Project/Department + SupplierType const-object với erasableSyntaxOnly)
  • contexts/AuthContext.tsx: thêm menu state + loadMenu() khi login + localStorage cache + refreshMenu()
  • hooks/usePermission.ts: can(menuKey, action) — search tree đệ quy
  • components/PermissionGuard.tsx: wrapper component
  • components/ui/: Dialog (modal overlay + Escape close), Textarea, Select
  • components/DataTable.tsx: generic table với columns config, sort (sortBy/sortDesc callback), loading, empty state, click row; Pagination component kèm theo
  • components/PageHeader.tsx: title + description + actions
  • components/Layout.tsx rewrite: render menu động từ AuthContext.menu (không hardcode nữa), MenuGroup collapsible cho parent có children, NavLink active highlight, icon map từ lucide-react theo field icon
  • lib/apiError.ts: extract user-friendly message từ ProblemDetails
  • 3 trang CRUD admin (master/SuppliersPage.tsx, ProjectsPage.tsx, DepartmentsPage.tsx):
    • Full CRUD với Dialog form, search, sort, paging
    • <PermissionGuard> wrap Create/Update/Delete button
    • useQuery + useMutation + invalidateQueries TanStack
    • Toast success/error
  • system/PermissionsPage.tsx: grid ma trận role × menu × CRUD, select role dropdown → tick checkbox tự động PUT /permissions upsert
  • App.tsx: thêm 4 route mới

Bug gặp + fix

Bug Root cause Fix
Build CS8514 in MenuPermissionHandler EF expression tree không support switch expression Tách switch ra ngoài AnyAsync() — switch trên Action, mỗi case gọi AnyAsync với predicate riêng
POST /api/suppliers lỗi với Unicode tiếng Việt qua curl command line Windows bash command line encoding không đúng UTF-8 Dùng --data-binary @file.json — API handle UTF-8 OK
TS1294 erasableSyntaxOnly + enum SupplierType TS 6 erasableSyntaxOnly không cho enum Dùng const + as const + type = typeof[keyof] pattern
fe-admin npm run dev báo port 8082 in use Background task trước chưa stop hẳn Tình trạng tạm — E2E vẫn pass qua port đã bind

E2E verified

  • GET /api/menus/me với admin token → 6 root + 6 child nodes (12 menu items)
  • GET /api/roles12 roles
  • POST /api/suppliers → 201 + id
  • GET /api/suppliers → PagedResult
  • PUT /api/suppliers/{id} → 204
  • DELETE /api/suppliers/{id} → 204, list GET sau đó không còn (soft delete OK)
  • GET /api/permissions/by-role/{adminRoleId} → 12 permissions all true
  • tsc -b fe-admin → pass

Handoff cho session tiếp theo

Phase 2 — Form Engine:

  • Convert 3 .doc files → .docx via PowerShell COM automation
  • Parse chi tiết field specs cho 5 contract templates
  • IFormRenderer service với OpenXml + ClosedXML
  • Form builder UI cho admin upload template
  • Preview + export flow

Xem docs/flows/form-render-flow.md + docs/changelog/migration-todos.md section Phase 2.

Còn thiếu trong Phase 1 (có thể làm parallel với Phase 2 nếu muốn):

  • FE: thêm trang Users management (tạo user mới, gán role)
  • FE: trang Roles CRUD (create/rename/delete custom role)
  • Contract entity + CRUD draft (skeleton cho Phase 3 chuẩn bị)
  • Test 1 role khác Admin → verify permission guard hoạt động đúng

Blocker:

  • Gitea remote URL