# 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 และการแก้ไข
