ปัญหาที่เจอ
ทำไมการดูแลให้อาหารฟาร์มไก่สาวถึงต้องการระบบ?
ฟาร์มไก่สาวต้องให้อาหารตรงเวลาวันละ 3 มื้อทุกวัน — ถ้าคนงานลืม ไก่ไม่ได้กิน เจ้าของไม่รู้จนกว่าจะเข้าฟาร์ม ส่วนรายงาน "วันนี้ให้ไปกี่กระสอบ ตายกี่ตัว ป่วยกี่ตัว" จดบนกระดาษบ้าง LINE chat บ้าง สุดท้ายหาย รวมข้อมูลไม่ได้
เวลาให้อาหารต้องตรงเป๊ะ — แต่ลืมง่าย
ไก่สาวต้องกินตรงเวลา 06:00 / 10:00 / 16:00 ทุกวัน — ถ้าเลื่อนเป็นชั่วโมง production lay ตก ไก่เครียด คนงานจำเองยาก โดยเฉพาะวันหยุดหรือเพิ่งจ้างใหม่
รายงานกระจาย จดมือ-แชต-กระดาษ
"วันนี้ใช้กี่กระสอบ" "ไก่ตายโรงไหนกี่ตัว" — บางคนพิมพ์ในแชต บางคนจดสมุด พอจะรวมรายเดือนหาไม่เจอ เปรียบเทียบมื้อต่อมื้อไม่ได้
เจ้าของไม่รู้ realtime ว่าเกิดอะไรขึ้น
คนงานอาจยังไม่ได้ให้อาหารแต่บอกว่าให้แล้ว — หรือมื้อนี้กินไม่หมดแต่ไม่ได้แจ้ง เจ้าของรู้ตอนเข้าฟาร์มหรือพรุ่งนี้ ซึ่งสายแล้ว
คนงานไม่อยากใช้แอปใหม่
คนงานฟาร์มคุ้น LINE มาก แต่ไม่อยากโหลดแอปเฉพาะทาง โหลดเสร็จลืม password ลืมว่าใช้ยังไง — UX ต้องอยู่ในที่ที่เขาใช้อยู่แล้ว
เจ้าของอยากดูข้อมูลแบบสเปรดชีต ไม่ใช่ dashboard ลึกๆ
เจ้าของฟาร์มต้องการดูข้อมูลดิบ แก้เองได้ ส่งให้บัญชี/สัตวแพทย์ได้ทันที — ไม่ต้องการ admin panel ที่ซับซ้อน
วิธีแก้ปัญหา
เอาบอทเข้ากลุ่ม LINE ที่คนงานอยู่อยู่แล้ว — เตือนตามเวลา กรอกผ่านฟอร์ม เก็บใน Sheet
บอทเตือนเข้ากลุ่ม LINE ทุกมื้อ
เพิ่มบอท "ลูกเจี๊ยบ" เข้ากลุ่มฟาร์มที่คนงานอยู่อยู่แล้ว — 05:45 ส่ง bubble พร้อมจำนวนกระสอบที่เจ้าของวางแผน 08:00 ส่ง bubble ให้กรอกรายงาน ครบ 3 มื้อ/วัน
กรอกฟอร์มใน LINE ตรงๆ — ไม่ต้องโหลดแอป
ใช้ LIFF (LINE Front-end Framework) — กดปุ่มใน bubble แล้วเปิดฟอร์มในแอป LINE เลย ไม่ต้องสมัคร ไม่ต้อง login ไม่ต้องโหลดอะไรเพิ่ม
Google Sheet เป็น source of truth
ทุกแผน ทุกรายงาน ทุก log ถูก append ลง Google Sheet — เจ้าของเปิดดูเองได้ แก้ filter sort export เป็น Excel ก็ได้ ไม่ต้องเรียนรู้ระบบใหม่
Confirmation dialog กันกรอกผิด
ก่อน submit ทุกฟอร์ม → modal สรุปข้อมูลทั้งหมด (6 ค่า + วันที่ + รวม) ให้กดยืนยันอีกครั้ง — เพราะคนงานกรอกบนมือถือพลาดง่าย แก้ทีหลังใน Sheet ก็ลำบาก
เมนูเรียกเฉพาะคำว่า "เมนูหลัก"
บอทอยู่ในกลุ่มที่คนงานคุยกันปกติ — ถ้าตอบทุกข้อความจะรบกวน ใช้ keyword "เมนูหลัก" เป็น trigger เดียว ทำให้บอทเงียบเป็นธรรมชาติเหมือนสมาชิกในกลุ่ม
User Flow
1 วันของลูกเจี๊ยบ — Owner วางแผนตอนกลางคืน บอททำงานเองตลอดวัน
Owner วางแผน
กลางคืน Owner กรอก 3 มื้อ × 2 โรง สำหรับวันรุ่งขึ้น
Bot เตือนคนงาน
05:45 ส่ง bubble จำนวนกระสอบ พร้อมปุ่ม "เริ่มให้อาหาร"
คนงานกรอกรายงาน
08:00 bot ส่ง bubble กรอก → คนงานกด → กรอก 6 ช่อง
เก็บใน Sheet
ข้อมูลเข้า Sheet ทันที + คำนวณ duration/delay อัตโนมัติ
Tech Stack & Architecture
Stack ที่เลือกเพื่อให้คนเดียวดูแลได้ทั้งระบบ — ไม่มี DB ที่ต้องบริหาร ไม่มี admin UI ที่ต้องสร้าง
LINE LIFF ทำให้ฟอร์มเปิดในแอป LINE เลย — ไม่ต้องโหลดแอป ไม่ต้อง login เพิ่ม · Google Sheets API เป็น database ที่ Owner เปิดดูเองได้แบบ native — ไม่ต้องสร้าง admin UI แยก · Vercel Hobby ฟรี + auto deploy จาก git push · cron-job.org ฟรี ยิงทุก 1 นาที (Vercel Hobby cron จำกัด 2 jobs/day ไม่พอ) — endpoint ตรวจเวลาเอง ครบ 6 trigger times/day
สิ่งที่สร้าง — 8 ฟีเจอร์หลัก
ครบ loop ตั้งแต่วางแผนถึงเก็บข้อมูล
กำหนดอาหาร 3 มื้อ (Owner)
Grid table 3 มื้อ × 2 โรง — เห็นพร้อมกันใน 1 viewport พร้อมรวมยอด + confirm dialog ก่อน save 6 rows
กรอกรายงาน (คนงาน)
6 ช่อง (กระสอบ/ตาย/ป่วย × 2 โรง) + note — คำนวณ duration/delay เทียบกับเวลา target อัตโนมัติ
บันทึกการผสมอาหาร
สูตร + จำนวนที่ผสมได้ + หมายเหตุ — เก็บ log แยก tab เพื่อ track stock
ดูรายงาน (Owner)
การ์ดเปิด Google Sheet ตรงๆ — Owner ดูข้อมูลดิบ filter sort export ได้ทันที
Carousel Menu
Flex carousel 4 cards เรียงตามมุมมอง Owner-first (กำหนด → ผสม → ดูรายงาน → กรอก) — trigger ด้วยคำว่า "เมนูหลัก"
Instruction & Report Bubble
Flex bubble 2 ชนิด — instruction (พร้อมจำนวนกระสอบ + ปุ่มเริ่ม) และ report reminder (ปุ่มเปิด LIFF กรอก)
Scheduler + Dedup
endpoint ตรวจเวลา Bangkok ทุกนาที ยิง bubble ตาม schedule + ใช้ reminder_log กัน double-send
Group Chat Support
บอทเข้ากลุ่ม LINE ได้ — register groupId อัตโนมัติตอน join + push ไป group แทน loop users
หน้าตาในกลุ่ม LINE
ตัวอย่าง flow ตอนเช้า — bot ส่ง instruction → คนงานกดเริ่ม
ใกล้เวลาให้อาหารมื้อเช้า
กดปุ่ม "เริ่มให้อาหาร" >
บันทึกเวลาเริ่มมื้อเช้าแล้ว — เริ่มให้อาหารได้เลยครับ
เมื่อให้เสร็จ กดปุ่ม "กรอกรายงาน" ใน bubble ที่จะส่งมาให้
ถึงเวลาบันทึกรายงานมื้อเช้า
กรอกจำนวนอาหารจริงและไก่ตาย/ป่วยของแต่ละโรง
หน้าตาฟอร์ม LIFF
กำหนดอาหาร 3 มื้อ ในหน้าจอเดียว (LIFF Tall size — viewport จำกัด)
🐥 ลูกเจี๊ยบ
| มื้อ | โรง 1 | โรง 2 |
|---|---|---|
| เช้า | 3.5 | 3.0 |
| กลางวัน | 2.5 | 2.0 |
| เย็น | 3.0 | 2.5 |
Hack กับปัญหา
6 โจทย์ที่ต้องคิดทางแก้เอง — design constraint + LINE platform limit + serverless quirk
LIFF Tall size — 6 fields ใน 1 viewport
เลือก LIFF size = Tall (~675px ใช้งานได้) แต่ Owner ต้องกรอก 3 มื้อ × 2 โรง = 6 ช่อง พร้อมกัน ถ้า scroll เยอะ keyboard ขึ้นบัง row ล่าง
Bot ในกลุ่ม — ตอบทุกข้อความ = รบกวน
บอทอยู่ในกลุ่มที่คนงานคุยกันปกติ — ถ้าตอบทุก text message (คำสั่ง "สวัสดี" "เมื่อไหร่" ฯลฯ) จะกลายเป็น spam ทันที
event.message.text.trim() === "เมนูหลัก" เป็น trigger เดียว ข้อความอื่น bot เงียบ 100% ผลคือบอทเงียบเป็นธรรมชาติเหมือนสมาชิกในกลุ่ม แค่เรียกตอนจะใช้Push ไป group ไม่ใช่ loop users
คนงานในกลุ่มไม่ได้ add bot 1-on-1 → LINE block การ pushMessage หา userId ตรงๆ → scheduler ส่ง bubble ให้ทุกคนไม่ได้
join event บันทึก groupId ลง sheet tab groups → scheduler push ไป groupId (ส่งครั้งเดียว ทุกคนในกลุ่มเห็น) ใน postback ยังจับ userId ของคนกดได้ปกติ — ได้ทั้ง broadcast efficiency + member identificationTimestamp อ่านยาก ใน Sheet
ครั้งแรกเก็บเป็น ISO UTC (2026-05-24T06:55:38.824Z) — Owner เปิด Sheet อ่านไม่รู้เรื่อง ต้องคำนวณ +7 ทุกครั้ง
formatBangkokTimestamp() ใช้ Intl.DateTimeFormat("sv-SE", { timeZone: "Asia/Bangkok" }) ให้ format YYYY-MM-DD HH:mm:ss ตรงตามเวลาไทยที่ Owner เข้าใจทันที + parseBangkokTimestamp() สำหรับคำนวณ duration/delay กลับเป็น Date + migration script update ข้อมูลเก่าให้เป็น format ใหม่ (idempotent)Vercel Hobby cron จำกัด 2 jobs/day
ต้องการ trigger 6 ครั้ง/วัน (5:45 / 8:00 / 9:45 / 11:00 / 15:45 / 18:00) — Vercel Hobby plan ให้แค่ 2 cron jobs/day ไม่พอ
bangkokNow().time) → ใช้ cron-job.org (ฟรี ยิงทุก 1 นาทีได้) ยิง 1,440 ครั้ง/วัน → endpoint ตอบ due=0 เฉพาะตอนไม่ตรงเวลา (95% ของเวลา) — ไม่เปลือง LINE quota เลย รองรับการเพิ่ม schedule ในอนาคตได้โดยไม่ต้องแก้ cron configNext.js 16 Turbopack + bun ทำเครื่องค้าง
ตอน dev — bun dev (Turbopack default) + ngrok + traffic เข้า → MacBook ค้าง kernel panic ต้อง force reboot 2 ครั้งติด
next dev --webpack (Next.js 16 ยัง support) — RSS 2.3GB ใช้งานได้ stable + เก็บ Turbopack ไว้ใน script สำรอง dev:turbo สำหรับลองใหม่ตอน upgrade Next.js version ภายหลัง บทเรียน: tech stack ใหม่ๆ ต้องมี fallback path เสมอDesign Decision ที่ต้องคุยกับลูกค้า
UX trade-off ที่ไม่ได้อยู่ใน playbook — ต้อง explain + decide ร่วมกัน
ในการทำ MVP ทุกตัว trade-off จะเยอะ — ส่ง message ทุกข้อความหรือเฉพาะ keyword? Native date picker หรือ custom? Owner mark group manually หรือ auto-detect? คำตอบที่ "ถูกต้อง" มีหลายแบบ ต้องวางทางเลือกให้ลูกค้าเห็น แล้ว explain trade-off ของแต่ละทาง ไม่ใช่เลือกแทนลูกค้า
Confirm Dialog
Reusable component ใช้ครบทั้ง 3 ฟอร์ม — สรุปข้อมูลก่อน save
Keyword Trigger
"เมนูหลัก" เท่านั้น — เงียบในกลุ่ม ไม่รบกวน
Tomorrow Prefill
Date default = today+1 เพราะ Owner วางแผนกลางคืน
Sheet Card
"ดูรายงาน" = เปิด Google Sheet ตรง ไม่สร้าง dashboard
เราได้อะไรจากโปรเจกต์นี้
5 บทเรียนจากการทำลูกเจี๊ยบ ตั้งแต่ requirement ถึง production
คนงานฟาร์มใช้ LINE อยู่แล้ว เลือก LIFF แทนสร้าง mobile app แยก = ไม่มี friction ในการ adopt — ไม่ต้องโหลดอะไร ไม่ต้องสมัคร ไม่ต้องเรียนรู้ UI ใหม่ บทเรียน: เลือก platform ที่ user คุ้นเคย สำคัญกว่าเลือก stack ที่ developer คุ้นเคย
Google Sheets เป็น "database ที่ Owner เปิดดูเองได้ filter export ส่งให้คนอื่นได้" — สำหรับ MVP ที่มี traffic ต่ำ + Owner เป็น power user spreadsheet อยู่แล้ว Sheets ดีกว่า PostgreSQL ทุกทาง (no admin UI ต้องสร้าง, no migration ต้องคิด, no hosting ต้องจ่าย) บทเรียน: เลือก storage ตาม Owner ไม่ใช่ตาม convention
ฟอร์มที่ส่ง 6 rows ทีเดียวลง Sheet → ถ้ากรอกผิดต้องไปแก้ใน Sheet เอง (ลำบาก) ทุกฟอร์มของลูกเจี๊ยบมี ConfirmDialog ที่สรุปทุกค่าก่อน save — เพิ่มเวลากรอก 2 วินาที แต่ลด error rate ลงเยอะ บทเรียน: friction ที่ใส่ในที่ถูกที่ = feature ไม่ใช่ bug
LIFF Tall size จำกัด viewport → บังคับให้ออกแบบ Grid 3×2 แทน 6 stacked inputs → ผลคือ overview ดีกว่ามาก ถ้ามี space เยอะอาจจะ default ไปทำ stacked layout ที่ scroll ยาว บทเรียน: constraint คือ design partner ไม่ใช่ obstacle
ตลอด session: เปลี่ยน ISO timestamp → Bangkok format (พร้อม migration), เปลี่ยน Turbopack → webpack หลังเครื่องค้าง, เปลี่ยน menu trigger จาก always-respond → keyword, เพิ่ม group support หลัง MVP — ทุกการเปลี่ยน document + commit เป็น checkpoint บทเรียน: ทำเร็ว ลอง iterate เร็ว ดีกว่าวางแผนนาน