Checklist สำหรับ review
นี่คือ checklist ที่ต้องไล่ดู — ด้วยตา บน diff ไหนก็ได้ ของคุณเองหรือของ AI — หลังจาก tool ใน Verification Tools รันแล้วผ่านสะอาด มันตั้งใจให้พอดีหน้าเดียวเวลาพิมพ์ออกมา: checklist ที่ไม่มีใครเปิดดูจริงตอน review นั้นไร้ค่า ทุกบรรทัดลิงก์ไปยัง catalog entry ที่อธิบายว่า ทำไม หน้านี้จึงยังเป็นแค่ list ไม่ใช่การรันคอร์สซ้ำ กลุ่มต่าง ๆ เรียงตามลำดับเดียวกับ How to read Supabase code you did not write บวกกลุ่ม Tooling สุดท้ายที่คลุมว่าอีกเจ็ดกลุ่มถูก verify ได้อย่างไรจริง ๆ
flowchart LR A["Schema & migrations"] --> T["Partial: tsc/deno check catch nothing semantic -- only a live query or gen types re-run does"] R["RLS & roles"] --> M["Accepted, not rejected -- pg_policies + a real anon/service_role curl shows it"] U["Auth & sessions"] --> M C["Client calls"] --> T2["tsc catches a typo'd method name, never a skipped error check"] E["Edge functions"] --> D["deno check only -- tsc is not run against edge functions at all"] RT["Realtime"] --> Q["pg_publication_tables / relreplident query -- nothing fails loudly"] S["Storage"] --> M O["Ops & pooling"] --> H["Mostly human review -- key provenance, prepare:false"]
Schema & migrations
หัวข้อที่มีชื่อว่า “Schema & migrations”- primary key ที่เป็น
uuidทุกตัว default เป็นgen_random_uuid()ไม่ใช่uuid_generate_v4()— หรือcreate extension "uuid-ossp"มีอยู่จริงใน migration ที่ apply แล้วหรือเปล่า? ดู AI Bug Catalog entry 1 - FK ที่ควรเป็นเจ้าของ lifecycle ของ parent (
references auth.users(id)พบบ่อยที่สุด) มีon delete cascadeหรือon delete set nullที่ตั้งใจไว้ชัดเจน — ไม่ใช่no actionแบบ implicit หรือเปล่า? ดู entry 2 - PR ล่าสุดที่ rename หรือลบ column ก็ regenerate และ commit
database.types.tsใน PR เดียวกันด้วยหรือเปล่า?tscผ่านไม่ใช่หลักฐานว่าทำแล้ว ดู entry 3
RLS & roles
หัวข้อที่มีชื่อว่า “RLS & roles”- ทุก table ที่เปิด RLS มี policy สำหรับทุกคำสั่งที่ client เรียกจริงหรือเปล่า (
select,insert,update,deleteเป็นอิสระต่อกัน)? ดู AI Bug Catalog entry 4 - policy
for update(หรือfor all) ทุกตัวมีwith checkชัดเจน หรืออาศัยusingที่ถูกใช้ซ้ำแบบเงียบ ๆ หรือเปล่า? ดู entry 5 พิสูจน์ด้วยการขโมย row จริง auth.uid()/auth.role()/auth.jwt()ถูก wrap ด้วย(select ...)ใน policy ทุกตัว ไม่ถูกเรียกเปล่า ๆ หรือเปล่า? ดู entry 6 พิสูจน์ด้วยความต่างของexplain analyzeจริงประมาณ 10 เท่า- ฟังก์ชัน
security definerทุกตัวตั้งsearch_path = ''หรือเปล่า? ดู entry 7 พิสูจน์ด้วยการรั่วไหลจาก schema-injection จริง — บรรทัดที่มีค่ามากที่สุดในหน้านี้ select count(*) from pg_policies where tablename = '<table>'คืนมากกว่าศูนย์สำหรับทุก table ที่เปิด RLS หรือเปล่า? ดู entry 8 พิสูจน์ด้วย table ที่ว่างเปล่าแบบเงียบเพราะ 0 policy จริง
Auth & sessions
หัวข้อที่มีชื่อว่า “Auth & sessions”- authorization check ฝั่ง server ทุกจุดใช้
getUser()/getClaims()ไม่ใช่getSession()เลยหรือเปล่า? ดู AI Bug Catalog entry 9 พิสูจน์ด้วยการ bypassgetSession()ด้วย token ที่ถูกแก้จริง - refresh-retry logic มี branch ชัดเจนสำหรับ
error_code === 'refresh_token_already_used'แยกจากความล้มเหลวชั่วคราวหรือเปล่า? ดู entry 10 - policy หรือโค้ด client ใด ๆ ที่อ่าน custom JWT claim (
auth.jwt() ->> '...') ถูกเช็คไขว้กับ Auth Hook จริงที่ลงทะเบียนไว้ใน[auth.hook.custom_access_token]ของconfig.tomlหรือเปล่า? ดู entry 11
Client calls
หัวข้อที่มีชื่อว่า “Client calls”- ทุก call ของ
supabase-jsdestructure และเช็คerrorไม่ใช่แค่dataหรือเปล่า? ดู AI Bug Catalog entry 12 .single()ทุกครั้งมีการเช็คPGRST116อยู่ข้าง ๆ หรือใช้.maybeSingle()ตรงที่ 0 row เป็นสิ่งที่คาดหวังไว้อยู่แล้วหรือเปล่า? ดู entry 13createClient()ถูกเรียกครั้งเดียวเป๊ะที่ module scope ไม่ใช่ต่อ request หรือต่อ component หรือเปล่า? ดู entry 14 พิสูจน์ด้วยคำเตือน “Multiple GoTrueClient instances” จริง- client ไหนผสม
global.headers.Authorization(ที่ freeze ตอนสร้าง) กับauth.setSession()ที่เรียกทีหลังหรือเปล่า? ดู entry 15 พิสูจน์ด้วยการรั่วไหลของข้อมูลจาก header ที่ถูก freeze จริง
Edge functions
หัวข้อที่มีชื่อว่า “Edge functions”importทุกตัวข้างในsupabase/functions/**/index.tsใช้jsr:/npm:/relative path ไม่ใช่ bare specifier เลยหรือเปล่า? ดู AI Bug Catalog entry 16 พิสูจน์ด้วยBOOT_ERROR503 จริงcreateClient()ข้างในแต่ละ function ได้รับ key ไหน เช็คไขว้กับว่างานของ function นั้นต้องข้าม RLS จริงหรือเปล่า? ดู entry 17- secret ไหนอยู่ใน
supabase/functions/<name>/.envธรรมดา แทนที่จะเป็นไฟล์ suffix.localหรือsupabase secrets setหรือเปล่า? ดู entry 18 พิสูจน์กับ.gitignoreของ CLI ตัวนี้เป๊ะ
Realtime
หัวข้อที่มีชื่อว่า “Realtime”- ทุก table ที่
postgres_changessubscription เล็งไปหาเป็นสมาชิกที่ยืนยันแล้วของsupabase_realtimeหรือเปล่า (select * from pg_publication_tables where pubname = 'supabase_realtime')? ดู AI Bug Catalog entry 19 พิสูจน์ด้วยการพลาดแบบเงียบจริง - ทุก private channel topic มี policy
select(และinsertสำหรับการ broadcast) ที่ตรงกันบนrealtime.messagesหรือเปล่า? ดู entry 20 พิสูจน์ด้วยการถูกปฏิเสธUnauthorizedจริง replica identity fullถูกตั้งบน table ใด ๆ ที่ consumer ของ Realtime อ่าน column ที่ไม่ใช่ key จากpayload.oldหรือเปล่า? ดู entry 21 พิสูจน์ด้วยการเทียบold: nullกับ row เต็มจริง
Storage
หัวข้อที่มีชื่อว่า “Storage”- policy ของ storage ทุกตัวเช็ค
(storage.foldername(name))[1]เทียบกับ id ของผู้เรียกเอง ไม่ใช่แค่bucket_idหรือเปล่า? ดู AI Bug Catalog entry 22 พิสูจน์ด้วยการเขียนข้าม folder ของคนอื่นจริง - bucket ไหนที่ใช้กับ
upload(..., { upsert: true })มี policyselectเพิ่มจากinsert/updateหรือเปล่า? ดู entry 23 พิสูจน์ด้วย 403 ที่เฉพาะกับ upsert จริง expiresInของ signed URL เคยถูกใช้เกินเวลาที่ URL นั้นถูก cache หรือใช้ซ้ำจริงหรือเปล่า? ดู entry 24 พิสูจน์ด้วยInvalidJWTหลังหมดอายุจริง
Ops & pooling
หัวข้อที่มีชื่อว่า “Ops & pooling”SERVICE_ROLE_KEY/SUPABASE_SERVICE_ROLE_KEYปรากฏอยู่ในที่ที่ client bundle อาจ ship ออกไปได้หรือเปล่า? ดู AI Bug Catalog entry 25 — บรรทัดที่ผลกระทบสูงที่สุดในหน้านี้postgres()/driver connection ใด ๆ ที่ผ่าน pooler โหมด transaction (พอร์ตแบบ:6543) ตั้งprepare: falseหรือเปล่า? ดู entry 26 มีเอกสารรองรับ และระบุตรง ๆ ว่า reproduce ไม่ได้ในการทดสอบความหนาแน่นต่ำในเครื่องของคอร์สนี้เอง- ผู้เรียก
pg_netใด ๆ อ่านnet._http_responseด้วยการรอ/retry loop จริง ไม่ใช่ทันทีใน statement เดียวกันหรือเปล่า? ดู entry 27 พิสูจน์ด้วย race condition จาก 0 row แล้วมีข้อมูลจริง
Tooling
หัวข้อที่มีชื่อว่า “Tooling”supabase db lintถูกรันก่อนเชื่อว่า migration ไม่มีปัญหา unindexed policy column,search_pathที่หายไป หรือauth.uid()ที่ไม่ wrap หรือเปล่า? ดู Verification Toolsdeno check— ไม่ใช่tsc— ถูกรันกับsupabase/functions/**/index.tsทุกตัว โดยรู้ว่าtscไม่เคยถูกรันกับ edge function เลยใน harness ของคอร์สนี้เองหรือเปล่า? ดู Verification Tools- CI รัน harness ของคอร์สนี้เอง (
npm run verify,--run,--apply) กับทุก fence ไม่ใช่แค่คนสกิมอ่านหรือเปล่า? ดู Verification Tools
Mental Model
หัวข้อที่มีชื่อว่า “Mental Model”Eight groups, same order as the reading-order lesson:
Schema & migrations -> extension deps, FK delete behavior, generated-type driftRLS & roles -> policy-per-command, using/with check, auth.uid() wrapping, search_path, RLS-enabled-zero-policiesAuth & sessions -> getUser() not getSession(), refresh reuse, custom claimsClient calls -> error checked, .single()/PGRST116, singleton, frozen headersEdge functions -> jsr:/npm:, which key, secrets file namingRealtime -> publication membership, private-channel policy, replica identityStorage -> folder-scoped policy, upsert needs select, signed URL expiryOps & pooling -> which key reaches this code, prepare:false, pg_net is async
Run this AFTER the tools in Verification Tools come back clean -- the checklist andthe tools cover different failure classes, and most of this catalog's 27 entries passevery tool cleanly right up until the checklist line that actually names the gap.