# 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 หลักอีกต่อไป
