ข้ามไปยังเนื้อหา

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"]
อะไรจับกลุ่มไหนได้จริงบ้าง
  • 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
  • ทุก 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 จริง
  • authorization check ฝั่ง server ทุกจุดใช้ getUser()/getClaims() ไม่ใช่ getSession() เลยหรือเปล่า? ดู AI Bug Catalog entry 9 พิสูจน์ด้วยการ bypass getSession() ด้วย 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
  • ทุก call ของ supabase-js destructure และเช็ค error ไม่ใช่แค่ data หรือเปล่า? ดู AI Bug Catalog entry 12
  • .single() ทุกครั้งมีการเช็ค PGRST116 อยู่ข้าง ๆ หรือใช้ .maybeSingle() ตรงที่ 0 row เป็นสิ่งที่คาดหวังไว้อยู่แล้วหรือเปล่า? ดู entry 13
  • createClient() ถูกเรียกครั้งเดียวเป๊ะที่ module scope ไม่ใช่ต่อ request หรือต่อ component หรือเปล่า? ดู entry 14 พิสูจน์ด้วยคำเตือน “Multiple GoTrueClient instances” จริง
  • client ไหนผสม global.headers.Authorization (ที่ freeze ตอนสร้าง) กับ auth.setSession() ที่เรียกทีหลังหรือเปล่า? ดู entry 15 พิสูจน์ด้วยการรั่วไหลของข้อมูลจาก header ที่ถูก freeze จริง
  • import ทุกตัวข้างใน supabase/functions/**/index.ts ใช้ jsr:/npm:/relative path ไม่ใช่ bare specifier เลยหรือเปล่า? ดู AI Bug Catalog entry 16 พิสูจน์ด้วย BOOT_ERROR 503 จริง
  • createClient() ข้างในแต่ละ function ได้รับ key ไหน เช็คไขว้กับว่างานของ function นั้นต้องข้าม RLS จริงหรือเปล่า? ดู entry 17
  • secret ไหนอยู่ใน supabase/functions/<name>/.env ธรรมดา แทนที่จะเป็นไฟล์ suffix .local หรือ supabase secrets set หรือเปล่า? ดู entry 18 พิสูจน์กับ .gitignore ของ CLI ตัวนี้เป๊ะ
  • ทุก table ที่ postgres_changes subscription เล็งไปหาเป็นสมาชิกที่ยืนยันแล้วของ 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 เต็มจริง
  • policy ของ storage ทุกตัวเช็ค (storage.foldername(name))[1] เทียบกับ id ของผู้เรียกเอง ไม่ใช่แค่ bucket_id หรือเปล่า? ดู AI Bug Catalog entry 22 พิสูจน์ด้วยการเขียนข้าม folder ของคนอื่นจริง
  • bucket ไหนที่ใช้กับ upload(..., { upsert: true }) มี policy select เพิ่มจาก insert/update หรือเปล่า? ดู entry 23 พิสูจน์ด้วย 403 ที่เฉพาะกับ upsert จริง
  • expiresIn ของ signed URL เคยถูกใช้เกินเวลาที่ URL นั้นถูก cache หรือใช้ซ้ำจริงหรือเปล่า? ดู entry 24 พิสูจน์ด้วย InvalidJWT หลังหมดอายุจริง
  • 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 แล้วมีข้อมูลจริง
  • supabase db lint ถูกรันก่อนเชื่อว่า migration ไม่มีปัญหา unindexed policy column, search_path ที่หายไป หรือ auth.uid() ที่ไม่ wrap หรือเปล่า? ดู Verification Tools
  • deno check — ไม่ใช่ tsc — ถูกรันกับ supabase/functions/**/index.ts ทุกตัว โดยรู้ว่า tsc ไม่เคยถูกรันกับ edge function เลยใน harness ของคอร์สนี้เองหรือเปล่า? ดู Verification Tools
  • CI รัน harness ของคอร์สนี้เอง (npm run verify, --run, --apply) กับทุก fence ไม่ใช่แค่คนสกิมอ่านหรือเปล่า? ดู Verification Tools
Eight groups, same order as the reading-order lesson:
Schema & migrations -> extension deps, FK delete behavior, generated-type drift
RLS & roles -> policy-per-command, using/with check, auth.uid() wrapping,
search_path, RLS-enabled-zero-policies
Auth & sessions -> getUser() not getSession(), refresh reuse, custom claims
Client calls -> error checked, .single()/PGRST116, singleton, frozen headers
Edge functions -> jsr:/npm:, which key, secrets file naming
Realtime -> publication membership, private-channel policy, replica identity
Storage -> folder-scoped policy, upsert needs select, signed URL expiry
Ops & 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 and
the tools cover different failure classes, and most of this catalog's 27 entries pass
every tool cleanly right up until the checklist line that actually names the gap.
ทำไม checklist นี้ถึงบอกให้รัน หลังจาก tool ใน Verification Tools แทนที่จะรันแทนมัน?
บรรทัด checklist ไหนถูกระบุว่าเป็น "บรรทัดที่ผลกระทบสูงที่สุดในหน้านี้" และทำไม?
ทำไมกลุ่ม Edge functions ถึงเจาะจงเรียกหา deno check แทน tsc แทนที่จะให้ทั้งคู่มีค่าเท่ากัน?
กลุ่ม RLS & roles มีบรรทัด checklist มากกว่ากลุ่มอื่นทุกกลุ่ม -- ทำไมคอร์สนี้ถึงให้น้ำหนักมันหนักขนาดนั้น?
ทำไมบรรทัด prepared-statement ของกลุ่ม Ops & pooling ถึง quote เอกสารทางการ แทนที่จะเป็น error ที่ reproduce ในเครื่องได้ ต่างจากบรรทัดอื่นส่วนใหญ่ในหน้านี้?