สถาปัตยกรรมของ Supabase
ไอเดียในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียในหนึ่งประโยค”ทุก request ที่เข้ามาที่ auto-generated API ของ Supabase จะไปถึง Postgres พร้อมพก Postgres role ตัวใดตัวหนึ่งเสมอ — anon, authenticated หรือ service_role — และ role นี้แหละคือแกนหลักทางสถาปัตยกรรมที่ทุกอย่างอื่น (Data API, Row Level Security) สร้างต่อยอดขึ้นมา
ทุก request พก role มาด้วย
หัวข้อที่มีชื่อว่า “ทุก request พก role มาด้วย”auto-generated API ของ Supabase authenticate ทุก request หรือไม่ก็ปฏิบัติกับ request นั้นแบบ anonymous อย่างชัดเจน ไม่ว่าจะเป็นแบบไหน request จะไปถึง Postgres ในฐานะหนึ่งในสาม role นี้
anon— request ที่ไม่ได้ authenticate ไม่มี user login อยู่authenticated— request จาก user ที่ login แล้ว พก JWT claim มาด้วย รวมถึงauth.uid()สำหรับระบุว่าเป็น user คนไหนservice_role— server-side code ที่เชื่อถือได้ role นี้ bypass Row Level Security ทั้งหมด เป็น key ตัวเดียวกับที่คุณเจอในบทก่อนหน้า
-- Inside a Row Level Security policy, this is exactly how you tell roles apart.create policy "Users can view their own profile"on public.profilesfor selectto authenticatedusing (auth.uid() = id);PostgREST แปล HTTP เป็น SQL ไม่ enforce อะไรเอง
หัวข้อที่มีชื่อว่า “PostgREST แปล HTTP เป็น SQL ไม่ enforce อะไรเอง”PostgREST คือ service ที่แปล HTTP request แบบ GET /rest/v1/profiles?select=* ให้กลายเป็น SQL query จริง แล้วรัน query นั้น ในฐานะ role ที่ request นั้นพกมา จุดนี้สำคัญกว่าที่ดูเผิน ๆ PostgREST ไม่ได้ implement authorization system แยกของตัวเองเลย แต่พึ่งพา access control ของ Postgres ทั้งหมด — permission แบบ grant/revoke ธรรมดา และ policy Row Level Security — เพื่อตัดสินว่า role นั้นทำอะไรได้จริงบ้าง access control อยู่ที่ database ไม่ใช่ที่ API layer ที่อยู่ด้านหน้า
// This client call becomes an HTTP request to PostgREST, executed as// whatever role the current session carries (anon or authenticated).const { data, error } = await supabase .from('profiles') .select('id, username') .eq('id', userId);service อื่น ๆ ก็แค่อ่านเขียน Postgres เหมือนกัน
หัวข้อที่มีชื่อว่า “service อื่น ๆ ก็แค่อ่านเขียน Postgres เหมือนกัน”Auth, Storage และ Realtime เป็น service แยก (process แยก) แต่ไม่มีตัวไหนสร้าง storage layer ของตัวเองขึ้นมาใหม่เลย ทุกตัวสุดท้ายอ่านเขียน Postgres database เดียวกันนี้
- Auth (GoTrue) จัดการ schema
auth—auth.users, session และ table ที่เกี่ยวข้อง - Storage จัดการ metadata table ของตัวเอง (bucket, object, permission) ใน schema
storageตัวไฟล์จริงอยู่ใน object store แต่ access rule เป็น row ใน Postgres - Realtime อ่าน write-ahead log (WAL) ของ Postgres เพื่อ stream การเปลี่ยนแปลงของ row นอกเหนือจากการมี broadcast/presence channel แบบ ephemeral ให้ใช้
flowchart LR
client["Client request (anon / authenticated / service_role)"] --> postgrest["PostgREST"]
postgrest -->|"executes SQL as that role"| pg[("Postgres
(grants + RLS enforced here)")]
auth["Auth (GoTrue)"] --> pg
storage["Storage"] --> pg
realtime["Realtime (reads WAL)"] --> pg