commit
This commit is contained in:
196
plans/action-auto-refresh-implementation-report.md
Normal file
196
plans/action-auto-refresh-implementation-report.md
Normal 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
1033
plans/action-auto-refresh.md
Normal file
File diff suppressed because it is too large
Load Diff
65
plans/add-year-filter-training-history-page.md
Normal file
65
plans/add-year-filter-training-history-page.md
Normal 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.
|
||||
258
plans/announcement-approval-workflow.md
Normal file
258
plans/announcement-approval-workflow.md
Normal 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
|
||||
587
plans/announcement-pin-action.md
Normal file
587
plans/announcement-pin-action.md
Normal 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
|
||||
- รายงานถูกสร้างเรียบร้อย
|
||||
373
plans/announcement-review-note-permission-bug-fix-plan.md
Normal file
373
plans/announcement-review-note-permission-bug-fix-plan.md
Normal 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 หลุดไปยังผู้ใช้งานทั่วไปอีก
|
||||
315
plans/approval-publishing-workflow-plan.md
Normal file
315
plans/approval-publishing-workflow-plan.md
Normal 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.
|
||||
624
plans/approval-publishing-workflow.md
Normal file
624
plans/approval-publishing-workflow.md
Normal 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
1108
plans/approval-workflow.md
Normal file
File diff suppressed because it is too large
Load Diff
522
plans/audit-employee-dashboard.md
Normal file
522
plans/audit-employee-dashboard.md
Normal 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.
|
||||
630
plans/audit-employee-online-lessons.md
Normal file
630
plans/audit-employee-online-lessons.md
Normal 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.
|
||||
493
plans/audit-employee-training-history.md
Normal file
493
plans/audit-employee-training-history.md
Normal 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.
|
||||
345
plans/audit-pending-review-page.md
Normal file
345
plans/audit-pending-review-page.md
Normal 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
64
plans/audit.md
Normal 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.
|
||||
30
plans/btn-add-online-lessons.md
Normal file
30
plans/btn-add-online-lessons.md
Normal 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 สามารถกดปุ่ม "+ เพิ่มบทเรียนออนไลน์" เพื่อสร้างบทเรียนใหม่ได้
|
||||
736
plans/category-and-required-field.md
Normal file
736
plans/category-and-required-field.md
Normal 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
|
||||
```
|
||||
223
plans/change-add-employee-directory-menu.md
Normal file
223
plans/change-add-employee-directory-menu.md
Normal 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.
|
||||
84
plans/change-admin-sidebar.md
Normal file
84
plans/change-admin-sidebar.md
Normal 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.
|
||||
144
plans/change-certificate-dialog.md
Normal file
144
plans/change-certificate-dialog.md
Normal 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.
|
||||
98
plans/change-certificate-empty-state.md
Normal file
98
plans/change-certificate-empty-state.md
Normal 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.
|
||||
93
plans/change-certificate-preview.md
Normal file
93
plans/change-certificate-preview.md
Normal 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
|
||||
177
plans/change-course-selection.md
Normal file
177
plans/change-course-selection.md
Normal 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.
|
||||
116
plans/change-dashboard-filter.md
Normal file
116
plans/change-dashboard-filter.md
Normal 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.
|
||||
263
plans/change-duration-minutes.md
Normal file
263
plans/change-duration-minutes.md
Normal 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.
|
||||
233
plans/change-employee-training-overview.md
Normal file
233
plans/change-employee-training-overview.md
Normal 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.
|
||||
143
plans/change-import-button-in-users.md
Normal file
143
plans/change-import-button-in-users.md
Normal 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.
|
||||
312
plans/change-import-employee-ksa-targets.md
Normal file
312
plans/change-import-employee-ksa-targets.md
Normal 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.
|
||||
107
plans/change-pending-review-action-menu.md
Normal file
107
plans/change-pending-review-action-menu.md
Normal 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.
|
||||
131
plans/change-sidebar-master-data-group.md
Normal file
131
plans/change-sidebar-master-data-group.md
Normal 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.
|
||||
227
plans/change-training-course-dropdown.md
Normal file
227
plans/change-training-course-dropdown.md
Normal 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.
|
||||
146
plans/change-training-hours-timepicker.md
Normal file
146
plans/change-training-hours-timepicker.md
Normal 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.
|
||||
129
plans/change-training-type-options.md
Normal file
129
plans/change-training-type-options.md
Normal 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.
|
||||
155
plans/change-user-management-it-admin-only.md
Normal file
155
plans/change-user-management-it-admin-only.md
Normal 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
107
plans/change-user-menu.md
Normal 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.
|
||||
144
plans/change-users-employee-code.md
Normal file
144
plans/change-users-employee-code.md
Normal 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.
|
||||
@@ -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
48
plans/data-ordering.md
Normal 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";
|
||||
}
|
||||
```
|
||||
26
plans/edit-employee-table.md
Normal file
26
plans/edit-employee-table.md
Normal 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 เท่านั้น
|
||||
|
||||
ผลลัพธ์ที่ต้องการ:
|
||||
ตารางแสดงเฉพาะ รหัสพนักงาน, ชื่อพนักงาน, ชั่วโมงการอบรม และปุ่มจัดการ โดยไม่แสดงฝ่ายกับตำแหน่ง
|
||||
510
plans/employee-create-training-record-audit.md
Normal file
510
plans/employee-create-training-record-audit.md
Normal 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
|
||||
634
plans/employee-directory-redesign.md
Normal file
634
plans/employee-directory-redesign.md
Normal 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 ถูกสร้างเรียบร้อย
|
||||
167
plans/employee-directory-table-redesign.md
Normal file
167
plans/employee-directory-table-redesign.md
Normal 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
|
||||
217
plans/employee-information-ui.md
Normal file
217
plans/employee-information-ui.md
Normal 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
|
||||
346
plans/enhancement-employee-directory.md
Normal file
346
plans/enhancement-employee-directory.md
Normal 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.
|
||||
90
plans/extract-total-hours.md
Normal file
90
plans/extract-total-hours.md
Normal 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 ส่วนใด
|
||||
- วิธีทดสอบ
|
||||
- ผลการทดสอบ
|
||||
908
plans/filter-single-select-plan.md
Normal file
908
plans/filter-single-select-plan.md
Normal 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 และไม่มีผลกระทบต่อฟังก์ชันเดิมของระบบ
|
||||
0
plans/fix-all-permission-findings-codex-prompt.md
Normal file
0
plans/fix-all-permission-findings-codex-prompt.md
Normal file
342
plans/fix-attachment-view.md
Normal file
342
plans/fix-attachment-view.md
Normal 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 ผ่านทั้งหมด
|
||||
@@ -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 และการแก้ไข
|
||||
@@ -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
|
||||
```
|
||||
71
plans/fix-layout-online-lesson-page.md
Normal file
71
plans/fix-layout-online-lesson-page.md
Normal 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 เหมือนหน้า ประวัติการอบรม
|
||||
681
plans/fix-online-lesson-review-note-visibility-prompt.md
Normal file
681
plans/fix-online-lesson-review-note-visibility-prompt.md
Normal 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 ที่มีอยู่
|
||||
92
plans/fix-online-lesson-review-note-visibility-report.md
Normal file
92
plans/fix-online-lesson-review-note-visibility-report.md
Normal 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.
|
||||
26
plans/fix-ui-issues-thai-language.md
Normal file
26
plans/fix-ui-issues-thai-language.md
Normal 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
|
||||
784
plans/fix-user-training-filters.md
Normal file
784
plans/fix-user-training-filters.md
Normal 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 และผลลัพธ์ข้อมูลจริงด้วย
|
||||
67
plans/fixing-black-screen-video.md
Normal file
67
plans/fixing-black-screen-video.md
Normal 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.
|
||||
58
plans/hrd-import-training-records.md
Normal file
58
plans/hrd-import-training-records.md
Normal 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
|
||||
- แสดงจำนวนรายการที่สำเร็จ/ผิดพลาด
|
||||
24
plans/identity-employee-cleanup.md
Normal file
24
plans/identity-employee-cleanup.md
Normal 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
|
||||
169
plans/identity-employee-master-refactor.md
Normal file
169
plans/identity-employee-master-refactor.md
Normal 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
|
||||
455
plans/implementation-plan.md
Normal file
455
plans/implementation-plan.md
Normal 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 ของโปรเจ็กต์
|
||||
85
plans/improve-employee-import.md
Normal file
85
plans/improve-employee-import.md
Normal 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. สรุปผลการแก้ไขเป็นรายงานหลังทำเสร็จ
|
||||
63
plans/mobile-tablet -ux.md
Normal file
63
plans/mobile-tablet -ux.md
Normal 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
|
||||
77
plans/modify-layout-employee-page.md
Normal file
77
plans/modify-layout-employee-page.md
Normal 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 ตรงกัน
|
||||
882
plans/online-lesson-create-workflow-redesign.md
Normal file
882
plans/online-lesson-create-workflow-redesign.md
Normal 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
|
||||
```
|
||||
410
plans/online-lesson-draft-save-redirect-plan.md
Normal file
410
plans/online-lesson-draft-save-redirect-plan.md
Normal 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
|
||||
- ห้ามรายงานว่าสำเร็จโดยไม่ตรวจสอบว่าหน้ารายการแสดงข้อมูลล่าสุดจริง
|
||||
1112
plans/online-lesson-returned-rejected-permission-logic-plan.md
Normal file
1112
plans/online-lesson-returned-rejected-permission-logic-plan.md
Normal file
File diff suppressed because it is too large
Load Diff
888
plans/online-lesson-submit-review-status-refresh-plan.md
Normal file
888
plans/online-lesson-submit-review-status-refresh-plan.md
Normal 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
373
plans/online-lessons.md
Normal 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 สามารถ:
|
||||
|
||||
- จัดการบทเรียนทั้งหมดได้
|
||||
- แก้ไขบทเรียนได้
|
||||
- ลบบทเรียนได้
|
||||
- เปิด/ปิดการเผยแพร่ได้
|
||||
829
plans/organizers-module-fix.md
Normal file
829
plans/organizers-module-fix.md
Normal 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 หรือข้อเสนอแนะในการพัฒนาต่อในอนาคต
|
||||
763
plans/permission-authorization.md
Normal file
763
plans/permission-authorization.md
Normal 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
|
||||
679
plans/permission-description.md
Normal file
679
plans/permission-description.md
Normal 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 ครบถ้วน
|
||||
465
plans/permission-management-implementation.md
Normal file
465
plans/permission-management-implementation.md
Normal 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 เอง
|
||||
652
plans/permission-validation-fix.md
Normal file
652
plans/permission-validation-fix.md
Normal 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. ข้อเสนอแนะเพิ่มเติม (ถ้ามี)
|
||||
2075
plans/phase-0-architecture-audit-part-1.md
Normal file
2075
plans/phase-0-architecture-audit-part-1.md
Normal file
File diff suppressed because it is too large
Load Diff
702
plans/policy-management-enhancement.md
Normal file
702
plans/policy-management-enhancement.md
Normal 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
152
plans/pre-sprint.md
Normal 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.
|
||||
79
plans/pre-uat-readiness.md
Normal file
79
plans/pre-uat-readiness.md
Normal 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
|
||||
289
plans/redesign-announcement.md
Normal file
289
plans/redesign-announcement.md
Normal 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
343
plans/req.md
Normal 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 ของรีโป เพื่อให้สามารถพัฒนาต่อจากฐานโค้ดนี้ได้จริง
|
||||
119
plans/responsive-datatable-review.md
Normal file
119
plans/responsive-datatable-review.md
Normal 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.
|
||||
193
plans/responsive-qa-after-management-change.md
Normal file
193
plans/responsive-qa-after-management-change.md
Normal 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.
|
||||
255
plans/responsive-table-fix.md
Normal file
255
plans/responsive-table-fix.md
Normal 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
146
plans/responsive.md
Normal 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.
|
||||
167
plans/role-permission-plan.md
Normal file
167
plans/role-permission-plan.md
Normal 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
146
plans/role-permission.md
Normal 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
491
plans/rule-ai.md
Normal 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
130
plans/sprint-4.md
Normal 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.
|
||||
181
plans/sprint-5-employee-import-review.md
Normal file
181
plans/sprint-5-employee-import-review.md
Normal 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.
|
||||
248
plans/sprint-6-12-employee-ownership-final-migration.md
Normal file
248
plans/sprint-6-12-employee-ownership-final-migration.md
Normal 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
|
||||
155
plans/sprint-6-5-pre-sprint-7.md
Normal file
155
plans/sprint-6-5-pre-sprint-7.md
Normal 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
135
plans/sprint-6-phase-1.md
Normal 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
206
plans/sprint-6-phase-2.md
Normal 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
126
plans/sprint-6-phase-3.md
Normal 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
108
plans/sprint-6-phase-4.md
Normal 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
81
plans/sprint-7-phase-1.md
Normal 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
|
||||
892
plans/staff-course-filter-single-select-plan.md
Normal file
892
plans/staff-course-filter-single-select-plan.md
Normal 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
453
plans/system-test-flow.md
Normal 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` ผ่าน
|
||||
529
plans/system-ui-permission-review-plan.md
Normal file
529
plans/system-ui-permission-review-plan.md
Normal 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. ยืนยันว่าไม่มีการแก้ไขโค้ดหรือข้อมูลในระบบ
|
||||
1297
plans/tms-phase-1-complete-remediation-prompt.md
Normal file
1297
plans/tms-phase-1-complete-remediation-prompt.md
Normal file
File diff suppressed because it is too large
Load Diff
2359
plans/tms-system-full-audit-prompts.md
Normal file
2359
plans/tms-system-full-audit-prompts.md
Normal file
File diff suppressed because it is too large
Load Diff
231
plans/training-attachment.md
Normal file
231
plans/training-attachment.md
Normal 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
Reference in New Issue
Block a user