# 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 `<select>` แทน shared form/select patterns ของโปรเจ็กต์
- หน้า employee dashboard ไม่มี notification widget โดยตรง ทั้งที่มี notifications page อยู่แล้ว ทำให้ข้อมูลสำคัญถูกแยกบริบทออกจากหน้าหลัก

---

## UX Review

จุดที่ดี:

- ผู้ใช้เห็นภาพรวมข้อมูลสำคัญได้เร็ว
- ประกาศล่าสุดและกิจกรรมล่าสุดช่วยสร้างบริบทการใช้งานประจำวัน

จุดที่ควรปรับ:

- หากเกิด error ผู้ใช้จะเห็นข้อความเชิงเทคนิคเกินไป
- หากไม่มีข้อมูลเพราะยังไม่ผูก employee profile, ไม่มี policy, หรือยังไม่เคยส่งรายการ ระบบไม่อธิบายสาเหตุให้ชัด
- notifications แยกไปอีกหน้า แต่ไม่มีทางเข้าที่เด่นพอจาก dashboard/sidebar สำหรับ employee
- recent activities ใช้วันฝึกอบรมแสดงผล แต่ใช้เวลาสร้างรายการเป็นตัวเรียงลำดับ ซึ่งอาจขัดกับความคาดหวังว่า “ล่าสุด” หมายถึงฝึกเมื่อไร

---

## Accessibility Review

จุดที่ดี:

- ใช้ semantic button/link/card ของ shared UI หลายจุด
- chart components เปิด `accessibilityLayer` ใน Recharts หลายตัว

จุดที่ควรปรับ:

- error UI หลายจุดพึ่งพาสีและข้อความทั่วไป แต่ไม่มี recovery action ครบทุก slot
- native chart summary ไม่มี text alternative เชิงสรุปมากนักสำหรับ screen reader
- badge/progress สื่อสถานะหลักด้วย visual emphasis มากกว่าคำอธิบายเฉพาะกรณี “เกินเป้า”

---

## Code Quality Review

จุดที่ดี:

- รวม logic ฝั่ง dashboard ไว้ใน data builder เดียว ทำให้ trace business logic ได้ง่าย
- type ค่อนข้างชัด และ model ที่ส่งไป component แยกตามการใช้งานจริง
- ใช้ helper role กลาง เช่น `isOrganizationAdminRole()`

จุดที่ควรปรับ:

- `OverviewFilterPanel` เช็ก admin role ด้วย string comparison ตรง ๆ แทน helper กลาง
- มีการผสม concern ของ employee/admin dashboard ไว้ใน route เดียวค่อนข้างมาก
- naming บางส่วนยังติด template เดิม เช่น `RecentSales` ทั้งที่ใช้แสดงกิจกรรมการอบรม

---

## API Review

สิ่งที่พบ:

- Dashboard data ฝั่ง overview ดึงตรงจาก server helper ไม่ผ่าน client query เป็นหลัก
- Notifications ใช้ route handlers และ React Query ตาม pattern โปรเจ็กต์
- Notifications API validate query params ด้วย Zod

จุดที่ควรปรับ:

- error responses จาก API ถูกส่งกลับไปยัง UI แล้ว render `error.message` ตรง ๆ ในบางหน้าของ dashboard/notifications
- dashboard เองยังไม่มี contract ที่แยก concern เช่น announcements กับ notifications ให้ชัดในหน้าหลัก

---

## Performance Review

จุดที่ดี:

- `getOverviewDashboardData()` ถูกห่อด้วย `cache()` ช่วยลดงานซ้ำใน request เดียว
- widget หลักเป็น server-driven ลด client state ที่ไม่จำเป็น

จุดที่ควรระวัง:

- หน้า overview มีหลาย parallel route ที่ต่างเรียก data helper เดียวกัน แม้ `cache()` จะช่วย แต่โครงสร้างยังค่อนข้างซับซ้อนสำหรับ dashboard ที่ข้อมูลสัมพันธ์กันสูง
- chart และ card ทั้งหมดโหลดพร้อมกัน ไม่มี loading boundary ระดับหน้า root ของ overview

---

## Security Review

จุดที่ดี:

- route protection ฝั่ง employee/HRD ใช้งานจริง
- dashboard scope ข้อมูลตาม organization และ user
- notifications API จำกัดตาม `organizationId` และ `userId`

ความเสี่ยง:

- error boundary หลายจุดเปิดเผย `error.message` ตรง ๆ เช่น [src/app/dashboard/overview/error.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/overview/error.tsx), [src/app/dashboard/overview/@sales/error.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/overview/@sales/error.tsx), [src/features/notifications/components/notifications-page.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/features/notifications/components/notifications-page.tsx)

---

## Consistency Review

สอดคล้อง:

- ใช้ shared UI stack และ page guard ตามแนวทางโปรเจ็กต์
- notifications page ใช้ React Query + HydrationBoundary ตาม pattern กลาง

ไม่สอดคล้อง:

- dashboard table-like recent activity ใช้ custom list ซึ่งโอเคตามลักษณะข้อมูล แต่ naming ยังโยงกับ template เดิม
- filter panel ของ overview ยังไม่ใช้ shared select/form wrappers แบบที่หลาย feature ใช้อยู่
- employee-accessible pages บางหน้าไม่มีเมนูนำทางที่สอดคล้องกับสิทธิ์จริง

---

## Edge Case Review

- New employee: แสดงค่า 0 ได้ แต่ไม่บอกว่าเพราะยังไม่มีข้อมูลพนักงาน/ประวัติอบรม
- No training records: รองรับได้
- All completed: รองรับได้
- Over target: คำนวณได้ แต่ UI ไม่สื่อส่วนเกิน
- Missing category: K / S / A จะเหลือค่าตามข้อมูลที่มี แต่ไม่ได้อธิบาย category ที่หาย
- Missing policy: fallback เป็น 0 ได้ แต่ไม่มี warning/explanation
- Missing profile: ไม่พัง แต่ silent failure ในเชิง UX
- API failure: มี error UI แต่ข้อความไม่เหมาะกับผู้ใช้ปลายทาง
- Slow network: มี loading เฉพาะบาง slot แต่ไม่มี root loading ของ overview

---

## Problems Found

### High

- Description: Error UI หลายจุดแสดง raw `error.message` ต่อผู้ใช้โดยตรง
- File: [overview/error.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/overview/error.tsx), [@sales/error.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/overview/@sales/error.tsx), [@area_stats/error.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/overview/@area_stats/error.tsx), [@pie_stats/error.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/overview/@pie_stats/error.tsx), [notifications-page.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/features/notifications/components/notifications-page.tsx)
- Component: `OverviewError`, `SalesError`, `AreaStatsError`, `PieStatsError`, `NotificationsPage`
- Severity: High
- Impact: เสี่ยงเปิดเผยข้อมูลเชิงเทคนิคจาก backend/runtime และทำให้ UX ของผู้ใช้ปลายทางสับสน
- Recommendation: แสดงข้อความกลางที่ปลอดภัยต่อผู้ใช้ และ log รายละเอียดไว้ภายในแทน

- Description: Dashboard ไม่สื่อกรณี “เกินเป้าชั่วโมง” แม้ข้อมูลคำนวณถึงเป้าแล้ว
- File: [overview-data.ts](/d:/WY-2569/HRD/training-system-minimal-refactor/src/features/overview/server/overview-data.ts), [ksa-progress.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/features/overview/components/ksa-progress.tsx)
- Component: `buildEmployeeCards`, `KsaProgress`
- Severity: High
- Impact: ผู้ใช้ที่ทำเกินเป้าจะเห็นเพียง 100% เท่ากับผู้ใช้ที่เพิ่งแตะเป้า ทำให้สูญเสียข้อมูลเชิงบริหารและแรงจูงใจ
- Recommendation: แยกสถานะ completed กับ exceeded และสื่อส่วนเกินบน UI

### Medium

- Description: Recent activities เรียงด้วย `createdAt` แต่แสดงวันที่เป็น `trainingDate`
- File: [overview-data.ts](/d:/WY-2569/HRD/training-system-minimal-refactor/src/features/overview/server/overview-data.ts), [recent-sales.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/features/overview/components/recent-sales.tsx)
- Component: `getOverviewDashboardData`, `RecentSales`
- Severity: Medium
- Impact: ผู้ใช้อาจเข้าใจว่าเป็น “อบรมล่าสุดตามวันที่ฝึก” ทั้งที่จริงคือ “รายการที่สร้างล่าสุด”
- Recommendation: เลือกให้ชัดว่าจะเรียงตามวันฝึกหรือวันส่ง และทำ label ให้ตรง

- Description: พนักงานเข้าหน้า notifications และ announcements ได้ แต่ navigation หลักไม่สอดคล้องกับสิทธิ์จริง
- File: [nav-config.ts](/d:/WY-2569/HRD/training-system-minimal-refactor/src/config/nav-config.ts), [notifications/page.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/notifications/page.tsx), [announcements/page.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/announcements/page.tsx)
- Component: sidebar config, employee-accessible routes
- Severity: Medium
- Impact: discoverability ต่ำ ผู้ใช้เข้าฟีเจอร์ที่มีสิทธิ์ได้ยาก และ navigation model ไม่สม่ำเสมอ
- Recommendation: ทบทวนเมนู employee ให้ตรงกับ route ที่เปิดใช้งานจริง

- Description: Summary cards แสดง badge แม้ไม่มีข้อความ badge จริง
- File: [overview/layout.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/overview/layout.tsx)
- Component: `OverViewLayout`
- Severity: Medium
- Impact: UI ดูไม่ตั้งใจและเพิ่ม noise ในส่วนสรุปสำคัญ
- Recommendation: render badge แบบมีเงื่อนไข หรือกำหนดข้อความ badge ให้ครบ

- Description: กรณี user ไม่มี employee profile / ไม่มี policy ระบบแสดงศูนย์อย่างเงียบ ๆ
- File: [overview-data.ts](/d:/WY-2569/HRD/training-system-minimal-refactor/src/features/overview/server/overview-data.ts)
- Component: `getOverviewDashboardData`
- Severity: Medium
- Impact: ผู้ใช้และทีม support แยกไม่ออกว่า “ไม่มีข้อมูล” หรือ “ข้อมูลเชื่อมไม่ครบ”
- Recommendation: เพิ่ม state หรือ messaging ที่อธิบายสาเหตุของข้อมูลว่าง

### Low

- Description: `OverviewFilterPanel` ใช้ string compare role ตรง ๆ แทน helper กลาง
- File: [overview-filter-panel.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/features/overview/components/overview-filter-panel.tsx)
- Component: `OverviewFilterPanel`
- Severity: Low
- Impact: ลดความสม่ำเสมอของโค้ดและเพิ่มโอกาส logic drift
- Recommendation: ใช้ role helper กลางเดียวกับส่วนอื่น

- Description: ชื่อ component `RecentSales` ไม่ตรงกับหน้าที่จริง
- File: [recent-sales.tsx](/d:/WY-2569/HRD/training-system-minimal-refactor/src/features/overview/components/recent-sales.tsx)
- Component: `RecentSales`
- Severity: Low
- Impact: อ่านโค้ดยากขึ้นและสะท้อนร่องรอยจาก template เดิม
- Recommendation: เปลี่ยนชื่อให้ตรงกับโดเมนเมื่อมีรอบ refactor

- Description: หน้า overview ไม่มี root loading state ของ route หลัก
- File: [src/app/dashboard/overview](/d:/WY-2569/HRD/training-system-minimal-refactor/src/app/dashboard/overview)
- Component: overview route
- Severity: Low
- Impact: initial load ของทั้งหน้าอาจดูนิ่งเกินไปหาก data ช้า และพึ่ง loading ของบาง slot เท่านั้น
- Recommendation: เพิ่ม loading ระดับหน้าให้สอดคล้องกับหน้า dashboard สำคัญอื่น ๆ

---

## Missing Features

- Notification summary/widget บนหน้า dashboard สำหรับ employee
- ข้อความอธิบายกรณีไม่พบ employee profile หรือ policy เป้าหมาย
- การสื่อสารสถานะ “เกินเป้า” แยกจาก “ครบเป้า”
- Navigation entry ที่สอดคล้องกับ employee-accessible notifications/announcements

---

## Improvement Opportunities

- แยก employee dashboard semantics ให้ชัดกว่าการ reuse `overview` route ร่วมกับ HRD
- เพิ่ม domain-specific naming ให้ component/slot เพื่อให้อ่านโค้ดง่ายขึ้น
- ทำ filter panel ให้ใช้ shared form/select stack ของโปรเจ็กต์
- เพิ่ม explanatory empty states ตามสาเหตุจริงของข้อมูลว่าง
- เพิ่ม text summary สำหรับ charts เพื่อช่วยทั้ง accessibility และการอ่านค่าบน mobile

---

## Final Assessment

Architecture: 8/10

Functionality: 7.5/10

UI: 7/10

UX: 6.8/10

Accessibility: 6.8/10

Performance: 7.5/10

Security: 7.5/10

Maintainability: 7.6/10

Overall Score: 7.3/10
