15 KiB
15 KiB
Role Permission Review
วันที่ตรวจสอบ: 2026-06-30
Scope
เอกสารนี้เป็นการตรวจสอบระบบสิทธิ์การเข้าถึงของ 3 กลุ่มหลัก:
- Employee
- HRD Admin
- IT Admin
ขอบเขตที่ตรวจ:
- การมองเห็นเมนูใน sidebar
- การกัน direct URL ที่ระดับ page
- การกันสิทธิ์ที่ระดับ API / server-side
- การจำกัดขอบเขตข้อมูล
- ความสอดคล้องระหว่าง requirement กับ implementation ปัจจุบัน
ไฟล์หลักที่ใช้ตรวจ:
src/config/nav-config.tssrc/hooks/use-nav.tssrc/lib/auth/roles.tssrc/lib/auth/session.tssrc/lib/auth/page-guards.tssrc/proxy.tssrc/app/dashboard/**src/app/api/**
Requirement Summary
จากแผนงานที่ให้ตรวจ ระบบนี้ควรแยกสิทธิ์อย่างน้อยเป็น 3 ระดับ:
- Employee เห็นเฉพาะส่วนที่ใช้กับตัวเอง และข้อมูลต้องถูก scope เป็นของตัวเอง
- HRD Admin จัดการข้อมูลฝั่งงานอบรมและข้อมูลบุคลากรในองค์กรได้
- IT Admin จัดการสิทธิ์ระดับสูงกว่า HRD และเข้าถึงส่วน technical / audit ได้
ประเด็นสำคัญที่แผนเน้นเป็นพิเศษ:
- เมนูและหน้าจอต้องสอดคล้องกับสิทธิ์จริง
- ห้ามพึ่งแค่ซ่อนเมนู ต้องกันที่ server ด้วย
- ข้อมูลของ Employee ต้องไม่ทะลุไปเห็นของคนอื่น
- ฟังก์ชัน
Import พนักงานควรถูกทบทวน/ถอดออกจาก flow ถ้าไม่ได้ต้องการใช้งานแล้ว
Findings
1. High: หน้าและ API Import พนักงาน ยังเปิดใช้งานอยู่
สถานะ: Fail
หลักฐาน:
- src/app/dashboard/employee-directory/page.tsx ยังมีปุ่มลิงก์ไป
/dashboard/import-employees - src/app/dashboard/import-employees/page.tsx ยังเปิดหน้า import
- src/app/api/import-employees/route.ts ยังเปิด API import โดยใช้
requireHRD()
ผลกระทบ:
- ถ้า requirement ล่าสุดต้องการยกเลิก flow นี้ ปัจจุบันถือว่ายังไม่ปิดจริง
- ผู้ใช้ HRD / IT ยังเข้าใช้งานได้ผ่านปุ่ม, direct URL และ API
คำแนะนำ:
- ถ้าต้องการถอดฟังก์ชันนี้จริง ควรลบปุ่ม, ปิดหน้า route, ปิด API และตรวจ flow ที่เกี่ยวข้องกับ
master-reviewต่อด้วย
2. Medium: สิทธิ์ฝั่ง Employee สำหรับเมนูบางหน้าไม่สอดคล้องกับสิทธิ์จริงของหน้า
สถานะ: Need Review
หลักฐาน:
- เมนู
Reportsใน src/config/nav-config.ts จำกัดเป็นbusinessRole: 'HRD' - แต่หน้า reports ใช้ src/app/dashboard/reports/page.tsx ผ่าน
requireEmployeeDashboardAccess() - data scope ของ reports ก็รองรับ employee แบบ self-scope ใน src/features/reports/server/report-data.ts
ข้อสังเกตเพิ่ม:
- หน้า
Announcementsใช้requireEmployeeDashboardAccess()ใน src/app/dashboard/announcements/page.tsx - หน้า
Notificationsใช้requireEmployeeDashboardAccess()ใน src/app/dashboard/notifications/page.tsx - แต่ใน
nav-config.tsเมนูAnnouncementsถูกวางไว้ในกลุ่ม HRD/IT เท่านั้น และNotificationsไม่มีใน sidebar
ผลกระทบ:
- สิทธิ์จริงของระบบกับสิ่งที่ผู้ใช้เห็นในเมนูไม่ตรงกัน
- ผู้ใช้ employee อาจ “เข้าได้แต่ไม่เห็นเมนู”
คำแนะนำ:
- ตกลงให้ชัดว่าหน้าใดควรเป็น employee-facing
- จากนั้น sync ระหว่าง
nav-config.tsกับ page/API permission ให้ตรงกัน
3. Medium: โมเดลสิทธิ์ IT กับ HRD ยังพึ่งการตีความทางอ้อมมากกว่าตารางสิทธิ์ที่ชัด
สถานะ: Need Review
หลักฐาน:
super_adminถูก map เป็นITใน src/lib/auth/roles.tsisHRD()คืนค่าtrueให้ทั้ง HRD และ super admin ใน src/lib/auth/roles.tsrequireHRD()จึงเปิดให้ IT ผ่านได้ด้วยใน src/lib/auth/session.ts
ผลกระทบ:
- ตอนนี้ระบบทำงานแบบ “IT เข้าส่วน HRD ได้ทั้งหมด” ซึ่งอาจถูกต้องก็ได้
- แต่ถ้าอนาคตอยากแยกสิทธิ์ HRD กับ IT ให้ต่างกันมากขึ้น จะตามแก้ยาก เพราะ logic ผูกกันอยู่หลายชั้น
คำแนะนำ:
- ถ้าต้องการให้ IT = สิทธิ์มากกว่า HRD แบบตั้งใจ ถือว่าใช้งานได้
- แต่ถ้าต้องการ matrix สิทธิ์ที่ตรวจสอบง่าย ควรมี role-permission matrix กลางที่อ่านแล้วตอบได้ทันทีว่าแต่ละ role ทำอะไรได้บ้าง
4. Low: เอกสาร RBAC ปัจจุบันไม่ตรงกับ implementation บางจุด
สถานะ: Need Review
หลักฐาน:
- docs/nav-rbac.md ระบุว่า HRD เข้าถึง
Audit Logsได้ - แต่เมนู
Audit Logsใน src/config/nav-config.ts จำกัดsystemRole: 'super_admin' - และหน้า audit log ใช้ src/app/dashboard/audit-logs/page.tsx ผ่าน
requireITDashboardAccess()
ผลกระทบ:
- คนดูเอกสารอาจเข้าใจสิทธิ์ผิด
- เสี่ยงตัดสินใจต่อยอด feature จากเอกสารที่ไม่ตรงโค้ดจริง
คำแนะนำ:
- อัปเดตเอกสารให้ตรงกับ implementation ปัจจุบัน
Menu Visibility Review
Employee
ผลที่พบ:
- เห็น
Overview,Training Records,Online Lessons - ไม่เห็น
Reportsจาก sidebar แม้ว่าหน้า reports จะเข้าได้จริง - ไม่เห็น
AnnouncementsและNotificationsจาก sidebar แม้ว่าหน้าเหล่านี้เปิดสิทธิ์ employee
สรุป: Partial
HRD Admin
ผลที่พบ:
- เห็น
Pending Review - เห็นกลุ่ม
ข้อมูลหลักและเข้าถึงEmployee Directory,Courses,Training Policy,Announcements - เข้า
Import Employeesได้ผ่าน direct URL และจากปุ่มในหน้า employee directory - ไม่เห็น
Usersเพราะเมนูนั้นเปิดเฉพาะ IT
สรุป: Mostly Pass
IT Admin
ผลที่พบ:
- เห็นเมนู
Users - เห็นส่วนของ HRD ได้ทั้งหมดผ่าน role mapping
- เห็น
Audit Logsเฉพาะsuper_admin
สรุป: Pass
Route Protection Review
ผ่าน
- หน้า employee-facing ใช้
requireEmployeeDashboardAccess() - หน้า HRD ใช้
requireHRDDashboardAccess() - หน้า IT ใช้
requireITDashboardAccess()หรือrequireUserManagementDashboardAccess()
หลักฐานสำคัญ:
- src/lib/auth/page-guards.ts
- src/app/dashboard/users/page.tsx
- src/app/dashboard/employee-directory/page.tsx
- src/app/dashboard/pending-review/page.tsx
- src/app/dashboard/audit-logs/page.tsx
ข้อสังเกต
- src/proxy.ts กันได้แค่ “ล็อกอินหรือยัง”
- การกัน “สิทธิ์ role ไหนเข้าได้” ยังต้องพึ่ง page guard และ API handler ต่อ ซึ่งตอนนี้ถือว่าทำถูกทิศทางแล้ว
สรุป: Pass
API / Server Action Permission Review
ผ่าน
Users APIเปิดเฉพาะ IT ผ่านrequireUserManagementAccess()Audit Logs APIเปิดเฉพาะ IT ผ่านrequireIT()Employee Directory,Courses,Training Policies,Import Employees,Master Reviewเปิดเฉพาะ HRD/IT ผ่านrequireHRD()
ผ่านแบบมีเงื่อนไข
Training Recordsใช้requireOrganizationAccess()แล้วคุมต่อด้วย scope และ review permission ภายใน serviceReports Exportกัน employee ไม่ให้ export รายงานรวม โดยอนุญาตเฉพาะemployeeTranscript
สรุป: Pass
Data Scope Review
Employee
ผ่าน:
- training records ถูก scope ตาม employee mapping ของ user
- reports ถูก scope ตาม employee ของตัวเอง ถ้า role ไม่ใช่ owner/admin
HRD / IT
ผ่าน:
- reports ระดับองค์กรเปิดให้ membership role
owner/admin - training review เปิดเฉพาะ role ที่ review ได้
สรุป: Pass
Hardcoded Roles Review
สิ่งที่พบ:
- role string หลักกระจุกอยู่ใน
src/lib/auth/roles.ts - แต่ยังมีการอ้าง role ตรง ๆ ซ้ำใน
nav-config.ts,session.ts, เอกสาร, และบาง feature
ประเมิน:
- ยังไม่ถึงขั้นกระจายมั่ว
- แต่ยังไม่มี permission matrix กลางที่เป็น single source of truth
สรุป: Acceptable but should improve later
Summary
ภาพรวมปัจจุบัน:
- ระบบกันสิทธิ์ที่ระดับ page และ API ถือว่าใช้ได้
- data scope ของ employee ฝั่ง training records และ reports ถือว่าปลอดภัยในระดับหนึ่ง
- จุดที่ไม่ตรง requirement ชัดที่สุดคือ
Import พนักงานยังไม่ถูกถอดออกจริง - อีกจุดที่ควรรีบจัดระเบียบคือความไม่ตรงกันระหว่าง “เมนูที่เห็น” กับ “สิทธิ์จริงของหน้า” โดยเฉพาะ
Reports,Announcements,Notifications
Recommended Next Actions
- ตัดสินใจให้ชัดว่า
Import พนักงานจะเก็บหรือจะถอด แล้วปิดทั้ง UI, route, API ให้ครบ - ทำ matrix สิทธิ์ของ
Employee / HRD / ITแบบสั้น ๆ แล้วใช้เป็นตัวเทียบกับnav-config.ts - sync
nav-config.tsกับ page/API permission ให้ผู้ใช้เห็นเมนูตรงกับสิทธิ์จริง - อัปเดต
docs/nav-rbac.mdให้ตรงกับโค้ดปัจจุบัน