หลักการเขียน PLAN.md สำหรับ AI Agent

หลักการเขียน PLAN.md

เอกสารนี้อธิบายหลักการและเหตุผลของแต่ละส่วนใน PLAN.md เพื่อให้ทั้ง Human และ AI Agent เข้าใจตรงกัน


ภาพรวม: PLAN.md คืออะไร

PLAN.md คือ สัญญาว่า Feature นี้ทำอะไร และ แผนงานสำหรับ AI Agent

ผู้อ่าน PLAN.md มี 2 กลุ่มที่ต้องการข้อมูลคนละแบบ:

ผู้อ่านต้องการรู้อ่านส่วนไหน
PM / StakeholderFeature นี้ deliver อะไรให้ User?Goal + Scope + Out of Scope
Dev / AI Agentต้องทำอะไรบ้าง?Story + Task + implementation detail

ส่วนที่ 1: Goal

เขียนอะไร: deploy แล้ว user ทำอะไรได้บ้าง — ไม่เกิน 2 บรรทัด

หลักการ: เขียนจากมุม User ไม่ใช่มุม Developer

## Goal
User อ่านบทความ access: free ทั้งหมดได้ผ่าน /articles/[category]/[slug]
Deploy ได้ทันทีโดยไม่รอ auth/payment

ห้าม: อธิบาย technical implementation ใน Goal


ส่วนที่ 2: Scope (ทำ)

Scope คืออะไร

Capability ที่ User ได้ จาก Feature นี้ — ภาษา business ไม่ใช่ technical

Format: ใช้ Table ไม่ใช่ Bullet List

## Scope (ทำ)

| Capability | Story |
|---|---|
| อ่านบทความ free ได้ผ่าน /articles/[category]/[slug] | Story 1.3 |
| Browse บทความแยกตาม category | Story 1.3 |
| SEO: og tags, JSON-LD, RSS | Story 1.4 |

ทำไมต้องเป็น Table

เพราะ Table บังคับให้ระบุ Scope item → Story ชัดเจนเสมอ

Bullet list  →  ไม่รู้ว่า Story ไหนรับผิดชอบ → งานอาจหาย
Table        →  เห็น mapping ทันที → ตรวจสอบได้ทุกเวลา

กฎ Scope Item

กฎตัวอย่าง
✅ เขียนในแง่ User เห็นBrowse บทความแยกตาม category
✅ ระบุ Route ที่เปิดให้ใช้Pages: /articles, /articles/[category]/[slug]
✅ Cross-cutting concernSEO: og tags, JSON-LD, RSS
❌ อย่าเขียน technical detailสร้าง content.config.ts (นี่คือ implementation detail ของ Story)
❌ อย่าเขียน Story ที่เป็น implementation detailConfig: articles collection schema

Story ที่ไม่ต้องอยู่ใน Scope

Story บางตัวเป็น implementation detail ที่ User ไม่เห็นตรงๆ แต่จำเป็นต้องทำ

Story 1.2: content.config.ts   →  User ไม่เห็น แต่ Story 1.3 depend on it
                                   ไม่ต้องอยู่ใน Scope
                                   แต่ต้องทำเพื่อให้ Story 1.3 ทำงานได้

ส่วนที่ 3: Out of Scope (ไม่ทำ)

Out of Scope คืออะไร

สิ่งที่ อาจเข้าใจผิดว่าต้องทำใน Feature นี้ แต่จริงๆ ไม่ใช่งานของ Feature นี้

3 ประเภทที่ต้องเขียน

ประเภท 1: Defer ไป Feature อื่น

สิ่งที่จะทำอยู่แล้ว แต่ไม่ใช่ตอนนี้

- Access guard สำหรับ paid content → ทำใน `articles-section-paid`

ต้องระบุ destination เสมอ — ถ้าไม่ระบุ งานมีโอกาสหาย

ประเภท 2: ตัดออกเพื่อ Simplify

สิ่งที่ stakeholder อาจ expect ว่ามี แต่ตัดออกด้วยเหตุผล

- Multiple subscription tiers (MVP แค่ has/doesn't have subscription)
- Refund flow
- Admin dashboard

อธิบายสั้นๆ ว่าทำไมตัดออก ป้องกันคำถามซ้ำ

ประเภท 3: Concern ของ Feature อื่น

สิ่งที่อยู่ใน project เดียวกันแต่เป็น Feature แยก

- Video player → ทำใน `videos-section`
- Auth/Payment ทุกรูปแบบ → ทำใน `auth-payment`

ถามตัวเองก่อนเขียน Out of Scope

“ถ้าคนอ่าน PLAN.md นี้แล้วถามว่า ‘แล้ว [X] ล่ะ?’ — ควรมีคำตอบใน Out of Scope ไหม?”

ถ้า [X] เป็นสิ่งที่สมเหตุสมผลที่จะถาม → ใส่


ส่วนที่ 4: Current State

เขียนอะไร: สถานะปัจจุบันของ code / files ก่อนเริ่มงาน

## Current State (as of YYYY-MM-DD)

src/content/
├── blog/            ← มีอยู่แล้ว → จะ migrate → articles/
└── typescripts/     ← มีอยู่แล้ว → จะ migrate → articles/typescript/

src/content.config.ts  ← registered: blog + typescripts (temporary)

ทำไมต้องมี: AI Agent ใช้ Current State เพื่อรู้ว่าเริ่มต้นจากตรงไหน ไม่ต้องไล่ analyze codebase เอง


ส่วนที่ 5: Stories

Story คืออะไร

กลุ่มงานที่ deliver ความสามารถชัดเจน 1 อย่าง ภายใน Feature

ความสัมพันธ์ Story กับ Scope

Scope item  →  บอกว่า "User ได้อะไร"    (ภาษา business)
Story       →  บอกว่า "ทำด้วยวิธีไหน"   (ภาษา dev)

Story ทุกตัวต้องอยู่ในหนึ่งในสองประเภท:

  1. User-facing — relate กับ Scope item โดยตรง
  2. Implementation detail — support Story อื่น แต่ไม่ต้องอยู่ใน Scope

Format Story Header

## Story 1.3: Article Pages
> 🧪 Story Test: [tests/story-1.3-article-pages.md](tests/story-1.3-article-pages.md) — รันก่อน commit

Implementation Detail ใต้ Story

เขียน bullet ที่ละเอียดพอให้ AI Agent ทำงานได้โดยไม่ต้องถาม

## Story 1.3: Article Pages
- ลบ `pages/blog/` เดิม
- สร้าง `pages/articles/index.astro``/articles`
- สร้าง `pages/articles/[category]/index.astro``/articles/[category]`
- สร้าง `pages/articles/[category]/[slug].astro``/articles/[category]/[slug]`

ส่วนที่ 6: Tasks (ภายใน Story)

Task คืออะไร

งานที่จับต้องได้ภายใน Story — ทุก Story ต้องมี Task เสมอ ไม่ว่างานจะเป็นแบบไหน

รวมถึงงานที่ไม่ใช่ code เช่น ย้ายไฟล์ ลบ legacy folder — เพื่อให้ Template สม่ำเสมอ และ CHECKLIST.md ติดตามได้ครบทุกขั้นตอน

Format

### TASK: [FE] ArticleCard Component
> 🧪 [tests/task-1.3-fe-article-card.md](tests/task-1.3-fe-article-card.md)
- รับ props: title, description, pubDate, category, slug
- แสดง heroImage ถ้ามี
- Link ไปที่ /articles/[category]/[slug]

Task Types

Typeใช้เมื่อAI อ่านแล้วรู้ว่า
[API]Backend endpoint / service / schemacode task — backend
[FE-BL]Frontend Business Logic (store, hook, composable)code task — frontend logic
[FE]UI Component หรือ Pagecode task — UI
[FE-IT]Integration Test FE ↔ APIcode task — integration
[Config]Config / Env / Schema definitioncode task — configuration
[CHORE]Non-code maintenance — ย้ายไฟล์, ลบ legacy, rename, migrate contentnon-code maintenance task

[CHORE] มาจาก git conventional commits (chore:) ซึ่ง Dev คุ้นเคยอยู่แล้ว AI Agent อ่าน [CHORE] แล้วรู้ทันทีว่าเป็น non-code maintenance task — ไม่ต้อง interpret จาก description

ตัวอย่าง [CHORE] Task

### TASK: [CHORE] Migrate Blog Content → Articles
- ย้าย src/content/blog/ → src/content/articles/general/
- ย้าย src/content/typescripts/ → src/content/articles/typescript/
- ลบ src/pages/blog/ ทั้งหมด
- ตรวจว่าไม่มี broken import หลังย้าย

การ Validate ความถูกต้องของ PLAN.md

✅ Checklist ก่อน Commit PLAN.md

[ ] ทุก Scope item มี Story อ้างอิงในตาราง
[ ] ทุก Story ที่ User-facing relate กับ Scope item
[ ] Out of Scope มี destination สำหรับทุก "defer" item
[ ] ไม่มี Story ที่ทำสิ่งที่อยู่ใน Out of Scope
[ ] Current State ตรงกับ codebase จริง
[ ] ทุก Task มี type label ใน format [TYPE]

ตรวจ Scope ↔ Story ใน CHECKLIST.md

เมื่อ tick Story ใน CHECKLIST.md เสร็จ → กลับไปดู Scope Coverage Check ก่อน merge:

Story 1.1 done  →  Scope "Migrate content" ✓ covered
Story 1.3 done  →  Scope "Pages + free access" ✓ covered
Story 1.4 done  →  Scope "SEO" ✓ covered

ตัวอย่างเปรียบเทียบ: ดี vs ไม่ดี

Scope

❌ ไม่ดี
## Scope (ทำ)
- สร้าง articles collection
- สร้าง pages
- SEO

✅ ดี
## Scope (ทำ)

| Capability | Story |
|---|---|
| อ่านบทความ access: free ผ่าน /articles/[category]/[slug] | Story 1.3 |
| Browse บทความแยกตาม category | Story 1.3 |
| SEO: og tags, JSON-LD, RSS | Story 1.4 |

Out of Scope

❌ ไม่ดี
## Out of Scope (ไม่ทำ)
- paid content
- video
- auth

✅ ดี
## Out of Scope (ไม่ทำ)
- Access guard สำหรับ paid content → ทำใน `articles-section-paid`
- Video player → ทำใน `videos-section`
- Auth/Payment ทุกรูปแบบ → ทำใน `auth-payment`
- Multiple subscription tiers (MVP: has/doesn't have subscription เท่านั้น)

สรุปสั้น

Goal          = "User ทำอะไรได้บ้าง"                       (1-2 บรรทัด)
Scope         = "Capability → Story"                       (table)
Out of Scope  = "ไม่ทำ + ไปอยู่ที่ไหน"                     (bullet + destination)
Current State = "เริ่มต้นจากตรงไหน"                        (file tree)
Story         = "ทำด้วยวิธีไหน"                            (implementation steps)
Task [API]    = "Backend code"                             (Human เขียน)
Task [FE-BL]  = "Frontend logic code"                      (Human เขียน)
Task [FE]     = "UI code"                                  (Human เขียน)