หลักการเขียน PLAN.md สำหรับ AI Agent
หลักการเขียน PLAN.md
เอกสารนี้อธิบายหลักการและเหตุผลของแต่ละส่วนใน PLAN.md เพื่อให้ทั้ง Human และ AI Agent เข้าใจตรงกัน
ภาพรวม: PLAN.md คืออะไร
PLAN.md คือ สัญญาว่า Feature นี้ทำอะไร และ แผนงานสำหรับ AI Agent
ผู้อ่าน PLAN.md มี 2 กลุ่มที่ต้องการข้อมูลคนละแบบ:
| ผู้อ่าน | ต้องการรู้ | อ่านส่วนไหน |
|---|---|---|
| PM / Stakeholder | Feature นี้ 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 concern | SEO: og tags, JSON-LD, RSS |
| ❌ อย่าเขียน technical detail | สร้าง content.config.ts |
| ❌ อย่าเขียน Story ที่เป็น implementation detail | Config: 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 ทุกตัวต้องอยู่ในหนึ่งในสองประเภท:
- User-facing — relate กับ Scope item โดยตรง
- 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 / schema | code task — backend |
[FE-BL] | Frontend Business Logic (store, hook, composable) | code task — frontend logic |
[FE] | UI Component หรือ Page | code task — UI |
[FE-IT] | Integration Test FE ↔ API | code task — integration |
[Config] | Config / Env / Schema definition | code task — configuration |
[CHORE] | Non-code maintenance — ย้ายไฟล์, ลบ legacy, rename, migrate content | non-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 เขียน)