เป๋าตังค์ 💚
เว็บแอป (PWA) บันทึกรายรับ–รายจ่าย ติดตั้งบนหน้าจอมือถือได้ โยนสลิปโอนเงินเข้าไปแล้วแอปจะอ่าน QR บนสลิป (ธนาคาร + เลขอ้างอิง) กันบันทึกซ้ำ และเก็บรูปสลิปไว้ใน Google Drive
- โค้ด: GitHub → deploy อัตโนมัติขึ้น Vercel ทุกครั้งที่ push
- ข้อมูลรายการ: Google Sheets (เปิดดู/แก้เองได้)
- รูปสลิป: โฟลเดอร์ใน Google Drive (ผ่าน Google Apps Script ไม่ต้องใช้ Google Cloud)
- ล็อกอิน: PIN (ใช้คนเดียว)
ฟีเจอร์
- 📎 สลิป — เลือกได้หลายรูปพร้อมกัน แอปอ่าน QR (ธนาคาร + เลขอ้างอิง กันบันทึกซ้ำ) และถ้าเปิด AI จะอ่าน ยอดเงิน วันที่ ชื่อผู้รับ และเดาหมวด ให้อัตโนมัติ
- + จดรายการ — จดรายรับ/รายจ่ายที่ไม่มีสลิป
- ดูตามวัน — แถบเลือกวันใต้การ์ด (มีจุดสีประจำวัน + แถบบอกยอดจ่าย), หัวข้อแต่ละวันบอกวันในสัปดาห์ และทุกรายการแสดงเวลาที่บันทึก
- ปฏิทินรายจ่าย — ในหน้าสรุป สีชมพูเข้มตามยอดจ่ายของแต่ละวัน แตะวันเพื่อดูรายการวันนั้น
- ธีมหวาน ๆ — พาสเทลชมพู–ลาเวนเดอร์, กระจกใส, แอนิเมชัน, น้องหมูมาสคอต, หัวใจลอยตอนบันทึก, รองรับโหมดมืด
- เปิดเร็ว — จำข้อมูลล่าสุดไว้ในเครื่อง เปิดแอปเห็นทันทีแล้วค่อยซิงค์
- แก้ไข / ลบ — แตะรายการ → ✏️ แก้ไข (เปลี่ยนสลิปได้) หรือ ลบ
- ค้นหาและตัวกรอง — ค้นหาทุกเดือน, กรองตามประเภท หมวด บัญชี
- บัญชี/กระเป๋า — เช่น เงินสด, กสิกร, SCB — เลือกให้อัตโนมัติจากธนาคารในสลิป
- 📊 สรุป — กราฟวงกลมตามหมวด, กราฟแท่ง 6 เดือน, ยอดแต่ละบัญชี
- วงเงินใช้จ่ายต่อเดือน — แถบบนหน้าหลัก บอกยอดที่เหลือและ "ใช้ได้อีกวันละกี่บาท" เตือนเมื่อถึง 80%
- งบประมาณรายหมวด — แถบความคืบหน้า และเตือนเมื่อใช้ถึง 80%
- รายการประจำ — ค่าเช่า/เงินเดือน ลงให้อัตโนมัติทุกเดือน
- ⚙️ ตั้งค่า — แก้หมวดหมู่ (ใส่อีโมจิหน้าชื่อได้ เช่น “☕ กาแฟ”), บัญชี, งบ, รายการประจำ
- สรุปทางอีเมล ทุกวันอาทิตย์ 19:00 พร้อมแนบ PDF สรุป (รหัสผ่านเปิดไฟล์ =
APP_PIN)
- สรุป PDF ดาวน์โหลดในแอป (ตั้งค่า → สรุป PDF) เลือกช่วงวันที่ได้ — ไฟล์ใส่รหัสผ่านเป็น PIN เดียวกับที่ใช้เข้าแอป
- Android: กด "แชร์" รูปสลิปจากแอปธนาคาร → เลือก เป๋าตังค์ ได้เลย (หลายรูปก็ได้)
ตั้งค่าครั้งแรก (ไม่ต้องใช้ Google Cloud)
1. Google Sheet + Apps Script
- สร้าง Google Sheet ใหม่ ตั้งชื่อเช่น
เป๋าตังค์
- เมนู ส่วนขยาย → Apps Script → ลบโค้ดเดิม แล้ววางโค้ดจากไฟล์
apps-script/Code.gs
- แก้บรรทัด
const SECRET = '...' เป็นข้อความสุ่มยาว ๆ แล้วกดบันทึก 💾
- ทำให้ใช้งานได้ (Deploy) → การทำให้ใช้งานได้รายการใหม่ → ⚙️ เลือก เว็บแอป
- ดำเนินการในฐานะ: ฉัน
- ผู้มีสิทธิ์เข้าถึง: ทุกคน
- กดอนุญาตสิทธิ์ ถ้าขึ้น "Google hasn't verified this app" ให้กด Advanced → Go to … (unsafe) → Allow (เป็นสคริปต์ของคุณเอง)
- คัดลอก URL ของเว็บแอป (ลงท้ายด้วย
/exec)
แท็บ รายการ และโฟลเดอร์ เป๋าตังค์ - สลิป ใน Drive จะถูกสร้างให้อัตโนมัติตอนใช้งานครั้งแรก
อัปเดต Apps Script เป็นเวอร์ชันใหม่
- เปิด Apps Script ของชีต → วางโค้ด
apps-script/Code.gs ใหม่ทับทั้งหมด (ใส่ค่า SECRET เดิม) → บันทึก 💾
- เลือกฟังก์ชัน authorize ที่แถบด้านบน → กด Run → อนุญาตสิทธิ์ (เพิ่มสิทธิ์ส่งอีเมล ตั้งเวลา อ่านอีเมลเจ้าของ และเรียก URL ภายนอกเพื่อดึง PDF) แล้ว Deploy → Manage deployments → New version
- Deploy → Manage deployments → ✏️ → Version: New version → Deploy (URL เดิมใช้ต่อได้)
2. Vercel
- https://vercel.com/new → Import repo
ms-mook/PaotangMook → Deploy
- Settings → Environment Variables ใส่:
| ชื่อ | ค่า |
|---|
APP_PIN | PIN 4–8 หลัก |
AUTH_SECRET | ข้อความสุ่มยาว ๆ (openssl rand -hex 32) |
APPS_SCRIPT_URL | URL เว็บแอปจากข้อ 1.6 |
APPS_SCRIPT_SECRET | ค่าเดียวกับ SECRET ในสคริปต์ |
GEMINI_API_KEY | (ไม่บังคับ) สำหรับ AI อ่านสลิป — ขอฟรีที่ https://aistudio.google.com/apikey |
- Deployments → Redeploy
3. ตรวจการเชื่อมต่อ
เปิด https://<โดเมน>/setup (ใส่ PIN) — ถ้าขึ้น ✅ ครบทุกข้อ พร้อมลิงก์ชีตและโฟลเดอร์สลิป ก็ใช้งานได้เลย 🎉
4. ติดตั้งบนมือถือ
- iPhone (Safari): ปุ่มแชร์ → เพิ่มไปยังหน้าจอโฮม
- Android (Chrome): กดปุ่ม ติดตั้ง ในแอป หรือเมนู ⋮ → ติดตั้งแอป
พัฒนาบนเครื่อง
cp .env.example .env.local # ใส่ค่า
npm install
npm run dev
โครงสร้าง
app/page.tsx หน้าหลัก: สรุปรายเดือน + รายการ
app/login, app/setup PIN และหน้าตรวจการเชื่อมต่อ
app/api/transactions อ่าน/เพิ่ม/ลบรายการ + อัปสลิป (ผ่าน Apps Script)
app/api/slip/[id] แสดงรูปสลิปจาก Drive
apps-script/Code.gs โค้ดที่วางใน Apps Script ของชีต (เขียน Sheet + Drive)
app/api/scan AI อ่านสลิป (Gemini)
app/api/settings บันทึกการตั้งค่า / ส่งอีเมลสรุป
app/api/report สร้าง PDF สรุป (pdfkit + ฟอนต์ Mali ใน assets/fonts) เข้ารหัสด้วย APP_PIN
components/ TxForm (เพิ่ม/แก้ไข + อ่านสลิป), DetailSheet, ListView, StatsView, SettingsView
lib/store.ts ตัวเรียก Apps Script ฝั่ง server
lib/slipqr.ts แกะ QR สลิป / พร้อมเพย์
lib/image.ts ย่อรูป + สแกน QR ในเบราว์เซอร์ (jsQR)
proxy.ts ตรวจ session ทุก request
public/sw.js service worker (offline shell + share target)
หมายเหตุความปลอดภัย
- ล็อกเมื่อไม่ได้ใช้งานเกิน 5 นาที — ปิดแอปทิ้งไว้ สลับไปแอปอื่น หรือเปิดหน้าจอค้างไว้เฉย ๆ เกิน 5 นาที แล้วกลับมาจะถูกถาม PIN ใหม่ (ใช้งานต่อเนื่องไม่ถูกถาม, เซสชันเก่าสุด 90 วัน) ไม่ได้ล็อกเครื่องอื่นให้ ถ้ามือถือหายให้เปลี่ยน
AUTH_SECRET แล้ว Redeploy
- ล็อก PIN อัตโนมัติ — ใส่ผิด 5 ครั้ง ล็อก 15 นาที ถ้าโดนล็อกซ้ำโดยไม่ได้เข้าสำเร็จในระหว่างนั้น เวลาจะทบเป็น 30 นาที → 1 ชม. … (สูงสุด 24 ชม.) ใส่ถูกเมื่อไรก็เริ่มนับใหม่ ตัวนับเก็บใน Apps Script จึงจำข้ามเครื่องเซิร์ฟเวอร์ได้ ระหว่างล็อก มือถือที่ล็อกอินค้างไว้ยังใช้งานได้ตามปกติ
- แนะนำ PIN 6–8 หลัก — หน้า
/setup จะเตือนถ้า PIN สั้นกว่านั้น
- URL ของ Apps Script เป็นสาธารณะ แต่ทุกคำสั่งต้องมี
SECRET ที่ตรงกัน ซึ่งเก็บไว้ฝั่ง server (Vercel) เท่านั้น ไม่เคยส่งไปถึงเบราว์เซอร์
- สคริปต์ส่งรูปให้เฉพาะไฟล์ที่อยู่ในโฟลเดอร์สลิปเท่านั้น
- ห้าม commit
.env* (มีใน .gitignore แล้ว) — ค่าลับทั้งหมดอยู่ใน Vercel เท่านั้น
หมายเหตุเรื่อง PDF
- รหัสผ่านของ PDF คือ
APP_PIN ถ้า PIN สั้น (เช่น 4 หลัก) การเข้ารหัสจะกันได้แค่คนที่เปิดไฟล์ผ่าน ๆ ไม่ใช่คนตั้งใจเจาะ — ยิ่ง PIN ยาวยิ่งปลอดภัย
- อีเมลรายสัปดาห์ให้ Apps Script ไปขอ PDF จากแอปด้วย SECRET เดียวกัน (Script จำที่อยู่แอปเมื่อกดบันทึกการตั้งค่า/ส่งสรุปครั้งแรก) ถ้าดึงไม่ได้อีเมลยังส่งตามปกติแต่ไม่มีไฟล์แนบ
- เปลี่ยน
APP_PIN แล้ว PDF ใหม่จะใช้รหัสใหม่ทันที (ไฟล์เก่าที่ส่งไปแล้วยังใช้รหัสเดิม)