/business-logic-spec — ระบุตรรกะและกฎทางธุรกิจ (Business Logic & Rules)
แปลง "กฎทางธุรกิจที่อยู่ในหัวคน" ให้เป็น spec ที่ชัด ทดสอบได้ และไม่กำกวม — ผ่าน business rules catalog, decision table, state machine และกฎคำนวณ/ตรวจสอบ — เพื่อให้ dev เขียนตรรกะถูกต้องตั้งแต่รอบแรก และ tester เขียน test case ได้ตรงกฎ
ใช้ตอนไหน
- หลังจากมี FR/NFR แล้ว (
/fr-nfr-spec) แต่ FR บอกแค่ "ระบบต้องคิดส่วนลด" โดยไม่บอก "คิดยังไง กี่ขั้น เงื่อนไขไหนชนะ"
- เมื่อตรรกะมีหลายเงื่อนไขซ้อนกัน (if-else ลึกหลายชั้น) จนอธิบายเป็นร้อยแก้วแล้วเริ่มขัดแย้งกันเอง → ใช้ decision table
- เมื่อ entity มี "สถานะ" และเปลี่ยนสถานะตาม event (เช่น คำสั่งซื้อ, คำขอลา, ใบกำกับภาษี) → ใช้ state machine
- เมื่อมีกฎคำนวณเงิน/ภาษี/ดอกเบี้ย/ส่วนลด ที่การปัดเศษหรือลำดับการคำนวณมีผลต่อผลลัพธ์
- ใช้ก่อนเข้า
/solution-design เพื่อให้สถาปนิกออกแบบโครงสร้างจากตรรกะที่นิ่งแล้ว ไม่ใช่เดาเอง
ขอบเขตเฉพาะเฟสนี้ = "ตรรกะและกฎ" เท่านั้น
- สถาปัตยกรรม / data model / API design →
/solution-design
- สิทธิ์ตามบทบาท / การแยกหน้าที่ (maker-checker เชิงสิทธิ์) →
/sod-matrix
- การยืนยันตัวตน / authorization เชิงเทคนิค →
/authn-authz-design
เฟสนี้พูดถึง maker-checker ได้แค่ "ระดับ logic ของ flow" (ใครทำสเต็ปไหน สถานะเปลี่ยนยังไง) ไม่ลงลึกว่า role ไหนมีสิทธิ์อะไร
Input ที่ต้องถามก่อนเริ่ม
- FR อ้างอิง — เฟสนี้ขยายความ FR ตัวไหน (ขอ FR-ID จาก
/fr-nfr-spec)
- โดเมน/กฎดิบ — กฎทางธุรกิจในรูปแบบที่ลูกค้าพูด (นโยบายส่วนลด, เกณฑ์อนุมัติ, เงื่อนไขคิดเงิน) พร้อม "ใครเป็นเจ้าของกฎ" (rule owner)
- entity ที่มีวงจรชีวิต — มี object ไหนที่มีสถานะและเปลี่ยนได้บ้าง (order, ticket, loan, invoice)
- หน่วย/ความแม่นยำ — สกุลเงิน, จำนวนทศนิยม, วิธีปัดเศษ (ปัดขึ้น/ลง/banker's), เขตเวลาอ้างอิง, ปฏิทิน (วันทำการ?)
- ลำดับความสำคัญของกฎ — ถ้ากฎหลายตัวชนกัน อันไหนชนะ (precedence / specificity)
- แหล่งความจริง — ค่าคงที่/เกณฑ์ (threshold) มาจาก config, ตารางในระบบ หรือ hardcode
ขั้นตอน (Playbook)
- รวบรวมกฎดิบ → จัดหมวด — ดึงทุกกฎจากเอกสาร/สัมภาษณ์ แล้วระบุประเภทแต่ละกฎ:
constraint — ข้อจำกัดที่ต้องเป็นจริงเสมอ (เช่น ยอดสั่งซื้อ > 0)
validation — กฎตรวจความถูกต้องของ input (รูปแบบ, ช่วงค่า)
computation — สูตรคำนวณ (ส่วนลด, ภาษี, ค่าธรรมเนียม)
derivation — ค่าที่อนุมานจากค่าอื่น (เกรดลูกค้าจากยอดสะสม)
process — กฎควบคุม flow/ลำดับขั้น (ต้องอนุมัติก่อนจ่าย)
- ให้ ID และเขียนลง catalog — ทุกกฎได้
BR-xxx พร้อมผูกกลับ FR-ID (traceability)
- ตรรกะหลายเงื่อนไข → decision table — แตกเป็น condition × action, ใส่ทุก combination แล้วตรวจ completeness (ครบทุกกรณี) และ consistency (ไม่มี 2 แถวขัดกัน)
- entity มีสถานะ → state machine — วาดตาราง transition (state/event/next/guard/action) และระบุ state เริ่มต้น/สิ้นสุด + transition ที่ "ห้ามเกิด"
- กฎคำนวณ → ระบุสูตร + ลำดับ + การปัดเศษ ให้ครบจน reproduce ได้ พร้อมตัวอย่างตัวเลขจริง (worked example)
- ล่า edge case — ค่า null/ว่าง, ขอบเขต (0, ค่าติดลบ, ค่าสูงสุด), การหารด้วยศูนย์, วันคาบเกี่ยว, สกุลเงินหลายตัว, การทำซ้ำ (idempotency), การยกเลิก/ย้อนกลับ
- ตรวจ traceability ย้อนกลับ — ทุก BR ต้องโยงไป FR; ทุก FR ที่มีตรรกะต้องมี BR รองรับ
- ส่งต่อ — สรุป assumption ที่ตั้งไว้ + คำถามค้างให้ rule owner ยืนยัน ก่อนส่งเข้า
/solution-design
Output / Artifact (เทมเพลตพร้อมใช้)
1) Business Rule Catalog (รูปแบบ entry แต่ละกฎ)
BR-012 ส่วนลดตามยอดสั่งซื้อ (Volume discount)
ประเภท (type) : computation
เจ้าของกฎ : ฝ่ายขาย (Sales policy 2026)
อ้างอิง FR : FR-031 (คำนวณราคาสุทธิตะกร้าสินค้า)
เงื่อนไข (when) : ลูกค้ายืนยันตะกร้า และ subtotal ≥ 1,000 THB
ผลลัพธ์ (then) : ใช้ส่วนลดตาม decision table DT-01 (ดูด้านล่าง)
ส่วนลดสูงสุดไม่เกิน 20% ของ subtotal
หน่วย/ปัดเศษ : THB, ปัดเศษทศนิยม 2 ตำแหน่งแบบ half-up หลังคำนวณส่วนลด
ความสำคัญ (prec.) : ใช้คู่กับ BR-013 (คูปอง) — ส่วนลดยอดคิดก่อน แล้วจึงหักคูปอง
ตัวอย่าง : subtotal 1,500 → tier 5% → ส่วนลด 75.00 → net 1,425.00
2) Decision Table — DT-01: ส่วนลดตามยอดสั่งซื้อ + ประเภทสมาชิก
อ่านแบบ "เงื่อนไขด้านบน, การกระทำด้านล่าง"; แต่ละคอลัมน์ R1..R5 คือ 1 กฎ (rule). - = ไม่สนใจ (don't care)
| เงื่อนไข (Condition) |
R1 |
R2 |
R3 |
R4 |
R5 |
| subtotal (THB) |
< 1000 |
1000–4999 |
1000–4999 |
≥ 5000 |
≥ 5000 |
| ระดับสมาชิก (tier) |
- |
ทั่วไป |
VIP |
ทั่วไป |
VIP |
| การกระทำ (Action) |
|
|
|
|
|
| % ส่วนลด |
0% |
5% |
8% |
10% |
15% |
| ส่งฟรี (free shipping) |
ไม่ |
ไม่ |
ใช่ |
ใช่ |
ใช่ |
| ต้องอนุมัติเพิ่ม |
ไม่ |
ไม่ |
ไม่ |
ไม่ |
ใช่* |
* R5: ถ้า %ส่วนลดรวมทั้งบิล > 20% หลังรวมคูปอง ต้องให้หัวหน้าฝ่ายขายอนุมัติ (ดู state machine ด้านล่าง)
ตรวจคุณภาพตาราง: completeness = ทุกช่วง subtotin × tier มีกฎรองรับ (รวม < 1000); consistency = ไม่มีแถวซ้อนทับให้ผลต่างกัน; edge = subtotal = 1000 และ = 5000 ตกอยู่กฎใด (ระบุชัดว่าใช้ ≥)
3) State Machine / Lifecycle — ตัวอย่าง: คำขออนุมัติเครดิตลูกค้า (Credit approval)
สถานะเริ่มต้น: DRAFT · สถานะสิ้นสุด: ACTIVE, REJECTED, CANCELLED
| State (สถานะ) |
Event (เหตุการณ์) |
Next state (ถัดไป) |
Guard (เงื่อนไขผ่าน) |
Action (การกระทำ) |
| DRAFT |
submit |
UNDER_REVIEW |
ข้อมูลครบตาม BR-020..023 |
สร้างเลขคำขอ, แจ้งผู้ตรวจ |
| DRAFT |
cancel |
CANCELLED |
— |
บันทึกเหตุผลยกเลิก |
| UNDER_REVIEW |
approve |
ACTIVE |
วงเงิน ≤ อำนาจอนุมัติผู้ตรวจ (BR-030) |
เปิดวงเงิน, แจ้งลูกค้า |
| UNDER_REVIEW |
escalate |
PENDING_MANAGER |
วงเงิน > อำนาจผู้ตรวจ |
ส่งต่อผู้จัดการ |
| UNDER_REVIEW |
reject |
REJECTED |
— |
บันทึกเหตุผล, แจ้งลูกค้า |
| PENDING_MANAGER |
approve |
ACTIVE |
ผู้จัดการอนุมัติ และวงเงิน ≤ เพดานบริษัท |
เปิดวงเงิน |
| PENDING_MANAGER |
reject |
REJECTED |
— |
บันทึกเหตุผล |
Transition ที่ห้ามเกิด (ระบุชัดเพื่อกัน bug): REJECTED → ACTIVE, ACTIVE → DRAFT, CANCELLED → * (terminal). การ approve ตัวเอง (maker = checker) ห้าม — กฎสิทธิ์เชิงบทบาทอยู่ที่ /sod-matrix
4) กฎคำนวณ/ตรวจสอบ (Computation & Validation rules)
BR-021 validation : tax_id ต้องเป็นตัวเลข 13 หลัก และผ่าน checksum; ว่าง = reject
BR-030 computation: ลำดับคำนวณราคาสุทธิ
1. subtotal = Σ(qty × unit_price) // ก่อนส่วนลด
2. volume_discount = subtotal × tier% (DT-01) // ปัด half-up 2 ตำแหน่ง
3. after_discount = subtotal − volume_discount
4. coupon = min(coupon_value, after_discount) // คูปองไม่ทำให้ติดลบ
5. vat = (after_discount − coupon) × 7% // VAT คิดหลังหักทุกส่วนลด
6. grand_total = after_discount − coupon + vat // ปัด half-up 2 ตำแหน่ง
เขตเวลา: ใช้ Asia/Bangkok สำหรับวันมีผลของโปรโมชัน
5) Edge cases & exception handling (ตาราง)
| กรณีขอบ (Edge case) |
กฎที่ใช้จัดการ |
ผลลัพธ์ที่คาด |
| subtotal = 0 / ตะกร้าว่าง |
BR-012 guard |
ไม่คิดส่วนลด, บล็อกการชำระเงิน |
| คูปอง > ยอดหลังส่วนลด |
BR-030 ขั้น 4 |
หักได้ไม่เกินยอด, ไม่ติดลบ |
| วงเงินเกินเพดานบริษัท |
state guard |
คงสถานะ PENDING_MANAGER, ไม่อนุมัติเอง |
| ส่งคำขอซ้ำ (double submit) |
idempotency key |
คืนผลเดิม ไม่สร้างคำขอใหม่ |
Checklist / Definition of Done
เคล็ดลับ & ข้อควรระวัง
- อย่าฝังกฎเป็นร้อยแก้ว — ถ้าเขียนเกิน 2-3 if ในประโยคเดียว ให้ย้ายเป็น decision table ทันที จะเห็นช่องโหว่เอง
- completeness > ความสวย — เติมทุก combination แม้กรณี "เป็นไปไม่ได้" แล้ว mark ว่า impossible/error ดีกว่าปล่อยช่องว่างให้ dev เดา
- แยก "ค่าคงที่" ออกจากตรรกะ — threshold/เปอร์เซ็นต์ควรชี้ไป config/ตาราง ไม่ hardcode ใน spec; ระบุแหล่งความจริง
- การปัดเศษคือ bug ยอดฮิต — ระบุ "ปัดเมื่อไหร่ (แต่ละขั้นหรือขั้นสุดท้าย)" และ "วิธีปัด" ให้ตรงกับฝ่ายบัญชี/กฎหมาย
- state machine ต้องมี transition ต้องห้าม — การไม่ระบุ "ห้ามจาก X ไป Y" คือต้นเหตุของ state corruption
- เขตเวลา/วันทำการ — โปรโมชัน, ดอกเบี้ย, SLA มักผิดเพราะ timezone หรือไม่นับวันหยุด ระบุปฏิทินอ้างอิงเสมอ
- อย่าปนเรื่องสิทธิ์ — "ใครได้รับอนุญาตให้อนุมัติ" ไม่ใช่ business logic เฟสนี้ ส่งไป
/sod-matrix / /authn-authz-design
เชื่อมกับเฟสอื่น
- ก่อนหน้า:
/fr-nfr-spec — FR บอก "ระบบต้องทำอะไร" เฟสนี้ลงลึก "ทำตามตรรกะ/กฎอะไรเป๊ะ ๆ"
- ถัดไป:
/solution-design — สถาปนิกรับ rule catalog + decision table + state machine ไปออกแบบโครงสร้าง/data model/API
- เกี่ยวข้อง:
/sod-matrix และ /authn-authz-design (สิทธิ์/อนุมัติเชิงบทบาท), /test-strategy (แปลง decision table/state machine เป็น test case), /threat-model (ตรวจ business-logic abuse)
- ภาพรวมทั้งวงจร:
/sdlc-agile
1---2name: business-logic-spec3description: ระบุ business logic/business rules ให้ชัดและทดสอบได้ — decision table, state machine, กฎคำนวณ/ตรวจสอบ, edge case — เพื่อให้ dev เขียนตรรกะถูกต้องและตรงเจตนาธุรกิจ (turn fuzzy domain rules into precise, testable specs). Trigger เมื่อผู้ใช้พิมพ์ /business-logic-spec หรือขอ "business logic / business rule / decision table / state machine / กฎทางธุรกิจ / ตรรกะระบบ / workflow rule".4---56# /business-logic-spec — ระบุตรรกะและกฎทางธุรกิจ (Business Logic & Rules)78แปลง "กฎทางธุรกิจที่อยู่ในหัวคน" ให้เป็น spec ที่ชัด ทดสอบได้ และไม่กำกวม — ผ่าน business rules catalog, decision table, state machine และกฎคำนวณ/ตรวจสอบ — เพื่อให้ dev เขียนตรรกะถูกต้องตั้งแต่รอบแรก และ tester เขียน test case ได้ตรงกฎ910## ใช้ตอนไหน1112- หลังจากมี FR/NFR แล้ว (`/fr-nfr-spec`) แต่ FR บอกแค่ "ระบบต้องคิดส่วนลด" โดยไม่บอก "คิดยังไง กี่ขั้น เงื่อนไขไหนชนะ"13- เมื่อตรรกะมีหลายเงื่อนไขซ้อนกัน (if-else ลึกหลายชั้น) จนอธิบายเป็นร้อยแก้วแล้วเริ่มขัดแย้งกันเอง → ใช้ **decision table**14- เมื่อ entity มี "สถานะ" และเปลี่ยนสถานะตาม event (เช่น คำสั่งซื้อ, คำขอลา, ใบกำกับภาษี) → ใช้ **state machine**15- เมื่อมีกฎคำนวณเงิน/ภาษี/ดอกเบี้ย/ส่วนลด ที่การปัดเศษหรือลำดับการคำนวณมีผลต่อผลลัพธ์16- ใช้ก่อนเข้า `/solution-design` เพื่อให้สถาปนิกออกแบบโครงสร้างจากตรรกะที่นิ่งแล้ว ไม่ใช่เดาเอง1718> ขอบเขตเฉพาะเฟสนี้ = "ตรรกะและกฎ" เท่านั้น19> - สถาปัตยกรรม / data model / API design → `/solution-design`20> - สิทธิ์ตามบทบาท / การแยกหน้าที่ (maker-checker เชิงสิทธิ์) → `/sod-matrix`21> - การยืนยันตัวตน / authorization เชิงเทคนิค → `/authn-authz-design`22> เฟสนี้พูดถึง maker-checker ได้แค่ "ระดับ logic ของ flow" (ใครทำสเต็ปไหน สถานะเปลี่ยนยังไง) ไม่ลงลึกว่า role ไหนมีสิทธิ์อะไร2324## Input ที่ต้องถามก่อนเริ่ม25261. **FR อ้างอิง** — เฟสนี้ขยายความ FR ตัวไหน (ขอ FR-ID จาก `/fr-nfr-spec`)272. **โดเมน/กฎดิบ** — กฎทางธุรกิจในรูปแบบที่ลูกค้าพูด (นโยบายส่วนลด, เกณฑ์อนุมัติ, เงื่อนไขคิดเงิน) พร้อม "ใครเป็นเจ้าของกฎ" (rule owner)283. **entity ที่มีวงจรชีวิต** — มี object ไหนที่มีสถานะและเปลี่ยนได้บ้าง (order, ticket, loan, invoice)294. **หน่วย/ความแม่นยำ** — สกุลเงิน, จำนวนทศนิยม, วิธีปัดเศษ (ปัดขึ้น/ลง/banker's), เขตเวลาอ้างอิง, ปฏิทิน (วันทำการ?)305. **ลำดับความสำคัญของกฎ** — ถ้ากฎหลายตัวชนกัน อันไหนชนะ (precedence / specificity)316. **แหล่งความจริง** — ค่าคงที่/เกณฑ์ (threshold) มาจาก config, ตารางในระบบ หรือ hardcode3233## ขั้นตอน (Playbook)34351. **รวบรวมกฎดิบ → จัดหมวด** — ดึงทุกกฎจากเอกสาร/สัมภาษณ์ แล้วระบุประเภทแต่ละกฎ:36 - `constraint` — ข้อจำกัดที่ต้องเป็นจริงเสมอ (เช่น ยอดสั่งซื้อ > 0)37 - `validation` — กฎตรวจความถูกต้องของ input (รูปแบบ, ช่วงค่า)38 - `computation` — สูตรคำนวณ (ส่วนลด, ภาษี, ค่าธรรมเนียม)39 - `derivation` — ค่าที่อนุมานจากค่าอื่น (เกรดลูกค้าจากยอดสะสม)40 - `process` — กฎควบคุม flow/ลำดับขั้น (ต้องอนุมัติก่อนจ่าย)412. **ให้ ID และเขียนลง catalog** — ทุกกฎได้ `BR-xxx` พร้อมผูกกลับ FR-ID (traceability)423. **ตรรกะหลายเงื่อนไข → decision table** — แตกเป็น condition × action, ใส่ทุก combination แล้วตรวจ completeness (ครบทุกกรณี) และ consistency (ไม่มี 2 แถวขัดกัน)434. **entity มีสถานะ → state machine** — วาดตาราง transition (state/event/next/guard/action) และระบุ state เริ่มต้น/สิ้นสุด + transition ที่ "ห้ามเกิด"445. **กฎคำนวณ → ระบุสูตร + ลำดับ + การปัดเศษ** ให้ครบจน reproduce ได้ พร้อมตัวอย่างตัวเลขจริง (worked example)456. **ล่า edge case** — ค่า null/ว่าง, ขอบเขต (0, ค่าติดลบ, ค่าสูงสุด), การหารด้วยศูนย์, วันคาบเกี่ยว, สกุลเงินหลายตัว, การทำซ้ำ (idempotency), การยกเลิก/ย้อนกลับ467. **ตรวจ traceability ย้อนกลับ** — ทุก BR ต้องโยงไป FR; ทุก FR ที่มีตรรกะต้องมี BR รองรับ478. **ส่งต่อ** — สรุป assumption ที่ตั้งไว้ + คำถามค้างให้ rule owner ยืนยัน ก่อนส่งเข้า `/solution-design`4849## Output / Artifact (เทมเพลตพร้อมใช้)5051### 1) Business Rule Catalog (รูปแบบ entry แต่ละกฎ)5253```54BR-012 ส่วนลดตามยอดสั่งซื้อ (Volume discount)55ประเภท (type) : computation56เจ้าของกฎ : ฝ่ายขาย (Sales policy 2026)57อ้างอิง FR : FR-031 (คำนวณราคาสุทธิตะกร้าสินค้า)58เงื่อนไข (when) : ลูกค้ายืนยันตะกร้า และ subtotal ≥ 1,000 THB59ผลลัพธ์ (then) : ใช้ส่วนลดตาม decision table DT-01 (ดูด้านล่าง)60 ส่วนลดสูงสุดไม่เกิน 20% ของ subtotal61หน่วย/ปัดเศษ : THB, ปัดเศษทศนิยม 2 ตำแหน่งแบบ half-up หลังคำนวณส่วนลด62ความสำคัญ (prec.) : ใช้คู่กับ BR-013 (คูปอง) — ส่วนลดยอดคิดก่อน แล้วจึงหักคูปอง63ตัวอย่าง : subtotal 1,500 → tier 5% → ส่วนลด 75.00 → net 1,425.0064```6566### 2) Decision Table — DT-01: ส่วนลดตามยอดสั่งซื้อ + ประเภทสมาชิก6768อ่านแบบ "เงื่อนไขด้านบน, การกระทำด้านล่าง"; แต่ละคอลัมน์ R1..R5 คือ 1 กฎ (rule). `-` = ไม่สนใจ (don't care)6970| เงื่อนไข (Condition) | R1 | R2 | R3 | R4 | R5 |71|----------------------------|--------|-----------|-----------|-----------|---------|72| subtotal (THB) | < 1000 | 1000–4999 | 1000–4999 | ≥ 5000 | ≥ 5000 |73| ระดับสมาชิก (tier) | - | ทั่วไป | VIP | ทั่วไป | VIP |74| **การกระทำ (Action)** | | | | | |75| % ส่วนลด | 0% | 5% | 8% | 10% | 15% |76| ส่งฟรี (free shipping) | ไม่ | ไม่ | ใช่ | ใช่ | ใช่ |77| ต้องอนุมัติเพิ่ม | ไม่ | ไม่ | ไม่ | ไม่ | ใช่* |7879\* R5: ถ้า %ส่วนลดรวมทั้งบิล > 20% หลังรวมคูปอง ต้องให้หัวหน้าฝ่ายขายอนุมัติ (ดู state machine ด้านล่าง)8081ตรวจคุณภาพตาราง: **completeness** = ทุกช่วง subtotin × tier มีกฎรองรับ (รวม < 1000); **consistency** = ไม่มีแถวซ้อนทับให้ผลต่างกัน; **edge** = subtotal = 1000 และ = 5000 ตกอยู่กฎใด (ระบุชัดว่าใช้ ≥)8283### 3) State Machine / Lifecycle — ตัวอย่าง: คำขออนุมัติเครดิตลูกค้า (Credit approval)8485สถานะเริ่มต้น: `DRAFT` · สถานะสิ้นสุด: `ACTIVE`, `REJECTED`, `CANCELLED`8687| State (สถานะ) | Event (เหตุการณ์) | Next state (ถัดไป) | Guard (เงื่อนไขผ่าน) | Action (การกระทำ) |88|-----------------|-------------------|--------------------|--------------------------------------------|------------------------------------|89| DRAFT | submit | UNDER_REVIEW | ข้อมูลครบตาม BR-020..023 | สร้างเลขคำขอ, แจ้งผู้ตรวจ |90| DRAFT | cancel | CANCELLED | — | บันทึกเหตุผลยกเลิก |91| UNDER_REVIEW | approve | ACTIVE | วงเงิน ≤ อำนาจอนุมัติผู้ตรวจ (BR-030) | เปิดวงเงิน, แจ้งลูกค้า |92| UNDER_REVIEW | escalate | PENDING_MANAGER | วงเงิน > อำนาจผู้ตรวจ | ส่งต่อผู้จัดการ |93| UNDER_REVIEW | reject | REJECTED | — | บันทึกเหตุผล, แจ้งลูกค้า |94| PENDING_MANAGER | approve | ACTIVE | ผู้จัดการอนุมัติ และวงเงิน ≤ เพดานบริษัท | เปิดวงเงิน |95| PENDING_MANAGER | reject | REJECTED | — | บันทึกเหตุผล |9697Transition ที่ห้ามเกิด (ระบุชัดเพื่อกัน bug): `REJECTED → ACTIVE`, `ACTIVE → DRAFT`, `CANCELLED → *` (terminal). การ approve ตัวเอง (maker = checker) ห้าม — *กฎสิทธิ์เชิงบทบาทอยู่ที่ `/sod-matrix`*9899### 4) กฎคำนวณ/ตรวจสอบ (Computation & Validation rules)100101```102BR-021 validation : tax_id ต้องเป็นตัวเลข 13 หลัก และผ่าน checksum; ว่าง = reject103BR-030 computation: ลำดับคำนวณราคาสุทธิ104 1. subtotal = Σ(qty × unit_price) // ก่อนส่วนลด105 2. volume_discount = subtotal × tier% (DT-01) // ปัด half-up 2 ตำแหน่ง106 3. after_discount = subtotal − volume_discount107 4. coupon = min(coupon_value, after_discount) // คูปองไม่ทำให้ติดลบ108 5. vat = (after_discount − coupon) × 7% // VAT คิดหลังหักทุกส่วนลด109 6. grand_total = after_discount − coupon + vat // ปัด half-up 2 ตำแหน่ง110 เขตเวลา: ใช้ Asia/Bangkok สำหรับวันมีผลของโปรโมชัน111```112113### 5) Edge cases & exception handling (ตาราง)114115| กรณีขอบ (Edge case) | กฎที่ใช้จัดการ | ผลลัพธ์ที่คาด |116|----------------------------------|------------------------|---------------------------------------|117| subtotal = 0 / ตะกร้าว่าง | BR-012 guard | ไม่คิดส่วนลด, บล็อกการชำระเงิน |118| คูปอง > ยอดหลังส่วนลด | BR-030 ขั้น 4 | หักได้ไม่เกินยอด, ไม่ติดลบ |119| วงเงินเกินเพดานบริษัท | state guard | คงสถานะ PENDING_MANAGER, ไม่อนุมัติเอง |120| ส่งคำขอซ้ำ (double submit) | idempotency key | คืนผลเดิม ไม่สร้างคำขอใหม่ |121122## Checklist / Definition of Done123124- [ ] ทุก business rule มี `BR-ID`, ประเภท (constraint/validation/computation/derivation/process) และเจ้าของกฎ125- [ ] ทุก BR ผูกกลับ `FR-ID` (traceability สองทาง — ไม่มี BR ลอย, ไม่มี FR ตรรกะที่ขาด BR)126- [ ] ตรรกะหลายเงื่อนไขทุกชุดมี decision table ที่ผ่าน completeness + consistency127- [ ] ทุก entity ที่มีสถานะมี state machine ครบ: state เริ่ม/จบ, guard, action, และ transition ต้องห้าม128- [ ] กฎคำนวณระบุสูตร + ลำดับ + การปัดเศษ + หน่วย/สกุลเงิน/เขตเวลา และมี worked example ตัวเลขจริง129- [ ] edge case สำคัญถูกระบุพร้อมพฤติกรรมที่คาด (null, ขอบเขต, หารศูนย์, ซ้ำ, ยกเลิก/ย้อน)130- [ ] precedence ของกฎที่ชนกันถูกระบุชัด131- [ ] assumption และคำถามค้างถูกบันทึก และ rule owner ยืนยันแล้ว132133## เคล็ดลับ & ข้อควรระวัง134135- **อย่าฝังกฎเป็นร้อยแก้ว** — ถ้าเขียนเกิน 2-3 if ในประโยคเดียว ให้ย้ายเป็น decision table ทันที จะเห็นช่องโหว่เอง136- **completeness > ความสวย** — เติมทุก combination แม้กรณี "เป็นไปไม่ได้" แล้ว mark ว่า impossible/error ดีกว่าปล่อยช่องว่างให้ dev เดา137- **แยก "ค่าคงที่" ออกจากตรรกะ** — threshold/เปอร์เซ็นต์ควรชี้ไป config/ตาราง ไม่ hardcode ใน spec; ระบุแหล่งความจริง138- **การปัดเศษคือ bug ยอดฮิต** — ระบุ "ปัดเมื่อไหร่ (แต่ละขั้นหรือขั้นสุดท้าย)" และ "วิธีปัด" ให้ตรงกับฝ่ายบัญชี/กฎหมาย139- **state machine ต้องมี transition ต้องห้าม** — การไม่ระบุ "ห้ามจาก X ไป Y" คือต้นเหตุของ state corruption140- **เขตเวลา/วันทำการ** — โปรโมชัน, ดอกเบี้ย, SLA มักผิดเพราะ timezone หรือไม่นับวันหยุด ระบุปฏิทินอ้างอิงเสมอ141- **อย่าปนเรื่องสิทธิ์** — "ใครได้รับอนุญาตให้อนุมัติ" ไม่ใช่ business logic เฟสนี้ ส่งไป `/sod-matrix` / `/authn-authz-design`142143## เชื่อมกับเฟสอื่น144145- **ก่อนหน้า:** `/fr-nfr-spec` — FR บอก "ระบบต้องทำอะไร" เฟสนี้ลงลึก "ทำตามตรรกะ/กฎอะไรเป๊ะ ๆ"146- **ถัดไป:** `/solution-design` — สถาปนิกรับ rule catalog + decision table + state machine ไปออกแบบโครงสร้าง/data model/API147- **เกี่ยวข้อง:** `/sod-matrix` และ `/authn-authz-design` (สิทธิ์/อนุมัติเชิงบทบาท), `/test-strategy` (แปลง decision table/state machine เป็น test case), `/threat-model` (ตรวจ business-logic abuse)148- **ภาพรวมทั้งวงจร:** `/sdlc-agile`