ทบทวน
สิ่งที่คุณสร้างไป
หัวข้อที่มีชื่อว่า “สิ่งที่คุณสร้างไป”คุณเริ่มจาก repository ว่างเปล่าและจบด้วย headless CMS ที่ทีมเนื้อหาจริง ๆ จำได้: ผู้เขียนล็อกอิน เขียนโพสต์ Markdown ใส่แท็กและเผยแพร่ แล้วตรวจสอบคอมเมนต์ที่ผู้อ่านทิ้งไว้ — และสาธารณะได้อ่านบล็อกที่เร็ว แคชได้ เป็นมิตรกับ SEO ที่ไม่เคยแตะฐานข้อมูลโดยตรง ระหว่างทางคุณไม่ได้แค่ต่อฟีเจอร์เข้าด้วยกัน แต่ได้ฝึกการตัดสินใจที่แยกของเล่นออกจากของที่ส่งมอบได้จริง
ฝั่ง backend คุณตั้งแอปพลิเคชัน NestJS ที่มี config แบบมี type และ AllExceptionsFilter ระดับ global โมเดลโพสต์ แท็ก ผู้ใช้ และคอมเมนต์เป็น Mongoose document และจัดโค้ดเป็นเลเยอร์แบบโมดูลและ provider แทนที่จะเป็นไฟล์เดียวที่ทำทุกอย่าง คุณเพิ่ม authentication จริง ๆ — รหัสผ่านที่แฮชด้วย bcrypt, JWT ที่ออกและตรวจสอบผ่าน Passport, roles และ guards ที่ตัดสินว่าใครทำอะไรได้ — แล้วเปิดเผยทั้งหมดออกมาเป็น API แบบ code-first GraphQL พร้อม resolver สำหรับโพสต์ แท็ก และคอมเมนต์ การทำ pagination และ @ResolveField author ที่ resolve ผู้เขียนของแต่ละโพสต์เมื่อถูกร้องขอ คุณให้เนื้อหามีเวิร์กโฟลว์ที่แท้จริง: slug ที่ไม่ซ้ำสร้างโดย SlugService, การเปลี่ยนสถานะ draft→publish, คอมเมนต์ที่ตรวจสอบก่อนแสดง และรอบ refactoring ที่มีชื่อซึ่งทิ้งโค้ดไว้ดีกว่าตอนที่เจอ
ฝั่ง frontend คุณสร้างแอปพลิเคชัน Next.js App Router ที่มี client gqlFetch แบบมี type, บล็อกสาธารณะแบบ ISR ที่เรนเดอร์ Markdown และส่ง SEO metadata, RSS และ sitemap และ admin dashboard ที่ต้องยืนยันตัวตนพร้อม Markdown editor และคิวตรวจสอบคอมเมนต์ คุณครอบคลุมทั้งสแตกด้วย Jest และ mongodb-memory-server ฝั่ง backend และ Vitest กับ React Testing Library ฝั่ง frontend และสุดท้ายแพ็กทั้งสามเซอร์วิสเป็น Docker image แบบ multi-stage ที่ขึ้นมาพร้อมกันด้วยคำสั่ง docker compose up เดียว
สองเส้นทาง: อ่านและเขียน
หัวข้อที่มีชื่อว่า “สองเส้นทาง: อ่านและเขียน”ถ้าคุณจะจำเรื่องเดียวเกี่ยวกับรูปทรงของ DevBlog ขอให้เป็นเรื่องนี้: มีสองเส้นทางผ่านระบบ และตั้งใจออกแบบให้ต่างกัน
เส้นทางเขียน (write path) ต้องยืนยันตัวตนและผ่าน GraphQL mutation ผู้เขียนล็อกอิน API ออก JWT และทุกการเรียก createPost, publishPost, addTag หรือการตรวจสอบคอมเมนต์ต่อจากนั้นพก token นั้นผ่าน guard ที่ตรวจ role ของผู้เขียนก่อนที่ resolver จะทำงานเสียอีก เส้นทางนี้เป็น dynamic โดยธรรมชาติ เพราะเปลี่ยนสถานะ ต้องมีการป้องกัน และมีคนใช้ไม่กี่คน ตรงนี้ความถูกต้องกับการควบคุมสิทธิ์เข้าถึงสำคัญกว่าความเร็วดิบ
เส้นทางอ่าน (read path) เป็นแบบไม่ระบุตัวตนและปรับให้เหมาะกับการแคช ผู้อ่านไม่เคยยืนยันตัวตนและไม่เคยยิง mutation เขาเข้าถึงหน้า Next.js ที่เรนเดอร์ล่วงหน้าและถูก revalidate ตามกำหนดเวลา (ISR) ซึ่งดึงเนื้อหาที่เผยแพร่แล้วจาก GraphQL API เดียวกันผ่าน query ฝั่งเซิร์ฟเวอร์ เพราะโพสต์ที่เผยแพร่แล้วเปลี่ยนน้อยเมื่อเทียบกับความถี่ที่ถูกอ่าน เส้นทางอ่านจึงแคชได้หนักและเสิร์ฟให้ทุกคนได้เร็ว ส่วนเส้นทางเขียนยังคงเป็น dynamic สำหรับคนไม่กี่คนที่เขียน GraphQL schema คือ contract เดียวที่คั่นอยู่ระหว่างสองเส้นทาง API ที่มี type ตัวเดียวกันนี้แหละที่ admin dashboard ยิง mutation ใส่ และที่บล็อกสาธารณะอ่านออกมา นี่คือเหตุผลว่าทำไมการแยกการเขียนออกจากการส่งมอบจึงคุ้มกับชิ้นส่วนที่เพิ่มขึ้น
ทบทวนทีละโมดูล
หัวข้อที่มีชื่อว่า “ทบทวนทีละโมดูล”ตารางด้านล่างจับคู่โมดูลทั้งสิบสองเข้ากับสิ่งที่คุณได้ฝึกจริง และคอร์สใน Learn Hub ที่แต่ละโมดูลต่อยอดมา
| โมดูล | สิ่งที่คุณได้ฝึก | คอร์สใน Learn Hub ที่อ้างอิง |
|---|---|---|
| 1 · Setup & Tooling | วางโครงโมโนรีโป เครื่องมือ และโครง Docker Compose | Node · Docker |
| 2 · Data Modeling | ออกแบบ schema ของ MongoDB สำหรับโพสต์ แท็ก ผู้ใช้ และคอมเมนต์ | MongoDB |
| 3 · Backend Foundations | จัดโครงโมดูลและ provider ของ NestJS พร้อม config และ exception filter ระดับ global | Node · Design Patterns |
| 4 · Authentication | auth แบบ bcrypt + JWT/Passport พร้อม roles และ guards | Node |
| 5 · GraphQL API | resolver แบบ code-first, pagination และ @ResolveField author | GraphQL |
| 6 · Content Workflow | slug ที่ไม่ซ้ำ การเปลี่ยนสถานะ draft→publish และรอบ refactoring ที่มีชื่อ | Refactoring · Design Patterns |
| 7 · Comments | โมเดลคอมเมนต์พร้อม flow อนุมัติ/ปฏิเสธแบบตรวจสอบก่อนแสดง | MongoDB · GraphQL |
| 8 · Frontend Foundations | โปรเจกต์ Next.js App Router และ client gqlFetch แบบมี type | Next.js · React |
| 9 · Public Blog | บล็อกสาธารณะแบบ ISR พร้อมเรนเดอร์ Markdown, SEO, RSS และ sitemap | Next.js |
| 10 · Admin Dashboard | dashboard ที่ต้องยืนยันตัวตนพร้อม Markdown editor และการตรวจสอบคอมเมนต์ | Next.js · React |
| 11 · Testing | Jest + mongodb-memory-server ฝั่ง backend, Vitest + RTL ฝั่ง frontend | — |
| 12 · Docker & Compose | image แบบ multi-stage และสแตก docker compose up เต็ม | Docker |
DevBlog คือ headless CMS บวกบล็อกสาธารณะ และรูปทรงที่เป็นเอกลักษณ์คือสองเส้นทางที่วางอยู่บน contract GraphQL เดียว: เส้นทางเขียนที่ต้องยืนยันตัวตนผ่าน mutation สำหรับคนไม่กี่คนที่เขียน และเส้นทางอ่านแบบ ISR ไม่ระบุตัวตนที่เน้นแคชสำหรับคนจำนวนมากที่อ่าน ระหว่างทางคุณได้ฝึก document data modelling, สถาปัตยกรรม NestJS แบบเลเยอร์, auth จริงพร้อม role และ guard, GraphQL API แบบ code-first ที่มี type, เวิร์กโฟลว์เนื้อหาและการตรวจสอบ, frontend Next.js App Router สำหรับผู้ใช้ทั้งสองกลุ่ม, เทสต์ทั่วทั้งสแตก และการ deploy ด้วย Docker Compose คำสั่งเดียว บทเรียนถัดไปจะชี้ทางว่าจะดันแต่ละเรื่องให้ไกลกว่านี้ได้อย่างไร
ถัดไป: แบบฝึกหัดต่อยอด →