KoderKoder.ai
ราคาองค์กรการศึกษาสำหรับนักลงทุน
เข้าสู่ระบบเริ่มต้นใช้งาน

ผลิตภัณฑ์

ราคาองค์กรสำหรับนักลงทุน

ทรัพยากร

ติดต่อเราสนับสนุนการศึกษาบล็อก

กฎหมาย

นโยบายความเป็นส่วนตัวข้อกำหนดการใช้งานความปลอดภัยนโยบายการใช้งานที่ยอมรับได้แจ้งการละเมิด

โซเชียล

LinkedInTwitter
Koder.ai
ภาษา

© 2026 Koder.ai สงวนลิขสิทธิ์

หน้าแรก›บล็อก›Claude Code: พรอมต์สำหรับการทำ PostgreSQL migrations อย่างปลอดภัย
05 ธ.ค. 2568·2 นาที

Claude Code: พรอมต์สำหรับการทำ PostgreSQL migrations อย่างปลอดภัย

เรียนรู้พรอมต์สำหรับ Claude Code ที่ช่วยให้มิเกรชัน PostgreSQL ปลอดภัยด้วยรูปแบบ expand-contract, การ backfill, และแผน rollback รวมถึงสิ่งที่ต้องตรวจบนสเตจก่อนปล่อย

Claude Code: พรอมต์สำหรับการทำ PostgreSQL migrations อย่างปลอดภัย

อะไรทำให้การเปลี่ยนแปลงสคีมาของ PostgreSQL เสี่ยง\n\nการเปลี่ยนสคีมาใน PostgreSQL ดูเรียบง่ายจนกว่าจะเจอทราฟฟิกและข้อมูลจริง ส่วนที่เสี่ยงมักไม่ใช่ SQL เอง แต่เป็นเมื่อโค้ดแอป สถานะฐานข้อมูล และเวลาการดีพลอยไม่ตรงกัน\n\nความล้มเหลวส่วนใหญ่เป็นเรื่องปฏิบัติและเจ็บปวด: ดีพลอยแล้วพังเพราะโค้ดเก้าเข้าถึงคอลัมน์ใหม่, มิเกรชันล็อกตารางสำคัญแล้วเกิด timeout, หรือการเปลี่ยนแปลง "เร็วๆ" เงียบๆ ลบหรือเขียนทับข้อมูล แม้ไม่พังทันที คุณอาจปล่อยบั๊กแฝงเช่นค่า default ผิด ข้อจำกัดแตก หรือดัชนีที่ยังสร้างไม่เสร็จ\n\nมิเกรชันที่สร้างโดย AI เพิ่มเลเยอร์ความเสี่ยงอีกชั้น เครื่องมืออาจสร้าง SQL ที่ถูกต้องแต่ไม่ปลอดภัยสำหรับโหลดงาน ปริมาณข้อมูล หรือตัวกระบวนการปล่อยของคุณ มันอาจเดาชื่อเทเบิล พลาดล็อกที่รันนาน หรือพูดข้ามๆ เรื่อง rollback เพราะการทำ down migrations ยาก หากคุณใช้ Claude Code สำหรับมิเกรชัน คุณต้องมีราวจับและบริบทที่เป็นรูปธรรม\n\nเมื่อโพสต์นี้บอกว่าการเปลี่ยนแปลง "ปลอดภัย" หมายถึงสามอย่าง:\n\n- เข้ากันได้ย้อนหลัง: เวอร์ชันเก่าและใหม่ของแอปสามารถรันพร้อมกันระหว่างการเปิดตัว\n- สังเกตได้: คุณสามารถวัดความก้าวหน้าและจับปัญหาได้เร็ว\n- กลับได้: คุณมีแผน rollback ที่ปฏิบัติได้ภายใต้ความกดดัน\n\nเป้าหมายคือต้องการให้มิเกรชันเป็นงานประจำ: คาดเดาได้ ทดสอบได้ และน่าเบื่อ\n\n## กฎความปลอดภัยที่ต้องทำตามก่อนเขียนพรอมต์ใดๆ\n\nเริ่มด้วยกฎไม่ต่อรองไม่กี่ข้อ สิ่งเหล่านี้ช่วยให้โมเดลมีสมาธิและช่วยไม่ให้คุณปล่อยการเปลี่ยนแปลงที่ทำงานได้เฉพาะบนแล็ปท็อปของคุณ\n\nแยกงานเป็นขั้นเล็กๆ การเปลี่ยนสคีมา การ backfill ข้อมูล การเปลี่ยนแปลงแอป และขั้นตอน cleanup เป็นความเสี่ยงต่างกัน การรวมมันเข้าด้วยกันทำให้มองไม่เห็นว่าพังตรงไหนและทำให้ rollback ยากขึ้น\n\nให้ความสำคัญกับการเพิ่มก่อนการทำลาย การเพิ่มคอลัมน์ ดัชนี หรือตารางมักเสี่ยงต่ำ การเปลี่ยนชื่อหรือลบอ็อบเจ็กต์คือจุดที่เกิด outage ทำส่วนที่ปลอดภัยก่อน ย้ายแอป แล้วค่อยลบของเก่าเมื่อแน่ใจว่าไม่ได้ใช้แล้ว\n\nทำให้แอปทนต่อทั้งสองรูปแบบได้สักระยะ โค้ดควรอ่านได้ทั้งคอลัมน์เก่าและใหม่ในช่วง rollout จะช่วยหลีกเลี่ยง race ที่เซิร์ฟเวอร์บางตัวรันโค้ดใหม่ขณะที่ฐานข้อมูลยังเก่า (หรือกลับกัน)\n\nปฏิบัติต่อมิเกรชันเหมือนโค้ดโปรดักชัน ไม่ใช่สคริปต์ด่วน แม้คุณจะสร้างด้วยแพลตฟอร์มอย่าง Koder.ai (backend Go กับ PostgreSQL บวกไคลเอนต์ React หรือ Flutter) ฐานข้อมูลถูกแชร์โดยทุกอย่าง ความผิดพลาดมีค่าใช้จ่ายสูง\n\nหากต้องการชุดกฎสั้นๆ ไว้ด้านบนของทุกคำขอ SQL ให้ใช้ประมาณนี้:\n\n- การเปลี่ยนครั้งละหนึ่งเรื่อง: expand แล้ว backfill แล้วสวิตช์โค้ด แล้ว cleanup\n- หลีกเลี่ยงล็อกยาว: ใช้การสร้างดัชนีแบบ concurrent และแบทช์ขนาดเล็กสำหรับอัปเดต\n- ต้องมีแผน rollback สำหรับทุกขั้นตอน รวมถึงวิธีหยุดกลางทางระหว่าง backfill\n- ต้องมีคำสั่งตรวจสอบและเมตริกความสำเร็จ (นับแถว อัตรา null เวลา)\n- ต้องมี runbook: วิธีรัน อะไรต้องเฝ้า และใครต้องถูกเรียก\n\nตัวอย่างปฏิบัติ: แทนที่จะเปลี่ยนชื่่อคอลัมน์ที่แอปพึ่งพา ให้เพิ่มคอลัมน์ใหม่ backfill แบบช้าๆ ดีพลอยโค้ดที่อ่านจากใหม่ก่อนแล้วค่อยลบคอลัมน์เก่าเมื่อแน่ใจว่ามันไม่ถูกใช้งานแล้ว\n\n## สิ่งที่ต้องใส่ในพรอมต์เพื่อให้ Claude Code อยู่ในกรอบ\n\nClaude เขียน SQL ได้จากคำขอสั้นๆ แต่มิเกรชันที่ปลอดภัยต้องการบริบท ปฏิบัติต่อพรอมต์เป็นบรีฟการออกแบบเล็กๆ: แสดงสิ่งที่มี อธิบายสิ่งที่ห้ามพัง และกำหนดความหมายของ "ปลอดภัย" สำหรับการเปิดตัวของคุณ\n\nเริ่มจากวางเฉพาะข้อเท็จจริงของฐานข้อมูลที่สำคัญ รวม definition ของเทเบิลและดัชนี ข้อจำกัดที่เกี่ยวข้อง (primary key, unique, foreign key, check, trigger) ถ้าเทเบิลที่เกี่ยวข้องมีส่วนเกี่ยวข้อง ให้วางส่วนนั้นด้วย ข้อมูลย่อที่แม่นยำป้องกันโมเดลเดาชื่อหรือพลาดข้อจำกัดสำคัญ\n\nเพิ่มสเกลของโลกจริง จำนวนแถว ขนาดตาราง อัตราเขียน และทราฟฟิกสูงสุดจะเปลี่ยนแผน "200M แถว และ 1k เขียน/วินาที" ต่างจาก "20k แถว และอ่านส่วนใหญ่" รวมเวอร์ชัน Postgres และวิธีที่มิเกรชันรันในระบบคุณ (ทรานแซกชันเดียว vs หลายขั้นตอน)\n\nอธิบายว่าแอปใช้ข้อมูลอย่างไร: การอ่านที่สำคัญ การเขียน และงานแบ็กกราวด์ ตัวอย่าง: "API อ่านตามอีเมล" "workers อัปเดตสถานะ" หรือ "reports สแกนตาม created_at" นี่คือสิ่งที่กำหนดว่าคุณต้องใช้ expand/contract, feature flags และความปลอดภัยของ backfill อย่างไร\n\nสุดท้ายชัดเจนเกี่ยวกับข้อจำกัดและผลลัพธ์ที่ต้องการ โครงสร้างง่ายๆ ทำงานได้ดี:\n\n- สคีมาปัจจุบัน (ส่วนที่เกี่ยวข้อง) และเป้าหมาย\n- สมมติฐานสเกล (แถว อัตราเขียน หน้าต่างบำรุงรักษา ถ้ามี)\n- การพึ่งพาแอป (queries/endpoints/jobs)\n- ข้อจำกัดเข้มงวด (no downtime, หลีกเลี่ยง full-table rewrite, หลีกเลี่ยงล็อกยาว)\n- ผลลัพธ์ที่ต้องส่ง: SQL และแผนรันภาษาธรรมดา การตรวจสอบ และ rollback\n\nการขอทั้ง SQL และแผนรันบังคับให้โมเดลคิดเรื่องลำดับ ความเสี่ยง และสิ่งที่ต้องตรวจก่อนปล่อย\n\n## Expand/contract อธิบายเป็นภาษาง่าย (และเมื่อใดควรใช้)\n\nรูปแบบ expand/contract เปลี่ยนฐานข้อมูล PostgreSQL โดยไม่ทำให้แอปพังขณะเปลี่ยนแปลง แทนที่จะสลับครั้งเดียวที่เสี่ยง คุณทำให้ฐานข้อมูลรองรับทั้งสองรูปร่างระหว่างการเปลี่ยน\n\nคิดแบบนี้: เพิ่มสิ่งใหม่อย่างปลอดภัย (expand), ย้ายทราฟฟิกและข้อมูลทีละน้อย, แล้วจึงลบของเก่า (contract) เหมาะอย่างยิ่งเมื่อมีงานช่วยโดย AI เพราะบังคับให้คุณวางแผนสำหรับช่วงกลางที่ยุ่งเหยิง\n\n### สี่เฟส\n\nโฟลว์ปฏิบัติได้แบบนี้:\n\n- Expand: เพิ่มคอลัมน์หรือเทเบิลใหม่ที่เป็น nullable หรือเพิ่มดัชนี ถ้าจำเป็น และเพิ่มข้อจำกัดโดยหลีกเลี่ยงการบล็อก (เช่น เพิ่มข้อจำกัดเป็น NOT VALID เมื่อเหมาะสม)\n- Compatibility: อัปเดตแอปให้รองรับทั้งฟิลด์เก่าและใหม่ อาจเป็น dual-write หรือ read-fallback\n- Backfill: คัดลอกข้อมูลทีละน้อย มีจุดตรวจและวิธี resume\n- Contract: เมื่อแน่ใจว่าใช้ทางใหม่แล้ว ให้เข้มงวดขึ้น (ตั้ง NOT NULL, validate ข้อจำกัด) แล้วค่อยลบคอลัมน์หรือเทเบิลเก่า\n\nใช้รูปแบบนี้เมื่อผู้ใช้บางส่วนอาจยังใช้โค้ดเก่าในขณะที่ฐานข้อมูลเปลี่ยน รวมการเปิดตัวหลายอินสแตนซ์ แอปมือถือที่อัปเดตช้า หรือการปล่อยที่มิเกรชันอาจใช้เวลานาทีหรือชั่วโมง\n\nกลยุทธ์ที่ช่วยได้คือวางแผนสำหรับสองรอบการปล่อย Release 1 ทำ expand + compatibility เพื่อไม่ให้พังหาก backfill ไม่เสร็จ Release 2 ทำ contract หลังยืนยันว่าโค้ดและข้อมูลใหม่อยู่ในที่ที่ควรจะเป็น\n\n## เทมเพลตพรอมต์ปลอดภัยสำหรับมิเกรชันแบบ expand/contract\n\nคัดลอกเทมเพลตนี้แล้วเติมข้อมูลในวงเล็บ มันบังคับให้ Claude Code ผลิต SQL ที่คุณสามารถรันได้ คำตรวจสอบ และแผน rollback ที่ปฏิบัติได้\n\n\nYou are helping me plan a PostgreSQL expand-contract migration.\n\nContext\n- App: [what the feature does, who uses it]\n- Database: PostgreSQL [version if known]\n- Table sizes: [rough row counts], write rate: [low/medium/high]\n- Zero/near-zero downtime required: [yes/no]\n\nGoal\n- Change: [describe the schema change]\n- Current schema (relevant parts):\n [paste CREATE TABLE or \\d output]\n- How the app will change (expand phase and contract phase):\n - Expand: [new columns/indexes/triggers, dual-write, read preference]\n - Contract: [when/how we stop writing old fields and remove them]\n\nHard safety requirements\n- Prefer lock-safe operations. Avoid full table rewrites on large tables when possible.\n- If any step can block writes, call it out explicitly and suggest alternatives.\n- Use small, reversible steps. No “big bang” changes.\n\nDeliverables\n1) UP migration SQL (expand)\n - Use clear comments.\n - If you propose indexes, tell me if they should be created CONCURRENTLY.\n - If you propose constraints, tell me whether to add them NOT VALID then VALIDATE.\n\n2) Verification queries\n - Queries to confirm the new schema exists.\n - Queries to confirm data is being written to both old and new structures (if dual-write).\n - Queries to estimate whether the change caused bloat/slow queries/locks.\n\n3) Rollback plan (realistic)\n - DOWN migration SQL (only if it is truly safe).\n - If down is not safe, write a rollback runbook:\n - how to stop the app change\n - how to switch reads back\n - what data might be lost or need re-backfill\n\n4) Runbook notes\n - Exact order of operations (including app deploy steps).\n - What to monitor during the run (errors, latency, deadlocks, lock waits).\n - “Stop/continue” checkpoints.\n\nOutput format\n- Separate sections titled: UP.sql, VERIFY.sql, DOWN.sql (or ROLLBACK.md), RUNBOOK.md\n\n\nสองบรรทัดพิเศษที่ช่วยในทางปฏิบัติ:\n\n- ให้บอกว่าแต่ละขั้นตอนที่บล็อกการเขียนให้ติดป้าย RISK: blocks writes และแนะนำเวลาที่ควรรัน (off-peak vs anytime)\n- บังคับให้ซื่อสัตย์เรื่องล็อก: "If you're not sure whether a statement takes an ACCESS EXCLUSIVE lock, say so and offer a safer option."\n\n## การปฏิบัติต่อการดำเนินการสคีมาทั่วไปและวิธีขอ SQL ที่ปลอดภัยกว่า\n\nการเปลี่ยนสคีมาเล็กๆ ก็ยังทำให้เกิดปัญหาได้ถ้ามันล็อกเป็นเวลานาน rewrite ตารางใหญ่ หรือพังกลางทาง เมื่อใช้ Claude Code สำหรับมิเกรชัน ให้ขอ SQL ที่หลีกเลี่ยงการ rewrite และทำให้แอปทำงานได้ในขณะที่ฐานข้อมูลปรับตาม\n\n### เพิ่มคอลัมน์และค่าเริ่มต้น (โดยไม่ล็อกนาน)\n\nการเพิ่มคอลัมน์แบบ nullable มักปลอดภัย การเพิ่มคอลัมน์พร้อม default แบบ non-null อาจเสี่ยงบนเวอร์ชันเก่าของ Postgres เพราะอาจ rewrite ทั้งตาราง\n\nวิธีปลอดภัยคือทำเป็นสองขั้น: เพิ่มคอลัมน์เป็น NULL โดยไม่มี default, backfill ทีละน้อย, แล้วตั้ง default สำหรับแถวใหม่ และเพิ่ม NOT NULL เมื่อข้อมูลสะอาด\n\nถ้าต้องบังคับ default ทันที ให้ขอคำอธิบายพฤติกรรมล็อกสำหรับเวอร์ชัน Postgres ของคุณและแผนสำรองถ้ารันนานกว่าที่คาด\n\n### ดัชนี, FK, ข้อจำกัด, การลบ\n\nสำหรับดัชนีบนตารางใหญ่ ให้ขอ CREATE INDEX CONCURRENTLY เพื่อให้การอ่าน/เขียนยังไหลได้ และระบุว่าไม่สามารถรันใน transactional block ซึ่งหมายความว่าเครื่องมือมิเกรชันของคุณต้องรองรับขั้นตอนนอกทรานแซกชัน\n\nสำหรับ foreign key ทางที่ปลอดภัยคือเพิ่มเป็น NOT VALID ก่อน แล้วค่อย validate ทีหลัง วิธีนี้ทำให้ขั้นแรกเร็วขึ้น ในขณะที่ยังบังคับสำหรับการเขียนใหม่\n\nเมื่อทำให้ข้อจำกัดเข้มขึ้น (NOT NULL, UNIQUE, CHECK) ให้ขอว่า "clean first, enforce second." มิเกรชันควรตรวจหาแถวที่ไม่สะอาด แก้ไข จากนั้นค่อยเปิดกฎเข้มงวด\n\nถ้าต้องการเช็คลิสต์สั้นๆ สำหรับใส่ในพรอมต์ ให้กระชับ:\n\n- ใส่หมายเหตุเรื่องล็อกและเวลาที่คาด\n- ใช้ CONCURRENTLY สำหรับดัชนีขนาดใหญ่และระบุขีดจำกัดของทรานแซกชัน\n- ชอบ NOT VALID แล้ว VALIDATE สำหรับ FK ใหม่\n- แยก backfill ออกจากการบังคับ NOT NULL/UNIQUE\n- ลบอ็อบเจ็กต์หลังรอบการปล่อยเต็มและยืนยันว่าไม่มีใครอ่านมันแล้ว\n\n## การขอ backfill ที่ช้า มั่นคง และกู้คืนได้\n\nBackfill เป็นจุดที่เจ็บปวดที่สุด ไม่ใช่ ALTER TABLE โดยตรง พรอมต์ที่ปลอดภัยปฏิบัติต่อ backfill เหมือนงานควบคุม: วัดได้ รีสตาร์ทได้ และไม่กดระบบ\n\nเริ่มด้วยการตั้งการตรวจรับที่รันง่ายและยากที่จะเถียง: นับแถวที่คาด ค่า null เป้าหมาย และ spot checks สักหน่อย (เช่น เปรียบเทียบค่าเก่า vs ใหม่สำหรับ 20 ID แบบสุ่ม)\n\nแล้วขอแผนแบทช์ ช่วยให้ล็อกสั้นและลดความประหลาดใจ คำขอที่ดีจะระบุ:\n\n- วิธีแบทช์ (ช่วง primary key หรือหน้าต่างเวลา เช่น created_at)\n- ขนาดแบทช์เป้าหมาย (เช่น 5,000 ถึง 50,000 แถว)\n- ว่าจะหน่วงระหว่างแบทช์บนตารางร้อนหรือไม่\n- ให้แต่ละแบทช์เป็นทรานแซกชันชัดเจน (ไม่ใช่ทรานแซกชันใหญ่อันเดียว)\n\nบังคับให้ idempotent เพราะ backfill มักล้มกลางทาง SQL ควรรันซ้ำได้โดยไม่ทำสำเนาหรือทำลายข้อมูล แบบทั่วไปคือ "อัปเดตเฉพาะที่ new column ยังเป็น NULL" หรือกฎที่กำหนดผลลัพธ์ได้แน่นอน\n\nอธิบายด้วยว่าแอปยังถูกต้องอย่างไรระหว่าง backfill ถ้ามีการเขียนใหม่เข้ามา คุณต้องมีสะพาน: dual-write ในโค้ดแอป, ทริกเกอร์ชั่วคราว, หรือ read-fallback บอกว่าคุณใช้แนวทางไหนได้อย่างปลอดภัย\n\nสุดท้าย ต้องมีการหยุดและต่อให้เป็นส่วนหนึ่งของดีไซน์ ขอการติดตามความคืบหน้าและจุดตรวจ เช่น ตารางเล็กๆ เก็บ last processed ID และคำสั่งที่รายงานความคืบหน้า (แถวที่อัปเดต, last ID, เวลาเริ่ม)\n\nตัวอย่าง: เพิ่ม users.full_name สร้างจาก first_name และ last_name แบบปลอดภัยคืออัปเดตเฉพาะแถวที่ full_name IS NULL ทำเป็นช่วง ID บันทึกความคืบหน้า และให้การสมัครใหม่ถูกเขียนอย่างถูกต้องจนกว่าจะสลับเสร็จ\n\n## วิธีขอแผน rollback ที่ใช้ได้จริง\n\nแผน rollback ไม่ใช่แค่ "เขียน down migration" มันคือสองปัญหา: ย้อนสคีมา และจัดการข้อมูลที่เปลี่ยนขณะที่เวอร์ชันใหม่ทำงาน การ rollback สคีมามักเป็นไปได้ ข้อมูลที่เปลี่ยนมักย้อนกลับไม่ได้ เว้นแต่คุณวางแผนตั้งแต่ต้น\n\nระบุให้ชัดเจนว่า rollback หมายถึงอะไรสำหรับการเปลี่ยนแปลงนั้น หากคุณจะลบคอลัมน์หรือเขียนค่าแทนที่ ให้ขอคำตอบที่เป็นจริงเช่น: "Rollback คืนความเข้ากันของแอปได้ แต่ข้อมูลเดิมไม่สามารถกู้คืนได้หากไม่มี snapshot." ความซื่อสัตย์นี้ช่วยให้ปลอดภัย\n\nขอทริกเกอร์ rollback ที่ชัดเจนเพื่อไม่ให้มีการถกเถียงขณะเกิดเหตุ ตัวอย่าง:\n\n- อัตราข้อผิดพลาดหรือ latency เกินค่าที่กำหนดเป็นเวลา 10 นาที\n- แผนการ query ถดถอย (เช่น seq scan บนตารางร้อน)\n- งาน backfill ตกหล่นเกิน N ชั่วโมง\n- การตรวจสอบข้อมูลล้มเหลว (null ที่ไม่ควรมี ซ้ำ หายไป)\n- ขั้นตอนมิเกรชันบล็อกการเขียนนานเกิน X วินาที\n\nต้องให้แพ็กเกจ rollback ทั้งหมด ไม่ใช่แค่ SQL: DOWN SQL (ถ้าปลอดภัย), ขั้นตอนโค้ด/คอนฟิกของแอปเพื่อความเข้ากันได้ และวิธีหยุดงานแบ็กกราวด์\n\nแพทเทิร์นพรอมต์นี้มักเพียงพอ:\n\n\nProduce a rollback plan for this migration.\nInclude: down migration SQL, app config/code switches needed for compatibility, and the exact order of steps.\nState what can be rolled back (schema) vs what cannot (data) and what evidence we need before deciding.\nInclude rollback triggers with thresholds.\n\n\nก่อนปล่อย จัดเก็บ "safety snapshot" เบาๆ เพื่อเปรียบเทียบก่อนและหลัง:\n\n- นับแถวของตารางที่ได้รับผลกระทบ (และส่วนย่อยที่สำคัญ)\n- ชุดตัวอย่างของ query ที่คาดผลลัพธ์\n- เกรณฑ์รวมง่ายๆ (sum, min/max) สำหรับคอลัมน์ที่แตะต้อง\n- รายการ ID สั้นๆ สำหรับ spot-check ก่อนและหลัง\n\nและชัดเจนว่าควรไม่ rollback เมื่อใด ถ้าเพียงเพิ่มคอลัมน์ nullable และแอป dual-write การแก้ข้างหน้า (hotfix โค้ด หยุด backfill แล้วต่อ) มักปลอดภัยกว่าการย้อนกลับและสร้างความเบี้ยวของข้อมูลมากขึ้น\n\n## ข้อผิดพลาดทั่วไปที่ต้องระวังเมื่อตั้งค่ามิเกรชันด้วย AI\n\nAI เขียน SQL ได้เร็ว แต่มันไม่เห็นฐานข้อมูลโปรดักชันของคุณ ความล้มเหลวมักเกิดเมื่อพรอมต์คลุมเครือและโมเดลเติมช่องว่างเอง\n\nกับดักทั่วไปคือข้ามสคีมาปัจจุบัน หากคุณไม่วาง definition ของเทเบิล ดัชนี และข้อจำกัด SQL อาจชี้ไปที่คอลัมน์ที่ไม่มีหรือพลาดกฎ unique ที่ทำให้ backfill กลายเป็นงานช้าและล็อกหนัก\n\nข้อผิดพลาดอีกอย่างคือรวม expand, backfill, และ contract ในดีพลอยเดียว ทำให้ไม่มีทางหนี หาก backfill ใช้เวลานานหรือผิดกลางทาง คุณจะติดกับแอปที่คาดหวังสภาพสุดท้าย\n\nปัญหาที่พบบ่อยที่สุด:\n\n- Backfill ที่ไม่ idempotent และไม่มีการติดตามความคืบหน้า\n- เพิ่ม NOT NULL, UNIQUE, หรือตั้ง FK ก่อนล้างและ validate ข้อมูล\n- ทรานแซกชันที่รันนานโดยไม่มี lock/statement timeouts\n- ไม่มีคำสั่งตรวจสอบ ทำให้ปัญหาแฝงจนผู้ใช้เจอเอง\n\nตัวอย่างชัดเจน: "เปลี่ยนชื่อคอลัมน์และอัปเดตแอป" หากแผนที่สร้างมาเปลี่ยนชื่อและ backfill ในทรานแซกชันเดียว backfill ช้าอาจล็อกและทำให้ทราฟฟิกเสีย หรือต้องบังคับให้พรอมต์ขนาดเล็ก แบทช์ explicit timeouts และคำสั่งตรวจสอบก่อนลบเส้นทางเก่า\n\n## สิ่งที่ต้องตรวจสอบบนสเตจก่อนปล่อย\n\nสเตจค้นพบปัญหาที่ไม่ปรากฏในฐานข้อมูลเดวิเลปขนาดเล็ก: ล็อกยาว, null ที่ไม่คาดคิด, ดัชนีหาย, หรือโค้ดทางผ่านที่ลืม\n\nก่อนอื่นตรวจว่าสคีมาในสเตจตรงตามแผนหลังมิเกรชัน: คอลัมน์ ชนิด ค่า default ข้อจำกัด และดัชนี ตรวจอย่างละเอียด หนึ่งดัชนีหายก็พอจะเปลี่ยน backfill ให้เป็นเคราะห์ร้าย\n\nแล้วรันวิเคราะห์มิเกรชันกับ dataset ที่สมจริง นั่นควรเป็นสำเนาล่าสุดของโปรดักชันที่มาสก์ข้อมูลสำคัญ หากทำไม่ได้ ให้แมตช์ปริมาณและจุดร้อนของโปรดักชัน (ตารางใหญ่ แถวกว้าง ตารางที่มีดัชนีเยอะ) บันทึกเวลาของแต่ละขั้นตอนเพื่อเตรียมคาดการณ์ในโปรดักชัน\n\nเช็คลิสต์สั้นสำหรับสเตจ:\n\n- สคีมาตรงตามแผน (คอลัมน์ ชนิด ข้อจำกัด ดัชนี)\n- บันทึกเวลาในข้อมูลที่สมจริง\n- ทดสอบความเข้ากันได้: แอปเก่ากับสคีมาใหม่ และแอปใหม่กับสคีมาเก่า (เมื่อแผนระบุว่าควรใช้งานได้)\n- รันคำสั่งตรวจสอบ: อัตรา null, นับแถว, ตรวจหา orphan สำหรับ FK ใหม่, ตัวอย่างการอ่าน\n- เฝ้าดูสัญญาณการปฏิบัติการระหว่างรัน: locks, deadlocks, timeouts, slow queries\n\nสุดท้าย ทดสอบฟลว์ผู้ใช้จริง ไม่ใช่แค่ SQL สร้าง แก้ไข และอ่านระเบียนที่เปลี่ยนแปลง หากใช้ expand/contract ยืนยันว่าทั้งสองสคีมาทำงานได้จนกว่าจะ cleanup เสร็จ\n\n## ตัวอย่างที่เป็นจริง: เปลี่ยนคอลัมน์โดยไม่ทำให้ผู้ใช้พัง\n\nสมมติคุณมีคอลัมน์ users.name เก็บชื่อเต็มอย่าง "Ada Lovelace" คุณต้องการ first_name และ last_name แต่ไม่สามารถทำให้การสมัคร การแสดงโปรไฟล์ หรือหน้าฝ่ายแอดมินพังขณะเปลี่ยนแปลง\n\nเริ่มด้วยขั้นตอน expand ที่ปลอดภัยแม้ไม่มีโค้ดใหม่ปล่อย: เพิ่มคอลัมน์ nullable เก็บของเก่าไว้ และหลีกเลี่ยงล็อกยาว\n\nsql\nALTER TABLE users ADD COLUMN first_name text;\nALTER TABLE users ADD COLUMN last_name text;\n\n\nจากนั้นอัปเดตพฤติกรรมแอปให้รองรับทั้งสองรูปแบบ ใน Release 1 แอปควรอ่านจากคอลัมน์ใหม่เมื่อมีค่า fallback ไปที่ name เมื่อเป็น null และเขียนทั้งสองที่เพื่อให้ข้อมูลใหม่สอดคล้อง\n\nต่อมาคือ backfill รันงานแบทช์ที่อัปเดตเป็นชิ้นเล็กๆ ต่อรอบ บันทึกความคืบหน้า และหยุดได้อย่างปลอดภัย ตัวอย่าง: อัปเดต users ที่ first_name เป็น null ตามลำดับ ID ทีละ 1,000 แถว และบันทึกจำนวนแถวที่เปลี่ยน\n\nก่อนเข้มงวด ให้ validate ในสเตจ:\n\n- สมัครใหม่เติม first_name และ last_name และยังตั้ง name\n- ผู้ใช้เดิมแสดงได้แม้มีแค่ name\n- Backfill หยุดและเริ่มใหม่ได้โดยไม่ทำงานซ้ำ\n- ไม่มี null ที่ไม่คาดคิดหลงเหลือหลัง backfill เสร็จ\n- คิวรีพื้นฐานบน users ไม่ช้าลงอย่างมีนัยสำคัญ\n\nRelease 2 สลับการอ่านไปคอลัมน์ใหม่เท่านั้น หลังจากนั้นค่อยเพิ่มข้อจำกัด (เช่น SET NOT NULL) และลบ name ในการปล่อยแยกครั้งถัดไป\n\nสำหรับ rollback ให้ทำให้ง่าย แอปยังอ่าน name ในการเปลี่ยนผ่าน และ backfill หยุดได้ หากต้องย้อน Release 2 ให้สลับการอ่านกลับไป name และทิ้งคอลัมน์ใหม่ไว้จนกว่าจะเสถียร\n\n## ขั้นตอนต่อไป: เปลี่ยนพรอมต์ของคุณให้เป็นนิสัยมิเกรชันที่ทำซ้ำได้\n\nปฏิบัติต่อการเปลี่ยนแต่ละครั้งเหมือน runbook เล็กๆ เป้าหมายไม่ใช่พรอมต์ที่สมบูรณ์แบบ แต่เป็นนิสัยที่บังคับรายละเอียดที่ถูกต้อง: สคีมา ข้อจำกัด แผนรัน และ rollback\n\nมาตรฐานสิ่งที่ต้องมีในทุกคำขอมิเกรชัน:\n\n- สคีมาปัจจุบันและการเปลี่ยนที่ชัดเจน (ตาราง คอลัมน์ ดัชนี)\n- ข้อจำกัดและข้อมูลทราฟฟิก (ขนาดตาราง อัตราเขียน downtime ที่อนุญาต)\n- ลำดับการปล่อย (expand, ปล่อยแอป, backfill, contract)\n- วิธีสังเกตความคืบหน้า (queries/metrics เวลาโดยประมาณ)\n- ขั้นตอน rollback (จะย้อนอะไรก่อน อะไรอาจคงเหลือเป็นข้อมูลที่ต้องกลับมา)\n\nกำหนดเจ้าของแต่ละขั้นก่อนจะรัน SQL ใครเป็นคนดูแลอะไรจะช่วยป้องกัน "ทุกคนคิดว่าอีกคนทำ": นักพัฒนารับผิดชอบพรอมต์และโค้ดมิเกรชัน, ops ควบคุมเวลาและการมอนิเตอร์ใน production, QA ยืนยันพฤติกรรมบนสเตจและขอบกรณี, และคนหนึ่งคนเป็นผู้ตัดสินใจ go/no-go\n\nถ้าคุณสร้างแอปผ่านแชท การร่างลำดับก่อนสร้าง SQL ช่วยได้ สำหรับทีมที่ใช้ Koder.ai, Planning Mode เป็นที่ที่เหมาะจะเขียนลำดับและ snapshot รวม rollback ช่วยลดความเสี่ยงหากเกิดสิ่งไม่คาดคิดระหว่าง rollout\n\nหลังปล่อย ให้กำหนดเวลา cleanup ของ contract ทันทีขณะที่บริบทยังสด เพื่อไม่ให้คอลัมน์เก่าและโค้ดความเข้ากันคงค้างเป็นเดือน

คำถามที่พบบ่อย

Why do PostgreSQL schema changes break production even when the SQL looks simple?

การเปลี่ยนสคีมาเสี่ยงเมื่อ โค้ดแอป สถานะฐานข้อมูล และจังหวะการดีพลอยไม่ตรงกัน\n\nโหมดล้มเหลวที่พบบ่อย:\n\n- โค้ดเวอร์ชันเก้าเข้าถึงคอลัมน์/ข้อจำกัดใหม่แล้วเกิดข้อผิดพลาด\n- มิเกรชันล็อกตารางที่ร้อนและคำขอเกิด timeout\n- การเปลี่ยน "เล็กน้อย" ทำให้ข้อมูลถูกเขียนทับหรือลบโดยไม่ตั้งใจ\n- งานดัชนี/ข้อจำกัดใช้เวลานานกว่าที่คิดและทำให้ query ช้า

What’s the safest default way to change a schema without downtime?

ใช้รูปแบบ expand/contract ที่ปลอดภัย:\n\n- Expand: เพิ่มคอลัมน์/ตาราง/ดัชนีแบบ nullable หรือในทางที่เข้ากันได้\n- Compatibility: ดีพลอยโค้ดที่อ่าน/เขียนกับทั้งสองรูปแบบ\n- Backfill: คัดลอกข้อมูลทีละน้อยพร้อมจุดตรวจ\n- Contract: บีบกฎให้เข้มขึ้นและลบฟิลด์เก่าเมื่อผ่านรอบการปล่อยทั้งหมด\n\nวิธีนี้ทำให้ทั้งเวอร์ชันแอปเก่าและใหม่ทำงานได้ระหว่างการเปิดตัว

What extra risks do AI-generated migrations introduce?

โมเดลอาจสร้าง SQL ที่ถูกต้อง แต่ ไม่ปลอดภัยสำหรับโหลดงานของคุณ\n\nความเสี่ยงเฉพาะจาก AI:\n\n- เดาโครงสร้างตาราง/คอลัมน์หรือพลาดข้อจำกัดสำคัญ\n- เสนอการมิเกรชันแบบ "big bang" ที่ตัดทาง rollback\n- มองข้ามพฤติกรรมล็อก ข้อจำกัดของทรานแซกชัน และการสร้างดัชนีที่ใช้เวลานาน\n- ย่อหน้าเกี่ยวกับ rollback โดยเฉพาะเมื่อข้อมูลถูกแปลงหรือลบ\n\nปฏิบัติต่อผลลัพธ์จาก AI เป็นฉบับร่างและขอแผนการรัน การตรวจสอบ และขั้นตอน rollback เสมอ

What should I paste into my prompt so Claude Code doesn’t guess?

ใส่เฉพาะข้อเท็จจริงที่มิเกรชันต้องใช้:\n\n- ชิ้นส่วน CREATE TABLE ที่เกี่ยวข้อง (บวกดัชนี, FK, UNIQUE/CHECK, ทริกเกอร์)\n- เวอร์ชัน Postgres และวิธีรันมิเกรชัน (ทรานแซกชันเดียว vs หลายขั้นตอน)\n- ขนาดสเกล: จำนวนแถว ขนาดตาราง อัตราเขียน และจราจรสูงสุด\n- วิธีที่แอปใช้ข้อมูล (อ่าน/เขียน/งานแบ็กกราวด์สำคัญ)\n- ข้อจำกัดเข้มงวด (ไม่มี downtime, หลีกเลี่ยง full-table rewrite, ข้อจำกัดล็อก)\n- ผลลัพธ์ที่ต้องการ: UP SQL + คำสั่งตรวจสอบ + แผน rollback + runbook\n\nสิ่งนี้ช่วยป้องกันการเดาชื่อและบังคับลำดับที่ถูกต้อง

Should I combine schema changes and backfills in one migration?

กฎเริ่มต้น: แยกงานออกจากกัน\n\nตัวอย่างการแยกงานที่เป็นประโยชน์:\n\n- มิเกรชัน 1: ขยายสคีมา (คอลัมน์/ตารางใหม่ อาจตั้งค่า NOT VALID สำหรับข้อจำกัด)\n- ดีพลอยแอป: โค้ดความเข้ากันได้ (read-fallback หรือ dual-write)\n- งาน backfill: อัปเดตเป็นชุดพร้อมติดตามความคืบหน้า\n- มิเกรชัน 2: contract (validate ข้อจำกัด, ตั้ง NOT NULL, ลบคอลัมน์เก่า)\n\nการรวมทุกอย่างในครั้งเดียวทำให้การแก้ปัญหาและ rollback ยากขึ้น

How do I add a new column with a default without causing long locks?

รูปแบบที่แนะนำ:\n\n1) ADD COLUMN ... NULL โดยไม่ตั้ง default (เร็ว)\n2) ทำ backfill เป็นชุด\n3) ตั้ง default สำหรับแถวใหม่\n4) เพิ่ม NOT NULL หลังการยืนยัน\n\nการเพิ่ม default แบบ non-null อาจเสี่ยงบนบางเวอร์ชันเพราะอาจ rewrite ทั้งตาราง หากต้องการ default ทันที ให้ขอคำอธิบายพฤติกรรมล็อกและแผนสำรอง

When should I use CREATE INDEX CONCURRENTLY, and what’s the catch?

ขอ:\n\n- CREATE INDEX CONCURRENTLY สำหรับตารางใหญ่/ร้อน\n- แจ้งว่าไม่สามารถรันใน transaction block ได้ (เครื่องมือของคุณต้องรองรับ)\n- คาดการณ์เวลาและสิ่งที่ต้องเฝ้าดู (lock waits, latency ของ query)\n\nเพื่อการตรวจสอบ ให้รวมเช็คว่า index ถูกสร้างและถูกใช้งาน (เช่น เปรียบเทียบ EXPLAIN ก่อน/หลังในสเตจ)

What’s the safest way to add a foreign key on a large table?

ใช้ NOT VALID ก่อน แล้วค่อย validate ภายหลัง:\n\n- เพิ่ม FK เป็น NOT VALID เพื่อให้ก้าวแรกไม่รบกวนมาก\n- รัน VALIDATE CONSTRAINT ในขั้นตอนแยกเมื่อคุณพร้อมเฝ้าดู\n\nวิธีนี้ยังบังคับ FK สำหรับการเขียนใหม่ ในขณะที่คุณควบคุมเวลาของการตรวจสอบที่มีค่าใช้จ่าย

How do I prompt for a backfill that won’t melt production and can resume?

งาน backfill ที่ดีต้องเป็น แบบแบทช์ ทำซ้ำได้ และรีซูมได้\n\nข้อกำหนดปฏิบัติ:\n\n- แบทช์โดยช่วง primary key หรือตามช่วงเวลา\n- อัปเดตเฉพาะแถวที่ยังต้องทำ (WHERE new_col IS NULL)\n- ให้แต่ละแบทช์เป็นทรานแซกชันสั้น ๆ และอาจหน่วงระหว่างแบทช์\n- ติดตามความคืบหน้า (last processed ID, rows updated, เวลาเริ่ม)\n- รับประกันว่าแอปยังทำงานถูกต้องระหว่าง backfill (dual-write, trigger ชั่วคราว, หรือ read-fallback)\n\nการออกแบบแบบนี้ทำให้ backfill ทนทานต่อการทำงานจริง

What does a realistic rollback plan look like for schema changes?

เป้าหมาย rollback ปกติ: คืนความเข้ากันของแอปให้เร็ว แม้ว่าข้อมูลจะไม่ถูกย้อนกลับอย่างสมบูรณ์\n\nแผน rollback ที่ใช้งานได้ควรมี:\n\n- ระบุว่า DOWN SQL ปลอดภัยจริงหรือไม่; ถ้าไม่ ให้เตรียม runbook แทน\n- ลำดับที่ชัดเจน: หยุด/พักงาน backfill, ดีพลอยโค้ดเปลี่ยนแปลง, แล้วทำขั้นตอนสคีมา\n- เกณฑ์ทริกเกอร์ rollback ที่ชัดเจน (อัตราข้อผิดพลาด, latency, lock waits, การตรวจสอบข้อมูลล้มเหลว)\n- บอกว่าคืนอะไรได้ (สคีมา) vs คืนอะไรไม่ได้ (ข้อมูล)\n\nบ่อยครั้ง rollback ที่ปลอดภัยที่สุดคือสลับการอ่านกลับไปยังฟิลด์เก่า ในขณะที่คอลัมน์ใหม่ยังคงอยู่

สารบัญ
อะไรทำให้การเปลี่ยนแปลงสคีมาของ PostgreSQL เสี่ยง\n\nการเปลี่ยนสคีมาใน PostgreSQL ดูเรียบง่ายจนกว่าจะเจอทราฟฟิกและข้อมูลจริง ส่วนที่เสี่ยงมักไม่ใช่ SQL เอง แต่เป็นเมื่อโค้ดแอป สถานะฐานข้อมูล และเวลาการดีพลอยไม่ตรงกัน\n\nความล้มเหลวส่วนใหญ่เป็นเรื่องปฏิบัติและเจ็บปวด: ดีพลอยแล้วพังเพราะโค้ดเก้าเข้าถึงคอลัมน์ใหม่, มิเกรชันล็อกตารางสำคัญแล้วเกิด timeout, หรือการเปลี่ยนแปลง "เร็วๆ" เงียบๆ ลบหรือเขียนทับข้อมูล แม้ไม่พังทันที คุณอาจปล่อยบั๊กแฝงเช่นค่า default ผิด ข้อจำกัดแตก หรือดัชนีที่ยังสร้างไม่เสร็จ\n\nมิเกรชันที่สร้างโดย AI เพิ่มเลเยอร์ความเสี่ยงอีกชั้น เครื่องมืออาจสร้าง SQL ที่ถูกต้องแต่ไม่ปลอดภัยสำหรับโหลดงาน ปริมาณข้อมูล หรือตัวกระบวนการปล่อยของคุณ มันอาจเดาชื่อเทเบิล พลาดล็อกที่รันนาน หรือพูดข้ามๆ เรื่อง rollback เพราะการทำ down migrations ยาก หากคุณใช้ Claude Code สำหรับมิเกรชัน คุณต้องมีราวจับและบริบทที่เป็นรูปธรรม\n\nเมื่อโพสต์นี้บอกว่าการเปลี่ยนแปลง "ปลอดภัย" หมายถึงสามอย่าง:\n\n- เข้ากันได้ย้อนหลัง: เวอร์ชันเก่าและใหม่ของแอปสามารถรันพร้อมกันระหว่างการเปิดตัว\n- สังเกตได้: คุณสามารถวัดความก้าวหน้าและจับปัญหาได้เร็ว\n- กลับได้: คุณมีแผน rollback ที่ปฏิบัติได้ภายใต้ความกดดัน\n\nเป้าหมายคือต้องการให้มิเกรชันเป็นงานประจำ: คาดเดาได้ ทดสอบได้ และน่าเบื่อ\n\n## กฎความปลอดภัยที่ต้องทำตามก่อนเขียนพรอมต์ใดๆ\n\nเริ่มด้วยกฎไม่ต่อรองไม่กี่ข้อ สิ่งเหล่านี้ช่วยให้โมเดลมีสมาธิและช่วยไม่ให้คุณปล่อยการเปลี่ยนแปลงที่ทำงานได้เฉพาะบนแล็ปท็อปของคุณ\n\nแยกงานเป็นขั้นเล็กๆ การเปลี่ยนสคีมา การ backfill ข้อมูล การเปลี่ยนแปลงแอป และขั้นตอน cleanup เป็นความเสี่ยงต่างกัน การรวมมันเข้าด้วยกันทำให้มองไม่เห็นว่าพังตรงไหนและทำให้ rollback ยากขึ้น\n\nให้ความสำคัญกับการเพิ่มก่อนการทำลาย การเพิ่มคอลัมน์ ดัชนี หรือตารางมักเสี่ยงต่ำ การเปลี่ยนชื่อหรือลบอ็อบเจ็กต์คือจุดที่เกิด outage ทำส่วนที่ปลอดภัยก่อน ย้ายแอป แล้วค่อยลบของเก่าเมื่อแน่ใจว่าไม่ได้ใช้แล้ว\n\nทำให้แอปทนต่อทั้งสองรูปแบบได้สักระยะ โค้ดควรอ่านได้ทั้งคอลัมน์เก่าและใหม่ในช่วง rollout จะช่วยหลีกเลี่ยง race ที่เซิร์ฟเวอร์บางตัวรันโค้ดใหม่ขณะที่ฐานข้อมูลยังเก่า (หรือกลับกัน)\n\nปฏิบัติต่อมิเกรชันเหมือนโค้ดโปรดักชัน ไม่ใช่สคริปต์ด่วน แม้คุณจะสร้างด้วยแพลตฟอร์มอย่าง Koder.ai (backend Go กับ PostgreSQL บวกไคลเอนต์ React หรือ Flutter) ฐานข้อมูลถูกแชร์โดยทุกอย่าง ความผิดพลาดมีค่าใช้จ่ายสูง\n\nหากต้องการชุดกฎสั้นๆ ไว้ด้านบนของทุกคำขอ SQL ให้ใช้ประมาณนี้:\n\n- การเปลี่ยนครั้งละหนึ่งเรื่อง: expand แล้ว backfill แล้วสวิตช์โค้ด แล้ว cleanup\n- หลีกเลี่ยงล็อกยาว: ใช้การสร้างดัชนีแบบ concurrent และแบทช์ขนาดเล็กสำหรับอัปเดต\n- ต้องมีแผน rollback สำหรับทุกขั้นตอน รวมถึงวิธีหยุดกลางทางระหว่าง backfill\n- ต้องมีคำสั่งตรวจสอบและเมตริกความสำเร็จ (นับแถว อัตรา null เวลา)\n- ต้องมี runbook: วิธีรัน อะไรต้องเฝ้า และใครต้องถูกเรียก\n\nตัวอย่างปฏิบัติ: แทนที่จะเปลี่ยนชื่่อคอลัมน์ที่แอปพึ่งพา ให้เพิ่มคอลัมน์ใหม่ backfill แบบช้าๆ ดีพลอยโค้ดที่อ่านจากใหม่ก่อนแล้วค่อยลบคอลัมน์เก่าเมื่อแน่ใจว่ามันไม่ถูกใช้งานแล้ว\n\n## สิ่งที่ต้องใส่ในพรอมต์เพื่อให้ Claude Code อยู่ในกรอบ\n\nClaude เขียน SQL ได้จากคำขอสั้นๆ แต่มิเกรชันที่ปลอดภัยต้องการบริบท ปฏิบัติต่อพรอมต์เป็นบรีฟการออกแบบเล็กๆ: แสดงสิ่งที่มี อธิบายสิ่งที่ห้ามพัง และกำหนดความหมายของ "ปลอดภัย" สำหรับการเปิดตัวของคุณ\n\nเริ่มจากวางเฉพาะข้อเท็จจริงของฐานข้อมูลที่สำคัญ รวม definition ของเทเบิลและดัชนี ข้อจำกัดที่เกี่ยวข้อง (primary key, unique, foreign key, check, trigger) ถ้าเทเบิลที่เกี่ยวข้องมีส่วนเกี่ยวข้อง ให้วางส่วนนั้นด้วย ข้อมูลย่อที่แม่นยำป้องกันโมเดลเดาชื่อหรือพลาดข้อจำกัดสำคัญ\n\nเพิ่มสเกลของโลกจริง จำนวนแถว ขนาดตาราง อัตราเขียน และทราฟฟิกสูงสุดจะเปลี่ยนแผน "200M แถว และ 1k เขียน/วินาที" ต่างจาก "20k แถว และอ่านส่วนใหญ่" รวมเวอร์ชัน Postgres และวิธีที่มิเกรชันรันในระบบคุณ (ทรานแซกชันเดียว vs หลายขั้นตอน)\n\nอธิบายว่าแอปใช้ข้อมูลอย่างไร: การอ่านที่สำคัญ การเขียน และงานแบ็กกราวด์ ตัวอย่าง: "API อ่านตามอีเมล" "workers อัปเดตสถานะ" หรือ "reports สแกนตาม created_at" นี่คือสิ่งที่กำหนดว่าคุณต้องใช้ expand/contract, feature flags และความปลอดภัยของ backfill อย่างไร\n\nสุดท้ายชัดเจนเกี่ยวกับข้อจำกัดและผลลัพธ์ที่ต้องการ โครงสร้างง่ายๆ ทำงานได้ดี:\n\n- สคีมาปัจจุบัน (ส่วนที่เกี่ยวข้อง) และเป้าหมาย\n- สมมติฐานสเกล (แถว อัตราเขียน หน้าต่างบำรุงรักษา ถ้ามี)\n- การพึ่งพาแอป (queries/endpoints/jobs)\n- ข้อจำกัดเข้มงวด (no downtime, หลีกเลี่ยง full-table rewrite, หลีกเลี่ยงล็อกยาว)\n- ผลลัพธ์ที่ต้องส่ง: SQL และแผนรันภาษาธรรมดา การตรวจสอบ และ rollback\n\nการขอทั้ง SQL และแผนรันบังคับให้โมเดลคิดเรื่องลำดับ ความเสี่ยง และสิ่งที่ต้องตรวจก่อนปล่อย\n\n## Expand/contract อธิบายเป็นภาษาง่าย (และเมื่อใดควรใช้)\n\nรูปแบบ expand/contract เปลี่ยนฐานข้อมูล PostgreSQL โดยไม่ทำให้แอปพังขณะเปลี่ยนแปลง แทนที่จะสลับครั้งเดียวที่เสี่ยง คุณทำให้ฐานข้อมูลรองรับทั้งสองรูปร่างระหว่างการเปลี่ยน\n\nคิดแบบนี้: เพิ่มสิ่งใหม่อย่างปลอดภัย (expand), ย้ายทราฟฟิกและข้อมูลทีละน้อย, แล้วจึงลบของเก่า (contract) เหมาะอย่างยิ่งเมื่อมีงานช่วยโดย AI เพราะบังคับให้คุณวางแผนสำหรับช่วงกลางที่ยุ่งเหยิง\n\n### สี่เฟส\n\nโฟลว์ปฏิบัติได้แบบนี้:\n\n- Expand: เพิ่มคอลัมน์หรือเทเบิลใหม่ที่เป็น nullable หรือเพิ่มดัชนี ถ้าจำเป็น และเพิ่มข้อจำกัดโดยหลีกเลี่ยงการบล็อก (เช่น เพิ่มข้อจำกัดเป็น NOT VALID เมื่อเหมาะสม)\n- Compatibility: อัปเดตแอปให้รองรับทั้งฟิลด์เก่าและใหม่ อาจเป็น dual-write หรือ read-fallback\n- Backfill: คัดลอกข้อมูลทีละน้อย มีจุดตรวจและวิธี resume\n- Contract: เมื่อแน่ใจว่าใช้ทางใหม่แล้ว ให้เข้มงวดขึ้น (ตั้ง NOT NULL, validate ข้อจำกัด) แล้วค่อยลบคอลัมน์หรือเทเบิลเก่า\n\nใช้รูปแบบนี้เมื่อผู้ใช้บางส่วนอาจยังใช้โค้ดเก่าในขณะที่ฐานข้อมูลเปลี่ยน รวมการเปิดตัวหลายอินสแตนซ์ แอปมือถือที่อัปเดตช้า หรือการปล่อยที่มิเกรชันอาจใช้เวลานาทีหรือชั่วโมง\n\nกลยุทธ์ที่ช่วยได้คือวางแผนสำหรับสองรอบการปล่อย Release 1 ทำ expand + compatibility เพื่อไม่ให้พังหาก backfill ไม่เสร็จ Release 2 ทำ contract หลังยืนยันว่าโค้ดและข้อมูลใหม่อยู่ในที่ที่ควรจะเป็น\n\n## เทมเพลตพรอมต์ปลอดภัยสำหรับมิเกรชันแบบ expand/contract\n\nคัดลอกเทมเพลตนี้แล้วเติมข้อมูลในวงเล็บ มันบังคับให้ Claude Code ผลิต SQL ที่คุณสามารถรันได้ คำตรวจสอบ และแผน rollback ที่ปฏิบัติได้\n\n```\nYou are helping me plan a PostgreSQL expand-contract migration.\n\nContext\n- App: [what the feature does, who uses it]\n- Database: PostgreSQL [version if known]\n- Table sizes: [rough row counts], write rate: [low/medium/high]\n- Zero/near-zero downtime required: [yes/no]\n\nGoal\n- Change: [describe the schema change]\n- Current schema (relevant parts):\n [paste CREATE TABLE or \\d output]\n- How the app will change (expand phase and contract phase):\n - Expand: [new columns/indexes/triggers, dual-write, read preference]\n - Contract: [when/how we stop writing old fields and remove them]\n\nHard safety requirements\n- Prefer lock-safe operations. Avoid full table rewrites on large tables when possible.\n- If any step can block writes, call it out explicitly and suggest alternatives.\n- Use small, reversible steps. No “big bang” changes.\n\nDeliverables\n1) UP migration SQL (expand)\n - Use clear comments.\n - If you propose indexes, tell me if they should be created CONCURRENTLY.\n - If you propose constraints, tell me whether to add them NOT VALID then VALIDATE.\n\n2) Verification queries\n - Queries to confirm the new schema exists.\n - Queries to confirm data is being written to both old and new structures (if dual-write).\n - Queries to estimate whether the change caused bloat/slow queries/locks.\n\n3) Rollback plan (realistic)\n - DOWN migration SQL (only if it is truly safe).\n - If down is not safe, write a rollback runbook:\n - how to stop the app change\n - how to switch reads back\n - what data might be lost or need re-backfill\n\n4) Runbook notes\n - Exact order of operations (including app deploy steps).\n - What to monitor during the run (errors, latency, deadlocks, lock waits).\n - “Stop/continue” checkpoints.\n\nOutput format\n- Separate sections titled: UP.sql, VERIFY.sql, DOWN.sql (or ROLLBACK.md), RUNBOOK.md\n```\n\nสองบรรทัดพิเศษที่ช่วยในทางปฏิบัติ:\n\n- ให้บอกว่าแต่ละขั้นตอนที่บล็อกการเขียนให้ติดป้าย `RISK: blocks writes` และแนะนำเวลาที่ควรรัน (off-peak vs anytime)\n- บังคับให้ซื่อสัตย์เรื่องล็อก: "If you're not sure whether a statement takes an ACCESS EXCLUSIVE lock, say so and offer a safer option."\n\n## การปฏิบัติต่อการดำเนินการสคีมาทั่วไปและวิธีขอ SQL ที่ปลอดภัยกว่า\n\nการเปลี่ยนสคีมาเล็กๆ ก็ยังทำให้เกิดปัญหาได้ถ้ามันล็อกเป็นเวลานาน rewrite ตารางใหญ่ หรือพังกลางทาง เมื่อใช้ Claude Code สำหรับมิเกรชัน ให้ขอ SQL ที่หลีกเลี่ยงการ rewrite และทำให้แอปทำงานได้ในขณะที่ฐานข้อมูลปรับตาม\n\n### เพิ่มคอลัมน์และค่าเริ่มต้น (โดยไม่ล็อกนาน)\n\nการเพิ่มคอลัมน์แบบ nullable มักปลอดภัย การเพิ่มคอลัมน์พร้อม default แบบ non-null อาจเสี่ยงบนเวอร์ชันเก่าของ Postgres เพราะอาจ rewrite ทั้งตาราง\n\nวิธีปลอดภัยคือทำเป็นสองขั้น: เพิ่มคอลัมน์เป็น NULL โดยไม่มี default, backfill ทีละน้อย, แล้วตั้ง default สำหรับแถวใหม่ และเพิ่ม NOT NULL เมื่อข้อมูลสะอาด\n\nถ้าต้องบังคับ default ทันที ให้ขอคำอธิบายพฤติกรรมล็อกสำหรับเวอร์ชัน Postgres ของคุณและแผนสำรองถ้ารันนานกว่าที่คาด\n\n### ดัชนี, FK, ข้อจำกัด, การลบ\n\nสำหรับดัชนีบนตารางใหญ่ ให้ขอ `CREATE INDEX CONCURRENTLY` เพื่อให้การอ่าน/เขียนยังไหลได้ และระบุว่าไม่สามารถรันใน transactional block ซึ่งหมายความว่าเครื่องมือมิเกรชันของคุณต้องรองรับขั้นตอนนอกทรานแซกชัน\n\nสำหรับ foreign key ทางที่ปลอดภัยคือเพิ่มเป็น `NOT VALID` ก่อน แล้วค่อย validate ทีหลัง วิธีนี้ทำให้ขั้นแรกเร็วขึ้น ในขณะที่ยังบังคับสำหรับการเขียนใหม่\n\nเมื่อทำให้ข้อจำกัดเข้มขึ้น (NOT NULL, UNIQUE, CHECK) ให้ขอว่า "clean first, enforce second." มิเกรชันควรตรวจหาแถวที่ไม่สะอาด แก้ไข จากนั้นค่อยเปิดกฎเข้มงวด\n\nถ้าต้องการเช็คลิสต์สั้นๆ สำหรับใส่ในพรอมต์ ให้กระชับ:\n\n- ใส่หมายเหตุเรื่องล็อกและเวลาที่คาด\n- ใช้ CONCURRENTLY สำหรับดัชนีขนาดใหญ่และระบุขีดจำกัดของทรานแซกชัน\n- ชอบ NOT VALID แล้ว VALIDATE สำหรับ FK ใหม่\n- แยก backfill ออกจากการบังคับ NOT NULL/UNIQUE\n- ลบอ็อบเจ็กต์หลังรอบการปล่อยเต็มและยืนยันว่าไม่มีใครอ่านมันแล้ว\n\n## การขอ backfill ที่ช้า มั่นคง และกู้คืนได้\n\nBackfill เป็นจุดที่เจ็บปวดที่สุด ไม่ใช่ `ALTER TABLE` โดยตรง พรอมต์ที่ปลอดภัยปฏิบัติต่อ backfill เหมือนงานควบคุม: วัดได้ รีสตาร์ทได้ และไม่กดระบบ\n\nเริ่มด้วยการตั้งการตรวจรับที่รันง่ายและยากที่จะเถียง: นับแถวที่คาด ค่า null เป้าหมาย และ spot checks สักหน่อย (เช่น เปรียบเทียบค่าเก่า vs ใหม่สำหรับ 20 ID แบบสุ่ม)\n\nแล้วขอแผนแบทช์ ช่วยให้ล็อกสั้นและลดความประหลาดใจ คำขอที่ดีจะระบุ:\n\n- วิธีแบทช์ (ช่วง primary key หรือหน้าต่างเวลา เช่น created_at)\n- ขนาดแบทช์เป้าหมาย (เช่น 5,000 ถึง 50,000 แถว)\n- ว่าจะหน่วงระหว่างแบทช์บนตารางร้อนหรือไม่\n- ให้แต่ละแบทช์เป็นทรานแซกชันชัดเจน (ไม่ใช่ทรานแซกชันใหญ่อันเดียว)\n\nบังคับให้ idempotent เพราะ backfill มักล้มกลางทาง SQL ควรรันซ้ำได้โดยไม่ทำสำเนาหรือทำลายข้อมูล แบบทั่วไปคือ "อัปเดตเฉพาะที่ new column ยังเป็น NULL" หรือกฎที่กำหนดผลลัพธ์ได้แน่นอน\n\nอธิบายด้วยว่าแอปยังถูกต้องอย่างไรระหว่าง backfill ถ้ามีการเขียนใหม่เข้ามา คุณต้องมีสะพาน: dual-write ในโค้ดแอป, ทริกเกอร์ชั่วคราว, หรือ read-fallback บอกว่าคุณใช้แนวทางไหนได้อย่างปลอดภัย\n\nสุดท้าย ต้องมีการหยุดและต่อให้เป็นส่วนหนึ่งของดีไซน์ ขอการติดตามความคืบหน้าและจุดตรวจ เช่น ตารางเล็กๆ เก็บ last processed ID และคำสั่งที่รายงานความคืบหน้า (แถวที่อัปเดต, last ID, เวลาเริ่ม)\n\nตัวอย่าง: เพิ่ม `users.full_name` สร้างจาก `first_name` และ `last_name` แบบปลอดภัยคืออัปเดตเฉพาะแถวที่ `full_name IS NULL` ทำเป็นช่วง ID บันทึกความคืบหน้า และให้การสมัครใหม่ถูกเขียนอย่างถูกต้องจนกว่าจะสลับเสร็จ\n\n## วิธีขอแผน rollback ที่ใช้ได้จริง\n\nแผน rollback ไม่ใช่แค่ "เขียน down migration" มันคือสองปัญหา: ย้อนสคีมา และจัดการข้อมูลที่เปลี่ยนขณะที่เวอร์ชันใหม่ทำงาน การ rollback สคีมามักเป็นไปได้ ข้อมูลที่เปลี่ยนมักย้อนกลับไม่ได้ เว้นแต่คุณวางแผนตั้งแต่ต้น\n\nระบุให้ชัดเจนว่า rollback หมายถึงอะไรสำหรับการเปลี่ยนแปลงนั้น หากคุณจะลบคอลัมน์หรือเขียนค่าแทนที่ ให้ขอคำตอบที่เป็นจริงเช่น: "Rollback คืนความเข้ากันของแอปได้ แต่ข้อมูลเดิมไม่สามารถกู้คืนได้หากไม่มี snapshot." ความซื่อสัตย์นี้ช่วยให้ปลอดภัย\n\nขอทริกเกอร์ rollback ที่ชัดเจนเพื่อไม่ให้มีการถกเถียงขณะเกิดเหตุ ตัวอย่าง:\n\n- อัตราข้อผิดพลาดหรือ latency เกินค่าที่กำหนดเป็นเวลา 10 นาที\n- แผนการ query ถดถอย (เช่น seq scan บนตารางร้อน)\n- งาน backfill ตกหล่นเกิน N ชั่วโมง\n- การตรวจสอบข้อมูลล้มเหลว (null ที่ไม่ควรมี ซ้ำ หายไป)\n- ขั้นตอนมิเกรชันบล็อกการเขียนนานเกิน X วินาที\n\nต้องให้แพ็กเกจ rollback ทั้งหมด ไม่ใช่แค่ SQL: DOWN SQL (ถ้าปลอดภัย), ขั้นตอนโค้ด/คอนฟิกของแอปเพื่อความเข้ากันได้ และวิธีหยุดงานแบ็กกราวด์\n\nแพทเทิร์นพรอมต์นี้มักเพียงพอ:\n\n```\nProduce a rollback plan for this migration.\nInclude: down migration SQL, app config/code switches needed for compatibility, and the exact order of steps.\nState what can be rolled back (schema) vs what cannot (data) and what evidence we need before deciding.\nInclude rollback triggers with thresholds.\n```\n\nก่อนปล่อย จัดเก็บ "safety snapshot" เบาๆ เพื่อเปรียบเทียบก่อนและหลัง:\n\n- นับแถวของตารางที่ได้รับผลกระทบ (และส่วนย่อยที่สำคัญ)\n- ชุดตัวอย่างของ query ที่คาดผลลัพธ์\n- เกรณฑ์รวมง่ายๆ (sum, min/max) สำหรับคอลัมน์ที่แตะต้อง\n- รายการ ID สั้นๆ สำหรับ spot-check ก่อนและหลัง\n\nและชัดเจนว่าควรไม่ rollback เมื่อใด ถ้าเพียงเพิ่มคอลัมน์ nullable และแอป dual-write การแก้ข้างหน้า (hotfix โค้ด หยุด backfill แล้วต่อ) มักปลอดภัยกว่าการย้อนกลับและสร้างความเบี้ยวของข้อมูลมากขึ้น\n\n## ข้อผิดพลาดทั่วไปที่ต้องระวังเมื่อตั้งค่ามิเกรชันด้วย AI\n\nAI เขียน SQL ได้เร็ว แต่มันไม่เห็นฐานข้อมูลโปรดักชันของคุณ ความล้มเหลวมักเกิดเมื่อพรอมต์คลุมเครือและโมเดลเติมช่องว่างเอง\n\nกับดักทั่วไปคือข้ามสคีมาปัจจุบัน หากคุณไม่วาง definition ของเทเบิล ดัชนี และข้อจำกัด SQL อาจชี้ไปที่คอลัมน์ที่ไม่มีหรือพลาดกฎ unique ที่ทำให้ backfill กลายเป็นงานช้าและล็อกหนัก\n\nข้อผิดพลาดอีกอย่างคือรวม expand, backfill, และ contract ในดีพลอยเดียว ทำให้ไม่มีทางหนี หาก backfill ใช้เวลานานหรือผิดกลางทาง คุณจะติดกับแอปที่คาดหวังสภาพสุดท้าย\n\nปัญหาที่พบบ่อยที่สุด:\n\n- Backfill ที่ไม่ idempotent และไม่มีการติดตามความคืบหน้า\n- เพิ่ม NOT NULL, UNIQUE, หรือตั้ง FK ก่อนล้างและ validate ข้อมูล\n- ทรานแซกชันที่รันนานโดยไม่มี lock/statement timeouts\n- ไม่มีคำสั่งตรวจสอบ ทำให้ปัญหาแฝงจนผู้ใช้เจอเอง\n\nตัวอย่างชัดเจน: "เปลี่ยนชื่อคอลัมน์และอัปเดตแอป" หากแผนที่สร้างมาเปลี่ยนชื่อและ backfill ในทรานแซกชันเดียว backfill ช้าอาจล็อกและทำให้ทราฟฟิกเสีย หรือต้องบังคับให้พรอมต์ขนาดเล็ก แบทช์ explicit timeouts และคำสั่งตรวจสอบก่อนลบเส้นทางเก่า\n\n## สิ่งที่ต้องตรวจสอบบนสเตจก่อนปล่อย\n\nสเตจค้นพบปัญหาที่ไม่ปรากฏในฐานข้อมูลเดวิเลปขนาดเล็ก: ล็อกยาว, null ที่ไม่คาดคิด, ดัชนีหาย, หรือโค้ดทางผ่านที่ลืม\n\nก่อนอื่นตรวจว่าสคีมาในสเตจตรงตามแผนหลังมิเกรชัน: คอลัมน์ ชนิด ค่า default ข้อจำกัด และดัชนี ตรวจอย่างละเอียด หนึ่งดัชนีหายก็พอจะเปลี่ยน backfill ให้เป็นเคราะห์ร้าย\n\nแล้วรันวิเคราะห์มิเกรชันกับ dataset ที่สมจริง นั่นควรเป็นสำเนาล่าสุดของโปรดักชันที่มาสก์ข้อมูลสำคัญ หากทำไม่ได้ ให้แมตช์ปริมาณและจุดร้อนของโปรดักชัน (ตารางใหญ่ แถวกว้าง ตารางที่มีดัชนีเยอะ) บันทึกเวลาของแต่ละขั้นตอนเพื่อเตรียมคาดการณ์ในโปรดักชัน\n\nเช็คลิสต์สั้นสำหรับสเตจ:\n\n- สคีมาตรงตามแผน (คอลัมน์ ชนิด ข้อจำกัด ดัชนี)\n- บันทึกเวลาในข้อมูลที่สมจริง\n- ทดสอบความเข้ากันได้: แอปเก่ากับสคีมาใหม่ และแอปใหม่กับสคีมาเก่า (เมื่อแผนระบุว่าควรใช้งานได้)\n- รันคำสั่งตรวจสอบ: อัตรา null, นับแถว, ตรวจหา orphan สำหรับ FK ใหม่, ตัวอย่างการอ่าน\n- เฝ้าดูสัญญาณการปฏิบัติการระหว่างรัน: locks, deadlocks, timeouts, slow queries\n\nสุดท้าย ทดสอบฟลว์ผู้ใช้จริง ไม่ใช่แค่ SQL สร้าง แก้ไข และอ่านระเบียนที่เปลี่ยนแปลง หากใช้ expand/contract ยืนยันว่าทั้งสองสคีมาทำงานได้จนกว่าจะ cleanup เสร็จ\n\n## ตัวอย่างที่เป็นจริง: เปลี่ยนคอลัมน์โดยไม่ทำให้ผู้ใช้พัง\n\nสมมติคุณมีคอลัมน์ `users.name` เก็บชื่อเต็มอย่าง "Ada Lovelace" คุณต้องการ `first_name` และ `last_name` แต่ไม่สามารถทำให้การสมัคร การแสดงโปรไฟล์ หรือหน้าฝ่ายแอดมินพังขณะเปลี่ยนแปลง\n\nเริ่มด้วยขั้นตอน expand ที่ปลอดภัยแม้ไม่มีโค้ดใหม่ปล่อย: เพิ่มคอลัมน์ nullable เก็บของเก่าไว้ และหลีกเลี่ยงล็อกยาว\n\n```sql\nALTER TABLE users ADD COLUMN first_name text;\nALTER TABLE users ADD COLUMN last_name text;\n```\n\nจากนั้นอัปเดตพฤติกรรมแอปให้รองรับทั้งสองรูปแบบ ใน Release 1 แอปควรอ่านจากคอลัมน์ใหม่เมื่อมีค่า fallback ไปที่ `name` เมื่อเป็น null และเขียนทั้งสองที่เพื่อให้ข้อมูลใหม่สอดคล้อง\n\nต่อมาคือ backfill รันงานแบทช์ที่อัปเดตเป็นชิ้นเล็กๆ ต่อรอบ บันทึกความคืบหน้า และหยุดได้อย่างปลอดภัย ตัวอย่าง: อัปเดต users ที่ `first_name` เป็น null ตามลำดับ ID ทีละ 1,000 แถว และบันทึกจำนวนแถวที่เปลี่ยน\n\nก่อนเข้มงวด ให้ validate ในสเตจ:\n\n- สมัครใหม่เติม `first_name` และ `last_name` และยังตั้ง `name`\n- ผู้ใช้เดิมแสดงได้แม้มีแค่ `name`\n- Backfill หยุดและเริ่มใหม่ได้โดยไม่ทำงานซ้ำ\n- ไม่มี null ที่ไม่คาดคิดหลงเหลือหลัง backfill เสร็จ\n- คิวรีพื้นฐานบน `users` ไม่ช้าลงอย่างมีนัยสำคัญ\n\nRelease 2 สลับการอ่านไปคอลัมน์ใหม่เท่านั้น หลังจากนั้นค่อยเพิ่มข้อจำกัด (เช่น `SET NOT NULL`) และลบ `name` ในการปล่อยแยกครั้งถัดไป\n\nสำหรับ rollback ให้ทำให้ง่าย แอปยังอ่าน `name` ในการเปลี่ยนผ่าน และ backfill หยุดได้ หากต้องย้อน Release 2 ให้สลับการอ่านกลับไป `name` และทิ้งคอลัมน์ใหม่ไว้จนกว่าจะเสถียร\n\n## ขั้นตอนต่อไป: เปลี่ยนพรอมต์ของคุณให้เป็นนิสัยมิเกรชันที่ทำซ้ำได้\n\nปฏิบัติต่อการเปลี่ยนแต่ละครั้งเหมือน runbook เล็กๆ เป้าหมายไม่ใช่พรอมต์ที่สมบูรณ์แบบ แต่เป็นนิสัยที่บังคับรายละเอียดที่ถูกต้อง: สคีมา ข้อจำกัด แผนรัน และ rollback\n\nมาตรฐานสิ่งที่ต้องมีในทุกคำขอมิเกรชัน:\n\n- สคีมาปัจจุบันและการเปลี่ยนที่ชัดเจน (ตาราง คอลัมน์ ดัชนี)\n- ข้อจำกัดและข้อมูลทราฟฟิก (ขนาดตาราง อัตราเขียน downtime ที่อนุญาต)\n- ลำดับการปล่อย (expand, ปล่อยแอป, backfill, contract)\n- วิธีสังเกตความคืบหน้า (queries/metrics เวลาโดยประมาณ)\n- ขั้นตอน rollback (จะย้อนอะไรก่อน อะไรอาจคงเหลือเป็นข้อมูลที่ต้องกลับมา)\n\nกำหนดเจ้าของแต่ละขั้นก่อนจะรัน SQL ใครเป็นคนดูแลอะไรจะช่วยป้องกัน "ทุกคนคิดว่าอีกคนทำ": นักพัฒนารับผิดชอบพรอมต์และโค้ดมิเกรชัน, ops ควบคุมเวลาและการมอนิเตอร์ใน production, QA ยืนยันพฤติกรรมบนสเตจและขอบกรณี, และคนหนึ่งคนเป็นผู้ตัดสินใจ go/no-go\n\nถ้าคุณสร้างแอปผ่านแชท การร่างลำดับก่อนสร้าง SQL ช่วยได้ สำหรับทีมที่ใช้ Koder.ai, Planning Mode เป็นที่ที่เหมาะจะเขียนลำดับและ snapshot รวม rollback ช่วยลดความเสี่ยงหากเกิดสิ่งไม่คาดคิดระหว่าง rollout\n\nหลังปล่อย ให้กำหนดเวลา cleanup ของ contract ทันทีขณะที่บริบทยังสด เพื่อไม่ให้คอลัมน์เก่าและโค้ดความเข้ากันคงค้างเป็นเดือนคำถามที่พบบ่อย
แชร์
Koder.ai
Build your own app with Koder today!

The best way to understand the power of Koder is to see it for yourself.

Start FreeBook a Demo