# CLAUDE.md — Agent Dev Thai Academy
กฎ 48 ข้อจาก 10 หลักสูตร 48 กระดาน หลักฐาน 9 แบบที่ต้องอยู่ในคำตอบก่อนคำว่าเสร็จ และรั้ว 12 แถวที่ใส่แล้วปัญหาไม่กลับมา กฎทุกข้อลงท้ายด้วย path ของกระดานที่สอนมันบนเว็บ Agent Dev Thai Academy หลักฐานกับรั้วลงท้ายด้วยชื่อกระดานที่มันย่อมา (หลักสูตร/กระดาน)
วางไฟล์นี้ที่ root ของ repo แล้วตัดบรรทัดที่ไม่เกี่ยวกับงานคุณออกได้ ฉบับยาวของแต่ละกระดาน (อาการ · prompt ตรวจ · หลักฐาน · รั้ว) อยู่ที่ /audit#หลักสูตร-กระดาน และกฎอีก 83 ข้อจากโพสต์ของเพจอยู่ที่ /audit#from-page

## กฎ

### SOLID ในโค้ดจริง — /solid
- Don't refactor or improve code beyond what was asked. Flag it instead. · /solid#S
- A new channel is a new file that implements the existing interface. Don't add a branch to the shared one. · /solid#O
- A new implementation passes the same contract test as the old one. Compiling is not done. · /solid#L
- Rules for some files go in .claude/rules/ with paths:, not in this file. · /solid#I
- Files with business rules never import a vendor SDK directly. · /solid#D

### Clean Architecture ในโค้ดจริง — /clean
- Search for an existing rule before writing a new one. Business rules import nothing from UI or DB. · /clean#rule
- Use cases take plain data. Convert requests, rows and timezones at the edge. · /clean#boundary
- Fetch data in code first. The model only reads the files. Missing data is n/a, never a guess. · /clean#humble
- Read env and create clients only in main. Fail at startup and name the missing variable. · /clean#main

### Design Patterns ในโค้ดจริง — /patterns
- A new pricing rule is a new class behind PricingRule. Don't add a case to the switch. · /patterns#strategy
- Emit an event. Don't call email or analytics directly from the code that raised it. · /patterns#observer
- Each external API gets one adapter file. Nothing else imports its SDK. · /patterns#adapter
- Add logging, caching or retry by wrapping the service, not by editing it. · /patterns#decorator
- Create courses through CourseFactory. Feature code never calls new VideoCourse(). · /patterns#factory
- Feature code calls checkout() on the facade. Don't wire payment, enrollment and email yourself. · /patterns#facade
- Every write command carries an id. An id the server has seen returns the old result. · /patterns#command
- Keep the enrollment steps in the base flow. A new course type overrides only the step that differs. · /patterns#template

### Engineering practice ในงานจริง — /practice
- Work on a feature branch. Never commit or push to main. · /practice#branch
- Before adding a table, service or module, state the smallest fix and why it is not enough. · /practice#small
- Paste the real test output before saying done. If a bug fix changes a test file, say why first. · /practice#ci
- One change per commit. Use feat:, fix: and BREAKING CHANGE: so the version reads from the log. · /practice#commit
- R0 (deploy, migration, push to main) stop and ask. R2 (easy to revert) just do it. · /practice#rollback

### DDD ในงานจริง — /ddd
- This terminal owns billing/ only. Changes that touch learning/ go through a handoff. · /ddd#context
- Use the terms in GLOSSARY.md. If a word could mean Customer or User, ask which. · /ddd#language
- Change an order only through Order methods. Totals are computed inside, never taken from the caller. · /ddd#aggregate
- Map external responses to our types in one translator. Missing fields become explicit nulls. · /ddd#acl

### แผนภาพที่ CI เช็กได้ — /uml
- domain/ never imports from app/ or infra/. CI checks the imports. · /uml#class
- Write the main flow as numbered steps, then one test that runs those steps through the public API. · /uml#sequence
- Status changes go through the transition table. An unknown status throws. It never falls back to a default. · /uml#state

### Agent setup ในงานจริง — /setup
- Hard limits live in hooks, folder rules in .claude/rules/ with paths. Before adding a rule, name the rule it overlaps. · /setup#rules
- On a pattern failure, log it to MEMORY.md: what happened, root cause, correct behavior. Read spec.md first; update it before saying done. · /setup#memory
- A new skill names the failure it prevents. Keep descriptions under two lines; cut skills that were never invoked. · /setup#skills
- Every pipeline with a read and a write side: verify both, not just the side that produces output. · /setup#pipeline

### ชิมก่อนรับ — /taste
- Before generating UI, read the reference notes. No gradient text, no particle hero, no three-column card grid. Run the slop audit before shipping. · /taste#web
- Before a draft ships, run the five taste filters: brag, voice, concrete, position, bloat. If it fails, rewrite it from a new angle; don't patch words. · /taste#post
- AI assists execution. Operator owns architecture. Don't over-automate decision-making. · /taste#gate

### ใช้ kanly ให้ agent มีกติกา — /kanly
- If a change here affects another repo, write a handoff before ending: what changed, what to do next, breaking changes, the new contract. Read pending handoffs before starting. · /kanly#handoff
- Never start an autonomous loop without named, checkable done conditions written first. Close only when every condition passes; a timeout is not done. · /kanly#contract
- The writer is not the approver. Review in a fresh context that sees the spec, the diff and the tests. Answer every flag: fix it or give a one-line reason; silence counts as a dodge. · /kanly#review
- Every terminal reads the same state file at start; whoever changes something writes it there. Never claim a change is complete without running verification. "I edited the file" is not done. · /kanly#receipt

### แผลเป็นจากงานจริง — /scars
- Name a derived fact once in core and call it from every path. A second definition of the same fact is the bug. · /scars#fact
- A replacement makes the old path unreachable in the same change, proven by grep. No soft deprecation; flip the doc too. · /scars#replace
- A why, triage or pushback turn contains zero edits. Report the operator's own change; never reverse it. · /scars#explain
- Put the money unit in the type, never in a comment or a field name. Convert once, at the provider boundary. · /scars#unit
- Name no cause without a receipt: file:line, a live response or a log line. Re-read your own diff first. · /scars#theory
- A catch never returns a value that looks like data. Health checks call the dependency, not the env var. · /scars#catch
- Before a code fix, name where the behaviour lives: repo, vendor dashboard or this deploy's secrets. Verify the runtime store. · /scars#outside
- Read done and deployed from the live endpoint and the running version, never from a handoff, a memory or a commit. · /scars#wire

## ก่อนพูดว่าเสร็จ · หลักฐานที่ต้องอยู่ในคำตอบ
- ทุกคำตอบเรื่องโครงสร้างมาเป็นตารางที่มีไฟล์กับช่วงบรรทัดจริง ไม่ใช่ชื่อไฟล์หรือคำว่า น่าจะ (solid/S · solid/L · clean/boundary · taste/web)
- ตัวเลขดิบ ไม่ใช่ค่าเฉลี่ย: PR ละกี่ไฟล์กี่บรรทัด, commit ที่ขึ้น `main` ตรงกี่ครั้ง, `new PrismaClient()` และ `process.env` อยู่กี่ที่, ใช้จริงต่อที่มีให้ของทุกไฟล์ที่ import (practice/small · practice/branch · clean/main · solid/I)
- ของที่อ้างว่ามี ยกมาทั้งบรรทัดจากไฟล์จริง หรือตอบว่าไม่มี: คำสั่ง rollback, เงื่อนไขจบของ loop, ไฟล์เสียง, บรรทัดที่บอกทุก session ให้อ่านไฟล์สถานะ (practice/rollback · kanly/contract · taste/post · kanly/receipt)
- ตารางจับคู่ที่ช่อง none คือของที่ต้องทำ: กฎ ↔ check ใน CI, cron ที่เขียนไฟล์ ↔ บรรทัดที่อ่านมัน, feature ↔ คนที่เจ็บถ้าไม่มี, commit ที่เปลี่ยนของที่อีก repo ใช้ ↔ handoff (practice/ci · setup/pipeline · taste/gate · kanly/handoff)
- graph ของ import และ sequence ของการเรียก ไล่จากเครื่องมือและโค้ดจริง พร้อมคำสั่งที่ใช้สร้างและไฟล์กับบรรทัดของแต่ละลูกศร ไม่ใช่วาดจากความจำ (uml/class · uml/sequence)
- ทุกทางเข้าของการกระทำเดียวกัน รวม script ที่คนรันมือ และทุกที่ที่เปลี่ยนจำนวนหรือสถานะ พร้อมคำตอบว่าเช็กกับเขียนอยู่ใน transaction เดียวกันไหม (patterns/command · ddd/aggregate · uml/state)
- โซ่การรั่วของ vendor: type หรือสถานะของมันไหลไป signature ไหน ไฟล์ไหน และกฎข้อไหนของเราตัดสินใจจากมัน (solid/D · ddd/acl · patterns/adapter)
- สิ่งที่โมเดลเห็นจริง ไม่ใช่สิ่งที่มีในโฟลเดอร์: ไฟล์ที่ถูกโหลดตอนเปิด session, จำนวน skill กับความยาวคำอธิบายรวม, คำที่ใช้เรียกเรื่องเดียวกันกี่แบบ (setup/memory · setup/skills · ddd/language)
- ของที่อ่านจากระบบจริง ไม่ใช่จากความจำ: ทุกที่ที่คำนวณความจริงเดียวกันเอง, ชื่อทางเก่าที่ค้นแล้วยังเจอ, ไฟล์ที่ถูกแก้ในรอบที่เป็นคำถาม, ที่ที่บอกหน่วยของทุกช่องเงิน, หลักฐานที่แนบกับสาเหตุแรกที่เอ่ย, catch ที่คืนค่าหน้าตาเหมือนข้อมูล, ที่ที่พฤติกรรมถูกตัดสินจริง, และที่มาของคำว่าเสร็จหรือ deploy แล้ว (scars/*)

## รั้ว · ใส่แล้วไม่กลับมาอีก
- โฟลเดอร์ละเจ้าของ ละ context เช่น `report/`, `charge/`, `sales/`, `billing/` แต่ละอันมี type ของตัวเองที่มีแค่ field ที่ใช้ และ port นิยามฝั่งคนใช้ (solid/S · solid/I · ddd/context)
- กฎธุรกิจอยู่ที่เดียวใน `core/` เป็น pure function ที่ test ได้โดยไม่เปิดเบราว์เซอร์ type ของ command อยู่ใน `core/` ชั้นนอกเป็นคนแปลงเข้าและแสดงผล (clean/rule · clean/humble · clean/boundary)
- `main.ts` ที่เดียวสร้าง client และอ่าน env แล้วส่งต่อ และ factory ที่เดียวต่อการตัดสินใจหนึ่งเรื่อง (clean/main · patterns/factory)
- ของนอกเข้าผ่านชั้นแปลเสมอ: adapter ละ vendor คืน type ของเรา, `acl/` แปลงสถานะเป็น enum ของเราก่อนเข้า domain, และ `eslint no-restricted-imports` ห้าม `core/` import SDK ของ vendor (solid/D · patterns/adapter · ddd/acl)
- ของใหม่คือไฟล์ใหม่ ไม่ใช่ if ใหม่: interface หนึ่งไฟล์กับ registry, strategy ละไฟล์, listener ละไฟล์ของ event ชื่อชัด, wrapper ละเรื่อง, command และ facade ละการกระทำ, โครงเดียว `runExport(steps)` ที่แต่ละรายงานส่งมาแค่ส่วนที่ต่าง (solid/O · patterns/*)
- สัญญาที่เครื่องรัน: `*.contract.test.ts` ต่อ interface, กฎของ class diagram เป็น config ของ `dependency-cruiser`, contract test ที่ใช้ fake จดลำดับการเรียกจาก sequence, ตาราง transition ไฟล์เดียวที่ throw เมื่อเส้นไม่อยู่ในตาราง (solid/L · uml/class · uml/sequence · uml/state)
- การเปลี่ยนจำนวนหรือสถานะผ่านทางเข้าเดียว เช่น `Cohort.enroll()` เช็กและเขียนใน transaction เดียว มี `version` หรือ row lock (ddd/aggregate)
- git: branch protection บน `main` ต้องผ่าน PR และ CI, CI เตือนเมื่อ diff เกิน 400 บรรทัด, commit บรรทัดแรกบอกอะไร body บอกทำไมและอะไรที่ตั้งใจไม่แตะ, ย้อนได้ด้วย `git revert` คำสั่งเดียว, กฎที่เครื่องตรวจได้ต้องมี check ใน CI (practice/*)
- ไฟล์ที่ agent อ่านก่อนทำ: `GLOSSARY.md` คำที่ใช้และคำที่ห้าม, `@MEMORY.md` กับกฎพลาดเมื่อไรจดสามช่อง, hook `PreToolUse` ที่ deny ไฟล์รหัสลับ force push และการลบทั้งโฟลเดอร์, skill ละโหมดคำอธิบายไม่เกินสองบรรทัด, cron ที่เขียนไฟล์มีบรรทัดที่อ่านมัน (ddd/language · setup/*)
- ก่อน gen และก่อนสร้าง: โน้ตอ้างอิงสามข้อที่จับต้องได้ใน repo, ห้าคำถามก่อนเขียน draft (โม้มั้ย เสียงเรามั้ย เรื่องจริงมั้ย ยั่วมั้ย บวมมั้ย), ห้าคำถามก่อนสร้าง feature ถ้าบอกไม่ได้ว่าใครเจ็บให้หยุด (taste/*)
- หลาย terminal: เปลี่ยนของที่อีก repo ใช้ต้องเขียน handoff ก่อนจบงาน, ไม่มีเงื่อนไขจบที่เช็กได้ไม่ปล่อย loop, คนเขียนไม่ใช่คนอนุมัติ, ไฟล์สถานะชุดเดียวที่ทุก terminal อ่านตอนเปิดและจดลงเมื่อเปลี่ยน (kanly/*)
- แผลจากงานจริง: ความจริงที่คำนวณได้มีชื่อเดียวใน `core/`, แทนที่แล้วทางเก่าหายใน change เดียวกันพร้อมผลค้น, รอบที่ถามว่าทำไมไม่มีการแก้ไฟล์, หน่วยเงินอยู่ใน type แปลงที่เดียว, ไม่มีหลักฐานไม่เอ่ยชื่อสาเหตุ, catch ไม่คืนค่าที่ดูเหมือนข้อมูล, บอกก่อนว่าพฤติกรรมอยู่ที่ไหนแล้วอ่านค่าจากที่ระบบใช้ตอนรัน, เสร็จอ่านจาก endpoint จริงและ version ที่รันอยู่ (scars/*)
