This commit is contained in:
2026-07-16 09:53:14 +07:00
parent 0fc112a2e8
commit 29cec708a3
1236 changed files with 212848 additions and 0 deletions

View File

@@ -0,0 +1,196 @@
# Auto Refresh Implementation Report
## 1. Executive Summary
Implemented a shared TanStack Query invalidation layer for CRUD and workflow mutations that affect multiple dashboard modules. The change keeps existing URL search params, filters, sorting, pagination, dialogs, and route-handler architecture intact while making related client-side caches stale after successful actions.
## 2. Modules Audited
- Users
- Employees
- Employee Directory
- Courses
- Training Records
- Training Record Reviews
- Training Record Certificates
- Training Matrix
- Online Lessons
- Announcements
- Training Policies
- Permission Management
- Employee Import and Master Review
- Organizers
- Notifications
- Products legacy feature
## 3. Problems Found
- Several mutations invalidated only their own feature list even when the action changed data used by other pages.
- Certificate upload/delete refreshed the certificate list but not the training record detail/list cache that can show certificate preview data.
- Course mutations refreshed Course Master but not course option consumers used by training records and matrix screens.
- People mutations refreshed users or employees separately, but related directory, permission, and training-record option caches could remain stale.
- Content workflow actions could create notifications while only refreshing the content module.
## 4. Root Causes
- Cache invalidation lived inside each feature mutation file with no shared dependency map.
- Query keys were consistent, but related keys were not grouped by domain.
- The app uses server-prefetch plus hydrated TanStack Query; after a client mutation, stale hydrated data needs explicit query invalidation.
## 5. Files Changed
- `src/lib/query-invalidation.ts`
- Added shared invalidation helpers grouped by domain: people, courses, training records, training matrix, content workflow, permissions, organizers, imports, and policies.
- Reason: centralizes related cache dependencies without introducing a new library or changing page architecture.
- Impact: mutations can refresh all affected query groups consistently.
- Test: lint and TypeScript compile.
- `src/features/users/api/mutations.ts`
- Switched create/update/delete to `invalidatePeopleData()`.
- Reason: user changes affect users, employee-facing selectors, directory consumers, and permission assignment screens.
- Impact: user-related pages update after CRUD.
- Test: lint and TypeScript compile.
- `src/features/employees/api/mutations.ts`
- Switched create/update/delete to `invalidatePeopleData()`.
- Reason: employee changes affect Employee Directory and training-record participant options.
- Impact: employee data consumers refresh after employee CRUD.
- Test: lint and TypeScript compile.
- `src/features/courses/api/mutations.ts`
- Switched create/update/delete to `invalidateCourseData()`.
- Reason: course changes affect Course Master, training-record course options, and matrix option/compliance consumers.
- Impact: course selectors and matrix-dependent data are refreshed after course CRUD.
- Test: lint and TypeScript compile.
- `src/features/training-records/api/mutations.ts`
- Switched create/update/delete/import to `invalidateTrainingRecordData()`.
- Reason: training records affect record lists, employee directory summaries, and training matrix compliance.
- Impact: list and related summaries refresh after record actions.
- Test: lint and TypeScript compile.
- `src/features/training-records/api/review-mutations.ts`
- Added related training record invalidation plus detail invalidation for the reviewed record.
- Reason: review actions affect pending/approved lists and the detail page.
- Impact: pending review and training record views refresh after review actions.
- Test: lint and TypeScript compile.
- `src/features/training-records/api/certificate-mutations.ts`
- Added record list/detail invalidation alongside certificate list invalidation.
- Reason: certificate changes can affect preview data shown on record views.
- Impact: attachment and record UI update together.
- Test: lint and TypeScript compile.
- `src/features/training-matrix/api/mutations.ts`
- Switched create/update/delete to `invalidateTrainingMatrixData()`.
- Reason: matrix target changes affect matrix pages, employee target summaries, and training-record compliance consumers.
- Impact: matrix-related screens update after matrix CRUD.
- Test: lint and TypeScript compile.
- `src/features/employee-directory/api/mutations.ts`
- Added matrix/record related invalidation after target upsert while keeping target detail invalidation.
- Reason: employee target edits affect matrix compliance and employee-directory views.
- Impact: target detail and related summaries refresh after save.
- Test: lint and TypeScript compile.
- `src/features/online-lessons/api/mutations.ts`
- Added content workflow invalidation for lesson CRUD/workflow actions.
- Reason: lesson submit/publish/delete can affect lesson lists/details and notifications.
- Impact: content and notification data refresh after lesson actions.
- Test: lint and TypeScript compile.
- `src/features/announcements/api/mutations.ts`
- Added content workflow invalidation for announcement CRUD, workflow, pin, and unpin actions.
- Reason: announcement actions can affect lists/details and notifications.
- Impact: announcement and notification data refresh after content actions.
- Test: lint and TypeScript compile.
- `src/features/training-policy/api/mutations.ts`
- Switched policy actions to `invalidateTrainingPolicyData()`.
- Reason: policy changes may affect matrix-related policy views.
- Impact: policy and related matrix data refresh after policy actions.
- Test: lint and TypeScript compile.
- `src/features/import-employees/api/mutations.ts`
- Switched import/review actions to `invalidateEmployeeImportData()`.
- Reason: imports and master review can change employees, directory data, and participant options.
- Impact: employee-facing data refreshes after import and review actions.
- Test: lint and TypeScript compile.
- `src/features/organizers/api/mutations.ts`
- Switched organizer CRUD to `invalidateOrganizerData()`.
- Reason: organizer changes can affect user/employee organization context data.
- Impact: organizer and related people data refresh after organizer actions.
- Test: lint and TypeScript compile.
- `src/features/permission-management/api/mutations.ts`
- Switched template and user-permission mutations to `invalidatePermissionData()` plus user detail invalidation where needed.
- Reason: permission mutations affect template/catalog/user/audit views and user lists.
- Impact: permission screens update more consistently after save/clone/activate/deactivate/delete.
- Test: lint and TypeScript compile.
- `src/features/products/api/mutations.ts`
- Added product detail invalidation after update.
- Reason: legacy detail view can otherwise show stale data after update.
- Impact: product detail cache refreshes after update.
- Test: lint and TypeScript compile.
## 6. Refresh Strategy by Module
- People data: invalidate users, employees, employee directory, training-record user options, and permission-management users.
- Course data: invalidate courses, training-record course options, training matrix options, and training matrix lists.
- Training record data: invalidate training records, employee directory, and training matrix compliance.
- Training matrix data: invalidate matrix, employee directory, and training record data.
- Content workflow data: invalidate announcements, online lessons, and notifications.
- Permission data: invalidate permission-management root keys and users.
- Import data: invalidate master review, employees, employee directory, and training-record user options.
- Organizer data: invalidate organizers, users, employees, and employee directory.
- Training policy data: invalidate training policies and training matrix.
## 7. Cache Keys Updated
- `['users']`
- `['employees']`
- `['employee-directory']`
- `['courses']`
- `['training-records']`
- `['training-records', 'course-options']`
- `['training-records', 'user-options']`
- `['training-matrix']`
- `['announcements']`
- `['online-lessons']`
- `['notifications']`
- `['permission-management']`
- `['master-review']`
- `['organizers']`
- `['training-policies']`
- `['products']`
## 8. Pagination Handling
Existing pagination, search, filter, and sort state remains URL-driven through current table components and `nuqs`. The implementation invalidates query prefixes instead of rewriting search params, so existing table state is preserved.
## 9. Related Data Revalidation
Related data is now grouped by domain in `src/lib/query-invalidation.ts`. Mutations call the relevant domain helper rather than refreshing only the immediate feature.
## 10. Full Page Reloads Removed
No `window.location.reload()` usage was found in the audited app code. Existing `router.refresh()` calls remain only where the surrounding component/page still uses server component refresh behavior after a mutation.
## 11. Test Results
- `npm run lint -- src/lib/query-invalidation.ts ...`: passed.
- `npx tsc --noEmit --pretty false`: passed.
## 12. Remaining Risks
- Some server-rendered dashboard summary/report widgets may use direct server data without a client query key; those still depend on navigation or `router.refresh()` unless migrated to TanStack Query.
- The current working tree already had unrelated edits in `src/app/dashboard/courses/page.tsx` and `src/features/courses/components/course-tables/columns.tsx`; this implementation did not revert or normalize those changes.
- Manual browser testing was not completed in this pass.
## 13. Recommendations
- Add query keys for dashboard/report summary widgets if they need live client refresh after related mutations.
- Keep future mutation files thin by using the shared domain invalidation helpers instead of adding one-off invalidate lists.
- Add a small integration test for high-risk flows: training record review, certificate upload/delete, course create/update, and employee import review.

1033
plans/action-auto-refresh.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
You are a Senior Full Stack Engineer working on this Next.js 16 Training System project.
Task:
In the Admin/HRD Training History page, add a Year filter.
Before editing code, inspect and follow:
1. AGENTS.md
2. docs/AI_DEVELOPMENT_GUIDE.md
3. docs/PROJECT_ARCHITECTURE.md
Scope:
Only modify the Admin/HRD Training History page and related query/filter logic if necessary.
Requirements:
1. Find the Admin/HRD Training History page.
2. Add a Year filter to the existing filter area.
3. The Year filter should allow HRD/Admin to filter training records by training year.
4. Default selected year should be the current year.
5. Year should be based on the training date, not created_at.
6. Preserve existing filters, table layout, pagination, sorting, and UI style.
7. Use existing project components such as Select, Button, DataTable, filter hooks, nuqs, TanStack Query, or existing patterns if already used.
8. Do not introduce a new UI pattern if an existing filter pattern exists.
9. Ensure the year filter works with server-side fetching if the current page uses server-side query params.
10. Ensure the filter persists in the URL if the page already uses URL search params.
11. Include an “All years” option if the existing filter design supports all/empty values.
12. Do not change employee-facing pages unless shared logic requires it.
13. Do not use any.
14. Ensure TypeScript and ESLint pass.
Implementation expectations:
- Add year filter state/search param.
- Pass year to the API/query options.
- Update API/service/database query to filter by YEAR(training_date) or the equivalent date range.
- Prefer date range filtering for performance:
training_date >= startOfYear
training_date < startOfNextYear
- Keep existing role permissions unchanged.
After implementation:
Create /docs/ai/report.md with:
- Summary
- Files changed
- Root cause / reason for change
- Changes made
- Testing checklist
- Risks
- Rollback plan
Testing checklist must include:
- Default current year shows records correctly
- Selecting another year updates table data
- All years shows all records if supported
- Existing filters still work together with year
- Pagination still works
- Sorting still works
- HRD/Admin permissions unchanged
- TypeScript passes
- ESLint passes
Return a concise summary after completing the changes.

View File

@@ -0,0 +1,258 @@
# Announcement Approval Workflow
## Background
ปัจจุบันโมดูล Announcement และ Online Lesson มี Workflow ที่แตกต่างกัน ส่งผลให้ผู้ใช้งานเกิดความสับสน และทำให้ระบบมี Business Logic ซ้ำกันหลายส่วน
ต้องการให้ Announcement ใช้ Approval Workflow เดียวกับ Online Lesson ทั้งในด้าน UI, Validation, Permission, Status และ Notification โดยยังคงพฤติกรรมของ Online Lesson ที่ทำงานถูกต้องอยู่แล้ว
---
# Requirement ที่เข้าใจ
## Objective
ปรับปรุงโมดูล Announcement ให้ใช้ Approval Workflow เดียวกับ Online Lesson
### Workflow
ผู้สร้าง
- Admin
- HRD Staff
สามารถ
- บันทึกฉบับร่าง
- ส่งตรวจสอบ
HRD Manager
สามารถ
- Preview
- Approve
- Reject พร้อม Comment
หลัง Approve
เปลี่ยนสถานะเป็น
Approved
โดยไม่ Publish ทันที
HRD Manager จึงสามารถ
- Publish
- Schedule Publish
ได้ภายหลัง
IT Admin และ Super Admin ยังคงสามารถดำเนินการทุกขั้นตอนได้ตามสิทธิ์
---
## UI
หน้าเพิ่มประกาศ
- ลบ Dropdown สถานะ
- ใช้ปุ่ม
- บันทึกฉบับร่าง
- ส่งตรวจสอบ
เหมือนหน้าเพิ่มบทเรียนออนไลน์ทุกประการ
---
## Validation
ใช้ Validation เดียวกับ Online Lesson
Draft
- บันทึกได้ตาม Logic ปัจจุบัน
Submit
- ต้องผ่าน Validation ทั้งหมด
หาก Validation ไม่ผ่าน
- ไม่เปลี่ยน Status
- แสดง Error ทุก Field
- ผู้ใช้สามารถแก้ไขแล้ว Submit ใหม่ได้
---
## Status
Announcement ต้องรองรับ
- Draft
- Pending Approval
- Approved
- Published
- Scheduled
- Rejected
- Archived
ใช้ Business Logic เดียวกับ Online Lesson
---
## Permission
Admin / HRD Staff
- Create
- Edit Draft
- Delete Draft
- Submit
HRD Manager
- View Pending
- Approve
- Reject
- Publish
- Schedule Publish
- Archive
IT Admin
- Full Access
Super Admin
- Full Access
Employee
- View Published Only
---
## Notification
เมื่อ Submit
แจ้งเตือน HRD Manager
เมื่อ Approve
แจ้งเตือนผู้สร้าง
เมื่อ Reject
แจ้งเตือนผู้สร้างพร้อมเหตุผล
เมื่อ Publish
แจ้งเตือนผู้สร้าง
ใช้ Notification Pattern เดียวกับ Online Lesson
---
# Scope of Work
- แก้ไขเฉพาะโมดูล Announcement
- ห้ามเปลี่ยนพฤติกรรมของ Online Lesson ที่ทำงานถูกต้องอยู่แล้ว
- ห้ามเกิด Regression กับ Online Lesson
- หากพบ Business Logic ซ้ำ สามารถ Refactor ได้เฉพาะส่วนที่ปลอดภัย
- Reuse Shared Component, Shared Hook และ Shared Service หากมีอยู่แล้ว
- ห้าม Copy Logic ของ Online Lesson มาใหม่โดยไม่จำเป็น
---
# Technical Requirements
ก่อนแก้ไขโค้ด
- ตรวจสอบ Architecture ปัจจุบัน
- ตรวจสอบ Shared Component
- ตรวจสอบ Shared Hook
- ตรวจสอบ Shared Service
- ตรวจสอบ Permission Middleware
- ตรวจสอบ Approval Flow
- ตรวจสอบ Notification Flow
ระหว่างแก้ไข
- ใช้มาตรฐานของ Project
- รักษา Type Safety
- ไม่เพิ่ม Dead Code
- ไม่เพิ่ม Duplicate Logic
หลังแก้ไข
- ตรวจสอบ TypeScript Error
- ตรวจสอบ ESLint
- ตรวจสอบ Build Error
- ตรวจสอบ Permission
- ตรวจสอบ Approval Workflow
- ตรวจสอบ Notification
- ตรวจสอบ UI Regression
---
# Deliverables
เมื่อดำเนินการเสร็จ
ต้องส่งมอบ
- โค้ดที่แก้ไขเรียบร้อย
- ไม่มี TypeScript Error
- ไม่มี ESLint Error
- ไม่มี Build Error
- Permission ทำงานถูกต้อง
- Workflow ทำงานถูกต้อง
- Validation ทำงานถูกต้อง
- Notification ทำงานถูกต้อง
- ไม่กระทบ Online Lesson
และสร้างเอกสาร
docs/announcement-approval-workflow-implementation-report.md
ภายในเอกสารต้องประกอบด้วย
1. Executive Summary
2. Architecture Review
3. Files Modified
4. Business Logic Changes
5. UI Changes
6. Permission Changes
7. Workflow Changes
8. Refactoring Summary
9. Breaking Changes (ถ้ามี)
10. Regression Risk
11. Test Checklist
- Create Draft
- Submit
- Approve
- Reject
- Publish
- Schedule Publish
- Notification
- Permission
- UI
- Validation
12. Known Issues (ถ้ามี)
13. Recommendation

View File

@@ -0,0 +1,587 @@
# Prompt: Move Announcement Pin Action Out of Create/Edit Form
## Objective
ปรับปรุงการจัดการฟังก์ชัน **ปักหมุดประกาศ** โดยนำตัวเลือกปักหมุดออกจากหน้าสร้างและหน้าแก้ไขประกาศ แล้วเปลี่ยนให้เป็น Action ที่ใช้งานหลังจากประกาศได้รับการเผยแพร่แล้ว
เป้าหมายคือ:
- ลดความซับซ้อนของแบบฟอร์มสร้างประกาศ
- แยกการจัดการเนื้อหาออกจากการจัดลำดับการแสดงผล
- ทำให้ Workflow ของประกาศชัดเจน
- จำกัดการปักหมุดตามสถานะและ Permission
- ใช้โครงสร้างเดิมของระบบให้มากที่สุด
---
# Existing Structure Review
ก่อนเริ่มแก้ไข ให้ตรวจสอบโครงสร้างเดิมที่เกี่ยวข้องทั้งหมด เช่น:
- Announcement database schema
- `is_pinned`, `pinned_at`, `pinned_by` หรือ Field ที่มีความหมายใกล้เคียง
- Create/Edit announcement form
- Announcement list
- Announcement detail
- Action menu
- API routes
- Server actions
- Query และ Sorting
- Permission
- Audit log
- Publish workflow
หากระบบมีโครงสร้างรองรับการปักหมุดอยู่แล้ว ให้ Reuse และปรับเฉพาะ UI/Workflow ตามความเหมาะสม
ใช้หลัก:
> Reuse > Extend > Refactor > Create New
ห้ามสร้าง Field, API หรือ Business Logic ซ้ำโดยไม่จำเป็น
---
# Scope
ดำเนินการดังนี้:
1. นำตัวเลือกปักหมุดออกจากหน้าสร้างประกาศ
2. นำตัวเลือกปักหมุดออกจากหน้าแก้ไขประกาศ
3. เพิ่ม Action ปักหมุดในหน้า Announcement List
4. เพิ่ม Action ปักหมุดในหน้า Announcement Detail หากเหมาะสม
5. จำกัด Action ตาม Status และ Permission
6. ปรับ Query การเรียงประกาศ
7. เพิ่ม Audit Log หากระบบรองรับ
8. ตรวจสอบ Regression ของ Workflow เดิม
---
# Create Announcement Form
นำ Section หรือ Field ต่อไปนี้ออกจากหน้าสร้างประกาศ:
```text
ปักหมุดประกาศ
ประกาศที่ปักหมุดจะแสดงด้านบนของรายการ
```
หน้าสร้างประกาศควรมีเฉพาะ:
- หัวข้อประกาศ
- รายละเอียดประกาศ
- วันเริ่มแสดง
- วันสิ้นสุดการแสดง
- ไฟล์แนบ
- ยกเลิก
- บันทึกร่าง
- ส่งตรวจสอบ
ห้ามส่งค่า `isPinned` หรือค่าที่เกี่ยวข้องจาก Create Form เว้นแต่โครงสร้าง API เดิมกำหนดเป็น Required ให้ปรับเป็นค่า Default ที่ปลอดภัย เช่น `false`
ประกาศใหม่ต้องมีค่าเริ่มต้น:
```text
is_pinned = false
```
---
# Edit Announcement Form
นำตัวเลือกปักหมุดออกจากหน้าแก้ไขประกาศเช่นเดียวกัน
หน้า Edit ใช้สำหรับแก้ไขเนื้อหาและช่วงเวลาการแสดงผลเท่านั้น
ห้ามให้การบันทึกหน้า Edit เปลี่ยนสถานะการปักหมุดโดยไม่ได้ตั้งใจ
---
# Announcement List
เพิ่มสถานะการปักหมุดให้มองเห็นได้ในรายการ เช่น:
- ไอคอน Pin ข้างชื่อประกาศ
- Badge `ปักหมุด`
- คอลัมน์การแสดงผล หากเหมาะกับ Layout เดิม
ตัวอย่าง:
```text
📌 ประกาศวันหยุดประจำปี
```
หรือ:
```text
[ปักหมุด] ประกาศวันหยุดประจำปี
```
หลีกเลี่ยงการเพิ่มคอลัมน์ใหม่ หากทำให้ตารางกว้างเกินไป ให้ใช้ไอคอนหรือ Badge ภายในคอลัมน์ชื่อประกาศแทน
---
# Action Menu
ใน Action Menu ของแต่ละประกาศ เพิ่มคำสั่งตามสถานะ:
หากยังไม่ปักหมุด:
```text
ปักหมุดประกาศ
```
หากปักหมุดอยู่แล้ว:
```text
ยกเลิกการปักหมุด
```
ใช้ไอคอนที่สื่อความหมาย เช่น:
- `Pin`
- `PinOff`
Action ต้องมี `aria-label` และข้อความภาษาไทยที่ชัดเจน
---
# Announcement Detail
หากหน้า Detail มีชุด Action อยู่แล้ว ให้เพิ่ม:
```text
ปักหมุดประกาศ
```
หรือ:
```text
ยกเลิกการปักหมุด
```
ไม่จำเป็นต้องเพิ่ม หากจะทำให้ Action ซ้ำซ้อนและหน้า List รองรับการใช้งานครบถ้วนแล้ว
ให้เลือกแนวทางที่สอดคล้องกับ Pattern ของระบบเดิม
---
# Status Rules
อนุญาตให้ปักหมุดเฉพาะประกาศที่มีสถานะ:
```text
Published
```
และควรอยู่ในเงื่อนไข:
- วันเริ่มแสดงมาถึงแล้ว หรือระบบอนุญาตให้ปักหมุดล่วงหน้าอย่างชัดเจน
- วันสิ้นสุดยังไม่ผ่านมา
- ไม่ถูก Archive
- ไม่ถูก Soft Delete
ห้ามปักหมุดประกาศสถานะ:
- Draft
- Pending Review
- Rejected
- Approved but not Published
- Inactive
- Archived
- Deleted
- Expired
หากระบบใช้ชื่อ Status ต่างจากนี้ ให้ Mapping กับ Enum เดิมของโปรเจกต์ ห้ามสร้าง Enum ซ้ำ
---
# Automatic Unpin Rules
ระบบต้องยกเลิกการปักหมุดอัตโนมัติ หรือไม่นำประกาศนั้นมาแสดงเป็นปักหมุด เมื่อ:
- ประกาศถูก Unpublish
- ประกาศถูก Archive
- ประกาศถูก Soft Delete
- ประกาศหมดอายุ
- วันสิ้นสุดการแสดงผลผ่านไปแล้ว
เลือกแนวทางให้สอดคล้องกับ Architecture เดิม:
1. อัปเดต `is_pinned = false` เมื่อสถานะเปลี่ยน
2. หรือ Filter ออกจาก Pinned Query โดยไม่เปลี่ยนข้อมูลเดิม
ควรเลือกวิธีที่ลดความเสี่ยงของข้อมูลไม่สอดคล้องกัน และอธิบายไว้ในรายงาน
---
# Multiple Pinned Announcements
รองรับการปักหมุดหลายประกาศ
ลำดับการแสดงผล:
1. ประกาศที่ปักหมุดก่อน
2. ภายในกลุ่มปักหมุด เรียงตาม `pinned_at DESC`
3. หากไม่มี `pinned_at` ให้ใช้ `published_at DESC`
4. ประกาศทั่วไปเรียงตามมาตรฐานเดิมของระบบ
ตัวอย่าง Query Logic:
```text
is_pinned DESC
pinned_at DESC
published_at DESC
created_at DESC
```
ให้ปรับตาม Field ที่มีอยู่จริงในระบบ
---
# Confirmation Dialog
ก่อนปักหมุด แสดง Dialog:
```text
ยืนยันการปักหมุดประกาศ
ประกาศนี้จะแสดงอยู่ด้านบนของรายการประกาศ
คุณต้องการดำเนินการต่อหรือไม่
```
ปุ่ม:
```text
ยกเลิก
ปักหมุดประกาศ
```
ก่อนยกเลิกการปักหมุด แสดง Dialog:
```text
ยืนยันการยกเลิกปักหมุด
ประกาศนี้จะกลับไปเรียงตามลำดับประกาศทั่วไป
คุณต้องการดำเนินการต่อหรือไม่
```
ปุ่ม:
```text
ยกเลิก
ยกเลิกการปักหมุด
```
หาก Pattern เดิมของระบบไม่ใช้ Confirm Dialog กับ Action ลักษณะนี้ สามารถใช้ Action ทันทีพร้อม Toast ได้ แต่ต้องรักษามาตรฐานเดียวกับ Feature อื่น
---
# Permission
ใช้ Permission-first Architecture เท่านั้น
เพิ่มหรือ Reuse Permission:
```text
announcement:pin
```
Permission นี้ครอบคลุม:
- ปักหมุดประกาศ
- ยกเลิกการปักหมุด
ทุก API หรือ Server Action ต้องตรวจสอบ Permission ฝั่ง Server
ห้ามตรวจสอบเฉพาะฝั่ง Client
ผู้ไม่มี Permission:
- ไม่เห็น Action
- เรียก API โดยตรงไม่ได้
- ได้รับ Response ที่เหมาะสม เช่น `403 Forbidden`
หากมี Permission เดิมที่มีความหมายตรงกัน ให้ Reuse และไม่สร้างซ้ำ
---
# API and Server Action
หากมี API เดิมรองรับ ให้ขยายของเดิม
หากไม่มี ให้เพิ่มเฉพาะ Endpoint หรือ Server Action ที่จำเป็น เช่น:
```text
POST /api/announcements/:id/pin
POST /api/announcements/:id/unpin
```
หรือใช้รูปแบบ Mutation ตาม Architecture เดิม
การปักหมุดต้องอัปเดต:
```text
is_pinned = true
pinned_at = current timestamp
pinned_by = current user
```
การยกเลิกปักหมุดต้องอัปเดต:
```text
is_pinned = false
pinned_at = null
pinned_by = null
```
หาก Schema เดิมไม่มี `pinned_at` หรือ `pinned_by` ให้ประเมินก่อนเพิ่ม โดยเพิ่มเฉพาะเมื่อจำเป็นต่อ Sorting และ Audit เท่านั้น
---
# Audit Log
หากระบบมี Audit Log อยู่แล้ว ให้บันทึก Action:
```text
ANNOUNCEMENT_PINNED
ANNOUNCEMENT_UNPINNED
```
ข้อมูลควรประกอบด้วย:
- Announcement ID
- Announcement title
- Actor
- Action
- Previous value
- New value
- Timestamp
ห้ามสร้างระบบ Audit ใหม่ หากมีโครงสร้างกลางอยู่แล้ว
---
# Toast Messages
ปักหมุดสำเร็จ:
```text
ปักหมุดประกาศเรียบร้อยแล้ว
```
ยกเลิกสำเร็จ:
```text
ยกเลิกการปักหมุดเรียบร้อยแล้ว
```
กรณีสถานะไม่รองรับ:
```text
สามารถปักหมุดได้เฉพาะประกาศที่เผยแพร่แล้วเท่านั้น
```
กรณีประกาศหมดอายุ:
```text
ไม่สามารถปักหมุดประกาศที่หมดอายุแล้วได้
```
กรณีไม่มีสิทธิ์:
```text
คุณไม่มีสิทธิ์จัดการการปักหมุดประกาศ
```
---
# Loading State
ขณะดำเนินการ:
- Disable Action ที่กำลังประมวลผล
- ป้องกันการกดซ้ำ
- แสดง Loading Indicator ตามมาตรฐานระบบ
- ไม่ปิดเมนูหรือ Dialog แบบทำให้ผู้ใช้ไม่ทราบผลลัพธ์
หลังสำเร็จ:
- Refresh หรือ Invalidate Query เฉพาะข้อมูลที่เกี่ยวข้อง
- ห้าม Reload ทั้งหน้าโดยไม่จำเป็น
---
# Accessibility
ตรวจสอบ:
- Action มีชื่อที่ Screen Reader เข้าใจได้
- ไอคอนไม่เป็นตัวสื่อความหมายเพียงอย่างเดียว
- Dialog Focus Management ถูกต้อง
- Keyboard Navigation ใช้งานได้
- Badge และสถานะไม่ใช้สีเพียงอย่างเดียว
---
# Responsive
หน้า List และ Action Menu ต้องใช้งานได้บน:
- Desktop
- Tablet
- Mobile
ห้ามให้ Badge หรือไอคอนปักหมุดทำให้ชื่อประกาศถูกบีบจนอ่านไม่ได้
---
# Business Logic Restrictions
ห้ามเปลี่ยน:
- Approval workflow
- Draft workflow
- Submit for review workflow
- Publish workflow
- Schedule publish workflow
- Versioning ของเนื้อหา
- File attachment logic
- Existing validation ที่ไม่เกี่ยวข้อง
- Existing permission ที่ไม่เกี่ยวข้อง
งานนี้ต้องเปลี่ยนเฉพาะ Workflow และ UI ของการปักหมุดประกาศ
---
# Testing
เพิ่มหรือปรับ Test Cases ให้ครอบคลุม:
## Functional
- Create announcement แล้ว `is_pinned` เป็น `false`
- หน้า Create ไม่มีตัวเลือกปักหมุด
- หน้า Edit ไม่มีตัวเลือกปักหมุด
- Published announcement สามารถปักหมุดได้
- Pinned announcement สามารถยกเลิกได้
- Draft ไม่สามารถปักหมุดได้
- Pending Review ไม่สามารถปักหมุดได้
- Archived ไม่สามารถปักหมุดได้
- Expired ไม่สามารถปักหมุดได้
- Unpublished announcement ไม่ถูกแสดงเป็นปักหมุด
- หลายประกาศปักหมุดเรียงถูกต้อง
## Permission
- มี `announcement:pin` เห็นและใช้ Action ได้
- ไม่มี Permission ไม่เห็น Action
- เรียก Server Action โดยไม่มี Permission ต้องถูกปฏิเสธ
## UI
- Badge หรือ Pin icon แสดงถูกต้อง
- Loading State ทำงาน
- Toast ถูกต้อง
- Confirm Dialog ถูกต้อง
- Mobile ใช้งานได้
## Regression
- Create Draft ยังทำงาน
- Submit Review ยังทำงาน
- Approve ยังทำงาน
- Publish ยังทำงาน
- Schedule Publish ยังทำงาน
- Edit Announcement ยังทำงาน
- Pagination/Search/Filter ยังทำงาน
---
# Deliverables
เมื่อดำเนินการเสร็จ ให้สร้างเอกสาร:
```text
docs/announcement-pin-action-enhancement-report.md
```
ประกอบด้วย:
## 1. Existing Structure Review
- โครงสร้างเดิมที่พบ
- Field เดิมที่ Reuse
- API/Action เดิมที่ Reuse
- Component เดิมที่ Reuse
- ส่วนที่ต้อง Refactor หรือ Extend
## 2. Files Changed
ระบุไฟล์ทั้งหมดที่แก้ไข
## 3. UI Changes
- สิ่งที่นำออกจาก Create/Edit
- Action ที่เพิ่มใน List/Detail
- Badge หรือสถานะที่เพิ่ม
## 4. Business Rules
- Status ที่ปักหมุดได้
- Automatic Unpin
- Sorting
- Multiple Pinned Announcements
## 5. Permission
- Permission ที่ใช้
- การตรวจสอบ Client/Server
## 6. Database and API Changes
- Field ที่เพิ่มหรือปรับ
- Migration
- Endpoint หรือ Server Action
## 7. Audit Log
Action ที่บันทึก
## 8. Testing Result
- Functional
- Permission
- Responsive
- Regression
## 9. Remaining Improvements
เช่น:
- Pin expiration
- Pin priority
- Scheduled pinning
- Limit maximum pinned announcements
- Drag-and-drop pinned ordering
---
# Success Criteria
งานถือว่าเสร็จเมื่อ:
- หน้าสร้างไม่มีตัวเลือกปักหมุด
- หน้าแก้ไขไม่มีตัวเลือกปักหมุด
- ปักหมุดจากหน้า List หรือ Detail ได้
- ปักหมุดได้เฉพาะประกาศที่เผยแพร่แล้ว
- Permission-first ทำงานครบ
- Server-side authorization ทำงาน
- Sorting ของประกาศปักหมุดถูกต้อง
- Automatic Unpin หรือ Filtering ทำงานถูกต้อง
- ไม่มีผลกระทบต่อ Approval/Publish Workflow
- TypeScript ไม่มี Error
- ESLint ผ่าน
- Build ผ่าน
- Tests ผ่าน
- ไม่มี Regression
- รายงานถูกสร้างเรียบร้อย

View File

@@ -0,0 +1,373 @@
# Fix Permission Bug: User สามารถเห็น "หมายเหตุการตรวจสอบ" ในหน้ารายละเอียดประกาศ
## ปัญหา
ปัจจุบันเมื่อผู้ใช้งาน (Employee/User) เปิดดูรายละเอียดประกาศจากหน้า "ประกาศล่าสุด" หรือหน้ารายละเอียดประกาศ
ระบบยังแสดง
- หมายเหตุการตรวจสอบ (Review Note)
- ความคิดเห็นของผู้ตรวจสอบ
ซึ่งเป็นข้อมูลภายในของ Workflow การอนุมัติ
ข้อมูลดังกล่าวควรเห็นได้เฉพาะ
- HRD
- HRD Manager
- Admin
- ผู้มีสิทธิ์ตรวจสอบประกาศ
ไม่ควรแสดงแก่ผู้ใช้งานทั่วไป
ถือเป็นปัญหา Information Disclosure และ Permission Logic
---
# เป้าหมาย
แก้ไขให้ข้อมูล Workflow ภายในไม่สามารถถูกเข้าถึงหรือแสดงผลโดยผู้ใช้งานทั่วไปได้
ทั้งในระดับ
- Backend API
- Frontend
- Permission
- Component
- DTO / Response
ให้เป็นมาตรฐาน Production Ready
---
# สิ่งที่ต้องตรวจสอบ
## 1. ตรวจสอบ API รายละเอียดประกาศ
ค้นหา API ที่ใช้
ตัวอย่างเช่น
- GET /announcements/:id
- getAnnouncementById()
- announcement.service.ts
- announcement.repository.ts
ตรวจสอบ Response ว่าส่งข้อมูลดังนี้หรือไม่
- review_note
- review_comment
- reviewer
- reviewer_name
- reviewer_id
- approved_by
- approved_at
- rejected_reason
- workflow
- audit
- review_status
หากส่งให้ User ต้องแก้ไข
---
## 2. แยก Public Response กับ Admin Response
หากใช้ DTO เดียวกัน
เช่น
AnnouncementDetailDto
ให้แยกเป็น
AnnouncementPublicDto
ประกอบด้วย
- id
- title
- content
- attachment
- published_at
- expired_at
- created_by (ถ้าจำเป็น)
- published_by (ถ้าจำเป็น)
เท่านั้น
ส่วน
AnnouncementAdminDto
จึงค่อยมี
- review_note
- reviewer
- workflow
- audit
- rejected_reason
- review history
---
## 3. ตรวจสอบ Permission ของ API
ถ้า API เดียวใช้ทั้ง Admin และ User
ให้ตรวจสอบสิทธิ์
ตัวอย่าง
```
if (isAdmin) {
return fullAnnouncement
}
return publicAnnouncement
```
ห้ามส่งข้อมูล Review กลับไปยัง User แล้วค่อยซ่อนด้วย Frontend
ต้องตัดออกจาก Response ตั้งแต่ Backend
---
## 4. ตรวจสอบ Frontend
ค้นหา Component
AnnouncementDetail
AnnouncementView
AnnouncementContent
หรือ Component ที่ใช้แสดงรายละเอียดประกาศ
ตรวจสอบว่ามีโค้ดลักษณะนี้หรือไม่
```
{announcement.review_note && (
...
)}
```
หรือ
```
Review Note
```
หรือ
```
หมายเหตุการตรวจสอบ
```
หากไม่มีการตรวจสอบ Permission
ให้เพิ่ม
```
isAdmin
```
หรือ
```
hasPermission(...)
```
ก่อน Render
ตัวอย่าง
```
{isAdmin && announcement.review_note && (
<ReviewNote />
)}
```
---
## 5. ตรวจสอบ Component ที่ใช้ร่วมกัน
หาก Admin และ User ใช้ Component เดียวกัน
ให้พิจารณา
Option A
แยกเป็น
AnnouncementAdminDetail
AnnouncementPublicDetail
หรือ
Option B
ส่ง prop
```
showReviewSection
```
เช่น
```
<AnnouncementDetail
announcement={announcement}
showReviewSection={isAdmin}
/>
```
ภายใน
```
{showReviewSection && (
...
)}
```
---
## 6. ตรวจสอบทุกหน้าที่เกี่ยวข้อง
ตรวจสอบ
- Dashboard ล่าสุด
- Announcement Detail
- Announcement List
- Search Result
- Notification เปิดประกาศ
ว่ามีการแสดง
Review Note
หรือ
Workflow
โดยไม่ตรวจสอบสิทธิ์หรือไม่
---
## 7. ตรวจสอบ Serializer / Mapper
หากมี
```
mapAnnouncement()
```
หรือ
```
toDto()
```
ตรวจสอบว่าไม่ได้ Mapping
```
review_note
```
ไปยัง Public DTO
---
## 8. ตรวจสอบ Database Query
หากใช้ Prisma
ตัวอย่าง
```
select:
```
ให้เลือกเฉพาะ Field ที่จำเป็น
ไม่ใช้
```
include: true
```
หรือ
```
select *
```
โดยไม่จำเป็น
เพื่อลดการส่งข้อมูลที่ไม่ควรออกจาก Server
---
# สิ่งที่ต้องแก้ไข
Backend
- แยก Public DTO
- ตัดข้อมูล Review ออกจาก Public API
- ตรวจสอบ Permission ก่อน Response
- จำกัด Select เฉพาะ Field ที่จำเป็น
Frontend
- ซ่อน Section Review สำหรับ User
- Render ตาม Permission
- แยก Component หากเหมาะสม
Architecture
- แยกข้อมูล Public และ Internal
- ลดการส่งข้อมูลเกินความจำเป็น
- ปรับโครงสร้างให้รองรับการขยาย Workflow ในอนาคต
---
# Acceptance Criteria
✅ ผู้ใช้งานทั่วไปไม่เห็น
- หมายเหตุการตรวจสอบ
- ความคิดเห็นผู้อนุมัติ
- Reviewer
- Workflow
- Audit
- Reject Reason
- Approval History
✅ HRD/Admin ยังเห็นข้อมูลทั้งหมดได้ตามสิทธิ์
✅ Public API ไม่ส่งข้อมูล Review อีกต่อไป
✅ Frontend ไม่มีการ Render ข้อมูล Review สำหรับ User
✅ ไม่มี Regression กับหน้าประกาศอื่น
✅ ผ่าน TypeScript และ ESLint
✅ ไม่กระทบ Workflow เดิม
---
# ผลลัพธ์ที่ต้องการจาก AI
1. วิเคราะห์สาเหตุที่แท้จริงของปัญหา
2. ระบุไฟล์ที่ต้องแก้ไขทั้งหมด
3. แก้ไข Backend และ Frontend
4. ปรับ Permission Logic ให้ถูกต้อง
5. ปรับ DTO/Mapper/Serializer
6. ปรับ Component ที่เกี่ยวข้อง
7. ตรวจสอบทุกหน้าที่ใช้รายละเอียดประกาศ
8. สรุปรายการไฟล์ที่แก้ไข
9. อธิบายเหตุผลของการแก้ไขแต่ละจุด
10. ยืนยันว่าไม่มีข้อมูลภายในของ Workflow หลุดไปยังผู้ใช้งานทั่วไปอีก

View File

@@ -0,0 +1,315 @@
# Approval & Publishing Workflow Plan
## Summary
This plan covers the implementation of approval, publishing, scheduling, preview, versioning, audit logging, and notification support for:
- `announcements`
- `online-lessons`
The goal is to extend the current simple `draft/published/archived` model into a controlled workflow without breaking the project's existing Auth.js, Drizzle, route-handler, and TanStack Query patterns.
## Current Repo Reality
### Announcements
- Current status model: `draft | published | archived`
- Employee visibility is currently based on:
- `status = published`
- `start_date <= now`
- `end_date is null or end_date >= now`
- HRD and super admin can manage records through existing create/update/delete endpoints
- Publish and archive are currently direct status updates
- Notifications already exist for published announcements
- Audit logging already exists for create, update, publish, archive
### Online Lessons
- Current status model: `draft | published | archived`
- Employee visibility is currently based on `is_published = true`
- Publish is currently a direct status change plus `isPublished/publishedAt`
- Audit logging and notifications are not yet as complete as announcements
### Roles
- Current business roles in code:
- `IT`
- `HRD`
- `EMPLOYEE`
- Current elevated system role:
- `super_admin`
- There is no dedicated `HRD_MANAGER` role in the current schema or auth helper layer
### Scheduler
- No existing publish scheduler or cron pattern was found in the repo
- Scheduled publish must therefore be introduced deliberately and in a way that matches deployment constraints
## Key Gaps To Solve
1. Status enums are too limited for the requested workflow.
2. No first-class review metadata exists for announcements or online lessons.
3. No versioning structure exists for either module.
4. No `HRD Manager` capability exists in the current role model.
5. No scheduled publish executor exists.
6. Employee visibility rules differ between announcements and online lessons and need to be normalized around `Published + current version`.
## Proposed Design Decisions
### 1. Workflow status model
Use the same workflow vocabulary for both modules:
- `draft`
- `pending_approval`
- `approved`
- `scheduled`
- `published`
- `rejected`
- `archived`
### 2. Versioning model
For both `announcements` and `online_lessons`, add:
- `version`
- `parent_id`
- `is_current`
Behavior:
- Records not yet published can be edited in place
- Once a record has been published, editing must create a new draft revision
- Only one version per logical record can be `is_current = true`
- Employee-facing queries must only show:
- `status = published`
- `is_current = true`
### 3. Permission model
Use the current auth model as the base and extend it with app-owned permission checks instead of inventing client-only gates.
Recommended interpretation for implementation:
- `super_admin`
- full override for all workflow actions
- `HRD`
- current generic HRD behavior should be split by permission, not by a brand new auth system
Recommended incremental approach:
- keep existing `businessRole` values
- introduce fine-grained permission checks for content workflow actions
- model `HRD Manager` as a permission-capable HRD user, not as a breaking replacement of the current role model
Suggested permission flags:
- `content:submit`
- `content:approve`
- `content:publish`
- `content:archive`
- `content:schedule`
- `content:manage_all`
This avoids rewriting the entire auth model while still supporting the requested behavior.
### 4. Scheduled publish
Because no scheduler pattern currently exists, implement in two layers:
- data model and API support first
- a server-triggerable publish processor second
Recommended first implementation:
- add a reusable server function that publishes due scheduled records
- expose an internal route handler or job entrypoint for future cron integration
This keeps the business logic testable even before infrastructure automation is added.
## Database Changes
### Announcements
Extend `announcements` with:
- `version`
- `parent_id`
- `is_current`
- `submitted_by`
- `submitted_at`
- `approved_by`
- `approved_at`
- `rejected_by`
- `rejected_at`
- `rejected_reason`
- `scheduled_publish_at`
- `published_by`
- `published_at`
- `unpublished_by`
- `unpublished_at`
- `archived_by`
- `archived_at`
Replace enum values to support the workflow states.
### Online Lessons
Extend `online_lessons` with the same workflow and versioning fields.
Review whether `is_published` should be retained temporarily as a derived compatibility field during migration or removed after full workflow migration.
## Backend Work Plan
### Phase 1. Shared workflow foundation
- add new enums to `src/db/schema.ts`
- add migration for announcements and online lessons
- add shared permission helpers for content workflow
- extend audit action constants
- extend notification service helpers
### Phase 2. Announcement workflow backend
- update list/detail access rules
- update create/edit behavior
- add submit for approval action
- add approve/reject action
- add publish now action
- add schedule publish action
- add cancel schedule action
- add unpublish action
- add archive action
- add create revision action for published records
### Phase 3. Online lesson workflow backend
- apply the same workflow actions and rules
- align employee visibility with `published + is_current`
### Phase 4. Scheduled publish processor
- create reusable processor for due announcements
- create reusable processor for due online lessons
- add internal route or task entrypoint for future cron wiring
## Frontend Work Plan
### Announcements
- refactor form actions:
- `Save Draft`
- `Submit for Approval`
- `Preview`
- remove direct publish/archive controls from HRD staff flows
- add manager/admin action controls based on status
- add revision flow for published records
- add preview route/view
### Online Lessons
- refactor form actions to match announcement workflow
- replace direct publish/archive actions with workflow-aware actions
- add preview and revision behavior
### HRD Manager Dashboard
Introduce a dedicated manager workflow page that groups both modules by status:
- pending approval
- approved waiting publish
- scheduled
- published
- rejected
- archived
Recommended implementation path:
- start with one page under dashboard
- use tabs or segmented sections
- reuse existing table/list patterns instead of inventing a new shell
## API Surface To Add
Recommended route pattern:
- `POST /api/announcements/[id]/submit`
- `POST /api/announcements/[id]/approve`
- `POST /api/announcements/[id]/reject`
- `POST /api/announcements/[id]/publish`
- `POST /api/announcements/[id]/schedule`
- `POST /api/announcements/[id]/cancel-schedule`
- `POST /api/announcements/[id]/unpublish`
- `POST /api/announcements/[id]/archive`
- `POST /api/announcements/[id]/revision`
Mirror the same shape for `online-lessons`.
Keep these actions separate from generic `PATCH` to preserve explicit permission checks and status transitions.
## Audit And Notification Plan
### Audit
Extend audit coverage for both modules:
- submit
- approve
- reject
- publish
- schedule
- cancel schedule
- unpublish
- archive
- create revision
### Notifications
Reuse the existing notification service.
Add notification types/messages for:
- submitted for approval
- approved
- rejected
- scheduled
- published
- unpublished
- archived
## Risks
1. Role model ambiguity:
`HRD Manager` does not yet exist as a first-class role, so permission-based implementation is safer than role explosion.
2. Scheduler infrastructure:
automatic scheduled publish cannot be considered complete until deployment wiring is agreed.
3. Versioning migration:
existing published records must be backfilled carefully so they become `version = 1` and `is_current = true`.
4. UI complexity:
if both modules implement bespoke workflow UIs separately, the code may drift. Shared status/action utilities should be introduced where practical.
## Implementation Order
1. Add workflow plan document
2. Add schema changes and migration
3. Add shared workflow permission helpers
4. Upgrade announcement backend
5. Upgrade online lesson backend
6. Add preview and revision flows
7. Add manager dashboard
8. Add scheduled publish processor entrypoint
9. Add docs and implementation report
## Immediate Next Step
Start with schema and contract design for:
- workflow statuses
- versioning columns
- approval metadata
- publish metadata
Then implement announcement backend first as the reference module, followed by online lessons.

View File

@@ -0,0 +1,624 @@
# Prompt: Implement Approval & Publishing Workflow for Announcement and Online Lesson
## Objective
ปรับปรุงระบบหลังบ้านของ Training Management System (TMS) ให้รองรับ Approval & Publishing Workflow สำหรับโมดูล:
1. ประกาศ (Announcement)
2. บทเรียนออนไลน์ (Online Lesson)
โดยให้ HRD Staff / Admin สามารถสร้างและส่งอนุมัติได้ แต่ไม่สามารถเผยแพร่สู่สาธารณะได้เอง ยกเว้น Admin IT ซึ่งเป็น Super Admin และสามารถดำเนินการได้ทั้งหมด
---
## Scope
ให้ดำเนินการเฉพาะโมดูล:
- Announcement
- Online Lesson
ยังไม่ต้องขยายไปยังโมดูลอื่น
---
## Roles & Permissions
### Admin IT / Super Admin
มีสิทธิ์ทำได้ทั้งหมด ได้แก่:
- Create
- Edit
- Delete
- Submit for Approval
- Approve
- Reject
- Publish
- Schedule Publish
- Unpublish
- Archive
- Preview
- Manage all records
### HRD Staff
มีสิทธิ์:
- Create
- Edit Draft
- Delete Draft
- Submit for Approval
- Preview Draft
ไม่มีสิทธิ์:
- Approve
- Reject
- Publish
- Schedule Publish
- Unpublish
- Archive
### HRD Manager
มีสิทธิ์:
- View Pending Approval
- Approve
- Reject
- Publish
- Schedule Publish
- Unpublish
- Archive
- Preview before Publish
- View HRD Manager Dashboard
### Employee
มีสิทธิ์:
- เห็นเฉพาะรายการที่มีสถานะ Published เท่านั้น
- ไม่สามารถเห็น Draft, Pending Approval, Approved, Scheduled, Rejected หรือ Archived
---
## Required Status
ให้รองรับสถานะดังนี้:
```text
Draft
Pending Approval
Approved
Scheduled
Published
Rejected
Archived
```
---
## Workflow
### Create Flow
```text
Create
Draft
Submit for Approval
Pending Approval
Approve
Approved
Publish Now / Schedule Publish
Published
```
---
### Reject Flow
```text
Pending Approval
Reject
Draft
```
เมื่อ Reject:
- ต้องบันทึกเหตุผลการ Reject
- รายการกลับเป็น Draft
- ผู้สร้างสามารถแก้ไขได้
- ผู้สร้างสามารถลบได้
- สามารถ Submit for Approval ใหม่ได้
---
### Schedule Publish Flow
```text
Approved
Schedule Publish
Scheduled
ถึงเวลาที่กำหนด
Published
```
ต้องรองรับ:
- ตั้งวันเวลาเผยแพร่
- แก้ไขวันเวลาเผยแพร่
- ยกเลิก Schedule
- Publish ทันที แม้เคยตั้ง Schedule ไว้แล้ว
---
## Versioning Requirement
ต้องเพิ่ม Versioning สำหรับ Announcement และ Online Lesson
### กรณีรายการยังไม่ Published
- สามารถแก้ไข Draft ได้ตามปกติ
### กรณีรายการ Published แล้ว
ห้ามแก้ไข Published Record โดยตรง
เมื่อมีการแก้ไขรายการที่ Published แล้ว ให้สร้าง Draft Revision ใหม่ เช่น:
```text
Published V1
Create Draft Revision
Draft V2
Submit for Approval
Pending Approval
Approved
Published V2
```
ข้อกำหนด:
- ต้องเก็บ version number
- ต้องระบุ parent/original record
- ต้องรู้ได้ว่า version ไหนเป็น current published version
- เมื่อ Publish version ใหม่ ให้ version เดิมไม่แสดงเป็น current แล้ว
- ต้องมีประวัติ version ให้ตรวจสอบย้อนหลังได้
---
## Preview Before Publish
ต้องเพิ่ม Preview ก่อน Publish
### HRD Staff
- Preview ได้เฉพาะ Draft / Revision ของตนเองหรือรายการที่มีสิทธิ์
### HRD Manager
- Preview รายการ Pending Approval, Approved, Scheduled ได้
- Preview ต้องแสดงหน้าตาใกล้เคียงกับที่ Employee จะเห็นจริง
### Admin IT
- Preview ได้ทุกสถานะและทุกรายการ
Preview ต้องไม่ทำให้สถานะเปลี่ยน
---
## HRD Manager Dashboard
เพิ่มหรือปรับหน้า Dashboard สำหรับ HRD Manager เพื่อดูรายการที่ต้องดำเนินการ
ควรมี Section หรือ Tab อย่างน้อย:
- Pending Approval
- Approved รอ Publish
- Scheduled
- Published
- Rejected
- Archived
ควรแสดงข้อมูลสำคัญ:
- ชื่อรายการ
- ประเภท: Announcement / Online Lesson
- ผู้สร้าง
- วันที่สร้าง
- วันที่ส่งอนุมัติ
- สถานะ
- วันที่ตั้งเผยแพร่ ถ้ามี
- ปุ่ม Action ตามสิทธิ์
---
## Frontend Requirement
### HRD Staff / Admin User
ในหน้า Create/Edit ต้องมีปุ่ม:
- Save Draft
- Submit for Approval
- Preview
ห้ามแสดงปุ่ม:
- Approve
- Reject
- Publish
- Schedule Publish
- Unpublish
- Archive
ยกเว้นผู้ใช้เป็น Admin IT
---
### HRD Manager
ต้องมีปุ่มตามสถานะ:
#### Pending Approval
- Preview
- Approve
- Reject
#### Approved
- Preview
- Publish Now
- Schedule Publish
#### Scheduled
- Preview
- Edit Schedule
- Cancel Schedule
- Publish Now
#### Published
- Preview
- Unpublish
- Archive
---
### Admin IT
ต้องเห็นและใช้งานปุ่มทั้งหมดได้ทุกสถานะตามความเหมาะสม
---
## Backend Requirement
ห้ามตรวจสอบสิทธิ์เฉพาะหน้า UI
ต้องตรวจสอบ Role/Permission ที่ API ทุกครั้ง
API สำคัญที่ต้องป้องกัน:
- Submit for Approval
- Approve
- Reject
- Publish
- Schedule Publish
- Cancel Schedule
- Unpublish
- Archive
- Delete
- Create Revision
หากไม่มีสิทธิ์ ให้ return:
```text
403 Forbidden
```
---
## Database Requirement
ตรวจสอบ schema เดิมก่อนเสมอ ห้ามเดาโครงสร้าง
ถ้ายังไม่มี field ที่จำเป็น ให้เพิ่มโดยออกแบบให้สอดคล้องกับ project pattern เดิม
ควรมี field ประมาณนี้:
```text
status
version
parent_id
is_current
submitted_by
submitted_at
approved_by
approved_at
rejected_by
rejected_at
rejected_reason
scheduled_publish_at
published_by
published_at
unpublished_by
unpublished_at
archived_by
archived_at
created_by
updated_by
created_at
updated_at
```
ถ้ามี Audit Log เดิม ให้ใช้ของเดิม
ถ้าไม่มี ให้เพิ่มตาม pattern ของโปรเจกต์
---
## Audit Log Requirement
ต้องบันทึกทุก action สำคัญ:
- Create
- Update
- Delete
- Submit for Approval
- Approve
- Reject
- Create Revision
- Schedule Publish
- Cancel Schedule
- Publish
- Unpublish
- Archive
Audit Log ควรเก็บ:
- module
- record_id
- action
- old_value
- new_value
- actor_id
- actor_role
- created_at
- note / reason
---
## Notification Requirement
ถ้ามีระบบ notification เดิม ให้ reuse ของเดิม
ต้องแจ้งเตือนอย่างน้อยในเหตุการณ์:
- HRD Staff ส่งอนุมัติ → แจ้ง HRD Manager
- HRD Manager Approve → แจ้งผู้สร้าง
- HRD Manager Reject → แจ้งผู้สร้าง พร้อมเหตุผล
- ตั้งเวลาเผยแพร่ → แจ้งผู้เกี่ยวข้อง
- Publish สำเร็จ → แจ้งผู้เกี่ยวข้อง
- Unpublish / Archive → แจ้งผู้เกี่ยวข้อง
---
## Scheduled Publish Job
ต้องตรวจสอบว่าระบบมี cron/job/scheduler อยู่แล้วหรือไม่
ถ้ามี ให้ใช้ pattern เดิม
ถ้าไม่มี ให้เสนอแนวทางที่เหมาะสมก่อนลงมือแก้
Scheduled Job ต้องทำงานประมาณนี้:
```text
ค้นหารายการ status = Scheduled
และ scheduled_publish_at <= current time
จากนั้นเปลี่ยนสถานะเป็น Published
บันทึก published_at
บันทึก Audit Log
```
ต้องระวัง timezone และใช้แนวทางเดียวกับ project เดิม
---
## Employee Visibility Rule
ทุกหน้า Employee ต้อง query เฉพาะ:
```text
status = Published
is_current = true
```
ห้ามแสดง:
- Draft
- Pending Approval
- Approved
- Scheduled
- Rejected
- Archived
- version เก่า
---
## Validation
ใช้ validation เดิมของ Create/Edit ให้มากที่สุด
ก่อน Submit for Approval ต้อง validate ข้อมูลเหมือนกับการเตรียมเผยแพร่จริง
หากข้อมูลไม่ครบ:
- ไม่เปลี่ยนสถานะ
- แสดง error ให้ครบทุกจุด
- ยังคงเป็น Draft
---
## Required Implementation Steps
1. ตรวจสอบโครงสร้างโปรเจกต์เดิมก่อนแก้ไข
2. ตรวจสอบ Announcement module
3. ตรวจสอบ Online Lesson module
4. ตรวจสอบ Role/Permission เดิม
5. ตรวจสอบ API routes / server actions / services เดิม
6. ตรวจสอบ Database schema เดิม
7. สร้าง `plan.md` ก่อนเริ่มแก้ไข
8. Implement database migration
9. Implement backend permission checks
10. Implement workflow actions
11. Implement versioning
12. Implement preview page/modal
13. Implement HRD Manager dashboard
14. Implement scheduled publish
15. Update employee visibility query
16. Add audit log
17. Add notification
18. Test role-based behavior
19. Test regression ทั้ง Announcement และ Online Lesson
20. สร้างเอกสารสรุปหลังทำงานเสร็จ
---
## Required Documents
หลังดำเนินการเสร็จ ต้องสร้างเอกสารไว้ในโฟลเดอร์ `docs`
ชื่อไฟล์แนะนำ:
```text
docs/approval-publishing-workflow.md
```
เนื้อหาในเอกสารต้องมี:
- Summary
- Objective
- Scope
- Role & Permission Matrix
- Workflow Diagram
- Status Transition
- Versioning Design
- Preview Before Publish
- HRD Manager Dashboard
- Database Changes
- API Changes
- Security / Permission Checks
- Audit Log
- Notification
- Testing Summary
- Files Changed
- Known Issues / Follow-up Items
---
## Testing Checklist
ต้องทดสอบอย่างน้อย:
### HRD Staff
- สร้าง Draft ได้
- แก้ไข Draft ได้
- ลบ Draft ได้
- Submit ได้
- Publish ไม่ได้
- Approve ไม่ได้
- Schedule Publish ไม่ได้
### HRD Manager
- เห็นรายการ Pending Approval
- Preview ได้
- Approve ได้
- Reject ได้
- Publish ได้
- Schedule Publish ได้
- Unpublish ได้
- Archive ได้
### Admin IT
- ทำได้ทุก action
- เห็นทุกสถานะ
- Override Publish ได้
### Employee
- เห็นเฉพาะ Published
- ไม่เห็น Draft / Pending / Approved / Scheduled / Rejected / Archived
- ไม่เห็น version เก่า
### Versioning
- Published แล้วแก้ไขต้องสร้าง Draft Revision
- Publish version ใหม่แล้ว version เดิมไม่เป็น current
- Employee เห็นเฉพาะ current published version
### Schedule Publish
- ตั้งเวลาเผยแพร่ได้
- ถึงเวลาแล้วเปลี่ยนเป็น Published
- ยกเลิก Schedule ได้
- Publish ทันทีได้
---
## Important Rules
- ห้ามสร้างระบบใหม่ซ้ำ หากมี pattern เดิมอยู่แล้ว
- ต้อง reuse component, service, hook, validation, permission helper เดิมให้มากที่สุด
- ห้ามแก้เฉพาะ UI โดยไม่ป้องกัน backend
- ห้ามให้ HRD Staff publish ได้
- Admin IT ต้องเป็น Super Admin
- Employee ต้องเห็นเฉพาะ Published current version เท่านั้น
- ต้องสร้างเอกสารสรุปไว้ใน `docs`
- ต้องสร้าง `plan.md` ก่อนลงมือแก้ไข
- ต้องสร้าง report หลังแก้ไขเสร็จ
---
## Final Deliverables
เมื่อทำเสร็จ ต้องมี:
1. Code changes สำหรับ Approval & Publishing Workflow
2. Database migration หรือ schema update
3. Updated frontend pages/components
4. Updated backend API/server actions
5. Role-based permission enforcement
6. Versioning support
7. Preview before Publish
8. HRD Manager Dashboard
9. Scheduled Publish support
10. Audit Log
11. Notification integration
12. `plan.md`
13. `docs/approval-publishing-workflow.md`
14. Final implementation report

1108
plans/approval-workflow.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,522 @@
# Employee Dashboard Audit (Read Only)
## Role
You are a Senior Full Stack Engineer, Software Architect, QA Engineer, UX/UI Reviewer, Security Reviewer, and Product Analyst.
Your responsibility is to perform a comprehensive READ-ONLY audit of the Employee Dashboard.
Do NOT modify any source code.
Do NOT generate implementation code.
Do NOT create pull requests.
Only inspect the project and produce documentation.
---
# Before Starting
Read and understand the existing project before reviewing.
Review these documents first (follow project priority):
1. AGENTS.md
2. docs/AI_DEVELOPMENT_GUIDE.md
3. docs/PROJECT_ARCHITECTURE.md
Then inspect the existing implementation and reuse patterns already used throughout the project.
---
# Scope
Review everything related to the Employee Dashboard.
Including but not limited to:
- Route
- Page
- Layout
- Dashboard Components
- Cards
- Summary Statistics
- Progress Display
- Training Hours Summary
- K / S / A Summary
- Recent Activities
- Notifications
- Charts (if any)
- Tables
- API
- Queries
- Mutations
- Validation
- Server Components
- Client Components
- Loading UI
- Error UI
- Empty State
- Responsive Design
---
# Functional Review
Verify every feature.
Examples
## Dashboard Summary
- Total Training Hours
- Required Hours
- Remaining Hours
- Completed Hours
- K Hours
- S Hours
- A Hours
Verify
- Is the calculation correct?
- Is the displayed data correct?
- Does it match business rules?
- Are edge cases handled?
---
## Training Progress
Review
- Progress bar
- Percentage
- Completion status
- Color indication
- Overflow
- Zero values
Verify
- 0 hours
- Partial completion
- Completed
- Exceeded target
---
## Recent Training
Verify
- Correct sorting
- Correct date
- Status badge
- Empty state
- Pagination (if applicable)
---
## Notifications
Review
- Pending approval
- Approved
- Rejected
- Expired training
- Missing mandatory training
---
## Dashboard Refresh
Verify
- Refresh after submission
- Refresh after approval
- Cache invalidation
- React Query behavior
---
# Business Rule Review
Verify the dashboard follows project requirements.
Examples
- Employee only sees their own data.
- Hours are calculated correctly.
- K / S / A totals are correct.
- Required hours come from current policy.
- Calendar year is used correctly.
- Previous years are separated correctly.
- Completed percentage is accurate.
Document any inconsistencies.
---
# Role Review
Review every permission.
Employee
Verify the employee can
- View own dashboard
- View own statistics
- View own training history
- View notifications
Verify the employee cannot
- View other employees
- Edit policy
- Approve training
- Modify categories
- Access admin pages
Check
- UI permission
- API permission
- Route protection
- Hidden navigation
- Direct URL access
Report every permission issue.
---
# UI Review
Review
- Layout consistency
- Alignment
- Card spacing
- Typography
- Colors
- Icons
- Progress bars
- Status badges
- Responsive behavior
- Mobile layout
- Tablet layout
- Desktop layout
Identify inconsistent UI.
---
# UX Review
Evaluate
- Information hierarchy
- Dashboard readability
- User flow
- Navigation
- Feedback after actions
- Empty state clarity
- Error messages
- Loading indicators
Suggest improvements without implementing them.
---
# Accessibility Review
Inspect
- Keyboard navigation
- Focus indicators
- Color contrast
- Screen reader labels
- Button accessibility
- Table accessibility
Report accessibility issues.
---
# Code Review
Inspect
## Architecture
- Folder structure
- Feature separation
- Component organization
## React
- Hooks usage
- State management
- Memoization
- Client vs Server Components
## TypeScript
- Strong typing
- Reusable interfaces
- Nullable handling
## Code Quality
- Duplicate logic
- Dead code
- Naming consistency
- File organization
Do NOT change anything.
---
# API Review
Review
- Query structure
- Response types
- Error handling
- Retry behavior
- Cache
- Query invalidation
---
# Performance Review
Inspect
- Unnecessary rendering
- Query optimization
- Large component rendering
- Loading strategy
- Lazy loading
- Suspense usage
- Memoization
- Bundle size concerns
---
# Security Review
Review
- Authentication
- Authorization
- Route Guard
- Role Guard
- Server validation
- API validation
- Sensitive information exposure
---
# Data Validation Review
Inspect
- Missing values
- Incorrect defaults
- Null handling
- Incorrect formatting
- Date formatting
- Hour calculations
---
# Consistency Review
Compare the dashboard with the rest of the project.
Verify
- Shared components
- Shared cards
- Shared table
- Shared loading UI
- Shared badges
- Shared dialogs
- Shared spacing
- Shared typography
Document inconsistencies.
---
# Edge Case Review
Check
- New employee
- No training records
- All completed
- Over target
- Missing category
- Missing policy
- Missing profile
- API failure
- Slow network
---
# Deliverables
Create
docs/review/employee-dashboard-audit.md
---
# Report Structure
# Employee Dashboard Audit Report
## Executive Summary
Overall Status
- Excellent
- Good
- Needs Improvement
- Critical
Brief summary of findings.
---
## Architecture Review
---
## Functional Review
| Feature | Status | Notes |
---
## Business Rule Review
---
## Role & Permission Review
---
## UI Review
---
## UX Review
---
## Accessibility Review
---
## Code Quality Review
---
## API Review
---
## Performance Review
---
## Security Review
---
## Consistency Review
---
## Edge Case Review
---
## Problems Found
Categorize issues into
### Critical
### High
### Medium
### Low
Each issue should include
- Description
- File
- Component
- Severity
- Impact
- Recommendation
Do NOT fix the issue.
---
## Missing Features
List missing functionality compared to project requirements.
---
## Improvement Opportunities
Suggest improvements only.
Do NOT implement them.
---
## Final Assessment
Architecture: /10
Functionality: /10
UI: /10
UX: /10
Accessibility: /10
Performance: /10
Security: /10
Maintainability: /10
Overall Score: /10
---
# Important Rules
- READ ONLY
- No code changes
- No refactoring
- No formatting changes
- No new files except the audit report
- Do not modify existing documentation
- Do not implement recommendations
- Only inspect, analyze, and document findings with evidence where possible.

View File

@@ -0,0 +1,630 @@
# Employee Online Lessons Audit (Read Only)
## Role
You are a Senior Full Stack Engineer, Software Architect, QA Engineer, UX/UI Reviewer, Security Reviewer, Performance Engineer, and Product Analyst.
Your task is to perform a comprehensive READ-ONLY audit of the Employee Online Lessons module.
This is an inspection and documentation task only.
Do NOT modify any source code.
Do NOT refactor.
Do NOT generate implementation code.
Do NOT format files.
Do NOT create pull requests.
Do NOT fix any issue.
Only inspect the project and generate an audit report.
---
# Before Starting
Review and understand the project first.
Read in this priority:
1. AGENTS.md
2. docs/AI_DEVELOPMENT_GUIDE.md
3. docs/PROJECT_ARCHITECTURE.md
Then inspect the existing implementation and identify reusable patterns already used in the project.
---
# Scope
Review every file related to the Employee Online Lessons module.
Including:
- Route
- Layout
- Page
- Lesson List
- Lesson Detail
- Lesson Card
- Video Player
- YouTube Embed
- Uploaded Video
- Thumbnail
- Attachments
- Certificate Section
- Related Files
- Search
- Filters
- Pagination
- Categories
- Progress Display
- Completed Status
- Empty State
- Loading State
- Error State
- Navigation
- API
- Queries
- Mutations
- Validation
- Types
- Services
- Role Guards
---
# Functional Review
Verify all user functionality.
## Lesson List
Review:
- Lesson list loads correctly
- Pagination
- Search
- Category filter
- Sorting
- Responsive cards
- Empty state
- Loading state
---
## Lesson Detail
Verify:
- Lesson title
- Description
- Instructor
- Category
- Duration
- Upload date
- Attachments
- Certificate availability
---
## Video
Review every supported video type.
Verify:
Uploaded Video
- MP4
- WebM
- MOV if supported
YouTube
- Standard URL
- Short URL
- Embed URL
Verify:
- Video loads
- Controls work
- Fullscreen
- Responsive
- Error handling
- Fallback UI
- Black screen handling
- Missing video handling
---
## Attachments
Review:
- Image preview
- PDF preview
- Download
- Missing file message
- Unsupported file handling
---
## Progress
Verify:
- Progress display
- Completed lessons
- Remaining lessons
- Completion badge
- Progress calculation
---
## Learning History
Verify:
- Viewed lessons
- Completed lessons
- Recent lessons
---
## Dashboard Integration
Verify:
- Dashboard reflects completed lessons correctly
- Training hours update correctly if applicable
---
# Business Rule Review
Verify project requirements.
Examples:
- Employee only accesses available lessons
- Hidden lessons cannot be accessed directly
- Draft lessons are not visible
- Archived lessons are hidden
- Training hours follow project rules
- Completion status updates correctly
- Certificates appear only when allowed
Document inconsistencies.
---
# Role Review
Review Employee permissions.
Employee can:
- View lesson list
- View lesson detail
- Watch videos
- Download allowed files
- View attachments
- Search lessons
- Filter lessons
Employee cannot:
- Create lessons
- Edit lessons
- Delete lessons
- Publish lessons
- Access HRD pages
- Access Admin pages
- View hidden lessons
- Access draft lessons
- Access restricted API endpoints
Verify:
- UI permissions
- API permissions
- Route guards
- Direct URL access
---
# UI Review
Inspect:
- Overall layout
- Card consistency
- Thumbnail ratio
- Video container
- Typography
- Colors
- Icons
- Buttons
- Attachments section
- Empty state
- Loading skeleton
- Status badges
- Progress indicators
- Responsive layout
Review Desktop
Review Tablet
Review Mobile
---
# UX Review
Evaluate:
- Lesson discovery
- Navigation flow
- Search usability
- Filter usability
- Video watching experience
- Attachment accessibility
- Error clarity
- Loading feedback
- Empty state guidance
Suggest improvements only.
Do NOT implement.
---
# Accessibility Review
Review:
- Keyboard navigation
- Video controls accessibility
- Focus indicators
- Screen reader labels
- Button labels
- Alt text
- Color contrast
- Dialog accessibility
- Download accessibility
---
# Code Review
Inspect.
## Architecture
- Folder structure
- Feature separation
- Component reuse
- Shared layout
- Shared cards
- Shared video components
---
## React
Review:
- Client Components
- Server Components
- Hooks
- Memoization
- Suspense
- Unnecessary rerenders
---
## TypeScript
Inspect:
- Strong typing
- Nullable handling
- API response typing
- Validation typing
- Enums
---
## Code Quality
Review:
- Duplicate code
- Dead code
- Large components
- Import consistency
- Naming consistency
- Unused files
- Shared utilities
Do NOT modify anything.
---
# API Review
Inspect:
- Lesson query
- Lesson detail query
- Video endpoint
- Attachment endpoint
- Error handling
- Authorization
- Pagination
- Search parameters
- Filter parameters
- Cache
- Query invalidation
---
# Security Review
Inspect:
- Authentication
- Authorization
- Route guards
- API guards
- Direct lesson access
- Hidden lesson protection
- Draft lesson protection
- File download authorization
- Video authorization
- Sensitive data exposure
---
# Performance Review
Inspect:
- Lazy loading
- Video loading
- Image optimization
- Thumbnail loading
- Pagination
- React Query cache
- Suspense
- Bundle size
- Large video handling
---
# Data Validation Review
Review:
- Missing lesson title
- Missing thumbnail
- Missing description
- Missing video
- Invalid YouTube URL
- Invalid uploaded video
- Missing attachments
- Invalid duration
- Null values
- Incorrect defaults
---
# Edge Case Review
Verify:
- No lessons
- Only one lesson
- Many lessons
- Missing thumbnail
- Missing video
- Broken YouTube link
- Broken uploaded video
- Missing attachment
- Invalid PDF
- Slow network
- API failure
- Unauthorized access
- Hidden lesson via direct URL
- Archived lesson via direct URL
---
# Consistency Review
Compare against the rest of the Training System.
Verify consistency of:
- Cards
- Buttons
- Typography
- Colors
- Badges
- Loading UI
- Empty UI
- Error UI
- Tables
- Navigation
- Dialogs
- Sheets
---
# Deliverable
Create only one report.
docs/review/employee-online-lessons-audit.md
Do not modify any source code.
Do not modify existing documentation.
---
# Report Structure
# Employee Online Lessons Audit Report
## Executive Summary
Overall Status
- Excellent
- Good
- Needs Improvement
- Critical
Summary of findings.
---
## Scope Reviewed
List reviewed routes, components, APIs, services, and permissions.
---
## Functional Review
| Feature | Status | Notes |
---
## Business Rule Review
---
## Role & Permission Review
---
## UI Review
---
## UX Review
---
## Accessibility Review
---
## Code Quality Review
---
## API Review
---
## Security Review
---
## Performance Review
---
## Data Validation Review
---
## Edge Case Review
---
## Consistency Review
---
## Problems Found
Group by severity.
### Critical
### High
### Medium
### Low
For every issue include:
- Description
- File
- Component
- Severity
- Impact
- Recommendation
Do NOT fix the issue.
---
## Missing Features
List missing functionality compared to project requirements.
---
## Improvement Opportunities
Provide recommendations only.
Do NOT implement.
---
## Final Assessment
Architecture: /10
Functionality: /10
Role & Permission: /10
UI: /10
UX: /10
Accessibility: /10
Performance: /10
Security: /10
Maintainability: /10
Overall Score: /10
---
# Important Rules
- READ ONLY
- No source code modifications
- No implementation
- No refactoring
- No formatting
- No automatic fixes
- No pull requests
- Only generate:
docs/review/employee-online-lessons-audit.md
- Every finding must include file path, affected component, evidence where possible, severity, impact, and recommendation.

View File

@@ -0,0 +1,493 @@
# Employee Training History Audit (Read Only)
## Role
You are a Senior Full Stack Engineer, Software Architect, QA Engineer, UX/UI Reviewer, Security Reviewer, and Product Analyst.
Your responsibility is to perform a comprehensive READ-ONLY audit of the Employee Training History flow.
Do NOT modify any source code.
Do NOT generate implementation code.
Do NOT create pull requests.
Only inspect the project and produce documentation.
---
# Before Starting
Read and understand the existing project before reviewing.
Review these documents first (follow project priority):
1. AGENTS.md
2. docs/AI_DEVELOPMENT_GUIDE.md
3. docs/PROJECT_ARCHITECTURE.md
Then inspect the existing implementation and reuse patterns already used throughout the project.
---
# Scope
Review everything related to Employee Training History.
Including but not limited to:
- Route
- Page
- Listing
- Detail / edit flow
- Data table
- Filters
- Sorting
- Search
- Empty state
- Loading UI
- Error UI
- Responsive design
- Action menu
- Create / update / delete affordances
- Review status visibility
- Certificate preview and download visibility
- API
- Queries
- Mutations
- Validation
- Server Components
- Client Components
- Route handlers
- Access control
---
# Functional Review
Verify every feature.
Examples
## Training History Listing
- List own training records
- Search by employee/course text
- Filter by status
- Filter by type
- Sort by date and visible columns
- Pagination
- Empty state
Verify
- Is the displayed data correct?
- Does sorting reflect the visible field?
- Does status/type filtering work correctly?
- Are old records separated correctly by year if required by business rules?
---
## Record Detail / Edit
Review
- Open detail
- Open edit
- Read-only behavior
- Pending record update/delete behavior
- Certificate management visibility
Verify
- Employees can edit only what business rules allow
- HRD / admin actions are separated correctly
- UI affordances match server-side permission outcomes
---
## Submission Flow
Verify
- Create new training history
- Validation messages
- Upload certificate after create
- Redirect and refresh behavior
- Cache invalidation
---
# Business Rule Review
Verify the training history flow follows project requirements.
Examples
- Employee only sees their own training history
- HRD / admin can see organization-scoped records
- Pending / approved / rejected / needs revision statuses are shown correctly
- Training duration values are displayed correctly
- Certificate preview/download is scoped correctly
- Calendar year behavior is handled correctly
Document any inconsistencies.
---
# Role Review
Review every permission.
Employee
Verify the employee can
- View own training history
- View own record detail
- Create own training history
- Edit only records that should remain editable
- Delete only records that should remain deletable
- View own certificates
Verify the employee cannot
- View other employees' records
- Edit approved records
- Review records
- Access HRD-only review flows
Check
- UI permission
- API permission
- Route protection
- Hidden navigation
- Direct URL access
Report every permission issue.
---
# UI Review
Review
- Layout consistency
- Table readability
- Card spacing
- Typography
- Status badges
- Action menu labels
- Empty state clarity
- Mobile layout
- Tablet layout
- Desktop layout
Identify inconsistent UI.
---
# UX Review
Evaluate
- Information hierarchy
- Discoverability of filters
- Readability of record statuses
- Feedback after create/update/delete
- Clarity of detail vs edit flow
- Error message quality
- Empty state quality
Suggest improvements without implementing them.
---
# Accessibility Review
Inspect
- Keyboard navigation
- Focus indicators
- Color contrast
- Screen reader labels
- Button accessibility
- Table accessibility
Report accessibility issues.
---
# Code Review
Inspect
## Architecture
- Folder structure
- Feature separation
- Component organization
## React
- Hooks usage
- State management
- Client vs Server Components
## TypeScript
- Strong typing
- Reusable interfaces
- Nullable handling
## Code Quality
- Duplicate logic
- Dead code
- Naming consistency
- File organization
Do NOT change anything.
---
# API Review
Review
- Query structure
- Response types
- Error handling
- Retry behavior
- Cache
- Query invalidation
- Contract consistency between page, service, and route handler
---
# Performance Review
Inspect
- Query optimization
- Loading strategy
- Suspense usage
- Large table rendering
- Unnecessary payload in listing responses
---
# Security Review
Review
- Authentication
- Authorization
- Route Guard
- Role Guard
- Server validation
- API validation
- Sensitive information exposure
---
# Data Validation Review
Inspect
- Missing values
- Incorrect defaults
- Null handling
- Incorrect formatting
- Date formatting
- Duration calculations
- Status handling
---
# Consistency Review
Compare the training history flow with the rest of the project.
Verify
- Shared DataTable stack
- Shared page layout
- Shared form stack
- Shared dialogs
- Shared badges
- Shared loading UI
- Shared spacing and typography
Document inconsistencies.
---
# Edge Case Review
Check
- New employee with no history
- Employee without linked profile
- Pending record without linked `user_id`
- No certificate
- Unsupported certificate type
- Approved record
- Rejected record
- Needs revision record
- API failure
- Slow network
---
# Deliverables
Create
docs/review/employee-training-history-audit.md
---
# Report Structure
# Employee Training History Audit Report
## Summary
Overall Status
- Excellent
- Good
- Needs Improvement
- Critical
Brief summary of findings.
---
## Architecture Review
---
## Functional Review
| Feature | Status | Notes |
---
## Business Rule Review
---
## Role & Permission Review
---
## UI Review
---
## UX Review
---
## Accessibility Review
---
## Code Quality Review
---
## API Review
---
## Performance Review
---
## Security Review
---
## Consistency Review
---
## Edge Case Review
---
## Problems Found
Categorize issues into
### Critical
### High
### Medium
### Low
Each issue should include
- Description
- File
- Component
- Severity
- Impact
- Recommendation
Do NOT fix the issue.
---
## Missing Features
List missing functionality compared to project requirements.
---
## Improvement Opportunities
Suggest improvements only.
Do NOT implement them.
---
## Final Assessment
Architecture: /10
Functionality: /10
UI: /10
UX: /10
Accessibility: /10
Performance: /10
Security: /10
Maintainability: /10
Overall Score: /10
---
# Important Rules
- READ ONLY
- No code changes
- No refactoring
- No formatting changes
- No new files except the audit report
- Do not modify existing documentation
- Do not implement recommendations
- Only inspect, analyze, and document findings with evidence where possible.

View File

@@ -0,0 +1,345 @@
# Role
You are a Senior Full Stack Engineer, UX Reviewer, QA Engineer, and Code Auditor.
Your task is to perform a READ-ONLY audit of the "รอตรวจสอบ (Pending Review)" page.
DO NOT modify any source code.
DO NOT generate code.
DO NOT create pull requests.
Only inspect the implementation and produce documentation.
---
## Before Starting
Read and understand the following documents first.
- AGENTS.md
- docs/AI_DEVELOPMENT_GUIDE.md
- docs/PROJECT_ARCHITECTURE.md
Then inspect the existing implementation.
---
## Scope
Review every part related to the Pending Review page including:
- Route
- Layout
- Page
- Components
- Table
- Toolbar
- Filter
- Search
- Pagination
- Dialog
- Sheet
- API
- Server Actions
- Services
- Prisma
- Validation
- Types
- Permissions
- Role Guards
- Navigation
- Loading UI
- Error UI
- Empty State
---
## Functional Review
Verify whether the page supports:
- Display pending records
- Pagination
- Search
- Sorting
- Filtering
- Responsive layout
- Loading state
- Empty state
- Error state
- Refresh after action
- Correct badge/status
- Correct action buttons
- Correct permissions
Document any missing functionality.
---
## UI / UX Review
Inspect
- spacing
- typography
- button consistency
- icon consistency
- table layout
- mobile responsiveness
- accessibility
- keyboard navigation
- focus state
- color consistency
List all UI inconsistencies.
---
## Code Quality Review
Inspect
- folder structure
- duplicated code
- reusable components
- React patterns
- TanStack Query usage
- TanStack Table usage
- Server Component vs Client Component
- unnecessary rerenders
- TypeScript typing
- validation
- naming conventions
- imports
- dead code
- unused files
Do not change anything.
---
## Security Review
Inspect
- role validation
- authentication
- authorization
- server-side validation
- API protection
- hidden actions
- direct URL access
- input validation
---
## Performance Review
Inspect
- unnecessary rendering
- query invalidation
- cache usage
- pagination strategy
- N+1 queries
- loading optimization
- memoization
- lazy loading
---
## Permission Review
Verify every role.
Example
Employee
## Can View:
## Can Edit:
## Can Delete:
HRD
Can ...
Admin IT
Can ...
Document any incorrect permissions.
---
## Data Validation
Check
- nullable fields
- required fields
- incorrect defaults
- inconsistent status
- incorrect enum usage
---
## API Review
Inspect
- query
- mutation
- error handling
- response type
- loading
- retry
- cache invalidation
---
## Report
Create
docs/review/pending-review-audit.md
The report must contain
# Pending Review Audit Report
## Summary
Overall Status
- Excellent
- Good
- Needs Improvement
- Critical
---
## Architecture Review
...
---
## UI Review
...
---
## UX Review
...
---
## Permission Review
...
---
## Functional Review
Checklist
| Feature | Status | Notes |
| ------- | ------ | ----- |
---
## Code Quality Review
...
---
## Security Review
...
---
## Performance Review
...
---
## Problems Found
Priority
Critical
High
Medium
Low
For each issue include
- Description
- File
- Component
- Reason
- Impact
---
## Recommendations
Only provide recommendations.
Do NOT implement them.
---
## Missing Features
List missing features.
---
## Final Score
Architecture:
/10
UI:
/10
UX:
/10
Performance:
/10
Security:
/10
Maintainability:
/10
Overall:
/10
---
IMPORTANT
- Read Only
- No source code modifications
- No automatic fixes
- No refactoring
- No formatting changes
- Produce documentation only

64
plans/audit.md Normal file
View File

@@ -0,0 +1,64 @@
# Audit Result: AI Development Constitution
Source plan: `plans/rule-ai.md`
Date: 2026-06-29
## What Was Audited
- Folder structure under `src/app`, `src/components`, `src/features`, `src/hooks`, `src/lib`, `src/db`, and `src/config`.
- Feature structure for all directories in `src/features`.
- Table patterns across training records, pending review, employee directory, audit logs, users, courses, employees, products, notifications, announcements, and online lessons.
- Form patterns using `useAppForm` and Zod.
- Route Handler and Drizzle persistence patterns.
- Auth and role helpers.
- Shared UI, dialog, sheet, alert dialog, upload, table, and layout components.
- Existing documentation and `AGENTS.md`.
## Important Corrections From The Plan
The plan names some tools that are not the actual stack. The generated docs follow the real repository implementation:
- Persistence is Drizzle ORM, not Prisma.
- Forms use TanStack Form, not React Hook Form.
- Runtime mutations use Route Handlers plus TanStack Query, not `next-safe-action`.
- Icons come from `@/components/icons`.
- Data tables should use the shared DataTable stack.
## Canonical Features Selected
Primary:
- `training-records`
Secondary:
- `employee-directory`
- `announcements`
- `audit-logs`
## Documents Created
- `docs/AI_DEVELOPMENT_GUIDE.md`
- `docs/PROJECT_ARCHITECTURE.md`
- `docs/REFRACTOR_REPORT.md`
## Files Updated
- `AGENTS.md`
## Key Findings
- `training-records` is the strongest canonical feature because it covers server data, Route Handlers, table, form, upload, and review behavior.
- `employee-directory` is a strong table reference for responsive DataTable behavior.
- `announcements` and `notifications` still use manual pagination in places.
- Legacy/template areas such as `products`, `employees`, `forms`, `kanban`, `chat`, and demo pages should not be copied into new runtime work.
- New tables should use `DataTable`, `DataTableToolbar`, `DataTablePagination`, `DataTableViewOptions`, `DataTableColumnHeader`, and `useDataTable`.
- New forms should use `useAppForm`, shared TanStack Form wrappers, and Zod.
## Recommended Next Steps
1. Keep `training-records` as the default feature reference for future work.
2. Finish aligning `online-lessons` to a single DataTable implementation.
3. Do not refactor legacy features without explicit approval.
4. Use `docs/REFRACTOR_REPORT.md` as the backlog for future consistency work.

View File

@@ -0,0 +1,30 @@
ตรวจสอบหน้า Online Lessons ฝั่ง HRD/Admin
ปัญหา:
ตอนนี้หน้า "บทเรียนออนไลน์" หรือ "เพิ่มบทเรียนออนไลน์" ไม่มีปุ่มสำหรับสร้างบทเรียนใหม่
สิ่งที่ต้องแก้:
1. เพิ่มปุ่มหลักด้านบนขวาของหน้า ชื่อ "+ เพิ่มบทเรียนออนไลน์"
2. ให้แสดงเฉพาะ role HRD/Admin หรือ IT Admin เท่านั้น
3. เมื่อกดปุ่ม ให้เปิดหน้า Form หรือ Dialog สำหรับสร้างบทเรียนออนไลน์
4. ถ้าในระบบมี Route สร้างอยู่แล้ว ให้กดไปที่ route นั้น เช่น:
/dashboard/online-lessons/create
หรือ /dashboard/online-lessons/manage/create
5. ถ้ายังไม่มี route ให้สร้าง Dialog/Form สำหรับเพิ่มข้อมูล
6. ปุ่มควรใช้ style เดียวกับปุ่มหลักในระบบ เช่น bg-green, rounded-md, icon Plus
7. ห้ามแสดงปุ่มนี้ในฝั่ง Employee
8. ห้ามกระทบการแสดงรายการบทเรียนเดิม
Fields ที่ฟอร์มสร้างบทเรียนควรมี:
- ชื่อบทเรียน
- รายละเอียด
- หมวดหมู่
- ลิงก์วิดีโอ หรือ อัปโหลดวิดีโอ
- ไฟล์แนบ
- รูปปก
- สถานะ Draft / Published
ผลลัพธ์ที่ต้องการ:
HRD/Admin สามารถกดปุ่ม "+ เพิ่มบทเรียนออนไลน์" เพื่อสร้างบทเรียนใหม่ได้

View File

@@ -0,0 +1,736 @@
# Prompt: Standardize Online Lesson Category (K/S/A) & Required Field Indicators
## Objective
ดำเนินการตรวจสอบ วิเคราะห์ และปรับปรุง Module **Online Lessons** ให้เป็นมาตรฐานเดียวกันทั้งระบบ โดยมีวัตถุประสงค์หลักดังนี้
1. เปลี่ยนฟิลด์ **หมวดหมู่ (Category)** ให้เป็น Select ที่ใช้ค่าคงที่ของระบบ (Knowledge / Skill / Attitude)
2. ตรวจสอบ Required Fields ทั้งหมดให้สอดคล้องกับ Validation
3. แสดงเครื่องหมาย **(\*) สีแดง** เฉพาะฟิลด์ที่ Required เท่านั้น
4. ลบเครื่องหมาย (\*) ออกจากฟิลด์ที่ไม่ Required
5. ปรับ UI, Validation, API และ Database Mapping ให้สอดคล้องกัน
6. ตรวจสอบทุกหน้าที่เกี่ยวข้องกับ Online Lessons
---
# Background
ปัจจุบันหน้า Online Lesson มีความไม่สอดคล้องระหว่าง
- UI
- Validation
- Business Rules
เช่น
- บาง Field ถูกบังคับกรอก แต่ไม่มีเครื่องหมาย \*
- บาง Field มี \* แต่จริง ๆ ไม่ได้ Required
- Category ยังไม่ใช้มาตรฐาน K/S/A ของระบบ Training
ต้องปรับให้ทั้งระบบมีมาตรฐานเดียวกัน
---
# IMPORTANT
ก่อนแก้ไข
AI ต้องตรวจสอบ Architecture ของ Project ก่อน
ห้ามสร้าง Pattern ใหม่ หากระบบมี Pattern เดิมอยู่แล้ว
ต้อง Reuse
- Shared Form Components
- Shared Select Components
- Shared Validation
- Shared Zod Schema
- Shared API Pattern
- Shared Constants
- Shared Badge
- Shared Label Components
---
# Scope
ตรวจสอบทุกหน้าที่เกี่ยวข้องกับ Online Lessons เช่น
- Create Online Lesson
- Edit Online Lesson
- View Online Lesson
- Detail Page
- List Page
- Filters
- Search
- API
- Validation
- DTO
- Type Definitions
รวมถึงทุก Component ที่ใช้ร่วมกัน
---
# Phase 0 — Architecture Audit
ก่อนแก้ไข
ตรวจสอบ
## Frontend
- Create Form
- Edit Form
- Shared Form
- Shared Label
- Shared Select
- Validation Display
---
## Backend
ตรวจสอบ
- Route Handler
- Server Action
- Service
- Repository
- DTO
---
## Database
ตรวจสอบว่า Category ปัจจุบันเก็บเป็นอะไร
เช่น
```
string
enum
lookup table
```
ห้ามเดา
อ้างอิงจาก Prisma Schema จริง
---
# Phase 1 — Category Redesign
## Business Rule
Category ของ Online Lesson
ให้เป็นค่าคงที่ของระบบ
ประกอบด้วย
```
Knowledge
Skill
Attitude
```
Database
เก็บเป็น Enum หรือ Constant
```
KNOWLEDGE
SKILL
ATTITUDE
```
UI
แสดง
```
K - Knowledge
S - Skill
A - Attitude
```
หรือ Label ตาม Design System ของระบบ
ห้ามใช้ Text Input
---
## Select
เปลี่ยน Category
เป็น
Select
Placeholder
```
เลือกหมวดหมู่
```
Options
```
K - Knowledge
S - Skill
A - Attitude
```
ห้ามให้ผู้ใช้กรอกเอง
---
## Validation
Category
Required
ต้องเลือก 1 ค่า
ข้อความ Error
```
กรุณาเลือกหมวดหมู่
```
---
# Phase 2 — Required Field Audit
ตรวจสอบทุก Field
ใน
Create
Edit
และ Shared Form
---
Rule
ตรวจสอบ
Validation Schema
เป็นหลัก
---
หาก
Validation
กำหนดว่า
Required
UI
ต้องมี
```
*
```
สีแดง
---
หาก
Validation
ไม่ได้ Required
UI
ต้องไม่มี
```
*
```
---
ห้ามมีความไม่ตรงกัน
---
# Phase 3 — Required Label Standard
ใช้ Pattern เดิมของ shadcn/ui
ตัวอย่าง
```
ชื่อบทเรียน *
```
โดย
```
*
```
ใช้สีแดง
เหมือนฟอร์มอื่นในระบบ
ห้ามสร้าง Component ใหม่ หากมี Shared Label อยู่แล้ว
---
# Phase 4 — Validation Review
ตรวจสอบ Validation ทุก Field
เช่น
- Title
- Description
- Category
- Cover
- Video
- Duration
- Visibility
- Provider
- Tags
หรือ Field ที่มีอยู่จริง
ห้ามเดา
ใช้ Schema จริง
---
หากพบว่า
UI
กับ
Validation
ไม่ตรงกัน
ให้ปรับ
UI
ตาม Validation
---
# Phase 5 — Database Mapping
ตรวจสอบ Mapping
UI
DTO
API
Service
Repository
Database
Category
ต้อง Mapping
```
K
KNOWLEDGE
```
```
S
SKILL
```
```
A
ATTITUDE
```
หรือใช้ Enum จริงของระบบ
ห้าม Hardcode
หากระบบมี Shared Enum
ต้อง Reuse
---
# Phase 6 — API Review
ตรวจสอบ
Create API
Edit API
Validation
ต้องรองรับ Category ใหม่
ห้ามรับค่าอื่น
เช่น
```
TEST
AAA
OTHER
```
หากไม่อยู่ใน Enum
ต้อง Reject
---
# Phase 7 — Edit Page
หน้า Edit
ต้องใช้
Category Select
แบบเดียวกับ
Create
และ
แสดงค่าเดิมได้ถูกต้อง
---
# Phase 8 — Filters
หากหน้า List
มี Filter
Category
ให้เปลี่ยนเป็น
Select
K/S/A
ด้วย
ห้ามใช้ Text Search
สำหรับ Category
---
# Phase 9 — Type Safety
ตรวจสอบ
TypeScript
ให้ใช้
Enum
หรือ
Literal Type
ของระบบ
ห้ามใช้
```
string
```
แบบกว้าง
ตัวอย่าง
```
type Category
=
"KNOWLEDGE"
|
"SKILL"
|
"ATTITUDE"
```
หรือ Enum เดิมของระบบ
---
# Phase 10 — Regression Testing
ตรวจสอบ
## Create
- Category เป็น Select
- Placeholder ถูกต้อง
- Required แสดง \*
- Validation ทำงาน
---
## Edit
- Category แสดงค่าเดิม
- เปลี่ยนค่าได้
- Save สำเร็จ
---
## View
- แสดง Category ถูกต้อง
---
## List
- Filter ใช้งานได้
---
## Validation
ทุก Field
ที่ Required
มี \*
ทุก Field
ที่ Optional
ไม่มี \*
---
## API
Reject
Invalid Category
---
## Database
Category
ถูกบันทึกถูกต้อง
---
## TypeScript
ไม่มี
Type Error
---
## ESLint
ไม่มี Error
---
# Code Quality
ตรวจสอบ
- ไม่มี Duplicate Logic
- ไม่มี Hardcode Category
- ไม่มี any ใหม่
- ไม่มี Dead Code
- ไม่มี console.log
- Reuse Existing Components
- Reuse Existing Enum
- Reuse Existing Validation
---
# Documentation
สร้างรายงาน
```
docs/online-lessons-category-standardization-report.md
```
---
รายงานต้องมี
```md
# Online Lessons Category Standardization Report
## Executive Summary
## Current Architecture
## Current Issues
## Category Design
## Required Field Audit
## Validation Audit
## Database Mapping
## API Changes
## UI Changes
## Files Modified
## Testing Result
## Regression Result
## Risks
## Recommendations
```
---
# Future Improvements
เสนอแนวทางเพิ่มเติม เช่น
- Category Color Badge
- Category Statistics Dashboard
- Category Permission
- Dynamic Category (หาก Business เปลี่ยนในอนาคต)
- Category Report
---
# Constraints
ห้าม
- เปลี่ยน Business Logic อื่น
- Hardcode Category
- Hardcode Enum
- เพิ่ม Library ใหม่
- ใช้ any
- เปลี่ยน Design System
- สร้าง Component ซ้ำ
ต้อง
- ใช้ Shared Enum
- ใช้ Shared Validation
- ใช้ Shared Label
- ใช้ Shared Select
- รักษา Type Safety
- รักษา Coding Standard
- รองรับการขยายไปยัง Module อื่น
---
# Deliverables
ดำเนินการดังนี้
1. Audit ระบบก่อนแก้ไข
2. แก้ไข Source Code
3. ตรวจสอบ Regression
4. สร้างรายงาน
```
docs/online-lessons-category-standardization-report.md
```
---
# Final Response
เมื่อดำเนินการเสร็จ ให้ตอบกลับเป็นภาษาไทย พร้อมสรุป
1. Architecture ที่ตรวจพบ
2. Category Design ที่ใช้
3. รายการ Required Fields ที่ตรวจพบ
4. การปรับ Required Indicator (\*)
5. Validation ที่แก้ไข
6. Database Mapping
7. API ที่แก้ไข
8. รายชื่อไฟล์ที่แก้ไข
9. ผลการทดสอบ
10. Regression Result
11. ความเสี่ยงที่เหลือ (ถ้ามี)
12. Path ของรายงาน
```
docs/online-lessons-category-standardization-report.md
```

View File

@@ -0,0 +1,223 @@
You are a Senior Frontend Engineer and Full Stack Engineer.
Project:
Training Management System (TMS)
Current task:
Update Master Data sidebar by keeping the existing "พนักงาน" menu and adding a new menu "รายชื่อพนักงานทั้งหมด".
Requirement:
Under the sidebar parent menu "ข้อมูลหลัก", keep the existing "พนักงาน" menu and add a new submenu named "รายชื่อพนักงานทั้งหมด".
Important constraints:
- Do NOT remove the existing "พนักงาน" menu.
- Do NOT change the existing "พนักงาน" route.
- Do NOT delete existing routes or APIs.
- Do NOT change database schema unless required for the new detail page.
- Keep Thai UI.
- Keep responsive/mobile sidebar behavior.
- Minimal-impact changes only.
Navigation structure:
ข้อมูลหลัก
├─ พนักงาน
├─ รายชื่อพนักงานทั้งหมด
├─ หลักสูตร
├─ นโยบาย
└─ ประกาศ
Existing menu:
- พนักงาน
Keep current route as-is.
Example:
/dashboard/users
or whatever route currently exists.
New menu:
- รายชื่อพนักงานทั้งหมด
Recommended route:
- /dashboard/employee-directory
Alternative route if project convention prefers:
- /dashboard/employees-directory
- /dashboard/employees/all
Page title:
- รายชื่อพนักงานทั้งหมด
Description:
- เรียกดูข้อมูลพนักงาน ข้อมูลชั่วโมงอบรม และรายการอบรมรายบุคคล
New page requirements:
1. Employee Directory Table
Columns:
- รหัสพนักงาน
- ชื่อพนักงาน
- ฝ่าย
- ตำแหน่ง
- Action
Action:
- Compact action menu or button
- Label:
ดูข้อมูลพนักงาน
2. Search
Search by:
- รหัสพนักงาน
- ชื่อพนักงาน
- ฝ่าย
- ตำแหน่ง
- อีเมล
Placeholder:
- ค้นหาด้วยรหัสพนักงาน ชื่อ ฝ่าย หรือตำแหน่ง...
3. Detail Page
When clicking "ดูข้อมูลพนักงาน", open:
- /dashboard/employee-directory/[id]
Detail page sections:
Section 1:
ข้อมูลทั่วไปพนักงาน
- รหัสพนักงาน
- ชื่อพนักงาน
- อีเมล
- บริษัท
- ฝ่าย
- แผนก
- ตำแหน่ง
- สถานะ
Section 2:
ข้อมูลชั่วโมงอบรม
- ชั่วโมงอนุมัติแล้ว
- ชั่วโมงรอตรวจสอบ
- ชั่วโมงไม่อนุมัติ
- เป้าหมายชั่วโมงรวม
- ความคืบหน้า
Section 3:
K/S/A Summary
- K approved / K target
- S approved / S target
- A approved / A target
Section 4:
รายการอบรม
- วันที่อบรม
- ชื่อหลักสูตร
- ประเภทการอบรม
- ชั่วโมงที่ส่ง
- ชั่วโมงที่อนุมัติ
- สถานะ
- ไฟล์เกียรติบัตร
4. Permission
HRD/Admin:
- Can access employee directory.
- Can view all employee details.
Employee:
- Must not see this menu.
- Must not access route by direct URL.
5. Responsive
- Table must not break page width.
- Use horizontal scroll inside table container.
- Detail cards stack on mobile.
- Thai text wraps correctly.
Files likely involved:
Navigation:
- src/config/nav-config.ts
Routes:
- src/app/dashboard/employee-directory/page.tsx
- src/app/dashboard/employee-directory/[id]/page.tsx
Feature:
- src/features/employee-directory/\*
Can reuse:
- src/features/users/\*
- src/features/employees/\*
- src/features/training-records/\*
- src/features/overview/server/overview-data.ts
- src/features/reports/server/report-data.ts
Output Review File:
Create:
docs/management-change-add-employee-directory-menu-review.md
Include:
1. Summary
2. Files Changed
3. Sidebar Changes
4. New Routes
5. Existing Employee Menu Kept
6. Employee Directory Page
7. Employee Detail Page
8. Permission Rules
9. Responsive Notes
10. Manual Test Checklist
11. Known Limitations
Manual Test Checklist:
- Existing "พนักงาน" menu remains.
- New "รายชื่อพนักงานทั้งหมด" menu appears under "ข้อมูลหลัก".
- HRD/Admin can open employee directory.
- Employee cannot see employee directory menu.
- Employee cannot access employee directory by URL.
- Employee directory table shows employee code.
- Employee directory table shows employee name.
- Employee directory table shows department/faction.
- Employee directory table shows position.
- Action opens employee detail.
- Detail page shows general employee data.
- Detail page shows training hour summary.
- Detail page shows K/S/A summary.
- Detail page shows training records.
- Mobile layout works.
- Existing "พนักงาน" page still works.
Return:
- Complete code changes with file paths.
- Content of docs/management-change-add-employee-directory-menu-review.md.
- Migration commands if required.

View File

@@ -0,0 +1,84 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current task:
Update Admin/HRD sidebar navigation based on management feedback.
Requirement:
Remove the following menus from Admin/HRD sidebar:
1. องค์กร
2. ตรวจสอบข้อมูลหลัก
Important constraints:
- Do NOT delete routes.
- Do NOT delete APIs.
- Do NOT delete database tables.
- Do NOT remove existing feature code.
- Do NOT break Employee Import or Master Review backend logic.
- Only hide/remove these items from sidebar navigation.
- Keep Thai UI.
- Minimal-impact changes only.
Behavior:
1. Admin/HRD sidebar should no longer show:
- องค์กร
- ตรวจสอบข้อมูลหลัก
2. Employee sidebar should remain unchanged according to latest requirements.
3. Existing routes may remain available internally:
- /dashboard/organizations or existing organization route
- /dashboard/master-review
4. Do not remove route files unless explicitly requested later.
5. If nav config has role-based items:
- remove or comment out these menu items from HRD/Admin nav group only.
6. If sidebar is generated from config:
Update:
- src/config/nav-config.ts
7. If organization menu comes from workspace/org switcher:
Do not remove organization switcher unless it is specifically the sidebar menu item named "องค์กร".
Only remove the sidebar navigation item.
8. Output Review File
Create:
docs/management-change-admin-sidebar-review.md
Include:
1. Summary
2. Files Changed
3. Navigation Changes
4. Routes Kept
5. Permission Impact
6. Manual Test Checklist
7. Known Limitations
Manual Test Checklist:
- HRD/Admin sidebar no longer shows "องค์กร".
- HRD/Admin sidebar no longer shows "ตรวจสอบข้อมูลหลัก".
- Other HRD menus still display correctly.
- Employee menus are not affected.
- Dashboard still works.
- Employee Import still works.
- Master Review backend/API is not deleted.
- No route or API was removed.
Return:
- Complete code changes with file paths.
- Content of docs/management-change-admin-sidebar-review.md.

View File

@@ -0,0 +1,144 @@
You are a Senior Frontend Engineer.
Project:
Training Management System (TMS)
Current task:
Fix certificate preview dialog UI based on UAT/management feedback.
Issue:
The certificate preview modal close button appears too close to the dialog edge or overflows visually.
The certificate image preview also needs better sizing for desktop and mobile.
Important constraints:
- Do NOT change folder structure.
- Do NOT change database schema.
- Do NOT break existing certificate preview/download behavior.
- Reuse existing Dialog / Button / icon components.
- Keep Thai UI.
- Keep responsive/mobile behavior.
- Minimal-impact changes only.
Requirements:
1. Fix close button position in certificate preview dialog.
Current issue:
- Close button appears near or outside the top-right edge.
- It looks visually misaligned.
Expected behavior:
- Close button must stay inside the dialog.
- Close button must be easy to click.
- Close button must not overlap the certificate image.
- Close button must work on desktop and mobile.
2. Add proper dialog header.
Header text:
- ตัวอย่างเกียรติบัตร
Layout:
- Header title on the left
- Close button on the right
- Divider or spacing before preview content
3. Prefer using DialogClose from shadcn/ui.
Example:
<DialogClose asChild>
<Button variant="ghost" size="icon">
<X className="h-4 w-4" />
</Button>
</DialogClose>
4. If the current dialog uses absolute positioning:
- Avoid top-0 right-0
- Use top-4 right-4 only if necessary
- Prefer flex justify-between inside header
5. Fix image preview sizing.
Image requirements:
- Use object-contain
- Width should not overflow dialog
- Height should not exceed viewport
- Recommended:
- max-h-[70vh]
- w-full
- object-contain
6. Fix dialog content sizing.
DialogContent requirements:
- max-w suitable for certificate preview
- max-h-[85vh]
- overflow-y-auto
- padding should not cause overflow
- mobile width should fit screen
Recommended classes:
- w-[calc(100vw-2rem)]
- max-w-3xl
- max-h-[85vh]
- overflow-y-auto
7. Keep certificate fallback behavior.
If file is not an image or image fails:
- Show certificate placeholder icon
- Do not show broken image icon
8. Apply fix to all certificate preview dialogs/components.
Files likely involved:
- src/features/training-records/components/training-record-certificate-manager.tsx
- src/features/training-records/components/training-record-view-page.tsx
- src/features/training-records/components/training-record-tables/columns.tsx
- src/components/ui/dialog.tsx only if shared dialog styling is causing the issue
9. Output Review File
Create:
docs/management-change-certificate-dialog-review.md
Include:
1. Summary
2. Files Changed
3. UI Changes
4. Dialog Behavior
5. Image Sizing
6. Mobile/Responsive Notes
7. Manual Test Checklist
8. Known Limitations
Manual Test Checklist:
- Certificate preview dialog opens correctly.
- Close button stays inside dialog.
- Close button does not overlap image.
- Close button works on desktop.
- Close button works on mobile.
- Large landscape certificate fits inside dialog.
- Portrait certificate fits inside dialog.
- Image does not overflow screen.
- PDF or unsupported file shows certificate placeholder icon.
- Broken image shows certificate placeholder icon.
- Download/open certificate still works.
Return:
- Complete code changes with file paths.
- Content of docs/management-change-certificate-dialog-review.md.

View File

@@ -0,0 +1,98 @@
You are a Senior Frontend Engineer.
Project:
Training Management System (TMS)
Current task:
Improve certificate attachment display fallback.
Requirement:
In the certificate column/card, show a certificate icon placeholder when there is no image preview. If there is no attached file, show the same certificate icon but display "ไม่มีไฟล์แนบ".
Important constraints:
- Do NOT change database schema.
- Do NOT break certificate download/open behavior.
- Keep Thai UI.
- Keep responsive behavior.
- Minimal-impact changes only.
Display rules:
Case 1: Image file exists and preview loads
- Show image preview.
Supported preview image types:
- jpg
- jpeg
- png
- webp
- gif
Case 2: File exists but is not previewable
Examples:
- pdf
- docx
- xlsx
- pptx
- zip
- image preview fails
Show placeholder:
- Certificate icon
- Text: เกียรติบัตร
- File type, e.g. PDF, DOCX, XLSX
Case 3: No file attached
Show placeholder:
- Certificate icon
- Text: ไม่มีไฟล์แนบ
Do NOT show:
- broken image icon
- "-"
- empty cell
Recommended icon:
- Award
or
- FileBadge
or
- FileCheck
UI requirement:
- Same card size for image, PDF, and no attachment states.
- Center icon and text.
- Border should be dashed or light border.
- Text should be small and readable.
- Works inside table cell.
Files likely involved:
- src/features/training-records/components/training-record-certificate-manager.tsx
- src/features/training-records/components/training-record-view-page.tsx
- src/features/training-records/components/training-record-tables/columns.tsx
- src/components/certificate-preview.tsx if exists
Output Review File:
Create:
docs/management-change-certificate-empty-state-review.md
Manual Test Checklist:
- Image certificate displays preview.
- PDF certificate shows certificate icon and PDF.
- DOCX certificate shows certificate icon and DOCX.
- Broken image shows certificate icon.
- No attachment shows certificate icon and "ไม่มีไฟล์แนบ".
- No table cell displays "-".
- Download/open still works when file exists.
- Mobile/table layout does not break.

View File

@@ -0,0 +1,93 @@
You are a Senior React/Next.js Engineer.
Project:
Training Management System (TMS)
Current task:
Improve certificate preview fallback behavior.
Requirements:
1. If uploaded certificate is an image:
- jpg
- jpeg
- png
- gif
- webp
Show image preview.
2. If image cannot be loaded:
- broken image
- 404
- invalid url
Show certificate placeholder icon.
3. If uploaded file is not an image:
- pdf
- docx
- xlsx
- pptx
- zip
- rar
Show certificate placeholder icon.
4. Use Lucide icon:
Preferred:
- Award
Fallback:
- GraduationCap
- FileBadge
- FileCheck
5. Placeholder UI should contain:
- Icon
- Text:
"เกียรติบัตร"
- Optional file type
Example:
🏆
เกียรติบัตร
PDF
6. Never display broken image icons.
7. Download/Open certificate action must still work.
8. Apply to:
- Training History
- Training Detail
- Training Record Table
Files likely involved:
src/features/training-records/components/\*
src/features/training-records/components/training-record-view-page.tsx
src/features/training-records/components/training-record-certificate-manager.tsx
src/features/training-records/components/training-record-tables/columns.tsx
Output:
docs/management-change-certificate-preview-review.md
Include:
1. Summary
2. Files Changed
3. Preview Logic
4. Placeholder Design
5. Supported File Types
6. Manual Test Checklist
7. Known Limitations

View File

@@ -0,0 +1,177 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current task:
Update Employee Training Record form course selection.
Requirement:
Change the course name field from plain text input to a searchable course combobox that supports both HRD Course Master and custom course name.
Important constraints:
- Do NOT change folder structure.
- Do NOT migrate ORM unless absolutely necessary.
- Reuse existing Course Master.
- Reuse existing Training Records module.
- Keep Thai UI.
- Keep responsive/mobile behavior.
- Minimal-impact changes only.
Behavior:
1. Course selection field
Replace current plain text input:
- courseName
With searchable combobox:
- Select from Course Master
- Search course by course name or course code
- Show active courses only
- Display course label as:
courseCode - courseName
Example:
IT001 - Cyber Security Awareness
2. Custom course option
Add option:
- อื่น ๆ / กรอกชื่อหลักสูตรเอง
When selected:
- courseId = null
- Show text input:
ชื่อหลักสูตรอื่น ๆ
- This input is required
3. When selecting Course Master
When employee selects a master course:
- courseId = selected course id
- courseName = selected course name
- Optional auto-fill:
- provider from course organizer/provider
- submittedHours from standardHours/defaultHours if available
Employee can still edit:
- training date
- training type
- submitted hours
- provider
- remark
- certificate
4. Validation
Rules:
- If courseId is selected:
- courseName should come from selected course
- If custom course is selected:
- custom courseName is required
- courseName cannot be empty
- submittedHours must be greater than 0
- certificate is still required if current rule requires it
Thai validation messages:
- กรุณาเลือกหลักสูตร หรือกรอกชื่อหลักสูตร
- กรุณากรอกชื่อหลักสูตร
- กรุณาระบุจำนวนชั่วโมงอบรม
5. Database behavior
Training record should save:
- courseId when selected from master
- courseName always
- courseId = null for custom course
Do not remove existing courseName field.
6. API / data fetching
Add or reuse course list API/query:
- GET active courses
- Support search keyword
- Return:
- id
- courseCode
- name
- category
- standardHours
- organizer
- certificateRequired
7. UI
Use existing shadcn/ui components if available:
- Command
- Popover
- Button
- Input
- Select
Combobox UX:
- Placeholder: เลือกหรือค้นหาหลักสูตร
- Empty state: ไม่พบหลักสูตร
- Custom option: อื่น ๆ / กรอกชื่อหลักสูตรเอง
- Mobile friendly
8. Files likely involved:
- src/features/training-records/components/training-record-form.tsx
- src/features/training-records/schemas/training-record.ts
- src/features/training-records/api/types.ts
- src/features/training-records/server/training-record-data.ts
- src/features/courses/server/course-data.ts
- src/app/api/courses/route.ts
9. Output Review File
Create:
docs/management-change-course-selection-review.md
Include:
1. Summary
2. Files Changed
3. UI Changes
4. Course Selection Behavior
5. Custom Course Behavior
6. Validation Rules
7. Database Behavior
8. Manual Test Checklist
9. Known Limitations
Manual Test Checklist:
- Employee can search course from Course Master.
- Employee can select course from Course Master.
- Selected course fills course name.
- Selected course fills provider if available.
- Selected course fills default hours if available.
- Employee can choose custom course.
- Custom course name is required.
- Saving master course stores courseId.
- Saving custom course stores courseId as null.
- HRD review still displays course name correctly.
- Duplicate warning still works.
- Mobile layout works.
Return:
- Complete code changes with file paths.
- Content of docs/management-change-course-selection-review.md.

View File

@@ -0,0 +1,116 @@
You are a Senior Frontend Engineer.
Project:
Training Management System (TMS)
Current task:
Update Dashboard Filter UI based on management feedback.
Important constraints:
- Do NOT change folder structure.
- Do NOT change API contract unless necessary.
- Do NOT break dashboard filtering logic.
- Keep Thai UI.
- Keep responsive/mobile support.
- Minimal-impact changes only.
Requirement:
Change the dashboard filter section from large card layout to compact toolbar filter style.
Current UI:
- Large card titled "ตัวกรองแดชบอร์ด"
- Description text
- Year select
- Apply filter button
- Reset button
New UI:
Use compact toolbar style similar to the data table filter pattern.
Employee dashboard filter should display:
- Search input or placeholder area if search is not used
- Year filter as compact dropdown button
- Status filter if available
- Reset filter button only when filters are active
Preferred visual style:
- Small height controls
- Inline horizontal layout on desktop
- Wrap or stack on mobile
- Use rounded border buttons
- Use icon + label format
- No large card container
- No large title/description
Example layout:
[ ค้นหาประวัติการอบรม... ] [ + ปี ] [ + สถานะ ] [ ล้างตัวกรอง ]
If search is not applicable to dashboard data:
- Use only:
[ ปี: 2026 ] [ ล้างตัวกรอง ]
For HRD dashboard:
- Use:
[ ค้นหา... ] [ + ปี ] [ + บริษัท ] [ + แผนก ] [ ล้างตัวกรอง ]
Behavior:
1. Preserve existing year filter behavior.
2. Preserve existing company/department filter behavior for HRD.
3. Remove the large filter card UI.
4. Do not remove the actual filtering feature.
5. Update responsive behavior:
- Desktop: inline row
- Mobile: wrap into multiple rows or full-width controls
6. Keep Thai labels:
- ปี
- บริษัท
- แผนก
- สถานะ
- ล้างตัวกรอง
- ค้นหา...
Files likely involved:
- src/features/overview/components/overview-filter-panel.tsx
- src/features/overview/server/overview-data.ts only if query param mapping needs adjustment
- src/app/dashboard/overview/page.tsx if filter panel is composed there
Output Review File:
Create:
docs/management-change-dashboard-filter-review.md
Include:
1. Summary
2. Files Changed
3. UI Changes
4. Filter Behavior
5. Responsive Notes
6. Manual Test Checklist
7. Known Limitations
Manual Test Checklist:
- Dashboard no longer shows large filter card.
- Employee dashboard shows compact filter toolbar.
- HRD dashboard shows compact filter toolbar.
- Year filter still works.
- Company filter still works for HRD.
- Department filter still works for HRD.
- Reset filter works.
- Mobile layout does not overflow.
- Dashboard data still updates after filtering.
Return:
- Complete code changes with file paths.
- Content of docs/management-change-dashboard-filter-review.md.

View File

@@ -0,0 +1,263 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current task:
Change training hours storage and display from decimal hours to duration minutes.
Requirement:
Training duration must be stored and calculated as hours and minutes, not decimal hours.
Important constraints:
- Do NOT use AM/PM.
- Do NOT use clock TimePicker.
- Do NOT store Date object.
- Keep Thai UI.
- Keep responsive/mobile behavior.
- Minimal-impact changes only.
Business examples:
- 01:45 = 1 ชั่วโมง 45 นาที
- 00:15 = 15 นาที
- 02:00 = 2 ชั่วโมง
- 30:00 = 30 ชั่วโมง
Recommended storage:
Store duration as total minutes.
Examples:
- 01:45 -> 105
- 00:15 -> 15
- 02:00 -> 120
- 30:00 -> 1800
Part 1: Database
Check current fields:
- submittedHours
- approvedHours
- targetHours
- kHours
- sHours
- aHours
If current DB stores decimal hours, add new minute-based fields if needed:
training_records:
- submittedMinutes integer
- approvedMinutes integer
employee_training_targets:
- totalTargetMinutes integer
- kTargetMinutes integer
- sTargetMinutes integer
- aTargetMinutes integer
training_policy:
- totalTargetMinutes integer
- kTargetMinutes integer
- sTargetMinutes integer
- aTargetMinutes integer
Important:
Do not drop old decimal fields yet.
Keep old fields for compatibility during migration.
Migration:
- Convert old decimal hours to minutes:
minutes = ROUND(hours \* 60)
Part 2: Duration Picker UI
Create or update component:
src/components/ui/duration-picker.tsx
Props:
- valueMinutes: number | null
- onChange: (minutes: number | null) => void
- maxHours?: number
- minuteStep?: number
- disabled?: boolean
UI:
- Two dropdowns:
1. ชั่วโมง
2. นาที
Hour options:
- 00 to 30
Minute options:
- 00
- 15
- 30
- 45
Display:
- --:-- when empty
- 00:15
- 01:45
- 02:00
- 30:00
Do not display:
- AM
- PM
Part 3: Form Behavior
In Create/Edit Training Record form:
Field:
- จำนวนชั่วโมงอบรม \*
Use DurationPicker.
Save:
- submittedMinutes
Validation:
- required
- > 0 minutes
- <= 1800 minutes
Thai messages:
- กรุณาระบุจำนวนชั่วโมงอบรม
- จำนวนชั่วโมงอบรมต้องมากกว่า 0 นาที
- จำนวนชั่วโมงอบรมต้องไม่เกิน 30 ชั่วโมง
Part 4: Display Formatting
Create helper functions:
formatDurationThai(minutes: number): string
Examples:
- 15 -> 15 นาที
- 60 -> 1 ชั่วโมง
- 105 -> 1 ชั่วโมง 45 นาที
- 120 -> 2 ชั่วโมง
- 1800 -> 30 ชั่วโมง
formatDurationHHMM(minutes: number): string
Examples:
- 15 -> 00:15
- 105 -> 01:45
- 120 -> 02:00
Part 5: Calculations
All dashboard/report calculations should use minutes:
- approvedMinutes
- pendingMinutes
- rejectedMinutes
- targetMinutes
When summing:
- SUM(minutes)
Do not sum decimal hours.
Part 6: K/S/A Targets
Targets should support minutes too.
Examples:
- K = 12 ชั่วโมง 30 นาที -> 750 minutes
- S = 10 ชั่วโมง -> 600 minutes
- A = 7 ชั่วโมง 30 นาที -> 450 minutes
Part 7: Backward Compatibility
If minute field is null:
- fallback to old decimal hour field:
minutes = ROUND(hours \* 60)
Use helper:
getDurationMinutes(minutesField, legacyHoursField)
Part 8: Update all UI locations
Update:
- Training Record table
- Training Detail
- HRD Review
- Dashboard
- K/S/A Progress
- Employee Directory
- Reports
- Export Excel
- Export PDF
Display examples:
- 1 ชั่วโมง 45 นาที
- 15 นาที
- 2 ชั่วโมง
Part 9: Output Review File
Create:
docs/management-change-duration-minutes-review.md
Include:
1. Summary
2. Database Changes
3. Migration Strategy
4. Duration Picker UI
5. Storage Behavior
6. Display Formatting
7. Dashboard Impact
8. Reports Impact
9. Backward Compatibility
10. Manual Test Checklist
11. Known Limitations
Manual Test Checklist:
- 00:15 saves 15 minutes.
- 01:45 saves 105 minutes.
- 02:00 saves 120 minutes.
- 30:00 saves 1800 minutes.
- 00:00 is blocked.
- More than 30:00 is blocked.
- Training history shows 1 ชั่วโมง 45 นาที.
- Dashboard sums minutes correctly.
- Reports export minutes correctly.
- Legacy decimal hours still display correctly.
- No AM/PM appears anywhere.
Return:
- Complete code changes with file paths.
- Migration command if required.
- Review file.

View File

@@ -0,0 +1,233 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current task:
Transform the Employees/Users page into an employee training overview page.
Requirement:
The "พนักงาน" menu should be used to view employee information, training history summary, and training hour progress, not only user account management.
Important constraints:
- Do NOT delete existing users route unless necessary.
- Do NOT remove user management permissions.
- Do NOT change database schema unless absolutely necessary.
- Reuse existing users/employees page.
- Reuse existing training records queries.
- Reuse existing Training Policy and employee-specific K/S/A target logic if available.
- Keep Thai UI.
- Keep responsive/mobile behavior.
- Minimal-impact changes only.
Part 1: Page Purpose
Update the Employees/Users page to show employee training overview.
Page title:
- พนักงาน
Description:
- ดูข้อมูลพนักงาน ประวัติการอบรม และจำนวนชั่วโมงการอบรม
Part 2: Table Columns
Replace or adjust current table columns to:
1. รหัสพนักงาน
2. ชื่อพนักงาน
3. แผนก
4. ตำแหน่ง
5. ชั่วโมงอนุมัติ
6. ชั่วโมงรอตรวจสอบ
7. ชั่วโมงไม่อนุมัติ
8. เป้าหมายชั่วโมง
9. ความคืบหน้า
10. สถานะ
Status logic:
- ผ่านเกณฑ์
- ยังไม่ผ่านเกณฑ์
Progress logic:
approvedHours / targetHours \* 100
If target is missing:
- use Training Policy default
If both employee target and policy missing:
- show "-"
Part 3: Search
Search should support:
- employeeCode
- employeeName
- email
- department
- position
Search placeholder:
- ค้นหาด้วยรหัสพนักงาน ชื่อ แผนก หรือตำแหน่ง...
Part 4: Filters
Add filters if existing pattern supports:
- แผนก
- สถานะผ่านเกณฑ์
- ปี
Part 5: Employee Detail
When HRD clicks an employee row or action button:
Route:
- /dashboard/users/[id]
or existing detail route
Show employee detail page with:
1. Employee profile summary
- รหัสพนักงาน
- ชื่อพนักงาน
- อีเมล
- แผนก
- ตำแหน่ง
- สถานะ
2. Training summary
- ชั่วโมงอนุมัติ
- ชั่วโมงรอตรวจสอบ
- ชั่วโมงไม่อนุมัติ
- เป้าหมายรวม
- ความคืบหน้า
3. K/S/A summary
- K approved / K target
- S approved / S target
- A approved / A target
4. Training history table
- วันที่อบรม
- ชื่อหลักสูตร
- ประเภทการอบรม
- ชั่วโมง
- สถานะ
- ไฟล์เกียรติบัตร
Part 6: Actions
Keep existing buttons:
- เพิ่มพนักงาน
- นำเข้าพนักงาน
But page should feel like HRD employee training overview.
Part 7: Permissions
HRD/Admin:
- can view all employees
- can view employee training summary
- can access employee detail
Employee:
- should not access all employee list
- employee uses own dashboard/training records instead
Part 8: Performance
Use database aggregation:
- SUM approved hours
- SUM pending hours
- SUM rejected hours
- GROUP BY employee
Avoid loading all training records and reducing in memory.
Part 9: Responsive
Desktop:
- Table can show all columns.
Mobile/tablet:
- Table must stay inside horizontal scroll container.
- No page-level overflow.
- Keep employee code/name/progress visible.
Part 10: Files likely involved
- src/app/dashboard/users/page.tsx
- src/app/dashboard/users/[id]/page.tsx if exists
- src/features/users/server/user-data.ts
- src/features/users/components/users-table.tsx
- src/features/users/components/users-columns.tsx
- src/features/users/api/types.ts
- src/features/training-records/server/training-record-data.ts
- src/features/overview/server/overview-data.ts if reusable target logic exists
- src/features/reports/server/report-data.ts if reusable aggregation exists
Part 11: Output Review File
Create:
docs/management-change-employee-training-overview-review.md
Include:
1. Summary
2. Files Changed
3. Page Purpose Changes
4. Table Columns Changed
5. Search/Filter Changes
6. Employee Detail Changes
7. Training Hours Calculation
8. Target/Progress Logic
9. Permission Rules
10. Responsive Notes
11. Manual Test Checklist
12. Known Limitations
Manual Test Checklist:
- HRD opens พนักงาน page.
- Page shows employee training overview.
- Employee code displays.
- Approved hours display correctly.
- Pending hours display correctly.
- Rejected hours display correctly.
- Target hours display correctly.
- Progress percentage displays correctly.
- Pass/fail status displays correctly.
- Search by employee code works.
- Search by name works.
- Search by department works.
- Import employee button still works.
- Add user button still works if required.
- Employee detail page shows training history.
- Employee user cannot access all employee list.
- Table does not break responsive layout.
- Mobile layout works.
Return:
- Complete code changes with file paths.
- Content of docs/management-change-employee-training-overview-review.md.

View File

@@ -0,0 +1,143 @@
You are a Senior Frontend Engineer.
Project:
Training Management System (TMS)
Current task:
Move Import Employees from sidebar into Users/Employees page as an action button.
Requirement:
Remove "นำเข้าพนักงาน" from sidebar navigation and add it as a button inside the Users/Employees page.
Important constraints:
- Do NOT delete /dashboard/import-employees route.
- Do NOT delete import employee API.
- Do NOT change database schema.
- Do NOT change permissions.
- Do NOT create nested sidebar menu.
- Keep Thai UI.
- Keep responsive behavior.
- Minimal-impact changes only.
Navigation change:
1. Remove root-level sidebar menu:
- นำเข้าพนักงาน
2. Do NOT add it as sidebar submenu.
3. Keep sidebar structure:
ข้อมูลหลัก
├─ พนักงาน
├─ หลักสูตร
├─ นโยบาย
└─ ประกาศ
Users/Employees page change:
1. On Users/Employees page, add action button:
Label:
- นำเข้าพนักงาน
Icon:
- Upload
or
- FileUp
Button behavior:
- Click redirects to:
/dashboard/import-employees
2. Place the button in page header action area.
Recommended layout:
Title:
- พนักงาน
Description:
- จัดการข้อมูลพนักงานและสิทธิ์การใช้งานระบบ
Actions:
- นำเข้าพนักงาน
- เพิ่มพนักงาน
If Add User already exists:
- Keep Add User button.
- Add Import Employees button beside it.
If space is limited on mobile:
- Stack buttons vertically or make full width.
3. Permission:
Button visible only for HRD/Admin.
Employee users should not see this button.
4. Direct route:
/dashboard/import-employees should remain protected as HRD/Admin only.
5. Responsive:
Desktop:
- Buttons align right in page header.
Mobile:
- Buttons stack full width.
- No overflow.
Files likely involved:
- src/config/nav-config.ts
- src/app/dashboard/users/page.tsx
- src/features/users/components/\*
- src/components/ui/heading.tsx or page header component if used
- src/app/dashboard/import-employees/page.tsx only if redirect/back button needed
Output Review File:
Create:
docs/management-change-import-button-in-users-review.md
Include:
1. Summary
2. Files Changed
3. Sidebar Changes
4. Users Page Changes
5. Permission Rules
6. Responsive Notes
7. Manual Test Checklist
8. Known Limitations
Manual Test Checklist:
- Sidebar no longer shows "นำเข้าพนักงาน".
- Sidebar still shows "พนักงาน".
- Users page shows "นำเข้าพนักงาน" button for HRD/Admin.
- Button links to /dashboard/import-employees.
- Add User button still works if present.
- Employee user does not see import button.
- Direct /dashboard/import-employees remains HRD/Admin only.
- Mobile layout does not overflow.
Return:
- Complete code changes with file paths.
- Content of docs/management-change-import-button-in-users-review.md.

View File

@@ -0,0 +1,312 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current task:
Enhance Employee Import to support employee-specific K/S/A training hour targets.
Requirement:
When HRD imports employees, the Excel template must support importing individual training hour targets per employee.
Target fields:
- ชั่วโมงรวม
- ชั่วโมง K
- ชั่วโมง S
- ชั่วโมง A
Important constraints:
- Do NOT remove existing employee import functionality.
- Do NOT break existing employee import template.
- Do NOT change folder structure.
- Keep Thai UI.
- Keep responsive/mobile behavior.
- Minimal-impact changes only.
- Use Drizzle ORM.
- Use existing Auth.js authorization.
Business rule:
Training Policy remains the default organization-wide target.
Employee-specific target overrides Training Policy for that employee and year.
Priority:
1. Employee-specific target
2. Training Policy default
Example:
Training Policy 2569:
- Total = 30
- K = 12
- S = 12
- A = 6
Employee AC2026 imported with:
- Total = 60
- K = 24
- S = 24
- A = 12
Dashboard and reports for AC2026 must use:
- Total = 60
- K = 24
- S = 24
- A = 12
Part 1: Database
Add new table if not existing:
employee_training_targets
Fields:
- id
- organizationId
- employeeId or userId
- year
- totalHours
- kHours
- sHours
- aHours
- createdBy
- updatedBy
- createdAt
- updatedAt
Recommended unique constraint:
- organizationId + employeeId/userId + year
Important:
Use whichever identifier is currently stable in the system:
- employeeId if employee table is the source of truth
- userId if users table stores employeeCode and is used by dashboard/report
Do not duplicate targets for the same employee/year.
If importing again:
- update existing target
Part 2: Excel Template
Update employee import template headers.
Existing headers:
- รหัสพนักงาน
- ชื่อพนักงาน
- อีเมล
- บริษัท
- แผนก
- ตำแหน่ง
- สถานะ
Add:
- ชั่วโมงรวม
- ชั่วโมง K
- ชั่วโมง S
- ชั่วโมง A
Final headers:
- รหัสพนักงาน
- ชื่อพนักงาน
- อีเมล
- บริษัท
- แผนก
- ตำแหน่ง
- สถานะ
- ชั่วโมงรวม
- ชั่วโมง K
- ชั่วโมง S
- ชั่วโมง A
Part 3: Import Validation
Validation rules:
1. Existing employee fields remain unchanged.
2. K/S/A target fields are optional.
3. If all target fields are empty:
- import employee normally
- do not create employee-specific target
- dashboard/report fallback to Training Policy
4. If any target field is filled:
- all 4 fields are required:
- ชั่วโมงรวม
- ชั่วโมง K
- ชั่วโมง S
- ชั่วโมง A
5. Values must be numeric.
6. Values must be >= 0.
7. ชั่วโมงรวม must be > 0.
8. ชั่วโมง K + ชั่วโมง S + ชั่วโมง A must equal ชั่วโมงรวม.
9. Year:
- use current selected/import year if import UI has year filter
- otherwise use current year
- for Thai year 2569 store as Gregorian 2026 if existing app uses Gregorian year
Thai error messages:
- กรุณาระบุชั่วโมงรวม
- กรุณาระบุชั่วโมง K
- กรุณาระบุชั่วโมง S
- กรุณาระบุชั่วโมง A
- ชั่วโมงต้องเป็นตัวเลข
- ชั่วโมงรวมต้องมากกว่า 0
- ผลรวมของชั่วโมง K/S/A ต้องเท่ากับชั่วโมงรวม
Part 4: Import Behavior
For each valid row:
1. Upsert employee/user as existing behavior.
2. If K/S/A target fields are provided:
- upsert employee_training_targets by employee/year
- update target values if already exists
3. Import result summary must include:
- จำนวนพนักงานที่นำเข้า
- จำนวนเป้าหมาย K/S/A ที่นำเข้า
- จำนวนรายการที่ใช้ค่า Training Policy เริ่มต้น
- จำนวนรายการผิดพลาด
Part 5: Employee Import Page UI
Update right-side supported template card to show:
- รหัสพนักงาน
- ชื่อพนักงาน
- อีเมล
- บริษัท
- แผนก
- ตำแหน่ง
- สถานะ
- ชั่วโมงรวม
- ชั่วโมง K
- ชั่วโมง S
- ชั่วโมง A
Add helper text:
- หากไม่ระบุชั่วโมง K/S/A ระบบจะใช้ค่าเริ่มต้นจาก Training Policy
Part 6: Dashboard Impact
Update dashboard target resolution:
For employee dashboard:
1. Check employee_training_targets for employee/year.
2. If found, use employee-specific target.
3. If not found, use Training Policy.
For HRD dashboard:
- Passed / Not Passed calculation should use each employee's individual target when available.
- Otherwise fallback to Training Policy.
Part 7: Reports Impact
Update reports if target is shown or used:
- Training Matrix
- Employee Transcript
- Department Summary if it uses target pass/fail
- Annual Summary if it uses target pass/fail
Rule:
Use employee-specific target first, fallback to policy.
Part 8: Permissions
Only HRD/Admin can import targets.
Employee:
- cannot modify target
- can only see calculated progress based on assigned target
Part 9: Audit Log
Add audit event when target is created/updated during import.
Events:
- EMPLOYEE_TARGET_CREATE
- EMPLOYEE_TARGET_UPDATE
Include:
- employeeCode
- year
- old target
- new target
Part 10: Output Review File
Create:
docs/management-change-import-employee-ksa-targets-review.md
Include:
1. Summary
2. Files Changed
3. Database Changes
4. Excel Template Changes
5. Validation Rules
6. Import Behavior
7. Dashboard Impact
8. Reports Impact
9. Audit Events
10. Permission Rules
11. Manual Test Checklist
12. Known Limitations
Manual Test Checklist:
- Download template includes K/S/A target columns.
- Import employee without K/S/A target works.
- Import employee with valid target works.
- Import creates employee-specific target.
- Re-import updates existing employee target.
- Import blocks missing partial target fields.
- Import blocks non-numeric target fields.
- Import blocks K+S+A not equal total.
- Import summary shows target counts.
- Employee dashboard uses employee target.
- Employee dashboard falls back to Training Policy when no target exists.
- HRD dashboard pass/fail uses employee target.
- Training Matrix uses employee target.
- Audit log records target create/update.
- Employee cannot edit target directly.
- Mobile import page remains responsive.
Return:
- Complete code changes with file paths.
- Migration command if required.
- Content of docs/management-change-import-employee-ksa-targets-review.md.

View File

@@ -0,0 +1,107 @@
You are a Senior Frontend Engineer.
Project:
Training Management System (TMS)
Current task:
Update Pending Review table action button UI.
Requirement:
Change the current full "ตรวจสอบ" button in the Pending Review table to a compact three-dot action menu.
Important constraints:
- Do NOT change database schema.
- Do NOT change business logic.
- Do NOT change route behavior.
- Do NOT break review workflow.
- Keep Thai UI.
- Keep responsive/mobile behavior.
- Minimal-impact changes only.
Current UI:
- Table row has full button:
"ตรวจสอบ"
New UI:
- Replace the full button with a compact three-dot action button:
"..."
- Clicking it opens dropdown menu.
Dropdown menu items:
1. ตรวจสอบ
- Icon: Check, Eye, or ClipboardCheck
- Navigate to existing review route
- Same behavior as current ตรวจสอบ button
Optional item if useful: 2. ดูรายละเอียด
- Navigate to training record detail page if existing route exists
Action button behavior:
- Use existing DropdownMenu component if available.
- Use icon button style.
- Button should be small and table-friendly.
- Align to center or right in action column.
- Keep accessible label:
aria-label="เมนูการดำเนินการ"
Recommended UI:
- Button variant="ghost"
- size="icon"
- Icon: MoreHorizontal
Action column:
- Header can be blank or "จัดการ"
- Width should be compact:
w-[60px] or min-w-[60px]
- Do not let this column expand table width.
Responsive:
- On mobile/tablet, the action menu must remain visible.
- Dropdown must not overflow viewport.
- Table should still horizontally scroll inside container if needed.
Files likely involved:
- src/features/training-records/components/pending-review-columns.tsx
- src/features/training-records/components/pending-review-table.tsx
- src/features/training-records/components/training-record-tables/columns.tsx
- src/components/ui/dropdown-menu.tsx if existing
Output Review File:
Create:
docs/management-change-pending-review-action-menu-review.md
Include:
1. Summary
2. Files Changed
3. UI Changes
4. Action Menu Behavior
5. Responsive Notes
6. Manual Test Checklist
7. Known Limitations
Manual Test Checklist:
- Pending Review table no longer shows full "ตรวจสอบ" button.
- Three-dot button appears in action column.
- Clicking three-dot button opens action menu.
- "ตรวจสอบ" menu item opens existing review page.
- Review workflow still works.
- Table width is reduced.
- Mobile layout works.
- Dropdown does not overflow viewport.
Return:
- Complete code changes with file paths.
- Content of docs/management-change-pending-review-action-menu-review.md.

View File

@@ -0,0 +1,131 @@
You are a Senior Frontend Engineer.
Project:
Training Management System (TMS)
Current task:
Refactor HRD/Admin sidebar navigation into grouped menu.
Requirement:
Group the following HRD/Admin menus under a parent menu named "ข้อมูลหลัก":
ข้อมูลหลัก
├─ พนักงาน
├─ หลักสูตร
├─ นโยบาย
├─ ประกาศ
Important constraints:
- Do NOT delete routes.
- Do NOT delete APIs.
- Do NOT change database schema.
- Do NOT break existing role-based navigation.
- Do NOT affect Employee sidebar.
- Keep Thai UI.
- Keep responsive/mobile sidebar behavior.
- Minimal-impact changes only.
Navigation behavior:
1. HRD/Admin sidebar should show parent menu:
- ข้อมูลหลัก
2. Under "ข้อมูลหลัก", show submenu items:
- พนักงาน
Route:
/dashboard/users or /dashboard/employees
Use whichever route currently exists for employee/user management.
- หลักสูตร
Route:
/dashboard/courses
- นโยบาย
Route:
/dashboard/training-policy
- ประกาศ
Route:
/dashboard/announcements
3. Remove these items from the root level of HRD/Admin sidebar:
- พนักงาน
- หลักสูตร
- นโยบาย
- ประกาศ
4. Keep other HRD/Admin root menus unchanged, such as:
- แดชบอร์ด
- รอตรวจสอบ
- ประวัติการอบรม
- นำเข้าพนักงาน
- รายงาน
- Audit Log
5. Employee sidebar must not be affected.
6. Sidebar UX:
- Parent menu "ข้อมูลหลัก" should be collapsible if the current sidebar supports nested items.
- If the current sidebar does not support collapsible groups, use existing nested item pattern if available.
- Submenu should highlight active route.
- If user is currently on one of child routes, parent menu should appear active/open.
7. Mobile behavior:
- Nested menu must work in mobile drawer.
- Sidebar should close after selecting submenu on mobile if current behavior supports it.
- Long Thai labels must not overflow.
Files likely involved:
- src/config/nav-config.ts
- src/components/layout/app-sidebar.tsx
- src/components/layout/nav-main.tsx
- src/components/layout/sidebar-nav.tsx
- src/components/ui/sidebar.tsx
Output Review File:
Create:
docs/management-change-sidebar-master-data-group-review.md
Include:
1. Summary
2. Files Changed
3. Navigation Before
4. Navigation After
5. Role Impact
6. Active Route Behavior
7. Mobile Sidebar Behavior
8. Manual Test Checklist
9. Known Limitations
Manual Test Checklist:
- HRD/Admin sees "ข้อมูลหลัก" parent menu.
- "ข้อมูลหลัก" contains พนักงาน.
- "ข้อมูลหลัก" contains หลักสูตร.
- "ข้อมูลหลัก" contains นโยบาย.
- "ข้อมูลหลัก" contains ประกาศ.
- Root-level พนักงาน menu is removed.
- Root-level หลักสูตร menu is removed.
- Root-level นโยบาย menu is removed.
- Root-level ประกาศ menu is removed.
- Other HRD/Admin menus still work.
- Employee sidebar is unchanged.
- Active submenu is highlighted.
- Parent menu opens when child route is active.
- Mobile sidebar nested menu works.
- No route or API was deleted.
Return:
- Complete code changes with file paths.
- Content of docs/management-change-sidebar-master-data-group-review.md.

View File

@@ -0,0 +1,227 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current task:
Update the Create/Edit Training Record form course field.
Requirement:
Change the course input behavior to a dropdown first, and only show text input when the employee selects "อื่น ๆ".
Important constraints:
- Do NOT change folder structure.
- Do NOT change database schema unless absolutely necessary.
- Do NOT remove existing courseName field.
- Do NOT break existing create/edit training record flow.
- Reuse existing Course Master data.
- Reuse existing Auth.js and Drizzle ORM.
- Keep Thai UI.
- Keep responsive/mobile behavior.
- Minimal-impact changes only.
Business behavior:
1. Course field should be displayed as a dropdown/select by default.
Label:
- ชื่อหลักสูตร \*
Placeholder:
- เลือกหลักสูตร
Dropdown options:
- Active courses from Course Master
- Last option must be:
อื่น ๆ
2. Course option display format:
If courseCode exists:
- courseCode - courseName
Example:
- IT001 - Cyber Security Awareness
If courseCode does not exist:
- courseName
3. When employee selects a Course Master item:
Set:
- courseId = selected course id
- courseName = selected course name
Optional auto-fill if data exists:
- provider / organizer
- submittedHours / standardHours
Do not show custom text input.
4. When employee selects "อื่น ๆ":
Behavior:
- Hide or replace the dropdown with a text input field.
- Show text input for custom course name.
Text input label:
- ชื่อหลักสูตรอื่น ๆ \*
Placeholder:
- กรอกชื่อหลักสูตร
Set:
- courseId = null
- courseName = custom text value
Also show a small button/link:
- เปลี่ยนกลับไปเลือกจากหลักสูตร
When clicked:
- Clear custom course name
- Show dropdown again
- courseId = selected/default state
- courseName = ""
5. Validation rules:
If selected course is from Course Master:
- courseId is required or courseName must be derived from selected course.
If selected "อื่น ๆ":
- custom courseName is required.
Thai validation messages:
- กรุณาเลือกหลักสูตร
- กรุณากรอกชื่อหลักสูตร
- กรุณาระบุจำนวนชั่วโมงอบรม
6. Edit mode behavior:
If existing record has courseId:
- show dropdown selected to that course.
If existing record has courseId = null but has courseName:
- show custom text input with existing courseName.
7. API / Data fetching:
Use existing Course Master API/query if available.
Course list should only show active courses.
Return course fields:
- id
- courseCode
- name
- standardHours
- organizer
- certificateRequired
8. Database behavior:
Training record must always save:
- courseName
Training record should save:
- courseId if selected from master
Training record should save:
- courseId = null if "อื่น ๆ"
Do not remove courseName because it is needed for historical reporting.
9. UI/UX:
Desktop:
- Dropdown full width
- Custom input full width
Mobile:
- Dropdown/input must fit screen width
Use existing UI components:
- Select
- Input
- Button
- FormField
Do not use complex combobox unless existing project already uses one.
10. Files likely involved:
- src/features/training-records/components/training-record-form.tsx
- src/features/training-records/schemas/training-record.ts
- src/features/training-records/api/types.ts
- src/features/training-records/server/training-record-data.ts
- src/app/api/training-records/route.ts
- src/app/api/training-records/[id]/route.ts
- src/app/api/courses/route.ts
- src/features/courses/server/course-data.ts
11. Output Review File
Create:
docs/management-change-training-course-dropdown-review.md
The file must include:
1. Summary
2. Files Changed
3. UI Changes
4. Course Dropdown Behavior
5. Custom Course Behavior
6. Edit Mode Behavior
7. Validation Rules
8. Database Behavior
9. Manual Test Checklist
10. Known Limitations
Manual Test Checklist:
- Create form shows course dropdown by default.
- Active Course Master records are shown in dropdown.
- "อื่น ๆ" appears as the last option.
- Selecting Course Master saves courseId and courseName.
- Selecting Course Master auto-fills provider if available.
- Selecting Course Master auto-fills hours if available.
- Selecting "อื่น ๆ" changes dropdown to text input.
- Custom course name is required when "อื่น ๆ" is selected.
- "เปลี่ยนกลับไปเลือกจากหลักสูตร" works.
- Edit existing master course shows dropdown selected.
- Edit existing custom course shows text input.
- HRD review page still shows course name correctly.
- Reports still show course name correctly.
- Mobile layout works.
Return:
- Complete code changes with file paths.
- Content of docs/management-change-training-course-dropdown-review.md.

View File

@@ -0,0 +1,146 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current task:
Update submitted training hours input to use TimePicker UI.
Requirement:
In Create/Edit Training Record form, change submitted hours input from number input to TimePicker-style input.
Important constraints:
- Do NOT change folder structure.
- Do NOT change database schema.
- Do NOT store Date object in database for hours.
- Keep existing submittedHours/hours database field as numeric/decimal.
- Keep Thai UI.
- Keep responsive/mobile behavior.
- Minimal-impact changes only.
Business logic:
1. Training hours should be selected using TimePicker UI.
Use existing component if available:
- src/components/ui/datetime-picker
- TimePicker
Example usage:
import { TimePicker } from "@/components/ui/datetime-picker";
2. The TimePicker value is a Date object in UI only.
Convert TimePicker value to decimal hours before submit.
Conversion examples:
- 00:30 -> 0.5
- 01:00 -> 1
- 01:30 -> 1.5
- 02:15 -> 2.25
- 07:30 -> 7.5
3. Convert decimal hours back to TimePicker value in edit mode.
Examples:
- 1.5 -> 01:30
- 2 -> 02:00
- 2.25 -> 02:15
- 7.5 -> 07:30
4. Add helper functions:
decimalHoursToDate(hours: number): Date
dateToDecimalHours(date: Date): number
Recommended behavior:
- Use a fixed base date, e.g. 1970-01-01
- Hours come from date.getHours()
- Minutes come from date.getMinutes()
- Decimal = hours + minutes / 60
5. Validation:
Rules:
- submittedHours is required.
- submittedHours must be greater than 0.
- submittedHours should not exceed 24 unless business requires otherwise.
- Minutes should support 15-minute or 30-minute increments if TimePicker supports it.
Thai validation messages:
- กรุณาระบุจำนวนชั่วโมงอบรม
- จำนวนชั่วโมงอบรมต้องมากกว่า 0
- จำนวนชั่วโมงอบรมต้องไม่เกิน 24 ชั่วโมง
6. UI label:
Label:
- จำนวนชั่วโมงอบรม \*
Helper text:
- เลือกระยะเวลาอบรม เช่น 01:30 = 1.5 ชั่วโมง
Display calculated text under input:
- รวม 1.5 ชั่วโมง
7. Do not break existing dashboard/report calculations.
Database should still save:
- submittedHours / hours as decimal number
8. Files likely involved:
- src/features/training-records/components/training-record-form.tsx
- src/features/training-records/schemas/training-record.ts
- src/features/training-records/api/types.ts
- src/app/api/training-records/route.ts
- src/app/api/training-records/[id]/route.ts
- src/lib/time-utils.ts or src/features/training-records/utils/time-utils.ts
9. Output Review File
Create:
docs/management-change-training-hours-timepicker-review.md
Include:
1. Summary
2. Files Changed
3. UI Changes
4. TimePicker Behavior
5. Decimal Conversion Logic
6. Validation Rules
7. Edit Mode Behavior
8. Dashboard/Report Impact
9. Manual Test Checklist
10. Known Limitations
Manual Test Checklist:
- Create form shows TimePicker for training hours.
- Selecting 01:30 saves 1.5 hours.
- Selecting 02:00 saves 2 hours.
- Selecting 02:15 saves 2.25 hours.
- Empty value is blocked.
- 00:00 is blocked.
- Value above 24 hours is blocked.
- Edit form converts 1.5 back to 01:30.
- Dashboard still calculates approved hours correctly.
- Reports still export decimal hours correctly.
- Mobile layout works.
Return:
- Complete code changes with file paths.
- Content of docs/management-change-training-hours-timepicker-review.md.

View File

@@ -0,0 +1,129 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current task:
Update Training Type options in Create/Edit Training Record form.
Requirement:
Change the training type dropdown options to the approved list below.
New Training Type options:
1. อบรมภายใน (Internal Training)
2. อบรมภายนอก (Public Training)
3. e-Learning / Online Course
4. On the Job Training (OJT)
Important constraints:
- Do NOT change folder structure.
- Do NOT migrate ORM unless absolutely necessary.
- Do NOT break existing training records.
- Keep Thai UI.
- Keep responsive/mobile behavior.
- Minimal-impact changes only.
Implementation rules:
1. Update training type options used in:
- Create Training Record form
- Edit Training Record form
- Training Record Detail
- HRD Review page
- Training Record table
- Reports export if training type is displayed
- Filter dropdown if training type filter exists
2. Internal values should stay in English-friendly constants.
Recommended internal values:
- INTERNAL_TRAINING
- EXTERNAL_TRAINING
- ONLINE_COURSE
- OJT
Display labels:
- อบรมภายใน (Internal Training)
- อบรมภายนอก (Public Training)
- e-Learning / Online Course
- On the Job Training (OJT)
3. Backward compatibility:
If old values exist in database, map them safely:
Old value -> New display/value:
- INTERNAL -> INTERNAL_TRAINING
- EXTERNAL -> EXTERNAL_TRAINING
- ONLINE -> ONLINE_COURSE
- ONSITE -> EXTERNAL_TRAINING or keep display as "อบรมภายนอก (Public Training)" unless business rule says otherwise
Do not break old records.
4. Validation:
Update Zod schema to allow only the new training type values.
If old records are edited:
- normalize old value to new value before saving if appropriate.
Thai validation message:
- กรุณาเลือกประเภทการอบรม
5. Files likely involved:
- src/features/training-records/constants/training-record-options.ts
- src/features/training-records/schemas/training-record.ts
- src/features/training-records/components/training-record-form.tsx
- src/features/training-records/components/training-record-view-page.tsx
- src/features/training-records/components/training-record-review-page.tsx
- src/features/training-records/components/training-record-tables/columns.tsx
- src/constants/thai-labels.ts
- src/features/reports/server/report-data.ts
- src/app/api/training-records/route.ts
- src/app/api/training-records/[id]/route.ts
6. Output Review File
Create:
docs/management-change-training-type-options-review.md
Include:
1. Summary
2. Files Changed
3. Training Type Options Updated
4. Backward Compatibility Mapping
5. Validation Rules
6. UI Changes
7. Report/Filter Impact
8. Manual Test Checklist
9. Known Limitations
Manual Test Checklist:
- Create form shows only 4 new training type options.
- Edit form shows only 4 new training type options.
- Training detail displays Thai/English label correctly.
- HRD review displays training type correctly.
- Training table displays training type correctly.
- Reports display training type correctly.
- Old INTERNAL value still displays safely.
- Old EXTERNAL value still displays safely.
- Old ONLINE value maps to e-Learning / Online Course.
- Old ONSITE value maps safely.
- Validation blocks empty training type.
- Mobile dropdown works.
Return:
- Complete code changes with file paths.
- Content of docs/management-change-training-type-options-review.md.

View File

@@ -0,0 +1,155 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current task:
Update sidebar permission for User Management menu.
Requirement:
The menu "พนักงาน" that represents User Management / login accounts must be visible only to Admin IT role.
Important constraints:
- Do NOT delete the User Management route.
- Do NOT delete APIs.
- Do NOT change database schema.
- Do NOT affect Employee Directory menu.
- Keep Thai UI.
- Minimal-impact changes only.
Business Rule:
1. Menu: พนักงาน
Purpose:
- User Management
- Login accounts
- Role
- Provider
- Keycloak mapping
Visible only to:
- admin_it
- IT Admin
- super_admin if currently used as highest role
Not visible to:
- HRD/Admin
- Employee/User
2. Menu: รายชื่อพนักงานทั้งหมด
Purpose:
- Employee Master
- Training hours
- Training history
Visible to:
- HRD/Admin
- Admin IT if allowed
- super_admin if used
3. Direct URL protection:
For User Management route:
- /dashboard/users
- /dashboard/users/\*
- related user management APIs
Only Admin IT / super_admin can access.
HRD/Admin direct URL access should be blocked:
- 403 Forbidden
or
- redirect to dashboard
4. Sidebar:
Under ข้อมูลหลัก:
For Admin IT:
- พนักงาน
- รายชื่อพนักงานทั้งหมด
- หลักสูตร
- นโยบาย
- ประกาศ
For HRD/Admin:
- รายชื่อพนักงานทั้งหมด
- หลักสูตร
- นโยบาย
- ประกาศ
For Employee:
- should not see ข้อมูลหลัก unless already allowed by current design
5. Files likely involved:
- src/config/nav-config.ts
- src/lib/auth/session.ts
- src/lib/auth/permissions.ts
- src/app/dashboard/users/page.tsx
- src/app/dashboard/users/[id]/page.tsx
- src/app/api/users/route.ts
- src/app/api/users/[id]/route.ts
- src/components/layout/app-sidebar.tsx
6. Add or reuse helper:
requireITAdmin()
or
requireUserManagementAccess()
Recommended:
function requireUserManagementAccess() {
allow roles:
- super_admin
- admin_it
}
Do not allow HRD admin.
7. Output Review File
Create:
docs/management-change-user-management-it-admin-only-review.md
Include:
1. Summary
2. Files Changed
3. Navigation Changes
4. Permission Rules
5. Route Protection
6. API Protection
7. Manual Test Checklist
8. Known Limitations
Manual Test Checklist:
- Admin IT sees พนักงาน menu.
- HRD/Admin does not see พนักงาน menu.
- Employee does not see พนักงาน menu.
- HRD/Admin still sees รายชื่อพนักงานทั้งหมด.
- Admin IT can open /dashboard/users.
- HRD/Admin cannot open /dashboard/users by direct URL.
- Employee cannot open /dashboard/users by direct URL.
- User management APIs reject HRD/Admin.
- Employee Directory is not affected.
- Other menus still work.
Return:
- Complete code changes with file paths.
- Content of docs/management-change-user-management-it-admin-only-review.md.

107
plans/change-user-menu.md Normal file
View File

@@ -0,0 +1,107 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current task:
Update User Dropdown Menu based on management feedback.
Important constraints:
- Do NOT change folder structure.
- Do NOT migrate ORM.
- Do NOT break existing Auth.js session.
- Keep Thai UI.
- Minimal-impact changes only.
Requirements:
1. In the user dropdown menu, display employee code under or near the user name/email.
Current display:
- Name
- Email
New display:
- Name
- Employee Code
- Email
Thai label:
- รหัสพนักงาน: EMP001
If employeeCode is missing:
- รหัสพนักงาน: -
2. Remove the Profile menu item from the dropdown.
Current dropdown items:
- Dashboard
- Profile
- Log out
New dropdown items:
- Dashboard
- Log out
3. Keep Dashboard menu item.
4. Keep Log out menu item.
5. Ensure employeeCode is available from:
- Auth.js session
- user query
- or existing user object
6. If employeeCode is not currently included in session:
- update session callback/type mapping safely
- do not expose sensitive fields
Files likely involved:
- src/components/layout/user-nav.tsx
- src/auth.ts
- src/lib/auth/session.ts
- src/types/next-auth.d.ts
- src/db/schema.ts only if employeeCode already exists but not selected
Output Review File:
Create:
docs/management-change-user-menu-review.md
Include:
1. Summary
2. Files Changed
3. Session Changes
4. UI Changes
5. Permission/Security Notes
6. Manual Test Checklist
7. Known Limitations
Manual Test Checklist:
- User dropdown shows name.
- User dropdown shows employee code.
- User dropdown shows email.
- Missing employee code displays "-".
- Profile menu is removed.
- Dashboard menu still works.
- Log out still works.
- No password hash or sensitive data is exposed.
- Works for Employee.
- Works for HRD.
Return:
- Complete code changes with file paths.
- Content of docs/management-change-user-menu-review.md.

View File

@@ -0,0 +1,144 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current task:
Enhance Users Management page.
Requirements:
1. Add Employee Code column to Users table.
Column order:
- Employee Code
- Name
- Department
- Position
- Role
- Status
Employee Code label:
- รหัสพนักงาน
Display:
- EMP0001
- EMP0002
- etc.
If employee code is missing:
- Display "-"
2. Update search functionality.
Current search:
- name
- email
New search:
- employeeCode
- name
- email
Search should work from a single search box.
Examples:
Search:
EMP0001
Result:
User with employee code EMP0001
Search:
อุษา
Result:
Matching employee
Search:
ausa.arun
Result:
Matching email
3. Update search placeholder.
Old:
Search users...
New:
ค้นหาด้วยรหัสพนักงาน ชื่อ หรืออีเมล...
4. Update server-side query.
Search fields:
- employeeCode
- name
- email
Do not perform client-side filtering.
5. Update sorting.
Allow sorting by:
- employeeCode
- name
6. Responsive.
Desktop:
Show Employee Code column.
Mobile:
Employee Code must remain visible.
Hide less important columns first:
- Position
- Email
- Role
7. Files likely involved:
- src/features/users/components/users-table.tsx
- src/features/users/components/users-columns.tsx
- src/features/users/server/user-data.ts
- src/features/users/api/types.ts
- src/app/dashboard/users/page.tsx
8. Output Review File
Create:
docs/management-change-users-employee-code-review.md
Include:
1. Summary
2. Files Changed
3. Table Changes
4. Search Changes
5. Sorting Changes
6. Responsive Changes
7. Manual Test Checklist
8. Known Limitations
Manual Test Checklist:
- Employee Code column appears.
- Employee Code sorting works.
- Search by Employee Code works.
- Search by Name works.
- Search by Email works.
- Placeholder updated.
- Missing employee code displays "-".
- Mobile layout works.
- Table does not overflow.

View File

@@ -0,0 +1,83 @@
ช่วยปรับหน้า "บทเรียนออนไลน์" ให้เหมือนหน้า "ประวัติการอบรม"
สิ่งที่ต้องแก้:
1. เอา Card ที่ครอบตารางรายการบทเรียนออกทั้งหมด
- ลบ <Card>
- ลบ <CardContent>
- ลบ padding ของ Card
- ไม่ต้องมี Shadow รอบตาราง
2. ให้ Table แสดงผลเหมือนหน้า "ประวัติการอบรม" ทุกประการ
- Table อยู่ต่อจาก Search/Filter ทันที
- ใช้ DataTable Component เดียวกัน
- ใช้ border และ rounded ของ DataTable เหมือนหน้า "ประวัติการอบรม"
- ใช้ spacing เดียวกัน
3. Search / Filter ยังอยู่ใน Card เหมือนเดิม
แต่ส่วนรายการ Table ไม่ต้องอยู่ใน Card
ตัวอย่าง Layout ที่ต้องการ
---
หัวข้อ
Card
├── Search
├── Filter
└── View
DataTable
├── Header
├── Rows
├── Pagination
└── Total
---
ไม่ต้องเป็น
---
Card
DataTable
---
4. Pagination และจำนวนรายการ
ให้แสดงเหมือนหน้า "ประวัติการอบรม"
เช่น
ทั้งหมด 5 รายการ
จำนวนต่อหน้า [10]
หน้า 1 จาก 1
5. Table ต้องใช้ Layout เดียวกับหน้า "ประวัติการอบรม"
- overflow-x-auto
- rounded-lg border
- table-fixed
- hover row
- row height
- header style
- spacing
- badge
- action menu
เหมือนกันทั้งหมด
6. ห้ามแก้ Business Logic
- API
- Query
- Data
- Columns
แก้เฉพาะ Layout
ผลลัพธ์ที่ต้องการ
หน้า "บทเรียนออนไลน์" มี Layout เหมือนหน้า "ประวัติการอบรม" โดย Search/Filter อยู่ด้านบน และตารางแสดงต่อทันทีโดยไม่มี Card ครอบตาราง

48
plans/data-ordering.md Normal file
View File

@@ -0,0 +1,48 @@
## Data Ordering Standard
ทุกหน้าที่เป็นรายการข้อมูลในระบบ ให้เรียงลำดับข้อมูลโดยอ้างอิงจากรายการที่สร้างล่าสุดก่อนเสมอ
### Default Sort
ให้ใช้ค่า Default Sort เป็น
created_at DESC
หรือ
createdAt DESC
ขึ้นอยู่กับชื่อ field ในระบบ
### หลักการ
- รายการที่สร้างใหม่ต้องแสดงอยู่ด้านบนสุด
- ห้ามใช้ training_date / วันที่อบรม เป็น default sort
- ห้ามใช้ updated_at เป็น default sort เว้นแต่หน้านั้นเป็น audit/history โดยเฉพาะ
- หากผู้ใช้กด sort เอง ให้ใช้ sort ตามที่ผู้ใช้เลือก
- เมื่อ clear filter หรือ reload หน้า ให้กลับมาเรียงตาม created_at DESC
### Scope
ให้ปรับทุกหน้าที่เป็นรายการข้อมูล เช่น
- รอตรวจสอบ
- ประวัติการอบรม
- บทเรียนออนไลน์
- ประกาศ
- รายงาน
- รายการอนุมัติ
- รายการ import
- หน้าจัดการ master data
### API Requirement
หากเป็น Server-side pagination/filter ให้ API ต้อง sort ด้วย created_at DESC เป็นค่าเริ่มต้น
ตัวอย่าง Prisma:
```ts
orderBy: {
created_at: "desc";
}
```

View File

@@ -0,0 +1,26 @@
แก้ไขหน้า Employee Directory เฉพาะตารางรายการพนักงาน
ต้องการให้ตารางไม่แสดงคอลัมน์:
- ฝ่าย
- ตำแหน่ง
สิ่งที่ต้องแก้:
1. ลบ column `department` หรือ `ฝ่าย` ออกจาก columns ของ DataTable
2. ลบ column `position` หรือ `ตำแหน่ง` ออกจาก columns ของ DataTable
3. ปรับ Header Group `ชั่วโมงการอบรม (ชม.)` ให้ `colSpan` และตำแหน่งใหม่ถูกต้อง หลังจากลบ 2 คอลัมน์แล้ว
4. ปรับ `min-w` ของ Table ให้เล็กลง เช่น จาก `min-w-[1200px]` เหลือประมาณ `min-w-[850px]` หรือ `min-w-[900px]`
5. ปรับความกว้าง column ที่เหลือให้สมดุล:
- รหัสพนักงาน 140px
- ชื่อพนักงาน 260px
- อนุมัติแล้ว 120px
- รอตรวจสอบ 120px
- ไม่อนุมัติ 120px
- รวมชั่วโมง 120px
- Actions 60px
6. ไม่ต้องแก้ API / Query / Business Logic
7. แก้เฉพาะ columns, table layout, className และ header group เท่านั้น
ผลลัพธ์ที่ต้องการ:
ตารางแสดงเฉพาะ รหัสพนักงาน, ชื่อพนักงาน, ชั่วโมงการอบรม และปุ่มจัดการ โดยไม่แสดงฝ่ายกับตำแหน่ง

View File

@@ -0,0 +1,510 @@
# Employee Create Training Record Audit (Read Only)
## Role
You are a Senior Full Stack Engineer, QA Engineer, UX/UI Reviewer, Security Reviewer, and Product Analyst.
Your task is to perform a comprehensive READ-ONLY audit of the Employee Create Training Record page.
Do NOT modify any source code.
Do NOT refactor code.
Do NOT format files.
Do NOT create pull requests.
Do NOT implement fixes.
Only inspect, analyze, and create an audit report.
---
## Before Starting
Review:
1. AGENTS.md
2. docs/AI_DEVELOPMENT_GUIDE.md
3. docs/PROJECT_ARCHITECTURE.md
Then inspect the existing implementation and follow existing project patterns.
---
## Scope
Review everything related to the Employee Create Training Record page, including:
- Route
- Page
- Layout
- Form components
- Input fields
- Select fields
- Date picker
- Time / hour input
- Training type
- Location type
- Provider / institute
- Note
- Online URL
- Certificate / evidence upload
- Submit button
- Cancel / back button
- Validation
- Duplicate warning
- Loading state
- Error state
- Success feedback
- API
- Mutation
- Server action
- Services
- Types
- Role guards
- Navigation menu
---
## Functional Review
Verify whether the page correctly supports:
- Employee can create own training record
- Employee cannot create record for another employee
- Required fields are validated
- Course name is required
- Training date is required
- Training hours support hour and minute format
- Training type works correctly
- Location type works correctly
- Provider / institute works correctly
- Note works correctly
- Online URL works correctly
- Certificate / evidence upload works correctly
- Duplicate training warning works correctly
- Submit loading state works correctly
- Submit success message works correctly
- Submit error message works correctly
- Redirect or refresh after submit works correctly
- Created record status is correct
- Created record waits for HRD review
- Employee cannot set K / S / A category
- Employee cannot set approval status
Document all missing or incorrect behavior.
---
## Business Rule Review
Verify the page follows Training System requirements:
- Employee submits training records for themselves only
- Employee cannot edit HRD-only fields
- HRD assigns K / S / A later
- HRD verifies and approves later
- Employee cannot approve own record
- Employee cannot change approval status
- Calendar year is handled correctly
- Training hours support hours and minutes
- Certificate attachment allows 1 file only
- Certificate/evidence rules match project requirements
- Online training URL rules are consistent
- Duplicate course behavior is warn but allow save
- New record should appear in Pending Review / History correctly
---
## Role Review
Review Employee permissions.
Verify the Employee can:
- Open create training record page
- Create own training record
- Upload own certificate/evidence
- Submit own online URL
- Cancel and return to history/dashboard
Verify the Employee cannot:
- Create training record for another employee
- Access HRD/Admin create/edit pages
- Assign K / S / A category
- Approve/reject records
- Edit HRD-only fields
- Change status manually
- Upload multiple certificate files if only 1 is allowed
- Bypass validation through direct API call
Check both:
- UI-level permission
- Server/API-level permission
---
## UI Review
Inspect:
- Form layout
- Field grouping
- Label clarity
- Placeholder clarity
- Required field indication
- Date picker UI
- Hour/minute input UI
- Select dropdown consistency
- Upload component UI
- Button style
- Icon consistency
- Spacing
- Typography
- Mobile layout
- Tablet layout
- Desktop layout
- Loading display
- Error display
- Success display
---
## UX Review
Evaluate:
- Is the form easy for employees to understand?
- Are required fields obvious?
- Is hour/minute entry clear?
- Is upload instruction clear?
- Is online URL instruction clear?
- Is duplicate warning understandable?
- Is submit feedback clear?
- Is error feedback helpful?
- Is cancel/back behavior clear?
- Does the page prevent accidental duplicate submission?
Suggest improvements only.
Do not implement.
---
## Accessibility Review
Inspect:
- Keyboard navigation
- Focus state
- Input labels
- Error message association
- Button labels
- Icon-only button accessibility
- File upload accessibility
- Date picker accessibility
- Select accessibility
- Color contrast
- Screen reader text
---
## Code Review
Inspect:
### Architecture
- Folder structure
- Feature separation
- Component reuse
- Shared form usage
- Shared validation usage
- Shared upload usage
### React
- Client vs Server Components
- Hooks usage
- Form state handling
- Mutation state handling
- Memoization
- Unnecessary rerenders
### TypeScript
- Strong typing
- Nullable fields
- Enum usage
- Form types
- API response types
- Validation schema types
### Code Quality
- Duplicate logic
- Dead code
- Naming consistency
- Import consistency
- Unused files
- Unused components
- Overly large components
Do NOT change anything.
---
## API Review
Inspect:
- Create mutation
- Request body
- Response shape
- Error handling
- Validation
- File upload handling
- Duplicate check handling
- Authorization checks
- Server-side employee ownership check
- Cache invalidation after create
- Redirect/refresh behavior after create
---
## Security Review
Review:
- Authentication
- Authorization
- Role guard
- Route guard
- API protection
- Server-side validation
- Employee ownership validation
- File upload validation
- File type validation
- File size validation
- Direct API call protection
- Sensitive data exposure
---
## Performance Review
Inspect:
- Form rendering performance
- Upload performance
- Large file handling
- Mutation handling
- Query invalidation
- Unnecessary client rendering
- Heavy components
- Lazy loading opportunities
---
## Data Validation Review
Check:
- Missing course name
- Missing training date
- Missing training hours
- Invalid hour/minute format
- Zero hour behavior
- Over 30 hours behavior
- Missing training type
- Missing location type
- Missing provider
- Invalid online URL
- Missing certificate when required
- Multiple file upload
- Invalid file type
- Invalid file size
- Null handling
- Incorrect defaults
---
## Edge Case Review
Check behavior for:
- New employee
- Employee profile missing
- No course master
- Course name duplicate
- Training date in future
- Training date in previous year
- 00:00 hours
- 00:15 hours
- 01:45 hours
- 30:00 hours
- More than 30 hours
- Online training without URL
- Offline training with URL
- File upload failed
- API failure
- Slow network
- Double submit
- Permission denied
---
## Deliverable
Create this report only:
docs/review/employee-create-training-record-audit.md
Do not create or modify any other file.
---
## Report Structure
# Employee Create Training Record Audit Report
## Executive Summary
Overall Status:
- Excellent
- Good
- Needs Improvement
- Critical
Brief summary of findings.
---
## Scope Reviewed
List reviewed routes, files, components, APIs, and permissions.
---
## Functional Review
| Feature | Status | Notes |
| ------- | ------ | ----- |
---
## Business Rule Review
| Rule | Status | Notes |
| ---- | ------ | ----- |
---
## Role & Permission Review
| Permission | Status | Notes |
| ---------- | ------ | ----- |
---
## UI Review
---
## UX Review
---
## Accessibility Review
---
## Code Quality Review
---
## API Review
---
## Security Review
---
## Performance Review
---
## Data Validation Review
---
## Edge Case Review
---
## Problems Found
Group by severity.
### Critical
### High
### Medium
### Low
For each issue include:
- Description
- File
- Component
- Severity
- Impact
- Recommendation
Do NOT fix the issue.
---
## Missing Features
List missing or incomplete functionality.
---
## Improvement Opportunities
Suggest improvements only.
Do NOT implement them.
---
## Final Assessment
Architecture: /10
Functionality: /10
Role & Permission: /10
UI: /10
UX: /10
Accessibility: /10
Security: /10
Performance: /10
Maintainability: /10
Overall Score: /10
---
## Important Rules
- READ ONLY
- No source code changes
- No refactoring
- No formatting changes
- No implementation
- No automatic fixes
- No pull request
- Only create `docs/review/employee-create-training-record-audit.md`
- Every issue should include file path and evidence where possible

View File

@@ -0,0 +1,634 @@
# Prompt: Employee Directory UX/UI Redesign
## Objective
ปรับปรุงหน้า **Employee Directory (รายชื่อพนักงานทั้งหมด)** ให้ใช้งานได้ดีขึ้นสำหรับระบบ Training Management System (TMS)
เป้าหมายคือ
- ลดพื้นที่ว่างด้านบน
- แสดงข้อมูลได้มากขึ้นโดยไม่ต้อง Scroll
- จัดลำดับข้อมูลใหม่ให้อ่านง่าย
- ปรับ Data Table ให้เป็น Enterprise UX
- ยังคงใช้ Design System ปัจจุบัน (shadcn/ui + TailwindCSS)
- ห้ามเปลี่ยน Business Logic
- ห้ามเปลี่ยน API
- ห้ามเปลี่ยน Permission
- ห้ามแก้ไข Workflow
---
# Requirements
## 1. Header
ปรับ Header ใหม่
Desktop
```
Dashboard / Employee Directory
รายชื่อพนักงานทั้งหมด
เรียกดูข้อมูลพนักงานและข้อมูลชั่วโมงการอบรมรายบุคคล
[+ สร้างรายชื่อพนักงาน]
[Import รายชื่อพนักงาน]
```
### Requirements
- ลด Vertical Space
- ปุ่มอยู่ด้านขวา
- Responsive
- Mobile ให้ปุ่มลงบรรทัดใหม่
---
## 2. Search & Filter Toolbar
เปลี่ยน Toolbar ใหม่
Desktop
```
[ Search................................ ]
[ บริษัท ▼ ]
[ ฝ่าย ▼ ]
[ สถานะ ▼ ]
[ รีเซ็ตตัวกรอง ]
```
### Search
Placeholder
```
ค้นหารหัสพนักงาน ชื่อพนักงาน...
```
Search Width
Desktop
```
ประมาณ 420-520px
```
### Filter
แสดงในแถวเดียว
ประกอบด้วย
- Company
- Department
- Status
ถ้ามี Filter อื่นอยู่แล้ว
ให้คงไว้
### Reset Filter
เพิ่มปุ่ม
```
รีเซ็ตตัวกรอง
```
ใช้ Button Ghost
---
## 3. Remove View Button
ตรวจสอบ
```
View
```
ด้านขวาของ Table
### กรณี
ไม่มีการสลับ
- Card View
- Compact View
- List View
ให้ลบออก
### หากเป็น Column Visibility
ให้เปลี่ยนข้อความเป็น
```
แสดงคอลัมน์
```
---
## 4. Summary Section
เพิ่ม Summary Cards
อยู่ระหว่าง
Toolbar
กับ
Data Table
Layout
Desktop
```
┌────────────┐
│ พนักงานทั้งหมด │
│ 1,254 คน │
└────────────┘
┌────────────┐
│ อนุมัติแล้ว │
│ 950 รายการ │
└────────────┘
┌────────────┐
│ รอตรวจสอบ │
│ 48 รายการ │
└────────────┘
┌────────────┐
│ ชั่วโมงรวม │
│ 28,560 ชม. │
└────────────┘
```
Requirements
- ใช้ Card ขนาดเล็ก
- Border ตาม Design System
- ไม่มี Shadow หนัก
- Responsive
Mobile
2 Columns
---
## 5. Data Table Header
ปัจจุบัน
Header มี 2 ชั้น
```
ชั่วโมงการอบรม
อนุมัติแล้ว
รอตรวจสอบ
ไม่อนุมัติ
รวม
```
ให้ปรับเหลือ
```
รหัสพนักงาน
ชื่อพนักงาน
อนุมัติแล้ว
รอตรวจสอบ
ไม่อนุมัติ
รวมชั่วโมง
จัดการ
```
ไม่ต้องมี Header ซ้อน
---
## 6. Column Order
กำหนดลำดับใหม่
```
รหัสพนักงาน
ชื่อพนักงาน
อนุมัติแล้ว
รอตรวจสอบ
ไม่อนุมัติ
รวมชั่วโมง
จัดการ
```
---
## 7. Employee Information
ภายใน Column
ชื่อพนักงาน
แสดง
```
สมชาย ใจดี
somchai@example.com
```
Email
ใช้
```
text-xs
text-muted-foreground
```
### Data Consistency
ห้ามบาง Row
แสดง Company
บาง Row
แสดง Email
ต้องเป็นรูปแบบเดียวกันทั้งระบบ
---
## 8. Numeric Columns
Column
- Approved
- Pending
- Rejected
- Total
ใช้
```
tabular-nums
text-right
```
### Total Column
ให้เด่นกว่า Column อื่น
เช่น
```
font-semibold
```
---
## 9. Action Column
ปุ่ม
```
```
เพิ่มพื้นที่
ประมาณ
```
56-64px
```
เพื่อให้กดง่าย
---
## 10. Table Row Hover
เพิ่ม Hover
```
hover:bg-muted/30
```
ไม่เปลี่ยนสีแรง
---
## 11. Sticky Header
หาก Data Table รองรับ
ให้เปิด
Sticky Header
เพื่อให้ Scroll แล้ว Header ไม่หาย
---
## 12. Responsive
Desktop
แสดง Table เต็ม
Mobile
ใช้
```
overflow-x-auto
```
Table
```
min-width
```
เพื่อไม่ให้ข้อมูลพัง
---
## 13. Pagination
ปรับ Footer
จาก
```
ทั้งหมด 1,254 รายการ
จำนวนต่อหน้า
หน้า 1 จาก 126
```
เป็น
```
1,254 รายการ
10 ต่อหน้า
1 / 126
```
หาก Design System รองรับ
---
## 14. Spacing
ลด Margin
ระหว่าง
Header
Toolbar
Summary
Table
ให้ข้อมูลอยู่เหนือ Fold มากขึ้น
---
## 15. Accessibility
ตรวจสอบ
- Button
- Search
- Select
- Action Menu
ให้มี
aria-label
ครบถ้วน
---
## 16. Performance
ห้าม
- Fetch ใหม่โดยไม่จำเป็น
- Render ใหม่ทั้ง Table
- ทำให้ Pagination ช้าลง
---
## 17. Business Logic
ห้ามแก้ไข
- API
- Query
- Mutation
- Validation
- Permission
- Role
- Authorization
- Pagination Logic
- Search Logic
- Filter Logic
ให้ปรับเฉพาะ UX/UI
---
# UI Style Guide
ใช้ Design System เดิมทั้งหมด
- shadcn/ui
- TailwindCSS
- Card
- Button
- Badge
- Input
- Select
- DropdownMenu
สี
ใช้ Theme เดิม
ห้าม Hardcode สี
Spacing
ใช้ Tailwind Spacing เดิมของระบบ
Typography
ใช้ Typography เดิม
---
# Files
ตรวจสอบและแก้ไขเฉพาะไฟล์ที่เกี่ยวข้อง เช่น
- Employee Directory Page
- Employee Table
- Toolbar
- Header
- Summary Card
- Pagination
- Columns
หากสามารถแยก Component ได้
ให้แยก Component
เช่น
```
EmployeeDirectoryHeader
EmployeeDirectoryToolbar
EmployeeDirectorySummary
EmployeeDirectoryTable
```
---
# Testing
ตรวจสอบ
- Desktop
- Tablet
- Mobile
ตรวจสอบ
- Search
- Filter
- Pagination
- Sorting
- Action Menu
ว่ายังทำงานได้เหมือนเดิม
---
# Deliverables
เมื่อดำเนินการเสร็จ
สร้างเอกสาร
```
docs/employee-directory-ui-improvement-report.md
```
ประกอบด้วย
## 1. Files Changed
ระบุไฟล์ทั้งหมด
---
## 2. UI Changes
อธิบาย
ก่อน
หลัง
---
## 3. Responsive Result
Desktop
Tablet
Mobile
---
## 4. Accessibility
สิ่งที่ปรับปรุง
---
## 5. Performance
มีผลกระทบหรือไม่
---
## 6. Screens Reviewed
ระบุหน้าที่ตรวจสอบ
---
## 7. Remaining Improvements
รายการที่แนะนำในอนาคต
เช่น
- Sticky First Column
- Column Visibility
- Export CSV
- Saved Filters
- KPI Dashboard
- Skeleton Loading
- Empty State
- Bulk Actions
---
# Success Criteria
ถือว่างานเสร็จเมื่อ
- Header ใหม่ใช้งานได้
- Toolbar ใหม่ใช้งานได้
- Summary Cards แสดงผลถูกต้อง
- Data Table อ่านง่ายขึ้น
- Responsive สมบูรณ์
- ไม่มี Regression
- TypeScript ไม่มี Error
- ESLint ผ่าน
- Build ผ่าน
- Report ถูกสร้างเรียบร้อย

View File

@@ -0,0 +1,167 @@
# Change Employee Directory Table Layout
## Objective
ปรับปรุงหน้า **Employee Directory** ให้แสดงเฉพาะข้อมูลพื้นฐานของพนักงาน
หน้านี้มีวัตถุประสงค์เพื่อค้นหาและจัดการข้อมูลพนักงาน ไม่ใช่แสดงสถิติการอบรม
---
## Requirements
### Remove Training Summary Columns
นำคอลัมน์ต่อไปนี้ออกจาก Data Table
- อนุมัติแล้ว
- รอตรวจสอบ
- ไม่อนุมัติ
- รวมชั่วโมง
รวมถึงลบ Header Group "ชั่วโมงการอบรม"
---
### New Table Columns
จัดเรียงคอลัมน์ใหม่เป็น
1. รหัสพนักงาน
2. ชื่อพนักงาน
3. ตำแหน่ง
4. ฝ่าย
5. จัดการ
---
### Employee Name Column
แสดง
```
สมชาย ใจดี
somchai@example.com
```
Email ใช้
- text-xs
- text-muted-foreground
หากไม่มี Email
แสดง "-"
---
### Position Column
แสดง
```
Senior Programmer
```
หากไม่มีข้อมูล
แสดง "-"
---
### Department Column
แสดง
```
Information Technology
```
หากไม่มีข้อมูล
แสดง "-"
---
### Action Column
คง Dropdown Menu เดิมไว้
ห้ามเปลี่ยน Business Logic
---
### Search
ยังค้นหาได้เหมือนเดิม
- รหัสพนักงาน
- ชื่อพนักงาน
---
### Sorting
รองรับการเรียงลำดับ
- รหัสพนักงาน
- ชื่อ
- ตำแหน่ง
- ฝ่าย
---
### Table Width
เมื่อเอาคอลัมน์ชั่วโมงออก
ให้ปรับความกว้างใหม่
ไม่ให้มีพื้นที่ว่างเกินจำเป็น
---
### Column Width Recommendation
| Column | Width |
| ----------- | ----: |
| รหัสพนักงาน | 140px |
| ชื่อพนักงาน | 260px |
| ตำแหน่ง | 220px |
| ฝ่าย | 220px |
| จัดการ | 60px |
---
## Business Logic
ห้ามแก้ไข
- API
- Query
- Pagination
- Permission
- Validation
- Mutation
ให้เปลี่ยนเฉพาะการแสดงผลของ Data Table เท่านั้น
---
## Deliverables
หลังดำเนินการเสร็จ
สร้างเอกสาร
```
docs/employee-directory-table-redesign.md
```
ประกอบด้วย
- Files Changed
- Columns Removed
- Columns Added
- Responsive Result
- Regression Check

View File

@@ -0,0 +1,217 @@
# Requirement ที่เข้าใจ
## Objective
ปรับปรุงมาตรฐานการแสดงข้อมูลพนักงาน (Employee Information Standard) ให้เป็นรูปแบบเดียวกันทั้งระบบ TMS เพื่อให้ผู้ใช้งานสามารถค้นหาและอ่านข้อมูลได้อย่างสม่ำเสมอ ลดความสับสนในการใช้งาน
---
# Functional Requirements
## Employee Information Standard
ทุกหน้าที่มีการแสดงข้อมูลพนักงาน ให้ใช้มาตรฐานเดียวกัน ดังนี้
### ตารางข้อมูล
ให้เพิ่มคอลัมน์ **รหัสพนักงาน (Employee Code)** เป็นคอลัมน์แรกของตาราง
ลำดับข้อมูลมาตรฐาน
- รหัสพนักงาน
- ชื่อพนักงาน
- บริษัท
- แผนก
- ข้อมูลเฉพาะของแต่ละโมดูล
- สถานะ
- Action
หากบางโมดูลไม่มีข้อมูลบริษัทหรือแผนก สามารถซ่อนเฉพาะคอลัมน์นั้นได้ แต่ลำดับของ Employee Code และ Employee Name ต้องเหมือนกันทุกหน้า
---
## Search Standard
ทุกหน้าที่มีข้อมูลพนักงาน
ให้รองรับการค้นหาด้วยช่องค้นหาเดียว
สามารถค้นหาได้จาก
- Employee Code
- Employee Name
- Last Name
- Full Name
และข้อมูลเฉพาะของแต่ละโมดูล เช่น
- Course Name
- Provider
- Announcement Title
- Online Lesson Title
Placeholder ให้ใช้มาตรฐานเดียวกัน
```
ค้นหาด้วยรหัสพนักงาน ชื่อพนักงาน หรือข้อมูลที่เกี่ยวข้อง...
```
โดยสามารถปรับท้ายข้อความตามโมดูลได้ เช่น
```
ค้นหาด้วยรหัสพนักงาน ชื่อพนักงาน หลักสูตร หรือผู้จัดอบรม...
```
---
## Sorting Standard
ทุกหน้าที่ใช้ DataTable
รองรับการ Sort
- Employee Code
- Employee Name
หาก DataTable เดิมรองรับ Sorting อยู่แล้ว ให้เพิ่มเฉพาะคอลัมน์ใหม่
---
## Responsive Standard
Desktop
แสดง Employee Code เป็นคอลัมน์แรก
Mobile
ให้แสดง
Employee Code
Employee Name
เป็นข้อมูลบนสุดของ Card หรือ Row
---
## Scope of Standard
ให้ตรวจสอบและปรับทุกหน้าที่มีการแสดงข้อมูลพนักงาน เช่น
- Pending Review
- Training Records
- Employee Management
- Dashboard
- Reports
- Approval Lists
- Online Lesson Progress (ถ้ามี)
- Announcement Reader (ถ้ามีข้อมูลพนักงาน)
- หน้าจัดการอื่น ๆ ที่มีการแสดงรายชื่อพนักงาน
หากพบหน้าที่ใช้รูปแบบต่างกัน ให้ปรับเป็นมาตรฐานเดียวกัน
---
# UI/UX Requirements
ทุกหน้าต้องใช้มาตรฐานเดียวกัน
- Employee Code อยู่ก่อน Employee Name
- ชื่อคอลัมน์ใช้ข้อความเดียวกัน
- Placeholder ใช้มาตรฐานเดียวกัน
- Search Logic เหมือนกัน
- Sorting เหมือนกัน
- Responsive เหมือนกัน
ห้ามแต่ละหน้ามีพฤติกรรมแตกต่างกันโดยไม่มีเหตุผลทาง Business
---
# Technical Requirements
ก่อนแก้ไข
- Audit ทุกหน้าที่แสดงข้อมูลพนักงาน
- ตรวจสอบ Shared DataTable
- ตรวจสอบ Shared Search Component
- ตรวจสอบ Shared Column Definition
- ตรวจสอบ API ที่รองรับ Employee Code
หากพบ Logic ซ้ำ
ให้ Refactor เป็น Shared Component หรือ Shared Utility
ห้าม Copy Code
---
# Scope of Work
- ปรับเฉพาะส่วนการแสดงข้อมูลพนักงาน
- ไม่เปลี่ยน Business Logic ของแต่ละโมดูล
- ไม่เปลี่ยน Permission
- ไม่เปลี่ยน Workflow
- ไม่กระทบ API หากสามารถใช้ข้อมูลเดิมได้
- หาก API ยังไม่ส่ง Employee Code ให้เพิ่มเฉพาะ Field ที่จำเป็น
---
# Acceptance Criteria
✅ Employee Code เป็นคอลัมน์แรกทุกหน้า
✅ Search รองรับ Employee Code และ Employee Name
✅ Placeholder ใช้มาตรฐานเดียวกัน
✅ Sort Employee Code ได้
✅ Sort Employee Name ได้
✅ Responsive แสดงผลถูกต้อง
✅ ไม่มี Regression
---
# Deliverables
- ปรับทุกหน้าที่แสดงข้อมูลพนักงานให้ใช้มาตรฐานเดียวกัน
- ตรวจสอบ TypeScript Error
- ตรวจสอบ ESLint
- ตรวจสอบ Build
- ตรวจสอบ Search
- ตรวจสอบ Sorting
- ตรวจสอบ Responsive
- ตรวจสอบ Regression
สร้างเอกสาร
docs/employee-information-ui-standard-implementation-report.md
ประกอบด้วย
1. Executive Summary
2. Standard Definition
3. Pages Updated
4. Files Modified
5. API Changes
6. UI Changes
7. Search Changes
8. Sorting Changes
9. Responsive Changes
10. Regression Review
11. Test Checklist
12. Recommendation

View File

@@ -0,0 +1,346 @@
# Sprint 6.12 UI Enhancement Employee Directory (HR Master)
You are a Senior Full Stack Engineer, UI/UX Engineer, and Solution Architect.
Project:
Training Management System (TMS)
Current Status:
Sprint 6.11 Identity / Employee Cleanup completed.
Current Task:
Redesign the **รายชื่อพนักงานทั้งหมด (Employee Directory)** page to become the central HR Employee Directory.
---
## Objective
Transform the page into a professional Employee Directory similar to modern HRIS systems.
This page is **NOT User Management**.
This page represents **Employee Master Data**.
All employee information must come from the **employees** table.
Do NOT use `users` as the primary data source.
---
# Data Source
Primary Table
employees
Related Tables
- training_records
- employee_training_targets
- departments
- companies
- positions
- training_policy (fallback only)
Never use users as employee master.
Employees without login accounts must still appear in this page.
---
# Page Layout
Top Section
Title
รายชื่อพนักงานทั้งหมด
Description
เรียกดูข้อมูลพนักงาน ข้อมูลชั่วโมงการอบรม และประวัติการอบรมรายบุคคล
---
Top Right Actions
Create two action buttons
Primary Button
- สร้างรายชื่อพนักงาน
Route
/dashboard/employee-directory/create
Secondary Button
Import รายชื่อพนักงาน
Route
/dashboard/import-employees
Buttons should remain responsive.
Desktop
[ + สร้างรายชื่อพนักงาน ]
[ Import รายชื่อพนักงาน ]
Mobile
Stack vertically.
---
Search Area
Large Search Box
Placeholder
ค้นหาด้วยรหัสพนักงาน ชื่อ ฝ่าย หรือตำแหน่ง...
Search Fields
- employeeCode
- displayName
- email
- department
- position
---
Filters
Add Filter Row
- บริษัท
- ฝ่าย
- ตำแหน่ง
- สถานะ
Use existing filter components.
---
Employee Table
Columns
1. รหัสพนักงาน
2. ชื่อพนักงาน
3. ฝ่าย
4. ตำแหน่ง
Training Hours
Group Header
ชั่วโมงการอบรม (ชม.)
Sub Columns
- อนุมัติแล้ว
- รอตรวจสอบ
- ไม่อนุมัติ
- รวมชั่วโมง
Action Column
Header
จัดการ
Button
ดูข้อมูลพนักงาน
OR
Three-dot action menu
Dropdown
- ดูข้อมูลพนักงาน
- แก้ไขข้อมูลพนักงาน
- กำหนดเป้าหมาย K/S/A (HRD Only)
---
Training Hour Logic
Calculate from
training_records.employee_id
Approved Hours
status = APPROVED
Pending Hours
status = PENDING
Rejected Hours
status = REJECTED
Total Hours
approved + pending + rejected
Do not calculate from users.
---
Employee Detail
Route
/dashboard/employee-directory/[employeeId]
Show
ข้อมูลทั่วไป
- รูปภาพ (ถ้ามี)
- รหัสพนักงาน
- ชื่อ
- อีเมล
- บริษัท
- ฝ่าย
- ตำแหน่ง
- สถานะ
Training Summary
- ชั่วโมงอนุมัติ
- ชั่วโมงรอตรวจสอบ
- ชั่วโมงไม่อนุมัติ
- ชั่วโมงรวม
- เป้าหมาย K
- เป้าหมาย S
- เป้าหมาย A
- Progress
Training History
Table
- วันที่
- หลักสูตร
- ประเภท
- ชั่วโมง
- สถานะ
- เกียรติบัตร
---
Permission
HRD/Admin
- View all employees
- Create employee
- Import employee
- Edit employee
- Set K/S/A Target
Employee
Cannot access Employee Directory.
---
Responsive
Desktop
Same layout as design.
Tablet
Filters wrap.
Buttons wrap.
Table scrolls horizontally.
Mobile
Cards stack.
Table stays inside scroll container.
No page overflow.
---
Files
Navigation
src/config/nav-config.ts
Pages
src/app/dashboard/employee-directory/page.tsx
src/app/dashboard/employee-directory/[employeeId]/page.tsx
Feature
src/features/employee-directory/\*
Server
src/features/employee-directory/server/employee-directory-data.ts
---
Output Review File
Create
docs/sprint-6-12-employee-directory-ui-review.md
Include
1. Summary
2. Files Changed
3. UI Improvements
4. Data Source Validation
5. Training Hour Calculation
6. Responsive Changes
7. Permission Rules
8. Manual Test Checklist
9. Known Limitations
Manual Checklist
✓ Employee Directory reads from employees.
✓ Employees without user account are displayed.
✓ Search works.
✓ Filters work.
✓ Create Employee button works.
✓ Import Employee button works.
✓ Training hour calculation uses training_records.employee_id.
✓ Employee detail works.
✓ Responsive layout works.
Return
- Complete code changes with file paths.
- Review document.
- Migration commands if required.

View File

@@ -0,0 +1,90 @@
# Task: เอาข้อมูลชั่วโมงรวม, ชั่วโมง K, ชั่วโมง S, ชั่วโมง A ออกจาก Import พนักงาน
ก่อนเริ่มแก้ไข กรุณาอ่านและปฏิบัติตาม `AGENTS.md` อย่างเคร่งครัด และตรวจสอบโครงสร้างเดิมก่อนแก้ไข
## เป้าหมาย
ปรับฟีเจอร์ Import พนักงาน ไม่ให้รับข้อมูลชั่วโมงสรุปจากไฟล์ Excel โดยตรง ได้แก่
- ชั่วโมงรวม
- ชั่วโมง K
- ชั่วโมง S
- ชั่วโมง A
เนื่องจากชั่วโมงเหล่านี้ต้องถูกคำนวณจาก Training Record จริงของพนักงาน ไม่ควรกรอกจากไฟล์ Import
## สิ่งที่ต้องแก้ไข
1. ตรวจสอบไฟล์ที่ประกาศหัวตาราง Import เช่น `thaiImportTemplateHeaders`
2. ลบหัวตารางต่อไปนี้ออกจาก Template Import:
- ชั่วโมงรวม
- ชั่วโมง K
- ชั่วโมง S
- ชั่วโมง A
3. ตรวจสอบ API ดาวน์โหลด Template:
- `/api/import-employees/template`
- ให้ไฟล์ Excel Template ที่ดาวน์โหลด ไม่มีคอลัมน์ชั่วโมงรวม/K/S/A แล้ว
4. ตรวจสอบ Logic Parse Excel:
- ห้ามอ่านค่า `total_hours`
- ห้ามอ่านค่า `k_hours`
- ห้ามอ่านค่า `s_hours`
- ห้ามอ่านค่า `a_hours`
5. ตรวจสอบ Validation:
- ลบ validation ที่บังคับหรือ validate ช่องชั่วโมงรวม/K/S/A
- ห้ามแจ้ง error หากไฟล์ไม่มีคอลัมน์เหล่านี้
6. ตรวจสอบ Import Logic:
- ห้ามนำค่าชั่วโมงรวม/K/S/A จาก Excel ไป update Employee หรือ Summary โดยตรง
- Summary ชั่วโมงต้องคำนวณใหม่จาก Training Record จริงเท่านั้น
7. ตรวจสอบ UI หน้า `/dashboard/import-employees`:
- ไม่ต้องแสดงข้อความว่า Import เป้าหมาย K/S/A
- ปรับข้อความให้เหลือเฉพาะ Import ข้อมูลพนักงานและประวัติการอบรม
- ไม่ต้องแสดงหัวตารางชั่วโมงรวม/K/S/A ในรายการหัวตาราง Template
## ข้อความ UI ที่ต้องการ
แก้ข้อความคำอธิบายเป็นประมาณนี้:
- อัปโหลดไฟล์ Excel `.xlsx` เพื่อเพิ่มหรืออัปเดตข้อมูลพนักงานและประวัติการอบรม
- ระบบจะนับรหัสพนักงาน 1 รหัสเป็นพนักงาน 1 คน หากพนักงานมีหลายหลักสูตร ระบบจะสร้างข้อมูลพนักงานเพียง 1 รายการ และบันทึกประวัติการอบรมทุกหลักสูตรเป็น Training Record
- ระบบจะคำนวณชั่วโมงสรุปจาก Training Record ให้อัตโนมัติ
## สิ่งที่ห้ามทำ
- ห้ามลบการบันทึก Training Record
- ห้ามลบ logic การคำนวณ Summary จาก Training Record
- ห้ามแก้ส่วนอื่นที่ไม่เกี่ยวข้อง
- ห้ามสร้าง schema/service/component ใหม่ถ้ามีของเดิมอยู่แล้ว
- ห้ามใช้ค่าชั่วโมงรวม/K/S/A จาก Excel เป็น source of truth
## Acceptance Criteria
หลังแก้ไขต้องได้ผลลัพธ์ดังนี้:
1. Template Import ไม่มีคอลัมน์:
- ชั่วโมงรวม
- ชั่วโมง K
- ชั่วโมง S
- ชั่วโมง A
2. Import ไฟล์ที่ไม่มีคอลัมน์เหล่านี้ได้สำเร็จ
3. ระบบยังสร้าง Employee ได้ถูกต้อง:
- รหัสพนักงานเดียวกัน = Employee 1 รายการ
4. ระบบยังสร้าง Training Record ครบทุกแถว
5. Summary ชั่วโมงของพนักงานยังถูกคำนวณจาก Training Record จริง
6. หน้า `/dashboard/import-employees` แสดงข้อความถูกต้อง และไม่มีข้อความเกี่ยวกับการ Import เป้าหมาย K/S/A
7. หลังแก้ไขเสร็จ ให้สรุปใน `report.md` ว่า:
- แก้ไฟล์ใดบ้าง
- ลบคอลัมน์ใดออก
- ปรับ logic ส่วนใด
- วิธีทดสอบ
- ผลการทดสอบ

View File

@@ -0,0 +1,908 @@
# Task: Refactor Employee Directory Filters to Single Select
## Objective
ปรับปรุงระบบ Filter ในหน้ารายชื่อพนักงาน (Employee Directory)
ปัจจุบัน Filter
- บริษัท
- ฝ่าย
- ตำแหน่ง
- สถานะ
เป็นรูปแบบที่สามารถเลือกได้หลายค่า (Multi Select)
ต้องการเปลี่ยนให้เป็น **Single Select** ทั้งหมด โดยสามารถเลือกได้เพียง 1 ค่าในแต่ละ Filter เพื่อให้ UX และมาตรฐานของระบบเหมือนกับหน้าบทเรียนออนไลน์
---
# Requirements
## 1. เปลี่ยน Filter เป็น Single Select
เปลี่ยน Filter ต่อไปนี้
- บริษัท
- ฝ่าย
- ตำแหน่ง
- สถานะ
จาก
Multi Select
เป็น
Single Select
สามารถเลือกได้เพียงค่าเดียว
ตัวอย่าง
เดิม
บริษัท
☑ ALLA
☑ ONVALLA
ใหม่
บริษัท
○ ALLA
○ ONVALLA
เลือกได้เพียงค่าเดียว
---
## 2. ใช้ Component มาตรฐานเดียวกับระบบ
ห้ามสร้าง Component ใหม่
ให้ใช้ Select Component เดียวกับที่ใช้งานใน
- Online Lessons
- Training Records
- Announcement
- Module อื่นที่ใช้ Select
เพื่อให้ UI และ UX เหมือนกันทั้งระบบ
---
## 3. Placeholder
แต่ละ Select
บริษัท
```
เลือกบริษัท
```
ฝ่าย
```
เลือกฝ่าย
```
ตำแหน่ง
```
เลือกตำแหน่ง
```
สถานะ
```
เลือกสถานะ
```
---
## 4. Clear Filter
เมื่อมีการเลือกค่าแล้ว
ต้องสามารถ
Clear
กลับเป็น
```
ทั้งหมด
```
ได้
โดยใช้รูปแบบเดียวกับหน้าอื่นของระบบ
---
## 5. URL Search Params
ต้องยังรองรับ
Server Side Filtering
เหมือนเดิม
เช่น
```
?company=1
```
```
?department=15
```
```
?position=6
```
```
?status=active
```
โดย
แต่ละ parameter
ต้องมีค่าเดียวเท่านั้น
ไม่ต้องรองรับ array
ห้ามส่ง
```
company=1,2
```
หรือ
```
company[]=1
```
---
## 6. Backend
ตรวจสอบ API
ให้รองรับ
Single Value
เท่านั้น
เช่น
```
company=1
```
ไม่ต้องรองรับ
```
company[]=1&company[]=2
```
หากยังมี Logic Array
ให้ Refactor ออก
---
## 7. State Management
State ของ Filter
ควรเป็น
```
company?: string
department?: string
position?: string
status?: string
```
ไม่ควรเป็น
```
string[]
```
หรือ
```
Set<string>
```
---
## 8. UX
เมื่อเลือกค่า
ให้ Reload/Search
ทันที
ไม่ต้องกดปุ่ม Search
Behavior ต้องเหมือนหน้า
Online Lessons
---
## 9. Performance
ห้าม Fetch Master Data ซ้ำ
หากมี Cache
ให้ใช้ของเดิม
---
## 10. Consistency
ตรวจสอบทุกจุดที่ใช้ Employee Directory Filter
ให้เป็นมาตรฐานเดียวกัน
เช่น
- Toolbar
- Search Params
- API
- Table Refresh
- Pagination
ต้องยังทำงานถูกต้องทั้งหมด
---
# Acceptance Criteria
- บริษัทเป็น Single Select
- ฝ่ายเป็น Single Select
- ตำแหน่งเป็น Single Select
- สถานะเป็น Single Select
- เลือกได้เพียง 1 ค่า
- Clear Filter ได้
- URL ใช้ค่าเดียว
- Backend รองรับค่าเดียว
- Pagination ยังทำงาน
- Sorting ยังทำงาน
- Search ยังทำงาน
- Auto Refresh หลังเลือก Filter
- ใช้ Select Component มาตรฐานเดียวกับระบบ
- ไม่สร้าง UI Component ใหม่
- TypeScript ผ่าน
- ESLint ผ่าน
- Build ผ่าน
---
# 11. UI/UX Improvement Requirements
นอกจากการเปลี่ยน Filter เป็น Single Select แล้ว ให้ปรับปรุง Layout และประสบการณ์การใช้งาน (UX) ของ Toolbar ให้เป็นมาตรฐานเดียวกับทั้งระบบ
## 11.1 จัด Layout ใหม่
จัดเรียง Toolbar ใหม่ให้อ่านง่ายและใช้งานสะดวก
ตัวอย่าง
---
ค้นหา.......................................................
[บริษัท ▼] [ฝ่าย ▼] [ตำแหน่ง ▼] [สถานะ ▼]
[Reset Filter]
---
ห้ามวาง Filter แบบกระจัดกระจายหรือขนาดไม่เท่ากัน
---
## 11.2 ขนาดของ Select
กำหนดขนาดของ Select ทุกตัวให้เท่ากัน
เช่น
```
min-w-[180px]
```
หรือ
```
w-44
```
แล้วแต่ Design System ของโปรเจกต์
ทุก Filter ต้องมีความสูงและระยะห่างเท่ากัน
---
## 11.3 ใช้มาตรฐานเดียวกับระบบ
Select
Search
Toolbar
Spacing
Border Radius
Height
Padding
Typography
ต้องใช้ Component และ Style เดียวกับ
- Online Lessons
- Announcements
- Training Records
- Module อื่นของ Dashboard
ห้ามสร้าง Design ใหม่
---
## 11.4 Reset Filters
เพิ่มปุ่ม
```
ล้างตัวกรอง
```
หรือ
```
Reset Filters
```
แสดงเฉพาะเมื่อมี Filter ถูกเลือก
เมื่อกดแล้ว
- Search Text
- Company
- Department
- Position
- Status
ต้องกลับเป็นค่าเริ่มต้นทั้งหมด
รวมถึง
- URL Search Params
- Pagination
ต้อง Reset กลับหน้าแรก
---
## 11.5 Auto Search
เมื่อเลือกค่าใน Select
ให้ระบบ
- Update URL
- Reload Table
- Reset Pagination ไปหน้าแรก
โดยอัตโนมัติ
ไม่ต้องมีปุ่ม Search
Behavior ต้องเหมือนกับ
Online Lessons
---
## 11.6 Responsive
บนหน้าจอขนาดเล็ก
Toolbar ต้องสามารถ Wrap ได้
ตัวอย่าง
Search
Company
Department
Position
Status
Reset
โดย Layout ต้องไม่ล้นหน้าจอ
ไม่เกิด Horizontal Scroll
---
## 11.7 Empty State
หาก Filter แล้วไม่พบข้อมูล
ให้แสดง Empty State มาตรฐานของระบบ
เช่น
```
ไม่พบข้อมูลที่ตรงกับเงื่อนไขการค้นหา
```
พร้อมปุ่ม
```
ล้างตัวกรอง
```
---
## 11.8 Accessibility
ทุก Select ต้องมี
- Label
- aria-label
- Keyboard Navigation
- Focus Ring
ตามมาตรฐาน shadcn/ui
---
## 11.9 Performance
ห้าม Fetch Master Data ใหม่ทุกครั้งที่เปิด Select
Master Data
- Company
- Department
- Position
- Status
ต้องใช้ Cache หรือ Query เดิมที่ระบบมีอยู่
---
## 11.10 Consistency Review
หลังจากแก้ไขแล้ว
ตรวจสอบว่า Toolbar ของ Employee Directory มีมาตรฐานเดียวกับทุกหน้าที่มี Filter ในระบบ ได้แก่
- Online Lessons
- Announcements
- Training Records
- Reports
- Employee Directory
หากพบรูปแบบที่แตกต่างกันโดยไม่มีเหตุผล ให้ปรับให้เป็นมาตรฐานเดียวกันทั้งระบบ
---
# Additional Review
หลังจากแก้ไขเสร็จ
ให้ตรวจสอบเพิ่มเติม
- ไม่มี Console Error
- ไม่มี React Warning
- ไม่มี Hydration Error
- ไม่มี TypeScript Error
- ไม่มี ESLint Error
- Build ผ่าน
- Filter ทุกตัวทำงานถูกต้อง
- Search ทำงานร่วมกับ Filter ได้
- Pagination ทำงานถูกต้อง
- Sorting ทำงานถูกต้อง
- URL Search Params ถูกต้อง
- Refresh หน้าแล้ว Filter ยังแสดงค่าที่เลือกอยู่
---
# 12. Filter Standardization (System-wide)
## Objective
ตรวจสอบและปรับปรุงระบบ Filter ทั้งหมดในโครงการให้เป็นมาตรฐานเดียวกัน (Filter Standardization)
ปัจจุบันแต่ละ Module ใช้รูปแบบ Filter แตกต่างกัน ทั้ง Component, Layout, URL Parameters และพฤติกรรมการทำงาน
ต้องการให้ทุกหน้ามี UX และ Implementation เดียวกัน เพื่อให้ง่ายต่อการดูแลรักษาและขยายระบบในอนาคต
---
# Scope
ตรวจสอบทุกหน้าที่มี Filter อย่างน้อย ได้แก่
- Employee Directory
- Training Records
- Pending Review
- Online Lessons
- Announcements
- Reports
- Employee History
- Master Review
- Employee Import
- Modules อื่นที่มี Filter
หากพบ Module อื่นที่มี Filter ให้รวมอยู่ใน Scope ด้วย
---
# 12.1 Filter Component Standard
Filter ทุกตัวต้องใช้ Component เดียวกัน
เช่น
- Select
- Search Input
- Date Picker
- Multi Select (เฉพาะกรณีจำเป็นจริง)
- Combobox (หากระบบใช้เป็นมาตรฐาน)
ห้ามสร้าง Component ใหม่ที่มีหน้าตาแตกต่างจาก Design System
---
# 12.2 Single Select Policy
Master Data Filter
- Company
- Department
- Position
- Status
- Category
- Type
- Policy
- Course
ให้ใช้
Single Select
เป็นค่า Default
ห้ามใช้ Multi Select
ยกเว้น
มี Business Requirement ระบุไว้อย่างชัดเจน
---
# 12.3 Toolbar Layout Standard
ทุกหน้าต้องใช้ Layout เดียวกัน
ตัวอย่าง
---
Search
Company
Department
Status
Date
Reset Filter
---
ลำดับต้องเหมือนกันทุกหน้า
Search อยู่ซ้ายสุด
Reset อยู่ขวาสุด
---
# 12.4 Search Behavior
Search ทุกหน้าต้อง
- Debounce
- Update URL
- Reset Pagination
- Reload Data
โดยอัตโนมัติ
ไม่ต้องมีปุ่ม Search
---
# 12.5 Filter Behavior
เมื่อเลือก Filter
ต้อง
- Update URL Search Params
- Reload Table
- Reset Pagination
- Preserve Sorting
เหมือนกันทุก Module
---
# 12.6 URL Standard
กำหนดมาตรฐานเดียวกัน
เช่น
```
?page=1
&pageSize=10
&search=...
&company=1
&department=5
&status=active
&sort=name.asc
```
ห้ามใช้รูปแบบแตกต่างกันระหว่าง Module
เช่น
```
company[]=1
```
```
status[]=...
```
หากไม่จำเป็น
---
# 12.7 Pagination
เมื่อ Filter เปลี่ยน
Pagination
ต้องกลับไป
หน้า 1
ทุกครั้ง
---
# 12.8 Reset Filter
ทุกหน้าที่มี Filter
ต้องมี
Reset Filters
เมื่อกดแล้ว
- Clear Search
- Clear Select
- Clear Date
- Reset URL
- Reset Pagination
- Reload Data
---
# 12.9 Responsive
Toolbar ทุกหน้า
ต้องรองรับ
Desktop
Tablet
Mobile
โดย
- Wrap ได้
- ไม่ล้น
- ไม่เกิด Horizontal Scroll
---
# 12.10 Empty State
ทุกหน้าต้องใช้ Empty State เดียวกัน
เช่น
```
ไม่พบข้อมูลที่ตรงกับเงื่อนไขการค้นหา
```
พร้อมปุ่ม
```
ล้างตัวกรอง
```
---
# 12.11 Accessibility
Filter ทุกตัวต้องรองรับ
- Keyboard Navigation
- Focus Ring
- aria-label
- Screen Reader
ตามมาตรฐาน shadcn/ui
---
# 12.12 Performance
Filter ต้อง
- ไม่ Fetch Master Data ซ้ำ
- ใช้ Cache เดิม
- ไม่เกิด Request ซ้ำ
- ไม่เกิด Infinite Render
---
# 12.13 Shared Components
หากพบว่ามีการเขียน Toolbar ซ้ำหลายหน้า
ให้ Refactor
สร้าง Shared Component
เช่น
```
<DataTableToolbar />
<FilterToolbar />
<SearchToolbar />
<ResetFiltersButton />
```
เพื่อใช้ร่วมกันทั้งระบบ
โดยต้องไม่ทำให้ Feature เดิมเสีย
---
# 12.14 Shared Hook
หากพบ Logic ซ้ำ
ให้สร้าง
```
useTableFilters()
useSearchParams()
useFilterState()
```
หรือ Shared Hook ที่เหมาะสม
เพื่อให้ทุก Module ใช้มาตรฐานเดียวกัน
---
# 12.15 Code Review
ตรวจสอบและลบ
- Duplicate Logic
- Duplicate Components
- Dead Code
- Legacy Filter
- Unused Search Params
---
# Acceptance Criteria
หลังจากแก้ไขแล้ว
✓ ทุกหน้าใช้ Filter มาตรฐานเดียวกัน
✓ Layout เหมือนกัน
✓ Select ใช้ Component เดียวกัน
✓ Search Behavior เหมือนกัน
✓ URL Format เหมือนกัน
✓ Pagination เหมือนกัน
✓ Reset Filter เหมือนกัน
✓ Responsive ทุกหน้า
✓ Accessibility ผ่าน
✓ ไม่มี Duplicate Components
✓ ไม่มี Duplicate Logic
✓ Shared Components ถูกใช้งานร่วมกัน
✓ Shared Hooks ถูกใช้งานร่วมกัน
✓ ไม่มี TypeScript Error
✓ ไม่มี ESLint Error
✓ Build ผ่าน
✓ ทุก Module ทำงานได้เหมือนเดิม (Backward Compatible)
---
# Final Verification
หลังจากดำเนินการเสร็จ ให้จัดทำรายงานสรุปประกอบด้วย
1. รายชื่อทุกหน้าที่มีการปรับปรุง Filter
2. รายการ Component ที่ถูก Refactor เป็น Shared Component
3. รายการ Hook ที่ถูกสร้างหรือปรับใช้ร่วมกัน
4. ตารางเปรียบเทียบพฤติกรรมของ Filter ก่อนและหลังการปรับปรุง
5. รายการจุดที่ยังไม่สามารถปรับให้เป็นมาตรฐานเดียวได้ พร้อมเหตุผลทางเทคนิคหรือ Business Requirement
6. ผลการทดสอบการทำงานของ Search, Filter, Sorting, Pagination และ URL Search Params ในแต่ละ Module
7. ยืนยันว่าไม่มี Regression และไม่มีผลกระทบต่อฟังก์ชันเดิมของระบบ

View File

@@ -0,0 +1,342 @@
# Prompt: Fix Attachment View & Download Behavior (Production Ready)
## Background
ปัจจุบันหน้าแสดงรายละเอียดบทเรียนออนไลน์ (Online Lesson Detail) ในส่วน **เอกสารแนบ** มีปุ่ม
- เปิดไฟล์
- ดาวน์โหลด
แต่เมื่อกด **เปิดไฟล์** ระบบกลับดาวน์โหลดไฟล์ทันที ซึ่งไม่ใช่พฤติกรรมที่ต้องการ
---
## ปัญหาที่พบ
ปัจจุบันทั้งสองปุ่มใช้งานผ่าน URL เดียวกัน
ตัวอย่าง
```tsx
<Button asChild variant="outline">
<Link href={lesson.attachment_url}>
</Link>
</Button>
<Button asChild>
<Link href={lesson.attachment_url}>
</Link>
</Button>
```
ทำให้
- เปิดไฟล์ = ดาวน์โหลด
- ดาวน์โหลด = ดาวน์โหลด
สาเหตุหลักเกิดจาก Response Header ของไฟล์เป็น
```
Content-Disposition: attachment
```
Browser จึงบังคับ Download
---
# Objective
แยกการทำงานของ
- View Attachment
- Download Attachment
ให้เป็นคนละ Endpoint
และรองรับการทำงานแบบ Production
---
# Requirements
## 1. สร้าง API สำหรับ View Attachment
เช่น
```
GET
/api/online-lessons/[id]/attachment/view
```
หรือ Route ที่เหมาะสมกับโครงสร้างโปรเจกต์
หน้าที่
- ตรวจสอบสิทธิ์การเข้าถึง
- ตรวจสอบว่าบทเรียนมีไฟล์แนบ
- อ่านไฟล์จาก Storage
- ส่งไฟล์กลับด้วย
```
Content-Disposition: inline
```
ไม่ใช่
```
attachment
```
พร้อมส่ง
```
Content-Type
```
ตาม Mime Type จริงของไฟล์
ตัวอย่าง
```
application/pdf
image/png
image/jpeg
```
---
## 2. สร้าง API สำหรับ Download
เช่น
```
GET
/api/online-lessons/[id]/attachment/download
```
ส่ง Response
```
Content-Disposition: attachment
```
เพื่อให้ Browser ดาวน์โหลดไฟล์
---
## 3. Frontend
ปรับปุ่ม
จากเดิม
```
lesson.attachment_url
```
ให้เรียก API ใหม่
### เปิดไฟล์
```
/attachment/view
```
### ดาวน์โหลด
```
/attachment/download
```
---
## 4. ใช้ Anchor แทน Next Link
สำหรับไฟล์
ไม่ควรใช้
```
next/link
```
ให้ใช้
```
<a>
```
ร่วมกับ
```
Button asChild
```
ตัวอย่าง
```
<Button asChild variant="outline">
<a
href="..."
target="_blank"
rel="noopener noreferrer"
>
เปิดไฟล์
</a>
</Button>
```
และ
```
<Button asChild>
<a href="...">
ดาวน์โหลด
</a>
</Button>
```
---
## 5. Browser Behavior
ต้องรองรับ
### PDF
เปิดใน Tab ใหม่
### Image
เปิดใน Browser
### Text
เปิดใน Browser
### Office File
หาก Browser เปิดไม่ได้
ให้ Browser ดาวน์โหลดตามปกติ
---
## 6. Security
ตรวจสอบสิทธิ์ก่อนเปิดไฟล์
ห้ามใช้ Public URL โดยตรง
Route ต้องตรวจสอบ
- Authentication
- Authorization
เหมือนการเปิดรายละเอียดบทเรียน
---
## 7. Error Handling
หาก
- ไม่พบไฟล์
- ไม่มีสิทธิ์
- Storage Error
ต้องส่ง Status Code ที่เหมาะสม
เช่น
```
404
403
500
```
Frontend ต้องแสดงข้อความแจ้งผู้ใช้
---
## 8. Logging
บันทึก Error ผ่านระบบ Logging ของโปรเจกต์
ไม่ใช้
```
console.log
```
---
## 9. UX
ส่วนเอกสารแนบควรเป็น
```
เอกสารแนบ
📄 คู่มือการใช้งาน.pdf
[เปิดไฟล์] [ดาวน์โหลด]
```
หากไม่มีไฟล์
```
เอกสารแนบ
ไม่มีไฟล์แนบ
```
ไม่ต้องแสดง Dropzone
---
## 10. Coding Standard
ต้องสอดคล้องกับมาตรฐานของโปรเจกต์
- Next.js App Router
- TypeScript Strict
- Server Component / Route Handler
- shadcn/ui
- TailwindCSS
- ไม่ใช้ any
- ESLint ผ่าน
- Type Check ผ่าน
---
# Acceptance Criteria
- เปิดไฟล์สามารถเปิดใน Browser ได้ (PDF / Image)
- ดาวน์โหลดทำงานแยกจากเปิดไฟล์
- ไม่ใช้ URL Storage ตรง ๆ บน Frontend
- ใช้ API กลางของระบบ
- ตรวจสอบ Permission ก่อนทุกครั้ง
- ไม่มี Regression
- ผ่าน Build
- ผ่าน Type Check
- ผ่าน ESLint
---
## Deliverables
ดำเนินการดังนี้
1. วิเคราะห์โครงสร้างเดิม
2. อธิบายสาเหตุของปัญหา
3. แก้ไข Backend
4. แก้ไข Frontend
5. ตรวจสอบ Security
6. ตรวจสอบ UX
7. ตรวจสอบ Regression
8. สรุปรายการไฟล์ที่แก้ไข
9. สรุปผลการทดสอบ
10. ยืนยันว่า Build / Type Check / ESLint ผ่านทั้งหมด

View File

@@ -0,0 +1,946 @@
# Prompt: แก้ไข Auth.js ClientFetchError และเพิ่มระบบ Session Inactivity Timeout 5 นาที
## บทบาทของคุณ
คุณคือ Senior Full-Stack Developer ที่มีความเชี่ยวชาญด้าน:
- Next.js 16 App Router
- React
- TypeScript
- Auth.js / NextAuth
- Middleware
- Session Management
- Security และ Authentication Flow
- TanStack Query หรือระบบ Client State ที่มีอยู่ในโครงการ
- Next.js Turbopack
ให้ตรวจสอบโครงสร้างและโค้ดเดิมของโครงการก่อนดำเนินการแก้ไข โดยต้องปรับปรุงจากโครงสร้างที่มีอยู่จริง ห้ามสร้างระบบ Authentication ซ้ำซ้อนโดยไม่จำเป็น
---
# ปัญหาที่ต้องแก้ไข
ระบบพบ Error ฝั่ง Client ดังนี้:
```text
Error Type:
Console ClientFetchError
Error Message:
Unexpected token '<', "<!DOCTYPE "... is not valid JSON.
Read more at:
https://errors.authjs.dev#autherror
Next.js version:
16.2.6 (Turbopack)
```
Error นี้บ่งชี้ว่า Client ของ Auth.js คาดว่าจะได้รับ JSON แต่ Endpoint เช่น:
```text
/api/auth/session
```
กลับส่ง HTML Response เช่น:
```html
<!DOCTYPE html>
```
ซึ่งอาจเกิดจาก:
- Auth.js Route ไม่ทำงานหรืออยู่ผิดตำแหน่ง
- `/api/auth/session` ตอบกลับเป็น 404 หรือ 500
- Middleware Redirect `/api/auth/*` ไปหน้าล็อกอิน
- Auth.js Configuration Error
- Database หรือ Adapter Error
- Environment Variable ไม่ครบหรือไม่ถูกต้อง
- Custom Error Handler ส่ง HTML แทน JSON
- Reverse Proxy หรือ Application Redirect ทำให้ Auth API ถูกเปลี่ยนปลายทาง
- Client เรียก `getSession()` หรือ `useSession()` ขณะที่ Auth Route ล้มเหลว
- SessionProvider ถูกตั้งค่าผิดตำแหน่ง
- Error Boundary หรือ Route Handler จัดการ Error ไม่ถูกต้อง
---
# เป้าหมายหลัก
ดำเนินการให้ครบทั้ง 2 ส่วนดังนี้:
1. ตรวจสอบและแก้ไข Auth.js `ClientFetchError`
2. เพิ่มระบบ Session Inactivity Timeout เมื่อผู้ใช้งานไม่มีการเคลื่อนไหวต่อเนื่อง 5 นาที
---
# ส่วนที่ 1: ตรวจสอบและแก้ไข Auth.js ClientFetchError
## 1. ตรวจสอบโครงสร้าง Auth.js ปัจจุบัน
ตรวจสอบไฟล์ที่เกี่ยวข้องทั้งหมด เช่น:
```text
auth.ts
src/auth.ts
app/api/auth/[...nextauth]/route.ts
src/app/api/auth/[...nextauth]/route.ts
middleware.ts
src/middleware.ts
proxy.ts
src/proxy.ts
providers.tsx
session-provider.tsx
layout.tsx
.env
.env.local
next.config.ts
```
รวมถึงไฟล์ Authentication, Authorization และ Database Adapter ที่เกี่ยวข้อง
ห้ามสมมติชื่อไฟล์หรือโครงสร้าง ให้ค้นหาจากโครงการจริงก่อน
---
## 2. ตรวจสอบ Auth Route
ตรวจสอบว่า Auth.js Route อยู่ในตำแหน่งที่ถูกต้องสำหรับ App Router เช่น:
```text
src/app/api/auth/[...nextauth]/route.ts
```
และ Export Handler ถูกต้อง เช่น:
```ts
import { handlers } from "@/auth";
export const { GET, POST } = handlers;
```
ตรวจสอบเพิ่มเติมว่า:
- Import path ถูกต้อง
- `handlers` ถูก Export จาก Auth configuration จริง
- ไม่มี Circular Dependency
- ไม่มี Route อื่นชนกับ `/api/auth/[...nextauth]`
- ไม่มี Rewrite หรือ Redirect ที่กระทบ Auth Route
---
## 3. ตรวจสอบ Auth.js Configuration
ตรวจสอบไฟล์ Auth configuration ว่ามีรูปแบบถูกต้อง เช่น:
```ts
import NextAuth from "next-auth";
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [],
});
```
ตรวจสอบ:
- Providers
- Credentials Provider
- Adapter
- Session Strategy
- JWT Callback
- Session Callback
- Authorized Callback
- Sign-in Page
- Error Page
- Environment Variables
- Database Connection
- Cookie Configuration
- Trust Host Configuration
- Base Path หากมีการตั้งค่า
หากมี Custom Adapter หรือ LDAP/Active Directory ให้ตรวจสอบ Error Handling ของส่วนนั้นด้วย
---
## 4. ตรวจสอบ Endpoint `/api/auth/session`
ทดสอบ Endpoint นี้โดยตรง:
```text
GET /api/auth/session
```
ผลลัพธ์ที่ถูกต้องต้องเป็น JSON และมี `Content-Type` เป็น:
```text
application/json
```
ตัวอย่างผลลัพธ์เมื่อยังไม่ได้เข้าสู่ระบบ:
```json
{}
```
หรือ Response ตามมาตรฐานของ Auth.js
ต้องไม่ตอบกลับเป็น:
- HTML
- หน้า Login
- หน้า 404
- หน้า Error ของ Next.js
- Redirect ไปหน้าอื่น
- Reverse Proxy Error Page
ให้ตรวจสอบ HTTP Status เช่น:
```text
200
302
307
401
404
500
```
และหาสาเหตุจาก Status ที่พบจริง
---
## 5. ตรวจสอบ Middleware หรือ Proxy
ตรวจสอบว่า Middleware หรือ Proxy ไม่ได้ดัก Route ต่อไปนี้:
```text
/api/auth
/api/auth/*
/_next/*
/favicon.ico
```
Auth.js API Route ต้องไม่ถูก Redirect ไปหน้าล็อกอิน
ปรับ Matcher ให้ยกเว้น Auth API และ Static Assets อย่างเหมาะสม เช่นแนวทาง:
```ts
export const config = {
matcher: ["/((?!api/auth|_next/static|_next/image|favicon.ico).*)"],
};
```
แต่ต้องปรับให้เข้ากับโครงสร้างจริงของโครงการ และต้องไม่ทำให้ Route Protection เดิมเสียหาย
หากโครงการใช้ `proxy.ts` ตามโครงสร้างของ Next.js รุ่นปัจจุบัน ให้ตรวจสอบไฟล์นั้นด้วย ไม่จำกัดเฉพาะ `middleware.ts`
---
## 6. ตรวจสอบ Environment Variables
ตรวจสอบ Environment Variables ที่เกี่ยวข้อง เช่น:
```text
AUTH_SECRET
AUTH_URL
NEXTAUTH_SECRET
NEXTAUTH_URL
DATABASE_URL
```
รวมถึง Environment Variables ของ:
- LDAP
- Active Directory
- OAuth Provider
- Database Adapter
- Reverse Proxy
- Internal API
ให้ใช้ชื่อตัวแปรตาม Version และโครงสร้าง Auth.js ที่โครงการใช้งานจริง
ห้ามเปิดเผย Secret ใน Log หรือ Commit
หาก Environment Variable ที่จำเป็นขาด ให้เพิ่มตัวอย่างใน:
```text
.env.example
```
โดยใช้ Placeholder เท่านั้น
---
## 7. ตรวจสอบ Server Error ที่แท้จริง
ตรวจสอบ Server Log และ Terminal Log ขณะที่เรียก:
```text
/api/auth/session
```
ค้นหา Root Cause เช่น:
- Database Connection Error
- Prisma Initialization Error
- LDAP Connection Error
- Provider Configuration Error
- Invalid Secret
- Callback Error
- JWT Decryption Error
- Cookie Parsing Error
- Runtime Compatibility Error
- Edge Runtime ไม่รองรับ Library บางตัว
- Node Runtime Configuration Error
ห้ามแก้ด้วยการซ่อน Error ฝั่ง Client เพียงอย่างเดียว ต้องแก้ Root Cause ที่ทำให้ Endpoint ส่ง HTML
---
## 8. ปรับปรุง Error Handling
ปรับปรุง Error Handling เพื่อให้:
- Auth API ไม่ส่ง HTML Response โดยไม่จำเป็น
- Client ไม่เกิด Unhandled Promise Rejection
- ไม่แสดง Stack Trace หรือข้อมูล Sensitive แก่ผู้ใช้งาน
- Server Log มีข้อมูลเพียงพอสำหรับ Debug
- Production แสดงข้อความที่เหมาะสม
- Development ยังสามารถตรวจสอบ Root Cause ได้
หาก `useSession()`, `getSession()`, `SessionProvider` หรือ Custom API Client มี Error Handling ไม่ครบ ให้ปรับปรุงด้วย
ห้ามใช้วิธีแก้แบบ:
```ts
try {
// ...
} catch {
return null;
}
```
หากทำให้ Root Cause ถูกซ่อนโดยไม่มี Logging ที่เหมาะสม
---
# ส่วนที่ 2: เพิ่มระบบ Session Inactivity Timeout 5 นาที
## ความต้องการ
เมื่อผู้ใช้งานเข้าสู่ระบบแล้ว หากไม่มีการเคลื่อนไหวหรือไม่มี Interaction กับระบบต่อเนื่องเป็นเวลา:
```text
5 นาที
```
ให้ระบบดำเนินการดังนี้:
1. แสดงข้อความแจ้งผู้ใช้งานว่า:
```text
คุณไม่ได้ใช้งานระบบเป็นเวลานาน เซสชันของคุณหมดอายุแล้ว กรุณาเข้าสู่ระบบใหม่
```
2. ทำการ Sign out จาก Auth.js อย่างถูกต้อง
3. ล้าง Client State หรือข้อมูล Session ที่เกี่ยวข้อง
4. Redirect กลับไปหน้าล็อกอิน
5. ผู้ใช้งานต้องเข้าสู่ระบบใหม่ก่อนใช้งานระบบต่อ
6. ห้ามเกิด Redirect Loop
7. ห้ามกระทบผู้ใช้งานที่ยังมีการเคลื่อนไหวอยู่
---
## 1. นิยาม Activity ของผู้ใช้งาน
ให้ถือว่า Event ต่อไปนี้เป็น Activity:
```text
mousedown
mousemove
keydown
scroll
touchstart
click
focus
```
สามารถเลือกใช้เฉพาะ Event ที่เหมาะสมเพื่อไม่ให้เกิด Performance Issue
ต้องใช้ Event แบบ Throttle หรือ Debounce เพื่อไม่ให้ Reset Timer ถี่เกินไป โดยเฉพาะ:
```text
mousemove
scroll
```
---
## 2. เริ่มตรวจจับเฉพาะผู้ที่เข้าสู่ระบบแล้ว
ระบบ Inactivity Timeout ต้องทำงานเฉพาะเมื่อ:
```ts
status === "authenticated";
```
ห้ามเริ่ม Timer ในกรณี:
```ts
status === "loading";
status === "unauthenticated";
```
เมื่อผู้ใช้งาน Logout แล้ว ต้อง Cleanup:
- Timer
- Event Listener
- Storage Listener
- Broadcast Channel
- Pending Callback
ทั้งหมดอย่างถูกต้อง
---
## 3. ระยะเวลา Timeout
กำหนดค่ากลาง เช่น:
```ts
const INACTIVITY_TIMEOUT_MS = 5 * 60 * 1000;
```
ควรจัดเก็บไว้ใน Configuration หรือ Constant กลาง เพื่อให้เปลี่ยนภายหลังได้ง่าย
ห้ามกระจายค่า `300000` ไว้หลายจุดในระบบ
---
## 4. รูปแบบการแจ้งเตือน
เมื่อครบ 5 นาที ให้แสดง Dialog, AlertDialog, Modal หรือ Toast ตาม Component มาตรฐานของโครงการ
แนะนำให้ใช้:
```text
AlertDialog
```
ข้อความ:
```text
เซสชันหมดอายุ
```
รายละเอียด:
```text
คุณไม่ได้ใช้งานระบบเป็นเวลานาน เซสชันของคุณหมดอายุแล้ว กรุณาเข้าสู่ระบบใหม่
```
ปุ่ม:
```text
เข้าสู่ระบบใหม่
```
เมื่อผู้ใช้งานกดปุ่ม ให้ Redirect ไปหน้าล็อกอิน
อย่างไรก็ตาม เพื่อความปลอดภัย ระบบต้อง Sign out และถือว่า Session หมดอายุทันทีเมื่อครบเวลา ไม่ควรรอให้ผู้ใช้งานกดปุ่มก่อนจึงค่อย Sign out
หากใช้ Toast ให้ตั้งระยะเวลาที่ผู้ใช้งานสามารถอ่านข้อความได้อย่างเหมาะสมก่อน Redirect
ห้ามใช้ Native Browser Alert หากโครงการมี UI Component มาตรฐานอยู่แล้ว
---
## 5. ลำดับการทำงานเมื่อหมดเวลา
ลำดับที่ต้องการ:
```text
ครบเวลาไม่มี Activity
ป้องกันการทำงานซ้ำด้วย Flag
หยุด Timer และถอด Event Listener
แสดงข้อความแจ้ง Session หมดอายุ
ล้างข้อมูล Client State ที่มีความ Sensitive
เรียก signOut ของ Auth.js
Redirect ไปหน้า Login
```
ตัวอย่างแนวทาง:
```ts
await signOut({
redirect: false,
});
router.replace("/login?reason=inactivity");
router.refresh();
```
ให้ปรับตาม Auth.js API และโครงสร้างจริงของโครงการ
หากจำเป็นต้องแสดงข้อความหลัง Redirect ให้ส่ง Query Parameter เช่น:
```text
/login?reason=inactivity
```
จากนั้นหน้า Login แสดงข้อความ:
```text
คุณไม่ได้ใช้งานระบบเป็นเวลานาน เซสชันของคุณหมดอายุแล้ว กรุณาเข้าสู่ระบบใหม่
```
ต้องลบหรือ Replace URL อย่างเหมาะสมหลังแสดงข้อความ เพื่อไม่ให้ข้อความแสดงซ้ำเมื่อ Refresh โดยไม่จำเป็น
---
## 6. รองรับหลาย Tab
ระบบควรรองรับกรณีเปิดหลาย Browser Tab
เมื่อผู้ใช้งานมี Activity ใน Tab หนึ่ง ควร Sync `lastActivity` ให้ Tab อื่นรับรู้ เพื่อไม่ให้ Tab อื่น Logout ผู้ใช้งานผิดพลาด
สามารถใช้:
```text
localStorage
storage event
BroadcastChannel
```
แนวทางที่แนะนำ:
```text
auth:last-activity
auth:session-expired
```
ข้อกำหนด:
- Activity จาก Tab หนึ่งต้องอัปเดตเวลาให้ Tab อื่น
- เมื่อ Session หมดอายุใน Tab หนึ่ง Tab อื่นต้อง Logout ตาม
- ป้องกันหลาย Tab เรียก `signOut()` พร้อมกันจำนวนมาก
- Cleanup Channel และ Listener เมื่อ Component Unmount
- ต้องตรวจสอบการทำงานใน Browser ที่ไม่รองรับ `BroadcastChannel`
---
## 7. ห้ามใช้เฉพาะ Client Timer เป็น Security Control
Client-side inactivity timer เป็นส่วนของ UX เท่านั้น
ต้องตรวจสอบ Session Configuration ฝั่ง Server ร่วมด้วย เช่น:
- JWT expiration
- Session maxAge
- Cookie expiration
- Server-side authorization
- Permission validation ใน Protected Route
- API Route ต้องตรวจ Session ทุกครั้ง
ห้ามถือว่าผู้ใช้หมดสิทธิ์เพียงเพราะ Client Redirect แล้วเท่านั้น
อย่างไรก็ตาม ระยะเวลาหมดอายุฝั่ง Server ไม่จำเป็นต้องเท่ากับ Inactivity Timeout 5 นาที หากระบบต้องรองรับ Sliding Session แต่ต้องอธิบายความแตกต่างไว้ใน Implementation Report
---
## 8. ระวังการสูญหายของข้อมูลใน Form
ตรวจสอบว่าหน้าใดมี Form ที่ผู้ใช้งานอาจกำลังกรอกข้อมูล
เมื่อ Session หมดอายุ:
- ต้องไม่พยายามบันทึกข้อมูลหลังหมด Session
- ต้องไม่เกิด API Request ด้วย Session ที่หมดอายุ
- ต้องไม่เก็บข้อมูล Sensitive ไว้ใน Local Storage โดยไม่จำเป็น
- สามารถแจ้งข้อความว่าข้อมูลที่ยังไม่ได้บันทึกอาจสูญหายได้ หากเหมาะสม
ไม่ต้องเพิ่มระบบ Auto Save เว้นแต่โครงการมีอยู่แล้ว
---
# สถาปัตยกรรมที่แนะนำ
สร้าง Component หรือ Hook กลาง เช่น:
```text
src/components/auth/session-inactivity-guard.tsx
```
หรือ:
```text
src/hooks/use-session-inactivity.ts
```
แล้วนำไปติดตั้งในตำแหน่งที่ครอบคลุมเฉพาะ Protected Area เช่น:
```text
src/app/dashboard/layout.tsx
```
หรือ Protected Layout ที่มีอยู่จริง
ไม่ควรติดตั้งใน Root Layout หากทำให้หน้า Login เริ่มจับเวลาโดยไม่จำเป็น
ตัวอย่างโครงสร้าง:
```text
Protected Layout
├── SessionProvider
├── SessionInactivityGuard
└── Protected Page Content
```
ให้ใช้ Provider และ Layout เดิมของโครงการ หากมีอยู่แล้ว
---
# ข้อกำหนดด้าน UX
## ข้อความภาษาไทย
หัวข้อ:
```text
เซสชันหมดอายุ
```
รายละเอียด:
```text
คุณไม่ได้ใช้งานระบบเป็นเวลานาน เซสชันของคุณหมดอายุแล้ว กรุณาเข้าสู่ระบบใหม่
```
ปุ่ม:
```text
เข้าสู่ระบบใหม่
```
กรณี Redirect ไปหน้า Login โดยตรง ให้หน้า Login แสดงข้อความ:
```text
คุณไม่ได้ใช้งานระบบเป็นเวลานาน กรุณาเข้าสู่ระบบใหม่
```
---
# ข้อกำหนดด้านความปลอดภัย
- ห้าม Log Token
- ห้าม Log Cookie
- ห้าม Log Password
- ห้าม Log LDAP Credential
- ห้ามเปิดเผย Environment Secret
- ห้ามเก็บ Access Token ใน Local Storage หากระบบเดิมไม่ได้ออกแบบเช่นนั้น
- API และ Server Action ต้องตรวจ Session ฝั่ง Server
- Protected Route ต้องไม่พึ่ง Client Guard เพียงอย่างเดียว
- ป้องกัน Open Redirect
- Redirect URL ต้องเป็น Internal Path ที่กำหนดไว้
- ป้องกันการเรียก Logout ซ้ำ
- ป้องกัน Redirect Loop ระหว่าง Login และ Protected Route
---
# Test Cases ที่ต้องตรวจสอบ
## Auth.js Error
### TC-AUTH-001
เปิด:
```text
/api/auth/session
```
ผลลัพธ์ที่คาดหวัง:
- HTTP Status ถูกต้อง
- Response เป็น JSON
- `Content-Type` เป็น JSON
- ไม่มี HTML Response
### TC-AUTH-002
เปิดหน้า Protected Route ขณะยังไม่เข้าสู่ระบบ
ผลลัพธ์ที่คาดหวัง:
- Redirect ไปหน้า Login อย่างถูกต้อง
- `/api/auth/session` ไม่ถูก Middleware Redirect
- ไม่เกิด `Unexpected token '<'`
### TC-AUTH-003
เข้าสู่ระบบสำเร็จ
ผลลัพธ์ที่คาดหวัง:
- `useSession()` ได้สถานะ `authenticated`
- ไม่มี `ClientFetchError`
- Session โหลดได้ตามปกติ
### TC-AUTH-004
Database หรือ LDAP ไม่พร้อมใช้งาน
ผลลัพธ์ที่คาดหวัง:
- Server มี Error Log ที่เหมาะสม
- Client ไม่เกิด Unhandled Error
- ผู้ใช้งานได้รับข้อความที่เหมาะสม
- ไม่มีข้อมูล Sensitive ถูกเปิดเผย
---
## Session Inactivity Timeout
### TC-IDLE-001
เข้าสู่ระบบและไม่มี Activity 5 นาที
ผลลัพธ์ที่คาดหวัง:
- แสดงข้อความ Session หมดอายุ
- Sign out สำเร็จ
- Redirect ไปหน้า Login
- ต้อง Login ใหม่
### TC-IDLE-002
มี Activity ก่อนครบ 5 นาที
ผลลัพธ์ที่คาดหวัง:
- Timer ถูก Reset
- ผู้ใช้งานไม่ถูก Logout
### TC-IDLE-003
มี Activity ต่อเนื่อง
ผลลัพธ์ที่คาดหวัง:
- ระบบไม่ Logout
- ไม่มี Memory Leak
- ไม่มี Timer ถูกสร้างซ้ำ
### TC-IDLE-004
เปิดระบบหลาย Tab และใช้งานอยู่ใน Tab หนึ่ง
ผลลัพธ์ที่คาดหวัง:
- Activity Sync ไปยัง Tab อื่น
- Tab อื่นไม่ Logout ผู้ใช้งานผิดพลาด
### TC-IDLE-005
Session หมดอายุใน Tab หนึ่ง
ผลลัพธ์ที่คาดหวัง:
- ทุก Tab รับรู้ว่า Session หมดอายุ
- ทุก Tab กลับหน้า Login
- ไม่เรียก Sign out ซ้ำอย่างผิดปกติ
### TC-IDLE-006
Logout ด้วยตนเองก่อนครบเวลา
ผลลัพธ์ที่คาดหวัง:
- Timer และ Event Listener ถูก Cleanup
- ไม่แสดงข้อความ Inactivity ภายหลัง
### TC-IDLE-007
Refresh หน้าใกล้ครบเวลา
ผลลัพธ์ที่คาดหวัง:
- ระบบอ่าน `lastActivity` ที่เหมาะสม
- ไม่ Reset Timeout อย่างไม่ถูกต้อง หากไม่มี Activity จริง
- ไม่ Logout ซ้ำ
### TC-IDLE-008
อยู่หน้า Login
ผลลัพธ์ที่คาดหวัง:
- ไม่มี Inactivity Timer ทำงาน
- ไม่มี Redirect Loop
- ไม่มีข้อความหมดอายุแสดงซ้ำโดยไม่จำเป็น
### TC-IDLE-009
ผู้ใช้งานกำลังกรอก Form แต่ไม่มี Mouse หรือ Keyboard Activity เกิน 5 นาที
ผลลัพธ์ที่คาดหวัง:
- Session หมดอายุตามข้อกำหนด
- ระบบแจ้งเตือนอย่างชัดเจน
- ไม่มีการส่ง Form หลัง Session หมดอายุ
---
# Quality Gate
ก่อนจบงานต้องดำเนินการ:
```bash
npm run lint
npm run typecheck
npm run build
```
หรือใช้คำสั่งที่มีอยู่จริงใน `package.json`
ต้องแก้ไข:
- TypeScript Error
- ESLint Error
- Build Error
- Import Error
- Hydration Error
- Unhandled Promise Rejection
- Memory Leak จาก Timer หรือ Event Listener
ห้ามปิด Rule หรือใช้:
```ts
any
@ts-ignore
eslint-disable
```
โดยไม่มีเหตุผลที่จำเป็นและมีคำอธิบาย
---
# ข้อจำกัดในการแก้ไข
- รักษาโครงสร้างและ Coding Convention เดิม
- ใช้ Component มาตรฐานที่โครงการมีอยู่แล้ว
- ไม่สร้าง Auth Provider ซ้ำ
- ไม่เปลี่ยน Authentication Flow โดยไม่จำเป็น
- ไม่ลบ Permission หรือ Route Protection เดิม
- ไม่ Hardcode Domain
- ไม่ Hardcode Secret
- ไม่ Hardcode Login URL หลายตำแหน่ง
- ไม่เปลี่ยน Session Strategy หากไม่มีเหตุผลรองรับ
- ไม่แก้เฉพาะอาการโดยละเลย Root Cause
- ห้ามทำให้ `/api/auth/session` ถูก Redirect ไปหน้า Login
---
# ผลลัพธ์ที่ต้องส่งมอบ
หลังดำเนินการเสร็จ ให้จัดทำรายงานสรุป Markdown โดยประกอบด้วย:
## 1. Root Cause
ระบุสาเหตุจริงของ:
```text
Unexpected token '<', "<!DOCTYPE "... is not valid JSON
```
พร้อมระบุว่า HTML Response มาจาก:
- Route ใด
- HTTP Status ใด
- Middleware, Server Error หรือ Configuration ส่วนใด
## 2. Files Changed
ระบุรายการไฟล์ที่:
- เพิ่มใหม่
- แก้ไข
- ลบ
พร้อมสรุปหน้าที่ของแต่ละไฟล์
## 3. Auth.js Fix
อธิบาย:
- สิ่งที่ผิด
- วิธีแก้
- เหตุผลที่วิธีใหม่ถูกต้อง
- ผลทดสอบ `/api/auth/session`
## 4. Inactivity Timeout Implementation
อธิบาย:
- จุดที่ติดตั้ง Guard
- Event ที่ใช้ตรวจ Activity
- วิธี Reset Timer
- วิธี Logout
- วิธี Redirect
- วิธีรองรับหลาย Tab
- วิธี Cleanup
## 5. Security Notes
อธิบาย:
- Client Timeout
- Server Session Expiration
- Protected API
- Cookie และ Token Handling
- ข้อจำกัดที่ยังเหลืออยู่
## 6. Test Results
สรุปผล:
```text
Lint
Typecheck
Build
Manual Test
Auth Session Endpoint Test
Multi-tab Test
Inactivity Test
```
## 7. Remaining Risks
หากยังมีข้อจำกัดหรือสิ่งที่ต้องดำเนินการต่อ ให้ระบุอย่างตรงไปตรงมา ห้ามรายงานว่าสำเร็จหากยังไม่ได้ทดสอบจริง
---
# Acceptance Criteria
งานถือว่าเสร็จสมบูรณ์เมื่อ:
- ไม่เกิด `ClientFetchError`
- ไม่เกิด `Unexpected token '<'`
- `/api/auth/session` ตอบกลับเป็น JSON
- Middleware ไม่ Redirect Auth API
- ผู้ใช้เข้าสู่ระบบได้ตามปกติ
- ผู้ใช้ที่ไม่มี Activity ครบ 5 นาทีถูก Sign out
- มีข้อความแจ้งว่าไม่ได้ใช้งานระบบเป็นเวลานาน
- Redirect กลับหน้า Login สำเร็จ
- ต้องเข้าสู่ระบบใหม่
- Activity ก่อนครบเวลาสามารถ Reset Timer ได้
- รองรับหลาย Tab
- ไม่มี Redirect Loop
- ไม่มี Timer หรือ Event Listener ค้าง
- Protected API ยังตรวจสอบ Session ฝั่ง Server
- Lint, Typecheck และ Build ผ่าน
- มี Implementation Report สรุป Root Cause และการแก้ไข

View File

@@ -0,0 +1,35 @@
# Prompt: Fix Employee Create Form Organization Reference
## Objective
ปรับปรุง Module User / Employee Directory หน้า “สร้างรายชื่อพนักงาน” ให้พนักงานใหม่ถูกสร้างภายใต้ Organizer / บริษัท ที่ถูกต้อง
ปัจจุบันฟอร์มมีช่อง “บริษัท” เป็น input text ธรรมดา ซึ่งเสี่ยงต่อข้อมูลไม่ตรงกับ Organizer จริงในระบบ
ต้องแก้ให้ระบบใช้ Organizer จริงแทนการกรอกข้อความเอง
---
## Requirement
### 1. Organization / Company Field
ปรับช่อง “บริษัท” ให้เป็นหนึ่งในแนวทางต่อไปนี้ตาม context ของระบบจริง
#### Case A: ผู้ใช้กำลังอยู่ใน Organizer Context แล้ว
ถ้ามี current organizer อยู่แล้ว เช่น จาก org switcher / session / route context
ให้ระบบอ้างอิง Organizer ปัจจุบันอัตโนมัติ
- ไม่ต้องให้ผู้ใช้พิมพ์ชื่อบริษัทเอง
- แสดงชื่อบริษัทแบบ read-only
- ส่ง `organizerId` หรือ `organizationId` ไปกับ payload
- ห้ามส่ง company เป็น text ธรรมดา
ตัวอย่าง UI:
```txt
บริษัท
O Company Site
```

View File

@@ -0,0 +1,71 @@
ช่วยแก้ Layout หน้า บทเรียนออนไลน์
ปัญหา:
- ตารางล้นออกด้านขวา
- ปุ่ม "+ เพิ่มบทเรียนออนไลน์" ด้านบนขวาโดนตัด/ล้นจอ
- Column ผู้สร้างยาวเกินไป
- ไม่มี Action column หรือ Action column ถูกดันออกนอกหน้าจอ
สิ่งที่ต้องแก้:
1. ครอบ Page content ด้วย container ที่ไม่ล้นจอ เช่น `max-w-full overflow-hidden`
2. Header ด้านบนให้ใช้ layout แบบ responsive:
- ซ้ายเป็น Title/Subtitle
- ขวาเป็นปุ่มเพิ่มบทเรียน
- ถ้าพื้นที่ไม่พอให้ปุ่มลงบรรทัดใหม่
3. ปุ่มเพิ่มบทเรียนต้องไม่ล้นจอ ใช้ `shrink-0` และข้อความไม่ซ้อน
4. Table card ให้ใช้:
- `overflow-hidden`
- ด้านในใช้ `overflow-x-auto`
5. Table ให้ใช้:
- `w-full`
- `table-fixed`
- `min-w-[1050px]` หรือปรับให้พอดีกับ column
6. กำหนด width ของ column ทุกช่อง เช่น:
- รูปปก / ไฟล์: 120px
- ชื่อบทเรียน: 320px
- หมวดหมู่: 140px
- ประเภทวิดีโอ: 140px
- ไฟล์แนบ: 140px
- สถานะ: 130px
- วันที่เผยแพร่: 150px
- ผู้สร้าง: 160px
- จัดการ: 70px
7. ช่องชื่อบทเรียน รายละเอียด และผู้สร้าง ให้ใช้ `truncate`
8. Action column ต้องอยู่ขวาสุดและเห็นได้ ไม่โดนตัด
9. ถ้าข้อมูลเยอะ ให้ scroll เฉพาะในตาราง ไม่ใช่ทั้งหน้า
10. ห้ามแก้ API หรือ Business Logic แก้เฉพาะ Layout / className / columns เท่านั้น
ตัวอย่างโครงสร้าง:
<div className="w-full max-w-full overflow-hidden">
<div className="flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
<div className="min-w-0">
<h1>บทเรียนออนไลน์</h1>
<p>เรียนรู้จากวิดีโอและเอกสารประกอบที่ HRD เผยแพร่ให้กับพนักงาน</p>
</div>
<Button className="shrink-0">
+ เพิ่มบทเรียนออนไลน์
</Button>
</div>
<Card className="overflow-hidden">
<div className="overflow-x-auto">
<Table className="w-full min-w-[1050px] table-fixed">
...
</Table>
</div>
</Card>
</div>
ผลลัพธ์ที่ต้องการ:
- หน้าไม่ล้นจอ
- ปุ่มเพิ่มบทเรียนแสดงครบ
- ตารางเลื่อนแนวนอนเฉพาะเมื่อจำเป็น
- Column ไม่เบียดกัน
- Action column แสดงครบ
- Layout เหมือนหน้า ประวัติการอบรม

View File

@@ -0,0 +1,681 @@
# Prompt: แก้ไขปัญหาการแสดงหมายเหตุการตรวจสอบในหน้าผู้ใช้งาน
## บทบาทของคุณ
คุณคือ Senior Full-Stack Engineer และ Software Architect ที่รับผิดชอบตรวจสอบและแก้ไขระบบ Training Management System ซึ่งพัฒนาด้วย Next.js, React, TypeScript และระบบ Permission-first
ให้ตรวจสอบ Codebase ปัจจุบันและแก้ไขปัญหาที่หน้า **รายละเอียดบทเรียนออนไลน์ของผู้ใช้งานทั่วไป** มีการแสดงข้อมูล **หมายเหตุการตรวจสอบ** ซึ่งเป็นข้อมูลภายในของกระบวนการตรวจสอบหรืออนุมัติ และไม่ควรถูกแสดงให้ผู้ใช้งานทั่วไปเห็น
ห้ามแก้ไขเฉพาะการซ่อน UI อย่างเดียวโดยไม่ตรวจสอบ API, DTO, Query และ Permission ที่เกี่ยวข้อง
---
# 1. ปัญหาที่ต้องแก้ไข
จากหน้าใช้งานจริง พบว่าผู้ใช้งานทั่วไปสามารถเห็น Section:
```text
หมายเหตุการตรวจสอบ
```
ทั้งที่บทเรียนอยู่ในสถานะเผยแพร่แล้ว และข้อมูลดังกล่าวเป็นส่วนหนึ่งของกระบวนการตรวจสอบภายใน
ปัญหานี้อาจเกิดจาก:
- Component แสดง `review_note`, `reviewNote`, `review_comment`, `approval_note` หรือฟิลด์ลักษณะเดียวกันโดยตรวจสอบเพียงว่ามีค่าหรือไม่
- หน้า User และหน้า Back Office ใช้ Component เดียวกันโดยไม่มีเงื่อนไข Permission
- API ของผู้ใช้งานทั่วไปส่งข้อมูลหมายเหตุภายในกลับมาด้วย
- DTO หรือ Serializer ไม่ได้แยก Public Field และ Internal Field
- Route หรือ Loader ไม่ได้กรองข้อมูลตาม Permission
- UI ใช้ Role Name แบบ hard-code แทน Permission
- ข้อมูล Approval/Review ถูกนำไปรวมอยู่ใน Public Lesson Detail โดยไม่จำเป็น
---
# 2. วัตถุประสงค์
แก้ไขระบบให้:
1. ผู้ใช้งานทั่วไปไม่เห็นหมายเหตุการตรวจสอบภายใน
2. ผู้ใช้งานทั่วไปไม่ได้รับข้อมูลหมายเหตุภายในจาก API
3. ผู้มี Permission ตรวจสอบหรืออนุมัติยังสามารถเห็นข้อมูลดังกล่าวได้ในหน้าหลังบ้าน
4. บทเรียนที่เผยแพร่แล้วแสดงเฉพาะข้อมูลที่เกี่ยวข้องกับผู้เรียน
5. ไม่มีการเปิดเผยข้อมูลภายในผ่าน Network Response, API Payload หรือ Client State
6. ใช้มาตรฐาน Permission-first ของระบบ
7. ไม่กระทบ Workflow การตรวจสอบ อนุมัติ และเผยแพร่เดิม
---
# 3. ขอบเขตการตรวจสอบ
ให้ตรวจสอบอย่างน้อยในส่วนต่อไปนี้:
- หน้า User Online Lesson Detail
- หน้า Online Lesson List ของผู้ใช้งาน
- หน้า Back Office Online Lesson Detail
- หน้า Create / Edit Online Lesson
- หน้า Review / Approval
- API Route สำหรับดึงรายละเอียดบทเรียน
- Server Action หรือ Service ที่เกี่ยวข้อง
- Query หรือ ORM Select
- DTO / Mapper / Serializer
- Shared Component ที่ใช้แสดงรายละเอียดบทเรียน
- Permission Guard
- TypeScript Types
- Cache หรือ Data Fetching Hook
- Test ที่เกี่ยวข้อง
ให้ค้นหาฟิลด์หรือคำที่เกี่ยวข้อง เช่น:
```text
review_note
reviewNote
review_comment
reviewComment
approval_note
approvalNote
internal_note
internalNote
review_message
reviewMessage
rejection_reason
rejectionReason
```
หากพบชื่อฟิลด์อื่นที่ทำหน้าที่เดียวกัน ให้รวมไว้ในขอบเขตด้วย
---
# 4. พฤติกรรมที่ต้องการ
## 4.1 ผู้ใช้งานทั่วไป
ผู้ใช้งานทั่วไปควรเห็นเฉพาะ:
- ชื่อบทเรียน
- สถานะที่เหมาะสมสำหรับผู้เรียน
- หมวดหมู่
- ผู้เผยแพร่
- วันที่เผยแพร่
- รายละเอียดบทเรียน
- วิดีโอ
- เอกสารประกอบ
- ข้อมูลอื่นที่เกี่ยวข้องกับการเรียน
ผู้ใช้งานทั่วไปต้องไม่เห็น:
- หมายเหตุการตรวจสอบภายใน
- ความเห็นผู้อนุมัติภายใน
- หมายเหตุสำหรับ HRD
- ข้อมูลการพิจารณาภายใน
- ข้อมูลการหารือระหว่างผู้ตรวจสอบ
- ฟิลด์ Internal Workflow อื่นที่ไม่ได้มีไว้สำหรับผู้เรียน
---
## 4.2 ผู้มีสิทธิ์ตรวจสอบหรืออนุมัติ
ผู้มี Permission ที่เกี่ยวข้อง เช่น:
```text
online_lessons:review
online_lessons:approve
online_lessons:manage
```
หรือ Permission จริงที่ระบบใช้อยู่ ควรยังสามารถเห็นหมายเหตุการตรวจสอบในหน้าหลังบ้านได้ตามเดิม
ห้ามเดาชื่อ Permission ให้ตรวจสอบจาก Codebase จริงก่อนใช้งาน
---
## 4.3 กรณีมีข้อความที่ต้องแจ้งผู้ใช้งาน
หากระบบมีความต้องการให้ผู้ใช้งานเห็นข้อความจากผู้ตรวจสอบ ให้แยกข้อมูลออกจากหมายเหตุภายในอย่างชัดเจน เช่น:
```ts
internalReviewNote
employeeFeedback
```
หรือ:
```ts
internalNote
reviewMessage
```
โดยกำหนดว่า:
- `internalReviewNote` แสดงเฉพาะผู้มี Permission ตรวจสอบ
- `employeeFeedback` แสดงให้ผู้ใช้งานเห็นเฉพาะกรณีที่ต้องดำเนินการ เช่น ถูกส่งกลับแก้ไขหรือถูกปฏิเสธ
ห้ามใช้ฟิลด์เดียวกันสำหรับทั้ง Internal Note และข้อความแจ้งผู้ใช้งาน หากความหมายของข้อมูลต่างกัน
---
# 5. ขั้นตอนการตรวจสอบก่อนแก้ไข
ก่อนแก้ไข ให้ตรวจสอบและสรุป:
1. หน้าใดเป็นหน้าที่เกิดปัญหา
2. Component ใดแสดง Section หมายเหตุ
3. ฟิลด์จริงในฐานข้อมูลและ TypeScript คือชื่ออะไร
4. API ใดส่งข้อมูลนี้กลับมา
5. Query หรือ ORM Select ดึงฟิลด์นี้มาหรือไม่
6. หน้า User และ Back Office ใช้ API เดียวกันหรือไม่
7. ใช้ Component ร่วมกันหรือไม่
8. Permission Model ปัจจุบันเป็นแบบใด
9. มี Role-based condition แบบเก่าหรือ Compatibility Mode อยู่หรือไม่
10. มี Test ครอบคลุมเรื่อง Field Visibility หรือไม่
ห้ามแก้ไขทันทีโดยไม่ตรวจสอบ Data Flow ตั้งแต่ Database → Service → API → Client → UI
---
# 6. แนวทางแก้ไขระดับ UI
หากพบว่า Component แสดงข้อมูลโดยตรวจสอบเพียงว่ามีค่า เช่น:
```tsx
{lesson.reviewNote && (
<ReviewNote note={lesson.reviewNote} />
)}
```
ให้แก้เป็น Permission-based Rendering เช่น:
```tsx
const canViewInternalReviewNote = hasPermission(
ONLINE_LESSON_PERMISSIONS.REVIEW,
);
{canViewInternalReviewNote && lesson.reviewNote && (
<ReviewNote note={lesson.reviewNote} />
)}
```
หรือใช้ Permission Helper จริงของระบบ
ข้อกำหนด:
- ห้ามตรวจสอบจากชื่อ Role โดยตรง หากระบบใช้ Permission-first แล้ว
- ห้ามใช้เงื่อนไขแบบ `role === "user"` เป็นวิธีหลัก
- ห้ามแสดง Section หากไม่มีข้อมูล
- ห้ามแสดงกรอบว่าง
- ห้ามแสดงหัวข้อโดยไม่มีเนื้อหา
- หน้า User ต้องไม่ render Internal Review Component
---
# 7. แนวทางแก้ไขระดับ API
ต้องป้องกันตั้งแต่ระดับ API ไม่ใช่ซ่อน UI เพียงอย่างเดียว
สำหรับ Endpoint ของผู้ใช้งานทั่วไป ให้คืนเฉพาะ Public Fields เช่น:
```ts
{
id,
title,
description,
category,
status,
publishedAt,
publishedBy,
videoUrl,
videoFileUrl,
thumbnailUrl,
attachments
}
```
ไม่ควรคืน:
```ts
reviewNote
internalNote
reviewedBy
reviewedAt
approvalComment
approvalHistory
```
เว้นแต่ผู้ใช้งานมี Permission ที่เหมาะสม
ตัวอย่างแนวทาง:
```ts
const canViewInternalReviewNote = await permissionService.hasPermission(
user,
ONLINE_LESSON_PERMISSIONS.REVIEW,
);
return {
...publicLessonFields,
...(canViewInternalReviewNote
? {
reviewNote: lesson.reviewNote,
reviewedBy: lesson.reviewedBy,
reviewedAt: lesson.reviewedAt,
}
: {}),
};
```
ให้เลือกแนวทางที่เหมาะกับ Architecture จริงของระบบ
---
# 8. Query และ ORM Select
หากใช้ Prisma หรือ ORM ให้แยก Query สำหรับ Public View และ Internal View
ตัวอย่าง:
```ts
const publicLessonSelect = {
id: true,
title: true,
description: true,
category: true,
status: true,
publishedAt: true,
videoUrl: true,
videoFileUrl: true,
thumbnailUrl: true,
attachments: true,
} satisfies Prisma.OnlineLessonSelect;
```
และสำหรับ Back Office:
```ts
const internalLessonSelect = {
...publicLessonSelect,
reviewNote: true,
reviewedBy: true,
reviewedAt: true,
} satisfies Prisma.OnlineLessonSelect;
```
ข้อกำหนด:
- อย่าดึง Internal Field มาโดยไม่จำเป็น
- อย่าใช้ `select: { ...ทุกฟิลด์ }` หรือดึงทั้ง Record หากไม่จำเป็น
- แยก Public DTO และ Internal DTO อย่างชัดเจน
- TypeScript Type ต้องสะท้อน Field ที่มีจริงในแต่ละ View
---
# 9. DTO และ Type Standardization
ให้ตรวจสอบว่ามี Type เดียวถูกใช้ทั้งหน้า User และ Back Office หรือไม่
หากมี ให้พิจารณาแยกเป็น:
```ts
type PublicOnlineLessonDetail = {
id: string;
title: string;
description: string | null;
category: string;
status: string;
publishedAt: string | null;
videoUrl: string | null;
attachments: Attachment[];
};
```
```ts
type InternalOnlineLessonDetail = PublicOnlineLessonDetail & {
reviewNote: string | null;
reviewedBy: Reviewer | null;
reviewedAt: string | null;
};
```
ห้ามทำให้ Public Type มี Internal Field ที่ผู้ใช้งานทั่วไปไม่ควรได้รับ
---
# 10. Shared Component
หากหน้า User และ Back Office ใช้ Component เดียวกัน ให้เลือกแนวทางใดแนวทางหนึ่ง:
## ทางเลือก A: แยก Component
```text
PublicOnlineLessonDetail
InternalOnlineLessonDetail
```
เหมาะเมื่อโครงสร้างข้อมูลและ UI ต่างกันชัดเจน
## ทางเลือก B: ใช้ Component เดียวแต่มี Capability Props
```tsx
<OnlineLessonDetail
lesson={lesson}
canViewInternalReviewNote={canViewInternalReviewNote}
/>
```
ข้อกำหนด:
- ห้ามส่ง Permission Object ขนาดใหญ่โดยไม่จำเป็น
- ใช้ Boolean Capability ที่อ่านง่าย
- ต้องไม่ทำให้ Public Component รับ Internal Data โดยไม่จำเป็น
- เลือกวิธีที่เข้ากับโครงสร้างเดิมและดูแลต่อได้ง่ายที่สุด
---
# 11. สถานะบทเรียน
สำหรับบทเรียนสถานะ `published` หรือสถานะเผยแพร่แล้ว:
- หน้า User ต้องแสดงเฉพาะข้อมูลเพื่อการเรียน
- ต้องไม่แสดง Review Note
- ต้องไม่แสดง Internal Approval Metadata
- ต้องไม่แสดงข้อความจากขั้นตอนก่อน Publish ที่ไม่เกี่ยวกับผู้เรียน
หากระบบมี Status อื่น เช่น:
```text
draft
pending_review
approved
rejected
returned
scheduled
published
archived
```
ให้กำหนด Visibility ให้ชัดเจนตาม Permission และ Context
---
# 12. Permission และ Security
ต้องตรวจสอบทั้งสองระดับ:
## Server-side
- ตรวจสอบ Permission ก่อนคืน Internal Field
- ห้ามพึ่ง Client-side Condition เพียงอย่างเดียว
- Endpoint สำหรับ User ต้องไม่เปิดเผยข้อมูลภายใน
- ห้ามใช้ Client Filtering เป็น Authorization
## Client-side
- ซ่อน Section ที่ไม่มีสิทธิ์
- ไม่ Render Internal Component
- ไม่เก็บ Internal Data ไว้ใน State ของหน้า User
- ไม่ส่ง Internal Data ผ่าน Props โดยไม่จำเป็น
---
# 13. Backward Compatibility
การแก้ไขต้องไม่กระทบ:
- หน้า Review ของ HRD
- หน้า Approval ของ HRD Manager
- หน้า Admin
- การบันทึก Review Note
- การแก้ไข Review Note
- Workflow Draft → Review → Approve → Publish
- Audit Log
- Notification
- Versioning
- Preview ก่อน Publish
- Schedule Publish
หากหน้า Back Office ใช้ API เดียวกับหน้า User ให้แยก Response ตาม Permission หรือแยก Endpoint อย่างเหมาะสม
---
# 14. UI/UX ที่ต้องการหลังแก้ไข
หน้า User Online Lesson Detail ควรมีโครงสร้าง:
```text
ชื่อบทเรียน + สถานะ
หมวดหมู่ / ผู้เผยแพร่ / วันที่เผยแพร่
รายละเอียดบทเรียน
วิดีโอ
เอกสารประกอบ
```
ต้องไม่มี:
```text
หมายเหตุการตรวจสอบ
```
เว้นแต่เป็นข้อความที่ตั้งใจส่งถึงผู้ใช้งานจริงและถูกจัดเก็บในฟิลด์แยกที่เหมาะสม
หากไม่มีเอกสารประกอบ ให้ใช้ข้อความตามมาตรฐานเดิมของระบบ เช่น:
```text
ไม่มีไฟล์แนบ
```
โดยไม่เกี่ยวข้องกับการแก้ไข Review Note
---
# 15. Acceptance Criteria
งานถือว่าเสร็จเมื่อผ่านเงื่อนไขต่อไปนี้:
## User View
- ผู้ใช้งานทั่วไปไม่เห็น Section หมายเหตุการตรวจสอบ
- ผู้ใช้งานทั่วไปไม่เห็น Internal Review Note ใน HTML
- ผู้ใช้งานทั่วไปไม่เห็น Internal Review Note ใน API Response
- ผู้ใช้งานทั่วไปไม่เห็นข้อมูลผ่าน Network Tab
- หน้า Published Lesson แสดงข้อมูลปกติครบถ้วน
- ไม่มีกรอบว่างหรือหัวข้อว่าง
## Internal View
- ผู้มี Permission Review ยังเห็นหมายเหตุการตรวจสอบ
- ผู้มี Permission Approve ยังเห็นข้อมูลที่จำเป็น
- การเพิ่มหรือแก้ไขหมายเหตุยังทำงานได้
- Workflow เดิมไม่เสีย
- Audit Log ยังถูกบันทึกตามเดิม
## Technical
- Permission Check อยู่ฝั่ง Server
- UI ใช้ Permission-first
- Public DTO ไม่มี Internal Field
- ไม่มี Role Hard-code ใหม่
- TypeScript ผ่าน
- ESLint ผ่าน
- Build ผ่าน
- Tests ผ่าน
- ไม่มี Regression ใน Online Lesson Module
---
# 16. Test Cases
## Test Case 1: ผู้ใช้งานทั่วไปเปิดบทเรียนเผยแพร่แล้ว
1. Login ด้วยบัญชี User
2. เปิดหน้า Online Lessons
3. เปิดรายละเอียดบทเรียนที่ Published
4. ตรวจสอบว่าไม่พบหัวข้อ `หมายเหตุการตรวจสอบ`
5. ตรวจสอบ Network Response ว่าไม่มี `reviewNote` หรือฟิลด์ภายใน
6. ตรวจสอบว่าวิดีโอและเอกสารยังแสดงปกติ
## Test Case 2: HRD เปิดหน้าหลังบ้าน
1. Login ด้วยบัญชีที่มี Permission Review
2. เปิด Online Lesson Detail ฝั่ง Back Office
3. ตรวจสอบว่ายังเห็นหมายเหตุการตรวจสอบ
4. ตรวจสอบว่าสามารถบันทึกหรือแก้ไขหมายเหตุได้
5. ตรวจสอบว่า Refresh แล้วข้อมูลยังอยู่
## Test Case 3: ไม่มีหมายเหตุ
1. เปิดรายการที่ไม่มี Review Note
2. ตรวจสอบว่าไม่แสดงหัวข้อหรือกรอบว่าง
3. ตรวจสอบ Layout ไม่เกิดช่องว่างผิดปกติ
## Test Case 4: ไม่มี Permission
1. เรียก Endpoint ด้วยบัญชีที่ไม่มี Permission
2. ตรวจสอบว่า Response ไม่มี Internal Field
3. ตรวจสอบว่าไม่สามารถเข้าถึงผ่านการแก้ URL หรือ Client State
## Test Case 5: Compatibility Mode
1. ตรวจสอบ Role เก่าหรือ Business Role ที่ยังมีอยู่
2. ยืนยันว่า Visibility ยึด Permission เป็นหลัก
3. ตรวจสอบว่า Compatibility Code ไม่ทำให้ User เห็นข้อมูลภายใน
---
# 17. แนวทางการดำเนินงาน
## Phase 1: Audit
- ค้นหา Component ที่แสดงหมายเหตุ
- ค้นหา API และ Query ที่ส่งข้อมูล
- ค้นหา Permission ที่เกี่ยวข้อง
- ตรวจสอบ Shared Component
- ตรวจสอบ DTO และ Types
- ตรวจสอบ Tests
## Phase 2: Design
- กำหนด Public Fields
- กำหนด Internal Fields
- กำหนด Permission Rule
- เลือกวิธีแยก Component หรือใช้ Capability Props
- กำหนด API Response Strategy
## Phase 3: Implementation
- แก้ Query หรือ Select
- แก้ DTO
- แก้ API Response
- แก้ UI Rendering
- แก้ TypeScript Types
- เพิ่มหรือปรับ Test
## Phase 4: Verification
- ทดสอบ User View
- ทดสอบ HRD View
- ตรวจสอบ Network Payload
- Run Type Check
- Run Lint
- Run Tests
- Run Build
- ตรวจสอบ Regression
---
# 18. Implementation Report
หลังแก้ไขเสร็จ ให้สร้างรายงาน Markdown โดยใช้โครงสร้าง:
```md
# Online Lesson Review Note Visibility Fix Report
## 1. Executive Summary
## 2. Problem Found
## 3. Root Cause
## 4. Data Flow Before Fix
## 5. Permission Rule Applied
## 6. Files Changed
## 7. API Changes
## 8. UI Changes
## 9. DTO and Type Changes
## 10. Test Results
## 11. Security Verification
## 12. Regression Check
## 13. Remaining Risks
```
ในหัวข้อ Files Changed ให้ระบุ:
- Path
- สิ่งที่แก้ไข
- เหตุผล
- ผลกระทบ
- วิธีทดสอบ
---
# 19. ข้อจำกัดสำคัญ
- ห้ามแก้เฉพาะ CSS เพื่อซ่อนข้อมูล
- ห้ามแก้เฉพาะ UI โดยไม่แก้ API
- ห้ามใช้ Role Name แบบ hard-code เป็นวิธีหลัก
- ห้ามเปลี่ยน Permission Model โดยไม่จำเป็น
- ห้ามเปลี่ยน Workflow Approval
- ห้ามลบ Review Note ออกจากระบบ
- ห้ามกระทบหน้าหลังบ้าน
- ห้ามแก้ Database Schema หากไม่จำเป็น
- ห้ามเพิ่ม Library ใหม่โดยไม่จำเป็น
- ห้ามลบ Audit Log
- ห้ามเปลี่ยนสถานะบทเรียน
- ห้ามเปลี่ยน API Contract ส่วนที่ไม่เกี่ยวข้อง
- ห้ามแก้ Module อื่นโดยไม่มีเหตุผล
หากพบปัญหาที่เกี่ยวข้องแต่ไม่อยู่ในขอบเขต ให้บันทึกไว้ใน Report โดยไม่แก้ไข เว้นแต่เป็น Blocking Issue
---
# 20. Definition of Done
งานนี้ถือว่าเสร็จสมบูรณ์เมื่อ:
1. ผู้ใช้งานทั่วไปไม่เห็นหมายเหตุการตรวจสอบ
2. API ของผู้ใช้งานทั่วไปไม่ส่ง Internal Review Data
3. ผู้มี Permission ยังเห็นและใช้งานหมายเหตุได้ตามเดิม
4. Public DTO และ Internal DTO แยกชัดเจน
5. UI ใช้ Permission-first
6. ไม่มี Role Hard-code ใหม่
7. ไม่มีข้อมูลภายในใน Network Response
8. TypeScript, Lint, Tests และ Build ผ่าน
9. มี Implementation Report
10. ไม่เกิด Regression ต่อ Workflow Online Lesson
---
# คำสั่งเริ่มต้น
เริ่มจากตรวจสอบ Codebase จริงก่อน โดยค้นหา Data Flow ของหมายเหตุการตรวจสอบตั้งแต่ Database, ORM Query, Service, API, DTO, Hook และ UI
จากนั้นให้สรุป:
1. Root Cause
2. ฟิลด์ที่เกี่ยวข้อง
3. API ที่เกี่ยวข้อง
4. Component ที่เกี่ยวข้อง
5. Permission ที่ควรใช้
6. ไฟล์ที่ต้องแก้ไข
7. แนวทางป้องกันข้อมูลรั่วไหล
เมื่อสรุปแล้ว ให้ดำเนินการแก้ไขครบทั้ง Server-side และ Client-side พร้อมทดสอบและจัดทำ Implementation Report
ไม่ต้องหยุดเพื่อถามยืนยันระหว่างดำเนินงาน เว้นแต่พบข้อขัดแย้งที่ไม่สามารถตัดสินใจได้จาก Codebase และ Requirement ที่มีอยู่

View File

@@ -0,0 +1,92 @@
# Online Lesson Review Note Visibility Fix Report
## 1. Executive Summary
Fixed the online lesson review note visibility leak by filtering internal workflow fields at the DTO serialization layer and gating the detail UI with a permission-derived capability. General users can still view published lesson content, but they no longer receive or render internal review data such as review comments, reviewer IDs, approval IDs, and workflow timestamps.
## 2. Problem Found
The online lesson detail page showed the internal review note section when `review_comment` existed. The same API serializer was used for learner-facing and back-office responses, so public/general users could also receive internal workflow data in network responses.
## 3. Root Cause
`serializeOnlineLesson()` always included workflow fields regardless of the current user's permissions. The detail component then rendered `review_comment` based only on whether the field had a value.
## 4. Data Flow Before Fix
Database `online_lessons.review_comment` and workflow actor fields were selected by `getBaseSelect()`, serialized by `serializeOnlineLesson()`, returned by `/api/online-lessons` and `/api/online-lessons/[id]`, cached by TanStack Query, and rendered by `OnlineLessonDetailPage`.
## 5. Permission Rule Applied
Internal review data is included only when `canReadAllContent('online_lesson', permissions)` returns true. This maps to the existing `online_lesson:read_all` permission and avoids adding new hard-coded role checks.
## 6. Files Changed
`src/features/online-lessons/server/online-lesson-data.ts`
- Added `includeInternalReviewData` serialization option.
- Public serialization omits internal workflow fields.
- List responses now include internal fields only for users with online lesson read-all permission.
`src/app/api/online-lessons/[id]/route.ts`
- Detail GET now serializes public or internal DTO based on `canReadAllContent`.
- Removed an unused local variable flagged by lint.
`src/features/online-lessons/api/types.ts`
- Marked internal workflow fields as optional because public DTOs intentionally omit them.
`src/app/dashboard/online-lessons/[id]/page.tsx`
- Computes `canViewInternalReviewData` on the server from existing permissions and passes it to the client detail component.
`src/features/online-lessons/components/online-lesson-detail-page.tsx`
- Renders the review note section only when `canViewInternalReviewData` is true.
- Hides creator metadata from the learner-facing detail header.
## 7. API Changes
For users without `online_lesson:read_all`, `/api/online-lessons` and `/api/online-lessons/[id]` no longer include these internal fields:
- `review_comment`
- `submitted_at`
- `submitted_by`
- `reviewed_at`
- `reviewed_by`
- `approved_at`
- `approved_by`
- `published_by`
- `created_by`
- `created_by_name`
- `updated_by`
- `updated_by_name`
Back-office users with `online_lesson:read_all` continue to receive these fields.
## 8. UI Changes
The user-facing detail page no longer displays the review note block for general users. Back-office users with the permission-derived capability can still see review notes in the detail view and form/edit workflow.
## 9. DTO and Type Changes
The shared `OnlineLesson` contract now treats internal workflow fields as optional so public DTOs can omit them without sending `null` placeholders or leaking field names.
## 10. Test Results
- `npm run lint -- src/features/online-lessons/api/types.ts src/features/online-lessons/server/online-lesson-data.ts src/app/api/online-lessons/[id]/route.ts src/app/dashboard/online-lessons/[id]/page.tsx src/features/online-lessons/components/online-lesson-detail-page.tsx` passed.
- `npx tsc --noEmit --pretty false` passed.
- `npm run build` passed.
## 11. Security Verification
The protection is enforced server-side before JSON serialization, so general users no longer receive internal review fields in API responses. The UI guard is a second layer and uses a capability computed from the same permission rule.
## 12. Regression Check
Existing workflow mutations still use the default internal serializer for create/update/audit flows. Review, return, reject, approve, publish, and archive behavior was not changed.
## 13. Remaining Risks
No automated browser test was added for inspecting the exact network payload. Manual verification should still include logging in as a general user, opening a published lesson, and confirming the response does not include `review_comment` or workflow actor fields.

View File

@@ -0,0 +1,26 @@
หลังแก้ไข Import Employee แล้ว หน้า `/dashboard/import-employees` แสดงภาษาไทยเพี้ยนเป็นตัวอักษรผิดรูป/อ่านไม่ได้
กรุณาแก้ไขปัญหา UI ภาษาไทยเพี้ยน โดยทำตามนี้:
1. ตรวจสอบไฟล์ทั้งหมดที่เกี่ยวข้องกับหน้า Import Employees
2. ตรวจสอบว่าไฟล์ถูกบันทึกเป็น UTF-8
3. ตรวจสอบข้อความภาษาไทยใน component/page ว่าถูกแก้หรือ corrupt ระหว่างแก้ไขหรือไม่
4. ถ้าข้อความไทยเสีย ให้ restore/เขียนข้อความใหม่เป็นภาษาไทยปกติ
5. ตรวจสอบ font ที่ใช้ใน layout/global css ว่ารองรับภาษาไทย เช่น `Sarabun`, `Noto Sans Thai`, หรือ system font
6. ห้ามแก้ logic import ที่เพิ่งทำเสร็จ หากไม่จำเป็น
7. แก้เฉพาะปัญหาการแสดงผลภาษาไทยในหน้า import employees และ component ที่เกี่ยวข้อง
8. ทดสอบหน้า `/dashboard/import-employees` ให้ข้อความภาษาไทยอ่านได้ปกติ
ข้อความที่ควรแสดงโดยประมาณ:
- นำเข้าพนักงาน
- อัปโหลดไฟล์ Excel เพื่อเพิ่มหรืออัปเดตข้อมูลพนักงานแบบกลุ่ม
- เลือกไฟล์ Excel
- ดาวน์โหลดเทมเพลต
- นำเข้าข้อมูลพนักงาน
- เงื่อนไขการนำเข้า
- ระบบจะนับรหัสพนักงาน 1 รหัสเป็นพนักงาน 1 คน
- หากพนักงานมีหลายหลักสูตร ระบบจะบันทึกประวัติการอบรมครบทุกหลักสูตร
- ระบบจะสรุปจำนวนชั่วโมงตามประเภท K/S/A ให้พนักงานแต่ละคน
หลังแก้ไขเสร็จ ให้สรุปไฟล์ที่แก้ สาเหตุ และวิธีทดสอบใน report.md

View File

@@ -0,0 +1,784 @@
# Fix User Training Filters — ประเภทการอบรมและสถานะไม่กรองข้อมูลจริง
## เป้าหมาย
แก้ไขปัญหาในหน้าผู้ใช้งานที่แสดงรายการประวัติการอบรม โดยตัวกรองต่อไปนี้ไม่สามารถกรองข้อมูลได้จริง
- ประเภทการอบรม
- สถานะรายการ
หลังแก้ไขแล้ว เมื่อผู้ใช้งานเลือกค่า Filter ระบบต้องแสดงเฉพาะข้อมูลที่ตรงกับเงื่อนไขที่เลือก และต้องทำงานร่วมกับ Search, Pagination, Sorting และ Filter อื่นที่มีอยู่เดิมได้อย่างถูกต้อง
---
## ปัญหาปัจจุบัน
ในหน้ารายการประวัติการอบรมของผู้ใช้งาน มี UI สำหรับเลือก Filter ดังนี้
1. ประเภทการอบรม
2. สถานะ
แต่เมื่อเลือกค่าแล้วพบว่า:
- ตารางยังแสดงข้อมูลทั้งหมด
- ข้อมูลในตารางไม่เปลี่ยนแปลง
- ไม่มีการ Refresh หรือ Refetch ข้อมูล
- Filter อาจถูกเปลี่ยนเฉพาะใน UI แต่ไม่ได้ส่งไปยัง API
- Backend อาจรับค่า Filter แต่ไม่ได้นำไปใช้ใน Query
- ค่าใน Select อาจไม่ตรงกับค่าที่เก็บในฐานข้อมูล
- Query Key หรือ URL Search Params อาจไม่มีค่า Filter อยู่ด้วย
---
## ขอบเขตการตรวจสอบ
ตรวจสอบ Flow ทั้งหมดตั้งแต่ UI จนถึง Database โดยห้ามแก้เฉพาะหน้า UI หาก Backend ยังไม่รองรับการกรองจริง
Flow ที่ต้องตรวจสอบ:
```text
Filter UI
→ Filter State
→ URL Search Params
→ API Request
→ API Validation
→ Service / Repository
→ Database Query
→ API Response
→ Table Rendering
```
---
## 1. ตรวจสอบหน้ารายการของผู้ใช้งาน
ค้นหาหน้ารายการประวัติการอบรมของผู้ใช้งาน เช่น:
```text
/dashboard/training-records
/dashboard/my-training-records
/dashboard/user/training-records
```
หรือ Route ที่ระบบใช้งานจริง
ตรวจสอบ Component ที่เกี่ยวข้อง เช่น:
```text
TrainingRecordList
TrainingRecordTable
TrainingRecordToolbar
TrainingRecordFilters
UserTrainingRecordTable
```
ต้องตรวจสอบว่าตัวกรองทั้งสองเชื่อมกับ State จริง ไม่ใช่แสดง UI อย่างเดียว
---
## 2. Filter ประเภทการอบรม
ตรวจสอบว่า Filter ประเภทการอบรมใช้ Field ใดในระบบจริง เช่น:
```ts
trainingType;
training_type;
type;
trainingMode;
training_mode;
```
ค่าที่เลือกจาก UI ต้องตรงกับค่าที่เก็บในฐานข้อมูล
ตัวอย่างค่าที่เป็นไปได้:
```ts
online;
offline;
```
หรือ:
```ts
internal;
external;
```
ห้ามสมมติค่าขึ้นใหม่ ให้ตรวจสอบจาก Schema, Enum, Zod Schema, TypeScript Type และข้อมูลใน Database ก่อน
ตัวอย่างโครงสร้าง Select:
```tsx
<Select
value={trainingType}
onValueChange={(value) => {
setTrainingType(value);
setPage(1);
}}
>
<SelectTrigger>
<SelectValue placeholder="ประเภทการอบรม" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all"></SelectItem>
<SelectItem value="online"></SelectItem>
<SelectItem value="offline"></SelectItem>
</SelectContent>
</Select>
```
ค่า `"all"` ต้องใช้สำหรับล้างเงื่อนไขเท่านั้น และไม่ควรถูกส่งไปกรองใน Database
ตัวอย่างการสร้าง Filter:
```ts
const filters = {
page,
limit,
...(search && { search }),
...(trainingType &&
trainingType !== "all" && {
trainingType,
}),
};
```
---
## 3. Filter สถานะ
ตรวจสอบสถานะที่ระบบรองรับจริง เช่น:
```ts
draft;
pending;
approved;
rejected;
returned;
cancelled;
```
ห้ามกำหนดรายการสถานะจากการคาดเดา ให้ตรวจสอบจาก:
- Database Schema
- Enum
- Zod Schema
- TypeScript Type
- Status Badge
- Workflow ปัจจุบันของระบบ
- API Endpoint ที่เกี่ยวข้อง
ตัวอย่าง Select:
```tsx
<Select
value={status}
onValueChange={(value) => {
setStatus(value);
setPage(1);
}}
>
<SelectTrigger>
<SelectValue placeholder="สถานะ" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all"></SelectItem>
<SelectItem value="draft"></SelectItem>
<SelectItem value="pending"></SelectItem>
<SelectItem value="approved"></SelectItem>
<SelectItem value="rejected"></SelectItem>
</SelectContent>
</Select>
```
ตัวอย่างการสร้าง Filter:
```ts
const filters = {
page,
limit,
...(search && { search }),
...(status && status !== "all" && { status }),
};
```
---
## 4. เชื่อม Filter กับ URL Search Params
หากหน้าปัจจุบันใช้ URL Search Params ให้ใช้รูปแบบเดียวกับ Filter อื่นที่มีอยู่เดิม
ตัวอย่าง URL:
```text
/dashboard/training-records?trainingType=online&status=pending&page=1
```
เมื่อเปลี่ยน Filter ต้อง:
1. อัปเดต Search Params
2. Reset หน้า Pagination กลับเป็นหน้า 1
3. Refetch หรือ Reload ข้อมูลตามค่าปัจจุบัน
4. ไม่ลบ Search Params อื่นที่ยังใช้งานอยู่
ตัวอย่าง:
```ts
const handleTrainingTypeChange = (value: string) => {
const params = new URLSearchParams(searchParams.toString());
if (value === "all") {
params.delete("trainingType");
} else {
params.set("trainingType", value);
}
params.set("page", "1");
router.replace(`${pathname}?${params.toString()}`);
};
```
ทำแนวทางเดียวกันกับ `status`
---
## 5. ตรวจสอบ Query Key และการ Refetch
หากใช้ React Query หรือ TanStack Query ต้องนำค่า Filter เข้าไปอยู่ใน `queryKey`
ตัวอย่างที่ไม่ถูกต้อง:
```ts
queryKey: ["training-records"];
```
ตัวอย่างที่ควรเป็น:
```ts
queryKey: [
"training-records",
{
page,
limit,
search,
trainingType,
status,
sort,
},
];
```
หากใช้ SWR ต้องนำ Query String หรือ Filter เข้าไปอยู่ใน Key เช่นกัน
```ts
const queryString = new URLSearchParams({
page: String(page),
limit: String(limit),
...(search && { search }),
...(trainingType &&
trainingType !== "all" && {
trainingType,
}),
...(status &&
status !== "all" && {
status,
}),
}).toString();
const { data } = useSWR(`/api/training-records?${queryString}`, fetcher);
```
เมื่อ Filter เปลี่ยน ระบบต้อง Refetch อัตโนมัติ โดยไม่ต้องกด Refresh หน้า Browser
---
## 6. ตรวจสอบ API Request
ตรวจสอบว่า Request ส่งค่า Filter ไปยัง API จริง
ตัวอย่าง:
```text
GET /api/training-records?trainingType=online&status=pending&page=1&limit=10
```
ตรวจสอบผ่าน:
- Browser Network Tab
- Server Log
- API Handler
- Query Parser
ห้ามส่งค่า:
```text
trainingType=all
status=all
```
หากเลือก “ทั้งหมด” ต้องไม่ส่ง Parameter นั้น หรือส่งเป็น `undefined`
---
## 7. ตรวจสอบ API Validation
เพิ่มหรือแก้ไข Schema สำหรับ Query Parameters ให้รองรับ Filter ทั้งสอง
ตัวอย่าง:
```ts
const trainingRecordQuerySchema = z.object({
page: z.coerce.number().int().positive().default(1),
limit: z.coerce.number().int().positive().max(100).default(10),
search: z.string().trim().optional(),
trainingType: trainingTypeSchema.optional(),
status: trainingRecordStatusSchema.optional(),
sort: z.string().optional(),
});
```
ควรใช้ Enum หรือ Schema ที่มีอยู่เดิม ห้ามสร้างค่าซ้ำหลายจุด
ตัวอย่าง:
```ts
const trainingTypeSchema = z.enum(["online", "offline"]);
const trainingRecordStatusSchema = z.enum([
"draft",
"pending",
"approved",
"rejected",
]);
```
รายการจริงต้องอ้างอิงจากระบบปัจจุบัน
หากได้รับค่าที่ไม่ถูกต้อง ควรตอบกลับด้วย Validation Error ที่เหมาะสม ไม่ควร silently ignore Filter
---
## 8. ตรวจสอบ Service หรือ Repository
นำค่าที่ผ่าน Validation แล้วส่งต่อไปยัง Service หรือ Repository
ตัวอย่าง:
```ts
const result = await getTrainingRecords({
userId: currentUser.id,
page: query.page,
limit: query.limit,
search: query.search,
trainingType: query.trainingType,
status: query.status,
sort: query.sort,
});
```
ต้องรักษาเงื่อนไขสำคัญของหน้าผู้ใช้งาน คือผู้ใช้งานต้องเห็นเฉพาะข้อมูลของตนเอง
ตัวอย่าง:
```ts
where: {
employeeId: currentEmployee.id,
...(trainingType && {
trainingType,
}),
...(status && {
status,
}),
}
```
ห้ามแก้ Filter แล้วทำให้ผู้ใช้งานสามารถเห็นข้อมูลของพนักงานคนอื่นได้
---
## 9. ตรวจสอบ Database Query
หากใช้ Prisma ให้เพิ่มเงื่อนไข Filter ใน `where`
ตัวอย่าง:
```ts
const where: Prisma.TrainingRecordWhereInput = {
employeeId: currentEmployee.id,
...(search && {
OR: [
{
courseName: {
contains: search,
mode: "insensitive",
},
},
{
providerName: {
contains: search,
mode: "insensitive",
},
},
],
}),
...(trainingType && {
trainingType,
}),
...(status && {
status,
}),
};
```
จากนั้นใช้ `where` ชุดเดียวกันทั้ง Query ข้อมูลและ Query นับจำนวน
```ts
const [items, total] = await Promise.all([
prisma.trainingRecord.findMany({
where,
skip,
take: limit,
orderBy,
}),
prisma.trainingRecord.count({
where,
}),
]);
```
ต้องใช้เงื่อนไขเดียวกันทั้ง `findMany` และ `count` เพื่อไม่ให้ Pagination แสดงจำนวนผิด
หากใช้ SQL โดยตรง ต้องเพิ่ม Parameterized Query และห้ามต่อ SQL String แบบไม่ปลอดภัย
---
## 10. รองรับการใช้หลาย Filter พร้อมกัน
Filter ต้องทำงานแบบ AND
ตัวอย่าง:
```text
ประเภทการอบรม = ออนไลน์
สถานะ = รอตรวจสอบ
```
ผลลัพธ์ต้องแสดงเฉพาะรายการที่:
```text
trainingType = online
AND
status = pending
```
และยังต้องทำงานร่วมกับ Search เช่น:
```text
search = React
AND
trainingType = online
AND
status = pending
```
---
## 11. Reset Pagination เมื่อ Filter เปลี่ยน
เมื่อผู้ใช้งานอยู่หน้า 3 แล้วเปลี่ยน Filter ระบบต้องกลับไปหน้า 1 เพื่อป้องกัน Empty State ที่เกิดจาก Page เดิมไม่มีข้อมูล
ตัวอย่าง:
```ts
onValueChange={(value) => {
setTrainingType(value);
setPagination((previous) => ({
...previous,
pageIndex: 0,
}));
}}
```
หากใช้ URL:
```ts
params.set("page", "1");
```
---
## 12. ปุ่มล้าง Filter
หากหน้าปัจจุบันมีปุ่ม Reset หรือ Clear Filter ต้องล้างค่าทั้งสองได้จริง
ค่าที่ต้องล้าง:
- Search
- ประเภทการอบรม
- สถานะ
- Filter อื่นที่อยู่ใน Toolbar ตามพฤติกรรมเดิม
- Pagination กลับไปหน้า 1
ตัวอย่าง:
```ts
const clearFilters = () => {
setSearch("");
setTrainingType("all");
setStatus("all");
setPage(1);
};
```
หากใช้ Search Params ต้องลบ Parameter ที่เกี่ยวข้องออกจาก URL
```ts
params.delete("trainingType");
params.delete("status");
params.set("page", "1");
```
---
## 13. Loading และ Empty State
เมื่อ Filter เปลี่ยน:
- แสดง Loading State ตามมาตรฐานเดิมของระบบ
- ป้องกันการกด Filter ซ้ำระหว่าง Pending หากจำเป็น
- ไม่แสดงข้อมูลเก่าที่ทำให้ผู้ใช้เข้าใจผิด
- หลังโหลดเสร็จต้องแสดงข้อมูลใหม่ทันที
เมื่อไม่มีข้อมูลตรงกับ Filter ให้แสดงข้อความ เช่น:
```text
ไม่พบรายการประวัติการอบรมที่ตรงกับเงื่อนไข
```
ควรมีปุ่ม:
```text
ล้างตัวกรอง
```
ไม่ควรใช้ข้อความทั่วไปว่า “ไม่มีข้อมูล” หากมี Filter ทำงานอยู่ เพราะผู้ใช้อาจเข้าใจว่าไม่มีประวัติการอบรมทั้งหมด
---
## 14. ตรวจสอบ Mapping ของ Label และ Value
ต้องแยกค่าที่แสดงกับค่าที่ส่งไป Backend อย่างชัดเจน
ตัวอย่าง:
```ts
const TRAINING_TYPE_OPTIONS = [
{
label: "ทั้งหมด",
value: "all",
},
{
label: "ออนไลน์",
value: "online",
},
{
label: "ออฟไลน์",
value: "offline",
},
];
```
ห้ามใช้ Label ภาษาไทยเป็น Database Value เว้นแต่ Schema ปัจจุบันเก็บค่าเป็นภาษาไทยจริง
ตัวอย่างที่ควรหลีกเลี่ยง:
```ts
<SelectItem value="ออนไลน์"></SelectItem>
```
หาก Database เก็บค่าเป็น:
```text
online
```
---
## 15. ใช้ Constant และ Type กลางของระบบ
หากมี Constant หรือ Enum อยู่แล้ว ให้ใช้ของเดิม เช่น:
```ts
TRAINING_TYPES;
TRAINING_RECORD_STATUSES;
TrainingType;
TrainingRecordStatus;
```
ห้ามประกาศรายการซ้ำแยกกันใน:
- Filter UI
- API Schema
- Status Badge
- Form
- Database Query
เพราะอาจทำให้ค่าไม่ตรงกันในอนาคต
ควรมี Source of Truth เดียวสำหรับ:
- Value
- Label
- Description
- Badge Variant
- Permission หรือ Workflow ที่เกี่ยวข้อง
---
## 16. ห้ามเปลี่ยน Business Rule เดิม
การแก้ไขครั้งนี้เป็นการแก้ Filter เท่านั้น
ห้ามเปลี่ยนโดยไม่จำเป็น:
- Workflow การอนุมัติ
- Permission
- สิทธิ์ของ Employee
- สิทธิ์ของ HRD
- การสร้างหรือแก้ไขรายการ
- Status Transition
- Sorting เริ่มต้น
- รูปแบบ Pagination
- Response Structure ของ API
- UI Style หลักของระบบ
หน้าผู้ใช้งานต้องยังคงเห็นเฉพาะรายการของตนเองตาม Permission เดิม
---
## 17. Test Cases ที่ต้องตรวจสอบ
### Test Case 1: Filter ประเภทการอบรม
1. เปิดหน้ารายการประวัติการอบรม
2. เลือกประเภท “ออนไลน์”
3. ตรวจสอบว่าทุกรายการเป็นประเภทออนไลน์
4. เปลี่ยนเป็น “ออฟไลน์”
5. ตรวจสอบว่าทุกรายการเป็นประเภทออฟไลน์
6. เลือก “ทุกประเภท”
7. ตรวจสอบว่าแสดงข้อมูลทุกประเภท
### Test Case 2: Filter สถานะ
1. เลือกสถานะ “รอตรวจสอบ”
2. ตรวจสอบว่าทุกรายการมีสถานะรอตรวจสอบ
3. เปลี่ยนเป็น “อนุมัติแล้ว”
4. ตรวจสอบว่าทุกรายการมีสถานะอนุมัติแล้ว
5. เลือก “ทุกสถานะ”
6. ตรวจสอบว่าแสดงข้อมูลทุกสถานะที่ผู้ใช้มีสิทธิ์เห็น
### Test Case 3: ใช้สอง Filter พร้อมกัน
1. เลือกประเภทออนไลน์
2. เลือกสถานะรอตรวจสอบ
3. ตรวจสอบว่าทุกรายการตรงทั้งสองเงื่อนไข
### Test Case 4: Filter ร่วมกับ Search
1. กรอกคำค้นหา
2. เลือกประเภทการอบรม
3. เลือกสถานะ
4. ตรวจสอบว่าข้อมูลตรงทุกเงื่อนไข
### Test Case 5: Filter ร่วมกับ Pagination
1. เลือก Filter ที่มีหลายหน้า
2. เปลี่ยนหน้า Pagination
3. ตรวจสอบว่า Filter ยังคงอยู่
4. เปลี่ยน Filter
5. ตรวจสอบว่าระบบกลับมาหน้า 1
### Test Case 6: Refresh หน้า
หากระบบใช้ URL Search Params:
1. เลือกประเภทและสถานะ
2. Refresh Browser
3. ตรวจสอบว่าค่า Filter ยังคงอยู่
4. ข้อมูลต้องยังตรงกับเงื่อนไขเดิม
### Test Case 7: Clear Filter
1. เลือกหลาย Filter
2. กดล้างตัวกรอง
3. ตรวจสอบว่าค่าทั้งหมดถูก Reset
4. ตารางกลับมาแสดงข้อมูลทั้งหมด
5. Pagination กลับมาหน้า 1
### Test Case 8: ไม่มีข้อมูลตรงกับ Filter
1. เลือกเงื่อนไขที่ไม่มีข้อมูล
2. ต้องแสดง Empty State ที่เหมาะสม
3. ปุ่มล้างตัวกรองต้องใช้งานได้
### Test Case 9: Permission
1. Login ด้วย Employee
2. ใช้ Filter ทุกประเภท
3. ตรวจสอบว่าไม่เห็นรายการของพนักงานคนอื่น
### Test Case 10: Count และ Pagination
1. เลือก Filter
2. ตรวจสอบจำนวนรายการทั้งหมด
3. ตรวจสอบจำนวนหน้า
4. จำนวนต้องสัมพันธ์กับข้อมูลหลังกรอง ไม่ใช่จำนวนทั้งหมดก่อนกรอง
---
## Acceptance Criteria
งานถือว่าเสร็จสมบูรณ์เมื่อ:
- Filter ประเภทการอบรมกรองข้อมูลได้จริง
- Filter สถานะกรองข้อมูลได้จริง
- Filter ทั้งสองใช้งานพร้อมกันได้
- ทำงานร่วมกับ Search ได้
- ทำงานร่วมกับ Sorting ได้
- ทำงานร่วมกับ Pagination ได้
- เปลี่ยน Filter แล้วข้อมูล Refresh หรือ Refetch อัตโนมัติ
- เปลี่ยน Filter แล้ว Pagination กลับหน้า 1
- เลือก “ทั้งหมด” แล้วล้างเงื่อนไขได้จริง
- ปุ่มล้างตัวกรองทำงานถูกต้อง
- จำนวนรายการและจำนวนหน้าหลังกรองถูกต้อง
- Frontend และ Backend ใช้ค่า Enum ตรงกัน
- ไม่มีการส่งค่า `"all"` ไปใช้ใน Database Query
- ผู้ใช้งานยังเห็นเฉพาะข้อมูลของตนเอง
- ไม่มี Regression ต่อ Filter หรือ Workflow อื่น
- TypeScript, Lint และ Build ผ่าน
- มีการเพิ่มหรือปรับปรุง Test ตามรูปแบบที่ Repository ใช้อยู่
---
## สิ่งที่ต้องส่งมอบ
หลังดำเนินการเสร็จ ให้สรุปผลดังนี้:
1. สาเหตุที่ทำให้ Filter ไม่ทำงาน
2. ไฟล์ที่แก้ไข
3. Filter ใช้ Field และ Value ใด
4. การเปลี่ยนแปลงฝั่ง Frontend
5. การเปลี่ยนแปลงฝั่ง API และ Backend
6. วิธี Reset Filter และ Pagination
7. Test Cases ที่ดำเนินการ
8. ผลการรัน Type Check, Lint, Test และ Build
9. ประเด็นที่ยังไม่ได้แก้หรือข้อจำกัด หากมี
ห้ามรายงานว่าแก้ไขสำเร็จโดยตรวจสอบเฉพาะ UI ต้องยืนยันจาก API Request และผลลัพธ์ข้อมูลจริงด้วย

View File

@@ -0,0 +1,67 @@
You are a Senior Frontend Engineer working on a Next.js 16 + React + TypeScript project.
Task:
Fix the Online Lesson Detail page where YouTube videos show a black screen inside the iframe.
Important:
Before editing code, inspect the existing implementation and follow project rules:
1. AGENTS.md
2. docs/AI_DEVELOPMENT_GUIDE.md
3. docs/PROJECT_ARCHITECTURE.md
Scope:
Only fix the YouTube embed issue.
Do not change unrelated UI, layout, API, React Query logic, or business logic.
Requirements:
1. Locate the OnlineLessonDetailPage component.
2. Review the existing getEmbeddableVideoUrl() function.
3. Improve the YouTube URL parser to support:
- https://www.youtube.com/watch?v=VIDEO_ID
- https://youtube.com/watch?v=VIDEO_ID
- https://m.youtube.com/watch?v=VIDEO_ID
- https://youtu.be/VIDEO_ID
- https://youtu.be/VIDEO_ID?si=xxxxx
- https://www.youtube.com/shorts/VIDEO_ID
- https://www.youtube.com/embed/VIDEO_ID
- URLs with timestamp parameters such as &t=30s
4. The parser must return:
https://www.youtube.com/embed/VIDEO_ID
5. If the URL is invalid or not supported, return null.
6. Remove the sandbox attribute from the YouTube iframe.
7. Update iframe attributes to:
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowFullScreen
referrerPolicy="strict-origin-when-cross-origin"
8. Keep uploaded video rendering unchanged.
9. Keep fallback Card behavior unchanged.
10. Do not use any.
11. Ensure TypeScript and ESLint pass.
After implementation:
Create /docs/ai/report.md with:
- Summary
- Files changed
- Root cause
- Changes made
- Testing checklist
- Risks
- Rollback plan
Testing checklist must include:
- youtube.com/watch URL
- youtu.be URL
- Shorts URL
- Embed URL
- Mobile YouTube URL
- URL with timestamp
- Invalid URL
- Local uploaded video
- Existing fallback button
- Responsive layout
Return a concise summary after completing the changes.

View File

@@ -0,0 +1,58 @@
## Import Training Records
ในเมนู **ประวัติการอบรม** ฝั่ง Admin / Staff HRD / HRD ให้เพิ่มปุ่ม:
- ดาวน์โหลด Template Excel
- นำเข้าประวัติการอบรม
## Workflow
1. HRD กดดาวน์โหลด Template Excel
2. HRD กรอกข้อมูลประวัติการอบรมของพนักงานหลายคน
3. HRD กดนำเข้าประวัติการอบรม
4. ระบบตรวจสอบข้อมูลในไฟล์
5. หาก Import สำเร็จ ให้สร้าง Training Record ให้พนักงานโดยตรงเป็นสถานะ `Approved`
## Permission
ผู้ที่สามารถ Import ได้:
- Admin
- Staff HRD
- HRD
- HRD Manager
- IT Admin
- Super Admin
Employee ไม่สามารถ Import ได้
## Template Excel ควรมี Field
- employee_code
- course_name
- training_date
- training_type
- location_type
- hours
- category
- provider
- note
## Validation
- employee_code ต้องมีอยู่ในระบบ
- course_name ต้องไม่ว่าง
- training_date ต้องเป็นวันที่ถูกต้อง
- hours ต้องมากกว่า 0
- category ต้องเป็น K, S หรือ A
- หากมี Error ให้แสดงรายการแถวที่ผิดพลาด
- Import สำเร็จเฉพาะแถวที่ผ่าน หรือใช้แนวทางทั้งไฟล์ต้องผ่านทั้งหมดก่อน Import ตามที่ระบบปัจจุบันรองรับ
## Result
หลัง Import สำเร็จ:
- สร้าง Training Record ให้พนักงาน
- Status = `Approved`
- บันทึก Audit Log
- แสดงจำนวนรายการที่สำเร็จ/ผิดพลาด

View File

@@ -0,0 +1,24 @@
Implement Sprint 6.11: Identity & Employee Architecture Cleanup.
Goal:
Finalize separation between login users and employee master data.
Tasks:
1. Create user_employee_map table.
2. Remove dependency on users.employeeId as primary mapping.
3. Make employee import write only to employees and employee_training_targets.
4. Stop auto-creating users during employee import.
5. Update training_records to use employeeId as owner.
6. Keep submittedByUserId / reviewedByUserId for action tracking.
7. Update dashboard, reports, and training matrix to aggregate by employeeId.
8. Keep existing login working.
9. Prepare future Keycloak mapping by empcode.
10. Create docs/sprint-6-11-identity-employee-cleanup-review.md.
Return:
- Migration changes
- Code changes
- Regression checklist
- Review document

View File

@@ -0,0 +1,169 @@
You are a Senior Full Stack Engineer and Solution Architect.
Project:
Training Management System (TMS)
Current task:
Refactor Identity/User and Employee Master architecture.
Business decision:
Separate user login accounts from employee master data.
Concept:
1. "พนักงาน" menu:
- Manage user login accounts
- Role
- Provider
- Keycloak mapping
- User access
2. "รายชื่อพนักงานทั้งหมด" menu:
- View employee master data
- Training hours
- K/S/A targets
- Training history
Important constraints:
- Do NOT break existing login.
- Do NOT remove existing users table.
- Do NOT remove existing training records.
- Use migration safely.
- Use Drizzle ORM.
- Keep Thai UI.
- Keep responsive/mobile behavior.
- Implement in small safe steps.
Architecture requirement:
1. Users table should represent login identity only.
Users should store:
- id
- organizationId
- email
- username
- employeeCode
- employeeId nullable
- provider
- providerUserId
- role
- status
- lastLoginAt
- createdAt
- updatedAt
2. Employees table should represent HR employee master.
Employees should store:
- id
- organizationId
- employeeCode
- prefix
- firstNameTh
- lastNameTh
- firstNameEn
- lastNameEn
- displayName
- email
- phone
- companyName or companyId
- departmentId
- positionId
- status
- hiredAt
- createdAt
- updatedAt
3. Auto map user with employee.
Mapping logic:
- Keycloak sends attribute:
empcode
- System maps:
empcode -> employees.employeeCode
- If found:
users.employeeId = employees.id
users.employeeCode = employees.employeeCode
- If not found:
login can be blocked or user can be created without employee link based on config.
For MVP, create user but mark employeeId = null and show "ยังไม่เชื่อมโยงข้อมูลพนักงาน".
4. Employee Import:
- Import employees into employees table.
- Do not create user login account automatically unless explicitly configured.
- If imported employeeCode matches existing users.employeeCode:
auto-link users.employeeId.
5. Training Records:
- Prefer employeeId as owner of training record.
- Keep userId only as submittedBy if existing.
- New records should save:
employeeId
submittedByUserId
6. Employee-specific targets:
- Link to employeeId.
7. Reports and Dashboard:
- Use employees as master source.
- Use training_records.employeeId for aggregation.
- Use user only for authentication/session.
8. Sidebar:
Under "ข้อมูลหลัก":
- พนักงาน
Purpose: User Login Management
- รายชื่อพนักงานทั้งหมด
Purpose: Employee Directory + Training Summary
- หลักสูตร
- นโยบาย
- ประกาศ
9. Permissions:
HRD/Admin:
- can view employee directory
- can manage user accounts if allowed
Employee:
- cannot view employee directory
- can view own dashboard/training history
10. Output Review File:
Create:
docs/identity-employee-separation-review.md
Include:
1. Summary
2. Architecture Changes
3. Database Changes
4. Migration Strategy
5. User Login Behavior
6. Keycloak Mapping Behavior
7. Employee Import Behavior
8. Training Record Impact
9. Dashboard Impact
10. Reports Impact
11. Permission Rules
12. Manual Test Checklist
13. Rollback Plan
14. Known Limitations
Return:
- Complete code changes with file paths
- Migration commands
- Review file
- Remaining risks

View File

@@ -0,0 +1,455 @@
# Training System Implementation Plan
เอกสารนี้สรุป implementation plan แบบ phase-by-phase สำหรับพัฒนาระบบ Training System บน stack ของโปรเจ็กต์นี้
- Next.js 16 App Router
- React 19
- TypeScript
- Auth.js
- PostgreSQL + Drizzle ORM
- TanStack React Query
- nuqs
- TanStack Form + Zod
- shadcn/ui + Tailwind CSS
เอกสารนี้อ้างอิงจาก [req.md](./req.md) และออกแบบให้สอดคล้องกับ feature-based architecture ของรีโปนี้
## Phase 0: Foundation Alignment
เป้าหมาย:
- ทำให้ requirement, domain language, และโครงสร้างข้อมูลสอดคล้องกับ stack และ architecture ของโปรเจ็กต์
งานหลัก:
- ยืนยันคำศัพท์โดเมนหลัก:
- `organization`
- `membership`
- `user`
- `employee`
- `course`
- `training_record`
- `certificate`
- `training_matrix`
- แยกความหมายของ `user` กับ `employee` ให้ชัด
- ยืนยัน status values กลางของระบบ เช่น:
- `pending`
- `approved`
- `rejected`
- `needs_revision`
- ยืนยัน training types:
- `online`
- `onsite`
- `internal`
- `external`
- กำหนด naming convention สำหรับ:
- database tables
- route handlers
- query keys
- feature folders
ผลลัพธ์:
- domain language ชัดเจน
- requirement พร้อมสำหรับลงมือทำ
## Phase 1: Auth, Organization, and RBAC Core
เป้าหมาย:
- วาง auth และ multi-tenant foundation ให้ทุกฟีเจอร์ใหม่ใช้งานร่วมกันได้
งานหลัก:
- ใช้ `Auth.js` เป็น auth boundary หลัก
- ใช้ตาราง:
- `users`
- `organizations`
- `memberships`
- ทำ server-side helpers:
- `requireSession()`
- `requireOrganizationAccess()`
- `requireRole()` เมื่อจำเป็น
- ปรับ route protection สำหรับ dashboard และ protected API
- ทำ session shape ให้ client ใช้:
- `activeOrganizationId`
- `activeOrganizationName`
- `role`
- `permissions`
- ปรับ navigation filtering ให้ดึงจาก app-owned session
ผลลัพธ์:
- ระบบ login/logout ใช้งานได้
- organization switching ใช้งานได้
- role-based access เริ่มทำงานได้
Acceptance Criteria:
- ผู้ใช้ที่ไม่ login เข้า dashboard ไม่ได้
- ผู้ใช้ที่ไม่มี active organization เข้า org-scoped page ไม่ได้
- visibility ของ nav เปลี่ยนตาม session และ role
## Phase 2: Shared Domain Schema
เป้าหมาย:
- วาง schema กลางของระบบ Training System ใน PostgreSQL ด้วย Drizzle
งานหลัก:
- เพิ่ม schema สำหรับ:
- `departments`
- `positions`
- `employees`
- `courses`
- `training_records`
- `certificates`
- `training_matrices`
- ทุก business table ต้องมี `organizationId`
- กำหนด foreign keys ให้ครบ
- เพิ่ม timestamps และ audit-friendly fields ตามความเหมาะสม
- สร้างและ apply migration
ผลลัพธ์:
- database model ครบพอสำหรับสร้างฟีเจอร์หลัก
Acceptance Criteria:
- schema build ผ่าน
- migration ใช้งานได้
- relation หลัก query ได้จริง
## Phase 3: Employee Management
เป้าหมาย:
- มี master data พนักงานที่ใช้เป็นฐานของการบันทึกอบรม
งานหลัก:
- สร้าง feature `employees`
- เพิ่มไฟล์:
- `src/features/employees/api/types.ts`
- `src/features/employees/api/service.ts`
- `src/features/employees/api/queries.ts`
- `src/features/employees/api/mutations.ts`
- `src/features/employees/components/*`
- `src/features/employees/schemas/*`
- เพิ่ม route handlers:
- `GET /api/employees`
- `POST /api/employees`
- `GET /api/employees/:id`
- `PATCH /api/employees/:id`
- สร้าง dashboard page สำหรับ list และ create/edit
- ใช้ React Query + nuqs table pattern
ข้อมูลหลัก:
- employee code
- full name
- department
- position
- company
- active status
ผลลัพธ์:
- admin จัดการข้อมูล employee ได้
Acceptance Criteria:
- list/filter/search/pagination ทำงาน
- create/update/disable employee ทำงาน
- จำกัดข้อมูลตาม organization
## Phase 4: Course Management
เป้าหมาย:
- มี course catalog กลางของ organization
งานหลัก:
- สร้าง feature `courses`
- เพิ่ม CRUD route handlers และ Drizzle queries
- สร้าง list page และ create/edit form
- ใช้ table pattern เดียวกับ `products` และ `users`
ข้อมูลหลัก:
- course name
- category
- organizer
- standard hours
- certificate validity
- required flag
ผลลัพธ์:
- admin จัดการหลักสูตรได้
Acceptance Criteria:
- create/update/delete course ทำงาน
- list/filter/search/sort ทำงาน
- course ถูกจำกัดตาม organization
## Phase 5: Training Record CRUD
เป้าหมาย:
- ทำ flow หลักของระบบให้ผู้ใช้บันทึกประวัติการอบรมได้จริง
งานหลัก:
- สร้าง feature `training-records`
- เพิ่ม route handlers:
- `GET /api/training-records`
- `POST /api/training-records`
- `GET /api/training-records/:id`
- `PATCH /api/training-records/:id`
- `DELETE /api/training-records/:id`
- สร้างหน้า:
- list page
- detail page
- create/edit form
- ใช้ TanStack Form + Zod
- ใช้ React Query mutations + invalidation
ข้อมูลหลัก:
- employee
- course
- training date
- training type
- hours
- organizer
- note
- approval status
ผลลัพธ์:
- ผู้ใช้เพิ่มและจัดการประวัติการอบรมได้
Acceptance Criteria:
- user เพิ่ม record ได้
- user เห็นเฉพาะ record ที่เกี่ยวข้องตาม policy
- admin เห็น records ภายใน organization
## Phase 6: Certificate Upload and Metadata
เป้าหมาย:
- รองรับไฟล์ใบรับรองและ metadata อย่างเป็นระบบ
งานหลัก:
- เพิ่ม certificate model และ route handlers ที่เกี่ยวข้อง
- เก็บ metadata ใน PostgreSQL:
- `fileName`
- `fileType`
- `fileSize`
- `storageKey`
- `uploadedAt`
- ผูก `certificate` กับ `training_record`
- เพิ่ม upload flow และ preview/open flow
- กำหนดข้อจำกัดไฟล์:
- `pdf`
- `jpg`
- `jpeg`
- `png`
ผลลัพธ์:
- training record มีหลักฐานแนบได้จริง
Acceptance Criteria:
- upload สำเร็จ
- metadata ถูกบันทึก
- เปิดดูย้อนหลังได้
- validation ประเภทและขนาดไฟล์ทำงาน
## Phase 7: Approval Workflow
เป้าหมาย:
- ให้ admin ตรวจสอบและอนุมัติรายการอบรมได้
งานหลัก:
- เพิ่ม admin queue สำหรับรายการ `pending`
- เพิ่ม actions:
- approve
- reject
- request changes
- เก็บ reviewer note
- กำหนด policy การแก้ไข record หลัง approve
- เพิ่ม filtering ตาม status
ผลลัพธ์:
- ระบบมี workflow ตรวจสอบจริง
Acceptance Criteria:
- admin เปลี่ยนสถานะได้
- user เห็นสถานะล่าสุดได้
- unauthorized user เปลี่ยนสถานะไม่ได้
## Phase 8: Training Matrix
เป้าหมาย:
- ทำ logic ความครบถ้วนตาม requirement ของแต่ละตำแหน่งหรือแผนก
งานหลัก:
- สร้าง feature `training-matrix`
- รองรับ mapping:
- department -> required courses
- position -> required courses
- เตรียมรองรับ employee-specific overrides ในอนาคต
- เพิ่มหน้า admin สำหรับจัดการ matrix
- เพิ่ม query/helper สำหรับคำนวณ compliance
คำตัดสินเชิงกติกาที่ต้อง implement:
- ใช้เฉพาะ approved training records
- course ที่หมดอายุสามารถถือว่าไม่ครบได้ ถ้าระบบกำหนด validity
- matrix ต้องคำนวณในระดับ organization เสมอ
ผลลัพธ์:
- ระบบสามารถตอบได้ว่าใครครบหรือยังไม่ครบ
Acceptance Criteria:
- admin กำหนด matrix ได้
- employee compliance คำนวณได้
- dashboard/report เรียกใช้ข้อมูลนี้ได้
## Phase 9: Dashboards and Analytics
เป้าหมาย:
- ทำ dashboard ให้สะท้อนข้อมูลธุรกิจจริง
งานหลัก:
- User dashboard:
- total courses
- total training hours
- total certificates
- missing required courses
- training chart by month/year
- Admin dashboard:
- employee count
- total hours
- pending approvals
- compliance percentage
- charts by department/category/time
- ใช้ Recharts
- ใช้ server prefetch + `HydrationBoundary` + `useSuspenseQuery`
ผลลัพธ์:
- dashboard ใช้ข้อมูลจาก DB จริง
Acceptance Criteria:
- metrics ถูกต้อง
- charts render ได้
- organization scoping ถูกต้อง
## Phase 10: Reports and Export
เป้าหมาย:
- เพิ่ม reporting สำหรับใช้งานจริงของ admin
งานหลัก:
- สร้าง feature `reports`
- ทำรายงาน:
- individual training history
- department training summary
- accumulated hours
- missing required courses
- expiring certificates
- organization training matrix summary
- เริ่มจาก on-screen report pages
- เพิ่ม export ใน phase ย่อยถัดไป เช่น CSV หรือ PDF
ผลลัพธ์:
- admin ตรวจสอบข้อมูลย้อนหลังและสรุปผลได้
Acceptance Criteria:
- รายงานโหลดได้
- filter/report criteria ใช้งานได้
- export อย่างน้อย 1 รูปแบบเมื่อรวมใน scope
## Phase 11: UX, Theme, and Hardening
เป้าหมาย:
- polish ระบบให้พร้อมใช้งานและขยายต่อ
งานหลัก:
- ปรับ visual theme ตาม requirement ผ่าน theme system ของโปรเจ็กต์
- ใช้สีหลัก:
- `#336b4a`
- `#808285`
- `#e26631`
- `#413b60`
- จัด empty/loading/error/access states ให้ครบ
- ปรับ mobile behavior ของ table และ form
- เพิ่ม validation messages ให้สม่ำเสมอ
- เก็บ lint/type/build issues ให้สะอาด
- เพิ่ม test coverage ใน critical flows
ผลลัพธ์:
- ระบบพร้อม demo และพร้อมพัฒนาต่อ
Acceptance Criteria:
- `build` ผ่าน
- ไม่มี lint issue ใหม่จากส่วนที่เพิ่ม
- flow หลักใช้งานได้ทั้ง desktop และ mobile
## Milestones ที่แนะนำ
### Milestone A
- Phase 1
- Phase 2
- Phase 3
- Phase 4
ผลลัพธ์:
- organization foundation พร้อม
- employee และ course CRUD พร้อม
### Milestone B
- Phase 5
- Phase 6
ผลลัพธ์:
- training records และ certificate flow ใช้งานได้
### Milestone C
- Phase 7
- Phase 8
ผลลัพธ์:
- approval workflow และ training matrix ใช้งานได้
### Milestone D
- Phase 9
- Phase 10
- Phase 11
ผลลัพธ์:
- dashboard, reports, และ UX polish พร้อมใช้งาน
## ลำดับลงมือที่แนะนำ
1. ทำ shared schema และ domain foundation ให้ครบก่อน
2. ทำ master data คือ `employees` และ `courses`
3. ทำ `training-records` และ `certificates`
4. ทำ approval workflow
5. ทำ training matrix
6. ทำ dashboard และ reports
7. ทำ polish และ hardening
## Mapping กับโครงสร้างรีโป
feature ที่ควรมีใน `src/features/`:
- `employees`
- `courses`
- `training-records`
- `certificates`
- `training-matrix`
- `reports`
page routes ที่ควรมีใน `src/app/dashboard/`:
- `employees`
- `courses`
- `training-records`
- `training-matrix`
- `reports`
API routes ที่ควรมีใน `src/app/api/`:
- `employees`
- `courses`
- `training-records`
- `certificates`
- `training-matrix`
- `reports` เมื่อจำเป็น
## หมายเหตุสำหรับการ implement
- ใช้ `PageContainer` สำหรับ page header ทุกหน้า
- ใช้ `apiClient` สำหรับเรียก local route handlers จาก `service.ts`
- ใช้ `queryOptions` และ `mutationOptions` ตาม pattern เดิม
- ใช้ `Icons` จาก `@/components/icons`
- อย่าใช้ mock data สำหรับฟีเจอร์ใหม่
- อย่าใช้ vendor UI ภายนอกแทน component patterns ของโปรเจ็กต์

View File

@@ -0,0 +1,85 @@
ช่วยแก้ไขฟีเจอร์ Import รายชื่อพนักงานของระบบ Training System
## เป้าหมาย
ปรับการนำเข้าพนักงานให้รองรับกรณีที่พนักงาน 1 คน มีข้อมูลประวัติการอบรมหรือหลักสูตรหลายรายการในไฟล์ Import โดยระบบต้องนับรหัสพนักงานเป็นพนักงานเพียง 1 คน แต่ต้องบันทึกประวัติการอบรมทั้งหมด และสรุปจำนวนชั่วโมงอบรมตามประเภทหลักสูตรให้ถูกต้อง
## เงื่อนไขหลัก
1. ใช้ `employeeCode` หรือรหัสพนักงานเป็นตัวระบุพนักงานหลัก
2. หากพบรหัสพนักงานซ้ำในไฟล์ Import เดียวกัน ให้ถือว่าเป็นพนักงานคนเดียวกัน
3. ห้ามสร้างข้อมูลพนักงานซ้ำตามจำนวนแถวในไฟล์ Import
4. พนักงาน 1 คน สามารถมีประวัติการอบรมได้หลายรายการ
5. ทุกแถวของไฟล์ Import ที่มีข้อมูลหลักสูตร ต้องถูกบันทึกเป็น Training History / Training Record
6. หลังนำเข้า ต้องคำนวณและสรุปชั่วโมงอบรมของพนักงานคนนั้นใหม่
7. การสรุปชั่วโมงต้องแยกตามประเภทหลักสูตร เช่น K, S, A และรวม Total
8. หาก Import เพิ่มในภายหลัง และพบรหัสพนักงานเดิมในระบบ
- ไม่ต้องสร้าง Employee ใหม่
- ให้เพิ่มเฉพาะประวัติการอบรมใหม่
- อัปเดตยอดรวมชั่วโมงของพนักงานใหม่
## พฤติกรรมที่ต้องการ
ตัวอย่างไฟล์ Import:
| employeeCode | employeeName | courseName | category | hours |
| ------------ | ------------ | -------------- | -------- | ----- |
| 66001 | นาย A | React Basic | K | 6 |
| 66001 | นาย A | Next.js | S | 8 |
| 66001 | นาย A | Cyber Security | A | 3 |
หลัง Import ต้องได้ผลลัพธ์เป็น:
Employee:
- 66001 นาย A จำนวน 1 รายการเท่านั้น
Training History:
- React Basic 6 ชั่วโมง ประเภท K
- Next.js 8 ชั่วโมง ประเภท S
- Cyber Security 3 ชั่วโมง ประเภท A
Training Summary:
- K = 6 ชั่วโมง
- S = 8 ชั่วโมง
- A = 3 ชั่วโมง
- Total = 17 ชั่วโมง
## แนวทางการแก้ไข
1. ตรวจสอบโค้ด Import เดิมก่อนแก้ไข
2. ตรวจสอบ schema/model ที่เกี่ยวข้อง เช่น Employee, TrainingRecord, TrainingHistory, TrainingSummary
3. แก้ logic การ import ให้ group ข้อมูลตาม `employeeCode`
4. ใช้ `upsert` หรือ find existing employee ก่อนสร้าง Employee
5. เพิ่ม Training Record ทุกแถวที่เป็นหลักสูตรของพนักงาน
6. ป้องกันการสร้าง Employee ซ้ำทั้งในไฟล์เดียวกันและในฐานข้อมูลเดิม
7. หลังเพิ่ม Training Record ให้คำนวณชั่วโมงรวมใหม่จากข้อมูล Training Record จริง
8. อัปเดต summary ชั่วโมงของพนักงานตาม category K/S/A/Total
9. ตรวจสอบ transaction เพื่อให้ข้อมูล Employee, Training Record และ Summary ถูกบันทึกครบหรือ rollback เมื่อเกิด error
10. เพิ่ม validation สำหรับข้อมูลสำคัญ เช่น employeeCode, courseName, category, hours
11. เพิ่มรายงานผลหลัง Import เช่น จำนวนพนักงานใหม่, จำนวนพนักงานเดิมที่อัปเดต, จำนวนประวัติอบรมที่เพิ่ม, จำนวนแถวที่ error
## Acceptance Criteria
- Import ไฟล์ที่มีรหัสพนักงานซ้ำหลายแถวแล้วระบบสร้าง Employee เพียง 1 คน
- Training Record ถูกสร้างครบทุกหลักสูตร
- พนักงานเดิมในระบบไม่ถูกสร้างซ้ำ
- Summary ชั่วโมง K/S/A/Total ถูกต้อง
- Import ซ้ำหรือ Import เพิ่มภายหลังต้องไม่ทำให้ Employee ซ้ำ
- มี error message ที่เข้าใจง่ายสำหรับแถวที่ข้อมูลไม่ครบ
- โค้ดต้องสอดคล้องกับโครงสร้างเดิมของโปรเจกต์
- ห้ามสร้าง service/component/schema ใหม่โดยไม่ตรวจสอบของเดิมก่อน
- หลังแก้ไขเสร็จ ให้สร้างรายงานสรุปไฟล์ที่แก้ไข จุดที่แก้ และวิธีทดสอบ
## ขอให้ทำงานตามลำดับนี้
1. อ่านโครงสร้าง Import เดิม
2. ระบุไฟล์ที่เกี่ยวข้อง
3. วางแผนการแก้ไขก่อนลงมือ
4. แก้ไข logic การ Import
5. เพิ่ม/แก้ validation ที่จำเป็น
6. ทดสอบด้วยกรณีรหัสพนักงานซ้ำหลายแถว
7. ทดสอบกรณีพนักงานเดิมในระบบ
8. สรุปผลการแก้ไขเป็นรายงานหลังทำเสร็จ

View File

@@ -0,0 +1,63 @@
You are a Senior Frontend QA Engineer.
Project:
Training Management System (TMS)
Current status:
Responsive Audit has been completed.
Current task:
Perform a final Mobile and Tablet UX Review before Sprint 6.
Requirements:
Review all TMS pages and components at:
- 360px
- 390px
- 412px
- 768px
- 1024px
- 1440px
Focus on:
1. Horizontal overflow
2. Button clipping
3. Table clipping
4. Dialog clipping
5. Long Thai text wrapping
6. Sidebar behavior
7. Drawer behavior
8. Search input usability
9. Filter usability
10. Form usability
11. Touch target size
12. Scroll behavior
Verify:
- No unusable controls
- No hidden action buttons
- No inaccessible form fields
- No unreadable Thai labels
Create:
docs/pre-sprint-6-mobile-ux-review.md
Include:
1. Summary
2. Screens Reviewed
3. Issues Found
4. Issues Fixed
5. Remaining Risks
6. Go-Live Mobile Readiness Score
7. Recommendation
Return:
- Code changes
- Review file
- Mobile readiness score

View File

@@ -0,0 +1,77 @@
ช่วยแก้ไข Layout หน้า `รายชื่อพนักงานทั้งหมด` ให้ตารางแสดงผลเหมือนกับหน้า `ประวัติการอบรม`
ปัญหาปัจจุบัน:
- ตารางของหน้ารายชื่อพนักงานล้นออกด้านขวา
- Header และ Column ของตารางดูกว้างเกิน container
- ต้องการให้ตารางอยู่ใน Card เหมือนหน้าประวัติการอบรม
- ให้ Scroll เฉพาะภายในตาราง ไม่ให้ดัน Layout ทั้งหน้า
สิ่งที่ต้องการให้แก้:
1. ครอบตารางด้วย container ที่มี `overflow-hidden`
2. เพิ่ม wrapper สำหรับตารางด้วย `overflow-x-auto`
3. ใช้ `Table` แบบ `w-full table-fixed`
4. กำหนดความกว้างของแต่ละคอลัมน์ให้เหมาะสม
5. ใช้ `truncate` กับข้อความยาว เช่น ชื่อพนักงาน ฝ่าย และตำแหน่ง
6. จัด Header กลุ่ม `ชั่วโมงการอบรม (ชม.)` ให้ไม่ทำให้ตารางล้น
7. ให้ดีไซน์ สี เส้นขอบ ระยะห่าง และความสูงของแถว ใกล้เคียงกับหน้า `ประวัติการอบรม`
8. ปุ่ม Search, Filter, View และ Pagination ไม่ต้องเปลี่ยน Logic เดิม
9. ห้ามแก้ Business Logic, API, Query หรือข้อมูลที่ดึงมา
10. แก้เฉพาะ Layout / CSS / className / Table structure เท่านั้น
โครงสร้างที่ต้องการโดยประมาณ:
```tsx
<Card className="overflow-hidden">
<CardContent className="p-0">
<div className="overflow-x-auto">
<Table className="w-full table-fixed">
<TableHeader>...</TableHeader>
<TableBody>...</TableBody>
</Table>
</div>
</CardContent>
</Card>
```
ตัวอย่างแนวทาง Column Width:
```tsx
<TableHead className="w-[120px]"></TableHead>
<TableHead className="w-[220px]"></TableHead>
<TableHead className="w-[160px]"></TableHead>
<TableHead className="w-[160px]"></TableHead>
<TableHead className="w-[100px] text-center"></TableHead>
<TableHead className="w-[100px] text-center"></TableHead>
<TableHead className="w-[100px] text-center"></TableHead>
<TableHead className="w-[100px] text-center"></TableHead>
```
ตัวอย่างการจัด Header กลุ่ม:
```tsx
<TableRow>
<TableHead colSpan={4}></TableHead>
<TableHead colSpan={4} className="text-center border-l">
(.)
</TableHead>
</TableRow>
```
ตัวอย่างการป้องกันข้อความยาวดันตาราง:
```tsx
<TableCell className="truncate">
<div className="truncate">{employee.name}</div>
</TableCell>
```
ผลลัพธ์ที่ต้องการ:
- ตารางไม่ล้นหน้าจอ
- Layout เหมือนหน้า `ประวัติการอบรม`
- Table อยู่ใน Card สวยงาม
- มี horizontal scroll เฉพาะเมื่อจำเป็น
- Responsive มากขึ้น
- Header และ Body align ตรงกัน

View File

@@ -0,0 +1,882 @@
# Prompt: Redesign Online Lesson Create Workflow (Draft & Submit for Review)
## Objective
ปรับปรุงหน้า **Create Online Lesson**
```
/dashboard/online-lessons/manage/new
```
โดยเปลี่ยนจากการให้ผู้ใช้เลือก **สถานะ (Status)** ผ่าน Dropdown
เป็นการใช้ **Action Button** เพื่อกำหนด Workflow แทน
พร้อมปรับทั้ง Frontend, Backend, Validation, Permission และ Workflow ให้รองรับ Approval Process ของระบบ
---
# Background
ระบบกำลังเปลี่ยนจากการให้ผู้ใช้เลือก Status เอง
เช่น
```
Draft
Pending Review
Published
```
ซึ่งไม่เหมาะสม
เป็น
Workflow Based
โดยผู้ใช้จะไม่สามารถเลือก Status เองได้
แต่ Status จะถูกกำหนดจาก Action ที่ผู้ใช้เลือกแทน
---
# Business Requirement
Staff
สามารถ
- บันทึกฉบับร่าง
- ส่งตรวจสอบ
Manager
สามารถ
- ตรวจสอบ
- อนุมัติ
IT Admin
สามารถ
- ตรวจสอบ
- อนุมัติ
- เผยแพร่
Super Admin
สามารถทำได้ทั้งหมด
---
# IMPORTANT
ก่อนแก้ไข
AI ต้องตรวจสอบ Existing Architecture ก่อน
ต้อง Audit
- Online Lesson Form
- Validation
- Submit Handler
- API
- Status Enum
- Status Constant
- Workflow
- Permission
- Notification
- Audit
ห้ามเดา
ห้าม Hardcode
ห้ามสร้าง Pattern ใหม่ หากระบบมี Pattern เดิมอยู่แล้ว
ต้อง Reuse
- Shared Form
- Shared Button
- Shared Mutation
- Shared Status
- Shared Permission
- Shared Dialog
- Shared Toast
- Shared Validation
---
# Phase 0 — Architecture Audit
ตรวจสอบ
## Frontend
- Create Page
- Edit Page
- Form Component
- Status Select
- Submit Function
- Button Component
---
## Backend
ตรวจสอบ
- API
- Route Handler
- Server Action
- Validation
- Service
- Repository
---
## Database
ตรวจสอบ
Status Field
เช่น
```
status
workflowStatus
lessonStatus
```
และ Enum
ที่ระบบใช้อยู่จริง
---
## Permission
ตรวจสอบ
Permission First
หรือ
Compatibility Mode
ห้ามใช้
```
businessRole
isHRD()
```
หากระบบมี Permission แล้ว
---
# Phase 1 — Remove Status Field
ลบ
```
สถานะ *
```
ออกจาก
Online Lesson Create Form
ผู้ใช้
ห้าม
เลือก Status เอง
---
ตรวจสอบ
- Form
- Schema
- Validation
- Default Value
- Payload
ให้สอดคล้องกันทั้งหมด
---
# Phase 2 — Redesign Action Buttons
เปลี่ยน Footer Action
จาก
```
Cancel
Create
```
เป็น
```
ยกเลิก
บันทึกฉบับร่าง
ส่งตรวจสอบ
```
---
Layout
```
---------------------------------------------------
Cancel
Save Draft
Submit For Review
```
Primary Button
คือ
```
ส่งตรวจสอบ
```
Secondary Button
คือ
```
บันทึกฉบับร่าง
```
---
# Phase 3 — Draft Action
เมื่อกด
```
บันทึกฉบับร่าง
```
ระบบต้อง
Save
พร้อม Status
```
DRAFT
```
หรือ
Status เดิมของระบบ
ห้าม Hardcode
---
Draft
สามารถ
Edit
Delete
ได้
เฉพาะ
Owner
ตาม Permission เดิม
---
# Phase 4 — Submit For Review
เมื่อกด
```
ส่งตรวจสอบ
```
ระบบต้อง
Save
พร้อม Status
```
PENDING_REVIEW
```
หรือ
Status เดิมของระบบ
ห้าม Hardcode
---
Validation
ต้องใช้
Validation
สำหรับ
Ready To Review
ไม่ใช่ Validation ของ Draft
---
เมื่อ Submit สำเร็จ
แสดง Toast
เช่น
```
ส่งบทเรียนเพื่อตรวจสอบเรียบร้อยแล้ว
```
---
# Phase 5 — Validation
ตรวจสอบ
Validation
แยกตาม Action
---
## Save Draft
Validation
สามารถผ่อนปรนได้
หากระบบรองรับ Draft Validation
เช่น
Title
อาจยังไม่ครบ
แต่สามารถ Save ได้
---
## Submit
Validation
ต้องครบทุก Field
เช่น
- Title
- Description
- Category
- Video
- Cover
- Duration
หรือ Field ที่ระบบกำหนด
ต้องผ่านทั้งหมด
---
# Phase 6 — Backend
ตรวจสอบ
API
ห้ามรับ
Status
จาก User
แบบอิสระ
เช่น
```
Published
Approved
Rejected
```
ผ่าน Create API
---
API
ต้องรองรับ
Action
เช่น
```
draft
submit
```
หรือ
Status
ที่ถูกตรวจสอบแล้ว
ตาม Pattern ของระบบ
---
ต้อง Validate
Transition
เช่น
Draft
Pending Review
ถูกต้อง
แต่
Draft
Published
ต้องห้าม
---
# Phase 7 — Permission
## Staff
เห็น
```
Save Draft
Submit
```
ไม่เห็น
Approve
Publish
Reject
---
## Manager
สามารถ
Approve
Return
Reject
จากหน้า Review
ไม่ใช่จากหน้า Create
---
## IT Admin
สามารถ
Approve
Publish
Return
Reject
ตาม Workflow
---
## Super Admin
สามารถ
ทำได้ทั้งหมด
---
# Phase 8 — Notification
เมื่อ
Submit
แจ้ง
Manager
IT
---
เมื่อ
Return
แจ้ง
Author
---
เมื่อ
Approve
แจ้ง
Author
---
เมื่อ
Publish
แจ้ง
Author
---
ใช้
Notification Pattern
เดิมของระบบ
---
# Phase 9 — Audit
สร้าง Audit
เช่น
```
ONLINE_LESSON_DRAFT_SAVED
ONLINE_LESSON_SUBMITTED
```
ข้อมูล
- User
- Action
- Previous Status
- New Status
- Timestamp
---
# Phase 10 — UI
Status
ไม่ต้องแสดง
ใน Form
แต่
List
และ
Detail
ยังต้องแสดง
Badge
ตามเดิม
เช่น
```
Draft
Pending Review
Approved
Published
```
---
# Phase 11 — Regression Testing
ตรวจสอบ
## UI
- ไม่มี Status Dropdown
- มี Save Draft
- มี Submit
---
## Draft
- Save สำเร็จ
- Status ถูกต้อง
- Edit ได้
- Delete ได้
---
## Submit
- Validation ครบ
- Status Pending Review
- Toast ถูกต้อง
---
## Permission
Staff
ไม่สามารถ
Publish
Approve
Reject
---
Manager
Approve
ได้
---
IT
Publish
ได้
---
## Database
Status
ถูกต้อง
---
## API
ไม่สามารถส่ง
Published
ตรงจาก Create
---
## Notification
ส่งครบ
---
## Audit
บันทึกครบ
---
# Code Quality
ตรวจสอบ
- ไม่มี Duplicate Logic
- ไม่มี Hardcode Status
- ไม่มี Hardcode Role
- ไม่มี any ใหม่
- ไม่มี console.log
- ไม่มี Dead Code
- Reuse Existing Components
- Reuse Existing Workflow
---
# Documentation
สร้างรายงาน
```
docs/online-lesson-create-workflow-redesign-report.md
```
---
รายงานต้องมี
```md
# Online Lesson Create Workflow Redesign Report
## Executive Summary
## Current Architecture
## Current Limitation
## Workflow Design
## Status Mapping
## Action Mapping
## Permission Matrix
## Validation Changes
## Backend Changes
## UI Changes
## Notification
## Audit Log
## Files Modified
## Testing Result
## Regression Result
## Risks
## Recommendations
```
---
# Future Improvements
เสนอแนวทาง
เช่น
- Approval Timeline
- Review Comment
- Multiple Reviewer
- Scheduled Publish
- Workflow Configuration
- Content Versioning
---
# Constraints
ห้าม
- ให้ User เลือก Status เอง
- Hardcode Status
- Hardcode Permission
- Duplicate Workflow
- เพิ่ม Library ใหม่
- ใช้ any
- เปลี่ยน Business Logic อื่น
ต้อง
- ใช้ Shared Workflow
- ใช้ Shared Permission
- ใช้ Shared Validation
- ใช้ Shared Status
- ใช้ Shared Notification
- รักษา Type Safety
- รักษา Coding Standard
---
# Final Response
เมื่อดำเนินการเสร็จ
ให้สรุปเป็นภาษาไทย
1. Architecture ที่ตรวจพบ
2. Workflow ใหม่
3. การ Mapping ระหว่าง Action กับ Status
4. Permission Matrix
5. Validation ที่เปลี่ยน
6. Backend ที่แก้ไข
7. Notification
8. Audit Log
9. รายชื่อไฟล์ที่แก้ไข
10. ผลการทดสอบ
11. ความเสี่ยงที่เหลือ
12. Path ของรายงาน
```
docs/online-lesson-create-workflow-redesign-report.md
```

View File

@@ -0,0 +1,410 @@
# Prompt: แก้ไขหน้าเจ้าหน้าที่บทเรียนออนไลน์ หลังบันทึกฉบับร่างให้กลับหน้ารายการ
## เป้าหมาย
ปรับปรุงหน้าเพิ่มหรือแก้ไขบทเรียนออนไลน์ของฝั่งเจ้าหน้าที่ เมื่อผู้ใช้งานกดปุ่ม **“บันทึกฉบับร่าง”** และระบบบันทึกสำเร็จ ให้ระบบนำผู้ใช้งานกลับไปยังหน้ารายการบทเรียนออนไลน์ทันที
---
## พฤติกรรมปัจจุบัน
หลังจากเจ้าหน้าที่กดปุ่ม:
```text
บันทึกฉบับร่าง
```
และบันทึกข้อมูลสำเร็จ ระบบยังคงอยู่ที่หน้าเดิม หรือไม่มีการนำทางกลับไปยังหน้ารายการบทเรียนออนไลน์
---
## พฤติกรรมที่คาดหวัง
เมื่อบันทึกฉบับร่างสำเร็จ ระบบต้อง:
1. แสดงข้อความแจ้งเตือนว่าบันทึกฉบับร่างสำเร็จ
2. อัปเดตหรือ Invalidate ข้อมูลรายการบทเรียนออนไลน์
3. นำผู้ใช้งานกลับไปยังหน้ารายการบทเรียนออนไลน์ของเจ้าหน้าที่
4. หน้ารายการต้องแสดงข้อมูลฉบับร่างที่เพิ่งสร้างหรือแก้ไขล่าสุด
5. รายการใหม่ต้องแสดงตาม Sorting มาตรฐานเดิมของระบบ โดยรายการที่สร้างหรืออัปเดตล่าสุดควรแสดงก่อน หากระบบกำหนดไว้เช่นนั้น
ตัวอย่าง Route ปลายทาง:
```text
/dashboard/online-lessons
```
ให้ตรวจสอบ Route จริงจาก Repository ห้ามสมมติหากระบบใช้ Path อื่น
---
## ขอบเขตการตรวจสอบ
ตรวจสอบ Flow ที่เกี่ยวข้องทั้งหมด:
```text
ปุ่มบันทึกฉบับร่าง
→ Form Submit
→ Server Action / API Mutation
→ บันทึกข้อมูลสำเร็จ
→ Invalidate / Refetch
→ Toast
→ Redirect กลับหน้ารายการ
```
ค้นหาไฟล์หรือ Component ที่เกี่ยวข้อง เช่น:
```text
OnlineLessonForm
OnlineLessonCreateForm
OnlineLessonEditForm
CreateOnlineLessonPage
EditOnlineLessonPage
useCreateOnlineLesson
useUpdateOnlineLesson
```
ชื่อจริงอาจแตกต่าง ให้ตรวจสอบจากโครงสร้างปัจจุบัน
---
## ตรวจสอบ Action ของปุ่ม Submit
หาก Form มีหลายปุ่ม เช่น:
```text
บันทึกฉบับร่าง
บันทึกส่งตรวจสอบ
```
ต้องแยก Action ให้ชัดเจน เช่น:
```ts
type SubmitAction = "draft" | "submit";
```
หรือใช้โครงสร้างเดิมที่ระบบมีอยู่แล้ว เช่น:
```ts
submitActionRef.current;
```
หลังบันทึกสำเร็จ ให้ตรวจสอบ Action ก่อนทำ Redirect
ตัวอย่างแนวคิด:
```ts
if (action === "draft") {
toast.success("บันทึกฉบับร่างเรียบร้อยแล้ว");
router.push("/dashboard/online-lessons");
router.refresh();
}
```
ห้าม Copy ตัวอย่างโดยตรง หากระบบมี Utility, Route Constant หรือ Navigation Pattern อยู่แล้ว ให้ใช้ของเดิม
---
## รองรับทั้งหน้าเพิ่มและหน้าแก้ไข
ตรวจสอบทั้งสองกรณี:
### หน้าเพิ่มบทเรียนออนไลน์
เมื่อสร้าง Draft สำเร็จ:
```text
Create Draft
→ กลับหน้ารายการ
```
### หน้าแก้ไขบทเรียนออนไลน์
เมื่อแก้ไข Draft และบันทึกสำเร็จ:
```text
Update Draft
→ กลับหน้ารายการ
```
หากหน้าแก้ไขรองรับการแก้เฉพาะสถานะ Draft ต้องคง Business Rule เดิมไว้
---
## การอัปเดตข้อมูลหน้ารายการ
ก่อนหรือหลัง Redirect ต้องทำให้หน้ารายการแสดงข้อมูลล่าสุด
หากใช้ Next.js Server Actions ให้ตรวจสอบการใช้:
```ts
revalidatePath("/dashboard/online-lessons");
```
หากใช้ React Query/TanStack Query ให้ตรวจสอบ:
```ts
queryClient.invalidateQueries({
queryKey: ["online-lessons"],
});
```
หากใช้ SWR ให้ตรวจสอบ:
```ts
mutate("/api/online-lessons");
```
ให้ใช้ Pattern จริงของระบบ ไม่ต้องเพิ่มหลายวิธีพร้อมกันโดยไม่จำเป็น
---
## ลำดับการทำงานที่แนะนำ
เมื่อบันทึกสำเร็จ:
```text
1. ยืนยันว่า API หรือ Server Action สำเร็จ
2. Invalidate หรือ Revalidate หน้ารายการ
3. แสดง Success Toast
4. Redirect ไปหน้ารายการ
```
ตัวอย่าง:
```ts
await saveDraft(values);
queryClient.invalidateQueries({
queryKey: ["online-lessons"],
});
toast.success("บันทึกฉบับร่างเรียบร้อยแล้ว");
router.push(ONLINE_LESSON_LIST_ROUTE);
```
หากใช้ `router.replace()` ตามมาตรฐานเดิมของระบบ ให้ใช้ Pattern เดิม
---
## การป้องกัน Redirect เมื่อบันทึกไม่สำเร็จ
ห้าม Redirect หาก:
- Validation ไม่ผ่าน
- API ตอบ Error
- Database บันทึกไม่สำเร็จ
- Upload File ไม่สำเร็จ
- Permission ไม่ผ่าน
- Server Action คืนสถานะ Failure
เมื่อเกิด Error ต้อง:
- อยู่หน้าเดิม
- แสดง Error Message
- รักษาข้อมูลใน Form ไว้
- ไม่เปลี่ยนสถานะโดยไม่ตั้งใจ
- ให้ผู้ใช้งานสามารถแก้ไขแล้วบันทึกใหม่ได้
ตัวอย่าง:
```ts
try {
await saveDraft(values);
toast.success("บันทึกฉบับร่างเรียบร้อยแล้ว");
router.push(listRoute);
} catch (error) {
toast.error(getErrorMessage(error));
}
```
---
## ป้องกันการ Submit ซ้ำ
ระหว่างบันทึก:
- Disable ปุ่มบันทึกฉบับร่าง
- แสดง Loading State
- ป้องกัน Double Click
- ไม่ Redirect ซ้ำ
- ไม่สร้าง Draft ซ้ำหลายรายการ
ตัวอย่าง:
```tsx
<Button type="submit" disabled={form.state.isSubmitting}>
{form.state.isSubmitting ? "กำลังบันทึก..." : "บันทึกฉบับร่าง"}
</Button>
```
ให้ใช้ State และ Component เดิมของระบบ
---
## ไม่กระทบปุ่ม “บันทึกส่งตรวจสอบ”
งานนี้ต้องตรวจสอบแยก Action ให้ถูกต้อง
ปุ่ม:
```text
บันทึกส่งตรวจสอบ
```
ต้องคงพฤติกรรมเดิม เว้นแต่ระบบกำหนดให้กลับหน้ารายการอยู่แล้ว
ห้ามทำให้:
- Draft ถูกเปลี่ยนเป็น Pending โดยไม่ตั้งใจ
- Submit Action ถูกตีความเป็น Draft
- ทั้งสองปุ่มใช้ Callback เดียวกันโดยไม่ตรวจสอบ Action
- Validation ของ Draft และ Submit ปะปนกัน
---
## กรณีมีไฟล์แนบ
หากการบันทึกบทเรียนออนไลน์มี:
- วิดีโอ
- Thumbnail
- เอกสารประกอบ
- ไฟล์แนบอื่น
ต้องรอให้กระบวนการ Upload และบันทึกข้อมูลเสร็จสมบูรณ์ก่อน Redirect
ห้าม Redirect ก่อน Upload เสร็จ เพราะอาจทำให้ข้อมูลหรือไฟล์ไม่ครบ
---
## Permission
ตรวจสอบว่าการเปลี่ยนแปลงนี้ใช้เฉพาะหน้าของเจ้าหน้าที่ที่มีสิทธิ์จัดการบทเรียนออนไลน์ เช่น:
```text
Staff
HRD Staff
HRD Manager
IT Admin
Super Admin
```
ให้ยึด Permission จริงจากระบบ
ห้ามเปลี่ยน:
- Permission Rule
- Approval Workflow
- Publish Workflow
- Status Transition
- สิทธิ์ของผู้ใช้งานทั่วไป
---
## Test Cases
### Test Case 1: สร้าง Draft สำเร็จ
1. เข้าหน้าเพิ่มบทเรียนออนไลน์
2. กรอกข้อมูลขั้นต่ำที่ Draft อนุญาต
3. กด “บันทึกฉบับร่าง”
4. ตรวจสอบว่าแสดงข้อความสำเร็จ
5. ตรวจสอบว่ากลับหน้ารายการ
6. ตรวจสอบว่ารายการ Draft ใหม่แสดงอยู่ในตาราง
### Test Case 2: แก้ไข Draft สำเร็จ
1. เปิดรายการสถานะ Draft
2. แก้ไขข้อมูล
3. กด “บันทึกฉบับร่าง”
4. ตรวจสอบว่ากลับหน้ารายการ
5. ตรวจสอบว่าข้อมูลล่าสุดแสดงถูกต้อง
### Test Case 3: Validation ไม่ผ่าน
1. กรอกข้อมูลไม่ถูกต้อง
2. กด “บันทึกฉบับร่าง”
3. ตรวจสอบว่าไม่ Redirect
4. แสดง Validation Error
5. ข้อมูลใน Form ไม่หาย
### Test Case 4: API Error
1. จำลอง API หรือ Database Error
2. กดบันทึกฉบับร่าง
3. ตรวจสอบว่าอยู่หน้าเดิม
4. แสดง Error Toast
5. ไม่สร้างข้อมูลซ้ำ
### Test Case 5: ป้องกันการ Submit ซ้ำ
1. กดบันทึกฉบับร่างหลายครั้งอย่างรวดเร็ว
2. ตรวจสอบว่าสร้างหรืออัปเดตเพียงครั้งเดียว
3. ปุ่มต้อง Disabled ระหว่าง Pending
### Test Case 6: ส่งตรวจสอบ
1. กด “บันทึกส่งตรวจสอบ”
2. ตรวจสอบว่า Workflow เดิมยังทำงานถูกต้อง
3. สถานะต้องเป็นไปตาม Business Rule เดิม
4. ไม่ถูกบันทึกเป็น Draft โดยผิดพลาด
### Test Case 7: ข้อมูลหน้ารายการล่าสุด
1. บันทึก Draft
2. กลับหน้ารายการ
3. ตรวจสอบว่าไม่ต้อง Refresh Browser
4. รายการใหม่หรือรายการที่แก้ไขต้องแสดงทันที
---
## Acceptance Criteria
งานถือว่าเสร็จเมื่อ:
- บันทึกฉบับร่างสำเร็จแล้วกลับหน้ารายการบทเรียนออนไลน์
- รองรับทั้งหน้า Create และ Edit
- หน้ารายการแสดงข้อมูลล่าสุดทันที
- มี Success Toast
- ไม่ Redirect เมื่อเกิด Error
- ไม่ Redirect เมื่อ Validation ไม่ผ่าน
- ป้องกัน Double Submit
- ไม่กระทบปุ่มบันทึกส่งตรวจสอบ
- ไม่เปลี่ยน Workflow และ Permission เดิม
- ไม่สร้างข้อมูลซ้ำ
- Type Check ผ่าน
- Lint ผ่าน
- Test ผ่าน
- Build ผ่าน
---
## รูปแบบรายงานผล
หลังแก้ไขเสร็จ ให้สรุป:
1. สาเหตุที่บันทึก Draft แล้วไม่กลับหน้ารายการ
2. Route หน้ารายการที่ใช้จริง
3. ไฟล์ที่แก้ไข
4. วิธีแยก Draft Action กับ Submit Action
5. วิธี Invalidate หรือ Revalidate ข้อมูล
6. พฤติกรรมเมื่อสำเร็จ
7. พฤติกรรมเมื่อเกิด Error
8. ผลการทดสอบ Create Draft
9. ผลการทดสอบ Edit Draft
10. ผล Type Check, Lint, Test และ Build
---
## ข้อกำหนดสุดท้าย
- ตรวจสอบโค้ดเดิมก่อนแก้ไข
- ใช้ Navigation และ Data Fetching Pattern เดิมของระบบ
- ห้ามสมมติ Route
- ห้าม Redirect ก่อนบันทึกและอัปโหลดเสร็จ
- ห้ามเปลี่ยน Business Rule
- ห้ามแก้เฉพาะหน้า Create โดยไม่ตรวจสอบหน้า Edit
- ห้ามรายงานว่าสำเร็จโดยไม่ตรวจสอบว่าหน้ารายการแสดงข้อมูลล่าสุดจริง

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,888 @@
# Prompt: ตรวจสอบและแก้ไขสถานะไม่อัปเดตทันทีหลังเจ้าหน้าที่กด “ส่งตรวจสอบ” จากปุ่ม Action
## บทบาท
ให้คุณทำหน้าที่เป็น Senior Full-Stack Developer และ Code Reviewer ตรวจสอบ Flow การเปลี่ยนสถานะของประวัติการอบรมในหน้าของเจ้าหน้าที่ ตั้งแต่ปุ่ม Action ไปจนถึงการอัปเดตข้อมูลบนหน้ารายการ
ต้องตรวจสอบโค้ดจริงใน Repository ก่อนแก้ไข ห้ามคาดเดา Query Key, API Route, Field, Status, State Management หรือ Data Fetching Library ขึ้นมาเอง
---
# ปัญหา
ในหน้าประวัติการอบรมของเจ้าหน้าที่ เมื่อกดคำสั่ง:
```text
ส่งตรวจสอบ
```
จากปุ่ม Action ของรายการ ระบบสามารถเปลี่ยนสถานะใน Backend หรือ Database ได้สำเร็จ แต่สถานะบนหน้ารายการยังไม่เปลี่ยนทันที
ผู้ใช้งานต้องกด Refresh Browser เอง จึงจะเห็นสถานะใหม่
ตัวอย่างพฤติกรรมปัจจุบัน:
```text
สถานะเดิม: ฉบับร่าง
กด Action → ส่งตรวจสอบ
ระบบแจ้งว่าสำเร็จ
สถานะในตารางยังเป็น: ฉบับร่าง
เมื่อ Refresh Browser
สถานะเปลี่ยนเป็น: รอตรวจสอบ
```
---
# เป้าหมาย
หลังเจ้าหน้าที่กด “ส่งตรวจสอบ” และระบบดำเนินการสำเร็จ ต้อง:
1. อัปเดตสถานะรายการบนหน้าจอทันที
2. ไม่ต้อง Refresh Browser
3. Refetch หรืออัปเดต Cache ของหน้ารายการอย่างถูกต้อง
4. อัปเดตจำนวนรายการและ Pagination ให้ตรงกับข้อมูลล่าสุด
5. หากหน้าปัจจุบันกรองเฉพาะสถานะฉบับร่าง รายการที่ส่งตรวจสอบแล้วต้องหายออกจากตารางทันที
6. รายการต้องไปปรากฏในสถานะรอตรวจสอบเมื่อเปิด Filter หรือหน้าที่เกี่ยวข้อง
7. ไม่กระทบ Search, Filter, Sorting, Pagination, Permission และ Workflow เดิม
---
# ขอบเขตการตรวจสอบ
ตรวจสอบ Flow ทั้งหมด:
```text
Action Menu
→ Confirmation Dialog
→ Mutation / Server Action / API Request
→ Backend Status Update
→ Database Commit
→ Response
→ Cache Invalidation / Refetch
→ Table Data
→ Status Badge
→ Pagination / Count
```
ค้นหาไฟล์และ Component ที่เกี่ยวข้อง เช่น:
```text
TrainingRecordActionMenu
TrainingRecordCellAction
DraftTrainingRecordAction
SubmitForReviewAction
PendingReviewActionMenu
TrainingRecordTable
TrainingRecordList
TrainingRecordStatusBadge
```
รวมถึง Hook หรือ Function เช่น:
```text
useSubmitTrainingRecord
useSubmitForReview
useUpdateTrainingRecordStatus
submitTrainingRecord
updateTrainingRecordStatus
```
ชื่อจริงอาจแตกต่าง ให้ตรวจสอบจาก Repository
---
# Phase 1: ตรวจสอบหน้ารายการและ Data Fetching
ตรวจสอบว่าหน้ารายการประวัติการอบรมใช้วิธีดึงข้อมูลแบบใด เช่น:
- TanStack Query / React Query
- SWR
- Server Component
- Server Action
- `router.refresh()`
- Local State
- TanStack Table
- URL Search Params
ระบุให้ได้ว่า Source of Truth ของข้อมูลในตารางคืออะไร
ตัวอย่างสิ่งที่ต้องตรวจสอบ:
```ts
useQuery({
queryKey: ["training-records", filters],
queryFn: ...
});
```
หรือ:
```ts
useSWR(`/api/training-records?${queryString}`, fetcher);
```
หรือ:
```tsx
const data = await getTrainingRecords(searchParams);
```
จากนั้นตรวจสอบว่าหลัง Mutation สำเร็จ มีการสั่งอัปเดต Source of Truth นั้นหรือไม่
---
# Phase 2: ตรวจสอบ Mutation ของปุ่ม “ส่งตรวจสอบ”
ตรวจสอบ Handler ที่ถูกเรียกเมื่อกด Action เช่น:
```ts
handleSubmitForReview;
submitForReviewMutation;
onSubmitForReview;
handleStatusChange;
```
ตรวจสอบประเด็นต่อไปนี้:
1. มีการ `await` API หรือ Server Action จริงหรือไม่
2. Toast แสดงก่อน API สำเร็จหรือไม่
3. `router.refresh()` ถูกเรียกก่อน Mutation เสร็จหรือไม่
4. มี `onSuccess` หรือ Success Callback หรือไม่
5. มีการ Invalidate Query หรือ Revalidate Path หรือไม่
6. Query Key ที่ Invalidate ตรงกับหน้ารายการจริงหรือไม่
7. มีการอัปเดต Local State หรือ Table Data หรือไม่
8. Action Menu ปิดแล้วใช้ `row.original` ชุดเดิมต่อหรือไม่
9. Response จาก API มีสถานะใหม่หรือไม่
10. มี Error ถูก Ignore หรือไม่
---
# สาเหตุที่ต้องตรวจสอบเป็นพิเศษ
## 1. Mutation สำเร็จแต่ไม่ได้ Invalidate Query
ตัวอย่างปัญหา:
```ts
const mutation = useMutation({
mutationFn: submitForReview,
});
```
แต่ไม่มี:
```ts
queryClient.invalidateQueries(...)
```
ผลคือ Backend เปลี่ยนสถานะแล้ว แต่ Table ยังใช้ Cache เดิม
---
## 2. Query Key ไม่ตรงกัน
ตัวอย่าง:
หน้ารายการใช้:
```ts
["training-records", filters];
```
แต่ Action Invalidate:
```ts
["training-record"];
```
หรือ:
```ts
["training-records", id];
```
ซึ่งไม่ครอบคลุม Query List
ให้ตรวจสอบ Query Key Factory หรือ Constant กลาง หากระบบมีอยู่แล้ว เช่น:
```ts
trainingRecordKeys.all;
trainingRecordKeys.lists();
trainingRecordKeys.list(filters);
trainingRecordKeys.detail(id);
```
ควรใช้ Key กลางแทน String ที่เขียนซ้ำ
---
## 3. ใช้ `router.refresh()` ไม่ตรงกับ Data Fetching Pattern
หาก Table ใช้ React Query หรือ SWR การเรียกเพียง:
```ts
router.refresh();
```
อาจไม่ทำให้ Client Cache เปลี่ยน
ในกรณีนี้ต้องใช้ Invalidate หรือ Mutate ของ Library ที่ใช้อยู่จริง
หากข้อมูลมาจาก Server Component และมี Cache ฝั่ง Server ต้องตรวจสอบ:
```ts
revalidatePath(...)
revalidateTag(...)
router.refresh()
```
ให้ใช้เท่าที่จำเป็นตามโครงสร้างจริง ห้ามเพิ่มทุกวิธีพร้อมกันโดยไม่มีเหตุผล
---
## 4. Refresh ถูกเรียกก่อน Backend Update เสร็จ
ตัวอย่างที่เสี่ยง:
```ts
startTransition(() => {
submitForReview(id);
router.refresh();
});
```
หาก `submitForReview` เป็น Async แต่ไม่ได้รอ ระบบอาจ Refresh ด้วยข้อมูลเก่าก่อน Database Commit
ต้องเปลี่ยนเป็น Flow ที่รอผลสำเร็จก่อน:
```ts
await submitForReview(id);
await refreshListData();
```
---
## 5. Invalidate เฉพาะ Query ที่แคบเกินไป
หากหน้ารายการมีหลาย Filter เช่น:
```text
status=draft
status=pending
status=approved
all statuses
```
การ Invalidate เฉพาะ Query Draft อาจทำให้ Query Pending หรือ All Status ยังเก็บ Cache เก่า
ควรตรวจสอบว่า Query Key Hierarchy รองรับการ Invalidate List ทั้งหมด เช่น:
```ts
queryClient.invalidateQueries({
queryKey: trainingRecordKeys.lists(),
});
```
หรือ Key ต้นทางที่ครอบคลุมรายการทั้งหมด
---
# แนวทางการแก้ไขตาม Data Fetching Library
## กรณีใช้ TanStack Query / React Query
ให้ใช้ `useQueryClient()` และ Invalidate Query List หลัง Mutation สำเร็จ
ตัวอย่างแนวคิด:
```ts
const queryClient = useQueryClient();
const submitForReviewMutation = useMutation({
mutationFn: submitForReview,
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: trainingRecordKeys.lists(),
});
toast.success("ส่งตรวจสอบเรียบร้อยแล้ว");
},
onError: (error) => {
toast.error(getErrorMessage(error));
},
});
```
หากระบบยังไม่มี Query Key Factory ให้พิจารณาใช้ Key เดิมให้ตรงกันก่อน ห้าม Refactor ใหญ่เกินขอบเขตโดยไม่จำเป็น
หากมี Detail Query ที่แสดงสถานะด้วย ให้ Invalidate เพิ่มเฉพาะที่เกี่ยวข้อง เช่น:
```ts
await Promise.all([
queryClient.invalidateQueries({
queryKey: trainingRecordKeys.lists(),
}),
queryClient.invalidateQueries({
queryKey: trainingRecordKeys.detail(trainingRecordId),
}),
]);
```
---
## กรณีใช้ SWR
ตรวจสอบ Key จริงของหน้ารายการ ซึ่งอาจมี Query String เช่น:
```text
/api/training-records?page=1&status=draft
```
ให้ใช้ `mutate` ที่ครอบคลุม Key รายการทั้งหมดตาม Pattern เดิม
ตัวอย่างแนวคิด:
```ts
await mutate(
(key) => typeof key === "string" && key.startsWith("/api/training-records"),
);
```
หรือใช้ Key Factory กลาง หากมีอยู่แล้ว
ห้ามเรียก `mutate("/api/training-records")` หาก Key จริงมี Query String และไม่เกิดการ Match
---
## กรณีใช้ Server Component / Server Action
ตรวจสอบว่า Mutation ฝั่ง Server เรียก:
```ts
revalidatePath("/dashboard/training-records");
```
หรือ:
```ts
revalidateTag("training-records");
```
จากนั้นฝั่ง Client อาจต้องเรียก:
```ts
router.refresh();
```
หลัง Server Action สำเร็จ
ตัวอย่างแนวคิด:
```ts
const result = await submitForReviewAction(id);
if (!result.success) {
throw new Error(result.message);
}
router.refresh();
toast.success("ส่งตรวจสอบเรียบร้อยแล้ว");
```
ต้องตรวจสอบให้แน่ใจว่า `router.refresh()` ถูกเรียกหลัง Action สำเร็จเท่านั้น
---
# การอัปเดตแบบ Optimistic
สามารถใช้ Optimistic Update ได้ หาก Pattern เดิมของระบบรองรับและ Type ปลอดภัย
แต่สำหรับกรณีสถานะเปลี่ยนแล้วรายการอาจต้อง:
- หายจาก Filter Draft
- ไปอยู่ Filter Pending
- เปลี่ยน Count
- เปลี่ยน Sorting
- เพิ่ม submitted_at
- เพิ่ม submitted_by
- สร้าง Audit Log
- สร้าง Notification
แนะนำให้ใช้:
```text
Mutation สำเร็จ
→ Invalidate
→ Refetch จาก Server
```
เป็นแนวทางหลัก เพื่อให้ข้อมูลตรงกับ Backend
หากต้องการ Optimistic Update ให้ทำร่วมกับ Invalidate ภายหลัง และต้องมี Rollback เมื่อเกิด Error
---
# การจัดการรายการที่ถูกกรองตามสถานะ
หากหน้าปัจจุบันเลือก Filter:
```text
สถานะ = ฉบับร่าง
```
เมื่อส่งตรวจสอบสำเร็จ รายการนั้นต้องหายจากตาราง เพราะสถานะใหม่ไม่ตรงกับ Filter ปัจจุบัน
ระบบต้องอัปเดต:
- Rows
- Total Count
- Page Count
- Empty State
- Pagination
ตัวอย่างกรณี:
```text
หน้า 2 มีรายการเดียว
ส่งตรวจสอบสำเร็จ
รายการหาย
หน้า 2 ไม่มีข้อมูล
```
ให้ตรวจสอบว่าระบบควร:
- กลับหน้า 1 หรือ
- ลดไปหน้าก่อนหน้า
ตาม Pagination Pattern เดิมของระบบ
ห้ามปล่อยให้ผู้ใช้ค้างอยู่บนหน้าว่างโดย Count และ Page ไม่ตรงกัน
---
# การ Reset หรือปรับ Pagination
หลังรายการถูกเปลี่ยนสถานะและหายจาก Filter ปัจจุบัน ให้ตรวจสอบ Pagination
หากข้อมูลหน้าปัจจุบันหมด ต้องปรับ Page ให้ถูกต้องตาม Pattern เดิม เช่น:
```ts
if (currentPage > newTotalPages) {
setPage(Math.max(newTotalPages, 1));
}
```
หากใช้ URL Search Params ต้องอัปเดต Parameter อย่างปลอดภัย
ห้าม Reset หน้า 1 ทุกครั้งโดยไม่มีเหตุผล หากระบบเดิมมีพฤติกรรมรักษาหน้าปัจจุบัน
---
# การอัปเดต Count หรือ Tab Badge
หากหน้าของเจ้าหน้าที่มี:
- จำนวนฉบับร่าง
- จำนวนรอตรวจสอบ
- Status Tabs
- Summary Cards
- Badge จำนวนรายการ
ต้อง Invalidate หรือ Refetch ข้อมูลสรุปที่เกี่ยวข้องด้วย
ตัวอย่าง Query Key ที่อาจต้องอัปเดต:
```text
training-records
training-record-counts
training-record-summary
dashboard-summary
notifications
```
ให้ตรวจสอบจากโค้ดจริงว่ามี Query ใดได้รับผลกระทบ
ห้าม Invalidate Query ทั้งระบบแบบกว้างเกินจำเป็น
---
# Loading และ Double Submit
ระหว่างส่งตรวจสอบ:
- Disable Action ที่กำลังกด
- แสดง Loading State
- ป้องกัน Double Click
- ป้องกัน Request ซ้ำ
- ไม่ปิด Dialog ก่อนเริ่ม Request หาก Pattern เดิมไม่รองรับ
- ไม่แสดง Toast สำเร็จก่อน Response สำเร็จ
ตัวอย่าง:
```tsx
<Button
disabled={submitForReviewMutation.isPending}
onClick={() => submitForReviewMutation.mutate(record.id)}
>
{submitForReviewMutation.isPending ? "กำลังส่ง..." : "ยืนยันส่งตรวจสอบ"}
</Button>
```
หากเป็น Action Menu หลายแถว ต้องพิจารณา Pending State แบบแยกตาม Record ID เพื่อไม่ให้ทุกแถว Disabled โดยไม่จำเป็น
---
# Error Handling
หากส่งตรวจสอบไม่สำเร็จ:
- ต้องไม่เปลี่ยนสถานะบน UI เป็นสถานะใหม่
- ต้องไม่ลบรายการออกจากตาราง
- ต้องไม่ Invalidate แบบทำให้ผู้ใช้เข้าใจผิด
- แสดง Error Message ที่เหมาะสม
- ปิดหรือเปิด Dialog ตาม Pattern เดิม
- ผู้ใช้สามารถลองใหม่ได้
หากใช้ Optimistic Update ต้อง Rollback Cache
---
# Permission และ Business Rule
ห้ามเปลี่ยน:
- สิทธิ์การส่งตรวจสอบ
- สถานะที่อนุญาตให้ส่งตรวจสอบ
- Workflow Transition
- Validation
- Audit Log
- Notification
- Approval Flow
- สิทธิ์ของ Employee, Staff, Manager, HRD หรือ Admin
- API Authorization
การแก้ไขครั้งนี้ต้องแก้เฉพาะการ Synchronize ข้อมูลหลัง Mutation สำเร็จ
หากพบว่า Backend อนุญาต Status Transition ผิด ต้องรายงานแยก ไม่ควรเปลี่ยน Business Rule โดยอัตโนมัติ
---
# ตรวจสอบ API Response
ตรวจสอบว่า API หรือ Server Action คืนผลลัพธ์ที่ชัดเจน เช่น:
```ts
{
success: true,
data: {
id: "...",
status: "pending",
updatedAt: "...",
},
}
```
หาก Response เดิมเพียงพอ ไม่ต้องเปลี่ยน Structure
หาก Response ไม่ชัดเจนจน Client ไม่ทราบว่าสำเร็จหรือไม่ ให้ปรับตามมาตรฐาน API เดิมของระบบ โดยหลีกเลี่ยง Breaking Change
---
# Test Cases
## Test Case 1: ส่งตรวจสอบสำเร็จจากรายการทั้งหมด
1. เปิดหน้าประวัติการอบรมของเจ้าหน้าที่
2. เลือกรายการสถานะฉบับร่าง
3. กด Action
4. กดส่งตรวจสอบ
5. ยืนยันคำสั่ง
6. ตรวจสอบ Success Message
7. ตรวจสอบว่าสถานะเปลี่ยนทันทีโดยไม่ Refresh Browser
8. ตรวจสอบข้อมูลจาก API หรือ Network ว่ามีการ Refetch
---
## Test Case 2: ส่งตรวจสอบขณะ Filter Draft
1. เลือก Filter สถานะฉบับร่าง
2. ส่งรายการหนึ่งไปตรวจสอบ
3. รายการต้องหายจากตารางทันที
4. Total Count ต้องลดลง
5. Page Count ต้องถูกต้อง
6. เมื่อเลือก Filter รอตรวจสอบ รายการต้องปรากฏ
---
## Test Case 3: ส่งตรวจสอบจากหน้ารวมทุกสถานะ
1. เปิดรายการทุกสถานะ
2. ส่ง Draft ไปตรวจสอบ
3. Row เดิมต้องยังอยู่ในตาราง หากตรงกับ Filter
4. Status Badge ต้องเปลี่ยนเป็นรอตรวจสอบ
5. Action Menu ต้องเปลี่ยนตามสถานะใหม่
---
## Test Case 4: ใช้ร่วมกับ Search
1. ค้นหารายการ
2. ส่งตรวจสอบจากผลการค้นหา
3. ตรวจสอบว่าสถานะอัปเดต
4. Search Value ต้องไม่หาย
5. ข้อมูลต้องยังตรงกับคำค้นหา
---
## Test Case 5: ใช้ร่วมกับ Pagination
1. ไปหน้าที่มากกว่า 1
2. ส่งรายการตรวจสอบ
3. ตรวจสอบ Count และ Page
4. หากหน้าปัจจุบันไม่มีข้อมูล ต้องปรับหน้าอย่างถูกต้อง
5. ห้ามเกิดหน้าว่างที่ Pagination ผิด
---
## Test Case 6: API Error
1. จำลอง API Error
2. กดส่งตรวจสอบ
3. ต้องแสดง Error
4. สถานะเดิมต้องคงอยู่
5. รายการต้องไม่หาย
6. ไม่ต้อง Refresh Browser เพื่อกู้สถานะ
---
## Test Case 7: Double Click
1. กดส่งตรวจสอบซ้ำอย่างรวดเร็ว
2. ต้องเกิด Request เดียว
3. ไม่สร้าง Audit Log หรือ Notification ซ้ำ
4. สถานะต้องเปลี่ยนเพียงครั้งเดียว
---
## Test Case 8: Query Key
1. ตรวจสอบ Query Key ของหน้ารายการ
2. ตรวจสอบ Query Key ที่ Invalidate
3. ต้อง Match กันตาม Hierarchy
4. ตรวจสอบ Filter หลายรูปแบบ
5. ทุก Query List ที่เกี่ยวข้องต้องอัปเดต
---
## Test Case 9: Refresh Browser หลังแก้ไข
1. ส่งตรวจสอบ
2. ตรวจสอบสถานะทันที
3. Refresh Browser
4. สถานะหลัง Refresh ต้องตรงกับก่อน Refresh
5. ไม่มีข้อมูลย้อนกลับเป็นสถานะเดิม
---
## Test Case 10: Permission
1. Login ด้วย Role ที่มีสิทธิ์ส่งตรวจสอบ
2. ตรวจสอบว่าส่งได้ตามเดิม
3. Login ด้วย Role ที่ไม่มีสิทธิ์
4. ตรวจสอบว่า Action ไม่แสดงหรือถูกปฏิเสธตามเดิม
5. การแก้ Cache ต้องไม่เปิดเผยข้อมูลของผู้ใช้อื่น
---
# Automated Test
หาก Repository มี Test Framework ให้เพิ่มหรือปรับปรุง Test ตาม Pattern เดิม
อย่างน้อยควรครอบคลุม:
```text
mutation success
mutation error
list query invalidation
filtered draft list update
all-status list update
pagination count update
double-submit prevention
permission unchanged
```
หากใช้ TanStack Query สามารถ Test ได้ว่า `invalidateQueries` ถูกเรียกด้วย Query Key ที่ถูกต้อง
หากใช้ SWR ให้ Test ว่า `mutate` Match Key ที่มี Query String
หากใช้ Server Action ให้ Test ว่า Revalidation และ Refresh เกิดหลัง Success
---
# Validation ก่อนส่งงาน
รันคำสั่งตาม `package.json` และ Repository จริง เช่น:
```bash
pnpm typecheck
pnpm lint
pnpm test
pnpm build
```
ห้ามแก้ Type Error ด้วย:
```ts
any
@ts-ignore
@ts-expect-error
eslint-disable
```
เว้นแต่มีเหตุผลจำเป็นและอธิบายไว้ในรายงาน
---
# Acceptance Criteria
งานถือว่าเสร็จเมื่อ:
- กดส่งตรวจสอบแล้วสถานะอัปเดตทันที
- ไม่ต้อง Refresh Browser
- Mutation รอ Backend สำเร็จก่อนอัปเดต UI
- ใช้ Cache Invalidation หรือ Refetch ตาม Data Fetching Pattern จริง
- Query Key ที่ Invalidate ตรงกับหน้ารายการ
- รายการ Draft หายจาก Draft Filter ทันที
- รายการปรากฏใน Pending Filter
- รายการในหน้ารวมเปลี่ยน Status Badge ทันที
- Action Menu เปลี่ยนตามสถานะใหม่
- Total Count และ Page Count ถูกต้อง
- Pagination ไม่ค้างหน้าที่ไม่มีข้อมูล
- Search, Filter และ Sorting ยังคงอยู่
- ป้องกัน Double Submit
- Error ไม่ทำให้ UI แสดงสถานะผิด
- Permission และ Workflow ไม่เปลี่ยน
- ไม่มี Regression ต่อหน้า Employee หรือหน้า HRD อื่น
- Type Check ผ่าน
- Lint ผ่าน
- Test ผ่าน
- Build ผ่าน
---
# รูปแบบรายงานผลหลังแก้ไข
หลังดำเนินการเสร็จ ให้รายงานตามหัวข้อต่อไปนี้
## 1. สาเหตุของปัญหา
ระบุสาเหตุจริง เช่น:
```text
Mutation สำเร็จ แต่ไม่มีการ invalidate list query
```
หรือ:
```text
invalidate query key ไม่ตรงกับ key ของหน้ารายการ
```
หรือ:
```text
router.refresh ถูกเรียกก่อน server action เสร็จ
```
ห้ามสรุปจากการคาดเดา
## 2. Data Fetching Pattern ที่ระบบใช้
ระบุว่าใช้:
```text
TanStack Query / SWR / Server Component / Server Action
```
และอธิบาย Source of Truth ของตาราง
## 3. ไฟล์ที่แก้ไข
ระบุ Path และหน้าที่ของแต่ละไฟล์
## 4. Query Key หรือ Cache Key
ระบุ Key ก่อนและหลังแก้ไข เช่น:
```ts
trainingRecordKeys.lists();
```
## 5. วิธีอัปเดตข้อมูลหลัง Mutation
ระบุว่าใช้:
```text
invalidateQueries
mutate
revalidatePath
revalidateTag
router.refresh
setQueryData
```
พร้อมเหตุผล
## 6. ผลต่อ Filter และ Pagination
อธิบายว่า Draft หายอย่างไร Count อัปเดตอย่างไร และ Page ถูกจัดการอย่างไร
## 7. Error Handling
อธิบายพฤติกรรมเมื่อ API ล้มเหลว
## 8. ผลการทดสอบ
รายงาน:
- Manual Test
- Automated Test
- Type Check
- Lint
- Build
## 9. Regression Check
ยืนยันว่า:
- Search ยังทำงาน
- Filter ยังทำงาน
- Sorting ยังทำงาน
- Pagination ยังทำงาน
- Permission ไม่เปลี่ยน
- Workflow ไม่เปลี่ยน
- หน้าอื่นที่ใช้ Query เดียวกันไม่เสีย
## 10. ประเด็นคงค้าง
หากยังมีข้อจำกัด ให้ระบุตรงไปตรงมา ห้ามรายงานว่างานสมบูรณ์หากยังต้อง Refresh เองในบางกรณี
---
# ข้อกำหนดสุดท้าย
- ตรวจสอบสาเหตุจากโค้ดจริงก่อนแก้ไข
- แก้ตาม Data Fetching Pattern เดิม
- ใช้ Query Key หรือ Cache Key กลาง หากมี
- ห้ามแก้ด้วย `window.location.reload()`
- ห้ามบังคับ Refresh Browser
- ห้ามใช้ `setTimeout()` เพื่อรอข้อมูล
- ห้ามแก้ด้วยการเปลี่ยนสถานะเฉพาะใน DOM
- ห้ามแสดง Success Toast ก่อน Backend สำเร็จ
- ห้าม Invalidate Cache ทั้งระบบโดยไม่จำเป็น
- ห้ามเปลี่ยน Permission หรือ Workflow
- ต้องยืนยันผลจากทั้ง Network, API Response และ UI
- ต้องทดสอบทั้งหน้ารวมสถานะและหน้าที่ Filter เฉพาะ Draft

373
plans/online-lessons.md Normal file
View File

@@ -0,0 +1,373 @@
ต้องการเพิ่มฟีเจอร์ใหม่ในระบบ Training System ชื่อ **บทเรียนออนไลน์ (Online Lessons)** โดยให้มีลักษณะคล้ายเมนู **ประกาศ** เดิม แต่เปลี่ยนวัตถุประสงค์เป็นการจัดการบทเรียนออนไลน์สำหรับ HRD และแสดงบทเรียนให้พนักงานเข้าไปเรียนได้
## 1. เมนูที่ต้องเพิ่ม
### สำหรับ HRD/Admin
เพิ่มเมนูใหม่ชื่อ:
**เพิ่มบทเรียนออนไลน์**
ใช้สำหรับให้ HRD เพิ่ม แก้ไข ลบ และเผยแพร่บทเรียนออนไลน์
Path แนะนำ:
```txt
/dashboard/online-lessons/manage
```
หรือ
```txt
/dashboard/online-lessons-admin
```
### สำหรับพนักงาน
เพิ่มเมนูใหม่ชื่อ:
**บทเรียนออนไลน์**
ใช้สำหรับให้พนักงานเปิดดูบทเรียน วิดีโอ และดาวน์โหลดไฟล์แนบ
Path แนะนำ:
```txt
/dashboard/online-lessons
```
---
## 2. สิทธิ์การเข้าถึง
### HRD/Admin
สามารถทำได้ดังนี้:
- เพิ่มบทเรียนออนไลน์
- แก้ไขบทเรียน
- ลบบทเรียน
- เปิด/ปิดการเผยแพร่
- แนบไฟล์เอกสาร
- เพิ่มลิงก์วิดีโอ หรืออัปโหลดวิดีโอ
- กำหนดสถานะบทเรียน
### Employee
สามารถทำได้ดังนี้:
- ดูรายการบทเรียนออนไลน์ที่เผยแพร่แล้วเท่านั้น
- เปิดดูวิดีโอ
- อ่านรายละเอียดบทเรียน
- ดาวน์โหลดไฟล์แนบ
- ไม่สามารถเพิ่ม แก้ไข หรือลบบทเรียนได้
---
## 3. ข้อมูลของบทเรียนออนไลน์
ให้สร้างข้อมูล Online Lesson โดยมี fields ประมาณนี้:
```ts
{
id: string;
title: string;
description?: string;
category?: string;
videoUrl?: string;
videoFileUrl?: string;
attachmentUrl?: string;
attachmentName?: string;
thumbnailUrl?: string;
status: "draft" | "published" | "archived";
isPublished: boolean;
publishedAt?: Date;
createdBy: string;
updatedBy?: string;
createdAt: Date;
updatedAt: Date;
}
```
---
## 4. หน้าจอ HRD: เพิ่มบทเรียนออนไลน์
ให้ทำหน้า Layout คล้ายเมนู **ประกาศ**
### รายการบทเรียน
แสดงเป็นตาราง มี columns:
- ชื่อบทเรียน
- หมวดหมู่
- ประเภทวิดีโอ
- ไฟล์แนบ
- สถานะ
- วันที่เผยแพร่
- ผู้สร้าง
- จัดการ
### ปุ่มหลัก
- เพิ่มบทเรียนออนไลน์
- ค้นหา
- Filter สถานะ
- Filter หมวดหมู่
- View
- Pagination
---
## 5. ฟอร์มเพิ่ม / แก้ไขบทเรียน
ฟอร์มควรมี fields ดังนี้:
### ข้อมูลหลัก
- ชื่อบทเรียน
- รายละเอียดบทเรียน
- หมวดหมู่
- สถานะ: Draft / Published / Archived
### วิดีโอ
ให้รองรับ 2 แบบ:
1. ใส่ลิงก์วิดีโอ เช่น YouTube, Google Drive, OneDrive, SharePoint หรือ URL ภายนอก
2. อัปโหลดไฟล์วิดีโอ เช่น `.mp4`, `.webm`, `.mov`
### เอกสารแนบ
ให้แนบไฟล์ประกอบบทเรียนได้ เช่น:
- PDF
- Word
- Excel
- PowerPoint
- รูปภาพ
- ZIP
### รูปปกบทเรียน
- อัปโหลด Thumbnail หรือไม่มีก็ได้
- ถ้าไม่มีรูป ให้แสดง icon default เหมือนระบบประกาศ
---
## 6. หน้าจอพนักงาน: บทเรียนออนไลน์
ให้แสดงเฉพาะบทเรียนที่สถานะเป็น `published` หรือ `isPublished = true`
### รูปแบบการแสดงผล
แนะนำให้แสดงเป็น Card Grid คล้ายประกาศ
แต่ละ Card แสดง:
- รูปปก หรือ icon default
- ชื่อบทเรียน
- รายละเอียดสั้น ๆ
- หมวดหมู่
- วันที่เผยแพร่
- ปุ่ม “เปิดบทเรียน”
---
## 7. หน้ารายละเอียดบทเรียน
เมื่อพนักงานกดเปิดบทเรียน ให้แสดงหน้า Detail
ข้อมูลที่ต้องแสดง:
- ชื่อบทเรียน
- รายละเอียด
- วิดีโอ
- ไฟล์แนบ
- วันที่เผยแพร่
### การแสดงวิดีโอ
ถ้าเป็น `videoUrl` ให้ embed หรือเปิดผ่าน iframe/player ถ้ารองรับ
ถ้าเป็น `videoFileUrl` ให้ใช้ HTML video player:
```tsx
<video controls className="w-full rounded-xl">
<source src={lesson.videoFileUrl} />
</video>
```
### ไฟล์แนบ
ถ้ามีไฟล์แนบ ให้แสดงรายการไฟล์พร้อมปุ่ม:
- ดาวน์โหลด
- เปิดไฟล์
ถ้าไม่มีไฟล์แนบ ให้แสดงข้อความ:
```txt
ไม่มีไฟล์แนบ
```
---
## 8. UI/UX
ให้ดีไซน์เหมือนเมนูประกาศเดิม
- ใช้ Card
- ใช้ Badge แสดงสถานะ
- ใช้ icon default ถ้าไม่มีรูปปก
- ใช้ Empty State เมื่อไม่มีบทเรียน
- ใช้ Confirm Dialog ก่อนลบ
- ใช้ Toast แจ้งผลสำเร็จ/ผิดพลาด
- รองรับ Responsive
- ใช้ Theme สีเดียวกับระบบเดิม
---
## 9. Validation
ใช้ Zod validation
เงื่อนไข:
- ชื่อบทเรียน: required
- รายละเอียด: optional
- ต้องมีอย่างน้อย 1 อย่างระหว่าง `videoUrl` หรือ `videoFile`
- สถานะ: required
- ไฟล์แนบ: optional
ตัวอย่าง validation:
```ts
const onlineLessonSchema = z
.object({
title: z.string().min(1, "กรุณากรอกชื่อบทเรียน"),
description: z.string().optional(),
category: z.string().optional(),
videoUrl: z
.string()
.url("URL วิดีโอไม่ถูกต้อง")
.optional()
.or(z.literal("")),
videoFile: z.any().optional(),
attachmentFile: z.any().optional(),
status: z.enum(["draft", "published", "archived"]),
})
.refine((data) => data.videoUrl || data.videoFile, {
message: "กรุณาใส่ลิงก์วิดีโอหรืออัปโหลดไฟล์วิดีโอ",
path: ["videoUrl"],
});
```
---
## 10. Database / Prisma Model
เพิ่ม model สำหรับ OnlineLesson
```prisma
model OnlineLesson {
id String @id @default(cuid())
title String
description String? @db.Text
category String?
videoUrl String?
videoFileUrl String?
attachmentUrl String?
attachmentName String?
thumbnailUrl String?
status String @default("draft")
isPublished Boolean @default(false)
publishedAt DateTime?
createdBy String?
updatedBy String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
```
---
## 11. API / Actions
สร้าง server actions หรือ API สำหรับ:
- createOnlineLesson
- updateOnlineLesson
- deleteOnlineLesson
- getOnlineLessonsForAdmin
- getPublishedOnlineLessons
- getOnlineLessonById
- uploadOnlineLessonFile
---
## 12. Sidebar Menu
เพิ่มเมนูใน Sidebar
### สำหรับ HRD/Admin
```txt
เพิ่มบทเรียนออนไลน์
```
Icon แนะนำ:
- BookOpen
- Video
- GraduationCap
- FileVideo
### สำหรับ Employee
```txt
บทเรียนออนไลน์
```
Icon แนะนำ:
- BookOpen
- PlayCircle
- MonitorPlay
---
## 13. ข้อจำกัด
ห้ามกระทบเมนูเดิม เช่น:
- ประกาศ
- หลักสูตร
- ประวัติการอบรม
- รายชื่อพนักงาน
- รายงาน
ห้ามแก้ Business Logic เดิมของระบบอบรม
ให้เพิ่มเป็น Module ใหม่แยกออกมา
---
## 14. ผลลัพธ์ที่ต้องการ
เมื่อ HRD เพิ่มบทเรียนออนไลน์และตั้งสถานะเป็น Published
พนักงานจะเห็นบทเรียนนั้นในเมนู **บทเรียนออนไลน์**
พนักงานสามารถ:
- เปิดดูวิดีโอได้
- อ่านรายละเอียดบทเรียนได้
- ดาวน์โหลดไฟล์แนบได้
HRD สามารถ:
- จัดการบทเรียนทั้งหมดได้
- แก้ไขบทเรียนได้
- ลบบทเรียนได้
- เปิด/ปิดการเผยแพร่ได้

View File

@@ -0,0 +1,829 @@
# Prompt: Organizers Module Enhancement (CRUD + Soft Delete + Permission + Audit)
## Objective
ดำเนินการตรวจสอบ วิเคราะห์ ออกแบบ และพัฒนา Module **Organizers** ให้รองรับการจัดการข้อมูลแบบสมบูรณ์ (CRUD) โดยใช้หลักการ **Soft Delete** และสอดคล้องกับ Architecture ของระบบปัจจุบัน
การดำเนินการต้องครอบคลุม
- Create Organizer
- View Organizer
- Edit Organizer
- Soft Delete Organizer
- Permission Control
- Validation
- Audit Log
- UI/UX Improvement
- Regression Testing
- Documentation
---
# Background
ระบบนี้เป็น Training Management System (TMS)
Architecture หลัก
- Next.js App Router
- TypeScript
- Prisma ORM
- TanStack Query
- TanStack Form
- shadcn/ui
- Permission Template First
- RBAC + Permission
- Audit Log
- Multi Organization
ปัจจุบันหน้า Organizers สามารถสร้าง Organizer ได้เพียงบางส่วน และยังไม่มีความสามารถในการ
- แก้ไข
- ลบ
- Soft Delete
- Validation ครบถ้วน
- Audit
- Permission ครบ
---
# IMPORTANT
ก่อนแก้ไข
AI ต้องตรวจสอบ Architecture เดิมก่อนทุกครั้ง
ห้ามสร้าง Pattern ใหม่ หากระบบมี Pattern เดิมอยู่แล้ว
ต้อง Reuse
- Shared Components
- Shared Dialog
- Shared Form
- Shared Validation
- Shared Permission
- Shared Toast
- Shared Table/Card Pattern
- Shared API Pattern
- Shared Service Layer
---
# Phase 0 — Architecture Audit
ก่อนแก้ไข
ตรวจสอบ
## Frontend
- Organizer Page
- Organizer List
- Organizer Card
- Create Form
- Existing Components
- Dialog Pattern
- Sheet Pattern
- Toast Pattern
---
## Backend
ตรวจสอบ
- API Routes
- Route Handlers
- Server Actions
- Service Layer
- Repository
- Prisma Queries
---
## Database
ตรวจสอบ
Organizer Model
เช่น
- id
- name
- slug
- createdAt
- updatedAt
ตรวจสอบว่ามี
- status
- isActive
- deletedAt
- deletedBy
อยู่แล้วหรือไม่
ห้ามเดา
ต้องอ้างอิงจาก Schema จริง
---
## Permission
ตรวจสอบ
ระบบใช้
Permission
หรือ
Business Role
หรือ
ทั้งสอง
ให้ใช้ Pattern เดิมของระบบ
---
# Phase 1 — Feature Analysis
วิเคราะห์ Feature ปัจจุบัน
ระบุว่า
สิ่งใดทำได้แล้ว
สิ่งใดยังไม่มี
เช่น
✅ View
✅ Create
❌ Edit
❌ Delete
❌ Soft Delete
❌ Validation
❌ Audit
---
# Phase 2 — UI Enhancement
ปรับปรุงหน้า Organizers
## Organizer List
แต่ละ Organizer Card
ให้มี
- Name
- Slug
- Status
- Created Date
และ Action
```
Edit
Delete
```
ใช้ Component Pattern เดิมของระบบ
---
## Empty State
หากไม่มี Organizer
แสดง
```
ยังไม่มี Organizer
```
พร้อมปุ่ม
```
สร้าง Organizer
```
---
## Loading
รองรับ
Loading
Skeleton
Spinner
ตามมาตรฐานของระบบ
---
## Error State
รองรับ
Error
Retry
---
# Phase 3 — Create Organizer
ตรวจสอบ Flow เดิม
ปรับปรุง Validation
Required
- Organizer Name
Validation
- Required
- Trim
- Duplicate
- Max Length
- Invalid Character
Slug
สร้างตาม Pattern เดิมของระบบ
ห้าม Hardcode
---
# Phase 4 — Edit Organizer
เพิ่มความสามารถ
Edit Organizer
สามารถแก้ไข
- Organizer Name
หากระบบรองรับ
สามารถแก้ไข
- Description
- Status
ห้ามแก้ไข
- Organizer ID
ห้ามเปลี่ยนข้อมูลที่กระทบ Foreign Key
---
ใช้
Dialog
หรือ
Sheet
ตาม Pattern เดิมของระบบ
---
# Phase 5 — Soft Delete
ระบบต้องใช้
Soft Delete เท่านั้น
ห้ามใช้
```ts
delete()
```
เด็ดขาด
ต้องใช้
```ts
update();
```
พร้อมเปลี่ยนสถานะ
เช่น
```
isActive = false
```
หรือ
```
status = INACTIVE
```
หรือ Pattern เดิมของระบบ
หากไม่มี Field รองรับ
ให้เพิ่มตามมาตรฐานเดิมของ Project
เช่น
```prisma
isActive Boolean @default(true)
deletedAt DateTime?
deletedBy String?
```
---
# Soft Delete Rule
เมื่อ Delete
ข้อมูล
Users
Training
Permission
Audit
History
ต้องยังอยู่ครบ
Frontend
ต้องไม่แสดง Organizer
แต่ Database
ต้องยังมีข้อมูล
---
# Confirmation Dialog
ก่อน Delete
แสดง Dialog
```
ยืนยันการปิดใช้งาน Organizer
Organizer นี้จะไม่ถูกลบออกจากฐานข้อมูล
ข้อมูลทั้งหมดจะยังคงอยู่
แต่จะไม่สามารถใช้งานได้
ต้องการดำเนินการต่อหรือไม่
```
Buttons
```
Cancel
Delete
```
Delete
ใช้
Destructive Variant
---
# Phase 6 — Query Update
ทุก Query
ที่ดึง Organizer
ต้องกรองเฉพาะ
Active
เช่น
```ts
where;
status = ACTIVE;
```
หรือ
```
isActive = true
```
ตาม Pattern เดิม
รวมถึง
- Organizer Switcher
- Dropdown
- Select
- Search
- API
- Dashboard
---
# Phase 7 — Validation
ตรวจสอบ
Frontend
Backend
API
Validation
ทั้งหมด
เช่น
Required
Duplicate
Slug
Name Length
Invalid Character
Inactive Record
Not Found
---
# Phase 8 — Permission
ใช้
Permission First
หากระบบรองรับแล้ว
ห้ามใช้
```
isHRD()
businessRole
```
หาก Architecture ใหม่รองรับ Permission แล้ว
ใช้ Permission เดิมของระบบ
เช่น
```
organization:view
organization:create
organization:update
organization:delete
organization:manage
```
หรือ Permission ที่มีอยู่จริง
---
เฉพาะ
IT Admin
Super Admin
เท่านั้น
ที่สามารถ
Create
Edit
Delete
ได้
Role อื่น
ต้อง
- ไม่เห็นปุ่ม
- เรียก API ไม่ได้
- ได้ 403
---
# Phase 9 — Audit Log
หากระบบรองรับ Audit
ให้บันทึก
```
ORGANIZATION_CREATED
ORGANIZATION_UPDATED
ORGANIZATION_SOFT_DELETED
```
ข้อมูลที่ควรบันทึก
- Organization ID
- Name
- User
- Time
- Old Value
- New Value
ตาม Pattern เดิม
---
# Phase 10 — Regression Testing
ตรวจสอบ
## Create
- Success
- Validation
- Duplicate
---
## Edit
- Success
- Validation
---
## Delete
- Confirmation
- Soft Delete
- ไม่ลบจริง
---
## Query
Inactive
ต้องไม่แสดง
---
## Switcher
Inactive
ต้องไม่แสดง
---
## Permission
Employee
ห้ามเห็น
Staff
ห้ามเห็น
Manager
ห้ามเห็น
IT
ใช้งานได้
Super Admin
ใช้งานได้
---
## Database
ตรวจสอบ
Record
ยังอยู่
แต่
Inactive
---
## TypeScript
ไม่มี
Type Error
---
## ESLint
ไม่มี Error
---
## Console
ไม่มี
console.log
---
# Phase 11 — Code Quality
ตรวจสอบ
- Reuse Existing Components
- Reuse Existing Dialog
- Reuse Existing Form
- Reuse Existing Mutation
- Reuse Existing Query
- ไม่มี Duplicate Logic
- ไม่มี Dead Code
- ไม่มี Unused Import
- ไม่มี any ใหม่
- ไม่มี Hardcode
---
# Deliverables
แก้ไข
Source Code
เฉพาะส่วนที่จำเป็น
---
สร้างรายงาน
```
docs/organizers-module-enhancement-report.md
```
---
# Report Structure
```
# Organizers Module Enhancement Report
## Executive Summary
## Current Architecture
## Current Limitation
## Root Cause Analysis
## Feature Comparison
Before
After
## Files Modified
## Database Changes
## API Changes
## UI Changes
## Permission Changes
## Validation Changes
## Soft Delete Design
## Audit Log
## Testing Result
### Create
### Edit
### Delete
### Permission
### Regression
## Risks
## Recommendations
## Future Improvements
```
---
# Constraints
ห้าม
- Physical Delete
- Hardcode Permission
- Hardcode Role
- Hardcode Organization ID
- เปลี่ยน Business Logic
- เปลี่ยน Database Schema โดยไม่จำเป็น
- เพิ่ม Library ใหม่
- ใช้ any
- ลบข้อมูลจริง
- Refactor Module อื่นที่ไม่เกี่ยวข้อง
ต้อง
- ใช้ Shared Components
- ใช้ Shared Permission
- ใช้ Shared Validation
- ใช้ Shared API Pattern
- ใช้ Shared Service Pattern
- รักษา Type Safety
- รักษา Coding Standard
- รักษา Backward Compatibility
---
# Final Response
เมื่อดำเนินการเสร็จ ให้สรุปผลเป็นภาษาไทย โดยประกอบด้วย
1. Executive Summary
2. Root Cause ที่พบ
3. รายการ Feature ที่เพิ่ม
4. รายชื่อไฟล์ที่แก้ไข
5. การออกแบบ Soft Delete
6. Permission ที่ใช้
7. Validation ที่เพิ่ม
8. ผลการทดสอบ (Create / Edit / Delete / Permission / Regression)
9. ความเสี่ยงที่เหลือ (ถ้ามี)
10. Path ของรายงาน
```
docs/organizers-module-enhancement-report.md
```
พร้อมระบุหากพบ Technical Debt หรือข้อเสนอแนะในการพัฒนาต่อในอนาคต

View File

@@ -0,0 +1,763 @@
# Prompt: Refactor Authorization เป็น Permission Template + Permission-first Model
## Context
โปรเจกต์นี้คือระบบ Training Management System (TMS) ที่ปัจจุบันยังมีการตรวจสอบสิทธิ์จาก `systemRole`, `membership.role`, `businessRole` และ helper เช่น `isHRD()` / `isIT()`
ต้องการปรับระบบสิทธิ์ใหม่ให้เป็น **Permission-first Authorization Model** โดยตัดแนวคิดว่า “Role คือสิทธิ์” ออก และเปลี่ยนมาใช้ **Permission Template** เป็นชุดสิทธิ์ต้นแบบแทน
อ้างอิงจากแผนเดิมใน `role-permission-migration-plan.md` ที่ระบุว่าควรย้ายระบบจาก role/helper เดิมไปสู่ permission-based model และให้ API/server ใช้ permission เป็นตัวตัดสินสิทธิ์จริง
---
## Final Direction
ให้เปลี่ยนแนวคิดจากเดิม:
```text
User
-> Role
-> Permission
```
เป็น:
```text
Organization
-> Permission Template
-> Permissions
-> User Assignment
-> User Permission Override
-> Effective Permissions
```
หลักการสำคัญ:
- Permission คือ source of truth
- Permission Template เป็นเพียงชุดสิทธิ์ต้นแบบ
- User ได้รับสิทธิ์จาก Template
- User สามารถมี Permission Override รายบุคคลได้
- ระบบต้องรองรับหลายองค์กร
- UI ซ่อน/แสดงได้ตาม Permission
- API/server ต้องตรวจ Permission เสมอ
- ห้ามใช้ Role เป็นตัวตัดสินสิทธิ์หลักอีกต่อไป
---
## Required Work
### 1. Audit Existing Authorization
ตรวจสอบโค้ดทั้งหมดก่อนแก้ไข
ค้นหาการใช้งาน:
```ts
systemRole
membership.role
businessRole
isHRD()
isIT()
requireHRD()
requireIT()
requireUserManagementAccess()
role === ...
```
ตรวจสอบในส่วน:
- API routes
- Server actions
- Page guards
- Navigation
- Feature components
- Data helpers
- Auth/session helpers
- User management
- Middleware
ให้สรุปก่อนว่าไฟล์ใดยังใช้ role-based authorization อยู่
---
### 2. Create Permission Catalog
สร้าง permission catalog กลาง เช่น:
```text
src/lib/auth/permissions.ts
```
ต้องมี permission constants และ type-safe permission list
ตัวอย่างกลุ่ม permission:
```ts
organization:manage
organization:switch
permission_template:read
permission_template:create
permission_template:update
permission_template:clone
permission_template:delete
permission_template:assign
user_permission:read
user_permission:update
user_permission:override
user_permission:remove_override
users:read
users:create
users:update
users:delete
users:manage
employee_directory:read
employee_directory:write
employee_import:run
employee_master_review:approve
training_record:self_read
training_record:self_write
training_record:read_all
training_record:write_all
training_record:submit
training_record:review
training_record:approve
training_record:reject
training_record:delete_draft
training_record:manage_attachments
announcement:read_public
announcement:read_all
announcement:create
announcement:edit_draft
announcement:delete_draft
announcement:submit
announcement:approve
announcement:reject
announcement:publish
announcement:schedule
announcement:unpublish
announcement:archive
announcement:restore
announcement:revision
announcement:preview
announcement:view_history
online_lesson:read_public
online_lesson:read_all
online_lesson:create
online_lesson:edit_draft
online_lesson:delete_draft
online_lesson:submit
online_lesson:approve
online_lesson:reject
online_lesson:publish
online_lesson:schedule
online_lesson:unpublish
online_lesson:archive
online_lesson:restore
online_lesson:revision
online_lesson:preview
online_lesson:view_history
reports:self_read
reports:organization_read
reports:export
reports:export_excel
reports:export_pdf
audit_logs:read
audit_logs:export
notifications:read
notifications:manage
```
---
### 3. Add Permission Template Data Model
ตรวจสอบ schema เดิมก่อนแก้ไข
ให้เพิ่มหรือปรับ database model ให้รองรับ:
```text
organizations
permission_templates
permission_template_permissions
user_permission_template_assignments
user_permission_overrides
permission_audit_logs
```
โครงสร้างต้องรองรับ:
- หลายองค์กร
- แต่ละองค์กรมี Permission Template ของตัวเอง
- Template สร้างได้
- Template แก้ไขได้
- Template Clone ได้
- Template ลบได้
- Template ที่ถูกใช้งานอยู่ต้องห้ามลบ หรือให้ soft delete เท่านั้น
- User 1 คนสามารถถูก assign template ได้อย่างน้อย 1 template ต่อ organization
- User สามารถมี permission override รายบุคคลได้
- Override ต้องรองรับทั้ง `allow` และ `deny`
- Override สามารถมี optional expiration date ได้ ถ้าออกแบบได้โดยไม่กระทบระบบมาก
- ทุกการเปลี่ยนแปลงต้องมี audit log
---
### 4. Default Permission Templates
สร้าง default templates เป็น seed data ไม่ใช่ hard-code role
ต้องมี template เริ่มต้นอย่างน้อย:
```text
Employee
HRD Staff
HRD Manager
Org Admin
IT Admin
Super Admin
```
ตัวอย่างสิทธิ์:
#### Employee
```text
notifications:read
announcement:read_public
online_lesson:read_public
training_record:self_read
training_record:self_write
training_record:submit
reports:self_read
```
#### HRD Staff
ได้ Employee permissions และเพิ่ม:
```text
employee_directory:read
employee_directory:write
courses:read
courses:write
training_matrix:read
training_matrix:write
training_record:read_all
training_record:write_all
announcement:read_all
announcement:create
announcement:edit_draft
announcement:delete_draft
announcement:submit
announcement:preview
online_lesson:read_all
online_lesson:create
online_lesson:edit_draft
online_lesson:delete_draft
online_lesson:submit
online_lesson:preview
```
ห้ามมี:
```text
announcement:approve
announcement:publish
announcement:schedule
announcement:archive
online_lesson:approve
online_lesson:publish
online_lesson:schedule
online_lesson:archive
```
#### HRD Manager
ได้ HRD Staff permissions และเพิ่ม:
```text
training_record:review
training_record:approve
training_record:reject
announcement:approve
announcement:reject
announcement:publish
announcement:schedule
announcement:unpublish
announcement:archive
announcement:restore
announcement:revision
announcement:view_history
online_lesson:approve
online_lesson:reject
online_lesson:publish
online_lesson:schedule
online_lesson:unpublish
online_lesson:archive
online_lesson:restore
online_lesson:revision
online_lesson:view_history
reports:organization_read
reports:export
reports:export_excel
reports:export_pdf
notifications:manage
```
#### Org Admin
```text
organization:manage
organization:switch
users:read
users:create
users:update
users:delete
users:manage
employee_directory:read
employee_directory:write
permission_template:read
permission_template:assign
user_permission:read
reports:organization_read
audit_logs:read
```
#### IT Admin / Super Admin
```text
permission_template:read
permission_template:create
permission_template:update
permission_template:clone
permission_template:delete
permission_template:assign
user_permission:read
user_permission:update
user_permission:override
user_permission:remove_override
users:manage
audit_logs:read
audit_logs:export
organization:manage
organization:switch
```
---
### 5. Permission Helper
สร้าง helper กลาง เช่น:
```text
src/lib/auth/authorization.ts
```
ต้องมี function:
```ts
getEffectivePermissions(userId, organizationId)
hasPermission(user, permission, context?)
hasAnyPermission(user, permissions, context?)
hasAllPermissions(user, permissions, context?)
requirePermission(user, permission, context?)
requireAnyPermission(user, permissions, context?)
requireAllPermissions(user, permissions, context?)
```
Effective permissions ต้องคำนวณจาก:
```text
Template permissions
+ user allow overrides
- user deny overrides
- expired overrides
```
เงื่อนไข:
- `deny` ต้องมี priority สูงกว่า `allow`
- expired permission ต้องไม่ถูกนำมาใช้
- ต้อง scope ตาม organization
- ต้อง cache ได้ถ้าเหมาะสม
- ต้อง clear cache เมื่อมีการแก้ template หรือ override
---
### 6. Session / Auth Update
ปรับ session ให้รองรับ permission-first model
Session ควรมี:
```ts
userId;
organizationId;
organizationIds;
activeOrganizationId;
permissionTemplateIds;
effectivePermissions;
```
คง field เดิม เช่น `businessRole`, `systemRole`, `membership.role` ไว้ชั่วคราวเพื่อ compatibility เท่านั้น
ห้ามใช้ field เดิมเป็น source of truth ใหม่
---
### 7. Permission Template Management UI
เพิ่มหน้าจัดการ Permission Template ใน Admin
ต้องรองรับ:
- ดูรายการ Template
- สร้าง Template
- แก้ไข Template
- Clone Template
- ลบ Template
- Soft delete Template ที่เคยถูกใช้งาน
- ดู Permission ภายใน Template
- ค้นหา Permission
- Group Permission ตาม module
- แสดงจำนวนผู้ใช้งาน Template
- บันทึกเหตุผลเมื่อแก้ไข
- เก็บ audit log ทุกครั้ง
---
### 8. User Permission Assignment UI
เพิ่มหรือปรับหน้า User Management ให้รองรับ:
- เลือก Organization
- เลือก User
- Assign Permission Template ให้ User
- เปลี่ยน Template
- แสดง Effective Permissions
- เพิ่ม Permission เฉพาะราย
- Deny Permission เฉพาะราย
- Remove Override
- กำหนดวันหมดอายุ Override ถ้ารองรับ
- บันทึกเหตุผล
- แสดงประวัติการเปลี่ยนสิทธิ์
Effective Permission Viewer ต้องแสดง:
```text
Template permissions
Allow overrides
Deny overrides
Expired overrides
Final effective permissions
```
---
### 9. Multi-Organization Support
ระบบต้องรองรับหลายองค์กร
หลักการ:
- Permission Template ต้องผูกกับ organization
- User assignment ต้องผูกกับ organization
- User override ต้องผูกกับ organization
- Effective permissions ต้องคำนวณตาม active organization
- การ query/write ข้อมูลต้องมี organization context
- Super Admin / IT Admin อาจ switch organization ได้ตาม permission
ต้องตรวจสอบ:
- organization switcher
- membership
- session
- API scope
- audit logs
- user management
- reports
---
### 10. Replace Server-Side Authorization
เปลี่ยน API/server guard จาก role-based เป็น permission-based
ตัวอย่าง:
เดิม:
```ts
if (!isHRD(user)) {
return forbidden();
}
```
ใหม่:
```ts
await requirePermission(user, "announcement:create", {
organizationId,
});
```
ต้องปรับอย่างน้อย:
- Announcements API
- Online Lessons API
- Training Records API
- Users API
- Employee Directory API
- Employee Import API
- Courses API
- Training Policy API
- Training Matrix API
- Reports API
- Audit Logs API
- Notifications API
สำคัญ:
Employee-facing API ต้อง enforce server-side scope เสมอ
```text
announcement / online lesson:
- status = published
- is_current = true
training records:
- self-scope เท่านั้น เว้นแต่มี training_record:read_all
```
---
### 11. Replace Page Guards And Navigation
ปรับ page guard และ navigation ให้ใช้ permission
ตัวอย่าง:
```ts
canViewUsers = hasPermission(user, "users:read");
canViewPendingReview = hasAnyPermission(user, [
"training_record:review",
"announcement:approve",
"online_lesson:approve",
]);
```
ห้ามใช้:
```ts
businessRole === "HRD";
isHRD();
isIT();
```
เป็นตัวตัดสินหลักอีกต่อไป
---
### 12. Feature UI Permission Visibility
ปรับ component ให้รับ permission context หรือ effective permissions
ตัวอย่าง:
- ปุ่ม Create แสดงเมื่อมี `announcement:create`
- ปุ่ม Submit แสดงเมื่อมี `announcement:submit`
- ปุ่ม Approve แสดงเมื่อมี `announcement:approve`
- ปุ่ม Publish แสดงเมื่อมี `announcement:publish`
- ปุ่ม Schedule แสดงเมื่อมี `announcement:schedule`
- ปุ่ม Archive แสดงเมื่อมี `announcement:archive`
แต่ต้องจำไว้ว่า UI visibility ไม่ใช่ security
Server/API ต้องตรวจ permission ซ้ำเสมอ
---
### 13. Audit Log
ทุก action ต่อไปนี้ต้องมี audit log:
- Create template
- Update template
- Clone template
- Delete template
- Assign template to user
- Change user template
- Add user permission override
- Deny user permission
- Remove override
- Organization switch ที่สำคัญ
- Permission-based workflow actions เช่น approve, publish, archive
Audit payload ควรเก็บ:
```text
actor_user_id
organization_id
target_user_id
target_template_id
action
before
after
reason
timestamp
```
---
### 14. Backward Compatibility
ห้ามลบ logic เดิมทันที
ให้ทำ compatibility layer เช่น:
```ts
mapLegacyRoleToPermissionTemplate();
resolveEffectivePermissionsFromLegacyRole();
```
เป้าหมายคือ:
- ระบบเดิมไม่พัง
- migration ทำเป็น phase ได้
- ค่อย ๆ ลดการใช้ `businessRole`, `systemRole`, `membership.role`
- ห้ามเขียน feature ใหม่โดยใช้ role-based authorization
---
### 15. Testing Checklist
ต้องทดสอบอย่างน้อย:
#### Employee
- เห็นเฉพาะข้อมูลตัวเอง
- เห็นเฉพาะ published content
- เข้า draft ผ่าน URL ตรงไม่ได้
- approve ไม่ได้
- publish ไม่ได้
#### HRD Staff Template
- สร้าง draft ได้
- แก้ draft ได้
- submit ได้
- preview ได้
- approve ไม่ได้
- publish ไม่ได้
- schedule ไม่ได้
- archive ไม่ได้
#### HRD Manager Template
- approve ได้
- reject ได้
- publish ได้
- schedule ได้
- archive ได้
- revision ได้
- export report ได้
#### IT Admin
- สร้าง template ได้
- แก้ template ได้
- clone template ได้
- ลบ template ได้ตามเงื่อนไข
- assign template ให้ user ได้
- override permission รายบุคคลได้
- ดู effective permissions ได้
- audit log ถูกบันทึกครบ
#### Multi-Organization
- User คนเดียวมีสิทธิ์ต่างกันในแต่ละ organization ได้
- active organization เปลี่ยนแล้ว permission เปลี่ยนตาม
- API ไม่ดึงข้อมูลข้าม organization
- audit log ระบุ organization ถูกต้อง
---
### 16. Documentation
หลังแก้ไขเสร็จ ให้สร้างเอกสารไว้ที่:
```text
docs/permission-template-authorization-implementation.md
```
เอกสารต้องมี:
- สรุปสิ่งที่แก้ไข
- โครงสร้าง Permission-first model
- Permission catalog
- Default permission templates
- Database/schema ที่เพิ่มหรือแก้ไข
- วิธีคำนวณ effective permissions
- วิธี assign template ให้ user
- วิธี override permission รายบุคคล
- วิธีรองรับหลายองค์กร
- API/page ที่เปลี่ยนแล้ว
- compatibility layer ที่ยังเหลือ
- test checklist
- known issues
- next steps
---
## Acceptance Criteria
งานนี้ถือว่าเสร็จเมื่อ:
- Permission เป็น source of truth
- Role ไม่ใช่ตัวกำหนดสิทธิ์หลักอีกต่อไป
- มี permission catalog กลาง
- มี Permission Template ที่จัดการผ่าน Admin ได้
- สร้าง/แก้ไข/Clone/ลบ Template ได้
- Assign Template ให้ User ได้
- Override Permission รายบุคคลได้
- รองรับหลายองค์กร
- Effective permissions คำนวณถูกต้อง
- API/server ใช้ `requirePermission()` เป็นหลัก
- Navigation/page guard ใช้ permission
- Employee เห็นเฉพาะข้อมูลที่ควรเห็น
- HRD Staff publish/approve ไม่ได้
- HRD Manager publish/approve ได้
- IT Admin จัดการ Template และ Permission ได้
- ทุกการเปลี่ยนสิทธิ์มี audit log
- มีเอกสารสรุปใน `docs`
- ระบบเดิมไม่พังระหว่าง migration
---
## Important Notes
- ห้ามใช้ Role เป็น source of truth
- ห้าม hard-code role ใน feature ใหม่
- ห้ามตรวจสิทธิ์เฉพาะ UI
- Server/API ต้องตรวจ permission เสมอ
- Permission Template คือชุดสิทธิ์ต้นแบบ ไม่ใช่ตัวตัดสินสิทธิ์
- User Permission Override ต้องมีผลต่อ effective permissions
- Multi-Organization ต้องไม่ทำให้ข้อมูลข้ามองค์กรรั่ว
- ต้อง reuse pattern เดิมของโปรเจกต์ก่อนสร้างของใหม่
- ต้องทำ migration แบบปลอดภัยและมี compatibility layer

View File

@@ -0,0 +1,679 @@
# Prompt.md — Permission Matrix UX Improvement & Permission Catalog Description
## Objective
ปรับปรุงหน้า **Permission Matrix** ให้ผู้ใช้งานสามารถเข้าใจ Permission แต่ละรายการได้ง่ายขึ้น โดยเพิ่มคำอธิบายภาษาไทย (Description) ให้กับทุก Permission
รอบนี้เป็นการปรับปรุงเฉพาะ **UI/UX และ Permission Catalog**
**ห้ามเปลี่ยน Business Logic**
**ห้ามเปลี่ยน Permission Code**
**ห้ามเปลี่ยน Authorization**
**ห้ามเปลี่ยน Database Schema**
---
# Required Reading
ก่อนเริ่ม Coding ให้อ่าน
- docs/PROJECT_ARCHITECTURE.md
- docs/AI_DEVELOPMENT_GUIDE.md
- AGENTS.md
และตรวจสอบ implementation ของ
```
src/features/permission-management
```
รวมถึง Permission Catalog ที่ใช้งานอยู่
ห้ามสร้าง Catalog ใหม่
ห้ามสร้างข้อมูลซ้ำ
---
# Objective Detail
Permission Matrix ต้องสามารถอธิบายว่า
Permission แต่ละรายการ
"ใช้ทำอะไร"
โดยใช้ข้อความภาษาไทยสั้น ๆ
เพื่อให้
- Super Admin
- HRD Manager
- System Administrator
- IT Administrator
สามารถเข้าใจได้ทันที
---
# Current UI
ปัจจุบัน
```
Manage
organization:manage
```
ซึ่งผู้ใช้งานทั่วไปไม่ทราบว่า
Manage
คืออะไร
---
# Expected UI
ปรับเป็น
```
Manage
จัดการข้อมูลองค์กร เช่น สร้าง แก้ไข ตั้งค่า เปิดหรือปิดการใช้งานองค์กร
organization:manage
[Action]
```
---
# UI Layout
ภายในการ์ดแต่ละ Permission
ให้เรียงลำดับดังนี้
1.
Permission Name
เช่น
```
Manage
```
2.
Description
เช่น
```
จัดการข้อมูลองค์กร เช่น สร้าง แก้ไข ตั้งค่า เปิดหรือปิดการใช้งานองค์กร
```
3.
Permission Code
```
organization:manage
```
4.
Action Badge
```
Action
```
---
# Typography
## Permission Name
- font-semibold
- text-base หรือ text-lg
---
## Description
- text-sm
- text-muted-foreground
- รองรับหลายบรรทัด
- line-clamp ได้หากจำเป็น
---
## Permission Code
- font-mono
- text-xs
- text-muted-foreground
---
## Badge
ใช้ Component เดิมของระบบ
---
# Permission Catalog Enhancement
ปรับปรุง Permission Catalog
ทุก Permission ต้องมีข้อมูลดังนี้
```ts
export interface PermissionDefinition {
module: string;
action: string;
code: string;
name: string;
description: string;
descriptionEn?: string;
}
```
โดย
description
เป็นคำอธิบายภาษาไทย
descriptionEn
สงวนไว้สำหรับอนาคต
---
# Data Structure
ตัวอย่าง
```ts
{
module: "Organizations",
action: "Manage",
code: "organization:manage",
name: "Manage",
description:
"จัดการข้อมูลองค์กร เช่น สร้าง แก้ไข ตั้งค่า เปิดหรือปิดการใช้งานองค์กร"
}
```
อีกตัวอย่าง
```ts
{
module: "Announcements",
action: "Publish",
code: "announcement:publish",
name: "Publish",
description:
"เผยแพร่ประกาศให้ผู้ใช้งานสามารถมองเห็นได้"
}
```
---
# Component Rules
Component
ห้าม Hardcode
ข้อความภาษาไทย
ต้องอ่านจาก
```
permission.description
```
เท่านั้น
เช่น
```tsx
<h3>{permission.name}</h3>
<p>{permission.description}</p>
<code>{permission.code}</code>
```
เพื่อรองรับ
- Multi-language
- Tooltip
- API Documentation
- Permission Detail
- Future UI
---
# Description Guidelines
คำอธิบายต้อง
- เป็นภาษาไทย
- อ่านเข้าใจง่าย
- ไม่ยาวเกินไป
- อธิบายการใช้งานจริง
- ไม่อธิบายชื่อ Permission ซ้ำ
ตัวอย่างที่ดี
```
สามารถสร้างประกาศใหม่ได้
```
ไม่ใช่
```
Permission สำหรับ Create Announcement
```
---
# Permission Description
## Organizations
### Manage
จัดการข้อมูลองค์กร เช่น สร้าง แก้ไข ตั้งค่า เปิดหรือปิดการใช้งานองค์กร
---
### Switch
สลับองค์กรที่กำลังใช้งาน สำหรับผู้ใช้ที่มีสิทธิ์หลายองค์กร
---
## Permission Templates
### Read
ดูรายการ Permission Template ทั้งหมด
---
### Create
สร้าง Permission Template ใหม่
---
### Update
แก้ไข Permission Template
---
### Clone
คัดลอก Permission Template เพื่อสร้างชุดสิทธิ์ใหม่
---
### Delete
ปิดการใช้งานหรือ Soft Delete Permission Template
---
### Assign
กำหนด Permission Template ให้ผู้ใช้งาน
---
## User Permissions
### Read
ดูสิทธิ์ของผู้ใช้งาน
---
### Update
แก้ไขชุดสิทธิ์ของผู้ใช้งาน
---
### Override
เพิ่มหรือลดสิทธิ์เฉพาะบุคคล โดยไม่กระทบ Template หลัก
---
## Dashboard
### View
ดู Dashboard และข้อมูลสรุปของระบบ
---
## Announcements
### View
ดูประกาศ
### Create
สร้างประกาศใหม่
### Update
แก้ไขประกาศ
### Delete
ยกเลิกเผยแพร่
### Approve
อนุมัติประกาศก่อนเผยแพร่
### Publish
เผยแพร่ประกาศให้ผู้ใช้งานเห็น
### Export
ส่งออกข้อมูลประกาศ
---
## Online Lessons
### View
ดูบทเรียนออนไลน์
### Create
สร้างบทเรียนออนไลน์
### Update
แก้ไขบทเรียนออนไลน์
### Delete
ลบบทเรียนออนไลน์
### Approve
อนุมัติบทเรียนออนไลน์
### Publish
เผยแพร่บทเรียนออนไลน์
---
## Training Records
### View
ดูประวัติการอบรม
### Create
สร้างประวัติการอบรม
### Update
แก้ไขประวัติการอบรม
### Delete
ลบประวัติการอบรม
### Approve
อนุมัติประวัติการอบรม
### Export
ส่งออกข้อมูลประวัติการอบรม
---
## Reports
### View
ดูรายงาน
### Export
ส่งออกรายงานเป็น Excel หรือ PDF
---
## Audit Logs
### View
ดูประวัติการใช้งานระบบ
### Export
ส่งออกประวัติการใช้งานระบบ
---
## Settings
### View
ดูหน้าการตั้งค่าระบบ
### Update
แก้ไขการตั้งค่าระบบ
---
## Permission Management
### View
ดูหน้าจัดการ Permission
### Create
สร้าง Permission Template
### Update
แก้ไข Permission Template
### Delete
ลบหรือปิดการใช้งาน Permission Template
### Assign
กำหนด Permission ให้ผู้ใช้งาน
### Override
เพิ่มหรือลดสิทธิ์เฉพาะบุคคล
### Manage
จัดการระบบ Permission ทั้งหมด
---
# Reuse
ห้ามสร้าง
Permission Catalog
ขึ้นใหม่
ให้เพิ่มเฉพาะ
```
description
```
และ
```
descriptionEn
```
เข้าไปใน Catalog เดิม
---
# Future Ready
Component
ต้องรองรับ
```
permission.description
permission.descriptionEn
```
โดยไม่ต้องแก้ไขอีกในอนาคต
---
# Do Not
ห้าม
- เปลี่ยน Permission Code
- เปลี่ยน Module
- เปลี่ยน Action
- เปลี่ยน Permission Group
- เปลี่ยน Authorization
- เปลี่ยน API
- เปลี่ยน Database
- เปลี่ยน Business Logic
รอบนี้เป็น
UX Improvement
เท่านั้น
---
# Deliverables
เมื่อดำเนินการเสร็จ
ให้สร้างรายงาน
```
docs/permission-matrix-ui-improvement-report.md
```
ประกอบด้วย
## 1. Summary
สิ่งที่ปรับปรุง
---
## 2. Files Modified
ไฟล์ที่แก้ไขทั้งหมด
---
## 3. UI Changes
รายละเอียดการเปลี่ยนแปลงของ Permission Matrix
---
## 4. Permission Catalog Changes
สรุปการเพิ่ม
- description
- descriptionEn
---
## 5. Permission Coverage
รายงานจำนวน Permission ทั้งหมด
พร้อมยืนยันว่า
ทุก Permission มี
- module
- action
- code
- name
- description
ครบถ้วน
---
## 6. Compatibility
ยืนยันว่า
- Permission Code ไม่เปลี่ยน
- Business Logic ไม่เปลี่ยน
- Authorization ไม่เปลี่ยน
- API ไม่เปลี่ยน
- Database ไม่เปลี่ยน
---
## 7. Verification
ตรวจสอบ
- TypeScript ผ่าน
- Lint ผ่าน
- Permission Matrix แสดง Description ถูกต้อง
- Permission Code ยังคงเดิม
- ทุก Permission มี Description ครบถ้วน

View File

@@ -0,0 +1,465 @@
# Prompt.md — Role & Permission Management (Coding Phase 1)
## Objective
เริ่มพัฒนาระบบ **Role & Permission Management** ตามแผนใน
`docs/role-permission-management-plan.md`
โดยยึดตามเอกสารนี้เป็นหลัก และ **ห้ามเพิ่ม Requirement ใหม่เอง**
---
# Required Reading
ก่อนเริ่ม Coding ต้องอ่านเอกสารต่อไปนี้
- `docs/PROJECT_ARCHITECTURE.md`
- `docs/AI_DEVELOPMENT_GUIDE.md`
- `AGENTS.md`
- `docs/role-permission-management-plan.md`
จากนั้นตรวจสอบโครงสร้างของโปรเจกต์จริงก่อนลงมือแก้ไข
ห้ามเดาโครงสร้าง
ต้อง Reuse Shared Components และ Shared Patterns ที่มีอยู่
---
# Coding Scope
ใน Phase นี้
ให้เริ่มสร้างโครงสร้างของ Feature Role & Permission Management
โดย **ยังไม่ต้องย้าย Feature อื่นมาใช้ Permission-first**
ยังไม่ต้องแก้ไขระบบ Authorization ของระบบเดิม
ยังไม่ต้องลบ Compatibility Mode
---
# Features to Implement
## 1. Permission Management Feature Module
สร้าง Feature ใหม่
```text
src/features/permission-management/
```
โดยจัดโครงสร้างให้สอดคล้องกับ Feature อื่นของโปรเจกต์
ตัวอย่าง
```text
api/
components/
schemas/
server/
hooks/
types/
```
ต้อง Reuse pattern เดิมของโปรเจกต์
---
## 2. Permission Template Management
สร้างหน้าจอ
```text
/dashboard/permissions/templates
```
รองรับ
- แสดงรายการ Permission Template
- Search
- Pagination
- Sorting
- Status Badge
- Assigned User Count
- Create
- Edit
- Clone
- Activate
- Deactivate
- Soft Delete
ใช้
- DataTable
- Sheet
- Dialog
- AlertDialog
จาก Shared Components
---
## 3. Permission Matrix
สร้างหน้า
```text
/dashboard/permissions/matrix
```
รองรับ
Grouped Permission
เช่น
Dashboard
Training Records
Announcements
Online Lessons
Employees
Reports
Settings
Permission Management
แต่ละ Module
มี Action
- View
- Create
- Edit
- Delete
- Approve
- Publish
- Export
- Manage
ใช้รูปแบบ Checklist
---
## 4. User Permission Assignment
สร้างหน้า
```text
/dashboard/permissions/users
```
รองรับ
- Search User
- แสดงข้อมูลพนักงาน
- Assign Template (1 Template ต่อ User)
- Extra Permission
- Deny Permission
- Effective Permission Preview
- Save Assignment
ต้องใช้ Transaction ฝั่ง Server
---
## 5. Permission Audit Logs
สร้างหน้า
```text
/dashboard/permissions/audit-logs
```
Reuse
Audit Log Listing เดิม
เพิ่มเฉพาะ Data Source
และ Filter
---
# API
สร้าง Route Handlers ตามแผน
Permission Templates
```text
GET
POST
PATCH
DELETE
Clone
Activate
Deactivate
```
Permission Assignment
```text
GET
PUT
POST Override
PATCH Override
DELETE Override
```
Permission Catalog
```text
GET
```
Permission Audit Logs
```text
GET
```
---
# Validation
ใช้
Zod
ทุก Request
ทุก Mutation
ทุก Form
ห้ามใช้ Manual Validation
---
# UI
ใช้ Shared UI เดิมทั้งหมด
เช่น
- Button
- Badge
- Dialog
- Sheet
- AlertDialog
- TanStack Table
- TanStack Query
- TanStack Form
ห้ามสร้าง UI Component ซ้ำ
---
# Authorization
หน้าทั้งหมด
API ทุกตัว
ต้องใช้
Super Admin เท่านั้น
ห้ามใช้
HRD
IT
Manager
Employee
เข้าถึงได้
---
# Database
ใช้ Schema ปัจจุบัน
ห้ามแก้ Migration
ห้ามสร้าง Migration ใหม่
หากพบจุดที่ Schema ยังไม่รองรับ
ให้เขียน
TODO
พร้อม Comment
และสรุปไว้ใน Report
---
# Compatibility
ต้องไม่ทำให้
Business Role
เสียหาย
ต้องไม่ลบ
- isHRD()
- isIT()
- businessRole
ต้องไม่เปลี่ยน
Navigation
ของระบบเดิม
ยกเว้นเพิ่มเมนูใหม่ของ Permission Management
---
# Navigation
เพิ่มเมนูใหม่
```text
Permission Management
```
ภายในมี
- Permission Templates
- Permission Matrix
- User Permissions
- Permission Audit Logs
เมนูนี้
Super Admin เท่านั้นที่มองเห็น
---
# Coding Rules
- Reuse Existing Pattern
- TypeScript Strict
- No Any
- No Dead Code
- No Duplicate Logic
- Reuse Query Pattern
- Reuse Mutation Pattern
- Reuse DataTable Pattern
- Reuse Sheet Pattern
- Reuse Form Pattern
---
# Files Expected
สร้างตามโครงสร้างที่ระบุใน
`docs/role-permission-management-plan.md`
หากมีไฟล์ใดต้องเปลี่ยน
ให้แก้เฉพาะเท่าที่จำเป็น
---
# Deliverables
เมื่อ Coding เสร็จแล้ว
ให้สร้าง Report
```text
docs/role-permission-management-implementation-report.md
```
ภายในประกอบด้วย
## 1. Summary
สิ่งที่พัฒนาแล้ว
---
## 2. Files Created
ไฟล์ใหม่ทั้งหมด
---
## 3. Files Modified
ไฟล์ที่แก้ไข
---
## 4. API Implemented
Route ทั้งหมด
---
## 5. UI Pages
หน้าที่สร้าง
---
## 6. Remaining TODO
สิ่งที่ยังไม่ได้ทำ
---
## 7. Known Limitations
ข้อจำกัด
---
## 8. Compatibility Status
สิ่งที่ยังใช้ Compatibility Mode
---
## Important Rules
- ห้ามแก้ Requirement
- ห้ามเพิ่ม Feature ใหม่
- ห้าม Refactor ส่วนอื่นของระบบ
- ห้ามลบระบบเดิม
- ต้องทำเฉพาะตามขอบเขตของ `docs/role-permission-management-plan.md`
- หากพบปัญหา ให้ใช้ TODO และบันทึกไว้ใน Report แทนการเปลี่ยน Architecture เอง

View File

@@ -0,0 +1,652 @@
# Prompt: Permission Template Type Validation Audit & Fix
## Objective
ดำเนินการตรวจสอบ วิเคราะห์ และแก้ไขปัญหาในฟอร์มที่เกี่ยวข้องกับ **Permission Template** ซึ่งปัจจุบันพบ Validation Error ดังนี้
```text
Invalid input: expected number, received string
```
เป้าหมายคือให้ระบบสามารถเลือก Permission Template ได้อย่างถูกต้อง โดยไม่มี Type Mismatch ระหว่าง Frontend, Validation Schema และ Backend พร้อมทั้งสร้างเอกสารสรุปผลการดำเนินงานไว้ในโฟลเดอร์ `docs/`
---
# Background
ระบบกำลังพัฒนาโดยใช้แนวคิด **Permission Template First Architecture**
Permission Template เป็นตัวกำหนดสิทธิ์หลักของผู้ใช้งาน
เมื่อผู้ใช้เลือก Permission Template จาก Dropdown ไม่ควรเกิด Validation Error และข้อมูลต้องสามารถบันทึกได้ทั้ง Create และ Edit
---
# Scope
ตรวจสอบทุกส่วนที่เกี่ยวข้องกับ Permission Template ได้แก่
- Form Component
- Select Component
- TanStack Form
- React Hook Form (ถ้ามี)
- Zod Schema
- DTO
- API Request
- API Route
- Service Layer
- Repository
- Prisma
- Database Mapping
- TypeScript Types
- Default Values
- Edit Form
- Create Form
รวมถึงไฟล์ Shared ที่เกี่ยวข้อง
---
# Phase 1 — Architecture Audit
ก่อนแก้ไข ต้องตรวจสอบระบบทั้งหมดก่อน
## ตรวจสอบ
### Frontend
- Permission Template Select
- Form State
- Default Values
- Initial Values
- Edit Values
- Submit Handler
### Validation
ตรวจสอบ
- zod schema
- validator
- preprocess
- transform
### Backend
ตรวจสอบ
- Route Handler
- Server Action
- Service
- Repository
- Prisma
### Database
ตรวจสอบว่า
Permission Template ใช้
```
INT
```
หรือ
```
UUID
```
หรือ
```
String
```
ห้ามเดา
ต้องอ้างอิงจากโค้ดจริง
---
# Phase 2 — Root Cause Analysis
ค้นหาสาเหตุที่แท้จริง
เช่น
## Case A
Select ส่ง
```ts
"1";
```
แต่ schema
```ts
z.number();
```
---
## Case B
Select ส่ง
```ts
"employee";
```
แต่ database ต้องการ
```ts
1;
```
---
## Case C
Default Value
```ts
permissionTemplateId: "";
```
แต่ schema
```ts
z.number();
```
---
## Case D
Edit Form
โหลดข้อมูลมาเป็น
```ts
number;
```
แต่ Select ต้องการ
```ts
string;
```
---
## Case E
API รับ
```ts
string;
```
แต่ backend schema
```ts
number;
```
---
ต้องระบุให้ชัดเจนว่า
Root Cause ที่แท้จริงคืออะไร
พร้อมอธิบายเหตุผล
---
# Phase 3 — Fix Frontend
## ตรวจสอบ Select
ตัวอย่าง
```tsx
<Select
value={...}
onValueChange={...}
>
```
ต้องตรวจสอบว่า
value
และ
onValueChange
มี Type ที่ถูกต้อง
หาก Database ใช้ numeric id
ให้แปลงค่าอย่างเหมาะสม
เช่น
```tsx
value={
field.state.value != null
? String(field.state.value)
: undefined
}
```
และ
```tsx
onValueChange={(value) => {
if (!value) {
field.handleChange(undefined)
return
}
field.handleChange(Number(value))
}}
```
ห้ามใช้
```ts
Number("");
```
จนกลายเป็น
```
0
```
โดยไม่ได้ตั้งใจ
---
# Phase 4 — Fix Default Values
ตรวจสอบ
Default Values
ทุกจุด
เช่น
ผิด
```ts
permissionTemplateId: "";
```
หรือ
```ts
permissionTemplateId: "1";
```
ให้ปรับให้สอดคล้องกับ schema
เช่น
```ts
undefined;
```
หรือ
```ts
null;
```
หรือ
```ts
number;
```
ตามมาตรฐานของระบบ
---
# Phase 5 — Fix Validation
ตรวจสอบ Zod Schema
หากต้องการ Number
ให้รองรับค่าจาก Select อย่างถูกต้อง
ตัวอย่าง
```ts
z.preprocess(...)
```
หรือ
ให้ Form State เป็น Number ตั้งแต่ต้น
เลือกวิธีที่สอดคล้องกับ Architecture ของโปรเจกต์
ห้ามเพิ่ม Logic ซ้ำซ้อน
---
# Phase 6 — Fix API
ตรวจสอบ Request Payload
ก่อนส่ง API
ต้องเป็น
```ts
number;
```
ไม่ใช่
```ts
string;
```
ตรวจสอบ
- mutation
- fetch
- api client
ทุกจุด
---
# Phase 7 — Fix Backend
ตรวจสอบ
- Route Handler
- Service
- DTO
- Validation
ต้องรับ Type ตรงกับ Frontend
ห้ามเกิด
```
string -> number
```
Mismatch
---
# Phase 8 — UX Improvement
ปัจจุบัน
ผู้ใช้เห็น
```text
Invalid input: expected number, received string
```
ซึ่งเป็น Technical Error
ให้ปรับเป็นข้อความที่ผู้ใช้เข้าใจได้
เช่น
```
กรุณาเลือก Permission Template
```
หรือ
```
กรุณาเลือกเทมเพลตสิทธิ์การใช้งาน
```
โดยยังคงเก็บ Technical Error ไว้สำหรับ Developer
---
# Phase 9 — Regression Testing
ตรวจสอบ
## Create
- เปิดหน้า
- ไม่มี Error
- เลือก Permission Template
- Submit ได้
---
## Edit
- โหลดค่าเดิมได้
- แสดงค่าใน Select ถูกต้อง
- เปลี่ยนค่าได้
- Save ได้
---
## Validation
- ไม่เลือก Template
- แสดงข้อความภาษาไทย
---
## API
ตรวจสอบ Payload
ต้องเป็น
```ts
permissionTemplateId: number;
```
---
## Database
ตรวจสอบข้อมูลที่บันทึก
ต้องตรงกับ Template ที่เลือก
---
## TypeScript
ต้องไม่มี
- type error
- eslint error
- any ใหม่
---
# Code Quality
หลังแก้ไขแล้ว
ตรวจสอบ
- ไม่มี duplicated logic
- ไม่มี dead code
- ไม่มี unused imports
- ไม่มี console.log
- ไม่มี TODO ค้าง
- ไม่มี workaround ชั่วคราว
- ใช้ Shared Component เดิม
- ใช้ Shared Utility เดิม
- ไม่สร้าง Helper ใหม่โดยไม่จำเป็น
---
# Deliverables
## 1. แก้ไข Source Code
แก้ไขเฉพาะส่วนที่จำเป็น
ห้าม Refactor ส่วนอื่น
---
## 2. สร้างรายงาน
สร้างไฟล์
```
docs/permission-template-validation-fix-report.md
```
---
รายงานต้องประกอบด้วย
# Permission Template Validation Fix Report
## Executive Summary
สรุปปัญหา
---
## Root Cause Analysis
อธิบายสาเหตุที่แท้จริง
---
## Architecture Review
อธิบาย Flow
Frontend
Validation
API
Backend
Database
---
## Files Modified
ระบุทุกไฟล์
พร้อมเหตุผลที่แก้ไข
---
## Implementation Details
อธิบาย
- Form
- Select
- Schema
- API
- Backend
ที่ถูกแก้ไข
---
## Before
อธิบายพฤติกรรมเดิม
---
## After
อธิบายพฤติกรรมใหม่
---
## Validation Result
ผลการทดสอบ
- Create
- Edit
- Validation
- API
- Database
---
## Regression Check
รายการที่ตรวจสอบแล้ว
---
## Risks
ผลกระทบที่อาจเกิดขึ้น
---
## Recommendation
ข้อเสนอแนะเพิ่มเติม
---
# Constraints
ต้องปฏิบัติตามข้อกำหนดดังต่อไปนี้
- ห้ามแก้ Database Schema โดยไม่จำเป็น
- ห้าม Hardcode Permission Template ID
- ห้ามเปลี่ยน Business Logic
- ห้ามเปลี่ยน Permission Logic
- ห้ามเปลี่ยน API Contract หากไม่จำเป็น
- ห้ามใช้ any
- ห้ามเพิ่ม Library ใหม่
- ต้องรักษา Type Safety
- ต้องใช้ Shared Component ของระบบ
- ต้องทำตาม Coding Standard ของโปรเจกต์
- ต้องรักษา Backward Compatibility หากมี
---
# Final Response
เมื่อดำเนินการเสร็จ ให้สรุปผลเป็นภาษาไทย โดยประกอบด้วย
1. Root Cause ที่พบ
2. แนวทางการแก้ไข
3. รายชื่อไฟล์ที่แก้ไข
4. ผลการทดสอบ
5. ความเสี่ยงที่เหลือ (ถ้ามี)
6. Path ของรายงานที่สร้างใน `docs/permission-template-validation-fix-report.md`
7. ข้อเสนอแนะเพิ่มเติม (ถ้ามี)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,702 @@
# Prompt: Enhance Training Policy Management Module (Production Ready)
## Objective
ปรับปรุง (Enhance) โมดูล **Training Policy Management** ของระบบ Training Management System (TMS)
**งานนี้ไม่ใช่การสร้างระบบใหม่ (Rewrite)**
ให้ตรวจสอบโครงสร้างเดิมของระบบก่อน และขยาย (Extend) หรือปรับปรุง (Refactor) ตามความเหมาะสม โดยคง Architecture, Coding Standard และ Business Logic ของระบบเดิมไว้ให้มากที่สุด
เป้าหมายคือยกระดับ Policy Management ให้เป็นศูนย์กลางในการกำหนดนโยบายการอบรมขององค์กร (Policy Engine) ที่สามารถรองรับการเติบโตของระบบในอนาคต
---
# IMPORTANT
ก่อนเริ่มพัฒนา
ต้องตรวจสอบโครงสร้างเดิมทั้งหมดของระบบ เช่น
- Database
- Prisma Schema
- Models
- Services
- Repository
- API
- Server Actions
- Validation
- Shared Components
- UI Components
- Permissions
- Audit Log
- Status
- Existing Policy Module
หากพบว่าโมดูลหรือโครงสร้างเดิมสามารถรองรับ Requirement ได้
ให้
- Reuse
- Extend
- Refactor
แทนการสร้างใหม่
ห้าม Rewrite ทั้ง Module
---
# Existing Implementation Compatibility
ให้ใช้หลัก
> Reuse > Extend > Refactor > Create New
ห้าม
- Duplicate Component
- Duplicate API
- Duplicate Business Logic
- Duplicate Validation
ห้ามสร้าง
- Table ใหม่
- API ใหม่
- Component ใหม่
หากของเดิมสามารถใช้งานต่อได้
หากจำเป็นต้องสร้าง
ต้องอธิบายเหตุผล
และกระทบระบบเดิมให้น้อยที่สุด
(Minimal Impact)
---
# Scope
พัฒนาและปรับปรุง
- Policy List
- View Policy
- Create Policy
- Edit Policy
- Clone Policy
- Archive
- Restore
- Activate
- Deactivate
- Version History
- Audit Log
---
# Policy Concept
Policy คือชุดกฎที่ใช้กำหนดการทำงานของระบบ
เช่น
- ชั่วโมงอบรมขั้นต่ำ
- ชั่วโมง K/S/A
- Mandatory Course
- Certificate Policy
- Approval Rule
- Effective Date
- Expiration Date
ทุก Feature ในระบบควรอ้างอิง Policy
ไม่ Hardcode ค่า
---
# Policy Fields
## General
- Policy Name \*
- Description
- Company
- Organization (ถ้ามี)
- Status
- Version
- Created By
- Updated By
- Created At
- Updated At
---
## Status
รองรับ
- Draft
- Active
- Inactive
- Archived
---
## Effective Date
- Effective From \*
- Effective To
รองรับ
"No Expiration"
---
## Training Hours
- Required Total Hours \*
- Required K Hours \*
- Required S Hours \*
- Required A Hours \*
Validation
```
K + S + A
ต้องเท่ากับ
Required Total
```
---
## Mandatory Courses
Multi Select
ค้นหาได้
แสดง
- Course Code
- Course Name
- Category
---
## Certificate Policy
- Certificate Required
- Validity
- Renewal Required
---
## Advanced Settings
รองรับในอนาคต
- Auto Approve
- Allow External Training
- Allow Self Submission
- Notification Rule
---
# Policy List
Columns
- Name
- Version
- Status
- Effective Date
- Updated By
- Updated At
- Action
Search
- Name
- Description
Filter
- Status
- Company
- Year
Sorting
- Name
- Updated
- Effective Date
- Status
Pagination
ใช้มาตรฐานเดียวกับระบบ
---
# View Policy
Read Only
แบ่ง Section
- General
- Hours
- Mandatory Courses
- Certificate
- Advanced
- History
---
# Create Policy
สร้างเป็น
Draft
Validation ครบ
ใช้ Required Style เดิมของระบบ
---
# Edit Policy
แก้ไขได้
Draft
Active
Inactive
Archived
ห้ามแก้ไข
- Version
- Created By
- Created At
ทุกครั้งที่ Save
- Updated At
- Updated By
ต้องอัปเดต
และสร้าง Audit Log
---
# Activate
Policy Active
ได้เพียง
1 Policy
ต่อ Scope
หากมี Active อยู่แล้ว
แสดง Confirm Dialog
ให้ Deactivate ของเดิม
ก่อน Activate ตัวใหม่
---
# Deactivate
รองรับ
Deactivate
หากไม่มี Active Policy เหลือ
แสดง Warning
---
# Clone
Clone Policy
Copy
- Hours
- Mandatory
- Certificate
- Settings
ไม่ Copy
- Audit
- Version
- History
Default
Status
Draft
Version
1
---
# Archive
ใช้
Soft Delete
เท่านั้น
ห้าม Hard Delete
Database
ใช้
deleted_at
deleted_by
หรือ
Status = Archived
ตามมาตรฐานของระบบ
---
# Restore
Archived
สามารถ Restore
กลับมาเป็น
Inactive
ได้
---
# Version History
ทุกครั้งที่ Save
สร้าง Version ใหม่
สามารถดูได้ว่า
Field ไหน
เปลี่ยนอะไร
เช่น
30 → 40
---
# Audit Log
รองรับ
- Create
- Edit
- Clone
- Activate
- Deactivate
- Archive
- Restore
Audit Log
ต้องเก็บ
- User
- Role
- Action
- Date
- Old Value
- New Value
- IP
- Browser
---
# Permission
ใช้ Permission-first เท่านั้น
ห้ามใช้ Business Role
Permission
- policy:view
- policy:create
- policy:update
- policy:delete
- policy:restore
- policy:clone
- policy:activate
- policy:audit
ทุก API
ต้องตรวจสอบ Permission
Server Side
---
# UI
ใช้
- shadcn/ui
- TailwindCSS
Design System เดิม
ห้ามสร้าง Design ใหม่
Layout
```
Policy Management
[+ New Policy]
Search
Filter
Table
```
Action Menu
- View
- Edit
- Clone
- Activate
- Deactivate
- Archive
- Restore
- Version History
- Audit Log
แสดงตาม Permission
---
# Validation
ตรวจสอบ
- Required Field
- Duplicate Name
- Hours Validation
- Effective Date
- Mandatory Course
---
# Responsive
Desktop
Tablet
Mobile
ต้องใช้งานได้
---
# Performance
- Memoization
- Server Pagination
- Lazy Rendering
- ห้าม Fetch ซ้ำ
---
# Security
ทุก API
ต้องตรวจสอบ Permission
Server Side
ห้ามใช้ Client Permission เพียงอย่างเดียว
---
# Existing Structure Review
ก่อนเริ่ม Coding
ให้ตรวจสอบว่า
- Database เดิมมีอะไร
- API เดิมมีอะไร
- Component เดิมมีอะไร
- Validation เดิมมีอะไร
จากนั้น
Reuse
Refactor
Extend
ตามความเหมาะสม
หากจำเป็นต้องสร้างใหม่
ให้ระบุเหตุผล
---
# Deliverables
เมื่อดำเนินการเสร็จ
สร้างเอกสาร
docs/policy-management-enhancement-report.md
ประกอบด้วย
## 1. Existing Structure Review
- สิ่งที่พบ
- ส่วนที่ Reuse
- ส่วนที่ Refactor
- ส่วนที่ Extend
- ส่วนที่สร้างใหม่ พร้อมเหตุผล
---
## 2. Files Changed
รายการไฟล์ทั้งหมด
---
## 3. Database Changes
Migration
Column
Index
Constraint
---
## 4. Permission Matrix
Permission ที่ใช้
---
## 5. Business Rules
อธิบายทุก Rule
---
## 6. Versioning
Workflow
---
## 7. Audit Log
Action ที่รองรับ
---
## 8. UI Screens
- List
- View
- Create
- Edit
- Version
- Audit
---
## 9. Testing
- CRUD
- Permission
- Validation
- Responsive
- Regression
---
## 10. Remaining Improvements
เสนอแนวทางพัฒนาเพิ่มเติม เช่น
- Scheduled Activation
- Policy Comparison
- Rollback Version
- Policy Approval Workflow
- Notification Before Expiry
- Company / Department / Position Specific Policy
---
# Success Criteria
งานถือว่าเสร็จเมื่อ
- ปรับปรุงจากโครงสร้างเดิม ไม่ Rewrite
- Reuse Component/API ได้มากที่สุด
- CRUD สมบูรณ์
- Clone
- Soft Delete
- Restore
- Activate / Deactivate
- Version History
- Audit Log
- Permission-first ครบทุก Action
- Validation ครบ
- Responsive สมบูรณ์
- TypeScript ไม่มี Error
- ESLint ผ่าน
- Build ผ่าน
- ไม่มี Regression
- รายงาน `docs/policy-management-enhancement-report.md` ถูกสร้างเรียบร้อย

152
plans/pre-sprint.md Normal file
View File

@@ -0,0 +1,152 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current status:
Sprint 5 has been completed and approved.
Before starting Sprint 6, perform a stabilization and technical debt review.
Important constraints:
- Do NOT change folder structure.
- Do NOT migrate ORM.
- Do NOT rename tables.
- Do NOT rename columns.
- Do NOT break existing routes.
- Reuse existing Auth.js.
- Reuse existing Drizzle ORM.
- Reuse existing UI components.
- Maintain Thai UI localization.
Current goal:
Prepare the system for Sprint 6 by fixing architecture gaps, validation gaps, and consistency issues discovered during Sprint 4 and Sprint 5.
Part 1: Dashboard Consistency Review
Requirements:
1. Verify dashboard calculations.
2. Ensure dashboard uses only APPROVED training records.
3. Verify:
- Total Hours
- Knowledge Hours
- Skill Hours
- Attitude Hours
4. Ensure policy values are loaded from Training Policy.
5. Remove any remaining hardcoded:
- 30 hours
- 12 hours
- 6 hours
6. Create a report listing all hardcoded training targets still found.
Part 2: Authorization Review
Requirements:
1. Review all routes under /dashboard.
2. Verify HRD-only pages:
- /dashboard/pending-review
- /dashboard/training-policy
- /dashboard/import-employees
- /dashboard/master-review
3. Verify Employee cannot access HRD routes.
4. Verify direct URL access is blocked.
5. Verify API routes have server-side authorization.
6. Create authorization review summary.
Part 3: Localization Consistency Review
Requirements:
1. Scan all TMS pages.
2. Find remaining English UI text.
3. Verify:
- Sidebar
- Form Labels
- Buttons
- Table Headers
- Toast Messages
- Validation Messages
- Empty States
- Loading States
- Error States
4. Replace remaining English user-facing text with Thai.
5. Keep internal enums and database values in English.
Part 4: Employee Import Hardening
Requirements:
1. Verify duplicate employee handling.
2. Verify duplicate email handling.
3. Verify invalid status handling.
4. Verify invalid Excel template handling.
5. Add clear Thai error messages.
6. Add downloadable error summary support if easy to implement.
Part 5: Master Review Hardening
Requirements:
1. Verify approve workflow.
2. Verify reject workflow.
3. Verify duplicate department creation prevention.
4. Verify duplicate position creation prevention.
5. Verify organization scoping.
Part 6: Output Review File
Create:
docs/pre-sprint-6-stabilization-review.md
The file must include:
1. Summary
2. Files Changed
3. Issues Found
4. Issues Fixed
5. Authorization Review
6. Localization Review
7. Dashboard Review
8. Import Review
9. Master Review
10. Remaining Technical Debt
11. Recommended Sprint 6 Scope
Part 7: Deliverables
Return:
- Complete code changes with file paths.
- Content of docs/pre-sprint-6-stabilization-review.md.
- List of unresolved issues requiring Sprint 6.

View File

@@ -0,0 +1,79 @@
You are a Senior QA Engineer and Solution Architect.
Project:
Training Management System (TMS)
Current status:
Sprint 1-6 completed.
Current task:
Perform a complete Pre-UAT Readiness Review before Sprint 7.
Important constraints:
- Do NOT add new business features.
- Focus only on stability, security, consistency, validation, and readiness.
- Keep existing architecture.
- Keep existing database schema unless a critical issue is found.
Review Scope:
1. Authentication
2. Authorization
3. Employee Training Records
4. HRD Workflow
5. Training Policy
6. Course Master
7. Employee Import
8. Master Review
9. Audit Log
10. Notification Center
11. Announcement
12. Dashboard
13. Responsive Design
14. Mobile UX
15. Localization
Review Areas:
- Security
- Permissions
- Data Visibility
- API Protection
- Validation
- File Upload Security
- Audit Coverage
- Notification Coverage
- Dashboard Accuracy
- Empty States
- Loading States
- Error Handling
- Responsive Issues
- Browser Compatibility
- Performance
Output File:
docs/pre-uat-readiness-review.md
Include:
1. Executive Summary
2. Critical Issues
3. High Priority Issues
4. Medium Priority Issues
5. Low Priority Issues
6. Security Review
7. Authorization Review
8. Performance Review
9. Responsive Review
10. UAT Readiness Score
11. Go-Live Readiness Score
12. Recommended Fixes Before Sprint 7
Return:
- Issues found
- Code changes if required
- Review file
- Final readiness score

View File

@@ -0,0 +1,289 @@
# Prompt: Redesign Announcement List to Enterprise Data Table
## Objective
ปรับปรุงหน้า **Announcements List** จาก Card Layout ให้เป็น **Enterprise Data Table** เพื่อให้เหมาะสำหรับการจัดการประกาศของผู้ดูแลระบบ (Admin / HRD / HRD Manager)
เป้าหมายของงานนี้คือ
- ลดพื้นที่แนวตั้งของรายการ
- รองรับข้อมูลจำนวนมาก
- ค้นหาและจัดการประกาศได้สะดวก
- รองรับ Sorting, Filtering และ Bulk Actions
- ใช้ Design System เดิมของระบบ (shadcn/ui + TailwindCSS)
- ไม่เปลี่ยน Business Logic, Workflow หรือ Permission เดิม
---
# Existing Implementation Compatibility
ก่อนเริ่มพัฒนา ให้ตรวจสอบโครงสร้างเดิมทั้งหมด เช่น
- Announcement List Page
- Announcement Card Component
- Query และ Pagination
- Filters
- Search
- Status Badge
- Action Menu
- Permission
- API
- Server Actions
- Shared Components
หากสามารถ Reuse Component เดิมได้ ให้ Reuse เป็นหลัก
ใช้หลัก
> Reuse > Extend > Refactor > Create New
ห้าม Rewrite Module ทั้งหมด
---
# Scope
ดำเนินการดังนี้
- เปลี่ยน Card Layout เป็น Data Table
- คง Search เดิม
- คง Filter เดิม
- เพิ่ม Sorting
- เพิ่ม Action Menu
- รองรับ Bulk Selection (ถ้ามีโครงสร้างรองรับ)
- แสดงสถานะและการปักหมุดใน Table
- ตรวจสอบ Responsive
---
# Table Columns
เรียงลำดับดังนี้
1. Checkbox (รองรับ Bulk Action)
2. Pin (📌)
3. หัวข้อประกาศ
4. สถานะ
5. วันที่เผยแพร่
6. วันสิ้นสุด
7. ผู้สร้าง
8. ไฟล์แนบ
9. จัดการ
### หัวข้อประกาศ
แสดง
- ชื่อประกาศ
- ข้อความย่อย (ถ้ามี)
ใช้ `truncate`
---
### Status
ใช้ Badge ตามมาตรฐานของระบบ
- Draft
- Pending Review
- Approved
- Published
- Expired
- Archived
---
### Pin
หากประกาศถูกปักหมุด
แสดงไอคอน 📌 หรือ Badge `Pinned`
หากไม่ปักหมุด ไม่ต้องแสดงข้อความ
---
### Publish Date
แสดงวันที่เผยแพร่
หากยังไม่เผยแพร่ แสดง "-"
---
### Expire Date
แสดงวันสิ้นสุดการแสดงผล
หากไม่มี แสดง "ไม่กำหนด"
---
### Attachment
หากมีไฟล์แนบ
แสดงไอคอนคลิปหนีบกระดาษ พร้อมจำนวนไฟล์ (ถ้ามีหลายไฟล์)
หากไม่มี
แสดง "-"
---
### Action Menu
ใช้ Dropdown Menu
รายการ Action ต้องเปลี่ยนตาม Status และ Permission
ตัวอย่าง
- ดูรายละเอียด
- แก้ไข
- ส่งตรวจสอบ
- อนุมัติ
- เผยแพร่
- ปักหมุด
- ยกเลิกการปักหมุด
- Archive
- ลบ
---
# Search
คง Search เดิม
ค้นหา
- หัวข้อประกาศ
- รายละเอียดประกาศ (ถ้าระบบรองรับ)
---
# Filter
คง Filter เดิม และปรับ Layout ให้เหมาะกับ Data Table
รองรับ
- Status
- ประเภท
- ผู้สร้าง
- ปี
- ปักหมุด
---
# Sorting
รองรับการเรียงลำดับ
- หัวข้อ
- สถานะ
- วันที่เผยแพร่
- วันสิ้นสุด
- ผู้สร้าง
---
# Bulk Action
หากระบบมี Permission และ API รองรับ
เพิ่ม Bulk Actions
- Publish
- Archive
- Delete
- Pin
- Unpin
หากยังไม่มีโครงสร้างรองรับ ให้เตรียม UI และระบุในรายงานว่าเป็น Future Enhancement
---
# Pagination
ใช้ Pagination เดิมของระบบ
ไม่เปลี่ยน Logic
---
# Responsive
Desktop
ใช้ Data Table
Mobile
สามารถแสดงเป็น Card ได้ หาก Data Table ใช้งานยากบนหน้าจอเล็ก
---
# Performance
- Reuse Query เดิม
- ไม่ Fetch ซ้ำ
- ใช้ Memoization ตามมาตรฐานเดิม
- ไม่กระทบ Server Pagination
---
# Business Logic
ห้ามแก้ไข
- Approval Workflow
- Publish Workflow
- Schedule Publish
- Permission
- Validation
- API Contract
- Business Rules
ให้เปลี่ยนเฉพาะการแสดงผล (Presentation Layer)
---
# Deliverables
เมื่อดำเนินการเสร็จ
สร้างเอกสาร
`docs/announcement-list-table-redesign.md`
ประกอบด้วย
- Existing Structure Review
- Files Changed
- UI Before / After
- Table Columns
- Action Menu
- Responsive Result
- Performance Impact
- Regression Check
- Future Improvements
---
# Success Criteria
งานถือว่าเสร็จเมื่อ
- เปลี่ยน Card Layout เป็น Data Table
- แสดงข้อมูลครบถ้วน
- Search และ Filter ยังทำงานได้
- Action Menu ใช้งานได้
- Sorting ทำงานได้
- Responsive สมบูรณ์
- ไม่มี Regression
- TypeScript ไม่มี Error
- ESLint ผ่าน
- Build ผ่าน
- Report ถูกสร้างเรียบร้อย

343
plans/req.md Normal file
View File

@@ -0,0 +1,343 @@
# Training System Requirements Aligned With Project Stack
## 1. เป้าหมายของระบบ
ระบบนี้เป็นเว็บแอปสำหรับจัดเก็บและติดตามประวัติการอบรมของพนักงาน รวมถึงไฟล์ใบรับรองการอบรม และการตรวจสอบความครบถ้วนตาม Training Matrix ของแต่ละหน่วยงานหรือแต่ละตำแหน่งงาน
เอกสารฉบับนี้ปรับให้สอดคล้องกับ stack และสถาปัตยกรรมของโปรเจ็กต์ปัจจุบัน โดยไม่ใช้ Google Apps Script, Google Sheets หรือ Google Drive เป็นแกนหลักของระบบ
## 2. Stack ที่ต้องใช้ตามโปรเจ็กต์นี้
- Frontend: Next.js 16 App Router + React 19 + TypeScript
- UI: Tailwind CSS v4 + shadcn/ui
- Auth: Auth.js
- Database: PostgreSQL + Drizzle ORM
- Data fetching: TanStack React Query
- URL state: nuqs
- Forms: TanStack Form + Zod ผ่าน `useAppForm`
- API boundary: Next.js Route Handlers ภายใต้ `src/app/api/**`
- Icons: ใช้ผ่าน `@/components/icons` เท่านั้น
## 3. แนวทางสถาปัตยกรรมที่ต้องยึด
- ใช้ feature-based structure ภายใต้ `src/features/<feature>/`
- ใช้ data layer pattern ของโปรเจ็กต์:
- `types.ts`
- `service.ts`
- `queries.ts`
- `mutations.ts` เมื่อมี create/update/delete
- ฝั่ง client ต้องเรียกข้อมูลผ่าน `service.ts`
- `service.ts` ต้องเรียก Route Handlers ด้วย `apiClient`
- Route Handlers ต้องเป็น boundary หลักสำหรับ auth, authorization, validation ขั้นต้น และ database access
- หน้า dashboard ต้องใช้ `PageContainer` สำหรับ page header
- table/listing ที่มี filter, search, sort, pagination ต้องใช้ React Query + nuqs ตาม pattern ของหน้า `products` และ `users`
- form ต้องใช้ `useAppForm` และ field wrappers ของโปรเจ็กต์
## 4. Domain Model ที่ต้องใช้ในระบบ
ระบบนี้ควรใช้คำศัพท์โดเมนให้ชัดและสอดคล้องกับโครงสร้าง auth ปัจจุบัน
- `user`: ผู้ใช้งานที่ล็อกอินเข้าระบบ
- `organization`: หน่วยงานเจ้าของข้อมูล หรือ tenant ของระบบ
- `membership`: ความสัมพันธ์ระหว่าง user กับ organization พร้อม role
- `employee`: ข้อมูลพนักงานที่ถูกติดตามประวัติการอบรม
- `course`: หลักสูตรอบรมกลาง
- `training_record`: รายการประวัติการอบรมของพนักงานแต่ละครั้ง
- `certificate`: ข้อมูลไฟล์ใบรับรองที่ผูกกับ training record
- `training_matrix`: ข้อกำหนดว่าตำแหน่งหรือแผนกใดต้องผ่านหลักสูตรอะไร
- `department`: หน่วยงานภายในองค์กร
- `position`: ตำแหน่งงาน
หมายเหตุ:
- ถ้าผู้ใช้ระบบกับพนักงานเป็นคนละแนวคิด ต้องแยก `user` ออกจาก `employee`
- ข้อมูลทั้งหมดควรถูกผูกกับ `organizationId` เพื่อรองรับ multi-tenant
## 5. ขอบเขตข้อมูลหลักใน PostgreSQL
ตารางหลักที่ควรมีในระบบนี้:
- `users`
- ข้อมูลบัญชีผู้ใช้งานสำหรับ Auth.js
- `organizations`
- ข้อมูลองค์กรหรือ workspace
- `memberships`
- บทบาทของผู้ใช้งานในแต่ละ organization
- `employees`
- รหัสพนักงาน, ชื่อ, แผนก, ตำแหน่ง, บริษัท, สถานะ
- `departments`
- หน่วยงานภายใน organization
- `positions`
- ตำแหน่งงานภายใน organization
- `courses`
- ชื่อหลักสูตร, หมวดหมู่, ผู้จัดอบรม, จำนวนชั่วโมง, อายุใบรับรอง, บังคับหรือไม่
- `training_records`
- employee, course, วันที่อบรม, รูปแบบการอบรม, ชั่วโมง, หมายเหตุ, สถานะอนุมัติ
- `certificates`
- ชื่อไฟล์, path หรือ storage key, mime type, uploadedAt
- `training_matrices`
- mapping ระหว่าง department หรือ position กับ course ที่จำเป็น
แนวทางสำคัญ:
- ทุกตารางเชิงธุรกิจควรมี `organizationId`
- ใช้ foreign keys ชัดเจนระหว่าง employee, course, training_record, certificate
- เก็บ file metadata ใน database และเก็บไฟล์จริงใน app-owned storage
## 6. แนวทางจัดเก็บไฟล์ใบรับรอง
ไม่ใช้ Google Drive เป็น storage หลักของระบบนี้
รอบแรกของระบบควรใช้แนวทางใดแนวทางหนึ่ง:
- ทางเลือกแนะนำสำหรับโปรเจ็กต์นี้:
- เก็บ metadata ใน PostgreSQL
- เก็บไฟล์จริงผ่าน local uploads หรือ object storage ที่ต่อเพิ่มภายหลัง
ข้อกำหนดเชิงระบบ:
- certificate ต้องผูกกับ `training_record`
- ต้องสามารถเปิดดูไฟล์ย้อนหลังได้
- ต้องรองรับไฟล์อย่างน้อย `pdf`, `jpg`, `jpeg`, `png`
- ต้องมี field สำหรับ `fileName`, `fileType`, `fileSize`, `storageKey`, `uploadedAt`
## 7. บทบาทผู้ใช้งาน
ระบบต้องรองรับ role อย่างน้อย:
- `member`
- ดู dashboard ของตัวเอง
- เพิ่มและแก้ไขประวัติการอบรมของตัวเอง
- อัปโหลดใบรับรองของตัวเอง
- ดูสถานะการอนุมัติ
- `admin`
- จัดการ employee
- จัดการ course
- ตรวจสอบและอนุมัติ training record
- จัดการ training matrix
- ดูรายงานภาพรวมของ organization
- `owner`
- สิทธิ์ระดับสูงสุดใน organization
- จัดการสมาชิกและค่ากำหนดหลักของ organization
Authorization ต้องตรวจที่ server-side ผ่าน session + membership ไม่ใช่ตรวจเฉพาะ client
## 8. ฟีเจอร์หลักสำหรับผู้ใช้งานทั่วไป
### 8.1 User Dashboard
ผู้ใช้งานต้องเห็น dashboard ส่วนตัวที่ประกอบด้วย:
- จำนวนหลักสูตรที่เคยอบรมทั้งหมด
- จำนวนชั่วโมงอบรมสะสม
- จำนวนใบรับรองที่บันทึกแล้ว
- จำนวนหลักสูตรที่ยังขาดตาม training matrix
- กราฟสรุปการอบรมรายเดือนหรือรายปี
แนวทาง implementation:
- ใช้ Recharts สำหรับกราฟ
- ใช้ server prefetch + `HydrationBoundary` + `useSuspenseQuery`
### 8.2 บันทึกการอบรม
ผู้ใช้งานต้องสามารถเพิ่มรายการอบรมได้ โดยข้อมูลหลักประกอบด้วย:
- employee หรือข้อมูลผู้เข้าอบรม
- course
- training date
- training type: `online | onsite | internal | external`
- training hours
- organizer
- note
- certificate file
- approval status
แนวทาง implementation:
- ใช้ TanStack Form + Zod
- submit ผ่าน mutation ไปยัง Route Handler
- หลังบันทึกต้อง invalidate query ที่เกี่ยวข้อง
### 8.3 รายการอบรมของฉัน
ผู้ใช้งานต้องสามารถ:
- ค้นหาตามชื่อหลักสูตร
- กรองตามปี
- กรองตามหมวดหมู่
- กรองตามสถานะ
- เปิดดูรายละเอียด
- เปิดดูไฟล์ใบรับรอง
- แก้ไขรายการของตัวเอง
- ลบรายการที่ยังไม่ถูกอนุมัติ หรือเป็นไปตาม policy ที่กำหนด
แนวทาง implementation:
- ใช้ Data Table pattern เดียวกับ `products` หรือ `users`
- ใช้ React Query + nuqs
## 9. ฟีเจอร์หลักสำหรับ Admin
### 9.1 Admin Dashboard
Admin ต้องเห็น dashboard ภาพรวมของ organization:
- จำนวนพนักงาน
- จำนวนชั่วโมงอบรมรวม
- เปอร์เซ็นต์ความครบถ้วนตาม training matrix
- จำนวนรายการที่รออนุมัติ
- สถิติแยกตามแผนก หมวดหมู่ และช่วงเวลา
### 9.2 จัดการ Employee
Admin ต้องสามารถ:
- เพิ่ม employee
- แก้ไข employee
- ปิดการใช้งาน employee
- กำหนดแผนก
- กำหนดตำแหน่ง
### 9.3 จัดการ Course
Admin ต้องสามารถ:
- เพิ่ม course
- แก้ไข course
- ลบ course
- กำหนด category
- กำหนด standard training hours
- กำหนด certificate validity
- ระบุว่าเป็น required course หรือไม่
### 9.4 ตรวจสอบและอนุมัติ Training Record
Admin ต้องสามารถ:
- เปิดดูไฟล์ใบรับรอง
- ตรวจสอบรายละเอียดการอบรม
- approve
- reject
- request changes
- ใส่หมายเหตุประกอบการตรวจสอบ
สถานะที่ควรใช้:
- `pending`
- `approved`
- `rejected`
- `needs_revision`
### 9.5 จัดการ Training Matrix
Admin ต้องสามารถ:
- กำหนดหลักสูตรบังคับตาม department
- กำหนดหลักสูตรบังคับตาม position
- กำหนดหลักสูตรเฉพาะรายบุคคลในอนาคตได้
- กำหนด minimum required hours เมื่อจำเป็น
- ดูสถานะครบหรือไม่ครบของแต่ละ employee
## 10. รายงานที่ระบบควรมี
อย่างน้อยควรมีรายงานต่อไปนี้:
- ประวัติการอบรมรายบุคคล
- การอบรมแยกตามแผนก
- ชั่วโมงอบรมสะสม
- หลักสูตรที่ยังขาดตาม matrix
- ใบรับรองใกล้หมดอายุ
- สรุป training matrix ของ organization
รูปแบบการแสดงผล:
- แสดงบนหน้า dashboard/table
- รองรับ export ใน phase ถัดไป
## 11. แนวทาง UI/UX ที่ต้องสอดคล้องกับโปรเจ็กต์
- ใช้ shadcn/ui และ component patterns ที่มีอยู่แล้ว
- ใช้ `PageContainer` สำหรับ page title, description, action
- ใช้ `@/components/icons` แทนการ import icon ตรงจาก package ภายนอก
- ใช้ Card, Table, Dialog, Sheet, Tabs ตามแนวทางเดิมของโปรเจ็กต์
- รองรับ desktop และ mobile
- ไม่ใช้ SweetAlert2 หรือระบบ popup ภายนอกเป็นค่าเริ่มต้น
- ใช้ toast/alert/dialog ที่มีในโปรเจ็กต์แทน
## 12. Visual Direction
โทนสีจาก requirement เดิมสามารถตีความเป็น theme ของระบบได้ แต่ต้อง implement ผ่าน theme/token ของโปรเจ็กต์นี้ ไม่ใช่เขียนเป็นระบบ CSS แยกใหม่
สีที่ต้องการ:
- เขียวเข้ม: `#336b4a`
- เทา: `#808285`
- ส้ม: `#e26631`
- ม่วงเข้ม: `#413b60`
แนวทางใช้งาน:
- primary actions: เขียวเข้ม
- warning/highlight states: ส้ม
- supporting accents/charts: ม่วงเข้ม
- muted text/borders: เทา
ถ้าต้องทำ theme จริง ให้เพิ่มผ่านระบบ theme ของโปรเจ็กต์ ไม่ทำแยกนอก `src/styles/themes` และ `theme.config.ts`
## 13. แนวทางแบ่ง feature ในรีโปนี้
ฟีเจอร์ที่ควรสร้างใน `src/features/`:
- `employees`
- `courses`
- `training-records`
- `certificates`
- `training-matrix`
- `reports`
แต่ละ feature ควรมี:
- `api/types.ts`
- `api/service.ts`
- `api/queries.ts`
- `api/mutations.ts` เมื่อมี mutation
- `components/`
- `schemas/`
- `constants/` เมื่อจำเป็น
และมี route ใต้ `src/app/dashboard/<feature>/page.tsx`
## 14. ลำดับการพัฒนาที่แนะนำ
เพื่อให้เข้ากับโครงสร้างของโปรเจ็กต์ ควรพัฒนาเป็นลำดับดังนี้:
1. Auth + organization + membership foundation
2. Employee management
3. Course management
4. Training record CRUD + certificate upload metadata
5. Training matrix
6. Dashboard summaries and reports
## 15. สิ่งที่ไม่ควรใช้ใน requirement ฉบับนี้
เพื่อให้ตรงกับโปรเจ็กต์นี้ ไม่ควรออกแบบระบบโดยอิงสิ่งต่อไปนี้เป็นแกนหลัก:
- Google Apps Script
- Google Sheets เป็น database หลัก
- Google Drive เป็น storage หลัก
- HTML/CSS/JavaScript แบบแยก standalone app
- SweetAlert2 เป็น UI feedback หลัก
- FontAwesome เป็น icon source หลัก
## 16. สรุป
ระบบ Training System ฉบับนี้ต้องถูกออกแบบให้เป็น multi-tenant web application บน stack ของโปรเจ็กต์ปัจจุบัน โดยใช้:
- Next.js App Router
- Auth.js
- PostgreSQL + Drizzle
- React Query + nuqs
- TanStack Form + Zod
- shadcn/ui + Tailwind CSS
และต้องจัดวางฟีเจอร์ตาม feature architecture ของรีโป เพื่อให้สามารถพัฒนาต่อจากฐานโค้ดนี้ได้จริง

View File

@@ -0,0 +1,119 @@
Implement **Sprint 6.12.1 Global DataTable Responsive Fix**
Goal:
Fix all DataTable layouts so they never overflow outside the content area.
Problem:
Training Records page currently overflows horizontally.
Pagination is partially outside the viewport.
Some table columns push the layout beyond the available width.
This fix must apply to ALL DataTable pages, including:
- Training Records
- Pending Review
- Employee Directory
- Users
- Reports
- Any reusable DataTable component
Requirements:
1. Every page container must use:
```tsx
className = "flex-1 min-w-0";
```
2. Every Card containing tables:
```tsx
overflow - hidden;
```
3. Every table wrapper:
```tsx
<div className="w-full overflow-x-auto">
```
4. Table:
```tsx
<Table className="min-w-full">
```
Do not allow page-level overflow.
5. Pagination
Must stay inside container.
Recommended:
```tsx
flex;
flex - wrap;
justify - between;
items - center;
gap - 4;
```
6. Search section
Use
```tsx
w-full max-w-sm
```
instead of fixed widths.
7. Certificate column
Use fixed width.
Image
```tsx
w - 20;
h - 20;
object - cover;
```
8. Mobile
Only table scrolls.
Entire page must never scroll horizontally.
9. Desktop
Table fits inside content container.
10. Audit all pages using reusable DataTable components.
Files likely involved:
- src/components/data-table/\*
- src/components/ui/table.tsx
- src/features/training-records/\*
- src/features/pending-review/\*
- src/features/users/\*
- src/features/employee-directory/\*
- src/features/reports/\*
- src/components/layout/page-container.tsx
Output Review:
docs/sprint-6-12-1-responsive-datatable-review.md
Include:
- Pages checked
- Files changed
- Responsive fixes
- Overflow fixes
- Manual regression checklist
Return complete code changes.

View File

@@ -0,0 +1,193 @@
You are a Senior Frontend QA Engineer.
Project:
Training Management System (TMS)
Current task:
Perform responsive QA after management UI changes.
Important constraints:
- Do NOT add new business features.
- Do NOT change database schema.
- Do NOT rewrite layout from scratch.
- Fix only responsive/UI issues found.
- Keep Thai UI.
- Keep existing desktop layout working.
- Minimal-impact changes only.
Screen sizes to test:
- 360px
- 390px
- 412px
- 768px
- 1024px
- 1440px
Browsers:
- Chrome
- Microsoft Edge
Pages to test:
Employee:
1. /dashboard/overview
2. /dashboard/training-records
3. /dashboard/training-records/create
4. /dashboard/training-records/[id]
5. /dashboard/announcements
6. /dashboard/announcements/[id]
7. /dashboard/notifications
HRD/Admin:
1. /dashboard/overview
2. /dashboard/pending-review
3. /dashboard/training-records
4. /dashboard/training-records/[id]/review
5. /dashboard/courses
6. /dashboard/training-policy
7. /dashboard/import-employees
8. /dashboard/announcements
9. /dashboard/reports
10. /dashboard/audit-logs
Focus areas:
1. Sidebar / Navigation
- Employee sidebar must not show Reports.
- Employee sidebar must not show Announcements if announcements are moved to dashboard.
- Employee sidebar must not show Notifications if notification is moved to bell icon.
- HRD/Admin sidebar must not show Organizations.
- HRD/Admin sidebar must not show Master Review.
- Sidebar drawer works on mobile.
- Sidebar closes after menu selection on mobile.
- Menu labels do not overflow.
2. Header
- Notification bell is visible on desktop and mobile.
- Notification badge does not overflow.
- User dropdown displays:
- name
- employee code
- email
- Profile menu is removed.
- User dropdown does not overflow mobile screen.
3. Dashboard
- Compact filter toolbar does not overflow.
- Filter controls wrap correctly on mobile.
- Announcement widget displays correctly on employee dashboard.
- KPI cards stack correctly.
- Charts do not overflow.
- Thai text wraps correctly.
4. Training Record Form
- Course dropdown fits mobile screen.
- "อื่น ๆ" option works without layout breaking.
- Custom course text input fits mobile screen.
- Training type dropdown with new 4 options fits mobile screen.
- TimePicker for training hours fits mobile screen.
- Date picker fits mobile screen.
- File upload area fits mobile screen.
- Submit/cancel buttons are usable on mobile.
5. Certificate Preview
- Image preview fits dialog.
- Close button stays inside dialog.
- Unsupported files show certificate icon.
- Broken images show certificate icon.
- Download/open action works.
- Dialog does not overflow on 360px.
6. Tables
- Tables scroll horizontally where needed.
- Table toolbar filters wrap correctly.
- Pagination works on mobile.
- Action buttons remain accessible.
- No table breaks page width.
7. Dialogs / Popovers
- Notification popover fits mobile.
- User dropdown fits mobile.
- Certificate dialog fits mobile.
- Review dialog fits mobile.
- Course dropdown/select popover fits mobile.
8. Reports
- HRD reports filter area fits mobile.
- Export buttons stack correctly.
- Report tables scroll horizontally.
- Employee cannot access reports.
9. Error / Loading / Empty States
- Loading skeleton does not overflow.
- Error pages are readable on mobile.
- Empty states are centered/clean.
Required fixes:
- Add max-w-full where needed.
- Add overflow-x-auto to wide tables.
- Use flex-col md:flex-row where controls overflow.
- Use w-full on mobile buttons/inputs.
- Use min-w-0 for long Thai text containers.
- Use truncate or break-words where appropriate.
- Keep desktop layout unchanged as much as possible.
Output Review File:
Create:
docs/responsive-qa-after-management-change-review.md
Include:
1. Summary
2. Screens Tested
3. Pages Reviewed
4. Issues Found
5. Issues Fixed
6. Files Changed
7. Responsive Patterns Applied
8. Remaining Risks
9. Manual Test Checklist
10. Responsive Readiness Score
Manual Test Checklist:
- 360px layout works.
- 390px layout works.
- 412px layout works.
- 768px layout works.
- 1024px layout works.
- 1440px layout works.
- Employee menu is correct.
- HRD/Admin menu is correct.
- Header bell works.
- User dropdown works.
- Dashboard filter does not overflow.
- Course dropdown works on mobile.
- Other course input works on mobile.
- TimePicker works on mobile.
- Certificate dialog works on mobile.
- Tables scroll correctly.
- Reports are HRD only.
- Thai text does not break layout.
Return:
- Complete code changes with file paths.
- Content of docs/responsive-qa-after-management-change-review.md.
- Remaining issues if any.

View File

@@ -0,0 +1,255 @@
You are a Senior Frontend Engineer and Responsive UI Specialist.
Project:
Training Management System (TMS)
Current issue:
The table components on these pages exceed the responsive breakpoint and are not mobile/tablet friendly:
1. /dashboard/pending-review
2. /dashboard/training-records
3. /dashboard/employees
Problem:
The table width overflows the page layout instead of being contained inside a responsive horizontal scroll area. On smaller breakpoints, table components push the dashboard content width beyond the viewport.
Current task:
Fix table responsiveness for Pending Review, Training Records, and Employees pages.
Important constraints:
- Do NOT change database schema.
- Do NOT change business logic.
- Do NOT remove table columns unless absolutely necessary.
- Do NOT rewrite the whole data table system.
- Reuse existing DataTable components.
- Keep Thai UI.
- Keep desktop layout as close as possible.
- Fix responsive behavior with minimal-impact changes.
Pages to inspect and fix:
- src/app/dashboard/pending-review/page.tsx
- src/features/training-records/components/pending-review-table.tsx
- src/features/training-records/components/pending-review-columns.tsx
- src/app/dashboard/training-records/page.tsx
- src/features/training-records/components/training-record-tables/index.tsx
- src/features/training-records/components/training-record-tables/columns.tsx
- src/app/dashboard/employees/page.tsx
- src/features/employees/components/\*
- src/components/ui/table/data-table.tsx
- src/components/ui/table/data-table-toolbar.tsx
- src/components/ui/table/data-table-pagination.tsx
- src/components/layout/page-container.tsx
Root causes to check:
1. Parent container missing:
- min-w-0
- max-w-full
- overflow-hidden
2. Table wrapper missing:
- w-full
- max-w-full
- overflow-x-auto
3. Table itself has fixed/min width too large without scroll container.
4. Toolbar filters use fixed width and do not wrap.
5. Pagination uses fixed row layout and overflows.
6. Table cell content does not truncate/wrap:
- long Thai course names
- employee names
- emails
- department names
- action buttons
Required fixes:
Part 1: Parent layout containment
Ensure page content wrappers include:
- min-w-0
- max-w-full
- overflow-hidden where appropriate
Example:
<div className="w-full min-w-0 max-w-full overflow-hidden">
Part 2: DataTable scroll wrapper
Ensure DataTable table area is wrapped with:
<div className="w-full max-w-full overflow-x-auto rounded-md border">
<Table className="min-w-[900px] md:min-w-full">
...
</Table>
</div>
Important:
- On mobile/tablet, table should scroll horizontally inside its own container.
- The whole page must NOT scroll horizontally.
Part 3: Page-level table cards
If table is inside Card, Card must have:
- min-w-0
- max-w-full
- overflow-hidden
CardContent should have:
- min-w-0
- max-w-full
- overflow-hidden or overflow-x-auto only at table area
Part 4: Toolbar responsiveness
DataTableToolbar should:
- stack on mobile
- wrap on tablet
- keep desktop inline
Use:
- flex flex-col gap-2 md:flex-row md:flex-wrap md:items-center
- w-full md:w-auto
- min-w-0
- search input w-full md:w-[250px]
Filters/buttons:
- w-full sm:w-auto
- justify-start
- flex-wrap
Part 5: Pagination responsiveness
DataTablePagination should:
- stack on mobile
- avoid fixed-width overflow
- use flex-col gap-2 sm:flex-row
- make pagination buttons wrap or remain inside container
Part 6: Column width strategy
For table columns:
Use controlled widths:
- Course Name: min-w-[220px] max-w-[320px] truncate or line-clamp-2
- Employee Name: min-w-[160px]
- Email: min-w-[220px] truncate
- Department: min-w-[160px]
- Status: min-w-[120px]
- Actions: sticky right-0 if already supported, or min-w-[100px]
Do not allow long text to force table beyond intended min width.
Use:
- truncate
- whitespace-nowrap where appropriate
- break-words for Thai long text if better
- line-clamp-2 for course name or remark
Part 7: Action buttons
Action cells should:
- not push table width too much
- use icon button or compact action dropdown on mobile if existing project supports it
Part 8: Verify affected pages
Pending Review:
- table should scroll within table area
- toolbar should not overflow
- action buttons still accessible
Training Records:
- table should scroll within table area
- certificate/status/action columns should remain usable
- long course names should not push layout
Employees:
- employee code/name/email/department columns should not push layout
- email should truncate
- action buttons should remain accessible
Part 9: Browser/responsive validation
Test visually or by code review at:
- 360px
- 390px
- 412px
- 768px
- 1024px
- 1440px
Expected:
- No page-level horizontal overflow
- Only table container scrolls horizontally
- Sidebar/header remain stable
- Toolbar wraps cleanly
- Pagination stays inside container
- Thai text does not break layout
Part 10: Output review file
Create:
docs/responsive-table-fix-review.md
Include:
1. Summary
2. Root Cause
3. Pages Fixed
4. Files Changed
5. Table Wrapper Changes
6. Toolbar Changes
7. Pagination Changes
8. Column Width Strategy
9. Responsive Test Checklist
10. Remaining Risks
11. Final Responsive Readiness Score
Manual Test Checklist:
- Pending Review table no longer breaks page width.
- Training Records table no longer breaks page width.
- Employees table no longer breaks page width.
- Tables scroll horizontally inside their own container.
- Page itself does not horizontally scroll.
- Toolbar wraps on mobile.
- Pagination stays inside container.
- Long Thai course names do not push layout.
- Long emails truncate correctly.
- Action buttons remain accessible.
- Works at 360px.
- Works at 390px.
- Works at 412px.
- Works at 768px.
- Works at 1024px.
- Desktop layout remains acceptable.
Return:
- Complete code changes with file paths.
- Content of docs/responsive-table-fix-review.md.
- Any remaining responsive issues.

146
plans/responsive.md Normal file
View File

@@ -0,0 +1,146 @@
You are a Senior Frontend Engineer.
Project:
Training Management System (TMS)
Current task:
Before Sprint 6, audit and fix responsive layout issues across the TMS system.
Important constraints:
- Do NOT change folder structure.
- Do NOT rewrite layout from scratch.
- Do NOT break existing desktop UI.
- Reuse existing sidebar, header, layout, shadcn/ui and Tailwind classes.
- Keep Thai UI.
- Minimal-impact changes only.
Goal:
Make the current TMS pages usable on:
- Desktop
- Tablet
- Mobile
Breakpoints:
- Mobile: 360px - 767px
- Tablet: 768px - 1023px
- Desktop: 1024px+
Pages to audit:
1. /dashboard/overview
2. /dashboard/training-records
3. /dashboard/training-records/[id]
4. /dashboard/training-records/[id]/review
5. /dashboard/pending-review
6. /dashboard/courses
7. /dashboard/training-policy
8. /dashboard/import-employees
9. /dashboard/master-review
10. /dashboard/reports
Responsive requirements:
1. Main layout
- Sidebar must collapse or become mobile drawer on small screens.
- Header must not overflow.
- User menu and search must remain usable.
- Page content must have proper padding on mobile.
2. Tables
- Tables must support horizontal scroll on mobile.
- No table should break page width.
- Important actions must remain accessible.
- Add responsive wrappers where needed:
overflow-x-auto
min-w-[...] for wide tables
3. Cards and dashboard
- Card grids must change from:
desktop: 3-4 columns
tablet: 2 columns
mobile: 1 column
- Charts must not overflow.
- Dashboard widgets must stack vertically on mobile.
4. Forms
- Forms must become single column on mobile.
- Buttons must stack or become full width on mobile.
- Inputs, selects, date pickers, file upload must fit screen width.
5. Dialogs / Modals
- Dialog width must fit mobile screens.
- Long content must scroll.
- Action buttons must remain visible.
6. Data table toolbar
- Filters must wrap on mobile.
- Search input must be full width on mobile.
- Export / action buttons must not overflow.
7. Thai text
- Long Thai labels must wrap correctly.
- Badges must not overflow.
- Table cells should use truncate or wrap where appropriate.
Implementation guidance:
- Prefer Tailwind responsive classes.
- Use:
w-full
max-w-full
overflow-x-auto
grid-cols-1 md:grid-cols-2 lg:grid-cols-4
flex-col md:flex-row
gap-3
px-4 md:px-6
text-sm md:text-base
- Avoid fixed widths unless necessary.
- Replace hardcoded widths with responsive widths.
Output review file:
Create:
docs/pre-sprint-6-responsive-audit-review.md
The file must include:
1. Summary
2. Files changed
3. Pages audited
4. Responsive issues found
5. Responsive issues fixed
6. Components updated
7. Breakpoints tested
8. Manual test checklist
9. Remaining limitations
10. Recommendation before Sprint 6
Manual test checklist:
- Desktop layout still works.
- Sidebar works on desktop.
- Sidebar/drawer works on mobile.
- Dashboard cards stack correctly on mobile.
- Tables scroll horizontally on mobile.
- Forms fit mobile width.
- Buttons are usable on mobile.
- Dialogs fit mobile width.
- No horizontal page overflow except intended table scroll.
- Thai labels do not break layout.
- HRD pages work on tablet.
- Employee pages work on mobile.
Return:
- Complete code changes with file paths.
- Content of docs/pre-sprint-6-responsive-audit-review.md.

View File

@@ -0,0 +1,167 @@
# Prompt.md — สร้าง Plan.md สำหรับหน้า Role & Permission Management
## Context
โปรเจกต์นี้คือ Training Management System (TMS) ที่กำลังปรับระบบสิทธิ์จากแนวคิด Role-based เดิม ไปเป็น Permission-first โดยใช้ Permission Template เป็นหลัก
เป้าหมายรอบนี้คือ **ยังไม่ต้องแก้ไขโค้ดจริง** แต่ให้ตรวจสอบโครงสร้างระบบเดิม และสร้างเอกสาร `Plan.md` สำหรับการพัฒนาหน้า Role & Permission Management อย่างเป็นระบบ
## Current Direction
ระบบต้องไม่ใช้ Role เป็นตัวกำหนดสิทธิ์หลักอีกต่อไป แต่ให้ใช้ Permission Template เป็นแกนหลัก
Role เดิม เช่น Employee, Staff, Manager, IT Admin, Super Admin อาจยังคงมีไว้เพื่อ compatibility หรือ metadata แต่สิทธิ์การใช้งานจริงต้องอ้างอิงจาก Permission Template และ Permission รายการย่อย
## Requirement Summary
ต้องสร้างแผนสำหรับหน้าจัดการ Role และ Permission โดยมีแนวคิดหลักดังนี้
1. มีหน้า Permission Template Management แยกจากหน้า User Permission Assignment
2. ผู้ใช้ 1 คนสามารถมี Permission Template ได้เพียง 1 Template เท่านั้น
3. ผู้ใช้สามารถมี Extra Permission หรือ Override Permission เพิ่มเติมรายบุคคลได้
4. Permission ต้องรองรับทั้งระดับเมนู และระดับ Action
5. ผู้ที่จัดการ Permission ได้คือ Super Admin เท่านั้น
6. การลบ Permission Template ต้องเป็น Soft Delete หรือ Deactivate เท่านั้น
7. ต้องมี Template เริ่มต้น ได้แก่
- Employee / User
- Staff
- Manager
- IT Admin
- Super Admin
8. ทุกการเปลี่ยนแปลง Permission ต้องบันทึก Audit Log
9. รอบนี้ให้สร้าง `Plan.md` เท่านั้น ยังไม่ต้องแก้ไขโค้ดจริง
## Pages to Plan
### 1. Permission Template Management Page
ควรวางแผนหน้าสำหรับจัดการ Permission Template โดยรองรับ
- แสดงรายการ Template ทั้งหมด
- สร้าง Template ใหม่
- แก้ไข Template
- Clone Template
- Soft Delete / Deactivate Template
- เปิด/ปิดการใช้งาน Template
- ดูจำนวนผู้ใช้ที่ใช้งาน Template
- ดู Permission ภายใน Template
- ป้องกันการลบ Template ที่เป็น system default โดยตรง
- จำกัดการเข้าถึงเฉพาะ Super Admin
### 2. Permission Matrix Page
ควรวางแผนหน้าสำหรับจัดการ Permission แบบ Matrix
Permission ควรแบ่งตาม Module และ Action เช่น
Modules ตัวอย่าง:
- Dashboard
- Training Records
- Online Lessons
- Announcements
- Employees
- Courses
- Approvals
- Reports
- Settings
- Permission Management
Actions ตัวอย่าง:
- View
- Create
- Edit
- Delete
- Approve
- Publish
- Export
- Manage
ต้องวางแผนให้สามารถเลือก Permission ได้ทั้งระดับเมนูและระดับ Action
### 3. User Permission Assignment Page
ควรวางแผนหน้าสำหรับกำหนดสิทธิ์รายผู้ใช้ โดยรองรับ
- ค้นหาผู้ใช้
- แสดงข้อมูลผู้ใช้ เช่น รหัสพนักงาน ชื่อ แผนก ตำแหน่ง
- เลือก Permission Template ได้ 1 Template
- เพิ่ม Extra Permission รายบุคคลได้
- Override / Remove Permission บางรายการได้ หากจำเป็น
- Preview สิทธิ์สุดท้ายที่ผู้ใช้จะได้รับ
- บันทึกการเปลี่ยนแปลง
- จำกัดการเข้าถึงเฉพาะ Super Admin
### 4. Audit Log Page
ควรวางแผนหน้าสำหรับตรวจสอบประวัติการเปลี่ยนแปลงสิทธิ์ โดยรองรับ
- ผู้ที่ทำรายการ
- ผู้ใช้ที่ถูกแก้ไขสิทธิ์
- รายการก่อนแก้ไข
- รายการหลังแก้ไข
- วันที่และเวลา
- ประเภท Action เช่น create, update, clone, deactivate, assign, override
- หมายเหตุหรือเหตุผลการแก้ไข
- ค้นหาและกรองข้อมูลได้
## Technical Audit Required
ก่อนสร้าง Plan.md ให้ตรวจสอบโครงสร้างเดิมของโปรเจกต์ก่อน โดยเฉพาะ
- โครงสร้าง route ใน `src/app`
- โครงสร้าง feature modules
- ระบบ auth ปัจจุบัน
- helper เดิม เช่น `isHRD()`, `businessRole`
- permission utility เดิม เช่น `requirePermission()`
- nav config เช่น `nav-config.ts`
- hook ที่เกี่ยวกับเมนู เช่น `use-nav.ts`
- schema/model ที่เกี่ยวข้องกับ user, role, permission
- API route handlers ที่เกี่ยวข้อง
- shared components เช่น DataTable, Dialog, Sheet, Form, Badge, Button
- audit log pattern ที่มีอยู่แล้ว ถ้ามี
ห้ามเดาโครงสร้างเอง ให้ตรวจสอบจากของจริงในโปรเจกต์ก่อนเสมอ
## Plan.md Must Include
ให้สร้างไฟล์ `Plan.md` โดยมีหัวข้ออย่างน้อยดังนี้
1. Objective
2. Current System Findings
3. Existing Files / Modules Related to Role & Permission
4. Proposed Permission Model
5. Proposed Pages
6. Proposed Database / Schema Changes
7. Proposed API Routes
8. Proposed UI Components
9. Access Control Rules
10. Audit Log Strategy
11. Migration Strategy from Role-based to Permission-first
12. Implementation Phases
13. Validation & Testing Checklist
14. Risks / Edge Cases
15. Files Expected to be Created or Modified
## Important Rules
- ห้ามแก้ไขโค้ดจริงในรอบนี้
- ห้ามสร้าง migration จริง
- ห้ามลบระบบ role เดิมทันที
- ต้องคำนึงถึง compatibility mode เดิม
- ต้องออกแบบให้ Super Admin เท่านั้นที่เข้าถึงหน้าจัดการ Permission ได้
- ต้องรองรับ Permission Template 1 รายการต่อผู้ใช้ 1 คน
- ต้องรองรับ Extra Permission / Override รายบุคคล
- ต้องใช้ Soft Delete สำหรับ Template
- ต้องมี Audit Log ทุกครั้งที่มีการเปลี่ยนแปลงสิทธิ์
- ต้องเขียน Plan.md ให้ละเอียดพอสำหรับใช้เป็นแผนก่อนลงมือ Coding Phase ถัดไป
## Expected Output
หลังตรวจสอบเสร็จ ให้สร้างไฟล์:
`docs/role-permission-management-plan.md`
โดยเป็นเอกสารแผนการพัฒนา ยังไม่ต้องแก้ไขโค้ดจริง

146
plans/role-permission.md Normal file
View File

@@ -0,0 +1,146 @@
ช่วยตรวจสอบระบบ Role & Permission ของโปรเจค Training Management System โดย “ยังไม่ต้องแก้ไขโค้ด”
เป้าหมาย:
ตรวจสอบว่าแต่ละ Role ในระบบมีสิทธิ์และเมนูตรงตาม Requirement หรือไม่ และจัดทำเอกสารผลการ Review เป็นไฟล์ Markdown
Role ที่ต้องตรวจสอบ:
1. Employee
2. HRD Admin
3. IT Admin
Requirement สิทธิ์ที่ต้องตรวจสอบ:
Employee:
- เห็นเฉพาะข้อมูลของตนเอง
- เห็นเมนู Dashboard, ประวัติการอบรม, การแจ้งเตือน, โปรไฟล์
- สามารถเพิ่มประวัติการอบรมของตนเองได้
- ไม่สามารถแก้ไขข้อมูลหลังส่งแล้ว
- ไม่สามารถอนุมัติรายการอบรม
- ไม่สามารถกำหนดหมวด K/S/A
- ไม่สามารถเข้าถึงเมนูพนักงาน, หลักสูตร, รายงาน, นโยบาย, ผู้ใช้งาน, ตั้งค่าระบบ, Audit Log
HRD Admin:
- เห็นข้อมูลการอบรมของพนักงานทั้งหมด
- เห็นเมนู Dashboard, ประวัติการอบรม, หลักสูตร, Import หลักสูตร, รายงาน, นโยบาย, การแจ้งเตือน, โปรไฟล์
- สามารถตรวจสอบ/อนุมัติ/ไม่อนุมัติรายการอบรม
- สามารถกำหนดหมวด K/S/A
- สามารถแก้ไขข้อมูลการอบรมได้
- สามารถจัดการหลักสูตรและ Import หลักสูตรได้
- สามารถ Export รายงานได้
- ห้ามเห็นเมนูพนักงาน
- ห้ามเห็นเมนูผู้ใช้งาน
- ห้ามเห็นเมนูตั้งค่าระบบ
- ห้ามเห็นเมนู Audit Log
IT Admin:
- เห็นและจัดการข้อมูลได้ทั้งระบบ
- เห็นเมนู Dashboard, ผู้ใช้งาน, พนักงาน, ประวัติการอบรม, หลักสูตร, Import หลักสูตร, รายงาน, นโยบาย, ตั้งค่าระบบ, Audit Log, การแจ้งเตือน, โปรไฟล์
- สามารถจัดการผู้ใช้งานและ Role ได้
- สามารถจัดการข้อมูลพนักงานได้
- สามารถดู Audit Log ได้
- สามารถตั้งค่าระบบได้
สิ่งที่ต้องตรวจสอบในโค้ด:
1. ตรวจสอบ Sidebar/Menu config ว่าแสดงเมนูตาม Role ถูกต้องหรือไม่
2. ตรวจสอบ Route Protection ว่าแต่ละ Role เข้า URL โดยตรงได้หรือไม่
3. ตรวจสอบ Page-Level Permission ว่าหน้าแต่ละหน้าตรวจสิทธิ์ถูกต้องหรือไม่
4. ตรวจสอบ API/Server Actions/Route Handlers ว่ามีการเช็กสิทธิ์ก่อนทำงานหรือไม่
5. ตรวจสอบ Query/Data Scope ว่า Employee เห็นเฉพาะข้อมูลตัวเอง และ HRD/IT เห็นข้อมูลที่เหมาะสม
6. ตรวจสอบ Action Permission เช่น Create, Update, Delete, Approve, Export, Import
7. ตรวจสอบว่า HRD ไม่สามารถเข้าถึงเมนู/หน้า “พนักงาน” และ “ผู้ใช้งาน”
8. ตรวจสอบว่า Import พนักงานถูกนำออกแล้ว และยังเหลือเฉพาะ Import หลักสูตรหรือไม่
9. ตรวจสอบว่าไม่มีการ hardcode role แบบกระจัดกระจายโดยไม่ผ่าน helper/middleware/permission config
10. ตรวจสอบ Audit Log เฉพาะ IT Admin
ข้อจำกัดสำคัญ:
- ห้ามแก้ไขโค้ด
- ห้าม refactor
- ห้ามลบไฟล์
- ห้ามเพิ่มฟีเจอร์
- ทำเฉพาะการตรวจสอบและสรุปผลเท่านั้น
ให้สร้างไฟล์เอกสารผลการตรวจสอบที่:
docs/role-permission-review.md
โครงสร้างเอกสารที่ต้องการ:
# Role & Permission Review
## 1. Scope การตรวจสอบ
อธิบายว่าตรวจสอบส่วนใดบ้าง
## 2. Requirement Summary
สรุปสิทธิ์ของแต่ละ Role แบบตาราง
## 3. Menu Visibility Review
ตรวจสอบเมนูที่แต่ละ Role เห็นได้
ให้ทำตาราง:
- Menu
- Employee
- HRD Admin
- IT Admin
- Current Implementation
- Result: Pass / Fail / Need Review
- Note
## 4. Route Protection Review
ตรวจสอบแต่ละ route/page ว่า role ไหนเข้าได้
ให้ระบุไฟล์ที่เกี่ยวข้อง
## 5. API / Server Action Permission Review
ตรวจสอบ action หรือ API ที่เกี่ยวข้องกับ:
- training records
- approvals
- courses
- imports
- reports
- employees
- users
- settings
- audit logs
## 6. Data Scope Review
ตรวจสอบว่า:
- Employee เห็นเฉพาะข้อมูลตนเอง
- HRD เห็นข้อมูลที่ต้องใช้ในการตรวจสอบอบรม
- IT เห็นข้อมูลทั้งระบบ
## 7. Findings
ให้สรุปเป็นรายการ:
- รหัส Finding เช่น ROLE-001
- ระดับความเสี่ยง: High / Medium / Low
- รายละเอียดปัญหา
- ไฟล์ที่พบ
- ผลกระทบ
- แนวทางแก้ไขที่แนะนำ
## 8. Summary
สรุปภาพรวมว่า Role Permission ปัจจุบันถูกต้องกี่ส่วน และมีจุดไหนที่ควรแก้ไข
รูปแบบการทำงาน:
1. อ่านเอกสารโปรเจคก่อน เช่น AGENTS.md, docs/AI_DEVELOPMENT_GUIDE.md, docs/PROJECT_ARCHITECTURE.md หากมี
2. ตรวจสอบ implementation จริงในโค้ด
3. ห้ามแก้ไขไฟล์โค้ด
4. สร้างหรืออัปเดตเฉพาะไฟล์ docs/role-permission-review.md
5. หลังทำเสร็จ ให้สรุปผลสั้น ๆ ในแชท พร้อมบอก path ของไฟล์เอกสารที่สร้าง
หากพบจุดที่ควรแก้ไข ให้เขียนเป็น Recommendation เท่านั้น ห้ามแก้ไขโค้ดในรอบนี้

491
plans/rule-ai.md Normal file
View File

@@ -0,0 +1,491 @@
# Project Architecture Audit & AI Development Constitution
คุณเป็น **Senior Software Architect**, **Tech Lead**, **UI/UX Architect** และ **Full Stack Engineer**
ก่อนเริ่มแก้ไขหรือสร้างโค้ดใด ๆ ในโปรเจกต์นี้ ให้ทำการ **สำรวจ (Audit)** โปรเจกต์ทั้งหมดก่อนเสมอ และสร้างเอกสารมาตรฐานสำหรับกำหนดกฎการพัฒนา เพื่อให้ AI ทุกตัวทำงานภายใต้ Pattern เดียวกัน
---
# เป้าหมาย
โปรเจกต์นี้ต้องมี **Architecture**, **Design System**, **Folder Structure**, **Coding Style** และ **Component Pattern** ที่เป็นมาตรฐานเดียวกัน
AI ต้อง **Reuse** ทุกอย่างที่มีอยู่แล้วก่อนเสมอ
ห้ามสร้าง Pattern ใหม่
ห้ามเดา
ห้ามคิด UI ใหม่
---
# สิ่งที่ต้องดำเนินการ
## Phase 1 : Project Audit
สำรวจโปรเจกต์ทั้งหมด
วิเคราะห์
- Folder Structure
- Feature Structure
- Routing
- Shared Components
- Layout
- Hooks
- Actions
- Prisma
- Schemas
- Types
- Constants
- Utils
- Forms
- Dialogs
- Tables
- Upload
- Authentication
- Role Permission
- Design System
ให้จัดทำรายงาน
---
## Phase 2 : Identify Canonical Features
เลือก Feature ที่สมบูรณ์ที่สุดในระบบ
เช่น
- Training Records
- Employee Directory
- Announcement
ถือเป็น Canonical Feature
Feature ใหม่ทุกตัว
ต้องอ้างอิงจาก Canonical Feature
ห้ามสร้าง Pattern ใหม่
---
## Phase 3 : Generate Documentation
สร้างไฟล์
docs/AI_DEVELOPMENT_GUIDE.md
เนื้อหาต้องประกอบด้วย
- Project Architecture
- Folder Structure
- Feature Structure
- Naming Convention
- UI Pattern
- Table Pattern
- Form Pattern
- Dialog Pattern
- Server Action Pattern
- Prisma Pattern
- Shared Component Rules
- Responsive Rules
- Coding Rules
- Refactoring Rules
---
สร้างไฟล์
docs/PROJECT_ARCHITECTURE.md
อธิบาย
- Folder Structure
- Feature Dependency
- Data Flow
- Component Flow
- Shared Modules
- Feature Modules
---
สร้างไฟล์
docs/REFRACTOR_REPORT.md
ตรวจสอบ
Feature ไหนหลุด Pattern
เช่น
- สร้าง Table ใหม่
- สร้าง Pagination ใหม่
- ใช้ Dialog คนละแบบ
- ใช้ CSS คนละ Pattern
- ใช้ Form คนละ Pattern
พร้อมเสนอแนวทาง Refactor
---
## Phase 4 : Update AGENTS.md
อัปเดตไฟล์
AGENTS.md
ให้เป็น Project Constitution
โดยต้องเพิ่มกฎต่อไปนี้
---
### Highest Priority
AI ต้องปฏิบัติตามลำดับนี้
1. Existing Project Implementation
2. docs/AI_DEVELOPMENT_GUIDE.md
3. docs/PROJECT_ARCHITECTURE.md
4. AGENTS.md
5. kiranism-shadcn-dashboard
6. shadcn/ui
7. TanStack Table
8. Next.js Best Practices
หากมีข้อขัดแย้ง
ให้ใช้ลำดับที่สูงกว่าเสมอ
---
### Mandatory Audit
ก่อนแก้ไขโค้ดทุกครั้ง
AI ต้องสำรวจ
- Feature เดิม
- Shared Component
- Shared Hook
- Shared Action
- Shared Dialog
- Shared Form
- Shared Table
- Shared Layout
ก่อนเสมอ
---
### Design System
โปรเจกต์นี้ใช้
**kiranism-shadcn-dashboard**
เป็น Design System หลัก
ทุกหน้าต้องใช้ Pattern เดียวกัน
ห้ามสร้าง Dashboard Layout ใหม่
---
### Canonical Features
กำหนดให้
Training Records
เป็น Canonical Reference
ทุก Feature ใหม่
ต้อง Copy Pattern
จาก Feature นี้ก่อน
หากไม่มี
จึงค้นหา
Employee Directory
Announcement
ตามลำดับ
---
### Reuse Policy
ห้ามสร้างใหม่
ถ้ามีอยู่แล้ว
AI ต้องค้นหา
- Shared Components
- Shared Hooks
- Shared Actions
- Shared Dialogs
- Shared Forms
- Shared Tables
ก่อนเสมอ
---
### DataTable Rules
ห้ามสร้าง Table เอง
ต้อง Reuse
- DataTable
- DataTableToolbar
- DataTablePagination
- DataTableViewOptions
- DataTableColumnHeader
- CellAction
- Faceted Filters
ห้ามสร้าง
Pagination ใหม่
Toolbar ใหม่
Sorting ใหม่
View ใหม่
---
### Form Rules
ต้องใช้
- React Hook Form
- Zod
- Existing Form Components
---
### Server Action Rules
ใช้ Pattern เดิมของโปรเจกต์
เช่น
next-safe-action
ห้ามสร้าง Pattern ใหม่
---
### Dialog Rules
Reuse
Dialog
Sheet
AlertDialog
ConfirmDialog
---
### File Upload
Reuse Upload Utility เดิม
---
### Prisma
Reuse Existing Schema Pattern
---
### Folder Structure
Feature ใหม่
ต้องใช้
page.tsx
columns.tsx
form.tsx
dialog.tsx
actions.ts
schema.ts
constants.ts
types.ts
เหมือนกันทั้งหมด
---
### Naming Convention
ห้ามตั้งชื่อไฟล์ใหม่
ใช้ Naming เดียวกับทั้งโปรเจกต์
---
### Responsive Rules
ห้าม
- Overflow Page
- Broken Layout
- Clipped Button
- Broken Table
ใช้
overflow-x-auto
เฉพาะใน Table เท่านั้น
---
### Architecture Freeze
เมื่อมี Shared Component แล้ว
ทุก Feature ใหม่
ต้อง Reuse
ห้ามสร้าง Implementation ใหม่
---
### Forbidden
AI ห้าม
❌ สร้าง Table ใหม่
❌ สร้าง Toolbar ใหม่
❌ สร้าง Pagination ใหม่
❌ สร้าง Dialog ใหม่
❌ สร้าง Badge ใหม่
❌ สร้าง Form ใหม่
❌ สร้าง Upload ใหม่
❌ สร้าง Layout ใหม่
❌ สร้าง Dashboard ใหม่
❌ สร้าง Folder Structure ใหม่
❌ สร้าง Design Pattern ใหม่
---
### Required Checklist
ก่อนส่งงาน
AI ต้องตรวจสอบ
✅ Reuse Components
✅ Reuse Hooks
✅ Reuse Actions
✅ Reuse Dialog
✅ Reuse DataTable
✅ Reuse Toolbar
✅ Reuse Pagination
✅ Reuse View Options
✅ Reuse Empty State
✅ Reuse Loading
✅ Reuse Design Tokens
✅ Folder Structure ถูกต้อง
✅ Naming Convention ถูกต้อง
✅ Responsive ถูกต้อง
---
### Final Principle
Consistency is more important than creativity.
Every new feature must look like it has always been part of the project.
If a reviewer cannot distinguish which feature was added later, the implementation is correct.
---
# สิ่งที่ AI ต้องทำหลังจากสร้างเอกสาร
1. ตรวจสอบทุก Feature ที่มีอยู่ในระบบ
2. เปรียบเทียบกับ Canonical Feature
3. สร้างรายการ Feature ที่หลุด Pattern
4. เสนอแผน Refactor
5. รอการอนุมัติก่อน Refactor
---
# กฎสำคัญที่สุด
ก่อนแก้ไข Feature หรือเขียนโค้ดใหม่ทุกครั้ง
AI ต้องอ่าน
- AGENTS.md
- docs/AI_DEVELOPMENT_GUIDE.md
- docs/PROJECT_ARCHITECTURE.md
ก่อนเสมอ
หากพบว่าโค้ดที่กำลังจะแก้ไขไม่ตรงกับมาตรฐาน
ให้เสนอการ Refactor ก่อน
ห้ามขยาย Pattern ที่ผิด
ห้ามสร้าง Pattern ใหม่
ต้องใช้ Pattern ของโปรเจกต์ และ **kiranism-shadcn-dashboard** อย่างเคร่งครัด
เมื่อไม่แน่ใจ ให้สำรวจโค้ดเดิมก่อนเสมอ และเลือก Reuse มากกว่าสร้างใหม่

130
plans/sprint-4.md Normal file
View File

@@ -0,0 +1,130 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current status:
- Auth.js role mapping is completed.
- Sidebar displays menu by role.
- Employee Training Records module is completed.
- HRD Review Workflow is completed.
Current task:
Implement Sprint 4: Training Policy and Course Master Enhancement.
Important constraints:
- Do NOT change existing folder structure.
- Do NOT create a new project.
- Do NOT migrate ORM.
- Use existing Drizzle ORM.
- Use existing Auth.js session.
- Reuse existing UI components.
- Reuse existing /dashboard route structure.
- Make minimal-impact changes only.
Part 1: Training Policy Module
Requirements:
1. Create Training Policy page.
Route:
/dashboard/training-policy
2. HRD can create and update yearly training policy.
Fields:
- year
- totalHours
- kHours
- sHours
- aHours
- isActive
3. Validation:
- year is required.
- totalHours is required.
- kHours is required.
- sHours is required.
- aHours is required.
- kHours + sHours + aHours must equal totalHours.
4. Default policy example:
- Total Hours = 30
- K = 12
- S = 12
- A = 6
5. Dashboard must use Training Policy instead of hardcoded values.
6. Only HRD can access and manage Training Policy.
Part 2: Course Master Enhancement
Requirements:
1. Update existing Course Master without changing module structure.
2. Ensure Course Master supports these fields:
- courseCode
- courseName
- description
- defaultCategory (K/S/A)
- defaultHours
- provider
- status
- mandatory
- certificateRequired
- validityMonths
- trainingCost
3. If existing fields already exist, reuse them.
4. If field names differ, map them carefully.
5. Do not remove existing course data.
6. Add Zod validation.
7. Add create/edit/list UI fields.
8. Add loading, empty, success, and error states.
Part 3: Output Review File
After implementing code changes, create a review output file in the project:
Path:
docs/sprint-4-training-policy-course-master-review.md
The file must include:
1. Summary of changes
2. Files changed
3. Database changes
4. Migration commands
5. New routes
6. Validation rules
7. Permission rules
8. Manual test checklist
9. Known limitations
10. Next recommended sprint
Manual Test Checklist must include:
- HRD can open Training Policy page.
- Employee cannot open Training Policy page.
- HRD can create policy.
- HRD can edit policy.
- System blocks invalid K/S/A sum.
- Dashboard uses policy values.
- HRD can create course.
- HRD can edit course.
- Course Master supports certificateRequired.
- Course Master supports trainingCost.
Return:
- Complete code changes with file paths.
- Content of docs/sprint-4-training-policy-course-master-review.md.
- Any commands required to run migration.

View File

@@ -0,0 +1,181 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current status:
- Sprint 4 is completed.
- Auth.js role mapping is completed.
- Sidebar displays menu by role.
- Employee Training Records module is completed.
- HRD Review Workflow is completed.
Current task:
Implement Sprint 5:
Employee Import, Master Review, and Thai UI Localization.
Important constraints:
- Do NOT change folder structure.
- Do NOT migrate ORM.
- Do NOT rename database tables.
- Do NOT rename database columns.
- Do NOT rename routes.
- Do NOT rename enum values.
- Use existing Drizzle ORM.
- Use existing Auth.js.
- Reuse existing UI components.
- Make minimal-impact changes only.
Part 1: Employee Import
Route:
- /dashboard/import-employees
Requirements:
1. HRD can upload Excel (.xlsx).
2. HRD can download import template.
3. Validate imported rows.
4. Import employee records.
5. Show import result summary.
Import fields:
- Employee Code
- Employee Name
- Email
- Company
- Department
- Position
- Status
Thai template headers:
- รหัสพนักงาน
- ชื่อพนักงาน
- อีเมล
- บริษัท
- แผนก
- ตำแหน่ง
- สถานะ
Part 2: Master Review
Route:
- /dashboard/master-review
Requirements:
1. Show pending companies.
2. Show pending departments.
3. Show pending positions.
4. HRD can approve or reject pending master records.
5. Approved records become active master data.
Thai labels:
- รอตรวจสอบข้อมูลหลัก
- บริษัท
- แผนก
- ตำแหน่ง
- อนุมัติ
- ไม่อนุมัติ
Part 3: Thai UI Localization
Convert all visible UI text to Thai across the existing TMS system.
Scope:
1. Sidebar menu labels
2. Page titles
3. Form labels
4. Table headers
5. Buttons
6. Status badges
7. Toast messages
8. Validation messages
9. Empty states
10. Loading states
11. Error states
12. Dashboard cards
13. Export headers
14. Import template headers
Important:
Keep internal values in English.
Examples:
- PENDING_REVIEW should display as "รอตรวจสอบ"
- APPROVED should display as "อนุมัติแล้ว"
- REJECTED should display as "ไม่อนุมัติ"
- ONLINE should display as "ออนไลน์"
- ONSITE should display as "อบรม ณ สถานที่"
- INTERNAL should display as "ภายในองค์กร"
- EXTERNAL should display as "ภายนอกองค์กร"
- K should display as "Knowledge (ความรู้)"
- S should display as "Skill (ทักษะ)"
- A should display as "Attitude (ทัศนคติ)"
Recommended approach:
1. Create or update a central label mapping file, for example:
src/constants/thai-labels.ts
2. Reuse label helper functions across modules:
- getTrainingStatusLabel()
- getTrainingTypeLabel()
- getTrainingCategoryLabel()
- getRoleLabel()
3. Avoid hardcoding repeated Thai labels in multiple files.
Part 4: Output Review File
Create:
docs/sprint-5-employee-import-master-review-thai-localization.md
The review file must include:
1. Summary
2. Files changed
3. Database changes
4. Routes added
5. Thai localization changes
6. Label mapping added
7. Import template format
8. Validation rules
9. Permission rules
10. Manual test checklist
11. Known limitations
12. Next recommended sprint
Manual test checklist must include:
- HRD can open Employee Import page.
- Employee cannot open Employee Import page.
- HRD can download Thai Excel template.
- HRD can upload employee Excel.
- System validates required fields.
- System shows import result in Thai.
- New company/department/position becomes pending master review.
- HRD can open Master Review page.
- HRD can approve pending master data.
- HRD can reject pending master data.
- Sidebar menu is displayed in Thai.
- Training status badges are displayed in Thai.
- Training type labels are displayed in Thai.
- Form validation messages are displayed in Thai.
- Toast messages are displayed in Thai.
- Dashboard labels are displayed in Thai.
- Existing routes still work.
Return:
- Complete code changes with file paths.
- Content of docs/sprint-5-employee-import-master-review-thai-localization.md.
- Any migration command if required.

View File

@@ -0,0 +1,248 @@
You are a Senior Full Stack Engineer and Solution Architect.
Project:
Training Management System (TMS)
Current status:
Sprint 6.11 Identity / Employee Cleanup completed.
Current task:
Implement Sprint 6.12 Employee Ownership Final Migration and Employee Directory Data Source Validation.
Goal:
Finish migration from user-owned training data to employee-owned training data for employee directory, dashboard, reports, and remaining aggregation paths.
Important constraints:
- Do NOT break existing credential login.
- Do NOT remove legacy columns yet.
- Do NOT remove users.employeeCode fallback yet unless fully safe.
- Do NOT change business features.
- Keep Auth.js working.
- Keep Drizzle ORM.
- Keep Thai UI.
- Minimal-impact changes only.
Part 0: Employee Directory Data Source Validation
Update:
- src/features/employee-directory/server/employee-directory-data.ts
- src/app/dashboard/employee-directory/page.tsx
- src/app/dashboard/employee-directory/[id]/page.tsx
- related employee directory components
Requirements:
1. Employee Directory list must use employees as the primary source.
The page:
- รายชื่อพนักงานทั้งหมด
Must read from:
- employees
Not from:
- users
2. Employee Directory table must show:
- รหัสพนักงาน from employees.employeeCode
- ชื่อพนักงาน from employees.displayName or firstNameTh + lastNameTh
- ฝ่าย/แผนก from employees.departmentId / department relation
- ตำแหน่ง from employees.positionId / position relation
3. Employee Directory detail must use employees as the primary source.
Detail page must show:
ข้อมูลทั่วไปพนักงาน:
- employeeCode
- displayName
- email
- companyName / company
- department
- position
- status
4. Training summary must use:
- training_records.employee_id = employees.id
Calculate:
- approved hours
- pending hours
- rejected hours
- total submitted hours
- K/S/A approved hours
5. Target resolution must use:
Priority:
1. employee_training_targets.employee_id
2. training_policy default
Do not use userId target resolution as primary.
6. Search must use employees fields:
Search by:
- employees.employeeCode
- employees.displayName
- employees.email
- department name
- position name
7. Filters must use employees fields:
- department
- position
- status
- company if available
8. Permission:
HRD/Admin:
- can access employee directory
Employee:
- cannot access employee directory by menu or direct URL
9. Do not require employee to have user account.
Important:
An employee imported into employees but without a linked user account must still appear in Employee Directory.
Part 1: Overview Dashboard Migration
Update:
- src/features/overview/server/overview-data.ts
Requirements:
1. Employee dashboard must resolve current employee through:
- user_employee_maps
- fallback users.employeeId if still exists
- fallback users.employeeCode only if needed
2. Employee dashboard must aggregate from:
- employees
- training_records.employee_id
3. HRD dashboard must use:
- employees as employee source
- training_records.employee_id as training ownership source
4. Pass/fail calculation must use:
- employee_training_targets.employee_id if exists
- fallback Training Policy
5. Avoid using users as the primary employee source.
Part 2: Reports Migration
Update:
- src/features/reports/server/report-data.ts
- src/app/api/reports/export/route.ts if needed
Requirements:
1. Employee Transcript:
- Employee users see only their mapped employee record.
- HRD/Admin can view organization employees.
- Data source must be employees + training_records.employee_id.
2. Training Matrix:
- Use employees + training_records.employee_id.
- Keep existing matrix behavior.
3. Department Summary:
- Count employees from employees table.
- Aggregate training hours from training_records.employee_id.
4. Annual Summary:
- Aggregate by employee-owned training records.
5. Export Excel/PDF must remain working.
Part 3: Employee Target Resolution
Update:
- src/features/training-policy/server/employee-training-target-data.ts
Requirements:
1. Resolve target by employeeId first.
2. Fallback to policy.
3. Avoid userId target resolution except legacy compatibility.
Part 4: Reduce Legacy Dependency
Search and review remaining usage of:
- users.employeeCode
- users.employeeId
- training_records.userId
Do not delete them yet.
Create a list of:
- still required
- can be migrated later
- safe to remove in future cleanup
Part 5: Regression
Validate:
- Employee login
- Employee dashboard
- HRD dashboard
- Employee Directory list
- Employee Directory detail
- Employee imported without user appears in Employee Directory
- Employee transcript
- Department summary
- Annual summary
- Training matrix
- Training record create
- HRD review
- Import employee
- Employee target import
Part 6: Output Review File
Create:
docs/sprint-6-12-employee-ownership-final-migration-review.md
Include:
1. Summary
2. Files Changed
3. Employee Directory Data Source Validation
4. Overview Migration
5. Reports Migration
6. Target Resolution Changes
7. Remaining Legacy Dependencies
8. Regression Checklist
9. Risks
10. Recommendation Before Sprint 7.2
Return:
- Complete code changes with file paths
- Review file
- Migration commands if required

View File

@@ -0,0 +1,155 @@
You are a Senior Full Stack Engineer and QA Engineer.
Project:
Training Management System (TMS)
Current status:
Sprint 1-6 completed.
Pre-UAT Readiness Review completed.
Before starting Sprint 7, fix all remaining important issues.
Current task:
Implement Sprint 6.5: Pre-Sprint 7 Hardening.
Important constraints:
- Do NOT add new business features.
- Do NOT change folder structure.
- Do NOT migrate ORM unless absolutely necessary.
- Do NOT rename tables or columns.
- Do NOT break existing routes.
- Reuse existing Auth.js.
- Reuse existing Drizzle ORM.
- Keep Thai UI.
- Keep responsive/mobile behavior.
- Minimal-impact changes only.
Priority 1: Notification Pagination Optimization
Problem:
Notification listing currently loads all matching rows, filters in memory, then slices for pagination.
Requirements:
1. Move notification pagination to database query level.
2. Use WHERE, ORDER BY, LIMIT, OFFSET at SQL/Drizzle level.
3. Keep existing search, read/unread filter, and type filter behavior.
4. Keep ownership check:
- organizationId
- userId
5. Preserve unread count accuracy.
6. Preserve header notification popover behavior.
7. Do not break Notification Center page.
Files likely involved:
- src/features/notifications/server/notification-data.ts
- src/app/api/notifications/route.ts
- src/features/notifications/api/types.ts
- src/features/notifications/api/service.ts
Priority 2: Announcement Route Loading/Error Coverage
Problem:
Announcement route segment does not have route-level loading.tsx and error.tsx.
Requirements:
1. Add route-level loading and error pages:
- src/app/dashboard/announcements/loading.tsx
- src/app/dashboard/announcements/error.tsx
- src/app/dashboard/announcements/[id]/loading.tsx
- src/app/dashboard/announcements/[id]/error.tsx
2. Use Thai UI.
3. Follow existing loading/error pattern from other dashboard modules.
4. Keep responsive layout.
Priority 3: RBAC Documentation Update
Problem:
docs/nav-rbac.md is outdated and still references Clerk/client-side authorization.
Requirements:
1. Update docs/nav-rbac.md to reflect current architecture:
- Auth.js
- Server-side authorization
- requireOrganizationAccess()
- requireHRD()
- requireEmployeeDashboardAccess()
- role-based sidebar filtering
- proxy.ts route protection
2. Remove outdated Clerk references.
3. Document:
- Employee access
- HRD access
- API protection
- direct URL protection
- file download protection
4. Keep the document clear and suitable for maintenance.
Priority 4: Browser Smoke Test Checklist
Create a smoke test checklist for:
- Chrome
- Microsoft Edge
Test areas:
Employee:
1. Login
2. View dashboard
3. Create training record
4. Upload certificate
5. Open/download certificate
6. Edit pending training record
7. Delete pending training record
8. View notification
9. View announcement
HRD:
1. Login
2. Open dashboard
3. Review pending training
4. Approve training
5. Reject training
6. Create announcement
7. Open/download announcement attachment
8. Import employee
9. Master review approve/reject
10. View audit logs
11. Export audit log CSV
Priority 5: Output Review File
Create:
docs/sprint-6-5-pre-sprint-7-hardening-review.md
The file must include:
1. Summary
2. Files Changed
3. Issues Fixed
4. Notification Pagination Optimization
5. Announcement Loading/Error Coverage
6. RBAC Documentation Update
7. Browser Smoke Test Checklist
8. Validation Result
9. Remaining Risks
10. Sprint 7 Readiness Score
Validation:
- Run typecheck
- Run lint
- Confirm no new migration is required unless changed
- Confirm existing routes still work
Return:
- Complete code changes with file paths
- Content of docs/sprint-6-5-pre-sprint-7-hardening-review.md
- Any remaining issues

135
plans/sprint-6-phase-1.md Normal file
View File

@@ -0,0 +1,135 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current status:
- Sprint 5 approved
- Responsive Audit approved
- Mobile UX Review approved
Current task:
Implement Sprint 6 Phase 1:
Audit Log Foundation
Important constraints:
- Do NOT change folder structure.
- Do NOT migrate ORM.
- Do NOT rename tables.
- Do NOT rename columns.
- Reuse existing Auth.js.
- Reuse existing Drizzle ORM.
- Reuse existing UI components.
- Keep Thai UI.
- Minimal-impact changes only.
Requirements:
1. Create Audit Log module.
Route:
- /dashboard/audit-logs
2. Create reusable audit service.
Example:
logAuditEvent({
userId,
module,
action,
entityId,
oldValue,
newValue,
ipAddress
})
3. Track:
Authentication
- LOGIN_SUCCESS
- LOGIN_FAILED
Training Records
- CREATE
- UPDATE
- DELETE
HRD Review
- APPROVE
- REJECT
Course Master
- CREATE
- UPDATE
Training Policy
- CREATE
- UPDATE
Employee Import
- IMPORT
Master Review
- APPROVE
- REJECT
4. Audit Log UI
Columns:
- วันที่
- ผู้ใช้งาน
- โมดูล
- รายการ
- รายละเอียด
5. Filters
- วันที่
- ผู้ใช้งาน
- โมดูล
- รายการ
6. Search
7. Export CSV
8. Thai UI
9. Role
HRD only
10. Output Review File
Create:
docs/sprint-6-phase-1-audit-log-review.md
Include:
1. Summary
2. Files Changed
3. Database Changes
4. Events Implemented
5. Permission Rules
6. Manual Test Checklist
7. Known Limitations
8. Next Phase Recommendation
Return:
- Complete code changes
- Review file
- Migration commands if required

206
plans/sprint-6-phase-2.md Normal file
View File

@@ -0,0 +1,206 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current status:
- Sprint 6 Phase 1 Audit Log Foundation is completed and approved.
- Audit service logAuditEvent(...) is available.
- Auth.js, RBAC, Thai localization, responsive layout, and mobile UX are already completed.
Current task:
Implement Sprint 6 Phase 2:
Notification Center
Important constraints:
- Do NOT change folder structure.
- Do NOT migrate ORM.
- Do NOT rename tables.
- Do NOT rename columns.
- Do NOT break existing routes.
- Reuse existing Auth.js.
- Reuse existing Drizzle ORM.
- Reuse existing UI components.
- Keep Thai UI.
- Keep responsive/mobile behavior.
- Minimal-impact changes only.
- Reuse existing Audit Log service for important notification actions.
Part 1: Notification Data Layer
Requirements:
1. Use existing notifications table if available.
2. If notifications table already exists, reuse it.
3. Do not create a new schema unless absolutely necessary.
4. Notification fields should support:
- id
- userId
- title
- message
- type
- referenceType
- referenceId
- isRead
- readAt
- createdAt
Part 2: Notification Service
Create reusable service functions:
- createNotification()
- createTrainingApprovedNotification()
- createTrainingRejectedNotification()
- createAnnouncementNotification()
- createImportCompletedNotification()
- createMasterReviewNotification()
- markNotificationAsRead()
- markAllNotificationsAsRead()
Notification types:
- TRAINING_APPROVED
- TRAINING_REJECTED
- ANNOUNCEMENT_PUBLISHED
- IMPORT_COMPLETED
- MASTER_REVIEW_APPROVED
- MASTER_REVIEW_REJECTED
- SYSTEM
Part 3: Integrate Notification Events
Add notification creation to existing workflows:
1. HRD approves training record
- Notify employee
- Title: รายการอบรมได้รับการอนุมัติ
- Message should include course name, category, and approved hours
2. HRD rejects training record
- Notify employee
- Title: รายการอบรมไม่ผ่านการอนุมัติ
- Message should include course name and reject reason
3. Employee import completed
- Notify HRD user who performed import
- Include total, success, failed count
4. Master review approved/rejected
- Notify HRD user who performed action
- Include master type and action result
Important:
- Do not implement Email notification in this phase.
- In-app notification only.
Part 4: Notification Center UI
Route:
- /dashboard/notifications
Requirements:
1. User can view own notifications.
2. HRD and Employee both can access notifications.
3. Show unread count.
4. Show list ordered by latest first.
5. Support filter:
- All
- Unread
- Read
- Type
6. Support search by title/message.
7. Support mark one as read.
8. Support mark all as read.
9. Support click notification to open related reference if reference route is known.
10. Use Thai labels.
11. Add loading state.
12. Add empty state.
13. Add error state.
14. Responsive/mobile friendly.
Part 5: Header / Sidebar Badge
Requirements:
1. Show unread notification badge in header or sidebar if existing notification UI exists.
2. Badge should show unread count.
3. Do not break existing header responsive behavior.
Part 6: Permissions
Rules:
1. User can only see their own notifications.
2. User can only mark their own notifications as read.
3. HRD cannot read another user's notifications from the notification center unless explicitly implemented later.
4. APIs must enforce user ownership server-side.
Part 7: Audit Log
Use existing logAuditEvent(...) for:
- NOTIFICATION_MARK_READ
- NOTIFICATION_MARK_ALL_READ
- NOTIFICATION_CREATE if created manually or system-level
Do not audit every automatic notification if it creates too much noise, but audit mark-read actions and system notifications.
Part 8: API Routes / Actions
Implement or reuse routes/actions:
- GET /api/notifications
- PATCH /api/notifications/[id]/read
- PATCH /api/notifications/read-all
If existing API path differs, reuse the existing pattern.
Part 9: Output Review File
Create:
docs/sprint-6-phase-2-notification-review.md
The review file must include:
1. Summary
2. Files Changed
3. Database Changes
4. Routes Added
5. Notification Events Implemented
6. Permission Rules
7. Audit Events Added
8. Thai Localization Changes
9. Responsive/Mobile Notes
10. Manual Test Checklist
11. Known Limitations
12. Next Phase Recommendation
Manual Test Checklist must include:
- Employee can see only own notifications.
- HRD can see only own notifications.
- Training approved creates notification for employee.
- Training rejected creates notification for employee.
- Import completed creates notification for HRD.
- Master review action creates notification for HRD.
- Unread count displays correctly.
- Mark as read works.
- Mark all as read works.
- Search works.
- Filter unread/read works.
- Notification center works on mobile.
- Direct API access cannot read other users' notifications.
- Audit log records mark read actions.
Return:
- Complete code changes with file paths.
- Content of docs/sprint-6-phase-2-notification-review.md.
- Migration commands if required.

126
plans/sprint-6-phase-3.md Normal file
View File

@@ -0,0 +1,126 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current status:
Sprint 6 Phase 1 Audit Log is completed.
Sprint 6 Phase 2 Notification Center is completed.
Current task:
Implement Sprint 6 Phase 3:
Announcement Module.
Important constraints:
- Do NOT change folder structure.
- Do NOT migrate ORM.
- Reuse existing Auth.js.
- Reuse existing Drizzle ORM.
- Reuse existing Notification Service.
- Reuse existing Audit Log Service.
- Keep Thai UI.
- Keep responsive/mobile support.
- Minimal-impact changes only.
Part 1: Announcement Module
Route:
- /dashboard/announcements
- /dashboard/announcements/[id]
Requirements:
1. HRD can:
- Create
- Edit
- Publish
- Pin
- Archive
2. Employee can:
- View published announcements
3. Announcement fields:
- title
- content
- attachment
- status
- isPinned
- startDate
- endDate
- createdBy
4. Status:
- DRAFT
- PUBLISHED
- ARCHIVED
5. Add search.
6. Add filter.
7. Add pagination.
8. Add responsive support.
9. Add Thai UI.
Part 2: Notification Integration
When announcement is published:
Use:
createAnnouncementNotification()
Notify users about new announcement.
Part 3: Audit Log Integration
Create events:
- ANNOUNCEMENT_CREATE
- ANNOUNCEMENT_UPDATE
- ANNOUNCEMENT_PUBLISH
- ANNOUNCEMENT_ARCHIVE
Use existing logAuditEvent() service.
Part 4: Permissions
HRD:
- Full access
Employee:
- View published only
Part 5: Output Review File
Create:
docs/sprint-6-phase-3-announcement-review.md
Include:
1. Summary
2. Files Changed
3. Database Changes
4. Routes Added
5. Notification Integration
6. Audit Events Added
7. Permission Rules
8. Responsive Notes
9. Thai Localization Notes
10. Manual Test Checklist
11. Known Limitations
12. Next Phase Recommendation
Return:
- Complete code changes
- Review file
- Migration commands if required

108
plans/sprint-6-phase-4.md Normal file
View File

@@ -0,0 +1,108 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current status:
Sprint 6 Phase 1 Audit Log completed.
Sprint 6 Phase 2 Notification Center completed.
Sprint 6 Phase 3 Announcement Module completed.
Current task:
Implement Sprint 6 Phase 4:
Dashboard Enhancement.
Important constraints:
- Do NOT change folder structure.
- Do NOT migrate ORM.
- Reuse existing overview/dashboard module.
- Reuse existing charts.
- Reuse existing UI components.
- Keep Thai UI.
- Keep responsive support.
- Minimal-impact changes only.
Part 1: Employee Dashboard
Add KPI Cards:
- Approved Hours
- Pending Hours
- Rejected Hours
- Completion Percentage
Add K/S/A Progress section.
Add Recent Activity section.
Part 2: HRD Dashboard
Add KPI Cards:
- Total Employees
- Employees Passed Target
- Employees Not Passed Target
- Pending Review Count
Add Charts:
- K/S/A Distribution
- Monthly Training Trend
- Department Ranking
- Top Courses
Part 3: Dashboard Filters
Employee:
- Year
HRD:
- Year
- Company
- Department
Part 4: Performance
Use database aggregation.
Avoid loading all records into memory.
Part 5: Responsive
Support:
- 360px
- 390px
- 412px
- 768px
- 1024px
- 1440px
Part 6: Output Review File
Create:
docs/sprint-6-phase-4-dashboard-review.md
Include:
1. Summary
2. Files Changed
3. Database Queries Added
4. KPI Cards Added
5. Charts Added
6. Filters Added
7. Responsive Notes
8. Performance Notes
9. Manual Test Checklist
10. Known Limitations
11. Go-Live Readiness Score
Return:
- Complete code changes
- Review file
- Any migration commands if required

81
plans/sprint-7-phase-1.md Normal file
View File

@@ -0,0 +1,81 @@
You are a Senior Full Stack Engineer.
Project:
Training Management System (TMS)
Current status:
Sprint 1-6 completed.
Sprint 6.5 Hardening completed.
UAT Seed Data completed.
Current task:
Implement Sprint 7 Phase 1:
Reports Enhancement.
Important constraints:
- Do NOT change folder structure.
- Do NOT migrate ORM.
- Reuse existing report module if available.
- Reuse existing Auth.js.
- Reuse existing Drizzle ORM.
- Keep Thai UI.
- Keep responsive/mobile support.
- Use database aggregation.
- Minimal-impact changes only.
Reports:
1. Employee Training Transcript
2. Training Matrix
3. Department Summary
4. Annual Training Summary
Requirements:
- Excel Export
- PDF Export
Filters:
- Year
- Company
- Department
Additional:
Employee:
- View own transcript only
HRD:
- View organization-wide reports
Performance:
- Use SQL aggregation
- Avoid in-memory report generation
Output:
docs/sprint-7-phase-1-reports-review.md
Include:
1. Summary
2. Files Changed
3. Database Queries Added
4. Reports Added
5. Export Features
6. Permission Rules
7. Responsive Notes
8. Manual Test Checklist
9. Known Limitations
10. Sprint 7.2 Recommendation
Return:
- Complete code changes
- Review file
- Migration commands if required

View File

@@ -0,0 +1,892 @@
# Task: Refactor Staff Course Page Filters to Single Select
## Context
ในส่วนของเจ้าหน้าที่ หน้าหลักสูตร (Courses) ยังใช้ Filter รูปแบบเก่า ซึ่งอาจเป็น Multi Select, Faceted Filter, Dropdown แบบ Checkbox หรือ Component เดิมที่ไม่เป็นมาตรฐานเดียวกับหน้ารายชื่อพนักงานและหน้าอื่นของระบบ
ต้องปรับ Filter ในหน้าหลักสูตรให้เป็นรูปแบบ **Select แบบเลือกได้เพียง 1 ค่าในแต่ละ Filter (Single Select)** และทำให้การทำงานสอดคล้องกับมาตรฐาน Filter ของระบบ
งานนี้ต้องแก้ไขครบทั้ง
- UI
- Filter state
- URL Search Params
- Server-side filtering
- API validation
- Pagination
- Sorting
- Empty state
- Responsive
- Automated tests
- Legacy code cleanup
ห้ามแก้เฉพาะหน้าตาของ Component โดยไม่ตรวจสอบ Logic ฝั่ง Backend และผลกระทบที่เกี่ยวข้อง
---
# Objective
1. เปลี่ยน Filter เก่าของหน้าหลักสูตรเป็น Single Select
2. แต่ละ Filter เลือกได้เพียง 1 ค่า
3. ใช้ Component และรูปแบบเดียวกับ Filter มาตรฐานของระบบ
4. URL Search Params ต้องเก็บค่าเดียวต่อ Filter
5. Backend ต้องรองรับ Single Value อย่างถูกต้อง
6. เมื่อเปลี่ยน Filter ต้อง Reset Pagination ไปหน้าแรก
7. Refresh หน้าแล้วค่าที่เลือกต้องยังคงแสดงตาม URL
8. Search, Sorting และ Pagination เดิมต้องทำงานร่วมกับ Filter ได้
9. ลบ Logic Multi Select หรือ Legacy Filter ที่ไม่ใช้งานแล้ว
10. ไม่กระทบ Permission และสิทธิ์การเข้าถึงหน้าหลักสูตร
---
# Phase 1: Inspect Before Editing
ก่อนแก้ไข ให้ตรวจสอบโครงสร้างปัจจุบันของหน้าหลักสูตรและรายงานสั้น ๆ ว่า
1. Route ของหน้าหลักสูตรอยู่ที่ใด
2. Toolbar หรือ Filter Component อยู่ไฟล์ใด
3. Table state ถูกจัดการด้วยวิธีใด
4. ใช้ TanStack Table, URL Search Params หรือ Local State หรือไม่
5. Filter ปัจจุบันเป็น Component ประเภทใด
6. Filter ใดเป็น Multi Select หรือ Faceted Filter
7. Search Params ปัจจุบันมีชื่ออะไร
8. API หรือ Server Action ใดรับค่าจาก Filter
9. Backend ปัจจุบันรองรับค่าแบบ Array, CSV หรือ Single Value
10. มี Shared Filter Component มาตรฐานในระบบอยู่แล้วหรือไม่
11. หน้า Employee Directory หรือ Online Lessons ใช้ Component ใดเป็นตัวอย่าง
12. มี Test เดิมที่เกี่ยวข้องหรือไม่
ให้ใช้โครงสร้างเดิมของโปรเจกต์เป็นหลัก และหลีกเลี่ยงการสร้าง Abstraction ใหม่โดยไม่จำเป็น
---
# Phase 2: Target Filters
ตรวจสอบ Filter ทั้งหมดที่มีอยู่จริงในหน้าหลักสูตร เช่น
- หมวดหมู่
- สถานะ
- ประเภท
- ผู้ให้บริการ
- Mandatory
- Certificate Required
- บริษัท
- ปี
- หรือ Filter อื่นที่ระบบมีอยู่จริง
ปรับ Filter ทุกตัวที่เป็นข้อมูลแบบเลือกหนึ่งค่าให้เป็น **Single Select**
## Default Policy
Filter ประเภทต่อไปนี้ให้เป็น Single Select โดยค่าเริ่มต้น
- Category
- Status
- Type
- Provider
- Mandatory
- Certificate Required
- Company
- Year
- Course state หรือ Active state
ห้ามคง Multi Select ไว้ เว้นแต่พบ Business Requirement ในโค้ดหรือเอกสารที่ระบุชัดเจนว่าต้องเลือกหลายค่า
หากพบ Filter ที่จำเป็นต้องเป็น Multi Select จริง ให้ยังไม่เปลี่ยนโดยพลการ และบันทึกไว้ใน Final Report พร้อมเหตุผล
---
# Phase 3: UI Requirements
## 3.1 Replace Legacy Filter
เปลี่ยน Component เดิม เช่น
- Faceted Filter
- Checkbox Dropdown
- Multi Select
- Command Menu แบบเลือกหลายค่า
- Badge Filter
- Popover Filter แบบ Toggle หลายค่า
ให้เป็น Select แบบเลือกได้เพียง 1 ค่า
ควรใช้ Component มาตรฐานของโปรเจกต์ เช่น
```tsx
<Select>
<SelectTrigger>
<SelectValue placeholder="เลือกหมวดหมู่" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all"></SelectItem>
...
</SelectContent>
</Select>
```
หากโปรเจกต์มี Shared Single Select Component อยู่แล้ว ให้ใช้ของเดิมแทนการสร้างใหม่
---
## 3.2 Required Placeholders
กำหนดข้อความ Placeholder ตาม Filter ที่มีจริง เช่น
- หมวดหมู่: `เลือกหมวดหมู่`
- สถานะ: `เลือกสถานะ`
- ประเภท: `เลือกประเภท`
- ผู้ให้บริการ: `เลือกผู้ให้บริการ`
- บริษัท: `เลือกบริษัท`
- ปี: `เลือกปี`
ข้อความต้องเป็นภาษาเดียวกับหน้าเดิมและใช้คำศัพท์เดียวกับระบบ
---
## 3.3 All Option
ทุก Filter ต้องสามารถกลับไปแสดงข้อมูลทั้งหมดได้
ใช้รูปแบบใดรูปแบบหนึ่งตามมาตรฐานโปรเจกต์
```text
ทั้งหมด
```
หรือ
```text
ทุกสถานะ
ทุกหมวดหมู่
```
ห้ามใช้ค่า `undefined` เป็น `SelectItem value` หาก Component ไม่รองรับ
สามารถใช้ค่าภายใน เช่น
```ts
const ALL_FILTER_VALUE = "all";
```
แล้วแปลงกลับเป็น `undefined` ก่อนอัปเดต URL หรือส่ง API
---
## 3.4 Single Selection
ในแต่ละ Filter
- เลือกได้เพียงค่าเดียว
- เมื่อเลือกค่าใหม่ ให้แทนค่าก่อนหน้า
- ห้ามแสดง Checkbox หลายรายการ
- ห้ามเก็บค่าเป็น Array
- ห้ามแสดงหลาย Badge ใน Filter เดียว
- ห้ามส่งค่าหลายรายการใน Query String
---
## 3.5 Toolbar Layout
จัด Toolbar ให้เป็นมาตรฐานเดียวกับหน้า Employee Directory หรือหน้าที่ใช้ Filter มาตรฐานล่าสุด
ลำดับที่แนะนำ
```text
[ค้นหาหลักสูตร] [หมวดหมู่] [สถานะ] [Filter อื่น] [ล้างตัวกรอง]
```
ข้อกำหนด
- Search อยู่ด้านซ้าย
- Filter เรียงต่อจาก Search
- ปุ่มล้างตัวกรองอยู่ท้ายแถว
- Select แต่ละตัวมีความกว้างเหมาะสมและสม่ำเสมอ
- ใช้ `flex-wrap`
- ไม่ล้น Container
- ไม่เกิด Horizontal Scroll ที่ Toolbar
ตัวอย่าง Class ที่พิจารณาใช้ได้ตาม Design System เดิม
```tsx
className = "flex flex-wrap items-center gap-2";
```
และ Select Trigger อาจใช้
```tsx
className = "w-full sm:w-[180px]";
```
ห้ามบังคับใช้ Class นี้หากขัดกับ Component มาตรฐานเดิมของโปรเจกต์
---
## 3.6 Active Filter Visibility
ผู้ใช้ต้องมองเห็นค่าที่กำลังเลือกอยู่จาก Select Trigger โดยตรง
ไม่จำเป็นต้องสร้าง Badge ซ้ำอีก เว้นแต่ระบบมีมาตรฐาน Active Filter Summary อยู่แล้ว
---
# Phase 4: Filter State Refactor
เปลี่ยน State จากรูปแบบหลายค่า เช่น
```ts
categories: string[];
statuses: string[];
selectedCategories: Set<string>;
selectedStatuses: Set<string>;
```
เป็นค่าเดียว เช่น
```ts
category?: string;
status?: string;
provider?: string;
company?: string;
year?: string;
```
หรือใช้ Type ที่เหมาะสมกับข้อมูลจริง เช่น
```ts
type CourseCategory = "K" | "S" | "A";
type CourseStatus = "active" | "inactive" | "draft";
```
ห้ามใช้ `any`
---
# Phase 5: URL Search Params Standard
## 5.1 Single Value Params
แต่ละ Filter ต้องใช้ Query Parameter ค่าเดียว เช่น
```text
/dashboard/courses?category=K
/dashboard/courses?status=active
/dashboard/courses?provider=internal
/dashboard/courses?category=K&status=active
```
ห้ามใช้รูปแบบ
```text
category=K,S
category[]=K&category[]=S
categories=K|S
status=active,inactive
```
---
## 5.2 Preserve Other Params
เมื่อเปลี่ยน Filter ต้องรักษา Parameter อื่นที่ยังเกี่ยวข้อง เช่น
- search
- sort
- pageSize
- company
- year
แต่ต้อง Reset
```text
page=1
```
ทุกครั้งที่ Search หรือ Filter เปลี่ยน
---
## 5.3 Remove Empty Params
เมื่อเลือก `ทั้งหมด`
ให้ลบ Parameter นั้นออกจาก URL
ตัวอย่าง
จาก
```text
/dashboard/courses?category=K&status=active
```
เมื่อเลือกหมวดหมู่ทั้งหมด ให้เหลือ
```text
/dashboard/courses?status=active
```
ห้ามคงค่า
```text
category=all
category=
category=undefined
category=null
```
ใน URL เว้นแต่โครงการมี Standard ระบุไว้ชัดเจน
---
## 5.4 Browser Navigation
ต้องรองรับ
- Refresh หน้า
- Back
- Forward
- Copy URL แล้วเปิดใหม่
โดย Select ต้องแสดงค่าตรงกับ URL เสมอ
---
# Phase 6: Search Behavior
Search หลักสูตรต้องยังทำงานร่วมกับ Filter ได้
ข้อกำหนด
- ใช้ Debounce ตามมาตรฐานเดิมของระบบ
- เมื่อ Search เปลี่ยน ให้ Reset หน้าเป็น 1
- Search และ Filter ต้องใช้พร้อมกันได้
- ห้ามทำ Request ซ้ำโดยไม่จำเป็น
- ห้ามเกิด Race Condition
- ห้าม Search ด้วยค่าก่อนหน้า หลัง URL เปลี่ยนแล้ว
หากหน้าเดิมใช้ Submit Search แบบกด Enter และเป็นมาตรฐานของโปรเจกต์ ให้คง Behavior เดิม ไม่ต้องเปลี่ยนเป็น Auto Search โดยไม่มีเหตุผล
---
# Phase 7: Backend and Data Query
ตรวจสอบทุกชั้นที่เกี่ยวข้อง ได้แก่
- Page searchParams
- Parser
- Zod schema
- Query DTO
- Repository
- Data access
- API route
- Server Action
- SQL/ORM query
- Count query
- Export query หากใช้ Filter ชุดเดียวกัน
## 7.1 Accept Single Value
Backend ต้องรับค่าเดียว เช่น
```ts
category?: string;
status?: string;
```
ไม่ใช่
```ts
category?: string[];
status?: string[];
```
---
## 7.2 Remove Array Logic
หากมี Logic เช่น
```ts
value.split(",");
Array.isArray(value);
inArray(column, values);
values.map(...);
```
ให้ตรวจสอบและ Refactor เป็นเงื่อนไขค่าเดียว เช่น
```ts
eq(courses.category, category);
```
หรือ ORM syntax ที่โปรเจกต์ใช้อยู่
ห้ามลบ `inArray` ที่ใช้กับเงื่อนไขอื่นซึ่งยังจำเป็น
---
## 7.3 Validation
ปรับ Zod Schema หรือ Parser ให้รองรับค่าที่อนุญาตเท่านั้น
ตัวอย่าง
```ts
const categorySchema = z.enum(["K", "S", "A"]).optional();
```
```ts
const statusSchema = z.enum(["active", "inactive"]).optional();
```
กรณีได้รับค่าที่ไม่ถูกต้อง ให้ใช้พฤติกรรมตามมาตรฐานระบบ เช่น
- Ignore invalid filter
- Return 400
- Redirect to sanitized URL
เลือกให้สอดคล้องกับ Module อื่น ห้ามสร้าง Behavior ใหม่เฉพาะหน้าหลักสูตร
---
## 7.4 Query Count Consistency
Query สำหรับนับจำนวนรายการและ Query สำหรับดึงข้อมูลต้องใช้ Filter ชุดเดียวกัน
เพื่อป้องกันปัญหา
- จำนวนรวมไม่ตรงกับข้อมูล
- Pagination แสดงหน้ามากเกินจริง
- หน้าเปล่าทั้งที่ Total มากกว่า 0
---
# Phase 8: Pagination and Sorting
## Pagination
เมื่อเปลี่ยน
- Search
- Category
- Status
- Filter อื่น
ต้องกลับหน้า 1
เมื่อเปลี่ยน Page Size ให้กลับหน้า 1 ตามมาตรฐานระบบ
## Sorting
- Sorting เดิมต้องยังทำงาน
- เปลี่ยน Filter แล้วไม่จำเป็นต้องล้าง Sorting
- Refresh หน้าแล้ว Sorting ต้องยังตรงกับ URL หากระบบเก็บ Sorting ใน URL
- Query ต้อง Apply Filter และ Sort อย่างถูกลำดับ
---
# Phase 9: Reset Filters
เพิ่มหรือปรับปุ่ม
```text
ล้างตัวกรอง
```
ให้แสดงเฉพาะเมื่อมี Search หรือ Filter ที่ Active อย่างน้อยหนึ่งรายการ
เมื่อกดแล้วต้อง
1. ล้าง Search
2. ล้าง Category
3. ล้าง Status
4. ล้าง Filter อื่นทั้งหมดของหน้าหลักสูตร
5. Reset หน้าเป็น 1
6. รักษา Page Size ตามมาตรฐานเดิม
7. ล้าง Search Params ที่เกี่ยวข้อง
8. Reload ข้อมูลทั้งหมด
9. Select ทุกตัวกลับเป็นค่า `ทั้งหมด`
หากหน้ามีปุ่ม Reset เดิม ให้ปรับของเดิม ไม่สร้างซ้ำ
---
# Phase 10: Empty State
แยก Empty State อย่างน้อย 2 กรณี
## ไม่มีข้อมูลหลักสูตรในระบบ
```text
ยังไม่มีข้อมูลหลักสูตร
```
และคง Action สร้างหลักสูตรตาม Permission เดิม
## มีข้อมูลแต่ไม่ตรงกับตัวกรอง
```text
ไม่พบหลักสูตรที่ตรงกับเงื่อนไขการค้นหา
```
พร้อมปุ่ม
```text
ล้างตัวกรอง
```
ปุ่มดังกล่าวต้องใช้ Reset Logic เดียวกับ Toolbar
---
# Phase 11: Permission Safety
ห้ามเปลี่ยนหรือทำให้ Permission ของหน้าหลักสูตรอ่อนลง
ต้องคงหลักการ
- `courses:read` สำหรับการอ่าน
- `courses:write` สำหรับสร้าง แก้ไข ลบ หรือ Action ที่เปลี่ยนข้อมูล
- ผู้ใช้ที่อ่านได้แต่เขียนไม่ได้ ต้องเห็น Filter และรายการได้
- ปุ่มสร้าง แก้ไข ลบ ต้องแสดงตาม Write Permission
- API Mutation ต้องตรวจ Permission ฝั่ง Server เสมอ
การปรับ Filter ห้ามกลับไปใช้ `requireHRD()` หรือ Role-based Guard หาก Module ถูกปรับเป็น Permission-first แล้ว
---
# Phase 12: Shared Filter Standardization
ตรวจสอบว่าหน้าหลักสูตรสามารถใช้ Shared Component หรือ Shared Utility ที่มีอยู่แล้วได้หรือไม่ เช่น
```tsx
<FilterToolbar />
<SingleSelectFilter />
<ResetFiltersButton />
```
หรือ Hook เช่น
```ts
useTableFilters();
useQueryState();
useFilterSearchParams();
```
หลักการ
- ใช้ของเดิมหากรองรับ Requirement
- ปรับปรุง Shared Component ได้ หากไม่ทำให้หน้าอื่น Regression
- ห้ามสร้าง Shared Component ที่ซับซ้อนเกินความจำเป็น
- ห้ามรวม Business Logic ของ Course เข้าไปใน Generic Component
- Generic Component ควรรับ Options, Value, Placeholder และ Callback ผ่าน Props
---
# Phase 13: Legacy Cleanup
หลังแก้ไข ให้ลบเฉพาะโค้ดที่ไม่ใช้งานแล้ว เช่น
- Multi Select state
- Checkbox Filter
- Faceted Filter config
- Array query parser
- CSV serialization
- Unused imports
- Dead utility
- Unused type
- Duplicate Reset handler
ห้ามลบ Shared Component เดิม หากยังมีหน้าอื่นใช้งาน
---
# Phase 14: Responsive and Accessibility
## Responsive
ตรวจสอบอย่างน้อย
- Desktop
- Tablet
- Mobile
Toolbar ต้อง
- Wrap ได้
- ไม่ล้น
- Select ใช้งานได้
- Search ไม่แคบจนอ่านไม่ได้
- ปุ่ม Reset ไม่ทับกับ Component อื่น
## Accessibility
Select ต้องมี
- Label หรือ Accessible Name
- `aria-label` เมื่อไม่มี Label ที่มองเห็น
- Keyboard navigation
- Focus state
- Disabled state ที่ถูกต้อง
- ไม่ใช้สีเป็นข้อมูลเพียงอย่างเดียว
---
# Phase 15: Testing Requirements
เพิ่มหรือปรับ Test ตาม Test Framework ที่โปรเจกต์ใช้อยู่
## Unit Tests
ทดสอบอย่างน้อย
1. Parser รับค่า Category ค่าเดียว
2. Parser รับค่า Status ค่าเดียว
3. ค่า `all` ถูกแปลงเป็น `undefined`
4. Invalid enum ถูกจัดการถูกต้อง
5. Reset ล้างเฉพาะ Filter ที่เกี่ยวข้อง
6. เปลี่ยน Filter แล้ว Page กลับเป็น 1
## Component Tests
ทดสอบอย่างน้อย
1. Select แสดง Placeholder
2. เลือกค่าได้เพียง 1 ค่า
3. เลือกค่าใหม่แทนค่าเดิม
4. ค่าใน Select ตรงกับ URL
5. Reset แล้วกลับเป็นทั้งหมด
6. ปุ่ม Reset แสดงเมื่อมี Active Filter
7. ปุ่ม Reset ซ่อนเมื่อไม่มี Active Filter
## Integration Tests
ทดสอบอย่างน้อย
1. Search + Category ทำงานร่วมกัน
2. Category + Status ทำงานร่วมกัน
3. Filter + Sorting ทำงานร่วมกัน
4. Filter + Pagination ทำงานร่วมกัน
5. Refresh แล้วยังคง Filter
6. Back/Forward อัปเดต Select ถูกต้อง
7. Total Count ตรงกับรายการ
8. Empty State ถูกต้อง
## Permission Tests
ทดสอบอย่างน้อย
1. ผู้มี `courses:read` เปิดหน้าและใช้งาน Filter ได้
2. ผู้ไม่มี `courses:read` เข้าไม่ได้
3. ผู้มี Read แต่ไม่มี Write ไม่เห็น Action เขียนข้อมูล
4. Filter ไม่ทำให้ API Mutation ข้าม Permission
---
# Phase 16: Manual Verification Scenarios
ทดสอบด้วย Browser ตามกรณีต่อไปนี้
## Scenario A: No Filter
- เปิดหน้าหลักสูตร
- เห็นข้อมูลทั้งหมด
- Select ทุกตัวแสดง `ทั้งหมด` หรือ Placeholder
- URL ไม่มี Filter Param ที่ว่างเปล่า
## Scenario B: Category
- เลือก K
- URL มี `category=K`
- ตารางแสดงเฉพาะ K
- Pagination กลับหน้า 1
## Scenario C: Change Selection
- จาก K เปลี่ยนเป็น S
- URL เปลี่ยนเป็น `category=S`
- ไม่มีค่า K ค้างอยู่
- ไม่เกิด Query แบบหลายค่า
## Scenario D: Combined Filters
- เลือก Category และ Status
- ตารางต้องตรงทั้งสองเงื่อนไข
- Total Count ถูกต้อง
## Scenario E: Clear One Filter
- เลือก Category เป็น `ทั้งหมด`
- ลบเฉพาะ `category` จาก URL
- Status และ Search ยังอยู่
## Scenario F: Reset All
- กดล้างตัวกรอง
- Search และทุก Select ถูกล้าง
- กลับหน้า 1
- ตารางแสดงทั้งหมด
## Scenario G: Refresh
- เลือก Filter
- Refresh หน้า
- Select และข้อมูลยังตรงกับ URL
## Scenario H: Mobile
- Toolbar Wrap ถูกต้อง
- Select เปิดและเลือกได้
- ไม่มี Horizontal Overflow
---
# Acceptance Criteria
ถือว่างานเสร็จเมื่อผ่านครบทุกข้อ
- หน้าหลักสูตรใช้ Select แทน Filter แบบเก่า
- Filter ที่กำหนดเลือกได้เพียง 1 ค่า
- ไม่มี Checkbox Multi Select ใน Filter ที่ถูกปรับ
- State ไม่ใช้ Array สำหรับ Single Select
- URL เก็บเพียงค่าเดียวต่อ Filter
- เลือก `ทั้งหมด` แล้วลบ Parameter ออกจาก URL
- เปลี่ยน Filter แล้ว Reset หน้าเป็น 1
- Search ทำงานร่วมกับ Filter
- Sorting ทำงานร่วมกับ Filter
- Pagination ทำงานถูกต้อง
- Total Count ตรงกับข้อมูล
- Refresh แล้วยังคง Filter
- Back/Forward ทำงานถูกต้อง
- Reset Filter ทำงานครบ
- Empty State ถูกต้อง
- Responsive
- Accessibility ผ่าน
- Permission เดิมไม่เสีย
- ไม่มี Console Error
- ไม่มี React Warning
- ไม่มี Hydration Error
- ไม่มี TypeScript Error
- ไม่มี ESLint Error
- Test ที่เกี่ยวข้องผ่าน
- Production Build ผ่าน
---
# Commands to Run
ตรวจสอบ `package.json` และใช้คำสั่งจริงของโปรเจกต์
อย่างน้อยต้องรัน
```bash
npm run lint
npm run typecheck
npm run test
npm run build
```
หากโปรเจกต์ใช้ `pnpm`, `yarn` หรือ `bun` ให้ใช้ Package Manager เดิมของโปรเจกต์
หากไม่มี Script บางรายการ ห้ามสร้างคำสั่งปลอม ให้รายงานตามจริงว่าใช้คำสั่งใดแทน
---
# Constraints
1. ห้ามแก้ Database Schema หากไม่จำเป็น
2. ห้ามเปลี่ยน Permission Model
3. ห้ามลด Server-side Authorization
4. ห้ามแก้ API Contract อื่นที่ไม่เกี่ยวข้อง
5. ห้ามสร้าง Component ซ้ำ หากมี Shared Component รองรับ
6. ห้ามเปลี่ยนทุก Filter ทั้งระบบโดยไม่มีการตรวจสอบ Regression
7. ห้ามใช้ `any` เพื่อหลบ TypeScript
8. ห้ามซ่อน Error ด้วย `eslint-disable` หรือ `@ts-ignore`
9. ห้ามเปลี่ยน Business Logic ของหลักสูตร
10. ห้ามลบ Feature เดิม เช่น Search, Sorting, Pagination, Export
11. ห้ามถือว่างานเสร็จจาก UI อย่างเดียว
12. ห้ามแก้ข้อมูล Production หรือ Seed Data โดยไม่จำเป็น
---
# Required Final Report
หลังดำเนินการเสร็จ ให้ตอบกลับด้วยรายงานตามหัวข้อต่อไปนี้
## 1. Root Cause
อธิบายว่า Filter เดิมใช้รูปแบบใด และเหตุใดจึงยังเป็นรูปแบบเก่า
## 2. Files Changed
แสดงรายการไฟล์ที่แก้ไข พร้อมสรุปหน้าที่ของแต่ละไฟล์
## 3. Filters Updated
แสดงตาราง
| Filter | Before | After | URL Param |
| -------- | ------------ | ------------- | ---------- |
| Category | Multi Select | Single Select | `category` |
| Status | Multi Select | Single Select | `status` |
ให้ใช้รายการ Filter จริงที่พบในระบบ
## 4. Frontend Changes
สรุป
- Component ที่ใช้
- State ที่เปลี่ยน
- Reset behavior
- Responsive behavior
## 5. Backend Changes
สรุป
- Parser
- Validation
- Query conditions
- Count query
- API compatibility
## 6. Legacy Cleanup
ระบุโค้ด Multi Select หรือ Array Logic ที่ลบออก
## 7. Permission Verification
ยืนยันว่า `courses:read/write` ยังคงถูกใช้ถูกต้องทั้ง UI และ Server
## 8. Tests Added or Updated
แสดง Test Cases และผลลัพธ์
## 9. Validation Results
รายงานผลจริงของ
```text
Lint:
Typecheck:
Tests:
Build:
```
ห้ามรายงานว่า Pass หากไม่ได้รันจริง
## 10. Remaining Issues
ระบุสิ่งที่ยังไม่ได้แก้ พร้อมเหตุผล หากไม่มีให้ระบุ
```text
ไม่พบประเด็นคงค้างในขอบเขตงานนี้
```
---
# Definition of Done
งานนี้จะถือว่าเสร็จสมบูรณ์เมื่อหน้าหลักสูตรของเจ้าหน้าที่ใช้ Filter แบบ Single Select อย่างครบถ้วนทั้ง UI และ Backend มีพฤติกรรมสอดคล้องกับมาตรฐาน Filter ของระบบ ไม่เกิด Regression และผ่านการตรวจสอบตาม Acceptance Criteria ทั้งหมด

453
plans/system-test-flow.md Normal file
View File

@@ -0,0 +1,453 @@
# Training System Test Flow
เอกสารนี้ใช้สำหรับทดสอบระบบตามโครงสร้างล่าสุดของโปรเจ็กต์:
- `Super Admin` จัดการ `Organizers`
- `Admin` จัดการ `Users`, `Courses`, `Training Records`, `Training Matrix`, `Reports`
- `User` เห็นเฉพาะ `Dashboard`, `Training Records`, `Reports`
- ใช้ `users` เป็น person entity เดียวของระบบแล้ว ไม่ใช้ `employees` เป็น runtime module
## 1. Scope
ครอบคลุม flow หลักดังนี้:
- Authentication และ organizer access
- Organizer management
- User management
- Course management
- Training record CRUD
- Certificate upload
- Approval workflow
- Training matrix
- Dashboard
- Reports และ CSV export
- RBAC และ data scoping
## 2. Test Prerequisites
ก่อนเริ่มทดสอบ ให้ตรวจสอบว่า:
- ตั้งค่า `.env.local` แล้ว
- PostgreSQL ทำงานได้
- migrations ถูก apply แล้ว
- dev server รันได้ด้วย `npm run dev`
- มีข้อมูล master ของ `departments` และ `positions`
บัญชีทดสอบที่แนะนำ:
- `super_admin` 1 คน
- `admin` 1 คน
- `user` 1 คน
ข้อมูลทดสอบขั้นต่ำ:
- 1 organizer
- 2 departments
- 2 positions
- 3 users
- 3 courses
## 3. Recommended Test Order
1. Auth and access
2. Organizer management
3. User management
4. Courses
5. Training records
6. Certificates
7. Approval workflow
8. Training matrix
9. Dashboard
10. Reports
11. RBAC regression
## 4. Auth And Access
### 4.1 Sign In
ทดสอบ:
- เปิด `/auth/sign-in`
- login ด้วย `super_admin`
- login ด้วย `admin`
- login ด้วย `user`
ผลที่คาดหวัง:
- `super_admin` เข้า organizer flow ได้
- `admin` เข้า `/dashboard/overview` ได้
- `user` เข้า `/dashboard/overview` ได้
### 4.2 Sign Up Disabled
ทดสอบ:
- เปิด `/auth/sign-up`
- เรียก `POST /api/auth/register`
ผลที่คาดหวัง:
- ผู้ใช้สมัครเองไม่ได้
- ระบบแจ้งชัดว่าต้องให้ admin สร้างบัญชีให้
### 4.3 Protected Routes
ทดสอบ:
- logout
- เปิด `/dashboard/overview`
- เรียก `/api/users`
ผลที่คาดหวัง:
- หน้า dashboard redirect ไป sign-in
- protected API ตอบ `401`
## 5. Organizer Flow
ใช้ `super_admin`
### 5.1 Organizer List
ทดสอบ:
- เปิด `/dashboard/organizers`
ผลที่คาดหวัง:
- เห็นรายการ organizer ทั้งหมด
### 5.2 Create Organizer
ทดสอบ:
- สร้าง organizer ใหม่
ผลที่คาดหวัง:
- สร้าง organizer สำเร็จ
- master data ของ organizer ใหม่ถูก seed ให้
## 6. User Flow
ใช้ `admin` หรือ `super_admin`
### 6.1 User List
ทดสอบ:
- เปิด `/dashboard/users`
- search
- filter status
- sort
- pagination
ผลที่คาดหวัง:
- ตารางโหลดข้อมูลได้
- filter และ sort ทำงานถูกต้อง
### 6.2 Create User
ทดสอบ:
- กดเพิ่ม user
- กรอก `full name`, `email`, `phone`, `employee code`
- เลือก `department` จาก dropdown
- เลือก `position` จาก dropdown
- ระบุ `hired date`
- สำหรับ `super_admin` ให้เลือก organizer ได้
- สำหรับ `admin` organizer ต้อง default จาก active organizer
ผลที่คาดหวัง:
- สร้าง user สำเร็จ
- user ใหม่มี membership ใน organizer ที่เลือก
### 6.3 Edit User
ทดสอบ:
- แก้ไข department, position, role, status
ผลที่คาดหวัง:
- ข้อมูลอัปเดตสำเร็จ
## 7. Sidebar Visibility
### 7.1 Super Admin
ผลที่คาดหวัง:
- เห็น `Dashboard`, `Organizers`, `Users`, `Courses`, `Training Records`, `Training Matrix`, `Reports`
### 7.2 Admin
ผลที่คาดหวัง:
- เห็น `Dashboard`, `Users`, `Courses`, `Training Records`, `Training Matrix`, `Reports`
- ไม่เห็น `Organizers`
### 7.3 User
ผลที่คาดหวัง:
- เห็นเฉพาะ `Dashboard`, `Training Records`, `Reports`
## 8. Course Flow
ใช้ `admin`
### 8.1 Course List And Filters
ทดสอบ:
- เปิด `/dashboard/courses`
- search
- filter category
- filter status
ผลที่คาดหวัง:
- ตารางแสดงผลถูกต้อง
### 8.2 Create And Edit Course
ทดสอบ:
- สร้าง course ใหม่
- แก้ไขข้อมูล course
ผลที่คาดหวัง:
- create/update สำเร็จ
## 9. Training Record Flow
### 9.1 Admin Creates Training Record
ใช้ `admin`
ทดสอบ:
- เปิด `/dashboard/training-records`
- สร้าง record ใหม่
- เลือก `user`
- เลือก `course`
- กรอก date, type, hours, organizer, note
ผลที่คาดหวัง:
- สร้าง record สำเร็จ
- status เริ่มที่ `pending`
### 9.2 User Creates Own Training Record
ใช้ `user`
ทดสอบ:
- เปิด `/dashboard/training-records`
- สร้าง record ใหม่
ผลที่คาดหวัง:
- dropdown `user` ต้องมองเห็นได้เฉพาะตัวเอง
- สร้าง record ของคนอื่นไม่ได้
### 9.3 List And Edit
ทดสอบ:
- list records
- filter by status
- filter by type
- เปิดหน้า detail/edit
ผลที่คาดหวัง:
- `admin` เห็นทุก record ใน organizer
- `user` เห็นเฉพาะ record ของตัวเอง
## 10. Certificate Flow
### 10.1 Upload Certificate
ทดสอบ:
- เปิดหน้า edit training record
- อัปโหลด `pdf`, `jpg`, `jpeg`, `png`
ผลที่คาดหวัง:
- upload สำเร็จ
- metadata ถูกบันทึก
### 10.2 View And Delete
ทดสอบ:
- เปิดดูไฟล์ย้อนหลัง
- ลบ certificate
ผลที่คาดหวัง:
- เปิดไฟล์ได้
- ลบแล้วรายการหาย
## 11. Approval Workflow
### 11.1 Admin Review
ใช้ `admin`
ทดสอบ:
- เปิด `/dashboard/training-records?status=pending`
- `Approve`
- `Reject`
- `Request Changes`
- ใส่ reviewer note
ผลที่คาดหวัง:
- เปลี่ยน status ได้
- reviewer note ถูกบันทึก
### 11.2 User Restrictions
ใช้ `user`
ทดสอบ:
- พยายาม review record
- พยายามแก้ approved record
ผลที่คาดหวัง:
- review ไม่ได้
- approved record แก้ไม่ได้ตาม policy
## 12. Training Matrix
ใช้ `admin`
### 12.1 Create Rules
ทดสอบ:
- เปิด `/dashboard/training-matrix`
- เพิ่ม rule แบบ department -> course
- เพิ่ม rule แบบ position -> course
- กำหนด renewal period
ผลที่คาดหวัง:
- สร้าง rules สำเร็จ
### 12.2 Compliance
ทดสอบ:
- user ที่มี approved records ครบ
- user ที่ยังขาด course
- user ที่มี course หมดอายุ
ผลที่คาดหวัง:
- compliance คำนวณถูกต้อง
- missing courses แสดงถูกต้อง
## 13. Dashboard
### 13.1 Admin Dashboard
ใช้ `admin`
ผลที่คาดหวัง:
- เห็นภาพรวมระดับ organizer
- summary cards, charts, recent activity ใช้ข้อมูลจริง
### 13.2 User Dashboard
ใช้ `user`
ผลที่คาดหวัง:
- เห็นเฉพาะข้อมูลของตัวเอง
- ไม่เห็น organizer-wide management views
## 14. Reports
### 14.1 Admin Reports
ใช้ `admin`
ทดสอบ:
- เปิด `/dashboard/reports`
- filter ตาม user
- filter ตาม department
- filter ตาม expiring days
ผลที่คาดหวัง:
- ตารางรายงานอัปเดตตาม filter
- export CSV ได้
### 14.2 User Reports
ใช้ `user`
ทดสอบ:
- เปิด `/dashboard/reports`
- ทดลองแก้ query string เอง
ผลที่คาดหวัง:
- เห็นเฉพาะข้อมูลของตัวเอง
- server บังคับ self-scope แม้ปรับ URL เอง
- export CSV ได้เฉพาะข้อมูลของตัวเอง
## 15. RBAC Regression
### 15.1 Cross-Organizer Isolation
ทดสอบ:
- login ด้วย user ของ organizer A
- พยายามเปิดข้อมูลของ organizer B
ผลที่คาดหวัง:
- มองไม่เห็นข้อมูลข้าม organizer
### 15.2 Legacy Employee Routes
ทดสอบ:
- เปิด `/dashboard/employees`
- เปิด `/dashboard/employees/new`
ผลที่คาดหวัง:
- ระบบพาไปหน้า `/dashboard/users`
## 16. Final Regression Checklist
- sign-in / sign-out ทำงาน
- sign-up ถูกปิด
- sidebar แยกตาม role ถูกต้อง
- organizer flow ใช้งานได้
- users ใช้งานได้
- courses ใช้งานได้
- training-records ใช้งานได้
- certificate upload ใช้งานได้
- approval workflow ใช้งานได้
- training matrix ใช้งานได้
- dashboard ใช้งานได้
- reports และ CSV export ใช้งานได้
- `npm run build` ผ่าน

View File

@@ -0,0 +1,529 @@
# Prompt: ตรวจสอบการแสดงผลของระบบเทียบกับ Permission โดยยังไม่แก้ไขโค้ด
## เป้าหมาย
ให้ตรวจสอบระบบทั้งหมดว่า การแสดงผลของหน้า เมนู ปุ่ม ข้อมูล ฟิลด์ และ Action ต่าง ๆ สอดคล้องกับ Permission และ Role ที่ระบบกำหนดไว้จริงหรือไม่
งานนี้เป็น **Audit / Review เท่านั้น**
ห้ามแก้ไขโค้ด ห้ามเปลี่ยน Permission และห้ามปรับพฤติกรรมของระบบในขั้นตอนนี้
ผลลัพธ์ที่ต้องการคือรายงานปัญหา พร้อมหลักฐาน ตำแหน่งโค้ด ผลกระทบ และแนวทางแก้ไขสำหรับนำไปดำเนินการในขั้นตอนถัดไป
---
## ขอบเขตการตรวจสอบ
ตรวจสอบทั้งระบบ ครอบคลุมอย่างน้อยดังนี้
- Sidebar และ Navigation
- Dashboard
- หน้ารายการ
- หน้ารายละเอียด
- หน้าสร้างข้อมูล
- หน้าแก้ไขข้อมูล
- Dialog, Modal, Drawer, Sheet และ Dropdown Menu
- ปุ่ม Action ในตาราง
- ปุ่มสร้าง แก้ไข ลบ ส่งตรวจสอบ อนุมัติ ปฏิเสธ ส่งกลับ และเผยแพร่
- ข้อมูลภายใน Card, Table, Form และ Detail Section
- หมายเหตุการตรวจสอบ
- ประวัติการอนุมัติ
- Audit Log
- API Route
- Server Action
- Query และ Service Layer
- Middleware
- Route Guard
- Permission Helper
- Role Guard
- Component Guard
- Backend Authorization
ให้ตรวจสอบทุกโมดูลที่มีอยู่ในระบบ เช่น
- ผู้ใช้งานและพนักงาน
- ประวัติการอบรม
- บทเรียนออนไลน์
- ประกาศ
- การแจ้งเตือน
- นโยบาย
- การอนุมัติ
- รายงาน
- ตั้งค่าระบบ
- Audit Log
- โมดูลอื่น ๆ ที่ค้นพบในโครงการ
---
## Role และ Permission
ให้ค้นหา Role และ Permission จากโค้ดจริงก่อนเริ่มตรวจสอบ เช่น
- User / Employee
- Admin
- HRD Staff
- HRD Manager
- IT Admin
- Reviewer
- Approver
- Role อื่น ๆ ที่ระบบมีอยู่จริง
ห้ามสมมติชื่อ Role หรือ Permission จากเอกสารเพียงอย่างเดียว
ให้ค้นหาแหล่งกำหนด Permission ทั้งหมด เช่น
- Enum
- Constant
- Permission Matrix
- Database Schema
- Seed Data
- Middleware
- Session
- JWT
- Auth.js callback
- Route configuration
- Sidebar configuration
- Helper function เช่น `hasPermission`, `canAccess`, `canManage`
- Server-side authorization
- Client-side conditional rendering
จากนั้นจัดทำ Permission Matrix ที่อ้างอิงจากโค้ดจริงก่อนตรวจสอบหน้าจอ
---
## หลักการตรวจสอบ
การตรวจสอบต้องครอบคลุมทั้งสองระดับ
### 1. การแสดงผลฝั่ง Client
ตรวจสอบว่า Role หรือ Permission แต่ละประเภทเห็นเฉพาะสิ่งที่ควรเห็นหรือไม่ เช่น
- เมนูที่ไม่มีสิทธิ์ถูกซ่อนหรือไม่
- ปุ่มที่ไม่มีสิทธิ์ถูกซ่อนหรือ Disable อย่างถูกต้องหรือไม่
- ข้อมูลภายในหน้ารายละเอียดถูกกรองตามสิทธิ์หรือไม่
- ฟิลด์ภายใน Form แสดงตาม Role หรือ Status หรือไม่
- Action Menu แสดงเฉพาะ Action ที่ทำได้จริงหรือไม่
- ข้อความ หมายเหตุ และประวัติภายในระบบเปิดเผยเกินสิทธิ์หรือไม่
### 2. การบังคับสิทธิ์ฝั่ง Server
ห้ามสรุปว่าระบบปลอดภัยเพียงเพราะซ่อนปุ่มหรือซ่อนเมนูแล้ว
ต้องตรวจสอบด้วยว่า ผู้ไม่มีสิทธิ์สามารถเรียกใช้งานผ่าน URL, API, Server Action หรือ Request โดยตรงได้หรือไม่ เช่น
- เปิด URL โดยตรง
- เรียก API โดยตรง
- ส่ง Request จาก DevTools
- แก้ไข Parameter
- เปลี่ยน Record ID
- เรียก Server Action โดยไม่ผ่าน UI
- เข้าถึงข้อมูลของผู้ใช้งานรายอื่น
- แก้ไขข้อมูลของผู้ใช้งานรายอื่น
- เรียก Action ที่ UI ซ่อนไว้
---
## ประเด็นสำคัญที่ต้องตรวจสอบ
### A. เมนูและเส้นทาง
ตรวจสอบว่า
- Sidebar แสดงเมนูตาม Permission
- ผู้ไม่มีสิทธิ์ไม่สามารถเข้าหน้าผ่าน URL โดยตรง
- Route Guard และ Middleware ใช้เงื่อนไขเดียวกับ Sidebar
- ไม่มีหน้าที่ซ่อนเมนูแต่ยังเข้าผ่าน URL ได้
- ไม่มีหน้าที่ Sidebar แสดงให้เห็น แต่เข้าใช้งานจริงไม่ได้
- Redirect และ Forbidden Page ทำงานสม่ำเสมอ
### B. ปุ่มและ Action
ตรวจสอบทุก Action เช่น
- สร้าง
- บันทึกฉบับร่าง
- แก้ไข
- ลบ
- ส่งตรวจสอบ
- อนุมัติ
- ปฏิเสธ
- ส่งกลับแก้ไข
- เผยแพร่
- ยกเลิกเผยแพร่
- ปักหมุด
- นำเข้า
- ส่งออก
- ดาวน์โหลด
- จัดการ Permission
ตรวจสอบว่า
- ปุ่มแสดงเฉพาะ Role ที่มีสิทธิ์
- Action สอดคล้องกับสถานะข้อมูล
- Backend ตรวจ Permission ซ้ำ
- ไม่สามารถข้าม Workflow ได้
- ไม่มี Action ที่ UI แสดงแต่ Backend ปฏิเสธโดยไม่ตั้งใจ
- ไม่มี Action ที่ UI ซ่อน แต่ Backend ยังอนุญาต
### C. การแสดงข้อมูลละเอียดอ่อน
ตรวจสอบข้อมูลที่อาจไม่ควรแสดงแก่ผู้ใช้งานทั่วไป เช่น
- หมายเหตุการตรวจสอบ
- เหตุผลการปฏิเสธ
- Internal Comment
- Reviewer Note
- Approval Note
- Audit Log
- ชื่อผู้อนุมัติ
- ประวัติการแก้ไข
- Metadata ภายใน
- Permission หรือ Role ภายใน
- ข้อมูลพนักงานรายอื่น
- ข้อมูลสถานะภายใน Workflow
ให้ตรวจสอบเป็นพิเศษว่า หน้าผู้ใช้งานทั่วไปมีการแสดง “หมายเหตุการตรวจสอบ” หรือข้อมูลภายในของเจ้าหน้าที่โดยไม่ตั้งใจหรือไม่
### D. Ownership และขอบเขตข้อมูล
ตรวจสอบว่า
- ผู้ใช้งานทั่วไปเห็นเฉพาะข้อมูลของตนเอง
- เจ้าหน้าที่เห็นข้อมูลตามบริษัท ฝ่าย หรือขอบเขตที่กำหนด
- Reviewer และ Approver เห็นเฉพาะรายการที่เกี่ยวข้อง
- Admin เห็นข้อมูลทั้งหมดตามที่ออกแบบ
- การเปลี่ยน ID ใน URL หรือ Request ไม่ทำให้เข้าถึงข้อมูลของผู้อื่น
- Query มีเงื่อนไขกรองตาม Ownership และ Permission
- การ Export ไม่ส่งออกข้อมูลเกินสิทธิ์
- Search และ Filter ไม่สามารถใช้ดึงข้อมูลนอกขอบเขต
### E. Workflow และ Status
ตรวจสอบ Permission ร่วมกับสถานะ เช่น
- Draft
- Pending
- Submitted
- Approved
- Rejected
- Returned
- Published
- Archived
- Cancelled
- สถานะอื่นที่มีอยู่จริง
ตัวอย่างการตรวจสอบ
- เจ้าของรายการแก้ไขได้เฉพาะ Draft หรือ Returned หรือไม่
- เมื่อส่งตรวจสอบแล้ว ผู้ใช้งานยังแก้ไขได้หรือไม่
- ผู้ใช้งานเห็นรายการ Rejected หรือ Returned ตามที่กำหนดหรือไม่
- Reviewer เห็นรายการที่ต้องตรวจสอบจริงหรือไม่
- Approver สามารถอนุมัติรายการที่ยังไม่ถึงขั้นตนเองหรือไม่
- รายการ Published แสดงแก่ผู้ใช้งานตามเงื่อนไขหรือไม่
- การแสดงปุ่มสอดคล้องกับ Permission และ Status พร้อมกันหรือไม่
---
## วิธีดำเนินการ
### ขั้นตอนที่ 1: สำรวจโครงสร้าง Permission
ค้นหาและสรุป
- Role ทั้งหมด
- Permission ทั้งหมด
- Mapping ระหว่าง Role และ Permission
- Permission Helper ทั้งหมด
- Route Guard
- API Guard
- Server Action Guard
- Ownership Rule
- Status Rule
### ขั้นตอนที่ 2: จัดทำ Permission Matrix
จัดทำตารางในรูปแบบประมาณนี้
| Module | Page / Action | User | Staff | Manager | Admin | เงื่อนไขเพิ่มเติม |
| -------------- | -------------------- | ---------: | ----: | ------: | ------: | ----------------------- |
| Online Lessons | ดูรายการเผยแพร่ | Yes | Yes | Yes | Yes | เฉพาะ Published |
| Online Lessons | ดูหมายเหตุการตรวจสอบ | No | Yes | Yes | Yes | ผู้ใช้งานทั่วไปห้ามเห็น |
| Online Lessons | แก้ไข Draft | Owner only | Yes | Yes | Yes | ตาม Ownership |
| Online Lessons | อนุมัติ | No | No | Yes | ตามระบบ | Pending เท่านั้น |
ให้ใช้ Role จริงจากระบบแทนตัวอย่างข้างต้น
### ขั้นตอนที่ 3: ตรวจสอบ UI กับ Matrix
ตรวจสอบทุกหน้าและ Component ว่า
- Render Condition ถูกต้องหรือไม่
- ใช้ Permission Helper มาตรฐานหรือไม่
- มีการ Hardcode Role หรือไม่
- มี Logic ซ้ำซ้อนหรือขัดแย้งกันหรือไม่
- มีการตรวจเฉพาะ Role แต่ไม่ตรวจ Permission หรือไม่
- มีการตรวจเฉพาะ Status แต่ไม่ตรวจ Role หรือไม่
- มีการซ่อนด้วย CSS โดยไม่ได้หยุดการ Render หรือไม่
### ขั้นตอนที่ 4: ตรวจสอบ Backend กับ Matrix
ตรวจสอบ
- API Route
- Route Handler
- Server Action
- Service Function
- Repository
- Database Query
ให้ยืนยันว่าแต่ละ Action ตรวจสอบครบทั้ง
1. Authentication
2. Role หรือ Permission
3. Ownership หรือ Data Scope
4. Record Status
5. Input Validation
### ขั้นตอนที่ 5: ตรวจหาความไม่สอดคล้อง
จัดประเภทปัญหาอย่างน้อยดังนี้
- UI แสดงเกินสิทธิ์
- UI ซ่อนผิด แม้มีสิทธิ์
- เข้าผ่าน URL โดยตรงได้
- API ไม่มี Authorization
- Server Action ไม่มี Authorization
- Data Query ไม่กรอง Ownership
- Export ข้อมูลเกินสิทธิ์
- Role และ Permission Logic ไม่ตรงกัน
- Permission Logic กระจายหลายจุด
- Hardcoded Role
- Status Guard ไม่ครบ
- ข้อมูลภายในรั่วไปยังผู้ใช้งานทั่วไป
- Client และ Server ใช้เงื่อนไขต่างกัน
- Permission Matrix ไม่ตรงกับการทำงานจริง
---
## สิ่งที่ห้ามทำ
- ห้ามแก้ไขไฟล์ใด ๆ
- ห้าม Refactor
- ห้ามเปลี่ยน Permission
- ห้ามเปลี่ยน Role
- ห้ามแก้ Middleware
- ห้ามแก้ Component
- ห้ามแก้ API
- ห้ามแก้ Server Action
- ห้ามแก้ Database Schema
- ห้ามสร้าง Migration
- ห้ามรันคำสั่งที่แก้ไขข้อมูล
- ห้ามลบหรือเพิ่ม Dependency
- ห้าม Commit
- ห้าม Push
- ห้ามสรุปจากชื่อไฟล์โดยไม่ได้อ่าน Logic จริง
อนุญาตเฉพาะการอ่าน วิเคราะห์ ค้นหา และจัดทำรายงาน
---
## รูปแบบรายงานที่ต้องส่งมอบ
สร้างไฟล์
```text
permission-display-audit.md
```
โดยมีโครงสร้างดังนี้
# Permission and Display Audit Report
## 1. Executive Summary
สรุปภาพรวมว่า
- ระบบสอดคล้องกับ Permission มากน้อยเพียงใด
- พบ Critical, High, Medium และ Low กี่รายการ
- โมดูลใดมีความเสี่ยงสูง
- มีข้อมูลใดถูกแสดงเกินสิทธิ์หรือไม่
- Backend บังคับ Permission ครบถ้วนหรือไม่
## 2. Roles and Permissions Discovered
ระบุ
- Role ที่พบ
- Permission ที่พบ
- แหล่งที่กำหนด
- File path
- Logic โดยย่อ
## 3. Permission Matrix
ตารางสิทธิ์ของทุกโมดูล ทุกหน้า และทุก Action
## 4. Route and Navigation Audit
ตาราง
| ID | Route | Menu Permission | Route Guard | Direct URL Result | Status |
| --- | ----- | --------------- | ----------- | ----------------- | ------ |
## 5. UI Display Audit
ตาราง
| ID | Module | Page / Component | Element | Expected | Actual | Severity | Evidence |
| --- | ------ | ---------------- | ------- | -------- | ------ | -------- | -------- |
## 6. Backend Authorization Audit
ตาราง
| ID | Endpoint / Action | Authentication | Permission | Ownership | Status Guard | Result |
| --- | ----------------- | -------------- | ---------- | --------- | ------------ | ------ |
## 7. Findings
สำหรับแต่ละปัญหา ให้ใช้รูปแบบ
### PERM-001: ชื่อปัญหา
- Severity:
- Module:
- Affected roles:
- Expected behavior:
- Actual behavior:
- Security or business impact:
- Root cause:
- Evidence:
- File path:
- Line or code reference:
- Reproduction steps:
- Recommended remediation:
- Related findings:
## 8. Role-based Test Scenarios
จัดทำกรณีทดสอบสำหรับแต่ละ Role เช่น
| Test ID | Role | Page | Action | Expected Result |
| ------- | ---- | ---- | ------ | --------------- |
ต้องครอบคลุมอย่างน้อย
- เปิดเมนู
- เปิด URL โดยตรง
- ดูรายการ
- ดูรายละเอียด
- สร้าง
- แก้ไข
- ลบ
- ส่งตรวจสอบ
- อนุมัติ
- ปฏิเสธ
- ส่งกลับ
- Export
- เข้าถึงข้อมูลของผู้อื่น
- เปลี่ยน Record ID
- เรียก API โดยตรง
## 9. Prioritized Remediation Plan
จัดลำดับแนวทางแก้ไข โดยยังไม่แก้โค้ด
### Priority 0 — Critical Security
ปัญหาที่ทำให้ผู้ไม่มีสิทธิ์เข้าถึงหรือแก้ไขข้อมูลได้
### Priority 1 — Permission Mismatch
UI และ Backend ใช้เงื่อนไขไม่ตรงกัน
### Priority 2 — Data Exposure
ข้อมูลภายในหรือหมายเหตุแสดงเกินสิทธิ์
### Priority 3 — Maintainability
Permission Logic ซ้ำซ้อน กระจาย หรือ Hardcode
## 10. Files Reviewed
ระบุไฟล์ทั้งหมดที่ตรวจสอบ พร้อมเหตุผลที่เกี่ยวข้อง
## 11. Files Not Reviewed or Limitations
ระบุส่วนที่ไม่สามารถตรวจสอบได้ พร้อมเหตุผลอย่างตรงไปตรงมา
## 12. Final Assessment
สรุปว่า
- ระบบพร้อมใช้งานในด้าน Permission หรือไม่
- ประเด็นใดต้องแก้ก่อน Production
- ประเด็นใดสามารถวางแผนแก้ภายหลัง
- ความเสี่ยงที่ยังเหลืออยู่
---
## ระดับความรุนแรง
### Critical
- ผู้ไม่มีสิทธิ์เข้าถึงหรือแก้ไขข้อมูลสำคัญได้
- API หรือ Server Action ไม่มี Authorization
- เปลี่ยน Record ID แล้วเข้าถึงข้อมูลของผู้อื่นได้
- สามารถข้าม Workflow หรืออนุมัติแทน Role อื่นได้
### High
- UI หรือ Route แสดงข้อมูลละเอียดอ่อนเกินสิทธิ์
- Permission ระหว่าง Client และ Server ไม่ตรงกัน
- Ownership Rule ไม่ครบ
- Export ข้อมูลเกินขอบเขต
### Medium
- ปุ่มแสดงหรือซ่อนผิด
- Status และ Permission ไม่สัมพันธ์กัน
- ผู้มีสิทธิ์ใช้งานไม่ได้ตามปกติ
- Logic ซ้ำซ้อนและเสี่ยงเกิดความไม่สอดคล้อง
### Low
- ข้อความไม่เหมาะสมกับ Role
- UI สื่อความหมาย Permission ไม่ชัด
- Code Quality หรือ Maintainability ที่ยังไม่ทำให้สิทธิ์ผิดทันที
---
## เกณฑ์การตรวจสอบเพิ่มเติม
- อ้างอิงจากโค้ดจริง ไม่อ้างอิงเฉพาะ Requirement
- ทุก Finding ต้องมี File path หรือหลักฐาน
- แยก Expected กับ Actual ให้ชัดเจน
- ห้ามรายงานเป็นข้อสันนิษฐานโดยไม่มีหลักฐาน
- เมื่อไม่แน่ใจให้ระบุว่า “ต้องยืนยันเพิ่มเติม”
- ตรวจสอบทั้ง Client และ Server เสมอ
- ให้ความสำคัญกับ Security มากกว่าการซ่อน UI
- ห้ามใช้คำว่า “ผ่าน” หากตรวจเพียงฝั่งหน้าเว็บ
- ตรวจสอบว่าการใช้ `role`, `permission`, `status` และ `ownership` เป็นมาตรฐานเดียวกันทั้งระบบหรือไม่
---
## คำสั่งสุดท้าย
เริ่มจากสำรวจโครงสร้างโปรเจกต์และ Permission ทั้งหมดก่อน จากนั้นตรวจสอบการแสดงผลและการเข้าถึงของระบบทุกโมดูล
งานนี้ให้ดำเนินการเฉพาะการตรวจสอบและจัดทำรายงานเท่านั้น ห้ามแก้ไขโค้ดทุกกรณี
เมื่อเสร็จแล้วให้สรุปในข้อความตอบกลับว่า
1. พบปัญหาทั้งหมดกี่รายการ แยกตาม Severity
2. โมดูลใดมีความเสี่ยงสูงที่สุด
3. มีกรณีข้อมูลแสดงเกินสิทธิ์หรือไม่
4. มี API หรือ Server Action ที่ไม่มี Authorization หรือไม่
5. สร้างไฟล์รายงานไว้ที่ตำแหน่งใด
6. ยืนยันว่าไม่มีการแก้ไขโค้ดหรือข้อมูลในระบบ

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,231 @@
# Prompt: ปรับปรุงหน้า Create/Edit Training Record สำหรับ Public Training Attachment Requirement
## Objective
ปรับปรุงหน้าที่เกี่ยวข้องกับการสร้าง/แก้ไขประวัติการอบรม เพื่อให้กรณีเลือกประเภทการอบรมเป็น **อบรมภายนอก (Public Training)** ระบบต้องแสดงหมายเหตุสีแดงในส่วน Upload และบังคับให้ผู้ใช้งานแนบไฟล์ประกอบก่อนบันทึก
## Scope
ให้ตรวจสอบและปรับปรุงทุกหน้าที่เกี่ยวข้อง เช่น
- `training-records/new`
- หน้าแก้ไขประวัติการอบรม
- หน้า HRD/Admin ที่สามารถสร้างหรือแก้ไข Training Record ได้
- Component/Form ที่ใช้ร่วมกันกับ Training Record Form
## Requirement
### 1. เงื่อนไขการแสดงหมายเหตุ
เมื่อผู้ใช้เลือกประเภทการอบรมเป็น
- **อบรมภายนอก (Public Training)**
ให้แสดงข้อความหมายเหตุสีแดงแบบ Dynamic ทันที โดยไม่ต้อง Refresh หน้า
หากเลือกประเภทอื่น ให้ซ่อนข้อความดังกล่าว
### 2. ตำแหน่งการแสดงผล
ให้แสดงในส่วน Upload ตามลำดับนี้
```text
หัวข้อ Upload
หมายเหตุสีแดง
ช่อง Upload Attachment
```
### 3. ข้อความหมายเหตุ
ให้ใช้ข้อความนี้
```text
หมายเหตุ: สำหรับการอบรมภายนอก ผู้ใช้งานจำเป็นต้องแนบใบรับรองการอบรมและแบบรายงานผลการฝึกอบรม/ดูงานภายนอก เพื่อใช้ประกอบการพิจารณา หากไม่แนบเอกสาร HRD อาจตีกลับรายการเพื่อให้ดำเนินการแก้ไข
```
### 4. Validation
กรณีเลือกประเภทการอบรมเป็น **อบรมภายนอก (Public Training)**
ระบบต้องบังคับให้แนบไฟล์ก่อนบันทึก
หากไม่ได้แนบไฟล์ ให้แสดง Validation Error และไม่อนุญาตให้ Submit
### 5. Attachment Rule
ช่อง Attachment ปัจจุบันรองรับไฟล์:
- PDF
- JPG
- JPEG
- PNG
ให้คงเงื่อนไขเดิมไว้ และปรับให้รองรับการแนบไฟล์ได้หลายไฟล์ ไม่จำกัดจำนวนไฟล์ แต่ขนาดรวม/หรือขนาดไฟล์ต้องไม่เกิน **10 MB** ตาม Pattern เดิมของระบบ
ห้ามแก้ไขชนิดไฟล์ที่รองรับโดยไม่จำเป็น
### 6. UX/UI Requirement
- ข้อความหมายเหตุต้องเป็นสีแดง
- ใช้ Component / Style เดิมของโปรเจกต์ก่อน เช่น `FormDescription`, `Alert`, `FormMessage`, `Label`, `Text`, หรือ class ที่มีอยู่
- ต้องรองรับ Responsive
- ต้องรองรับ Dark Mode ถ้าระบบเดิมรองรับ
- ไม่ทำให้ Layout เดิมเสีย
- ข้อความต้องอ่านง่ายและอยู่ใกล้กับช่อง Upload
### 7. Technical Requirement
ก่อนแก้ไขให้ตรวจสอบก่อนว่าโปรเจกต์ใช้ Form Pattern แบบใด เช่น
- React Hook Form
- TanStack Form
- Zod Validation
- Server Action
- API Route
- Shared Form Component
ให้แก้ไขตาม Pattern เดิมของโปรเจกต์เท่านั้น
ห้ามสร้าง Logic ซ้ำ หากมี Component หรือ Validation Schema ใช้ร่วมกันอยู่แล้ว
### 8. สิ่งที่ต้องตรวจสอบก่อนแก้ไข
ให้ตรวจสอบไฟล์/ส่วนที่เกี่ยวข้อง เช่น
- Training Record Form Component
- Create Training Record Page
- Edit Training Record Page
- HRD/Admin Training Record Page
- Attachment Upload Component
- Validation Schema
- API/Mutation ที่เกี่ยวข้องกับการบันทึก Training Record
- Type ของ Training Record
- ค่า enum หรือ master data ของ Training Type
ต้องยืนยันให้ได้ว่าค่า **Public Training** ในระบบถูกเก็บเป็นค่าใด เช่น
```ts
PUBLIC_TRAINING
public_training
Public Training
```
ห้ามเดาค่าเอง ให้ตรวจสอบจาก Source Code หรือ Database Seed/Master Data ก่อน
## Implementation Steps
1. อ่านโครงสร้างเดิมของ Training Record Form
2. ตรวจสอบว่าประเภทการอบรมถูกเก็บและใช้งานอย่างไร
3. ตรวจสอบ Attachment Upload Component เดิม
4. เพิ่ม Dynamic Warning สำหรับ Public Training
5. เพิ่ม Validation บังคับแนบไฟล์เมื่อเลือก Public Training
6. ตรวจสอบการแนบหลายไฟล์และขนาดไม่เกิน 10 MB
7. ทดสอบทุกหน้าที่เกี่ยวข้อง
8. ตรวจสอบ TypeScript, ESLint และ Build
9. สร้างเอกสารรายงานผลการทำงานไว้ในโฟลเดอร์ `docs/`
## Expected Behavior
### Case 1: เลือกประเภทอื่นที่ไม่ใช่ Public Training
- ไม่แสดงหมายเหตุสีแดง
- ไม่บังคับแนบ Attachment เพิ่มเติม
- บันทึกได้ตามเงื่อนไขเดิม
### Case 2: เลือก Public Training แต่ไม่แนบไฟล์
- แสดงหมายเหตุสีแดง
- Submit ไม่สำเร็จ
- แสดงข้อความแจ้งเตือนว่าจำเป็นต้องแนบไฟล์ประกอบ
### Case 3: เลือก Public Training และแนบไฟล์ถูกต้อง
- แสดงหมายเหตุสีแดง
- Submit สำเร็จ
- ไฟล์ Attachment ถูกบันทึกตาม Flow เดิม
### Case 4: เลือก Public Training แล้วเปลี่ยนกลับเป็นประเภทอื่น
- ซ่อนหมายเหตุสีแดงทันที
- Validation เรื่อง Attachment ต้องกลับไปใช้เงื่อนไขเดิม
## Testing Checklist
ให้ทดสอบอย่างน้อยดังนี้
- [ ] หน้า `training-records/new`
- [ ] หน้า Edit Training Record
- [ ] หน้า HRD/Admin ที่เกี่ยวข้อง
- [ ] เลือก Public Training แล้วข้อความแสดงทันที
- [ ] เปลี่ยนจาก Public Training เป็นประเภทอื่นแล้วข้อความหาย
- [ ] Public Training ไม่แนบไฟล์แล้ว Submit ไม่ได้
- [ ] Public Training แนบไฟล์แล้ว Submit ได้
- [ ] แนบไฟล์ PDF ได้
- [ ] แนบไฟล์ JPG/JPEG/PNG ได้
- [ ] ไฟล์เกิน 10 MB ต้องถูกปฏิเสธ
- [ ] Layout ไม่เสียบน Desktop
- [ ] Layout ไม่เสียบน Mobile
- [ ] ไม่มี TypeScript Error
- [ ] ไม่มี ESLint Error
- [ ] Build ผ่าน
## Report Requirement
หลังดำเนินการเสร็จ ให้สร้างไฟล์เอกสารรายงานผลไว้ในโฟลเดอร์ `docs/`
ตั้งชื่อไฟล์ประมาณนี้
```text
docs/public-training-attachment-requirement-report.md
```
ในรายงานต้องมีหัวข้อดังนี้
```md
# Public Training Attachment Requirement Report
## Summary
สรุปสิ่งที่ดำเนินการ
## Files Changed
รายการไฟล์ที่แก้ไข
## Requirement Mapping
Mapping ระหว่าง Requirement กับสิ่งที่แก้ไข
## Implementation Details
รายละเอียดการปรับปรุง Logic/UI/Validation
## Validation Rules
สรุปเงื่อนไข Validation ที่เพิ่ม
## Testing Result
ผลการทดสอบตาม Checklist
## Impact Analysis
ผลกระทบต่อระบบเดิม
## Notes / Limitations
ข้อจำกัดหรือสิ่งที่ควรตรวจสอบเพิ่มเติม
```
## Important Rules
- ห้ามแก้ไขส่วนที่ไม่เกี่ยวข้อง
- ห้ามเปลี่ยน Database Schema หากไม่จำเป็น
- ห้ามเปลี่ยน API Contract เดิมโดยไม่จำเป็น
- ห้ามเปลี่ยน Role Permission เดิม
- ต้องใช้ Pattern เดิมของโปรเจกต์
- ต้องสร้างรายงานไว้ใน `docs/` หลังแก้ไขเสร็จ
- หากพบว่า Requirement กระทบหลายจุด ให้สรุปก่อนแก้ไขใน `plan.md`

Some files were not shown because too many files have changed in this diff Show More