16 KiB
Role Permission Migration Plan
วันที่จัดทำ: 2026-07-07
Goal
ย้ายระบบสิทธิ์ปัจจุบันจากแนวทางที่พึ่งพา:
systemRolemembership.rolebusinessRole- helper แบบ
isHRD()/isIT()
ไปสู่ระบบ role + permission ที่ตรวจสอบได้ชัดเจนและรองรับ workflow ใหม่ของโปรเจกต์
เอกสารนี้สรุปเป็นแบบ file-by-file ว่าควรแก้อะไรบ้างในโค้ดปัจจุบัน
Migration Principles
- API และ server ต้องใช้ permission เป็นตัวตัดสินสิทธิ์จริง
- UI และ navigation เป็นเพียง layer สำหรับซ่อน/แสดง
businessRoleให้คงไว้ช่วง migration เพื่อ compatibility- ทุกการเปลี่ยน role model ต้องมี migration ของ
memberships.permissions
Phase 0: Schema And Contracts
src/db/schema.ts
Current:
membership_role=owner | admin | membersystem_role=standard | super_adminpermissionsเป็น text array
Change:
- ขยาย
membership_roleหรือสร้าง enum ใหม่ให้รองรับ:ownerorg_adminhrd_managerhrd_staffemployee
- คง
permissionsไว้เป็น array แต่เปลี่ยน default generation ให้สอดคล้อง matrix ใหม่ - พิจารณาเพิ่ม migration สำหรับ backfill permissions ให้ membership เดิม
Deliverable:
- schema update
- drizzle migration
- backfill strategy สำหรับ membership เดิม
Phase 1: Central Auth Model
src/lib/auth/roles.ts
Current:
- มี
BusinessRole = IT | HRD | EMPLOYEE - ใช้
getBusinessRole(),isHRD(),isIT() getDefaultPermissionsForRole()ยังรองรับเพียง admin/user แบบง่าย
Change:
- เพิ่ม type ใหม่:
SystemRoleOrganizationRolePermission
- แทนที่ default permission แบบเก่าด้วย permission catalog กลาง
- เพิ่ม helper:
getDefaultPermissionsForOrganizationRole(role)hasPermission(permissions, permission)hasAnyPermission(permissions, permissions[])hasAllPermissions(permissions, permissions[])
- คง
getBusinessRole()ไว้ช่วงเปลี่ยนผ่าน แต่ mark เป็น compatibility helper - ลดการใช้
isHRD()/isIT()ลง โดย redirect ให้ไปใช้ permission helper
New file: src/lib/auth/permissions.ts
Add:
- permission constants ทั้งระบบ
- grouped permission sets
- role-to-permission mapping
src/lib/auth/session.ts
Current:
- มี
requireHRD(),requireIT(),requireUserManagementAccess() - เช็กสิทธิ์จาก role helper เป็นหลัก
Change:
- เพิ่ม:
requirePermission(permission)requireAnyPermission([...])requireAllPermissions([...])
- ให้
requireHRD()/requireIT()กลายเป็น transitional wrapper หรือค่อยเลิกใช้ - ให้
requireOrganizationAccess({ permission })ใช้ permission matrix ใหม่
src/auth.ts
Current:
- session callback derive
businessRole - เติม
permissionsจาก membership หรือ default เดิม
Change:
- เปลี่ยน default permission sourcing ให้ใช้ role mapping ใหม่
- เพิ่ม
organizationRoleลง session ให้ชัด - คง
businessRoleไว้ชั่วคราวเพื่อไม่ให้ UI เดิมพัง - เตรียมรองรับ role ใหม่ใน session payload
src/types/next-auth.d.ts
Change:
- เพิ่ม
organizationRole - เปลี่ยน
permissions: string[]เป็น type-safe alias ถ้าต้องการ - คง
businessRoleไว้ช่วงเปลี่ยนผ่าน
Phase 2: Navigation And Access Metadata
src/config/nav-config.ts
Current:
- ใช้
businessRole,businessRoles,systemRole
Change:
- เปลี่ยน metadata ให้รองรับ:
permissionanyPermissionsallPermissionsorganizationRoleเฉพาะบางกรณีถ้าจำเป็น
- ลดการใช้
businessRoleลง - sync เมนูที่เปิดให้ employee ใช้จริง เช่น
Reports,Announcements,Notificationsกับ access rule ใหม่
src/types/index.ts
Change:
- update nav access types ให้รองรับ permission-based metadata
src/hooks/use-nav.ts
Current:
- ใช้
getBusinessRole(),hasBusinessRoleAccess(),systemRole
Change:
- เพิ่มการเช็ก:
permissionanyPermissionsallPermissions
- คง support ของ field เก่าไว้ช่วง migration ถ้าจำเป็น
- เปลี่ยน source of truth จาก
businessRoleเป็นpermissions
Phase 3: Page Guards
src/lib/auth/page-guards.ts
Change:
- เพิ่ม:
requirePermissionDashboardAccess(permission, fallback?)requireAnyPermissionDashboardAccess([...], fallback?)
- ให้หน้าต่าง ๆ ที่เป็น HRD/IT เฉพาะทางย้ายไปใช้ permission guard
Dashboard pages under src/app/dashboard/**/page.tsx
Current:
- หลายหน้าพึ่ง
requireEmployeeDashboardAccess()หรือrequireHRDDashboardAccess()
Change:
- เปลี่ยนทีละหน้าให้ใช้ permission guard ที่ตรง feature มากขึ้น
Priority pages:
src/app/dashboard/users/page.tsxsrc/app/dashboard/employee-directory/page.tsxsrc/app/dashboard/courses/page.tsxsrc/app/dashboard/training-policy/page.tsxsrc/app/dashboard/pending-review/page.tsxsrc/app/dashboard/audit-logs/page.tsxsrc/app/dashboard/announcements/page.tsxsrc/app/dashboard/online-lessons/page.tsxsrc/app/dashboard/reports/page.tsx
Phase 4: Feature Server Data Helpers
src/features/announcements/server/announcement-data.ts
Current:
- ใช้
isHRD({ businessRole, systemRole })
Change:
- ส่ง permission context เข้า helper แทน
- แยก:
- public reader
- all-status reader
- content manager
- ใช้ permission เช่น:
announcement:read_publicannouncement:read_allannouncement:createannouncement:publish
src/features/online-lessons/server/online-lesson-data.ts
Change:
- ทำแบบเดียวกับ announcements
- เลิกใช้
isHRD()เป็น primary gate
src/features/reports/server/report-data.ts
Current:
- ผสม role-based scope แบบ membership role
Change:
- แยก
reports:self_readกับreports:organization_read - export ต้องใช้
reports:export
src/features/training-records/server/training-record-data.ts
Change:
- เปลี่ยน review/manage scope ไปใช้ permission:
training_record:self_*training_record:read_alltraining_record:reviewtraining_record:manage_attachments
src/features/training-matrix/server/training-matrix-data.ts
Current:
- มี helper
canManageTrainingMatrix(role)
Change:
- เปลี่ยนเป็น permission-based helper
src/features/users/server/user-data.ts
Change:
- รองรับ role ใหม่ใน CRUD
- อัปเดตการ map/create/update membership
- อัปเดต default permissions ตอนสร้าง user
Phase 5: API Route Handlers
Announcements
Files:
- src/app/api/announcements/route.ts
- src/app/api/announcements/[id]/route.ts
- src/app/api/announcements/[id]/attachment/route.ts
Change:
- เปลี่ยนจาก
requireHRD()หรือisHRD()ไปใช้ permission checks - แยก action ตาม permission เช่น create/edit/submit/publish/archive
- ระยะต่อไปเพิ่ม route action แยกสำหรับ workflow
Online Lessons
Files:
Change:
- ใช้ permission checks แทน
isHRD() - แยก read_public / read_all / create / publish / archive
Users
Files:
Change:
- เปลี่ยนจาก
requireUserManagementAccess()ไปใช้users:*,roles:assign,permissions:assign
Employee Directory / Import / Master Review
Files:
src/app/api/employee-directory/**src/app/api/import-employees/**src/app/api/master-review/route.ts
Change:
- ใช้:
employee_directory:reademployee_directory:writeemployee_import:runemployee_master_review:approve
Courses / Training Policy / Training Matrix
Files:
src/app/api/courses/**src/app/api/training-policies/**src/app/api/training-matrix/**
Change:
- เปลี่ยนไปใช้ permission ของแต่ละ module โดยตรง
Training Records
Files:
src/app/api/training-records/**
Change:
- เปลี่ยน review / attachment / update / delete checks ไปใช้ permission model ใหม่
Audit Logs
Files:
src/app/api/audit-logs/**
Change:
- ใช้
audit_logs:read
Reports
Files:
src/app/api/reports/**
Change:
- ใช้:
reports:self_readreports:organization_readreports:export
Phase 6: Feature UI Components
Announcements UI
Files:
src/features/announcements/components/**
Change:
- เปลี่ยน visibility ของปุ่มและ action menu ให้ใช้ permission-based props
- หน้า employee กับ HRD ควรใช้ component เดิมได้ แต่แยก action ตาม permission
Online Lessons UI
Files:
src/features/online-lessons/components/**
Change:
- เปลี่ยน action menu และ create/manage flow ให้ใช้ permission-based props
Training Records UI
Files:
src/features/training-records/components/**
Change:
- เปลี่ยนปุ่ม review/edit/manage attachments ให้ใช้ permission context แทน business role
Users UI
Files:
src/features/users/components/**
Change:
- แบบฟอร์มและ action menu ต้องรองรับ role ใหม่
- ต้องมี UI สำหรับเลือก role และอาจรวม permission assignment ถ้าจะเปิดใช้งานรายคน
Phase 7: Notifications And Audit
src/features/notifications/server/notification-service.ts
Change:
- เพิ่ม notification types ที่สะท้อน workflow ใหม่
- เพิ่ม helper สำหรับ notify ตาม role/permission group ถ้าจำเป็น
src/features/audit-logs/server/audit-service.ts
Change:
- เพิ่ม audit action ใหม่สำหรับ workflow/action ที่อ้างกับ permission model
- พิจารณาเพิ่ม
actor_roleหรือactor_permissionsใน payload audit ถ้าต้องการ trace ละเอียดขึ้น
Phase 8: Documentation And Compatibility Cleanup
Docs to update
Files:
- docs/nav-rbac.md
- docs/PROJECT_ARCHITECTURE.md
- docs/AI_DEVELOPMENT_GUIDE.md
- docs/role-permission-review.md
Change:
- update ให้ตรงกับ permission-first model
Compatibility cleanup
Files to revisit later:
src/lib/auth/roles.tssrc/hooks/use-nav.ts- feature components ที่ยังส่ง
businessRole/systemRoleลงไปหลายชั้น
Final cleanup:
- ลดการใช้
businessRoleให้เหลือเฉพาะ temporary adapter - ลบ logic
isHRD()/isIT()ที่ไม่จำเป็น
Suggested Execution Order
schema.ts+ migrationpermissions.ts+roles.tsauth.ts+session.ts+next-auth.d.tstypes/index.ts+nav-config.ts+use-nav.ts- API route handlers
- feature server helpers
- feature UI
- docs cleanup
High-Risk Areas
-
src/auth.tsเพราะกระทบทุก session -
src/lib/auth/session.tsเพราะเป็นจุดศูนย์กลางของ server-side authorization -
src/config/nav-config.tsและsrc/hooks/use-nav.tsเพราะมีความไม่ตรงกันระหว่างเมนูและสิทธิ์จริงอยู่แล้ว -
src/features/users/server/user-data.tsเพราะเกี่ยวกับ role assignment และ membership write path -
src/app/api/announcements/**และsrc/app/api/online-lessons/**เพราะจะเป็น feature แรกที่ใช้ workflow permission ใหม่แบบจริงจัง
Done Criteria
ถือว่าย้ายสำเร็จเมื่อ:
- API สำคัญทั้งหมดตรวจ permission โดยตรง
- nav และ page guard ใช้ permission model เดียวกัน
- role ใหม่ถูกสร้าง/แก้ไขได้จาก user management
- default permissions ของแต่ละ role ถูก seed/backfill ครบ
- employee ยังเห็นเฉพาะข้อมูลที่ควรเห็น
businessRoleไม่ใช่ source of truth หลักอีกต่อไป