Files
alla-tms/plans/fix-online-lesson-review-note-visibility-prompt.md
2026-07-16 09:53:14 +07:00

682 lines
27 KiB
Markdown

# 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 ที่มีอยู่