Appearance
Achievement - Technical Map
Source map
Frontend
| File | Vai trò |
|---|---|
diva-admin/src/modules/achievement/module.ts | Đăng ký route, navigation, permission config |
diva-admin/src/modules/achievement/types.ts | Route constants và full-scope roles |
diva-admin/src/modules/achievement/pages/AchievementManagement.tsx | Tab quản lý huy hiệu cá nhân/phòng ban |
diva-admin/src/modules/achievement/pages/AchievementProgram.tsx | Tab quản lý chương trình cá nhân/phòng ban |
diva-admin/src/modules/achievement/pages/PersonalManagementDetail.tsx | Detail nhân viên |
diva-admin/src/modules/achievement/pages/DepartmentManagementDetail.tsx | Detail phòng ban |
diva-admin/src/modules/achievement/graphql/achievement-program.graphql | Query/mutation cá nhân |
diva-admin/src/modules/achievement/graphql/department-achievement-program.graphql | Query/mutation phòng ban |
diva-admin/src/modules/achievement/compositions/useProgramImport.ts | Validate và build file import cá nhân |
diva-admin/src/modules/achievement/compositions/useDepartmentProgramImport.ts | Validate và build file import phòng ban |
Backend
| File | Vai trò |
|---|---|
diva-backend/services/controller/migrations/default/1718883205125_employee_achievement/up.sql | Tạo bảng cá nhân và program |
diva-backend/services/controller/migrations/ecommerce/1718785620656_department_program/up.sql | Tạo bảng phòng ban |
diva-backend/services/controller/migrations/default/1720069376030_add_achievement_role_module/up.sql | Gán role module cho achievement |
diva-backend/services/controller/migrations/default/1720516140850_add_permissions/up.sql | Thêm role module cho nhiều role khác |
diva-backend/services/controller/metadata/databases/default/tables/*.yaml | Hasura metadata cho bảng cá nhân |
diva-backend/services/controller/metadata/databases/ecommerce/tables/*.yaml | Hasura metadata cho bảng phòng ban |
diva-backend/services/crm-api/action/apply_employee_program.go | Action backend áp dụng program cá nhân thành link huy hiệu |
Route map
| Route | Component | Guard / moduleId |
|---|---|---|
/a/achievement-management | AchievementManagement | achievement_management |
/a/achievement-management/account/:accountCode | PersonalManagementDetail | achievement_management |
/a/achievement-management/department/:departmentCode | DepartmentManagementDetail | achievement_management |
/a/achievement-program | AchievementProgram | program_management |
Route gốc /a redirect sang /a/achievement-program (diva-admin/src/modules/achievement/module.ts).
Permission / navigation
| Item | Rule |
|---|---|
| Sidebar group | moduleId = "achievement", chỉ hiện trên PLATFORM_ADMIN |
| Submenu huy hiệu | achievement_management, yêu cầu FULL_ACHIEVEMENT_MANAGEMENT_ROLES |
| Submenu chương trình | program_management, không gắn permissions, nhưng vẫn bị module/role gate ở router |
| Router guard | Cho phép nếu user có module tương ứng hoặc là achievement trên platform admin |
GraphQL operations
4.1 Cá nhân
| Operation | Type | Dùng ở đâu | Ghi chú |
|---|---|---|---|
GetProgram | query | ProgramTable | Lấy danh sách program cá nhân + aggregate |
GetProgramForSelect | query | ProgramSelect, import validator | Dùng làm select box và kiểm tra program code |
GetProgramByPk | query | ProgramCreate, ProgramDetail | Load detail 1 program |
CreateProgram | mutation | ProgramCreate | Insert program + nested link |
UpdateProgramByPk | mutation | ProgramCreate | Update program + replace toàn bộ links |
DeleteProgram | mutation | Có trong file graphql nhưng chưa thấy UI gọi trực tiếp | |
UpdateProgramEmployeeAchievementLink | mutation | ProgramApply, ProgramImport | Bulk insert employee_achievement_link |
GetProgramEmployeeAchievementLink | query | PersonalAchievementTable, ProgramDetail | Lấy link nhân viên - huy hiệu |
GetAccountWithAchievementLink | query | PersonalManagementDetail | Load detail account + achievements |
4.2 Phòng ban
| Operation | Type | Dùng ở đâu | Ghi chú |
|---|---|---|---|
GetDepartmentProgram | query | DepartmentProgramTable | Lấy danh sách department_program + aggregate |
GetDepartmentProgramForSelect | query | DepartmentProgramSelect, import validator | Dùng làm select box và kiểm tra program code |
GetDepartmentProgramByPk | query | DepartmentProgramCreate, DepartmentProgramApply | Load detail 1 department_program |
CreateDepartmentProgram | mutation | DepartmentProgramCreate | Insert department_program + nested link |
UpdateDepartmentProgramByPk | mutation | DepartmentProgramCreate | Update + replace link |
DeleteDepartmentProgram | mutation | Có trong file graphql nhưng chưa thấy UI gọi trực tiếp | |
UpdateProgramDepartmentAchievementLink | mutation | DepartmentProgramApply, DepartmentProgramImport | Bulk insert department_achievement_link |
GetProgramDepartmentAchievementLink | query | DepartmentAchievementTable, DepartmentProgramDetail | Lấy link phòng ban - huy hiệu |
GetDepartmentWithAchievementLink | query | DepartmentManagementDetail | Load detail department + achievements |
Data model
5.1 Bảng cá nhân
| Table | Key columns | Ý nghĩa |
|---|---|---|
achievement | code, name, description, image_url | Danh mục huy hiệu cá nhân |
program | code, name, duration_from, duration_to, description, created_at | Chương trình cá nhân |
program_achievement_link | achievement_code, program_code | Link program -> achievement |
program_manager_link | account_code, program_code | Manager của program |
program_employee_link | account_code, program_code | Thành viên program |
employee_achievement_link | account_code, achievement_code, program_code, created_at | Huy hiệu đã phát cho nhân viên |
5.2 Bảng phòng ban
| Table | Key columns | Ý nghĩa |
|---|---|---|
department_achievement | code, name, description, image_url | Danh mục huy hiệu phòng ban |
department_program | code, name, duration_from, duration_to, description, created_at | Chương trình phòng ban |
department_program_achievement_link | achievement_code, program_code | Link program -> achievement |
department_program_manager_link | account_code, program_code | Manager của program |
department_achievement_link | department_code, achievement_code, program_code, created_at | Huy hiệu đã phát cho phòng ban |
5.3 Defaults và code prefix
| Entity | Prefix | Sequence |
|---|---|---|
achievement.code | HHCN | achievement_seq |
program.code | CTCN | program_seq |
department_achievement.code | HHPB | achievement_seq |
department_program.code | CTPB | program_seq |
Flow triển khai
6.1 List và detail
AchievementManagement/AchievementProgramđọcquery.tabđể chọn tab mặc định.- Danh sách chính dùng
XTable+ pagination trên GraphQL aggregate. - Search input chỉ lọc theo
_iliketrêncodevàname. - Detail screens query theo
accountCodehoặcdepartmentCoderồi filter tiếp theoprogramCode,keywords,createdAt.
6.2 Create / update program
- Form lấy dữ liệu hiện tại bằng
GetProgramByPkhoặcGetDepartmentProgramByPk. - Khi create:
- insert master table,
- nested insert
managers, - nested insert
achievements.
- Khi update:
update_*_by_pk,- delete toàn bộ
*_achievement_linkcũ, - insert lại toàn bộ link mới,
- delete toàn bộ
*_manager_linkcũ, - insert lại manager link mới.
6.3 Apply
- Chọn program.
- Load list huy hiệu thuộc program.
- Chọn nhân viên/phòng ban hoặc chọn tất cả.
- Build mảng
{ program_code, achievement_code, account_code|department_code, created_at }. - Gọi bulk insert mutation.
6.4 Import
- Load file Excel bằng
exceljs. - Dò 4 cột theo template.
- Validate
program,achievement,account/department,created_at. - Sau khi hợp lệ mới cho phép bulk insert.
Hasura permissions
7.1 Cá nhân
| Table | Select | Insert | Update | Delete |
|---|---|---|---|---|
achievement | user | user | user | user |
employee_achievement_link | user | user | - | user |
program | user | user | user | user |
program_achievement_link | user | user | - | user |
program_manager_link | user | user | - | user |
7.2 Phòng ban
| Table | Select | Insert | Update | Delete |
|---|---|---|---|---|
department_achievement | user | user | user | user |
department_achievement_link | user | user | - | user |
department_program | user | user | user | user |
department_program_achievement_link | user | user | - | user |
department_program_manager_link | user | user | - | user |
Observability / NFR
| Hạng mục | Ghi chú |
|---|---|
| Pagination | Dùng aggregate count làm rowsNumber để XTable tính trang |
| Network policy | Các query quan trọng đều network-only để tránh cache cũ |
| Validation | Import không xử lý theo transaction; dữ liệu phải sạch trước khi mutate |
| UX state | Một số component lưu userBehavior.limit theo route key riêng |
Rủi ro / Findings kỹ thuật
| Mức | File | Vấn đề |
|---|---|---|
| P1 | diva-admin/src/modules/achievement/compositions/useProgramImport.ts:105-160 | sheet.eachRow(async ...) không được await, nên kiểm tra row có thể chưa xong nhưng progress/import đã tiếp tục. |
| P1 | diva-admin/src/modules/achievement/compositions/useDepartmentProgramImport.ts:105-163 | Cùng lỗi async iteration như luồng import cá nhân. |
| P2 | diva-admin/src/modules/achievement/components/AchievementManagement/PersonalAchievementTable.tsx:39-41,146-151 | Key đọc userBehavior và key ghi userBehavior không khớp (-personal vs -personal-detail), limit đã chọn khó được persist đúng. |
| P2 | diva-admin/src/modules/achievement/components/AchievementManagement/DepartmentAchievementTable.tsx:42-45,150-155 | Lỗi persist limit tương tự ở tab phòng ban. |
| P2 | diva-admin/src/modules/achievement/components/AchievementProgram/ProgramDetail.tsx:21-27 + diva-backend/services/controller/metadata/databases/default/tables/public_account.yaml | Query dùng filter department_id trên account, trong khi metadata account hiện chỉ thể hiện relation departments; đây là điểm cần xác minh vì có rủi ro không khớp schema hiện tại. |