commit
This commit is contained in:
487
docs/role-permission-migration-plan.md
Normal file
487
docs/role-permission-migration-plan.md
Normal file
@@ -0,0 +1,487 @@
|
||||
# Role Permission Migration Plan
|
||||
|
||||
วันที่จัดทำ: 2026-07-07
|
||||
|
||||
## Goal
|
||||
|
||||
ย้ายระบบสิทธิ์ปัจจุบันจากแนวทางที่พึ่งพา:
|
||||
|
||||
- `systemRole`
|
||||
- `membership.role`
|
||||
- `businessRole`
|
||||
- helper แบบ `isHRD()` / `isIT()`
|
||||
|
||||
ไปสู่ระบบ `role + permission` ที่ตรวจสอบได้ชัดเจนและรองรับ workflow ใหม่ของโปรเจกต์
|
||||
|
||||
เอกสารนี้สรุปเป็นแบบ file-by-file ว่าควรแก้อะไรบ้างในโค้ดปัจจุบัน
|
||||
|
||||
## Migration Principles
|
||||
|
||||
1. API และ server ต้องใช้ permission เป็นตัวตัดสินสิทธิ์จริง
|
||||
2. UI และ navigation เป็นเพียง layer สำหรับซ่อน/แสดง
|
||||
3. `businessRole` ให้คงไว้ช่วง migration เพื่อ compatibility
|
||||
4. ทุกการเปลี่ยน role model ต้องมี migration ของ `memberships.permissions`
|
||||
|
||||
## Phase 0: Schema And Contracts
|
||||
|
||||
### [src/db/schema.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/db/schema.ts)
|
||||
|
||||
Current:
|
||||
|
||||
- `membership_role` = `owner | admin | member`
|
||||
- `system_role` = `standard | super_admin`
|
||||
- `permissions` เป็น text array
|
||||
|
||||
Change:
|
||||
|
||||
- ขยาย `membership_role` หรือสร้าง enum ใหม่ให้รองรับ:
|
||||
- `owner`
|
||||
- `org_admin`
|
||||
- `hrd_manager`
|
||||
- `hrd_staff`
|
||||
- `employee`
|
||||
- คง `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](/D:/WY-2569/HRD/training-system-minimal-refactor/src/lib/auth/roles.ts)
|
||||
|
||||
Current:
|
||||
|
||||
- มี `BusinessRole = IT | HRD | EMPLOYEE`
|
||||
- ใช้ `getBusinessRole()`, `isHRD()`, `isIT()`
|
||||
- `getDefaultPermissionsForRole()` ยังรองรับเพียง admin/user แบบง่าย
|
||||
|
||||
Change:
|
||||
|
||||
- เพิ่ม type ใหม่:
|
||||
- `SystemRole`
|
||||
- `OrganizationRole`
|
||||
- `Permission`
|
||||
- แทนที่ 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](/D:/WY-2569/HRD/training-system-minimal-refactor/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](/D:/WY-2569/HRD/training-system-minimal-refactor/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](/D:/WY-2569/HRD/training-system-minimal-refactor/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](/D:/WY-2569/HRD/training-system-minimal-refactor/src/config/nav-config.ts)
|
||||
|
||||
Current:
|
||||
|
||||
- ใช้ `businessRole`, `businessRoles`, `systemRole`
|
||||
|
||||
Change:
|
||||
|
||||
- เปลี่ยน metadata ให้รองรับ:
|
||||
- `permission`
|
||||
- `anyPermissions`
|
||||
- `allPermissions`
|
||||
- `organizationRole` เฉพาะบางกรณีถ้าจำเป็น
|
||||
- ลดการใช้ `businessRole` ลง
|
||||
- sync เมนูที่เปิดให้ employee ใช้จริง เช่น `Reports`, `Announcements`, `Notifications` กับ access rule ใหม่
|
||||
|
||||
### [src/types/index.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/types/index.ts)
|
||||
|
||||
Change:
|
||||
|
||||
- update nav access types ให้รองรับ permission-based metadata
|
||||
|
||||
### [src/hooks/use-nav.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/hooks/use-nav.ts)
|
||||
|
||||
Current:
|
||||
|
||||
- ใช้ `getBusinessRole()`, `hasBusinessRoleAccess()`, `systemRole`
|
||||
|
||||
Change:
|
||||
|
||||
- เพิ่มการเช็ก:
|
||||
- `permission`
|
||||
- `anyPermissions`
|
||||
- `allPermissions`
|
||||
- คง support ของ field เก่าไว้ช่วง migration ถ้าจำเป็น
|
||||
- เปลี่ยน source of truth จาก `businessRole` เป็น `permissions`
|
||||
|
||||
## Phase 3: Page Guards
|
||||
|
||||
### [src/lib/auth/page-guards.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/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.tsx`
|
||||
- `src/app/dashboard/employee-directory/page.tsx`
|
||||
- `src/app/dashboard/courses/page.tsx`
|
||||
- `src/app/dashboard/training-policy/page.tsx`
|
||||
- `src/app/dashboard/pending-review/page.tsx`
|
||||
- `src/app/dashboard/audit-logs/page.tsx`
|
||||
- `src/app/dashboard/announcements/page.tsx`
|
||||
- `src/app/dashboard/online-lessons/page.tsx`
|
||||
- `src/app/dashboard/reports/page.tsx`
|
||||
|
||||
## Phase 4: Feature Server Data Helpers
|
||||
|
||||
### [src/features/announcements/server/announcement-data.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/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_public`
|
||||
- `announcement:read_all`
|
||||
- `announcement:create`
|
||||
- `announcement:publish`
|
||||
|
||||
### [src/features/online-lessons/server/online-lesson-data.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/features/online-lessons/server/online-lesson-data.ts)
|
||||
|
||||
Change:
|
||||
|
||||
- ทำแบบเดียวกับ announcements
|
||||
- เลิกใช้ `isHRD()` เป็น primary gate
|
||||
|
||||
### [src/features/reports/server/report-data.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/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](/D:/WY-2569/HRD/training-system-minimal-refactor/src/features/training-records/server/training-record-data.ts)
|
||||
|
||||
Change:
|
||||
|
||||
- เปลี่ยน review/manage scope ไปใช้ permission:
|
||||
- `training_record:self_*`
|
||||
- `training_record:read_all`
|
||||
- `training_record:review`
|
||||
- `training_record:manage_attachments`
|
||||
|
||||
### [src/features/training-matrix/server/training-matrix-data.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/features/training-matrix/server/training-matrix-data.ts)
|
||||
|
||||
Current:
|
||||
|
||||
- มี helper `canManageTrainingMatrix(role)`
|
||||
|
||||
Change:
|
||||
|
||||
- เปลี่ยนเป็น permission-based helper
|
||||
|
||||
### [src/features/users/server/user-data.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/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](/D:/WY-2569/HRD/training-system-minimal-refactor/src/app/api/announcements/route.ts)
|
||||
- [src/app/api/announcements/[id]/route.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/app/api/announcements/[id]/route.ts)
|
||||
- [src/app/api/announcements/[id]/attachment/route.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/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:
|
||||
|
||||
- [src/app/api/online-lessons/route.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/app/api/online-lessons/route.ts)
|
||||
- [src/app/api/online-lessons/[id]/route.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/app/api/online-lessons/[id]/route.ts)
|
||||
|
||||
Change:
|
||||
|
||||
- ใช้ permission checks แทน `isHRD()`
|
||||
- แยก read_public / read_all / create / publish / archive
|
||||
|
||||
### Users
|
||||
|
||||
Files:
|
||||
|
||||
- [src/app/api/users/route.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/app/api/users/route.ts)
|
||||
- [src/app/api/users/[id]/route.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/app/api/users/[id]/route.ts)
|
||||
|
||||
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:read`
|
||||
- `employee_directory:write`
|
||||
- `employee_import:run`
|
||||
- `employee_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_read`
|
||||
- `reports:organization_read`
|
||||
- `reports: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](/D:/WY-2569/HRD/training-system-minimal-refactor/src/features/notifications/server/notification-service.ts)
|
||||
|
||||
Change:
|
||||
|
||||
- เพิ่ม notification types ที่สะท้อน workflow ใหม่
|
||||
- เพิ่ม helper สำหรับ notify ตาม role/permission group ถ้าจำเป็น
|
||||
|
||||
### [src/features/audit-logs/server/audit-service.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/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](/D:/WY-2569/HRD/training-system-minimal-refactor/docs/nav-rbac.md)
|
||||
- [docs/PROJECT_ARCHITECTURE.md](/D:/WY-2569/HRD/training-system-minimal-refactor/docs/PROJECT_ARCHITECTURE.md)
|
||||
- [docs/AI_DEVELOPMENT_GUIDE.md](/D:/WY-2569/HRD/training-system-minimal-refactor/docs/AI_DEVELOPMENT_GUIDE.md)
|
||||
- [docs/role-permission-review.md](/D:/WY-2569/HRD/training-system-minimal-refactor/docs/role-permission-review.md)
|
||||
|
||||
Change:
|
||||
|
||||
- update ให้ตรงกับ permission-first model
|
||||
|
||||
### Compatibility cleanup
|
||||
|
||||
Files to revisit later:
|
||||
|
||||
- `src/lib/auth/roles.ts`
|
||||
- `src/hooks/use-nav.ts`
|
||||
- feature components ที่ยังส่ง `businessRole` / `systemRole` ลงไปหลายชั้น
|
||||
|
||||
Final cleanup:
|
||||
|
||||
- ลดการใช้ `businessRole` ให้เหลือเฉพาะ temporary adapter
|
||||
- ลบ logic `isHRD()` / `isIT()` ที่ไม่จำเป็น
|
||||
|
||||
## Suggested Execution Order
|
||||
|
||||
1. `schema.ts` + migration
|
||||
2. `permissions.ts` + `roles.ts`
|
||||
3. `auth.ts` + `session.ts` + `next-auth.d.ts`
|
||||
4. `types/index.ts` + `nav-config.ts` + `use-nav.ts`
|
||||
5. API route handlers
|
||||
6. feature server helpers
|
||||
7. feature UI
|
||||
8. docs cleanup
|
||||
|
||||
## High-Risk Areas
|
||||
|
||||
1. `src/auth.ts`
|
||||
เพราะกระทบทุก session
|
||||
|
||||
2. `src/lib/auth/session.ts`
|
||||
เพราะเป็นจุดศูนย์กลางของ server-side authorization
|
||||
|
||||
3. `src/config/nav-config.ts` และ `src/hooks/use-nav.ts`
|
||||
เพราะมีความไม่ตรงกันระหว่างเมนูและสิทธิ์จริงอยู่แล้ว
|
||||
|
||||
4. `src/features/users/server/user-data.ts`
|
||||
เพราะเกี่ยวกับ role assignment และ membership write path
|
||||
|
||||
5. `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 หลักอีกต่อไป
|
||||
Reference in New Issue
Block a user