# Employee Dashboard Audit Report ## Executive Summary Overall Status - Good ภาพรวม: - หน้า Employee Dashboard ใช้สถาปัตยกรรมที่สอดคล้องกับโปรเจ็กต์ค่อนข้างดี โดยมี route guard, server-side data aggregation และแยก component ตาม feature ชัดเจน - ข้อมูลหลักของพนักงาน เช่น ชั่วโมงที่อนุมัติแล้ว ความคืบหน้า K / S / A กิจกรรมล่าสุด และประกาศล่าสุด ถูกดึงจากฝั่ง server ภายใต้ขอบเขตองค์กรและผู้ใช้ที่กำลังล็อกอิน - จุดที่ควรปรับหลัก ๆ อยู่ที่ error handling, ความสม่ำเสมอของ navigation/UX, การแสดงผล progress เมื่อเกินเป้า, และการสื่อสารกรณีข้อมูลว่างหรือผู้ใช้ยังไม่ผูก employee profile --- ## Architecture Review สิ่งที่พบ: - Route หลักอยู่ที่ [src/app/dashboard/page.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/page.tsx) และ redirect ไป `/dashboard/overview` - Employee Dashboard จริงถูกวางบน [src/app/dashboard/overview/layout.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/overview/layout.tsx) และ [src/app/dashboard/overview/page.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/overview/page.tsx) - Layout ใช้ parallel routes แยก slot เป็น `@area_stats`, `@sales`, `@bar_stats`, `@pie_stats` - Data หลักรวมอยู่ใน [src/features/overview/server/overview-data.ts](/d:/WY-2569/HRD/training-system-minimal-refactor/src/features/overview/server/overview-data.ts) และใช้ `cache()` ลดการคำนวณซ้ำใน render เดียวกัน - Guard ใช้ [src/lib/auth/page-guards.ts](/d:/WY-2569/HRD/training-system-minimal-refactor/src/lib/auth/page-guards.ts) ผ่าน `requireEmployeeDashboardAccess()` ข้อสรุป: - โครงสร้างโดยรวมดี และแยก server responsibility ไว้ถูกที่ - อย่างไรก็ดี Employee Dashboard ถูกวางชื่อ route เป็น `overview` มากกว่าจะมี bounded context ชัดเจนแบบ `employee-dashboard` ทำให้ความหมายของหน้าและความต่างระหว่าง employee กับ HRD พึ่งพา conditional rendering ค่อนข้างมาก --- ## Functional Review | Feature | Status | Notes | | ------- | ------ | ----- | | View own dashboard | Pass | พนักงานเข้า dashboard ได้ผ่าน `requireEmployeeDashboardAccess()` | | Summary cards | Pass | มี approved, pending/revision, rejected, progress | | Required hours resolution | Partial | fallback ไป policy ล่าสุดหรือ 0 ได้ แต่ไม่มีข้อความอธิบายเมื่อไม่พบ policy/target | | K / S / A summary | Pass | คิดจาก approved records เท่านั้น ซึ่งสอดคล้องกับการวัดความคืบหน้า | | Recent activities | Partial | แสดง 5 รายการล่าสุด แต่เรียงตาม `createdAt` ไม่ใช่ `trainingDate` | | Announcements widget | Pass | แสดงประกาศล่าสุดและลิงก์ไปหน้ารายละเอียดได้ | | Notifications page | Pass | มีหน้ารายการ notifications แยกต่างหาก | | Progress bar | Partial | รองรับ 0 และ partial ได้ แต่กรณีเกินเป้าถูก cap ที่ 100% ทำให้ไม่เห็นว่าทะลุเป้า | | Empty states | Partial | มี empty state ในหลาย widget แต่ไม่มีคำอธิบายกรณีผู้ใช้ยังไม่ผูก employee profile | | Error states | Partial | มี error boundary ครบหลายจุด แต่แสดง raw `error.message` ต่อผู้ใช้ | | Responsive layout | Pass | layout ใช้ grid ที่ยุบลงได้ทั้ง mobile และ desktop | | Dashboard filter | Partial | employee กรองได้ตามปี, admin กรองได้หลายมิติ แต่ใช้ native select และ submit form แบบพื้นฐาน | | Refresh behavior | Partial | ข้อมูลดึงจาก server render ใหม่ได้ แต่หน้า dashboard ไม่มี evidence ชัดเจนเรื่อง targeted invalidation หลัง action อื่น ๆ | --- ## Business Rule Review สิ่งที่สอดคล้อง: - Employee เห็นเฉพาะข้อมูลตนเองผ่าน `getEmployeeIdsForUser()` และเงื่อนไข scope ใน [overview-data.ts](/d:/WY-2569/HRD/training-system-minimal-refactor/src/features/overview/server/overview-data.ts) - ชั่วโมง approved ใช้ `approvedHours` ถ้ามี ไม่เช่นนั้น fallback ไป `hours` - K / S / A คิดจากรายการที่อนุมัติแล้วเท่านั้น - ปีที่ใช้กรองแยกจากค่า default ปีปัจจุบัน จุดที่ควรระวัง: - การใช้ปีอ้างอิงด้วย `new Date().getUTCFullYear()` และช่วงวันแบบ UTC อาจต่างจากการตีความปีตาม timezone ธุรกิจที่ใช้งานจริงปลายปี/ต้นปี - หากพนักงานไม่มี employee profile ที่ผูกกับ user ระบบจะคืนค่าศูนย์เกือบทั้งหมด แต่ไม่ได้บอกผู้ใช้ว่าสาเหตุคือ “ยังไม่พบข้อมูลพนักงาน” - ความคืบหน้าถูกจำกัดไม่เกิน 100% ทำให้ business outcome แบบ “เกินเป้า” ไม่ถูกสื่อสารบน UI --- ## Role & Permission Review Employee - View own dashboard: Pass - View own statistics: Pass - View own training history: Pass - View notifications: Pass ผ่าน [src/app/dashboard/notifications/page.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/notifications/page.tsx) - View announcements: Pass ผ่าน [src/app/dashboard/announcements/page.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/announcements/page.tsx) - View other employees: Not observed in dashboard flow - Approve training / edit policy / access HRD pages: Guarded by HRD-only routes ข้อสังเกต: - ฝั่ง route protection ถือว่าดี - แต่ navigation ไม่สม่ำเสมอ: employee เข้า announcements และ notifications ได้โดยตรง แต่เมนูใน [src/config/nav-config.ts](/d:/WY-2569/HRD/training-system-minimal-refactor/src/config/nav-config.ts) ไม่ได้เปิดเส้นทางเหล่านี้ให้เห็นอย่างชัดเจนใน sidebar หลัก --- ## UI Review จุดที่ดี: - ใช้ `PageContainer`, `Card`, `Badge`, `Progress` และ chart shell เดียวกับโปรเจ็กต์ - spacing โดยรวมสม่ำเสมอ - widget หลักแบ่งเป็น summary + content blocks อ่านง่ายบน desktop จุดที่ควรปรับ: - summary cards render `Badge` ทุกใบ แม้หลายใบส่ง `badge: ''` มา ทำให้มี badge ว่างหรือเหลือเพียง icon ใน [src/app/dashboard/overview/layout.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/overview/layout.tsx) - filter panel ใช้ native `