Skip to content

แนวคิด

คู่มือนี้อธิบายแนวคิดหลักเบื้องหลัง OpenSpec และวิธีที่แนวคิดเหล่านี้เชื่อมโยงกัน สำหรับการใช้งานจริง โปรดดูที่ เริ่มต้นใช้งาน และ ขั้นตอนการทำงาน

ปรัชญา

OpenSpec สร้างขึ้นจากหลักการสี่ประการ:

fluid not rigid         — no phase gates, work on what makes sense
iterative not waterfall — learn as you build, refine as you go
easy not complex        — lightweight setup, minimal ceremony
brownfield-first        — works with existing codebases, not just greenfield

ทำไมหลักการเหล่านี้จึงสำคัญ

Fluid not rigid (ยืดหยุ่น ไม่แข็งทื่อ). ระบบข้อกำหนดแบบดั้งเดิมจะล็อคคุณให้อยู่ในขั้นตอน: ขั้นแรกวางแผน จากนั้นจึงนำไปปฏิบัติ แล้วก็เสร็จ OpenSpec มีความยืดหยุ่นมากกว่า — คุณสามารถสร้างผลลัพธ์ในลำดับใดก็ได้ที่เหมาะสมกับงานของคุณ

Iterative not waterfall (ทำซ้ำ ไม่ใช่วอเตอร์ฟอล). ข้อกำหนดมีการเปลี่ยนแปลง ความเข้าใจลึกซึ้งยิ่งขึ้น สิ่งที่ดูเหมือนเป็นแนวทางที่ดีในตอนเริ่มต้นอาจไม่สามารถใช้ได้หลังจากที่คุณเห็นโค้ดเบส OpenSpec ยอมรับความเป็นจริงนี้

Easy not complex (ง่าย ไม่ซับซ้อน). บางกรอบงานข้อกำหนดต้องมีการตั้งค่าอย่างกว้างขวาง รูปแบบที่เข้มงวด หรือกระบวนการที่หนัก OpenSpec ไม่เข้ามาขวางทางคุณ เริ่มต้นใช้งานได้ในไม่กี่วินาที เริ่มทำงานได้ทันที ปรับแต่งเฉพาะเมื่อจำเป็น

Brownfield-first (ให้ความสำคัญกับระบบเดิมก่อน). งานซอฟต์แวร์ส่วนใหญ่ไม่ใช่การสร้างจากศูนย์ — แต่เป็นการปรับเปลี่ยนระบบที่มีอยู่ แนวทางแบบเดลต้าของ OpenSpec ทำให้ง่ายต่อการระบุการเปลี่ยนแปลงพฤติกรรมที่มีอยู่ ไม่ใช่แค่การอธิบายระบบใหม่

ภาพรวมทั้งหมด

OpenSpec จัดระเบียบงานของคุณออกเป็นสองพื้นที่หลัก:

┌────────────────────────────────────────────────────────────────────┐
│                        openspec/                                   │
│                                                                    │
│   ┌─────────────────────┐      ┌───────────────────────────────┐   │
│   │       specs/        │      │         changes/              │   │
│   │                     │      │                               │   │
│   │  แหล่งข้อมูลจริง    │◄─────│  การแก้ไขที่เสนอ              │   │
│   │  ระบบของคุณทำงาน    │ merge│  แต่ละการเปลี่ยนแปลง = โฟลเดอร์เดียว │   │
│   │  อย่างไรในปัจจุบัน  │      │  มีสิ่งประดิษฐ์ + เดลต้า     │   │
│   │                     │      │                               │   │
│   └─────────────────────┘      └───────────────────────────────┘   │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘

ข้อกำหนด (Specs) คือแหล่งข้อมูลจริง — อธิบายว่าระบบของคุณทำงานอย่างไรในปัจจุบัน

การเปลี่ยนแปลง (Changes) คือการแก้ไขที่เสนอ — เก็บไว้ในโฟลเดอร์แยกจนกว่าคุณจะพร้อมรวมเข้าด้วยกัน

การแยกส่วนนี้เป็นกุญแจสำคัญ คุณสามารถทำงานกับหลายการเปลี่ยนแปลงพร้อมกันได้โดยไม่ขัดแย้ง คุณสามารถตรวจสอบการเปลี่ยนแปลงก่อนที่จะส่งผลต่อข้อกำหนดหลัก และเมื่อคุณเก็บถาวรการเปลี่ยนแปลง เดลต้าของมันจะรวมเข้ากับแหล่งข้อมูลจริงอย่างราบรื่น

พื้นที่ทำงานประสานงาน

การรองรับพื้นที่ทำงานอยู่ระหว่างการพัฒนาอย่างแข็งขันและยังไม่พร้อมใช้งาน อย่าสร้างระบบอัตโนมัติภายนอก การบูรณาการ หรือเวิร์กโฟลว์ที่มีอายุยาวนานบนพฤติกรรมของพื้นที่ทำงาน คำสั่ง ไฟล์สถานะ และเอาต์พุต JSON อาจเปลี่ยนแปลงได้ตลอดเวลา

คำสั่งด้านล่างนี้ให้ขั้นตอนการตั้งค่าเบื้องต้นสำหรับการวางแผนข้าม repos หรือโฟลเดอร์ที่เชื่อมโยง

โปรเจกต์ OpenSpec ที่อยู่ใน repo เป็นค่าเริ่มต้นที่เหมาะสมเมื่อ repo เดียวเป็นเจ้าของขั้นตอนการวางแผน การดำเนินการ และการเก็บถาวร บางงานครอบคลุมหลาย repos หรือโฟลเดอร์ สำหรับกรณีนั้น พื้นที่ทำงานประสานงานของ OpenSpec คือบ้านวางแผนที่ยั่งยืน

โมเดลทางจิตของพื้นที่ทำงานคือ:

text
workspace = ที่ที่การเปลี่ยนแปลงข้าม repo ที่เกี่ยวข้องอยู่
link      = ชื่อที่เสถียรสำหรับ repo หรือโฟลเดอร์ที่พื้นที่ทำงานสามารถวางแผนได้
change    = คุณลักษณะ การแก้ไข โปรเจกต์ หรือส่วนงานที่วางแผนไว้อื่นๆ หนึ่งรายการ

พื้นที่ทำงานมีรูปร่างที่แตกต่างจากโปรเจกต์ที่อยู่ใน repo:

text
workspace-folder/
├── changes/                       # การวางแผนระดับพื้นที่ทำงาน
└── .openspec-workspace/
    ├── workspace.yaml             # ตัวตนพื้นที่ทำงานที่ใช้ร่วมกันและชื่อลิงก์
    └── local.yaml                 # เส้นทางท้องถิ่นของเครื่องนี้

สถานะ OpenSpec ที่อยู่ใน repo ยังคงรูปร่างเดิม:

text
repo-root/
└── openspec/
    ├── specs/
    └── changes/

ความแตกต่างนี้มีความสำคัญ โฟลเดอร์พื้นที่ทำงานเป็นพื้นผิวประสานงานสำหรับการวางแผนข้าม repos หรือโฟลเดอร์ที่เชื่อมโยง ไดเรกทอรี openspec/ ของแต่ละ repo ยังคงเป็นบ้านสำหรับข้อกำหนดที่ repo เป็นเจ้าของ การเปลี่ยนแปลงที่อยู่ใน repo และการวางแผนการดำเนินการ ผู้ใช้ไม่จำเป็นต้องรัน openspec init ที่อยู่ใน repo ภายในโฟลเดอร์พื้นที่ทำงาน

ชื่อลิงก์ที่เสถียรคือวิธีที่การวางแผนพื้นที่ทำงานอ้างถึง repos และโฟลเดอร์ สถานะพื้นที่ทำงานที่ใช้ร่วมกันเก็บชื่อเช่น api, web หรือ checkout แต่ละเครื่องแมปชื่อเหล่านั้นไปยังเส้นทางท้องถิ่นของตัวเองใน .openspec-workspace/local.yaml

yaml
# .openspec-workspace/workspace.yaml
version: 1
name: platform
links:
  api: {}
  web: {}
yaml
# .openspec-workspace/local.yaml
version: 1
paths:
  api: /repos/api
  web: /repos/web

พื้นที่ทำงานที่สร้างโดย OpenSpec จะไม่รวม .openspec-workspace/local.yaml ออกจากสถานะการพกพาสำหรับการทำงานร่วมกันโดยค่าเริ่มต้น .openspec-workspace/workspace.yaml ยังคงพกพาได้เนื่องจากเก็บชื่อพื้นที่ทำงานและชื่อลิงก์ที่เสถียร ไม่ใช่เส้นทาง checkout แบบสัมบูรณ์ของผู้ใช้รายใดรายหนึ่ง

เส้นทางที่เชื่อมโยงอาจเป็น repos เต็มรูปแบบ โฟลเดอร์ภายใน monorepo ขนาดใหญ่ หรือโฟลเดอร์ที่มีอยู่อื่นๆ ไม่จำเป็นต้องมีสถานะ openspec/ ที่อยู่ใน repo ก่อนจึงจะเข้าร่วมการวางแผนพื้นที่ทำงานได้ เวิร์กโฟลว์การดำเนินการ การตรวจสอบ หรือการเก็บถาวรในภายหลังอาจต้องการความพร้อมของ repo มากขึ้น แต่การมองเห็นในการวางแผนเริ่มต้นจากลิงก์

text
multi-repo:
  api      -> /repos/api
  web      -> /repos/web

large monorepo:
  billing  -> /repos/platform/services/billing
  checkout -> /repos/platform/apps/checkout

พื้นที่ทำงานที่จัดการอยู่ภายใต้ไดเรกทอรีข้อมูล OpenSpec มาตรฐาน:

text
getGlobalDataDir()/workspaces

ซึ่งหมายความว่า $XDG_DATA_HOME/openspec/workspaces เมื่อตั้งค่า XDG_DATA_HOME, ~/.local/share/openspec/workspaces บน fallback แบบ Unix และ %LOCALAPPDATA%\openspec\workspaces บน fallback ดั้งเดิมของ Windows เชลล์ดั้งเดิมของ Windows, PowerShell และ WSL2 แต่ละตัวเก็บสตริงเส้นทางสำหรับรันไทม์ที่รัน OpenSpec พื้นฐานนี้ไม่แปลงระหว่าง D:\repo, /mnt/d/repo และเส้นทาง UNC WSL

OpenSpec ยังเก็บรีจิสทรีเฉพาะเครื่องที่:

text
getGlobalDataDir()/workspaces/registry.yaml

รีจิสทรีแมปชื่อพื้นที่ทำงานไปยังตำแหน่งพื้นที่ทำงาน เพื่อให้คำสั่งทั่วไปในภายหลังสามารถแสดงรายการหรือเลือกพื้นที่ทำงานที่รู้จักจากที่ใดก็ได้ เป็นเพียงดัชนีเท่านั้น โฟลเดอร์พื้นที่ทำงานแต่ละแห่งยังคงมีอำนาจสูงสุดสำหรับ .openspec-workspace/workspace.yaml และ .openspec-workspace/local.yaml ของตัวเอง ดังนั้นบันทึกรีจิสทรีที่ล้าสมัยสามารถรายงานและซ่อมแซมได้โดยไม่ต้องกำหนดพื้นที่ทำงานใหม่

การมองเห็นพื้นที่ทำงานไม่ใช่ความมุ่งมั่นในการเปลี่ยนแปลง ตั้งค่าพื้นที่ทำงานเมื่อ OpenSpec ควรรู้ว่า repos หรือโฟลเดอร์ใดเกี่ยวข้อง สร้างการเปลี่ยนแปลงในภายหลังเมื่อคุณพร้อมที่จะวางแผนคุณลักษณะ การแก้ไข โปรเจกต์ หรือส่วนงานอื่นๆ

คำสั่งที่เป็นประโยชน์:

bash
# การตั้งค่าแบบมีคำแนะนำ
openspec workspace setup

# การตั้งค่าที่เป็นมิตรกับระบบอัตโนมัติ
openspec workspace setup --no-interactive --name platform --link /repos/api --link web=/repos/web
openspec workspace setup --no-interactive --name platform --link /repos/api --opener codex

# ดูพื้นที่ทำงานที่รู้จักจากรีจิสทรีท้องถิ่น
openspec workspace list
openspec workspace ls

# เพิ่มหรือซ่อมแซมลิงก์สำหรับพื้นที่ทำงานที่เลือก
openspec workspace link /repos/api
openspec workspace link api-service /repos/api
openspec workspace relink api-service /new/path/to/api

# ตรวจสอบว่าเครื่องนี้สามารถแก้ไขอะไรได้บ้าง
openspec workspace doctor
openspec workspace doctor --workspace platform

# เปิดชุดงานที่เชื่อมโยง
openspec workspace open
openspec workspace open platform --agent github-copilot
openspec workspace open --editor

workspace setup เสมอสร้างพื้นที่ทำงานในตำแหน่งพื้นที่ทำงานมาตรฐาน บันทึกในรีจิสทรีท้องถิ่น แสดงตำแหน่งพื้นที่ทำงาน และต้องมี repo หรือโฟลเดอร์ที่เชื่อมโยงอย่างน้อยหนึ่งรายการ การตั้งค่าแบบโต้ตอบถามหาตัวเปิดที่ต้องการ การตั้งค่าแบบไม่โต้ตอบเก็บตัวเปิดเมื่อระบุ --opener codex, --opener claude, --opener github-copilot หรือ --opener editor เท่านั้น

OpenSpec ยังคงรักษาไฟล์เปิดพื้นที่ทำงานราก: บล็อกคำแนะนำที่จัดการโดย OpenSpec ใน AGENTS.md, ไฟล์ <workspace-name>.code-workspace เฉพาะเครื่องสำหรับ VS Code และ GitHub Copilot-in-VS-Code เปิด และรายการละเว้นเฉพาะสำหรับไฟล์ .code-workspace ที่ดูแลรักษา ไฟล์ *.code-workspace ที่ผู้ใช้สร้างขึ้นยังคงติดตามได้เนื่องจากกฎการละเว้นกำหนดเป้าหมายเฉพาะไฟล์ที่ดูแลรักษาเท่านั้น

พื้นที่ทำงาน VS Code ที่ดูแลรักษารวมรากประสานงานเป็น . พร้อม repos หรือโฟลเดอร์ที่เชื่อมโยงที่ถูกต้องเป็นรากเพิ่มเติม VS Code แสดงรายการเหล่านั้นเป็นพื้นที่ทำงานหลายราก

workspace open เปิดชุดงานที่เชื่อมโยงด้วยตัวเปิดที่ต้องการที่เก็บไว้ เว้นแต่จะส่ง --agent <tool> หรือ --editor สำหรับเซสชันนั้น การส่งทั้งสองตัวเลือกตัวเปิดถือเป็นข้อผิดพลาด การเปิดพื้นที่ทำงานรากทำให้ repos และโฟลเดอร์ที่เชื่อมโยงมองเห็นได้สำหรับการสำรวจและการวางแผน การดำเนินการเริ่มต้นหลังจากที่ผู้ใช้ร้องขออย่างชัดเจน

workspace link และ workspace relink บันทึกเฉพาะโฟลเดอร์ที่มีอยู่เท่านั้น ไม่สร้าง คัดลอก ย้าย เริ่มต้น หรือแก้ไข repo หรือโฟลเดอร์ที่เชื่อมโยง หลังจากลิงก์หรือลิงก์ใหม่สำเร็จ OpenSpec จะรีเฟรชคำแนะนำที่จัดการ ไฟล์พื้นที่ทำงาน VS Code และกฎการละเว้น

คำสั่งพื้นที่ทำงานที่ต้องการพื้นที่ทำงานหนึ่งแห่งสามารถรันจากที่ใดก็ได้ด้วย --workspace <name> หากคุณรันคำสั่งภายในโฟลเดอร์พื้นที่ทำงานหรือไดเรกทอรีย่อย OpenSpec จะใช้พื้นที่ทำงานปัจจุบันนั้น หากมีพื้นที่ทำงานที่รู้จักหลายแห่งและคุณไม่ได้ส่ง --workspace <name> คำสั่งของผู้ใช้จะแสดงตัวเลือก --json และ --no-interactive จะล้มเหลวด้วยข้อผิดพลาดสถานะที่มีโครงสร้างแทนการแจ้งเตือน

คำสั่งพื้นที่ทำงานโดยตรงรองรับเอาต์พุต JSON สำหรับสคริปต์ การตอบกลับ JSON เก็บข้อมูลหลักในอ็อบเจกต์ workspace, workspaces หรือ link และรายงานคำเตือนหรือข้อผิดพลาดในอาร์เรย์ status อ็อบเจกต์ที่แข็งแรงใช้ status: []

ข้อกำหนด (Specs)

ข้อกำหนดอธิบายพฤติกรรมของระบบของคุณโดยใช้ข้อกำหนดและสถานการณ์ที่มีโครงสร้าง

โครงสร้าง

openspec/specs/
├── auth/
│   └── spec.md           # พฤติกรรมการยืนยันตัวตน
├── payments/
│   └── spec.md           # การประมวลผลการชำระเงิน
├── notifications/
│   └── spec.md           # ระบบการแจ้งเตือน
└── ui/
    └── spec.md           # พฤติกรรม UI และธีม

จัดระเบียบข้อกำหนดตามโดเมน — การจัดกลุ่มเชิงตรรกะที่สมเหตุสมผลสำหรับระบบของคุณ รูปแบบทั่วไป:

  • ตามพื้นที่คุณลักษณะ: auth/, payments/, search/
  • ตามส่วนประกอบ: api/, frontend/, workers/
  • ตามบริบทที่มีขอบเขต: ordering/, fulfillment/, inventory/

รูปแบบข้อกำหนด

ข้อกำหนดประกอบด้วยข้อกำหนด และแต่ละข้อกำหนดมีสถานการณ์:

markdown
# ข้อกำหนดการยืนยันตัวตน

วัตถุประสงค์

การยืนยันตัวตนและการจัดการเซสชันสำหรับแอปพลิเคชัน

ข้อกำหนด

ข้อกำหนด: การยืนยันตัวตนผู้ใช้

ระบบ SHALL ออกโทเค็น JWT เมื่อเข้าสู่ระบบสำเร็จ

สถานการณ์: ข้อมูลรับรองที่ถูกต้อง

  • GIVEN ผู้ใช้ที่มีข้อมูลรับรองที่ถูกต้อง
  • WHEN ผู้ใช้ส่งแบบฟอร์มเข้าสู่ระบบ
  • THEN โทเค็น JWT จะถูกส่งคืน
  • AND ผู้ใช้จะถูกเปลี่ยนเส้นทางไปยังแดชบอร์ด

สถานการณ์: ข้อมูลรับรองไม่ถูกต้อง

  • GIVEN ข้อมูลรับรองที่ไม่ถูกต้อง
  • WHEN ผู้ใช้ส่งแบบฟอร์มเข้าสู่ระบบ
  • THEN ข้อความแสดงข้อผิดพลาดจะปรากฏขึ้น
  • AND ไม่มีโทเค็นถูกออก

ข้อกำหนด: การหมดอายุของเซสชัน

ระบบ MUST ทำให้เซสชันหมดอายุหลังจากไม่มีการใช้งาน 30 นาที

สถานการณ์: หมดเวลาเนื่องจากไม่มีการใช้งาน

  • GIVEN เซสชันที่ผ่านการยืนยันตัวตนแล้ว
  • WHEN ผ่านไป 30 นาทีโดยไม่มีกิจกรรม
  • THEN เซสชันจะถูกทำให้ไม่ถูกต้อง
  • AND ผู้ใช้ต้องยืนยันตัวตนใหม่

**องค์ประกอบหลัก:**

| องค์ประกอบ | วัตถุประสงค์ |
|------------|--------------|
| `## Purpose` | คำอธิบายระดับสูงของโดเมนข้อกำหนดนี้ |
| `### Requirement:` | พฤติกรรมเฉพาะที่ระบบต้องมี |
| `#### Scenario:` | ตัวอย่างที่เป็นรูปธรรมของข้อกำหนดในการดำเนินการ |
| SHALL/MUST/SHOULD | คำสำคัญ RFC 2119 ที่บ่งบอกความแข็งแกร่งของข้อกำหนด |

### เหตุใดจึงจัดโครงสร้างข้อกำหนดในลักษณะนี้

**ข้อกำหนดคือ "สิ่งที่"** — ข้อกำหนดระบุว่าระบบควรทำอะไรโดยไม่ระบุการนำไปใช้

**สถานการณ์คือ "เมื่อใด"** — สถานการณ์ให้ตัวอย่างที่เป็นรูปธรรมซึ่งสามารถตรวจสอบได้ สถานการณ์ที่ดี:
- สามารถทดสอบได้ (คุณสามารถเขียนการทดสอบอัตโนมัติสำหรับมันได้)
- ครอบคลุมทั้งเส้นทางที่ดีและกรณีขอบ
- ใช้รูปแบบ Given/When/Then หรือรูปแบบที่มีโครงสร้างคล้ายกัน

**คำสำคัญ RFC 2119** (SHALL, MUST, SHOULD, MAY) สื่อสารเจตนา:
- **MUST/SHALL** — ข้อกำหนดสัมบูรณ์
- **SHOULD** — แนะนำ แต่มีข้อยกเว้น
- **MAY** — ไม่บังคับ

### สิ่งที่ข้อกำหนดเป็น (และไม่เป็น)

ข้อกำหนดคือ **สัญญาพฤติกรรม** ไม่ใช่แผนการนำไปใช้

เนื้อหาข้อกำหนดที่ดี:
- พฤติกรรมที่สังเกตได้ซึ่งผู้ใช้หรือระบบปลายน้ำพึ่งพา
- อินพุต เอาต์พุต และเงื่อนไขข้อผิดพลาด
- ข้อจำกัดภายนอก (ความปลอดภัย ความเป็นส่วนตัว ความน่าเชื่อถือ ความเข้ากันได้)
- สถานการณ์ที่สามารถทดสอบหรือตรวจสอบอย่างชัดเจน

สิ่งที่ควรหลีกเลี่ยงในข้อกำหนด:
- ชื่อคลาส/ฟังก์ชันภายใน
- ทางเลือกไลบรารีหรือเฟรมเวิร์ก
- รายละเอียดการนำไปใช้ทีละขั้นตอน
- แผนการดำเนินงานโดยละเอียด (สิ่งเหล่านั้นอยู่ใน `design.md` หรือ `tasks.md`)

การทดสอบอย่างรวดเร็ว:
- หากการนำไปใช้สามารถเปลี่ยนแปลงได้โดยไม่เปลี่ยนแปลงพฤติกรรมที่มองเห็นจากภายนอก ก็อาจไม่ควรอยู่ในข้อกำหนด

### รักษาความเบา: ความเข้มงวดแบบก้าวหน้า

OpenSpec มุ่งหวังที่จะหลีกเลี่ยงระบบราชการ ใช้ระดับที่เบาที่สุดที่ยังคงทำให้การเปลี่ยนแปลงสามารถตรวจสอบได้

**ข้อกำหนดแบบ Lite (ค่าเริ่มต้น):**
- ข้อกำหนดที่เน้นพฤติกรรมสั้นๆ
- ขอบเขตและเป้าหมายที่ไม่ชัดเจน
- การตรวจสอบการยอมรับที่เป็นรูปธรรมไม่กี่ข้อ

**ข้อกำหนดแบบเต็ม (สำหรับความเสี่ยงที่สูงกว่า):**
- การเปลี่ยนแปลงข้ามทีมหรือข้ามที่เก็บ
- การเปลี่ยนแปลงสัญญา API การโยกย้าย ข้อกังวลด้านความปลอดภัย/ความเป็นส่วนตัว
- การเปลี่ยนแปลงที่ความคลุมเครืออาจทำให้ต้องทำงานซ้ำที่มีค่าใช้จ่ายสูง

การเปลี่ยนแปลงส่วนใหญ่ควรอยู่ในโหมด Lite

### ความร่วมมือระหว่างมนุษย์และเอเจนต์

ในหลายทีม มนุษย์สำรวจและเอเจนต์ร่างเอกสาร ลูปที่ตั้งใจไว้คือ:

1. มนุษย์ให้เจตนา บริบท และข้อจำกัด
2. เอเจนต์แปลงสิ่งนี้เป็นข้อกำหนดและสถานการณ์ที่เน้นพฤติกรรม
3. เอเจนต์เก็บรายละเอียดการนำไปใช้ไว้ใน `design.md` และ `tasks.md` ไม่ใช่ `spec.md`
4. การตรวจสอบยืนยันโครงสร้างและความชัดเจนก่อนการนำไปใช้

สิ่งนี้ทำให้ข้อกำหนดอ่านง่ายสำหรับมนุษย์และสอดคล้องสำหรับเอเจนต์

## การเปลี่ยนแปลง

การเปลี่ยนแปลงคือข้อเสนอการแก้ไขระบบของคุณ ซึ่งถูกจัดรูปแบบเป็นโฟลเดอร์ที่มีทุกสิ่งที่จำเป็นเพื่อความเข้าใจและการนำไปใช้งาน

### โครงสร้างการเปลี่ยนแปลง

openspec/changes/add-dark-mode/ ├── proposal.md # เหตุผลและเนื้อหา ├── design.md # วิธีการ (แนวทางทางเทคนิค) ├── tasks.md # รายการตรวจสอบการนำไปใช้ ├── .openspec.yaml # เมตาดาต้าการเปลี่ยนแปลง (ไม่บังคับ) └── specs/ # ข้อกำหนดเดลต้า └── ui/ └── spec.md # สิ่งที่เปลี่ยนแปลงใน ui/spec.md


การเปลี่ยนแปลงแต่ละรายการมีความสมบูรณ์ในตัวเอง ประกอบด้วย:
- **เอกสารประกอบ** — เอกสารที่บันทึกเจตนา การออกแบบ และงาน
- **ข้อกำหนดเดลต้า** — ข้อกำหนดสำหรับสิ่งที่ถูกเพิ่ม แก้ไข หรือลบ
- **เมตาดาต้า** — การกำหนดค่าเพิ่มเติมสำหรับการเปลี่ยนแปลงเฉพาะนี้

### เหตุใดการเปลี่ยนแปลงจึงเป็นโฟลเดอร์

การจัดรูปแบบการเปลี่ยนแปลงเป็นโฟลเดอร์มีข้อดีหลายประการ:

1. **รวมทุกอย่างไว้ด้วยกัน** ข้อเสนอ การออกแบบ งาน และข้อกำหนดอยู่ในที่เดียว ไม่ต้องค้นหาจากหลายที่

2. **ทำงานแบบขนาน** การเปลี่ยนแปลงหลายรายการสามารถมีอยู่พร้อมกันได้โดยไม่ขัดแย้ง ทำงานกับ `add-dark-mode` ในขณะที่ `fix-auth-bug` ก็อยู่ในระหว่างดำเนินการ

3. **ประวัติที่ชัดเจน** เมื่อเก็บถาวร การเปลี่ยนแปลงจะย้ายไปที่ `changes/archive/` พร้อมบริบทที่สมบูรณ์ คุณสามารถย้อนดูและเข้าใจไม่เพียงแค่ว่ามีการเปลี่ยนแปลงอะไร แต่ยังรวมถึงเหตุผลด้วย

4. **สะดวกต่อการตรวจสอบ** โฟลเดอร์การเปลี่ยนแปลงง่ายต่อการตรวจสอบ — เปิดมัน อ่านข้อเสนอ ตรวจสอบการออกแบบ ดูข้อกำหนดเดลต้า

## เอกสารประกอบ

เอกสารประกอบคือเอกสารภายในโฟลเดอร์การเปลี่ยนแปลงที่ช่วยนำทางการทำงาน

### กระแสเอกสารประกอบ

proposal ──────► specs ──────► design ──────► tasks ──────► implement │ │ │ │ why what how steps

  • scope changes approach to take

เอกสารประกอบสร้างขึ้นจากกันและกัน เอกสารประกอบแต่ละชิ้นให้บริบทสำหรับชิ้นถัดไป

### ประเภทเอกสารประกอบ

#### ข้อเสนอ (`proposal.md`)

ข้อเสนอจะบันทึก **เจตนา** **ขอบเขต** และ **แนวทาง** ในระดับสูง

```markdown
# ข้อเสนอ: เพิ่มโหมดมืด

## เจตนา
ผู้ใช้ร้องขอตัวเลือกโหมดมืดเพื่อลดความเมื่อยล้าของดวงตา
ระหว่างการใช้งานในเวลากลางคืนและตรงกับความต้องการของระบบ

## ขอบเขต
อยู่ในขอบเขต:
- ตัวสลับธีมในการตั้งค่า
- การตรวจจับความต้องการของระบบ
- บันทึกความต้องการใน localStorage

อยู่นอกขอบเขต:
- ธีมสีที่กำหนดเอง (งานในอนาคต)
- การแทนที่ธีมต่อหน้า

## แนวทาง
ใช้คุณสมบัติ CSS ที่กำหนดเองสำหรับธีมด้วย React context
สำหรับการจัดการสถานะ ตรวจจับความต้องการของระบบเมื่อโหลดครั้งแรก
อนุญาตให้แทนที่ด้วยตนเอง

เมื่อใดควรอัปเดตข้อเสนอ:

  • ขอบเขตเปลี่ยนแปลง (แคบลงหรือกว้างขึ้น)
  • เจตนาชัดเจนขึ้น (เข้าใจปัญหาดีขึ้น)
  • แนวทางเปลี่ยนแปลงอย่างมีนัยสำคัญ

ข้อกำหนด (ข้อกำหนดเดลต้าใน specs/)

ข้อกำหนดเดลต้าอธิบาย สิ่งที่เปลี่ยนแปลง เมื่อเทียบกับข้อกำหนดปัจจุบัน ดู ข้อกำหนดเดลต้า ด้านล่าง

การออกแบบ (design.md)

การออกแบบจะบันทึก แนวทางทางเทคนิค และ การตัดสินใจทางสถาปัตยกรรม

markdown
# การออกแบบ: เพิ่มโหมดมืด

## แนวทางทางเทคนิค
สถานะธีมจัดการผ่าน React Context เพื่อหลีกเลี่ยง prop drilling
คุณสมบัติ CSS ที่กำหนดเองช่วยให้สลับได้ในเวลาทำงานโดยไม่ต้องสลับคลาส

## การตัดสินใจทางสถาปัตยกรรม

### การตัดสินใจ: Context แทน Redux
ใช้ React Context สำหรับสถานะธีมเพราะ:
- สถานะไบนารีง่าย (สว่าง/มืด)
- ไม่มีการเปลี่ยนสถานะที่ซับซ้อน
- หลีกเลี่ยงการเพิ่มการพึ่งพา Redux

### การตัดสินใจ: คุณสมบัติ CSS ที่กำหนดเอง
ใช้ตัวแปร CSS แทน CSS-in-JS เพราะ:
- ทำงานกับ stylesheet ที่มีอยู่
- ไม่มีค่าใช้จ่ายเพิ่มเติมในเวลาทำงาน
- โซลูชันที่เบราว์เซอร์รองรับโดยธรรมชาติ

## การไหลของข้อมูล
```
ThemeProvider (context)


ThemeToggle ◄──► localStorage


CSS Variables (applied to :root)
```

## การเปลี่ยนแปลงไฟล์
- `src/contexts/ThemeContext.tsx` (ใหม่)
- `src/components/ThemeToggle.tsx` (ใหม่)
- `src/styles/globals.css` (แก้ไข)

เมื่อใดควรอัปเดตการออกแบบ:

  • การนำไปใช้พบว่าแนวทางใช้ไม่ได้
  • ค้นพบโซลูชันที่ดีกว่า
  • การพึ่งพาหรือข้อจำกัดเปลี่ยนแปลง

งาน (tasks.md)

งานคือ รายการตรวจสอบการนำไปใช้ — ขั้นตอนที่เป็นรูปธรรมพร้อมช่องทำเครื่องหมาย

markdown
# งาน

## 1. โครงสร้างพื้นฐานธีม
- [ ] 1.1 สร้าง ThemeContext พร้อมสถานะสว่าง/มืด
- [ ] 1.2 เพิ่มคุณสมบัติ CSS ที่กำหนดเองสำหรับสี
- [ ] 1.3 ดำเนินการบันทึกใน localStorage
- [ ] 1.4 เพิ่มการตรวจจับความต้องการของระบบ

## 2. คอมโพเนนต์ UI
- [ ] 2.1 สร้างคอมโพเนนต์ ThemeToggle
- [ ] 2.2 เพิ่มตัวสลับไปยังหน้าการตั้งค่า
- [ ] 2.3 อัปเดต Header เพื่อรวมตัวสลับด่วน

## 3. การจัดรูปแบบ
- [ ] 3.1 กำหนดจานสีธีมมืด
- [ ] 3.2 อัปเดตคอมโพเนนต์เพื่อใช้ตัวแปร CSS
- [ ] 3.3 ทดสอบอัตราส่วนคอนทราสต์เพื่อการเข้าถึง

แนวปฏิบัติที่ดีที่สุดสำหรับงาน:

  • จัดกลุ่มงานที่เกี่ยวข้องภายใต้หัวข้อ
  • ใช้ลำดับเลขชั้น (1.1, 1.2 เป็นต้น)
  • รักษางานให้เล็กพอที่จะทำให้เสร็จในหนึ่งเซสชัน
  • ทำเครื่องหมายงานเมื่อทำเสร็จ

ข้อกำหนดเดลต้า

ข้อกำหนดเดลต้าเป็นแนวคิดหลักที่ทำให้ OpenSpec ใช้งานได้สำหรับการพัฒนาแบบบราวน์ฟิลด์ พวกเขาอธิบาย สิ่งที่เปลี่ยนแปลง แทนที่จะระบุข้อกำหนดทั้งหมดซ้ำ

รูปแบบ

markdown
# เดลต้าสำหรับ Auth

## ข้อกำหนดที่เพิ่ม

### ข้อกำหนด: การยืนยันตัวตนสองปัจจัย
ระบบต้องรองรับการยืนยันตัวตนสองปัจจัยแบบ TOTP

#### สถานการณ์: การลงทะเบียน 2FA
- กำหนดให้ผู้ใช้ที่ยังไม่ได้เปิดใช้งาน 2FA
- เมื่อผู้ใช้เปิดใช้งาน 2FA ในการตั้งค่า
- จากนั้นจะแสดงรหัส QR สำหรับตั้งค่าแอปยืนยันตัวตน
- และผู้ใช้ต้องยืนยันด้วยรหัสก่อนเปิดใช้งาน

#### สถานการณ์: การเข้าสู่ระบบด้วย 2FA
- กำหนดให้ผู้ใช้ที่เปิดใช้งาน 2FA แล้ว
- เมื่อผู้ใช้ส่งข้อมูลรับรองที่ถูกต้อง
- จากนั้นจะแสดงคำท้า OTP
- และการเข้าสู่ระบบจะเสร็จสมบูรณ์หลังจาก OTP ที่ถูกต้องเท่านั้น

## ข้อกำหนดที่แก้ไข

### ข้อกำหนด: การหมดอายุเซสชัน
ระบบต้องทำให้เซสชันหมดอายุหลังจากไม่มีกิจกรรม 15 นาที
(ก่อนหน้า: 30 นาที)

#### สถานการณ์: หมดเวลาเนื่องจากไม่มีกิจกรรม
- กำหนดให้เซสชันที่ผ่านการยืนยันตัวตนแล้ว
- เมื่อเวลาผ่านไป 15 นาทีโดยไม่มีกิจกรรม
- จากนั้นเซสชันจะถูกยกเลิก

## ข้อกำหนดที่ลบ

### ข้อกำหนด: จดจำฉัน
(เลิกใช้เพื่อสนับสนุน 2FA ผู้ใช้ควรยืนยันตัวตนใหม่ทุกเซสชัน)

ส่วนเดลต้า

ส่วนความหมายสิ่งที่เกิดขึ้นเมื่อเก็บถาวร
## ข้อกำหนดที่เพิ่มพฤติกรรมใหม่เพิ่มต่อท้ายข้อกำหนดหลัก
## ข้อกำหนดที่แก้ไขพฤติกรรมที่เปลี่ยนแปลงแทนที่ข้อกำหนดที่มีอยู่
## ข้อกำหนดที่ลบพฤติกรรมที่เลิกใช้ลบออกจากข้อกำหนดหลัก

เหตุใดจึงใช้เดลต้าแทนข้อกำหนดเต็ม

ความชัดเจน เดลต้าแสดงให้เห็นอย่างชัดเจนว่ามีการเปลี่ยนแปลงอะไร การอ่านข้อกำหนดเต็ม คุณจะต้องเปรียบเทียบทางจิตใจกับเวอร์ชันปัจจุบัน

หลีกเลี่ยงความขัดแย้ง การเปลี่ยนแปลงสองรายการสามารถแตะต้องไฟล์ข้อกำหนดเดียวกันได้โดยไม่ขัดแย้ง ตราบใดที่พวกเขาแก้ไขข้อกำหนดที่ต่างกัน

ประสิทธิภาพในการตรวจสอบ ผู้ตรวจสอบเห็นการเปลี่ยนแปลง ไม่ใช่บริบทที่ไม่เปลี่ยนแปลง มุ่งเน้นไปที่สิ่งที่สำคัญ

เหมาะกับบราวน์ฟิลด์ งานส่วนใหญ่แก้ไขพฤติกรรมที่มีอยู่ เดลต้าทำให้การดัดแปลงเป็นสิ่งสำคัญ ไม่ใช่สิ่งที่คิดทีหลัง

สคีมา

สคีมาจะกำหนดประเภทของสิ่งประดิษฐ์ (artifacts) และการพึ่งพาอาศัยกันสำหรับเวิร์กโฟลว์

วิธีการทำงานของสคีมา

yaml
# openspec/schemas/spec-driven/schema.yaml
name: spec-driven
artifacts:
  - id: proposal
    generates: proposal.md
    requires: []              # ไม่มีการพึ่งพา สามารถสร้างได้ก่อน

  - id: specs
    generates: specs/**/*.md
    requires: [proposal]      # ต้องการ proposal ก่อนจึงจะสร้างได้

  - id: design
    generates: design.md
    requires: [proposal]      # สามารถสร้างพร้อมกับ specs ได้

  - id: tasks
    generates: tasks.md
    requires: [specs, design] # ต้องการทั้ง specs และ design ก่อน

สิ่งประดิษฐ์จะสร้างกราฟการพึ่งพาอาศัยกัน:

                    proposal
                   (โหนดหลัก)

         ┌─────────────┴─────────────┐
         │                           │
         ▼                           ▼
      specs                       design
   (ต้องการ:                  (ต้องการ:
    proposal)                   proposal)
         │                           │
         └─────────────┬─────────────┘


                    tasks
                (ต้องการ:
                specs, design)

การพึ่งพาเป็นตัวเปิดใช้งาน ไม่ใช่ตัวปิดกั้น มันแสดงให้เห็นว่าสิ่งใดที่สามารถสร้างได้ ไม่ใช่สิ่งที่คุณต้องสร้างต่อไป คุณสามารถข้าม design ได้หากไม่ต้องการ คุณสามารถสร้าง specs ก่อนหรือหลัง design ก็ได้ — ทั้งสองขึ้นอยู่กับ proposal เท่านั้น

สคีมาที่มีมาในตัว

spec-driven (ค่าเริ่มต้น)

เวิร์กโฟลว์มาตรฐานสำหรับการพัฒนาแบบขับเคลื่อนด้วยสเปก:

proposal → specs → design → tasks → implement

เหมาะสำหรับ: งานฟีเจอร์ส่วนใหญ่ที่คุณต้องการตกลงในสเปกก่อนการนำไปใช้งาน

สคีมาที่กำหนดเอง

สร้างสคีมาที่กำหนดเองสำหรับเวิร์กโฟลว์ของทีมคุณ:

bash
# สร้างจากศูนย์
openspec schema init research-first

# หรือแยกมาจากที่มีอยู่แล้ว
openspec schema fork spec-driven research-first

ตัวอย่างสคีมาที่กำหนดเอง:

yaml
# openspec/schemas/research-first/schema.yaml
name: research-first
artifacts:
  - id: research
    generates: research.md
    requires: []           # ทำวิจัยก่อน

  - id: proposal
    generates: proposal.md
    requires: [research]   # ข้อเสนออิงจากผลวิจัย

  - id: tasks
    generates: tasks.md
    requires: [proposal]   # ข้าม specs/design ไปที่ tasks โดยตรง

ดูรายละเอียดเพิ่มเติมเกี่ยวกับการสร้างและใช้งานสคีมาที่กำหนดเองได้ที่ การปรับแต่ง

การจัดเก็บ

การจัดเก็บจะทำการเปลี่ยนแปลงให้สมบูรณ์โดยการรวมสเปกเดลต้าเข้ากับสเปกหลัก และเก็บรักษาการเปลี่ยนแปลงไว้เพื่อเป็นประวัติศาสตร์

เกิดอะไรขึ้นเมื่อคุณจัดเก็บ

ก่อนจัดเก็บ:

openspec/
├── specs/
│   └── auth/
│       └── spec.md ◄────────────────┐
└── changes/                         │
    └── add-2fa/                     │
        ├── proposal.md              │
        ├── design.md                │ รวม
        ├── tasks.md                 │
        └── specs/                   │
            └── auth/                │
                └── spec.md ─────────┘


หลังจัดเก็บ:

openspec/
├── specs/
│   └── auth/
│       └── spec.md        # ตอนนี้รวมข้อกำหนด 2FA แล้ว
└── changes/
    └── archive/
        └── 2025-01-24-add-2fa/    # เก็บรักษาไว้เพื่อประวัติศาสตร์
            ├── proposal.md
            ├── design.md
            ├── tasks.md
            └── specs/
                └── auth/
                    └── spec.md

กระบวนการจัดเก็บ

  1. รวมเดลต้า ส่วนของสเปกเดลต้าแต่ละส่วน (ADDED/MODIFIED/REMOVED) จะถูกนำไปใช้กับสเปกหลักที่สอดคล้องกัน

  2. ย้ายไปยังที่จัดเก็บ โฟลเดอร์การเปลี่ยนแปลงจะถูกย้ายไปที่ changes/archive/ โดยมีคำนำหน้าเป็นวันที่เพื่อเรียงลำดับตามเวลา

  3. รักษาบริบท สิ่งประดิษฐ์ทั้งหมดยังคงอยู่ครบถ้วนในที่จัดเก็บ คุณสามารถย้อนกลับไปดูเพื่อทำความเข้าใจว่าเหตุใดจึงมีการเปลี่ยนแปลงนั้น

ทำไมการจัดเก็บจึงสำคัญ

สถานะที่สะอาด การเปลี่ยนแปลงที่ทำงานอยู่ (changes/) จะแสดงเฉพาะงานที่กำลังดำเนินการ งานที่เสร็จสมบูรณ์จะถูกย้ายออกไป

เส้นทางตรวจสอบ ที่จัดเก็บจะรักษาบริบททั้งหมดของการเปลี่ยนแปลงทุกครั้ง — ไม่ใช่แค่ว่ามีอะไรเปลี่ยนแปลง แต่รวมถึงข้อเสนอที่อธิบายเหตุผล การออกแบบที่อธิบายวิธีการ และงานที่แสดงให้เห็นถึงสิ่งที่ทำสำเร็จ

วิวัฒนาการของสเปก สเปกจะเติบโตอย่างเป็นธรรมชาติเมื่อมีการจัดเก็บการเปลี่ยนแปลง ที่จัดเก็บแต่ละแห่งจะรวมเดลต้าของมัน สร้างข้อกำหนดที่ครอบคลุมเมื่อเวลาผ่านไป

ทุกสิ่งทำงานร่วมกันอย่างไร

┌──────────────────────────────────────────────────────────────────────────────┐
│                              โฟลว์ OPENSPEC                                   │
│                                                                              │
│   ┌────────────────┐                                                         │
│   │  1. เริ่มต้น   │  /opsx:propose (หลัก) หรือ /opsx:new (ขยาย)            │
│   │     การเปลี่ยนแปลง│                                                         │
│   └───────┬────────┘                                                         │
│           │                                                                  │
│           ▼                                                                  │
│   ┌────────────────┐                                                         │
│   │  2. สร้าง      │  /opsx:ff หรือ /opsx:continue (เวิร์กโฟลว์ขยาย)        │
│   │     สิ่งประดิษฐ์│  สร้าง proposal → specs → design → tasks               │
│   │                │  (อิงตามการพึ่งพาของสคีมา)                              │
│   └───────┬────────┘                                                         │
│           │                                                                  │
│           ▼                                                                  │
│   ┌────────────────┐                                                         │
│   │  3. นำไปใช้    │  /opsx:apply                                            │
│   │     งาน        │  ทำงานตามรายการงาน ทำเครื่องหมายว่าเสร็จ                  │
│   │                │◄──── อัปเดตสิ่งประดิษฐ์เมื่อคุณเรียนรู้                   │
│   └───────┬────────┘                                                         │
│           │                                                                  │
│           ▼                                                                  │
│   ┌────────────────┐                                                         │
│   │  4. ตรวจสอบ    │  /opsx:verify (ไม่บังคับ)                               │
│   │     งาน        │  ตรวจสอบว่าการนำไปใช้ตรงกับสเปก                          │
│   └───────┬────────┘                                                         │
│           │                                                                  │
│           ▼                                                                  │
│   ┌────────────────┐     ┌──────────────────────────────────────────────┐    │
│   │  5. จัดเก็บ    │────►│  สเปกเดลต้ารวมเข้ากับสเปกหลัก               │    │
│   │     การเปลี่ยนแปลง│     │  โฟลเดอร์การเปลี่ยนแปลงย้ายไปที่ archive/     │    │
│   └────────────────┘     │  สเปกเป็นแหล่งข้อมูลจริงที่อัปเดตแล้ว        │    │
│                          └──────────────────────────────────────────────┘    │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

วงจรแห่งคุณธรรม:

  1. สเปกอธิบายพฤติกรรมปัจจุบัน
  2. การเปลี่ยนแปลงเสนอการแก้ไข (ในรูปแบบเดลต้า)
  3. การนำไปใช้ทำให้การเปลี่ยนแปลงเป็นจริง
  4. การจัดเก็บรวมเดลต้าเข้ากับสเปก
  5. สเปกอธิบายพฤติกรรมใหม่แล้ว
  6. การเปลี่ยนแปลงครั้งถัดไปต่อยอดจากสเปกที่อัปเดต

อภิธานศัพท์

คำศัพท์คำจำกัดความ
สิ่งประดิษฐ์ (Artifact)เอกสารภายในหนึ่งการเปลี่ยนแปลง (proposal, design, tasks หรือสเปกเดลต้า)
การจัดเก็บ (Archive)กระบวนการที่ทำให้การเปลี่ยนแปลงสมบูรณ์และรวมเดลต้าของมันเข้ากับสเปกหลัก
การเปลี่ยนแปลง (Change)การแก้ไขที่เสนอต่อระบบ จัดเป็นแพ็กเกจในรูปแบบโฟลเดอร์ที่มีสิ่งประดิษฐ์
สเปกเดลต้า (Delta spec)สเปกที่อธิบายการเปลี่ยนแปลง (ADDED/MODIFIED/REMOVED) เมื่อเทียบกับสเปกปัจจุบัน
โดเมน (Domain)การจัดกลุ่มเชิงตรรกะสำหรับสเปก (เช่น auth/, payments/)
ข้อกำหนด (Requirement)พฤติกรรมเฉพาะที่ระบบต้องมี
สถานการณ์ (Scenario)ตัวอย่างที่เป็นรูปธรรมของข้อกำหนด โดยทั่วไปอยู่ในรูปแบบ Given/When/Then
สคีมา (Schema)คำจำกัดความของประเภทสิ่งประดิษฐ์และการพึ่งพาอาศัยกัน
สเปก (Spec)ข้อกำหนดที่อธิบายพฤติกรรมของระบบ ประกอบด้วยข้อกำหนดและสถานการณ์
แหล่งข้อมูลจริง (Source of truth)ไดเรกทอรี openspec/specs/ ที่มีพฤติกรรมที่ตกลงกันไว้ในปัจจุบัน

ขั้นตอนถัดไป