DutchBud: จาก Laravel API สู่ Go, OTAP CI และประตู regression บน ACC

posted in: Uncategorized | 0

เผยแพร่กรกฎาคม 2026 · บันทึกโครงสร้างพื้นฐานจาก 3DN

DutchBud คือแอปธนาคารส่วนตัวของเรา — แอป Android ที่สื่อสารกับ bank.dutchie.org ผ่าน JSON API การพาแอปจาก “ใช้ได้บนแล็ปท็อป” ไปเป็น “ใช้ได้บนมือถือผ่าน WireGuard ตอนตีสอง” ต้องแตะ DNS, pipeline deploy OTAP, การแยก API จาก Laravel ไป Go อย่างตั้งใจ และชุด regression test ที่เปรียบเทียบทุก release บน Acceptatie กับข้อมูลในรูปแบบ production โพสต์นี้คือทัวร์ครับ

แอป DutchBud บนสมาร์ทโฟนเชื่อมต่อกับโครงสร้างธนาคาร on-premises
DutchBud บนมือถือ API และสแตก OTAP ด้านหลังบนเครื่องที่เราควบคุม

ตั้งค่า DutchBud แบบ end-to-end

สแตกตั้งใจให้น่าเบื่อ — และนั่นเป็นคำชม:

  • Android client — แอป Kotlin ใช้ token auth กับ endpoint /api/*
  • Laravel web app — ยังให้ UI บราวเซอร์ migrations และสคริปต์ deploy OTAP ใน web root แยกตาม environment
  • Go bank-api — JSON API production บน application server คู่กันเป็น systemd service nginx ส่ง /api/ ผ่าน HAProxy ไป Go ส่วน Laravel ดูแลส่วนที่เหลือ
  • การเข้าถึง edge — client WireGuard resolve ชื่อภายในผ่าน authoritative DNS ของเรา bank.dutchie.org ไปถึง DMZ front ประเทศไทยบนเครือข่ายส่วนตัว

การทดสอบบนมือถือช่วงแรกเจอกับดัก ops คลาสสิก: BIND ที่หลุดมาบน gateway ตอบ DNS พร้อมพฤติกรรม AAAA เสีย ทำให้ resolution ของ WireGuard ดูโอเคจนกว่าจะไม่โอเค ชี้ client ไป resolver ที่ถูกต้อง หยุดบริการที่หลุดมา และแก้ port forwarding ทำให้ resolution คาดเดาได้อีกครั้ง login 422 กลายเป็นปัญหา reachability ไม่ใช่รหัสผ่านผิด — พอ DNS และ routing ซื่อสัตย์ แอปก็กลับมา

โต๊ะพัฒนาตอนกลางคืนพร้อมมือถือ Android และเทอร์มินัล
ส่วนไม่หรูของ mobile banking: DNS, token และกาแฟพอสำหรับอ่าน log ของ API service

ทำไมย้าย API จาก Laravel ไป Go

Laravel ยอดเยี่ยมสำหรับความเร็วในการทำ product แต่ไม่ค่อยยอดเยี่ยมเมื่อทุก API call จ่ายภาษี bootstrap framework PHP เต็มๆ บน path ที่แอป Android เรียกหลายสิบครั้งต่อ session เราวัดบน host เดียวกันก่อนตัดสินใจ:

  • Bootstrap framework Laravel อย่างเดียว: ~100 ms ก่อน controller ทำงาน
  • Go GET /api/bank-accounts: ~12 ms บน localhost
  • Go GET /api/payments?page=1: ~150 ms (ผูกกับ database ไม่ใช่ framework)
  • Go POST /api/login: ~280 ms — bcrypt ยังครอง login ชนะอยู่ที่อื่น

เกณฑ์ตัดสินเป็นเรื่องปฏิบัติ ไม่ใช่ศาสนา:

  1. Latency บน JSON path ร้อน — บัญชีและ list endpoint ต้องรู้สึกทันทีบนมือถือ
  2. memory footprint — Go binary เล็กต่อ node ชนะ PHP-FPM pool สำหรับ read-heavy API
  3. ความเรียบง่ายในการ operate — binary เดียว structured logging config บน API host
  4. เก็บ Laravel ตรงที่เก่ง — Blade UI Eloquent migrations playbook OTAP เดิมไม่เปลี่ยน
กราฟแท่งเปรียบเทียบ latency API Laravel และ Go
การเปรียบเทียบที่วัดได้ซึ่ง justify การแยก: Go บน /api/ Laravel บนพื้นผิวเว็บ

OTAP CI — จาก push dev ถึงประตู production

แอป bank เป็น OTAP pilot ของเรา GitLab CI บน dedicated runner deploy ตาม branch:

  • dev → Ontwikkel แล้ว fast-forward tst → Test
  • commit ต้องมี Refs #N pipeline โพสต์ “Ready for Test” บน issue ที่เชื่อม
  • acc → deploy Acceptatie แบบ manual หลังลูกค้าอนุมัติบน Test
  • master → Productie แบบ manual

Deploy คือ SSH git checkout ที่แข็งแกร่งบน application host: fetch hard reset ไป SHA ของ pipeline แก้สิทธิ์ รัน environment setup ถ้ามี ไม่มีปริศนา rsync — แค่ความจริงของ git ทุก stage

ไดอะแกรม stage GitLab CI OTAP DutchBud จาก dev ถึง regression check
flow OTAP รวม stage regression ACC ที่เพิ่มบน branch acc

Regression test บนรูปแบบ production จริง

Acceptatie ไม่ใช่ฐานข้อมูลของเล่น หลัง deploy:acceptatie แบบ manual CI รัน:

  1. sync:prod-db-to-acc — คัดลอกข้อมูล production ไป acceptance database พร้อม sync receipt storage
  2. migrate:acc — ใช้ Laravel migrations ที่ค้างบน ACC
  3. regression:check — ยิง ACC API สดและเทียบกับ baseline ที่ commit แล้ว

ชุดทดสอบอยู่ใน bank-api repository สี่ scenario — login, bank-accounts, budget-posts, payments หน้า 1 — แต่ละอัน 20 iteration แบบ sequential (~6 วินาทีรวม) ทุก scenario บันทึก HTTP status shape hash ของ JSON payload (โครงสร้างและ key ไม่ใช่ค่าที่เปลี่ยน) และ p95 latency baseline เริ่มต้นหลัง prod sync: login p95 598 ms bank-accounts 116 ms budget-posts 184 ms payments 178 ms กับ 58 payments และ 3 accounts

check job ทำให้ pipeline fail ถ้า shape เปลี่ยนหรือ p95 เกิน baseline × tolerance (1.25× ค่าเริ่มต้น 1.5× สำหรับ login) ต้องการ baseline ใหม่หลังเปลี่ยน API โดยตั้งใจ? รัน regression:capture แบบ manual แล้ว commit baseline ที่อัปเดตใน bank-api repo ผลลัพธ์อยู่ใน GitLab job log — ไม่ต้องพึ่ง SaaS ภายนอก

ไดอะแกรม flow regression ACC จาก sync ฐานข้อมูล production ถึงเทียบ baseline
ข้อมูล ACC ในรูปแบบ production → probe API แบบสคริปต์ → ประตู baseline ที่ commit

สิ่งที่เราเรียนรู้

แอปมือถือลงโทษบาปโครงสร้างพื้นฐานเล็กๆ DNS ที่เกือบใช้ได้แย่กว่า DNS ที่ล้มเหลวชัดเจน แยก API runtime ได้เมื่อขอบเขตคือ nginx และสัญญาคือ JSON OTAP ได้รับความไว้วางใจเมื่อ Test กับ Acceptatie ต่างกันเชิงกล — promotion แบบ manual บวก regression อัตโนมัติบนข้อมูล prod-shaped คือความต่างนั้น

DutchBud คือซอฟต์แวร์ส่วนตัวบนรางมืออาชีพ ครั้งหน้าที่หน้าบัญชีสีเขียวโหลดภายในหนึ่งวินาทีผ่าน WireGuard นั่นคือ Go, PowerDNS, GitLab CI และไฟล์ baseline ที่บอกว่า “ยังรูปแบบเดียวกับเมื่อวาน”

มีคำถามเกี่ยวกับโครงสร้างพื้นฐานหรือแนวทาง hosting ของเรา? ติดต่อเรา

ใส่ความเห็น

อีเมลของคุณจะไม่แสดงให้คนอื่นเห็น ช่องข้อมูลจำเป็นถูกทำเครื่องหมาย *