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

View File

@@ -0,0 +1,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