Supabase ทำงานอย่างไรข้างใน
ทุกโมดูลก่อนหน้านี้สอน Supabase จากมุมมอง “ข้างนอก” — เรียก supabase.from('table').select() เขียน policy เรียก function เปิด function invoke สมัคร subscribe channel แล้วเชื่อว่ามันทำงานถูกต้อง โมดูลนี้เปิดกล่องออกมาดู ทุก claim ด้านล่างมาจากคำสั่งจริงที่รันกับ local stack ของคอร์สนี้เอง (Postgres, PostgREST, GoTrue, Realtime, Edge Runtime) หรือไม่ก็อ้างอิงบรรทัดจริงจาก source/docs ของ Supabase — ไม่มีการเดาแล้วเล่าเป็นข้อเท็จจริง
ทำไมโมดูลนี้ถึงต้องมี
หัวข้อที่มีชื่อว่า “ทำไมโมดูลนี้ถึงต้องมี”มีสองอย่างที่มักพังตอนโปรเจกต์ Supabase ขึ้น production จริง และทั้งสองเป็นปัญหาระดับ internals ไม่ใช่ปัญหาระดับ API:
- “รันบนเครื่องผมได้ปกติ แต่ production ช้ากว่าหรือไม่ก็โยน permission error ที่ไม่มี tutorial ไหนพูดถึง” Data API, RLS, และ connection pooler ทั้งหมดพฤติกรรมต่างออกไปภายใต้ concurrency จริงและ grant จริง เทียบกับการทดสอบมือครั้งเดียว
- โค้ด Supabase ที่ AI generate มาอ่านลื่นแต่ผิดตรงจุดที่โมดูลนี้ครอบคลุมพอดี —
security definerที่ไม่ตั้งsearch_path, ตารางที่ตกหล่นจาก publication,filterของpostgres_changesที่ถูกเข้าใจผิดว่าเป็นขอบเขตความปลอดภัย, สมมติฐานเรื่อง JWT signing key ที่ไม่จริงแล้วตั้งแต่ตุลาคม 2025 โค้ดที่อ่านลื่นแบบนี้แหละคือสิ่งที่ทำให้บั๊กพวกนี้รอดจาก code review ไปได้
การเข้าใจกลไกจริง — ไม่ใช่ไดอะแกรมที่ใครสักคนวาดไว้ครั้งเดียว แต่เป็นคำสั่งที่รันซ้ำได้ — คือสิ่งที่ทำให้คุณทำนายความล้มเหลวทั้งสองแบบนี้ได้ก่อนที่มันจะ page คุณตอนตีสาม
ลำดับการอ่าน
หัวข้อที่มีชื่อว่า “ลำดับการอ่าน”อ่านจากบนลงล่าง แต่ละบทพิงบทก่อนหน้า
- Postgres Roles and Grants — สาย role
anon/authenticated/service_role/authenticatorที่ PostgREST authenticate เป็นจริง ๆ และทำไมตารางใหม่เอี่ยมถึงมองเห็นได้จากanonก่อนที่คุณจะเขียน policy สักบรรทัด - PostgREST: Request to SQL — SQL ตัวจริงที่
select/insert/rpcแปลงเป็น อ่านย้อนกลับจากpg_stat_statementsบวก schema cache ที่ต้องรู้ก่อนว่า function ของคุณมีอยู่ก่อนมันจะ route ไปให้ - Edge Runtime Isolates — V8 isolate ข้างใน
supabase/edge-runtimeคืออะไรจริง ๆ, permission sandbox ของมัน, และตัวเลข cold/warm ที่คอร์สนี้วัดไปแล้ว อธิบายในระดับกลไก - Realtime: the WAL Pipeline — เส้นทางจริงจาก
INSERTหนึ่งครั้งไปถึงแท็บเบราว์เซอร์ที่ subscribe อยู่: WAL, logical replication slot, ตารางrealtime.subscriptionของ Realtime เอง, RLS ต่อ subscriber - Auth Token Lifecycle — GoTrue เซ็น token ยังไง, PostgREST verify มันโดยไม่ต้องเรียกกลับไปที่ GoTrue ยังไง, refresh rotation กับการตรวจจับการ reuse ลงถึงระดับแถวจริงในตาราง, และจุด hook ที่โปรเจกต์เสียบเข้าไปได้
ทุกการพิสูจน์ในโมดูลนี้ทำยังไง
หัวข้อที่มีชื่อว่า “ทุกการพิสูจน์ในโมดูลนี้ทำยังไง”ทุก fence SQL รันจริง ไม่ว่าจะอยู่ใน transaction ที่ rollback (ตรวจ syntax/semantics เท่านั้น) หรือ commit ด้วย --apply เมื่อการพิสูจน์ curl/supabase-js ถัดไปต้องการให้ object นั้นมีอยู่จริง ทุก curl รันกับ local stack ของคอร์สนี้เอง (supabase status --workdir tools/probe -o env สำหรับ URL/key จริง) ตัด JWT ของ anon/service-role และ UUID ดิบออกแล้ว object ที่โมดูลนี้สร้าง (ตาราง, function, publication) ตั้งชื่อ namespace int_* เพื่อไม่ให้ชนกับ schema local ของโมดูลอื่นบน shared stack เดียวกัน เวอร์ชันที่ใช้ตอนเขียนโมดูลนี้: Postgres 17.6.1, PostgREST v16.2, GoTrue (Auth) v2.196.0, Realtime v2.130.0, Storage v1.72.1, Supavisor 2.9.12 — รัน docker ps และคำสั่ง curl เช็กเวอร์ชันในแต่ละบทใหม่เองถ้าคุณอ่านทีหลังและอยากได้ตัวเลขปัจจุบัน