208 lines
10 KiB
Markdown
208 lines
10 KiB
Markdown
# Permission Template Authorization Implementation
|
|
|
|
วันที่อัปเดต: 2026-07-07
|
|
|
|
## Scope ของเฟสแรก
|
|
|
|
เฟสแรกของงาน `permission-authorization` เน้นวาง foundation ให้ระบบย้ายจาก role-based authorization ไปสู่ permission-first model แบบค่อยเป็นค่อยไป โดยยังไม่บังคับเปลี่ยนทุก feature พร้อมกันในครั้งเดียว
|
|
|
|
สิ่งที่ทำในเฟสนี้:
|
|
|
|
- เพิ่ม permission catalog กลาง
|
|
- เพิ่ม helper สำหรับเช็ก permission แบบ type-safe
|
|
- ผูก default permission ของ membership เข้ากับ catalog กลาง
|
|
- เพิ่ม session helper สำหรับ `requirePermission()` / `requireAnyPermission()` / `requireAllPermissions()`
|
|
- เชื่อม `src/auth.ts` ให้ resolve effective permissions จาก template assignment และ override
|
|
- ขยาย session payload ให้มี `effectivePermissions` และ `permissionTemplateIds`
|
|
- เพิ่ม schema และ migration สำหรับ permission template, assignment, override, และ audit log
|
|
|
|
## โครงสร้าง Permission-first Model
|
|
|
|
โครงสร้างเป้าหมายของระบบ:
|
|
|
|
```text
|
|
Organization
|
|
-> Permission Template
|
|
-> Template Permissions
|
|
-> User Template Assignments
|
|
-> User Permission Overrides
|
|
-> Effective Permissions
|
|
```
|
|
|
|
หลักการในเฟสนี้:
|
|
|
|
- `Permission` คือ source of truth ใหม่
|
|
- `membership.role` ยังอยู่เพื่อ compatibility ระหว่าง migration
|
|
- `businessRole`, `isHRD()`, `isIT()` ยังไม่ถูกลบทิ้ง แต่ไม่ควรเป็นฐานของ feature ใหม่
|
|
- `super_admin` ยังเป็น system-level bypass ได้ตาม helper ปัจจุบัน
|
|
|
|
## Permission Catalog
|
|
|
|
ไฟล์หลัก:
|
|
|
|
- [src/lib/auth/permissions.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/lib/auth/permissions.ts)
|
|
- [src/lib/auth/authorization.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/lib/auth/authorization.ts)
|
|
|
|
สิ่งที่เพิ่ม:
|
|
|
|
- `Permission` type แบบรวมค่า permission ทั้งระบบ
|
|
- permission catalog แยกตาม module
|
|
- default permission set สำหรับ `owner`, `admin`, `member`
|
|
- helper:
|
|
- `hasPermission()`
|
|
- `hasAnyPermission()`
|
|
- `hasAllPermissions()`
|
|
- `normalizePermissions()`
|
|
- `isPermission()`
|
|
|
|
## Default Permission Mapping
|
|
|
|
ไฟล์ที่ผูก default mapping:
|
|
|
|
- [src/lib/auth/roles.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/lib/auth/roles.ts)
|
|
|
|
สถานะปัจจุบัน:
|
|
|
|
- `getDefaultPermissionsForRole()` ถูกเปลี่ยนให้ดึงจาก catalog กลางแล้ว
|
|
- ระบบเดิมยังสามารถสร้าง default permissions จาก membership role ได้เหมือนเดิม
|
|
- ยังไม่ได้ย้ายไปใช้ seeded permission templates จริงในฐานข้อมูล
|
|
|
|
## Session และ Authorization Helper
|
|
|
|
ไฟล์หลัก:
|
|
|
|
- [src/auth.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/auth.ts)
|
|
- [src/lib/auth/session.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/lib/auth/session.ts)
|
|
- [src/types/next-auth.d.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/types/next-auth.d.ts)
|
|
- [src/types/index.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/types/index.ts)
|
|
|
|
สิ่งที่เพิ่ม:
|
|
|
|
- `resolveEffectivePermissions()` ถูกใช้ใน session callback แล้ว
|
|
- `requirePermission(permission)`
|
|
- `requireAnyPermission(permissions)`
|
|
- `requireAllPermissions(permissions)`
|
|
- nav access metadata รองรับ `Permission` type มากขึ้น
|
|
|
|
ข้อสำคัญ:
|
|
|
|
- session จะพยายามอ่านสิทธิ์จาก:
|
|
- active permission template assignments
|
|
- active user permission overrides
|
|
- fallback membership permissions หรือ default role permissions
|
|
- `session.user.permissions` และ `session.user.effectivePermissions` ตอนนี้ชี้ไปที่ผลลัพธ์ effective permissions ชุดเดียวกัน
|
|
- `requireOrganizationAccess()` และ `requirePermission()` เปลี่ยนมาอ้าง `session.user.effectivePermissions` เป็นหลักแล้ว
|
|
|
|
## Database / Schema ที่เพิ่ม
|
|
|
|
ไฟล์หลัก:
|
|
|
|
- [src/db/schema.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/db/schema.ts)
|
|
- [drizzle/0015_permission_template_authorization.sql](/D:/WY-2569/HRD/training-system-minimal-refactor/drizzle/0015_permission_template_authorization.sql)
|
|
|
|
ตารางและ enum ที่เพิ่ม:
|
|
|
|
1. `permission_override_effect`
|
|
ใช้เก็บค่า `allow` และ `deny`
|
|
|
|
2. `permission_templates`
|
|
เก็บ template รายองค์กร
|
|
|
|
คอลัมน์สำคัญ:
|
|
|
|
- `organization_id`
|
|
- `code`
|
|
- `name`
|
|
- `description`
|
|
- `is_system`
|
|
- `is_default`
|
|
- `is_active`
|
|
- `deleted_at`
|
|
|
|
3. `permission_template_permissions`
|
|
เก็บรายการ permission ของแต่ละ template
|
|
|
|
4. `user_permission_template_assignments`
|
|
เก็บการ assign template ให้ user แบบผูกกับ organization
|
|
|
|
หมายเหตุ:
|
|
|
|
- รองรับหลาย template ต่อ user ต่อ organization ได้
|
|
- มี `is_active` สำหรับรองรับการปิด assignment โดยไม่ต้องลบทิ้ง
|
|
|
|
5. `user_permission_overrides`
|
|
เก็บ override รายบุคคล
|
|
|
|
ความสามารถที่รองรับแล้วใน schema:
|
|
|
|
- `allow` override
|
|
- `deny` override
|
|
- `expires_at`
|
|
- `revoked_at`
|
|
- `revoked_by`
|
|
|
|
6. `permission_audit_logs`
|
|
เก็บ audit trail สำหรับการเปลี่ยน template, assignment, override
|
|
|
|
## วิธีคำนวณ Effective Permissions
|
|
|
|
logic ที่ถูกต่อเข้ากับ session แล้วในรอบนี้:
|
|
|
|
```text
|
|
effective permissions
|
|
= permissions จาก template assignment ที่ active
|
|
+ allow overrides ที่ยังไม่หมดอายุ
|
|
- deny overrides ที่ active และยังไม่หมดอายุ
|
|
```
|
|
|
|
กติกาที่ต้องใช้ในเฟสถัดไป:
|
|
|
|
- `deny` มี priority สูงกว่า `allow`
|
|
- override ที่หมดอายุแล้วต้องไม่ถูกใช้
|
|
- ทุกการคำนวณต้องผูกกับ `active organization`
|
|
- ถ้า user ยังไม่มี active template assignment จะ fallback ไปที่ `memberships.permissions`
|
|
- ถ้า membership ไม่มี permissions เลย จะ fallback ไปที่ default permissions ตาม role เดิม
|
|
|
|
## ไฟล์ที่แก้ในเฟสนี้
|
|
|
|
- [src/lib/auth/permissions.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/lib/auth/permissions.ts)
|
|
- [src/lib/auth/authorization.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/lib/auth/authorization.ts)
|
|
- [src/lib/auth/roles.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/lib/auth/roles.ts)
|
|
- [src/auth.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/auth.ts)
|
|
- [src/lib/auth/session.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/lib/auth/session.ts)
|
|
- [src/types/next-auth.d.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/types/next-auth.d.ts)
|
|
- [src/types/index.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/types/index.ts)
|
|
- [src/db/schema.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/db/schema.ts)
|
|
- [drizzle/0015_permission_template_authorization.sql](/D:/WY-2569/HRD/training-system-minimal-refactor/drizzle/0015_permission_template_authorization.sql)
|
|
|
|
## สิ่งที่ยังไม่ได้ทำ
|
|
|
|
- seed default permission templates ลงฐานข้อมูล
|
|
- helper `getEffectivePermissions(userId, organizationId)`
|
|
- admin UI สำหรับจัดการ template
|
|
- UI สำหรับ assign template และตั้ง override รายบุคคล
|
|
- migration ของ feature guards จาก role-based เป็น permission-based แบบครบทุกหน้า
|
|
- audit write logic ตอน create/update/assign/override
|
|
|
|
## ลำดับงานถัดไปที่แนะนำ
|
|
|
|
1. เพิ่ม permission template service และ effective permission resolver
|
|
2. seed default permission templates และ assignment strategy สำหรับข้อมูลเดิม
|
|
3. ทำ seed default templates ต่อ organization
|
|
4. ย้าย page guards และ navigation ไปใช้ permission helper
|
|
5. ย้าย route handlers สำคัญไปใช้ `requirePermission()`
|
|
6. ค่อยทำ admin UI สำหรับ template และ user assignment
|
|
|
|
## Verification
|
|
|
|
ตรวจสอบแล้วในรอบนี้:
|
|
|
|
- `oxlint` ผ่านสำหรับไฟล์ auth/schema ที่แก้
|
|
- `tsc --noEmit` ผ่านหลังเพิ่ม foundation ของ permission helper
|
|
- `session.user.permissions` ถูกย้ายให้ใช้ผลจาก effective permission resolver แล้ว
|
|
|
|
หมายเหตุ:
|
|
|
|
- หลังเพิ่ม migration `0015` ควรรัน `npm run migrate` ในเครื่องก่อนเริ่มทำ service/UI เฟสถัดไป
|
|
- ยังไม่ได้เพิ่ม snapshot ใหม่ใน `drizzle/meta` เพราะรอบนี้เพิ่ม migration SQL แบบ manual เพื่อคุมผลกระทบให้แคบที่สุด
|