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>
6.0 KiB
6.0 KiB
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(+SupplierTypeenum 5 loại: NCC/NTP/TĐ/ĐVDV/CĐT),Project,Department— extendAuditableEntity - EF
IEntityTypeConfigurationvới unique indexCode, query filterIsDeleted - DbSets trong
ApplicationDbContext+IApplicationDbContext(thêm packageMicrosoft.EntityFrameworkCorevà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:
MenuKeysconst (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 CanReadListMenuItemsQuery+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 policyPermissions.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.tsconst +menu.ts(MenuNode/MenuItem/Role/Permission) +master.ts(Supplier/Project/Department + SupplierType const-object với erasableSyntaxOnly) contexts/AuthContext.tsx: thêmmenustate +loadMenu()khi login + localStorage cache +refreshMenu()hooks/usePermission.ts:can(menuKey, action)— search tree đệ quycomponents/PermissionGuard.tsx: wrapper componentcomponents/ui/: Dialog (modal overlay + Escape close), Textarea, Selectcomponents/DataTable.tsx: generic table với columns config, sort (sortBy/sortDesc callback), loading, empty state, click row;Paginationcomponent kèm theocomponents/PageHeader.tsx: title + description + actionscomponents/Layout.tsxrewrite: 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 fieldiconlib/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 buttonuseQuery+useMutation+invalidateQueriesTanStack- Toast success/error
system/PermissionsPage.tsx: grid ma trận role × menu × CRUD, select role dropdown → tick checkbox tự động PUT/permissionsupsertApp.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/mevới admin token → 6 root + 6 child nodes (12 menu items) ✅GET /api/roles→ 12 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 -bfe-admin → pass ✅
Handoff cho session tiếp theo
Phase 2 — Form Engine:
- Convert 3
.docfiles →.docxvia PowerShell COM automation - Parse chi tiết field specs cho 5 contract templates
IFormRendererservice 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