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

10 KiB

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

โครงสร้างเป้าหมายของระบบ:

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

ไฟล์หลัก:

สิ่งที่เพิ่ม:

  • Permission type แบบรวมค่า permission ทั้งระบบ
  • permission catalog แยกตาม module
  • default permission set สำหรับ owner, admin, member
  • helper:
    • hasPermission()
    • hasAnyPermission()
    • hasAllPermissions()
    • normalizePermissions()
    • isPermission()

Default Permission Mapping

ไฟล์ที่ผูก default mapping:

สถานะปัจจุบัน:

  • getDefaultPermissionsForRole() ถูกเปลี่ยนให้ดึงจาก catalog กลางแล้ว
  • ระบบเดิมยังสามารถสร้าง default permissions จาก membership role ได้เหมือนเดิม
  • ยังไม่ได้ย้ายไปใช้ seeded permission templates จริงในฐานข้อมูล

Session และ Authorization Helper

ไฟล์หลัก:

สิ่งที่เพิ่ม:

  • 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 ที่เพิ่ม

ไฟล์หลัก:

ตารางและ enum ที่เพิ่ม:

  1. permission_override_effect ใช้เก็บค่า allow และ deny

  2. permission_templates เก็บ template รายองค์กร

คอลัมน์สำคัญ:

  • organization_id
  • code
  • name
  • description
  • is_system
  • is_default
  • is_active
  • deleted_at
  1. permission_template_permissions เก็บรายการ permission ของแต่ละ template

  2. user_permission_template_assignments เก็บการ assign template ให้ user แบบผูกกับ organization

หมายเหตุ:

  • รองรับหลาย template ต่อ user ต่อ organization ได้
  • มี is_active สำหรับรองรับการปิด assignment โดยไม่ต้องลบทิ้ง
  1. user_permission_overrides เก็บ override รายบุคคล

ความสามารถที่รองรับแล้วใน schema:

  • allow override
  • deny override
  • expires_at
  • revoked_at
  • revoked_by
  1. permission_audit_logs เก็บ audit trail สำหรับการเปลี่ยน template, assignment, override

วิธีคำนวณ Effective Permissions

logic ที่ถูกต่อเข้ากับ session แล้วในรอบนี้:

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 เดิม

ไฟล์ที่แก้ในเฟสนี้

สิ่งที่ยังไม่ได้ทำ

  • 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 เพื่อคุมผลกระทบให้แคบที่สุด