# Prompt: Standardize Auto Refresh After CRUD Operations
## บทบาทของคุณ
คุณคือ Senior Full-Stack Engineer และ Software Architect ที่รับผิดชอบตรวจสอบและปรับปรุงระบบ Training Management System ซึ่งพัฒนาด้วย Next.js, React, TypeScript และ Data Table
ให้ตรวจสอบโครงสร้างเดิมของระบบก่อนดำเนินการแก้ไข และปรับปรุงพฤติกรรมหลังการทำรายการต่าง ๆ ให้ข้อมูลบนหน้าจออัปเดตโดยอัตโนมัติ โดยไม่ต้องให้ผู้ใช้กด Refresh Browser เอง
การแก้ไขต้องยึดโครงสร้างและเทคโนโลยีที่ระบบใช้อยู่จริง เช่น:
- SWR
- TanStack Query
- Next.js Server Components
- Next.js Server Actions
- Client-side API Fetching
- `router.refresh()`
- Local State
- Data Table
- Pagination
- Search
- Filter
- Sorting
ห้ามเปลี่ยน Library หรือ Architecture หลักโดยไม่จำเป็น
---
# 1. วัตถุประสงค์
ปรับปรุงระบบให้หลังจากผู้ใช้ดำเนินการสำเร็จ เช่น เพิ่ม แก้ไข ลบ อนุมัติ ปฏิเสธ เผยแพร่ หรือ Import ข้อมูล ระบบต้องอัปเดตข้อมูลบนหน้าจอทันทีโดยอัตโนมัติ
ผู้ใช้ต้องไม่ต้อง:
- กด Refresh Browser
- ออกจากหน้าแล้วกลับเข้ามาใหม่
- เปลี่ยน Tab ไปมา
- กดค้นหาใหม่
- เปลี่ยน Pagination เพื่อบังคับโหลดข้อมูล
ระบบต้องแสดงข้อมูลล่าสุดที่ตรงกับฐานข้อมูลหลัง Action สำเร็จ
---
# 2. ขอบเขตการตรวจสอบ
ตรวจสอบทุกหน้าที่มีการแสดงรายการข้อมูล และมีการทำ Action ที่ส่งผลต่อข้อมูลในรายการ
อย่างน้อยให้ครอบคลุม Module ต่อไปนี้ หากมีอยู่ในระบบ:
- Employees
- Users
- Training Records
- Pending Training Reviews
- Online Lessons
- Announcements
- Policies
- Course Master
- Permission Templates
- Roles and Permissions
- Approval Workflow
- Notifications
- Import History
- Audit Logs
- Organization Management
- Departments
- Positions
- Companies
- Reports
- Settings
ให้ค้นหาเพิ่มเติมจาก Codebase ว่ามี Module อื่นที่มี CRUD หรือ Status Action หรือไม่ และรวมไว้ในขอบเขตด้วย
---
# 3. Action ที่ต้องรองรับ Auto Refresh
หลัง Action ต่อไปนี้สำเร็จ ระบบต้อง Refresh หรือ Revalidate ข้อมูลที่เกี่ยวข้องโดยอัตโนมัติ
## CRUD Actions
- Create
- Update
- Delete
- Soft Delete
- Restore
- Archive
- Unarchive
## Workflow Actions
- Submit for Review
- Approve
- Reject
- Return for Revision
- Cancel
- Publish
- Unpublish
- Schedule Publish
- Pin
- Unpin
- Activate
- Deactivate
## Bulk Actions
- Bulk Delete
- Bulk Approve
- Bulk Reject
- Bulk Activate
- Bulk Deactivate
- Bulk Import
- Bulk Update
## Import Actions
- Import Excel
- Import CSV
- Import Training Records
- Import Employee Data
- Import Course Master
หากพบ Action อื่นที่เปลี่ยนแปลงข้อมูล ให้ใช้มาตรฐานเดียวกัน
---
# 4. ขั้นตอนการตรวจสอบก่อนแก้ไข
ก่อนแก้ไข Code ให้ตรวจสอบและระบุว่าแต่ละหน้าดึงข้อมูลด้วยวิธีใด
ตัวอย่าง:
- SWR
- TanStack Query
- Server Component
- Server Action
- Client Component Fetch
- Custom Hook
- Local State
- Context
- Zustand
- Redux
- URL Search Params
ให้ตรวจสอบว่า:
1. Query Key หรือ Cache Key ถูกสร้างที่ใด
2. Filter ถูกส่งเข้า Query อย่างไร
3. Pagination ใช้ `page`, `limit`, `offset` หรือ `cursor`
4. Search ใช้ URL Search Params หรือ Local State
5. Sort ถูกจัดเก็บไว้ที่ใด
6. Action Handler อยู่ใน Component, Hook, Service หรือ Server Action
7. หลัง Action สำเร็จมีการเรียก Refresh หรือ Revalidation อยู่แล้วหรือไม่
8. มีการ Refresh ผิด Key หรือ Refresh ไม่ครบทุกข้อมูลที่เกี่ยวข้องหรือไม่
9. มีการใช้ `window.location.reload()` หรือไม่
10. มีข้อมูลสรุป เช่น Count, Badge, KPI หรือ Dashboard ที่ต้อง Refresh พร้อมกันหรือไม่
ห้ามเดารูปแบบการ Fetch ให้ตรวจสอบ Code จริงก่อนแก้ไข
---
# 5. มาตรฐานการ Refresh ตามเทคโนโลยี
เลือกวิธี Refresh ให้ตรงกับ Architecture ของแต่ละหน้า
## 5.1 กรณีใช้ SWR
หลัง Action สำเร็จให้ใช้ `mutate()` หรือ Global Mutate กับ Key ที่ถูกต้อง
ตัวอย่าง:
```tsx
const { data, mutate, isLoading } = useSWR(queryKey, fetcher);
const handleDelete = async (id: string) => {
try {
await deleteRecord(id);
await mutate();
toast.success("ลบข้อมูลสำเร็จ");
} catch (error) {
toast.error(getErrorMessage(error));
}
};
```
กรณีใช้ Dynamic Key ให้ตรวจสอบว่า Key ที่ Mutate ตรงกับ Key ที่ใช้ Fetch จริง
ตัวอย่าง:
```tsx
await mutate(getTrainingRecordsKey(filters));
```
หาก Action ส่งผลต่อหลาย Key ให้ Revalidate ทุก Key ที่เกี่ยวข้อง
ตัวอย่าง:
```tsx
await Promise.all([
mutate(getTrainingRecordsKey(filters)),
mutate(getPendingReviewCountKey()),
mutate(getDashboardSummaryKey()),
]);
```
ห้ามสร้าง Cache Key ซ้ำหลายรูปแบบโดยไม่จำเป็น
---
## 5.2 กรณีใช้ TanStack Query
หลัง Action สำเร็จให้ใช้ `invalidateQueries()` หรือ `setQueryData()` ตามความเหมาะสม
ตัวอย่าง:
```tsx
await deleteRecord(id);
await queryClient.invalidateQueries({
queryKey: ["training-records"],
});
toast.success("ลบข้อมูลสำเร็จ");
```
หาก Query Key มี Filter:
```tsx
await queryClient.invalidateQueries({
queryKey: ["training-records", filters],
});
```
หาก Action ส่งผลต่อหลายรายการ:
```tsx
await Promise.all([
queryClient.invalidateQueries({
queryKey: ["training-records"],
}),
queryClient.invalidateQueries({
queryKey: ["dashboard-summary"],
}),
queryClient.invalidateQueries({
queryKey: ["pending-review-count"],
}),
]);
```
หลีกเลี่ยงการ Invalidate Cache ทั้งระบบโดยไม่จำเป็น
---
## 5.3 กรณีใช้ Next.js Server Component หรือ Server Action
ให้ใช้วิธีที่เหมาะสม เช่น:
- `router.refresh()`
- `revalidatePath()`
- `revalidateTag()`
ตัวอย่างฝั่ง Client:
```tsx
const router = useRouter();
await deleteRecord(id);
router.refresh();
toast.success("ลบข้อมูลสำเร็จ");
```
ตัวอย่าง Server Action:
```tsx
"use server";
import { revalidatePath } from "next/cache";
export async function deleteTrainingRecord(id: string) {
await trainingRecordService.delete(id);
revalidatePath("/dashboard/training-records");
}
```
หากมีหลายหน้าที่ใช้ข้อมูลเดียวกัน ให้พิจารณาใช้ `revalidateTag()` แทนการระบุ Path ซ้ำหลายจุด
ห้ามเรียก `router.refresh()` โดยไม่จำเป็นในหน้าที่ใช้ SWR หรือ TanStack Query หากการ Refresh ไม่ได้ทำให้ Cache ของ Client ถูกอัปเดต
---
## 5.4 กรณีใช้ Local State
หากรายการถูกเก็บอยู่ใน Local State และไม่มี Data Fetching Library ให้ปรับ State หลัง Action สำเร็จ
ตัวอย่าง Delete:
```tsx
setItems((currentItems) =>
currentItems.filter((item) => item.id !== deletedId),
);
```
ตัวอย่าง Update:
```tsx
setItems((currentItems) =>
currentItems.map((item) => (item.id === updatedItem.id ? updatedItem : item)),
);
```
อย่างไรก็ตาม หากฐานข้อมูลเป็น Source of Truth ให้พิจารณา Fetch ข้อมูลใหม่หลัง Action สำเร็จเพื่อป้องกันข้อมูลไม่ตรงกับ Server
---
# 6. ลำดับการทำงานมาตรฐาน
กำหนดลำดับหลัง Action สำเร็จให้เหมือนกันทั้งระบบ
```text
User confirms action
↓
Set loading state
↓
Call API / Server Action
↓
Server returns success
↓
Refresh / Revalidate affected data
↓
Adjust pagination if necessary
↓
Close Dialog / Drawer / Sheet
↓
Reset form or selected rows
↓
Show success toast
↓
Remain on the current screen
```
กรณี Create หรือ Update ที่ต้องกลับไปหน้า List:
```text
Submit form
↓
Server returns success
↓
Revalidate list data
↓
Navigate back to list
↓
List displays latest data
↓
Show success toast
```
ต้องป้องกันการกด Action ซ้ำระหว่างกำลังดำเนินการ
---
# 7. Pagination Handling
ต้องรองรับกรณีลบรายการสุดท้ายของหน้าปัจจุบัน
ตัวอย่าง:
- ผู้ใช้อยู่หน้า 3
- หน้า 3 มีข้อมูลเพียง 1 รายการ
- ผู้ใช้ลบรายการนั้น
- หลังลบ หน้า 3 ไม่มีข้อมูลเหลือ
ระบบต้องกลับไปหน้าก่อนหน้าโดยอัตโนมัติ
ตัวอย่าง Logic:
```tsx
const isLastItemOnPage = currentItems.length === 1;
const shouldGoToPreviousPage = isLastItemOnPage && currentPage > 1;
if (shouldGoToPreviousPage) {
setPage(currentPage - 1);
} else {
await refreshData();
}
```
หาก Pagination ถูกควบคุมผ่าน URL Search Params ให้ Update URL แทน Local State
ต้องไม่ปล่อยให้ผู้ใช้เห็นหน้าว่าง ทั้งที่หน้าก่อนหน้ายังมีข้อมูล
---
# 8. Preserve User Context
หลัง Refresh ข้อมูล ต้องรักษาบริบทของผู้ใช้ไว้ให้มากที่สุด
ห้าม Reset ค่าเหล่านี้โดยไม่จำเป็น:
- Current Page
- Page Size
- Search Keyword
- Filters
- Status Tab
- Selected Year
- Company Filter
- Department Filter
- Employee Filter
- Sort Order
- Column Visibility
- Date Range
ตัวอย่าง:
ก่อนลบ:
```text
Page: 2
Search: safety
Status: approved
Year: 2026
Sort: created_at desc
```
หลังลบสำเร็จ ระบบต้องยังอยู่ในบริบทเดิม เว้นแต่หน้าปัจจุบันไม่สามารถใช้งานได้ เช่น ลบรายการสุดท้ายของหน้า
---
# 9. Sorting Standard
หลัง Create หรือ Update สำเร็จ ต้องตรวจสอบว่ารายการแสดงตาม Sorting ของระบบจริง
หากมาตรฐานของหน้ารายการคือข้อมูลที่สร้างใหม่แสดงก่อน ให้ Query ใช้:
```text
created_at DESC
```
ห้ามใช้ `updated_at DESC` แทนโดยไม่ตั้งใจ เพราะการแก้ไขรายการเก่าอาจทำให้รายการนั้นย้ายขึ้นไปด้านบน ทั้งที่มาตรฐานต้องการเรียงตามวันที่สร้าง
ให้ใช้ Sorting ตาม Requirement ของแต่ละหน้า และคง Sort เดิมหลัง Refresh
---
# 10. Dialog, Drawer และ Form Handling
หลัง Action สำเร็จ:
- ปิด Dialog, Drawer หรือ Sheet
- Reset Form เมื่อเหมาะสม
- Reset Selected File
- Reset Selected Rows
- Reset Delete Confirmation Text
- Clear Temporary State
- ปลด Loading State
- ป้องกัน Dialog ปิดก่อน Server ตอบกลับสำเร็จ
ตัวอย่าง:
```tsx
try {
setIsSubmitting(true);
await updateRecord(values);
await mutate();
setOpen(false);
form.reset();
toast.success("บันทึกข้อมูลสำเร็จ");
} catch (error) {
toast.error(getErrorMessage(error));
} finally {
setIsSubmitting(false);
}
```
กรณี Action ล้มเหลว:
- ห้ามปิด Dialog
- ห้าม Reset Form
- ห้าม Refresh รายการโดยไม่จำเป็น
- ต้องแสดง Error ที่เข้าใจได้
- ต้องคงข้อมูลที่ผู้ใช้กรอกไว้
---
# 11. Toast และ Feedback
ให้ใช้รูปแบบข้อความที่ชัดเจนและสม่ำเสมอ
ตัวอย่าง:
```text
เพิ่มข้อมูลสำเร็จ
บันทึกข้อมูลสำเร็จ
แก้ไขข้อมูลสำเร็จ
ลบข้อมูลสำเร็จ
ส่งตรวจสอบสำเร็จ
อนุมัติรายการสำเร็จ
ปฏิเสธรายการสำเร็จ
เผยแพร่ข้อมูลสำเร็จ
นำเข้าข้อมูลสำเร็จ
```
ไม่ควรแสดง Success Toast ก่อน Refresh ข้อมูลเสร็จ หากอาจทำให้ผู้ใช้เห็น Toast สำเร็จแต่ข้อมูลบนหน้าจอยังไม่เปลี่ยน
ลำดับที่แนะนำ:
```text
API Success
→ Refresh Data
→ Close Dialog
→ Toast Success
```
หาก Refresh ล้มเหลวหลัง Server บันทึกสำเร็จ ให้แสดงข้อความที่สะท้อนสถานะจริง เช่น:
```text
บันทึกข้อมูลสำเร็จ แต่ไม่สามารถโหลดข้อมูลล่าสุดได้ กรุณาลองใหม่อีกครั้ง
```
---
# 12. Loading State
ระหว่าง Action ต้องมี Loading State ที่ชัดเจน
ตัวอย่าง:
```tsx
```
สำหรับ Delete:
```tsx
```
ห้ามให้ผู้ใช้กด Action ซ้ำระหว่าง Request กำลังทำงาน
หาก Refresh Data ใช้เวลานาน ให้คง Loading State จนกว่าจะ Refresh เสร็จ
---
# 13. Optimistic Update
สามารถใช้ Optimistic Update ได้เฉพาะเมื่อมีความเหมาะสมและมี Rollback ที่ถูกต้อง
ตัวอย่างกรณี Delete:
```tsx
const previousData = data;
mutate(
{
...data,
items: data.items.filter((item) => item.id !== id),
},
false,
);
try {
await deleteRecord(id);
await mutate();
} catch (error) {
mutate(previousData, false);
throw error;
}
```
ห้ามใช้ Optimistic Update หาก:
- Action มี Workflow ซับซ้อน
- Server อาจเปลี่ยนข้อมูลเพิ่มเติม
- มี Permission Validation
- มี Approval State
- มีข้อมูล Summary หลายจุด
- มีความเสี่ยงที่ Client State จะไม่ตรงกับ Server
กรณีดังกล่าวให้ Refresh จาก Server หลัง Action สำเร็จ
---
# 14. ห้ามใช้ Full Page Reload
ห้ามใช้วิธีต่อไปนี้เป็นแนวทางหลัก:
```tsx
window.location.reload();
```
```tsx
location.reload();
```
```tsx
window.location.href = window.location.href;
```
ห้าม Navigate ออกจากหน้าแล้วกลับเข้ามาใหม่เพียงเพื่อให้ข้อมูล Refresh
อนุญาตเฉพาะกรณีมีข้อจำกัดทางเทคนิคที่พิสูจน์ได้ และต้องระบุเหตุผลใน Implementation Report
---
# 15. Related Data Revalidation
ให้ตรวจสอบว่า Action หนึ่งส่งผลต่อข้อมูลส่วนอื่นหรือไม่
ตัวอย่าง การอนุมัติ Training Record อาจส่งผลต่อ:
- Training Records List
- Pending Review List
- Pending Review Count
- Employee Training Hours
- Employee Dashboard
- HRD Dashboard
- K/S/A Summary
- Notification List
- Audit Log
ดังนั้นหลัง Approve อาจต้อง Refresh มากกว่าหนึ่ง Query
ตัวอย่าง:
```tsx
await Promise.all([
mutate(getPendingTrainingRecordsKey(filters)),
mutate(getApprovedTrainingRecordsKey()),
mutate(getEmployeeTrainingSummaryKey(employeeId, year)),
mutate(getHRDDashboardKey(year)),
mutate(getNotificationCountKey()),
]);
```
ให้ทำ Dependency Mapping สำหรับ Action สำคัญก่อนแก้ไข
---
# 16. Cache Key Standardization
ตรวจสอบและปรับ Cache Key ให้มีมาตรฐาน
ตัวอย่าง SWR Key:
```tsx
export const trainingRecordsKeys = {
all: "/api/training-records",
list: (filters: TrainingRecordFilters) => ["/api/training-records", filters],
detail: (id: string) => ["/api/training-records", id],
summary: (employeeId: string, year: number) => [
"/api/training-records/summary",
employeeId,
year,
],
};
```
ตัวอย่าง TanStack Query Key:
```tsx
export const trainingRecordKeys = {
all: ["training-records"] as const,
lists: () => [...trainingRecordKeys.all, "list"] as const,
list: (filters: TrainingRecordFilters) =>
[...trainingRecordKeys.lists(), filters] as const,
details: () => [...trainingRecordKeys.all, "detail"] as const,
detail: (id: string) => [...trainingRecordKeys.details(), id] as const,
};
```
หลีกเลี่ยงการเขียน String Key กระจัดกระจายในหลายไฟล์
---
# 17. Error Handling
ทุก Action ต้องมี Error Handling ที่สม่ำเสมอ
```tsx
try {
await action();
await refreshData();
toast.success("ดำเนินการสำเร็จ");
} catch (error) {
toast.error(getErrorMessage(error));
}
```
ต้องแยกกรณี:
- API Action ล้มเหลว
- Permission Denied
- Validation Error
- Record Not Found
- Conflict
- Network Error
- Refresh Data ล้มเหลวหลัง Action สำเร็จ
ห้ามกลืน Error โดยไม่แสดงผล
ห้ามแสดง Success Toast หาก API Action ล้มเหลว
---
# 18. Permission และ Security
การเพิ่ม Auto Refresh ต้องไม่ลดทอน Security
ต้องตรวจสอบว่า:
- Permission Validation ยังอยู่ที่ Server
- ผู้ใช้ไม่สามารถเห็นข้อมูลที่ไม่มีสิทธิ์หลัง Refresh
- Cache Key ต้องแยกตาม Scope ที่จำเป็น
- ข้อมูลระหว่าง Company หรือ Department ต้องไม่ปะปนกัน
- ห้ามพึ่ง Client-side Filtering เพื่อควบคุมสิทธิ์
- Server ต้องเป็นผู้คืนข้อมูลตาม Permission ของผู้ใช้
การ Refresh เป็นเพียงการโหลดข้อมูลใหม่ ไม่ใช่กลไก Authorization
---
# 19. Code Quality
การแก้ไขต้อง:
- ใช้ TypeScript Type ที่ชัดเจน
- หลีกเลี่ยง `any`
- ไม่ Duplicate Logic
- สร้าง Helper หรือ Custom Hook หาก Pattern ถูกใช้ซ้ำ
- ใช้ชื่อ Function ที่สื่อความหมาย
- ไม่เพิ่ม Dependency ใหม่โดยไม่จำเป็น
- รักษา Existing Coding Style
- รักษา Existing Folder Structure
- ไม่แก้ไขส่วนที่ไม่เกี่ยวข้อง
- ไม่เปลี่ยน API Contract โดยไม่จำเป็น
หากระบบมี Pattern กลางอยู่แล้ว ให้ปรับปรุง Pattern เดิมแทนสร้าง Pattern ใหม่ซ้ำซ้อน
---
# 20. Shared Helper หรือ Custom Hook
หากพบ Logic ซ้ำหลายหน้า ให้พิจารณาสร้าง Shared Helper
ตัวอย่าง:
```tsx
type RefreshOptions = {
refreshList?: () => Promise;
refreshSummary?: () => Promise;
closeDialog?: () => void;
resetForm?: () => void;
successMessage: string;
};
export async function handleSuccessfulMutation({
refreshList,
refreshSummary,
closeDialog,
resetForm,
successMessage,
}: RefreshOptions) {
await Promise.all([refreshList?.(), refreshSummary?.()]);
closeDialog?.();
resetForm?.();
toast.success(successMessage);
}
```
อย่างไรก็ตาม ห้ามสร้าง Abstraction ที่ซับซ้อนเกินความจำเป็น
ให้เลือกเฉพาะกรณีที่ช่วยลด Code ซ้ำและทำให้ระบบดูแลต่อได้ง่ายขึ้นจริง
---
# 21. Acceptance Criteria
งานจะถือว่าเสร็จเมื่อผ่านเงื่อนไขทั้งหมดต่อไปนี้
## Functional
- หลัง Create สำเร็จ รายการใหม่แสดงบน List โดยอัตโนมัติ
- หลัง Update สำเร็จ ข้อมูลที่แก้ไขแสดงทันที
- หลัง Delete สำเร็จ รายการหายจาก List ทันที
- หลัง Approve รายการย้ายออกจาก Pending และไปอยู่ Approved
- หลัง Reject สถานะใหม่แสดงทันที
- หลัง Publish สถานะ Published แสดงทันที
- หลัง Import รายการที่นำเข้าแสดงโดยไม่ต้อง Refresh Browser
- Count, Badge และ Summary ที่เกี่ยวข้องอัปเดตพร้อมกัน
- ไม่มีข้อมูลเก่าค้างบนหน้าจอหลัง Action สำเร็จ
## Pagination
- การลบรายการสุดท้ายของหน้าไม่ทำให้ค้างอยู่หน้าว่าง
- ระบบกลับไปหน้าก่อนหน้าเมื่อจำเป็น
- Page Size ไม่ถูก Reset
- Search และ Filter เดิมยังอยู่
## UX
- Dialog ปิดหลัง Action และ Refresh สำเร็จ
- Form ถูก Reset เมื่อเหมาะสม
- มี Loading State
- ปุ่มไม่สามารถกดซ้ำได้
- Success Toast แสดงหลังข้อมูลอัปเดตแล้ว
- Error ไม่ทำให้ข้อมูลใน Form หาย
## Technical
- ไม่มีการใช้ `window.location.reload()` เป็นแนวทางหลัก
- Cache Key ถูกต้อง
- ไม่มีการ Refresh Query ที่ไม่เกี่ยวข้องจำนวนมากเกินไป
- ไม่เกิด Infinite Request Loop
- ไม่เกิด Duplicate Fetch ที่ผิดปกติ
- ไม่เกิด React State Update หลัง Component Unmount
- TypeScript ผ่าน
- ESLint ผ่าน
- Build ผ่าน
- Existing Tests ผ่าน
---
# 22. Test Cases ที่ต้องดำเนินการ
ให้ทดสอบอย่างน้อยตามรายการต่อไปนี้
## Create
1. เปิดหน้ารายการ
2. เพิ่มข้อมูลใหม่
3. บันทึกสำเร็จ
4. ตรวจสอบว่ารายการใหม่ปรากฏตาม Sorting
5. ตรวจสอบว่าไม่ต้อง Refresh Browser
6. ตรวจสอบว่า Filter และ Search เดิมยังอยู่
## Update
1. แก้ไขรายการ
2. บันทึกสำเร็จ
3. ตรวจสอบว่าข้อมูลบน Table เปลี่ยนทันที
4. เปิด Detail ตรวจสอบข้อมูลล่าสุด
5. ตรวจสอบว่าไม่มีข้อมูลเก่าจาก Cache
## Delete
1. ลบรายการที่อยู่กลางหน้า
2. ตรวจสอบว่ารายการหายทันที
3. ลบรายการสุดท้ายของหน้า
4. ตรวจสอบว่าระบบกลับหน้าก่อนหน้าเมื่อจำเป็น
5. ตรวจสอบ Total Count
## Status Action
1. Submit รายการ Draft
2. ตรวจสอบว่ารายการหายจาก Draft
3. ตรวจสอบว่ารายการปรากฏใน Pending
4. Approve รายการ
5. ตรวจสอบว่า Pending Count ลดลง
6. ตรวจสอบว่า Approved Count เพิ่มขึ้น
7. ตรวจสอบ Dashboard Summary
## Error
1. จำลอง API Error
2. ตรวจสอบว่า Dialog ไม่ปิด
3. ตรวจสอบว่า Form ไม่ถูก Reset
4. ตรวจสอบว่า Success Toast ไม่แสดง
5. ตรวจสอบว่า Error Message แสดงถูกต้อง
## Concurrent Data
1. เปิดข้อมูลเดียวกันสอง Tab
2. แก้ไขข้อมูลจาก Tab แรก
3. ทำ Action จาก Tab ที่สอง
4. ตรวจสอบ Conflict Handling
5. ตรวจสอบว่าข้อมูลล่าสุดถูกโหลดหลัง Action
---
# 23. รูปแบบการดำเนินงาน
ให้ดำเนินการตามลำดับดังนี้
## Phase 1: Audit
- ค้นหาหน้าทั้งหมดที่มี CRUD และ Workflow Actions
- ระบุ Data Fetching Method ของแต่ละหน้า
- ระบุ Action ที่ยังไม่มี Auto Refresh
- ระบุ Query Key หรือ Cache Key ที่เกี่ยวข้อง
- ระบุผลกระทบต่อ Related Data
- ระบุจุดที่ใช้ `window.location.reload()`
- จัดทำรายการไฟล์ที่จะต้องแก้ไข
## Phase 2: Design
- กำหนด Refresh Strategy ของแต่ละหน้า
- กำหนด Cache Key Standard
- กำหนด Pagination Handling
- กำหนด Dependency Mapping
- กำหนด Shared Helper หากจำเป็น
## Phase 3: Implementation
- แก้ไข Action Handler
- เพิ่ม Refresh หรือ Revalidation
- ปรับ Loading State
- ปรับ Dialog และ Form Reset
- ปรับ Pagination หลัง Delete
- ปรับ Related Data Refresh
- ลบ Full Page Reload ที่ไม่จำเป็น
## Phase 4: Verification
- Run Type Check
- Run Lint
- Run Tests
- Run Build
- ทดสอบ Manual Test Cases
- ตรวจสอบ Regression
- ตรวจสอบ Network Request
- ตรวจสอบ Infinite Loop
---
# 24. Implementation Report
หลังดำเนินการเสร็จ ให้จัดทำรายงานสรุปใน Markdown โดยมีหัวข้ออย่างน้อยดังนี้
```md
# Auto Refresh Implementation Report
## 1. Executive Summary
## 2. Modules Audited
## 3. Problems Found
## 4. Root Causes
## 5. Files Changed
## 6. Refresh Strategy by Module
## 7. Cache Keys Updated
## 8. Pagination Handling
## 9. Related Data Revalidation
## 10. Full Page Reloads Removed
## 11. Test Results
## 12. Remaining Risks
## 13. Recommendations
```
ในหัวข้อ Files Changed ให้ระบุ:
- Path ของไฟล์
- สิ่งที่แก้ไข
- เหตุผลที่แก้ไข
- ผลกระทบ
- วิธีทดสอบ
---
# 25. ข้อจำกัดสำคัญ
- ห้ามแก้ไข Business Logic โดยไม่เกี่ยวข้องกับปัญหา
- ห้ามเปลี่ยน Workflow Approval
- ห้ามเปลี่ยน Permission Model
- ห้ามเปลี่ยน Database Schema หากไม่จำเป็น
- ห้ามเพิ่ม Library ใหม่โดยไม่จำเป็น
- ห้ามเปลี่ยน UI Layout โดยไม่เกี่ยวข้อง
- ห้ามลบ Feature เดิม
- ห้ามใช้ Full Page Reload เป็นวิธีแก้หลัก
- ห้าม Refresh Cache ทั้งระบบโดยไม่จำเป็น
- ห้ามปิด Dialog ก่อน Action สำเร็จ
- ห้ามแสดง Success Toast ก่อน Server ตอบกลับสำเร็จ
- ห้าม Reset Search, Filter หรือ Pagination โดยไม่จำเป็น
หากพบปัญหาอื่นนอกขอบเขต ให้บันทึกไว้ใน Implementation Report แต่ไม่ต้องแก้ไข เว้นแต่เป็น Blocking Issue ที่ทำให้งานนี้ไม่สามารถทำงานได้
---
# 26. Definition of Done
งานนี้ถือว่าเสร็จสมบูรณ์เมื่อ:
1. ทุกหน้าที่มี CRUD หรือ Workflow Action ได้รับการตรวจสอบ
2. ทุก Action สำคัญมี Auto Refresh
3. ข้อมูลบนหน้าจอตรงกับ Server หลัง Action
4. Related Count และ Summary อัปเดตถูกต้อง
5. Search, Filter, Sort และ Pagination ยังคงเดิม
6. Delete รายการสุดท้ายของหน้าถูกจัดการถูกต้อง
7. ไม่มี Full Page Reload ที่ไม่จำเป็น
8. ไม่มี Infinite Fetch Loop
9. TypeScript, Lint และ Build ผ่าน
10. มี Implementation Report ฉบับสมบูรณ์
---
# คำสั่งเริ่มต้น
เริ่มจากตรวจสอบ Codebase ปัจจุบันก่อน ห้ามแก้ไขทันทีโดยยังไม่ทราบว่าแต่ละหน้าใช้ Data Fetching และ Cache Strategy แบบใด
จากนั้นให้สรุป:
1. Module ที่ตรวจพบ
2. หน้าที่มีปัญหา Auto Refresh
3. วิธี Fetch ข้อมูลของแต่ละหน้า
4. Action ที่ยังไม่ Refresh
5. Cache Key ที่เกี่ยวข้อง
6. ไฟล์ที่ต้องแก้ไข
7. แผนการแก้ไข
เมื่อสรุปแล้ว ให้ดำเนินการแก้ไขทุกจุดที่อยู่ในขอบเขตจนเสร็จ พร้อมทดสอบและจัดทำ Implementation Report
ไม่ต้องหยุดเพื่อถามยืนยันระหว่างการดำเนินงาน เว้นแต่พบข้อขัดแย้งที่ไม่สามารถตัดสินใจจาก Codebase และ Requirement ที่มีอยู่ได้