ตั้งใน Vercel → Project → Settings → Environment Variables (สคริปต์ scripts/setup-deploy.sh ช่วยกรอกครั้งแรก) ตัวแปร NEXT_PUBLIC_* ถูกฝังตอน build — เปลี่ยนแล้วต้อง redeploy
ค่าของ production อยู่ที่ Vercel ที่เดียวเท่านั้น — ไฟล์ .env ในเครื่องไม่ถูกส่งขึ้นไปกับ deploy อีกแล้ว (ตั้งแต่ 2026-09-18) · deploy ที่สั่งจาก terminal (vercel deploy) อัปโหลดทั้งโฟลเดอร์และ ไม่สน .gitignore ไฟล์ .env จึงเคยขึ้นไปและ build อ่านมันจริง ทำให้ key ระดับ service role กับ DATABASE_URL ไปนั่งอยู่ในไฟล์ต้นฉบับของ deployment โดยไม่มีใครต้องใช้ (deploy ที่เกิดจาก git push ไม่เคยมีปัญหานี้ เพราะไฟล์ไม่ได้อยู่ใน repo) · ถ้าจะเพิ่มตัวแปรใหม่ ให้เพิ่มที่ Vercel แล้ว redeploy — ใส่ในไฟล์ในเครื่องอย่างเดียวจะไม่มีผลกับ production เลย
ตรวจว่า Vercel มีครบไหมก่อน deploy: npx tsx scripts/check-deploy-env.ts (อ่านแค่ ชื่อ ตัวแปร ไม่อ่านค่า) — บอกว่าตัวไหนที่โค้ดอ่านแต่ Vercel ไม่มี
| ตัวแปร | ใช้ทำอะไร | เปลี่ยนแล้วเกิดอะไร |
|---|---|---|
DATABASE_URL | Postgres (Supabase transaction pooler พอร์ต 6543) | ผิด = ทั้งแอปล่ม |
NEXT_PUBLIC_SUPABASE_URL / NEXT_PUBLIC_SUPABASE_ANON_KEY | Supabase Auth ฝั่งเบราว์เซอร์/เซิร์ฟเวอร์ | ไม่มี = หน้า login ขึ้น “โหมดพัฒนา” |
SUPABASE_SERVICE_ROLE_KEY | สร้าง/ลบบัญชี เชิญ ลิงก์รีเซ็ต (หน้าทีม/ผู้ใช้) | ไม่มี = จัดการบัญชีไม่ได้ |
APP_SECRET | เข้ารหัส Thunder key ของทุกร้านและของแพลตฟอร์ม, ค่า LINE OA (token/secret), ลิงก์ใบจองที่ผูกกับ LINE และคุกกี้ state ของ LINE Login (หน้า “ตั้งค่าแพลตฟอร์ม”) | เปลี่ยนแล้ว key ทุกตัวอ่านไม่ได้ ต้องวาง key ใหม่ทั้งของร้าน (ผู้ดูแลระบบวางให้) ของแพลตฟอร์ม และค่า LINE (ตั้งค่า LINE) · ใช้เป็น salt ของ ip hash ใน feedback คู่มือด้วย |
THUNDER_BASE_URL | ปลายทาง API ตรวจสลิป | ปกติไม่ต้องแก้ · key ไม่ได้อยู่ใน env — key ร้านอยู่ในฐานข้อมูลต่อร้าน, key แพลตฟอร์มตั้งที่ “ตั้งค่าแพลตฟอร์ม” |
SLIP_VERIFIER | fake เฉพาะ dev เพื่อจำลองผลตรวจ | ห้ามตั้งใน production |
NEXT_PUBLIC_VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY / VAPID_SUBJECT | แจ้งเตือนเด้ง (Web Push) ของทีมงาน | ไม่ตั้ง = ซ่อนชิป “แจ้งเตือนเด้ง” ทั้งระบบ (ส่วนอื่นทำงานปกติ) · สร้างคู่กุญแจด้วย npx web-push generate-vapid-keys |
NEXT_PUBLIC_TURNSTILE_SITE_KEY | ช่องยืนยัน “ไม่ใช่บอท” (Cloudflare Turnstile) ที่ /signup /login /ลืมรหัสผ่าน | ไม่ตั้ง = ไม่แสดงช่องยืนยัน · ฝังตอน build ตั้งแล้วต้อง redeploy ก่อนไปเปิด Attack Protection ใน Supabase · Secret key อยู่ที่ Supabase ไม่ใช่ที่นี่ |
RATE_LIMIT_FAIL_OPEN | ตั้ง 1 เพื่อให้ตัวจำกัดอัตราปล่อยผ่านทุกคำขอเมื่อฐานข้อมูลมีปัญหา | ใช้เฉพาะตอนเกิดเหตุ แล้วเอาออก — ปกติไม่ต้องตั้ง |
CRON_SECRET | ป้องกัน /api/cron/* (10 งาน) | ต้องตรงกับที่ Vercel Cron ส่ง (Vercel ตั้งให้อัตโนมัติเมื่อมีตัวแปรนี้) |
NEXT_PUBLIC_APP_URL | สร้างลิงก์ใบจอง ลิงก์ในอีเมล QR เช็คอิน sitemap ลิงก์ในข้อความ LINE และ Webhook/Callback URL ของ LINE · ปัจจุบัน https://tablezups.com | เปลี่ยนโดเมนไม่ใช่แก้ตัวแปรตัวเดียว — ดูลำดับครบใน ADR-0033: redeploy + เพิ่มโฮสต์ใน Cloudflare Turnstile (ไม่งั้นล็อกอินไม่ได้ทั้งระบบ) + Redirect URL ใน Supabase + URL ใน LINE Developers + ตัด APK ใหม่ให้เครื่องแคชเชียร์ (โดเมนถูกฝังตอน build และ 301 ใช้กับ POST ไม่ได้) |
NEXT_PUBLIC_SUPPORT_LINE / NEXT_PUBLIC_SUPPORT_EMAIL | ปุ่ม “ติดต่อผู้ดูแลระบบ” ในคู่มือ (/help) และหน้าแรก | ไม่ตั้ง = ไม่แสดงปุ่ม · ตั้งแล้วต้อง redeploy |
EXPERIMENTAL_BANK_ACCOUNT_QR | 1 เพื่อเปิด “QR แบบเลขบัญชี (ทดลอง)” ในตั้งค่าร้าน | ปกติไม่ตั้ง (แอปธนาคารส่วนใหญ่สแกนไม่ได้) |
DEV_AUTH_USER_ID / DEV_AUTH_EMAIL | จำลองผู้ใช้ตอน dev โดยไม่มี Supabase | ไม่มีผลใน production |
สคริปต์ที่เกี่ยวข้อง
bash scripts/setup-deploy.sh— wizard 11 ขั้น (Supabase → migrate/buckets → Thunder → Vercel → seed → smoke test)npx tsx scripts/check-deploy-env.ts— เทียบชื่อตัวแปรที่โค้ดอ่าน กับที่ Vercel มีใน Production (รันก่อน deploy ทุกครั้งที่เพิ่ม/ย้ายตัวแปร)npx tsx scripts/grant-admin.ts <email>— ตั้ง platform admin คนแรกnpm run db:migrate— apply migration หลังอัปเดตโค้ดnpx tsx --env-file=.env.production.local scripts/reset-venue-data.ts— ล้างประวัติการจอง/ลูกค้าของร้าน: ไม่ใส่ slug = แสดงรายการร้านทั้งหมดจากฐานข้อมูล (หมายเลข · slug · ชื่อ · สถานะ · แพ็กเกจ · จำนวนการจอง) ให้เลือกหมายเลข (a= ทุกร้าน, Enter = ยกเลิก) · ใส่<slug> [<slug> …]= ดูตัวอย่างจำนวนของร้านนั้น เพิ่ม--yesเพื่อลบ · ลบ (การจอง สลิป+รูป รอคิว บันทึกลูกค้า เบอร์ที่บล็อก สถิติเบอร์ คิว LINE ยอดสแกนแบนเนอร์ บันทึกกิจกรรมของการจอง/ลูกค้า) โดยคง การตั้งค่า ผัง โลโก้ แกลเลอรี ปฏิทินจอง ทีม แพ็กเกจ เครดิต ประวัติชำระค่าบริการ และแชท · ก่อนลบทุกร้านต้องพิมพ์ slug ยืนยันทีละร้าน (มี preview ให้ดูก่อนเสมอ) · ลงบันทึกกิจกรรมของร้านเป็น “ล้างประวัติการจอง/ลูกค้าของร้าน (ผู้ดูแลระบบ)” · ใช้หลังทดสอบร้านจริงเสร็จ รันตอนไม่มีลูกค้ากำลังจองnpx tsx --env-file=.env.production.local scripts/copy-venue-settings.ts <ต้นทาง> <ปลายทาง> [--yes]— คัดลอกการตั้งค่าจากร้านหนึ่งไปอีกร้าน (ตั้งร้านใหม่ให้เหมือนร้านเดิม): ไม่ใส่ slug = แสดงรายการร้าน (หมายเลข · slug · ชื่อ · สถานะ · แพ็กเกจ · จำนวนโต๊ะ · จำนวนหมวดเมนู) ให้เลือกต้นทางแล้วปลายทาง · ใส่ 2 slug = ดูตัวอย่างค่าที่จะเปลี่ยน (เลขบัญชี/พร้อมเพย์แสดงแค่ 4 ตัวท้าย) เพิ่ม--yesเพื่อคัดลอก · คัดลอก 6 ส่วน: ค่าตั้งค่าร้าน (เวลาเปิด-ปิด/ช่วงบริการ/มัดจำ/กันโต๊ะ/บล็อกไม่มา/ติดต่อ/โซเชียล/ข้อความโปรโมต/ข้อมูลโซน/ตั้งค่า POS ใบเสร็จและภาษี) · บัญชีรับเงิน · รูป (ผัง โลโก้ แกลเลอรี รูปเมนู — สำเนาในถังของร้านปลายทาง ไม่ใช้ไฟล์ร่วมกัน) · โต๊ะ (จับคู่ตามรหัสโต๊ะ: รหัสเดิมแก้ทับ รหัสใหม่เพิ่ม โต๊ะที่ต้นทางไม่มีถูกปิดใช้งาน ไม่ลบ) · จุดพิมพ์ (จับคู่ตามชื่อ+ชนิด รวมที่อยู่เครื่องพิมพ์) · เมนูทั้งต้น (ถ้าปลายทางมีเมนูอยู่แล้ว สคริปต์ถามว่าจะลบเมนูเดิมแล้วคัดลอกแทนไหม;--replace-menu= ตอบตกลงล่วงหน้า บิลเก่าไม่กระทบ) — ข้ามส่วนไหนใส่--skip-settings/--skip-bank/--skip-images/--skip-tables/--skip-printers/--skip-menu· ไม่แตะ slug ชื่อร้าน สถานะ แพ็กเกจ/เครดิต key ตรวจสลิป (Super Admin วางให้ต่อร้าน) ทีมงาน เครื่องแคชเชียร์ ปฏิทินจอง การจอง บิล · ถ้าบัญชีรับเงินของปลายทางเปลี่ยน ระบบตั้งสถานะ “ต้องลงทะเบียนกับผู้ให้บริการตรวจสลิปใหม่” ให้ (กดในหน้าตั้งค่า) · ก่อนคัดลอกต้องพิมพ์ slug ปลายทางยืนยัน (มี preview + คำเตือนให้อ่านก่อนเสมอ) · ลงบันทึกกิจกรรมของร้านปลายทางเป็น “คัดลอกการตั้งค่ามาจากร้านอื่น (ผู้ดูแลระบบ)” พร้อมค่าก่อน/หลัง · หลังคัดลอก เปิดหน้าตั้งค่าของร้านปลายทางตรวจอีกครั้ง และจับคู่เครื่องแคชเชียร์/เครื่องพิมพ์ถ้าใช้ POS