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>