Skip to main content

เครื่องมือ Migration / Seed / Dump

ภาพรวม

Repo database-2026 ไม่ได้ทำหน้าที่เพียงเก็บ schema แต่เป็น ชุดเครื่องมือจัดการวงจรชีวิตของฐานข้อมูล ทั้งการสร้าง migration, การ seed ข้อมูลตั้งต้น, การสร้างคอมเมนต์ประกอบคอลัมน์ และการเก็บ snapshot โครงสร้างจริงจากเซิร์ฟเวอร์

สิ่งที่ต้องเข้าใจก่อนแก้ไขอะไรก็ตามคือ schema ถูกจัดการผ่านสามช่องทางที่ปะปนกันอยู่

  1. Prisma (prisma/schema.prisma และ prisma/migrations/) ครอบคลุมเฉพาะ schema public และเฉพาะบางตารางเท่านั้น
  2. Manual SQL (manual-sql/) สำหรับตาราง คอลัมน์ และ trigger ที่ Prisma ไม่รู้จัก ต้อง apply ด้วย psql เอง
  3. App migrations (apps/<ชื่อแอป>/migrations/) สำหรับ schema แยกอย่าง appointment, bulletin และ loyalty ซึ่ง Prisma ไม่แตะเลย

โครงสร้างข้อมูลหลัก

คำสั่งใน package.json

Scriptคำสั่งจริงใช้ทำอะไร
npm run initprisma migrate reset แล้วตามด้วย up --file=initสร้าง schema ครั้งแรก
npm run statusprisma migrate statusตรวจว่ามี migration ใดยังไม่ถูก apply
npm run applyprisma migrate deployapply migration ขึ้นฐานข้อมูล
npm run up --file=<ชื่อไฟล์>migrate diff เขียนไฟล์ down แล้วตามด้วย migrate dev --create-onlyสร้างคู่ไฟล์ up และ down
npm run down --file=<ชื่อไฟล์>prisma db execute กับไฟล์ใน prisma/down/ย้อน migration
npx ts-node seed.tsอ่านไฟล์ตามตัวแปร $FILE_SEED ใน seed-data/seed ทีละไฟล์
npx ts-node seed-all.tsไล่ทุกไฟล์ใน seed-data/seed ทั้งชุด

กลไกของ seed.ts และ seed-all.ts เรียบง่ายมาก คืออ่านไฟล์ SQL แล้วแยกคำสั่งด้วย split(';') ก่อนส่งเข้า $executeRawUnsafe ทีละคำสั่ง ข้อจำกัดที่ตามมาคือไฟล์ seed จะมีเครื่องหมาย ; อยู่ภายในสตริงไม่ได้

ลำดับการ seed

ลำดับมีความสำคัญเพราะมี FK ระหว่างตาราง ไฟล์ seed-data/01 ถึง 16 เรียงตามลำดับดังนี้

system_modulesystem_rolesystem_role_moduleorganizationuserline_oaline_useraudiencerich_menupassword_historyrich_messagecampaignapi_clientapi_keytracking_line_usersform_builder_rule

src/generate-comment.ts

เป็น custom Prisma generator ที่แปลงคอมเมนต์แบบ /// ใน schema ให้กลายเป็นคำสั่ง COMMENT แล้วสร้างออกมาเป็น migration ให้อัตโนมัติ ใช้ lock file ร่วมกับ sha256 เพื่อตรวจว่าคอมเมนต์ เปลี่ยนแปลงหรือไม่ เครื่องมือนี้เป็น workaround ของ Prisma issue #8703 โดยต้อง apply เองเสมอ และมีข้อจำกัดกับชื่อฟิลด์ที่ไม่ได้อยู่ในรูปแบบ snake case

schema-dumps/2026-07-24/

Snapshot โครงสร้างของ preprod ที่ได้จาก pg_dump --schema-only บน PostgreSQL 17.9

  • schema.sql เก็บโครงสร้างเต็ม
  • triggers-summary.txt สรุปหนึ่งบรรทัดต่อหนึ่ง trigger
  • notify-functions.txt รวมทุกฟังก์ชันที่เรียก pg_notify

Dump ชุดนี้ครอบคลุมเฉพาะ schema public และ appointment ณ วันที่ทำ ยังไม่รวม bulletin และ loyalty

เครื่องมือตรวจ drift

prisma-example-script/check-diff-schema-db.txt เก็บตัวอย่างคำสั่ง prisma migrate diff สำหรับเทียบ schema.prisma กับฐานข้อมูลจริงในแต่ละสภาพแวดล้อม (local, UAT, production) นี่คือเครื่องมือหลักในการหา drift ที่เกิดจากการ apply manual SQL

ส่วน prisma/ERD.md เป็น ERD แบบ mermaid ที่ ล้าสมัยแล้ว ยังใช้ชื่ออย่าง Organize และมี Pdpa กับ AudienceMember ที่ไม่มีอยู่ในสคีมาปัจจุบัน จึงควรยึด schema.prisma เป็นหลัก

ไฟล์ที่เกี่ยวข้อง

  • package.json, seed.ts, seed-all.ts, README.md (คู่มือฉบับภาษาไทย)
  • src/generate-comment.ts, src/dist/generate-comment.js
  • prisma/schema.prisma, prisma/migrations/, prisma/ERD.md
  • manual-sql/0.select.sql ถึง manual-sql/9.import_mapping.sql
  • apps/{appointment,bulletin,loyalty}/migrations/
  • schema-dumps/2026-07-24/, prisma-example-script/check-diff-schema-db.txt
  • .env.example — ตัวแปร DATABASE_URL และ DATABASE_NAME โดยตัวอย่างในไฟล์ยังเขียนเป็น mysql แต่ระบบจริงใช้ postgresql
  • .gitignore — ระบุให้ ignore prisma/migrations และ prisma/down ดังนั้น migration ที่ถูก commit ไว้จึงมาจากการ force add เฉพาะบางไฟล์

จุดเชื่อมต่อกับ Service อื่น

  • ทุก service ใช้ schema ที่ repo นี้กำหนด แต่ ไม่มี service ใดใช้ Prisma ตอน runtime โดย cms-api-go และ client-api-go ใช้ raw SQL ร่วมกับ sqlx หรือ GORM ส่วน worker-go และ webhook-go ก็ใช้แนวทางเดียวกัน ผลที่ตามมาคือการเปลี่ยนชื่อคอลัมน์จะไม่ถูกจับได้ตอน compile ต้องไล่แก้ query ในแต่ละ service เอง
  • ข้อควรระวัง: prisma migrate ไม่รู้จัก manual SQL และ app schema การรัน prisma migrate reset จะล้างเฉพาะ public และทำให้ trigger ทั้งหมดหายไป จึงต้อง apply ไฟล์ใน manual-sql/ ใหม่ทุกครั้ง (README มีหัวข้อ "วิธี Reinit" อธิบายไว้)