Files
alla-tms/plans/permission-authorization.md
2026-07-16 09:53:14 +07:00

764 lines
20 KiB
Markdown

# Prompt: Refactor Authorization เป็น Permission Template + Permission-first Model
## Context
โปรเจกต์นี้คือระบบ Training Management System (TMS) ที่ปัจจุบันยังมีการตรวจสอบสิทธิ์จาก `systemRole`, `membership.role`, `businessRole` และ helper เช่น `isHRD()` / `isIT()`
ต้องการปรับระบบสิทธิ์ใหม่ให้เป็น **Permission-first Authorization Model** โดยตัดแนวคิดว่า “Role คือสิทธิ์” ออก และเปลี่ยนมาใช้ **Permission Template** เป็นชุดสิทธิ์ต้นแบบแทน
อ้างอิงจากแผนเดิมใน `role-permission-migration-plan.md` ที่ระบุว่าควรย้ายระบบจาก role/helper เดิมไปสู่ permission-based model และให้ API/server ใช้ permission เป็นตัวตัดสินสิทธิ์จริง
---
## Final Direction
ให้เปลี่ยนแนวคิดจากเดิม:
```text
User
-> Role
-> Permission
```
เป็น:
```text
Organization
-> Permission Template
-> Permissions
-> User Assignment
-> User Permission Override
-> Effective Permissions
```
หลักการสำคัญ:
- Permission คือ source of truth
- Permission Template เป็นเพียงชุดสิทธิ์ต้นแบบ
- User ได้รับสิทธิ์จาก Template
- User สามารถมี Permission Override รายบุคคลได้
- ระบบต้องรองรับหลายองค์กร
- UI ซ่อน/แสดงได้ตาม Permission
- API/server ต้องตรวจ Permission เสมอ
- ห้ามใช้ Role เป็นตัวตัดสินสิทธิ์หลักอีกต่อไป
---
## Required Work
### 1. Audit Existing Authorization
ตรวจสอบโค้ดทั้งหมดก่อนแก้ไข
ค้นหาการใช้งาน:
```ts
systemRole
membership.role
businessRole
isHRD()
isIT()
requireHRD()
requireIT()
requireUserManagementAccess()
role === ...
```
ตรวจสอบในส่วน:
- API routes
- Server actions
- Page guards
- Navigation
- Feature components
- Data helpers
- Auth/session helpers
- User management
- Middleware
ให้สรุปก่อนว่าไฟล์ใดยังใช้ role-based authorization อยู่
---
### 2. Create Permission Catalog
สร้าง permission catalog กลาง เช่น:
```text
src/lib/auth/permissions.ts
```
ต้องมี permission constants และ type-safe permission list
ตัวอย่างกลุ่ม permission:
```ts
organization:manage
organization:switch
permission_template:read
permission_template:create
permission_template:update
permission_template:clone
permission_template:delete
permission_template:assign
user_permission:read
user_permission:update
user_permission:override
user_permission:remove_override
users:read
users:create
users:update
users:delete
users:manage
employee_directory:read
employee_directory:write
employee_import:run
employee_master_review:approve
training_record:self_read
training_record:self_write
training_record:read_all
training_record:write_all
training_record:submit
training_record:review
training_record:approve
training_record:reject
training_record:delete_draft
training_record:manage_attachments
announcement:read_public
announcement:read_all
announcement:create
announcement:edit_draft
announcement:delete_draft
announcement:submit
announcement:approve
announcement:reject
announcement:publish
announcement:schedule
announcement:unpublish
announcement:archive
announcement:restore
announcement:revision
announcement:preview
announcement:view_history
online_lesson:read_public
online_lesson:read_all
online_lesson:create
online_lesson:edit_draft
online_lesson:delete_draft
online_lesson:submit
online_lesson:approve
online_lesson:reject
online_lesson:publish
online_lesson:schedule
online_lesson:unpublish
online_lesson:archive
online_lesson:restore
online_lesson:revision
online_lesson:preview
online_lesson:view_history
reports:self_read
reports:organization_read
reports:export
reports:export_excel
reports:export_pdf
audit_logs:read
audit_logs:export
notifications:read
notifications:manage
```
---
### 3. Add Permission Template Data Model
ตรวจสอบ schema เดิมก่อนแก้ไข
ให้เพิ่มหรือปรับ database model ให้รองรับ:
```text
organizations
permission_templates
permission_template_permissions
user_permission_template_assignments
user_permission_overrides
permission_audit_logs
```
โครงสร้างต้องรองรับ:
- หลายองค์กร
- แต่ละองค์กรมี Permission Template ของตัวเอง
- Template สร้างได้
- Template แก้ไขได้
- Template Clone ได้
- Template ลบได้
- Template ที่ถูกใช้งานอยู่ต้องห้ามลบ หรือให้ soft delete เท่านั้น
- User 1 คนสามารถถูก assign template ได้อย่างน้อย 1 template ต่อ organization
- User สามารถมี permission override รายบุคคลได้
- Override ต้องรองรับทั้ง `allow` และ `deny`
- Override สามารถมี optional expiration date ได้ ถ้าออกแบบได้โดยไม่กระทบระบบมาก
- ทุกการเปลี่ยนแปลงต้องมี audit log
---
### 4. Default Permission Templates
สร้าง default templates เป็น seed data ไม่ใช่ hard-code role
ต้องมี template เริ่มต้นอย่างน้อย:
```text
Employee
HRD Staff
HRD Manager
Org Admin
IT Admin
Super Admin
```
ตัวอย่างสิทธิ์:
#### Employee
```text
notifications:read
announcement:read_public
online_lesson:read_public
training_record:self_read
training_record:self_write
training_record:submit
reports:self_read
```
#### HRD Staff
ได้ Employee permissions และเพิ่ม:
```text
employee_directory:read
employee_directory:write
courses:read
courses:write
training_matrix:read
training_matrix:write
training_record:read_all
training_record:write_all
announcement:read_all
announcement:create
announcement:edit_draft
announcement:delete_draft
announcement:submit
announcement:preview
online_lesson:read_all
online_lesson:create
online_lesson:edit_draft
online_lesson:delete_draft
online_lesson:submit
online_lesson:preview
```
ห้ามมี:
```text
announcement:approve
announcement:publish
announcement:schedule
announcement:archive
online_lesson:approve
online_lesson:publish
online_lesson:schedule
online_lesson:archive
```
#### HRD Manager
ได้ HRD Staff permissions และเพิ่ม:
```text
training_record:review
training_record:approve
training_record:reject
announcement:approve
announcement:reject
announcement:publish
announcement:schedule
announcement:unpublish
announcement:archive
announcement:restore
announcement:revision
announcement:view_history
online_lesson:approve
online_lesson:reject
online_lesson:publish
online_lesson:schedule
online_lesson:unpublish
online_lesson:archive
online_lesson:restore
online_lesson:revision
online_lesson:view_history
reports:organization_read
reports:export
reports:export_excel
reports:export_pdf
notifications:manage
```
#### Org Admin
```text
organization:manage
organization:switch
users:read
users:create
users:update
users:delete
users:manage
employee_directory:read
employee_directory:write
permission_template:read
permission_template:assign
user_permission:read
reports:organization_read
audit_logs:read
```
#### IT Admin / Super Admin
```text
permission_template:read
permission_template:create
permission_template:update
permission_template:clone
permission_template:delete
permission_template:assign
user_permission:read
user_permission:update
user_permission:override
user_permission:remove_override
users:manage
audit_logs:read
audit_logs:export
organization:manage
organization:switch
```
---
### 5. Permission Helper
สร้าง helper กลาง เช่น:
```text
src/lib/auth/authorization.ts
```
ต้องมี function:
```ts
getEffectivePermissions(userId, organizationId)
hasPermission(user, permission, context?)
hasAnyPermission(user, permissions, context?)
hasAllPermissions(user, permissions, context?)
requirePermission(user, permission, context?)
requireAnyPermission(user, permissions, context?)
requireAllPermissions(user, permissions, context?)
```
Effective permissions ต้องคำนวณจาก:
```text
Template permissions
+ user allow overrides
- user deny overrides
- expired overrides
```
เงื่อนไข:
- `deny` ต้องมี priority สูงกว่า `allow`
- expired permission ต้องไม่ถูกนำมาใช้
- ต้อง scope ตาม organization
- ต้อง cache ได้ถ้าเหมาะสม
- ต้อง clear cache เมื่อมีการแก้ template หรือ override
---
### 6. Session / Auth Update
ปรับ session ให้รองรับ permission-first model
Session ควรมี:
```ts
userId;
organizationId;
organizationIds;
activeOrganizationId;
permissionTemplateIds;
effectivePermissions;
```
คง field เดิม เช่น `businessRole`, `systemRole`, `membership.role` ไว้ชั่วคราวเพื่อ compatibility เท่านั้น
ห้ามใช้ field เดิมเป็น source of truth ใหม่
---
### 7. Permission Template Management UI
เพิ่มหน้าจัดการ Permission Template ใน Admin
ต้องรองรับ:
- ดูรายการ Template
- สร้าง Template
- แก้ไข Template
- Clone Template
- ลบ Template
- Soft delete Template ที่เคยถูกใช้งาน
- ดู Permission ภายใน Template
- ค้นหา Permission
- Group Permission ตาม module
- แสดงจำนวนผู้ใช้งาน Template
- บันทึกเหตุผลเมื่อแก้ไข
- เก็บ audit log ทุกครั้ง
---
### 8. User Permission Assignment UI
เพิ่มหรือปรับหน้า User Management ให้รองรับ:
- เลือก Organization
- เลือก User
- Assign Permission Template ให้ User
- เปลี่ยน Template
- แสดง Effective Permissions
- เพิ่ม Permission เฉพาะราย
- Deny Permission เฉพาะราย
- Remove Override
- กำหนดวันหมดอายุ Override ถ้ารองรับ
- บันทึกเหตุผล
- แสดงประวัติการเปลี่ยนสิทธิ์
Effective Permission Viewer ต้องแสดง:
```text
Template permissions
Allow overrides
Deny overrides
Expired overrides
Final effective permissions
```
---
### 9. Multi-Organization Support
ระบบต้องรองรับหลายองค์กร
หลักการ:
- Permission Template ต้องผูกกับ organization
- User assignment ต้องผูกกับ organization
- User override ต้องผูกกับ organization
- Effective permissions ต้องคำนวณตาม active organization
- การ query/write ข้อมูลต้องมี organization context
- Super Admin / IT Admin อาจ switch organization ได้ตาม permission
ต้องตรวจสอบ:
- organization switcher
- membership
- session
- API scope
- audit logs
- user management
- reports
---
### 10. Replace Server-Side Authorization
เปลี่ยน API/server guard จาก role-based เป็น permission-based
ตัวอย่าง:
เดิม:
```ts
if (!isHRD(user)) {
return forbidden();
}
```
ใหม่:
```ts
await requirePermission(user, "announcement:create", {
organizationId,
});
```
ต้องปรับอย่างน้อย:
- Announcements API
- Online Lessons API
- Training Records API
- Users API
- Employee Directory API
- Employee Import API
- Courses API
- Training Policy API
- Training Matrix API
- Reports API
- Audit Logs API
- Notifications API
สำคัญ:
Employee-facing API ต้อง enforce server-side scope เสมอ
```text
announcement / online lesson:
- status = published
- is_current = true
training records:
- self-scope เท่านั้น เว้นแต่มี training_record:read_all
```
---
### 11. Replace Page Guards And Navigation
ปรับ page guard และ navigation ให้ใช้ permission
ตัวอย่าง:
```ts
canViewUsers = hasPermission(user, "users:read");
canViewPendingReview = hasAnyPermission(user, [
"training_record:review",
"announcement:approve",
"online_lesson:approve",
]);
```
ห้ามใช้:
```ts
businessRole === "HRD";
isHRD();
isIT();
```
เป็นตัวตัดสินหลักอีกต่อไป
---
### 12. Feature UI Permission Visibility
ปรับ component ให้รับ permission context หรือ effective permissions
ตัวอย่าง:
- ปุ่ม Create แสดงเมื่อมี `announcement:create`
- ปุ่ม Submit แสดงเมื่อมี `announcement:submit`
- ปุ่ม Approve แสดงเมื่อมี `announcement:approve`
- ปุ่ม Publish แสดงเมื่อมี `announcement:publish`
- ปุ่ม Schedule แสดงเมื่อมี `announcement:schedule`
- ปุ่ม Archive แสดงเมื่อมี `announcement:archive`
แต่ต้องจำไว้ว่า UI visibility ไม่ใช่ security
Server/API ต้องตรวจ permission ซ้ำเสมอ
---
### 13. Audit Log
ทุก action ต่อไปนี้ต้องมี audit log:
- Create template
- Update template
- Clone template
- Delete template
- Assign template to user
- Change user template
- Add user permission override
- Deny user permission
- Remove override
- Organization switch ที่สำคัญ
- Permission-based workflow actions เช่น approve, publish, archive
Audit payload ควรเก็บ:
```text
actor_user_id
organization_id
target_user_id
target_template_id
action
before
after
reason
timestamp
```
---
### 14. Backward Compatibility
ห้ามลบ logic เดิมทันที
ให้ทำ compatibility layer เช่น:
```ts
mapLegacyRoleToPermissionTemplate();
resolveEffectivePermissionsFromLegacyRole();
```
เป้าหมายคือ:
- ระบบเดิมไม่พัง
- migration ทำเป็น phase ได้
- ค่อย ๆ ลดการใช้ `businessRole`, `systemRole`, `membership.role`
- ห้ามเขียน feature ใหม่โดยใช้ role-based authorization
---
### 15. Testing Checklist
ต้องทดสอบอย่างน้อย:
#### Employee
- เห็นเฉพาะข้อมูลตัวเอง
- เห็นเฉพาะ published content
- เข้า draft ผ่าน URL ตรงไม่ได้
- approve ไม่ได้
- publish ไม่ได้
#### HRD Staff Template
- สร้าง draft ได้
- แก้ draft ได้
- submit ได้
- preview ได้
- approve ไม่ได้
- publish ไม่ได้
- schedule ไม่ได้
- archive ไม่ได้
#### HRD Manager Template
- approve ได้
- reject ได้
- publish ได้
- schedule ได้
- archive ได้
- revision ได้
- export report ได้
#### IT Admin
- สร้าง template ได้
- แก้ template ได้
- clone template ได้
- ลบ template ได้ตามเงื่อนไข
- assign template ให้ user ได้
- override permission รายบุคคลได้
- ดู effective permissions ได้
- audit log ถูกบันทึกครบ
#### Multi-Organization
- User คนเดียวมีสิทธิ์ต่างกันในแต่ละ organization ได้
- active organization เปลี่ยนแล้ว permission เปลี่ยนตาม
- API ไม่ดึงข้อมูลข้าม organization
- audit log ระบุ organization ถูกต้อง
---
### 16. Documentation
หลังแก้ไขเสร็จ ให้สร้างเอกสารไว้ที่:
```text
docs/permission-template-authorization-implementation.md
```
เอกสารต้องมี:
- สรุปสิ่งที่แก้ไข
- โครงสร้าง Permission-first model
- Permission catalog
- Default permission templates
- Database/schema ที่เพิ่มหรือแก้ไข
- วิธีคำนวณ effective permissions
- วิธี assign template ให้ user
- วิธี override permission รายบุคคล
- วิธีรองรับหลายองค์กร
- API/page ที่เปลี่ยนแล้ว
- compatibility layer ที่ยังเหลือ
- test checklist
- known issues
- next steps
---
## Acceptance Criteria
งานนี้ถือว่าเสร็จเมื่อ:
- Permission เป็น source of truth
- Role ไม่ใช่ตัวกำหนดสิทธิ์หลักอีกต่อไป
- มี permission catalog กลาง
- มี Permission Template ที่จัดการผ่าน Admin ได้
- สร้าง/แก้ไข/Clone/ลบ Template ได้
- Assign Template ให้ User ได้
- Override Permission รายบุคคลได้
- รองรับหลายองค์กร
- Effective permissions คำนวณถูกต้อง
- API/server ใช้ `requirePermission()` เป็นหลัก
- Navigation/page guard ใช้ permission
- Employee เห็นเฉพาะข้อมูลที่ควรเห็น
- HRD Staff publish/approve ไม่ได้
- HRD Manager publish/approve ได้
- IT Admin จัดการ Template และ Permission ได้
- ทุกการเปลี่ยนสิทธิ์มี audit log
- มีเอกสารสรุปใน `docs`
- ระบบเดิมไม่พังระหว่าง migration
---
## Important Notes
- ห้ามใช้ Role เป็น source of truth
- ห้าม hard-code role ใน feature ใหม่
- ห้ามตรวจสิทธิ์เฉพาะ UI
- Server/API ต้องตรวจ permission เสมอ
- Permission Template คือชุดสิทธิ์ต้นแบบ ไม่ใช่ตัวตัดสินสิทธิ์
- User Permission Override ต้องมีผลต่อ effective permissions
- Multi-Organization ต้องไม่ทำให้ข้อมูลข้ามองค์กรรั่ว
- ต้อง reuse pattern เดิมของโปรเจกต์ก่อนสร้างของใหม่
- ต้องทำ migration แบบปลอดภัยและมี compatibility layer