27 KiB
Prompt: แก้ไขปัญหาการแสดงหมายเหตุการตรวจสอบในหน้าผู้ใช้งาน
บทบาทของคุณ
คุณคือ Senior Full-Stack Engineer และ Software Architect ที่รับผิดชอบตรวจสอบและแก้ไขระบบ Training Management System ซึ่งพัฒนาด้วย Next.js, React, TypeScript และระบบ Permission-first
ให้ตรวจสอบ Codebase ปัจจุบันและแก้ไขปัญหาที่หน้า รายละเอียดบทเรียนออนไลน์ของผู้ใช้งานทั่วไป มีการแสดงข้อมูล หมายเหตุการตรวจสอบ ซึ่งเป็นข้อมูลภายในของกระบวนการตรวจสอบหรืออนุมัติ และไม่ควรถูกแสดงให้ผู้ใช้งานทั่วไปเห็น
ห้ามแก้ไขเฉพาะการซ่อน UI อย่างเดียวโดยไม่ตรวจสอบ API, DTO, Query และ Permission ที่เกี่ยวข้อง
1. ปัญหาที่ต้องแก้ไข
จากหน้าใช้งานจริง พบว่าผู้ใช้งานทั่วไปสามารถเห็น Section:
หมายเหตุการตรวจสอบ
ทั้งที่บทเรียนอยู่ในสถานะเผยแพร่แล้ว และข้อมูลดังกล่าวเป็นส่วนหนึ่งของกระบวนการตรวจสอบภายใน
ปัญหานี้อาจเกิดจาก:
- 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. วัตถุประสงค์
แก้ไขระบบให้:
- ผู้ใช้งานทั่วไปไม่เห็นหมายเหตุการตรวจสอบภายใน
- ผู้ใช้งานทั่วไปไม่ได้รับข้อมูลหมายเหตุภายในจาก API
- ผู้มี Permission ตรวจสอบหรืออนุมัติยังสามารถเห็นข้อมูลดังกล่าวได้ในหน้าหลังบ้าน
- บทเรียนที่เผยแพร่แล้วแสดงเฉพาะข้อมูลที่เกี่ยวข้องกับผู้เรียน
- ไม่มีการเปิดเผยข้อมูลภายในผ่าน Network Response, API Payload หรือ Client State
- ใช้มาตรฐาน Permission-first ของระบบ
- ไม่กระทบ 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 ที่เกี่ยวข้อง
ให้ค้นหาฟิลด์หรือคำที่เกี่ยวข้อง เช่น:
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 ที่เกี่ยวข้อง เช่น:
online_lessons:review
online_lessons:approve
online_lessons:manage
หรือ Permission จริงที่ระบบใช้อยู่ ควรยังสามารถเห็นหมายเหตุการตรวจสอบในหน้าหลังบ้านได้ตามเดิม
ห้ามเดาชื่อ Permission ให้ตรวจสอบจาก Codebase จริงก่อนใช้งาน
4.3 กรณีมีข้อความที่ต้องแจ้งผู้ใช้งาน
หากระบบมีความต้องการให้ผู้ใช้งานเห็นข้อความจากผู้ตรวจสอบ ให้แยกข้อมูลออกจากหมายเหตุภายในอย่างชัดเจน เช่น:
internalReviewNote
employeeFeedback
หรือ:
internalNote
reviewMessage
โดยกำหนดว่า:
internalReviewNoteแสดงเฉพาะผู้มี Permission ตรวจสอบemployeeFeedbackแสดงให้ผู้ใช้งานเห็นเฉพาะกรณีที่ต้องดำเนินการ เช่น ถูกส่งกลับแก้ไขหรือถูกปฏิเสธ
ห้ามใช้ฟิลด์เดียวกันสำหรับทั้ง Internal Note และข้อความแจ้งผู้ใช้งาน หากความหมายของข้อมูลต่างกัน
5. ขั้นตอนการตรวจสอบก่อนแก้ไข
ก่อนแก้ไข ให้ตรวจสอบและสรุป:
- หน้าใดเป็นหน้าที่เกิดปัญหา
- Component ใดแสดง Section หมายเหตุ
- ฟิลด์จริงในฐานข้อมูลและ TypeScript คือชื่ออะไร
- API ใดส่งข้อมูลนี้กลับมา
- Query หรือ ORM Select ดึงฟิลด์นี้มาหรือไม่
- หน้า User และ Back Office ใช้ API เดียวกันหรือไม่
- ใช้ Component ร่วมกันหรือไม่
- Permission Model ปัจจุบันเป็นแบบใด
- มี Role-based condition แบบเก่าหรือ Compatibility Mode อยู่หรือไม่
- มี Test ครอบคลุมเรื่อง Field Visibility หรือไม่
ห้ามแก้ไขทันทีโดยไม่ตรวจสอบ Data Flow ตั้งแต่ Database → Service → API → Client → UI
6. แนวทางแก้ไขระดับ UI
หากพบว่า Component แสดงข้อมูลโดยตรวจสอบเพียงว่ามีค่า เช่น:
{lesson.reviewNote && (
<ReviewNote note={lesson.reviewNote} />
)}
ให้แก้เป็น Permission-based Rendering เช่น:
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 เช่น:
{
id,
title,
description,
category,
status,
publishedAt,
publishedBy,
videoUrl,
videoFileUrl,
thumbnailUrl,
attachments
}
ไม่ควรคืน:
reviewNote
internalNote
reviewedBy
reviewedAt
approvalComment
approvalHistory
เว้นแต่ผู้ใช้งานมี Permission ที่เหมาะสม
ตัวอย่างแนวทาง:
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
ตัวอย่าง:
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:
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 หรือไม่
หากมี ให้พิจารณาแยกเป็น:
type PublicOnlineLessonDetail = {
id: string;
title: string;
description: string | null;
category: string;
status: string;
publishedAt: string | null;
videoUrl: string | null;
attachments: Attachment[];
};
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
PublicOnlineLessonDetail
InternalOnlineLessonDetail
เหมาะเมื่อโครงสร้างข้อมูลและ UI ต่างกันชัดเจน
ทางเลือก B: ใช้ Component เดียวแต่มี Capability Props
<OnlineLessonDetail
lesson={lesson}
canViewInternalReviewNote={canViewInternalReviewNote}
/>
ข้อกำหนด:
- ห้ามส่ง Permission Object ขนาดใหญ่โดยไม่จำเป็น
- ใช้ Boolean Capability ที่อ่านง่าย
- ต้องไม่ทำให้ Public Component รับ Internal Data โดยไม่จำเป็น
- เลือกวิธีที่เข้ากับโครงสร้างเดิมและดูแลต่อได้ง่ายที่สุด
11. สถานะบทเรียน
สำหรับบทเรียนสถานะ published หรือสถานะเผยแพร่แล้ว:
- หน้า User ต้องแสดงเฉพาะข้อมูลเพื่อการเรียน
- ต้องไม่แสดง Review Note
- ต้องไม่แสดง Internal Approval Metadata
- ต้องไม่แสดงข้อความจากขั้นตอนก่อน Publish ที่ไม่เกี่ยวกับผู้เรียน
หากระบบมี Status อื่น เช่น:
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 ควรมีโครงสร้าง:
ชื่อบทเรียน + สถานะ
หมวดหมู่ / ผู้เผยแพร่ / วันที่เผยแพร่
รายละเอียดบทเรียน
วิดีโอ
เอกสารประกอบ
ต้องไม่มี:
หมายเหตุการตรวจสอบ
เว้นแต่เป็นข้อความที่ตั้งใจส่งถึงผู้ใช้งานจริงและถูกจัดเก็บในฟิลด์แยกที่เหมาะสม
หากไม่มีเอกสารประกอบ ให้ใช้ข้อความตามมาตรฐานเดิมของระบบ เช่น:
ไม่มีไฟล์แนบ
โดยไม่เกี่ยวข้องกับการแก้ไข 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: ผู้ใช้งานทั่วไปเปิดบทเรียนเผยแพร่แล้ว
- Login ด้วยบัญชี User
- เปิดหน้า Online Lessons
- เปิดรายละเอียดบทเรียนที่ Published
- ตรวจสอบว่าไม่พบหัวข้อ
หมายเหตุการตรวจสอบ - ตรวจสอบ Network Response ว่าไม่มี
reviewNoteหรือฟิลด์ภายใน - ตรวจสอบว่าวิดีโอและเอกสารยังแสดงปกติ
Test Case 2: HRD เปิดหน้าหลังบ้าน
- Login ด้วยบัญชีที่มี Permission Review
- เปิด Online Lesson Detail ฝั่ง Back Office
- ตรวจสอบว่ายังเห็นหมายเหตุการตรวจสอบ
- ตรวจสอบว่าสามารถบันทึกหรือแก้ไขหมายเหตุได้
- ตรวจสอบว่า Refresh แล้วข้อมูลยังอยู่
Test Case 3: ไม่มีหมายเหตุ
- เปิดรายการที่ไม่มี Review Note
- ตรวจสอบว่าไม่แสดงหัวข้อหรือกรอบว่าง
- ตรวจสอบ Layout ไม่เกิดช่องว่างผิดปกติ
Test Case 4: ไม่มี Permission
- เรียก Endpoint ด้วยบัญชีที่ไม่มี Permission
- ตรวจสอบว่า Response ไม่มี Internal Field
- ตรวจสอบว่าไม่สามารถเข้าถึงผ่านการแก้ URL หรือ Client State
Test Case 5: Compatibility Mode
- ตรวจสอบ Role เก่าหรือ Business Role ที่ยังมีอยู่
- ยืนยันว่า Visibility ยึด Permission เป็นหลัก
- ตรวจสอบว่า 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 โดยใช้โครงสร้าง:
# 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
งานนี้ถือว่าเสร็จสมบูรณ์เมื่อ:
- ผู้ใช้งานทั่วไปไม่เห็นหมายเหตุการตรวจสอบ
- API ของผู้ใช้งานทั่วไปไม่ส่ง Internal Review Data
- ผู้มี Permission ยังเห็นและใช้งานหมายเหตุได้ตามเดิม
- Public DTO และ Internal DTO แยกชัดเจน
- UI ใช้ Permission-first
- ไม่มี Role Hard-code ใหม่
- ไม่มีข้อมูลภายในใน Network Response
- TypeScript, Lint, Tests และ Build ผ่าน
- มี Implementation Report
- ไม่เกิด Regression ต่อ Workflow Online Lesson
คำสั่งเริ่มต้น
เริ่มจากตรวจสอบ Codebase จริงก่อน โดยค้นหา Data Flow ของหมายเหตุการตรวจสอบตั้งแต่ Database, ORM Query, Service, API, DTO, Hook และ UI
จากนั้นให้สรุป:
- Root Cause
- ฟิลด์ที่เกี่ยวข้อง
- API ที่เกี่ยวข้อง
- Component ที่เกี่ยวข้อง
- Permission ที่ควรใช้
- ไฟล์ที่ต้องแก้ไข
- แนวทางป้องกันข้อมูลรั่วไหล
เมื่อสรุปแล้ว ให้ดำเนินการแก้ไขครบทั้ง Server-side และ Client-side พร้อมทดสอบและจัดทำ Implementation Report
ไม่ต้องหยุดเพื่อถามยืนยันระหว่างดำเนินงาน เว้นแต่พบข้อขัดแย้งที่ไม่สามารถตัดสินใจได้จาก Codebase และ Requirement ที่มีอยู่