ฉลากกินไม่แบ่งเบื้องหลังการสร้าง
จากไอเดีย ภาพ และเสียง สู่ตัวเกมและการเผยแพร่ เลือกดูแต่ละช่วง พร้อมปัญหาที่เจอและวิธีที่ใช้แก้
ภาพประกอบasset กระดาษฉลากที่ยังไม่มีข้อมูลสด แอปวาดเลขและข้อความทับใน runtime
สื่อประกอบ
ให้ AI วาดกระดาษ ให้แอปเขียนข้อมูลจริง
เริ่มจากอะไร
ให้ AI สร้างกระดาษและภาพประกอบ แล้วให้แอปวาดเลข เครดิต และข้อความสดลงบนพื้นที่ที่เว้นไว้
โจทย์ที่ต้องรับมือ
ถ้าเลขหรือข้อความติดมากับรูป จะเปลี่ยนตามรอบไม่ได้ และอ่านไม่ชัดเมื่อย่อภาพลงบนมือถือ
วิธีแก้
แยกภาพออกจากข้อมูลทั้งหมด ใช้แม่แบบที่ไม่มีตัวเลข แล้วตรวจหน้าแชร์ให้แสดงเฉพาะข้อมูลที่ระบบมีจริง
- กำหนด brief ของ ticket template พร้อมช่องเลขและพื้นที่ข้อมูลที่เว้นว่าง
- สร้าง raster เฉพาะกระดาษ ลายพิมพ์ และ illustration โดยไม่ใส่เลขหรือข้อความอ่านได้
- วางข้อความสดใน Flutter และตรวจ public share ให้ใช้เฉพาะ field ที่ API ส่งมา
รายละเอียดเทคนิคและผลตรวจ
กระบวนการพัฒนา
ทิศทางภาพใช้กระดาษตลาดไทย แมว และอาหารแบบ parody งานภาพเป็นฉากรองให้เลข เครดิต และผลรอบที่ต้องอ่านชัดและเปลี่ยนได้
- กำหนด brief ของ ticket template พร้อมช่องเลขและพื้นที่ข้อมูลที่เว้นว่าง
- สร้าง raster เฉพาะกระดาษ ลายพิมพ์ และ illustration โดยไม่ใส่เลขหรือข้อความอ่านได้
- วางข้อความสดใน Flutter และตรวจ public share ให้ใช้เฉพาะ field ที่ API ส่งมา
ข้อจำกัดในการออกแบบ
ข้อความหรือเลขที่ติดมากับภาพจะเปลี่ยนตามรอบไม่ได้ อ่านไม่ชัดเมื่อย่อ และเสี่ยงทำให้หน้าแชร์สื่อข้อมูลที่ระบบไม่ได้มี
วิธีแก้ในระบบ
แยก artwork ออกจาก dynamic text ใช้หกช่องว่างเป็นฐาน และ review concept ของหน้าแชร์เทียบกับ ShareResult response ก่อนทำจริง
ผลและขอบเขตการตรวจ
art manifest ระบุให้ TicketPreviewScreen/TicketLeafPreview วางข้อมูลสด และ visual review ของ public share v4 ผ่านในระดับ concept ไม่ใช่ผล runtime test
อ้างอิง: docs/ticket-template-art-manifest.md + docs/ux-ui-redesign/asset-reviews/29-ticket-public-share-v4.md
เสียงแตะสั้น ๆ ต้องไม่ผูกกับงานหลัก
เริ่มจากอะไร
ใช้เสียงแตะสั้น ๆ ผ่านระบบกลางเดียว พร้อมสวิตช์เปิด–ปิดที่จำค่าของผู้ใช้ไว้
โจทย์ที่ต้องรับมือ
เสียงอาจยังไม่พร้อมในการแตะครั้งแรก แต่ปุ่มและงานหลักของแอปต้องทำงานต่อได้ทันที
วิธีแก้
เตรียมเครื่องเล่นไว้ใช้ซ้ำ เล่นเสียงแบบไม่รอ และจัดการข้อผิดพลาดภายในระบบเสียงโดยไม่ขวางการใช้งาน
- โหลด preference และเตรียม AudioPool แบบใช้ซ้ำหนึ่งชุด
- ต่อเสียงผ่าน interaction ของ Material controls และแยก disabled controls
- จำกัด pool ไม่เกินสาม player และเรียกเล่นเสียงแบบไม่รอให้จบ
รายละเอียดเทคนิคและผลตรวจ
กระบวนการพัฒนา
แอปใช้ ui-click สั้นสำหรับปุ่มและเมนู มีสวิตช์เสียงใน Profile และบันทึก preference ระบบเสียงเป็นบริการร่วม ไม่สร้าง player ใหม่ในทุกปุ่ม
- โหลด preference และเตรียม AudioPool แบบใช้ซ้ำหนึ่งชุด
- ต่อเสียงผ่าน interaction ของ Material controls และแยก disabled controls
- จำกัด pool ไม่เกินสาม player และเรียกเล่นเสียงแบบไม่รอให้จบ
ข้อจำกัดในการออกแบบ
เสียงอาจไม่พร้อมเมื่อแตะครั้งแรก หรือ native audio plugin อาจไม่พร้อมใน widget test หาก flow หลักรอเสียง การตอบสนองของแอปจะผูกกับบริการที่ล้มได้
วิธีแก้ในระบบ
ถ้า pool ยังไม่พร้อมให้เริ่ม initialize แล้วกลับทันที จัดการ error ภายในบริการ ใช้ ambient session บน iOS และไม่แย่ง audio focus บน Android
ผลและขอบเขตการตรวจ
source มี widget tests สำหรับปุ่มที่กดได้ต้องขอเสียงหนึ่งครั้ง และปุ่ม disabled ต้องไม่ขอเสียง สิ่งนี้ตรวจ interaction contract ไม่ได้ยืนยันเสียงที่ได้ยินจากลำโพง
อ้างอิง: apps/mobile/lib/core/feedback/ui_sounds.dart + apps/mobile/test/core/ui_sounds_test.dart
ส่งรายการซ้ำได้ แต่หักเครดิตซ้ำไม่ได้
เริ่มจากอะไร
เชื่อมค้นหาเลข ตะกร้า ยืนยันรายการ และผลรอบ โดยให้เซิร์ฟเวอร์เป็นผู้ตัดสินเครดิตกับรางวัล
โจทย์ที่ต้องรับมือ
ถ้าเน็ตขาดระหว่างยืนยัน แอปอาจไม่รู้ว่ารายการสำเร็จแล้วหรือยัง การส่งซ้ำต้องไม่หักเครดิตอีกรอบ
วิธีแก้
ให้คำขอเดิมมีรหัสอ้างอิงเดิม เซิร์ฟเวอร์คืนรายการเดิมเมื่อส่งซ้ำ และบันทึกรายการกับเครดิตพร้อมกัน
- ค้นหา inventory ในเครื่อง และส่งรายการเมื่อผู้เล่นยืนยัน checkout
- ส่ง idempotency key พร้อม request fingerprint เพื่อระบุการ retry ของรายการเดิม
- commit order, ticket blob, request record และเครดิตใน transaction เดียว
รายละเอียดเทคนิคและผลตรวจ
กระบวนการพัฒนา
วงจรเลือกฉลากต้องเชื่อมค้นหาในเครื่อง ตะกร้า checkout และ settlement ฝั่งเซิร์ฟเวอร์ ใน monorepo ที่ Flutter กับ Go ใช้ Protobuf contract ร่วมกัน
- ค้นหา inventory ในเครื่อง และส่งรายการเมื่อผู้เล่นยืนยัน checkout
- ส่ง idempotency key พร้อม request fingerprint เพื่อระบุการ retry ของรายการเดิม
- commit order, ticket blob, request record และเครดิตใน transaction เดียว
ข้อจำกัดในการออกแบบ
network timeout ทำให้ client ไม่รู้ว่า server รับรายการไปแล้วหรือยัง ถ้า retry สร้างรายการใหม่ ผู้เล่นอาจถูกหักเครดิตซ้ำ ส่วน worker ที่ล้มกลาง settlement ต้องทำต่อโดยไม่สุ่มผลใหม่
วิธีแก้ในระบบ
key เดิมและ payload เดิมคืน order เดิม ถ้า payload ไม่ตรงให้ปฏิเสธ ผล draw ที่บันทึกแล้วแก้ทับไม่ได้ และมี marker กัน leaderboard บวกยอดซ้ำ
ผลและขอบเขตการตรวจ
atomicity contract ระบุวิธี recovery และ rejection ชัดเจน ขณะที่ production API lane ใช้ read-only checks ไม่สร้างรายการหรือออกรางวัลจริงเพื่อสาธิต
อ้างอิง: docs/atomicity-and-idempotency.md + docs/ticket-purchase-ux.md
จัดระบบหน้าจอก่อนแต่งรายละเอียด
เริ่มจากอะไร
ตรวจภาพรวมของหน้าจอ สี คำเรียก และเส้นทางเลือกฉลาก ก่อนแก้รายละเอียดเฉพาะจุด
ปัญหาที่เจอ
หน้าแต่ละส่วนใช้สีและรูปแบบไม่สอดคล้องกัน และบางหน้ามีข้อมูลทางเทคนิคที่ผู้ใช้ไม่จำเป็นต้องอ่าน
วิธีแก้
แนวทางจาก audit คือจัดธีมและเจ้าของหน้าจอให้ชัด ใช้คำอย่างฉลาก เครดิต และผลรอบในเส้นทางหลัก
- ทำ problem map เรื่อง hierarchy, type, color, navigation และ state ของแต่ละหน้า
- กำหนด screen ownership, domain components และ design tokens แทนชุด card ซ้ำ ๆ
- ตรวจ flow เลือกเลข–ตรวจรายการ–ผลลัพธ์ และข้อความที่ผู้ใช้เห็นให้เป็นศัพท์ของ product
รายละเอียดเทคนิคและผลตรวจ
กระบวนการพัฒนา
ก่อน redesign มี audit จาก source, widget tests และภาพ Android ที่เก็บไว้ เพราะช่วงนั้นยังเปิด runtime ของทุก target ไม่ได้ จึงต้องแยกข้อค้นพบจากภาพกับผลการกดใช้งานจริง
- ทำ problem map เรื่อง hierarchy, type, color, navigation และ state ของแต่ละหน้า
- กำหนด screen ownership, domain components และ design tokens แทนชุด card ซ้ำ ๆ
- ตรวจ flow เลือกเลข–ตรวจรายการ–ผลลัพธ์ และข้อความที่ผู้ใช้เห็นให้เป็นศัพท์ของ product
ปัญหาที่บันทึกไว้
Home มี implementation เก่าซ่อน Offstage คู่กับหน้าใหม่ สี cream/navy/red ใน feature ขัดกับ theme สีน้ำเงิน และบางหน้ามีข้อความ gRPC, hash หรือ UID ที่ไม่ช่วยให้ผู้ใช้ตัดสินใจ
วิธีแก้ในระบบ
รายงานวางทางแก้ที่ระดับ shared theme และเจ้าของหน้าจอ พร้อมใช้คำอย่างฉลาก เครดิต และผลรอบ แทนการเผยรายละเอียดระบบใน flow หลัก
ผลและขอบเขตการตรวจ
นี่คือข้อค้นพบและแนวทางจาก audit 5 ส.ค. ไม่ใช่คำยืนยันว่าทุกข้อถูกปิดแล้ว หลักฐาน runtime และ acceptance ของแต่ละการแก้ต้องตรวจแยก
อ้างอิง: docs/ui-redesign-audit.md · 5 Aug 2026
มีข้อมูลแล้ว ไม่ควรกลับไปเห็นหน้ารอ
เริ่มจากอะไร
เปิดหน้าด้วยข้อมูลที่เคยบันทึกไว้ก่อน แล้วดึงข้อมูลใหม่เบื้องหลังเพื่อให้กลับมาใช้งานต่อได้เร็ว
ปัญหาที่เจอ
การโหลดใหม่ทั้งหน้าทำให้ข้อมูลที่อ่านได้อยู่แล้วหายไปชั่วคราว ส่วนข้อมูลเก่าอาจถูกแสดงผิดเป็นฉลากของรอบใหม่
วิธีแก้
คงข้อมูลที่ยังใช้ได้ไว้ระหว่าง refresh และล้างรายการเก่าเมื่อเซิร์ฟเวอร์ยืนยันว่ารอบปัจจุบันยังไม่มีรายการ
- เก็บ Protobuf snapshot ของ bootstrap, รอบ, orders, ผล, อันดับ และ profile
- rehydrate เมื่อกลับ foreground และคง content ไว้ระหว่าง network refresh
- ล้าง order เก่าหาก server ยืนยันว่ารอบปัจจุบันยังไม่มีรายการ
รายละเอียดเทคนิคและผลตรวจ
กระบวนการพัฒนา
startup และ navigation ใช้ local cache เป็นภาพแรก แล้ว refresh จากเครือข่ายเบื้องหลัง เพื่อไม่ให้ทุกการเปลี่ยนหน้ารอ API ซ้ำ
- เก็บ Protobuf snapshot ของ bootstrap, รอบ, orders, ผล, อันดับ และ profile
- rehydrate เมื่อกลับ foreground และคง content ไว้ระหว่าง network refresh
- ล้าง order เก่าหาก server ยืนยันว่ารอบปัจจุบันยังไม่มีรายการ
ปัญหาที่บันทึกไว้
refresh ที่แทนทั้งหน้าด้วย loading ทำให้ข้อมูลที่อ่านได้อยู่แล้วหายชั่วคราว อีกด้านหนึ่ง cache ที่ไม่ผูกกับรอบอาจเอาฉลากของรอบเก่ามาแสดงเป็นของวันนี้
วิธีแก้ในระบบ
ให้ cache เป็น first render source เฉพาะ snapshot ที่มีความหมาย แล้ว reconcile กับ server โดยไม่ทิ้ง content ทั้งหน้า พร้อม invalidate ข้อมูลของรอบเก่า
ผลและขอบเขตการตรวจ
รายงาน 11 ส.ค. ระบุ Flutter 126 tests, Android cache-first E2E และ purchase E2E 2 กรณีผ่าน เป็นรายงานคนละชุดกับ store-readiness ที่มี 116 tests
อ้างอิง: docs/qa/cache-first-startup-e2e-2026-08-11.md
รวมทุกส่วน ก่อนส่งถึงมือผู้เล่น
จากงานแต่ละส่วนสู่แอปเดียว
เตรียม production flavor ของ Flutter เป็น AAB และตรวจ package กับ Firebase config ให้ตรงกับบริการจริง รายงาน 11 ส.ค. ระบุ artifact รุ่น 1.0.1+4
ตัวแอปและหน้าร้านต้องตรงกัน
แยกการทดสอบ API ที่ไม่แก้รายการจริงออกจากการซื้อและ settlement ในระบบทดสอบ รายงาน readiness มี Flutter 116 tests และ journey definitions 100 รายการ ซึ่งไม่ใช่การกดครบทุกเส้นทางบนเครื่องจริง
สถานะในบันทึกการเผยแพร่
รายงานยืนยัน health check, API แบบ authenticated read-only และ AAB พร้อมส่ง ส่วนหน้า product มีลิงก์ Google Play กับ App Store แต่รายงานนี้ไม่ได้เป็นใบยืนยันวันอนุมัติของทั้งสอง Store
อ้างอิงวันที่ในบันทึก ไม่ใช่สถานะ Store แบบเรียลไทม์
รายละเอียด Build และหลักฐาน
การรวมระบบ
- เริ่มจาก monorepo ที่มี Flutter app, Go API, Protobuf contract, infrastructure และ scripts ในที่เดียว
- ทำเส้นทาง anonymous login → ค้นหาเลข → ส่งฉลาก → settlement ฝั่งเซิร์ฟเวอร์ → ผลและอันดับ ให้เชื่อมกันครบ
- แยกการทดสอบที่แก้ข้อมูลออกจาก production read-only checks เพื่อเช็กระบบจริงโดยไม่ออกรางวัลหรือเพิ่มเครดิตระหว่าง QA
ผลตรวจ
รายงาน 11 ส.ค. 2026 บันทึก Go tests, Flutter 116 tests, static analysis และ journey catalog 100 รายการผ่าน พร้อมตรวจ API แบบ authenticated read-only ข้อมูลนี้เป็นหลักฐาน ณ วันที่รายงาน ไม่ใช่การรันทดสอบซ้ำในวันนี้
การส่งขึ้น Store
เตรียม production flavor และ AAB โดยตรวจ package และ Firebase configuration ให้ตรงกับบริการจริง รายงาน 11 ส.ค. 2026 บันทึก health check, authenticated API แบบ read-only, notification และ artifact ก่อนขึ้น Store หน้า product มีลิงก์ดาวน์โหลดทั้ง Android และ iOS
บันทึกอ้างอิง
- docs/ticket-template-art-manifest.md + docs/ux-ui-redesign/asset-reviews/29-ticket-public-share-v4.md
- apps/mobile/lib/core/feedback/ui_sounds.dart + apps/mobile/test/core/ui_sounds_test.dart
- docs/atomicity-and-idempotency.md + docs/ticket-purchase-ux.md
- docs/ui-redesign-audit.md · 5 Aug 2026
- docs/qa/cache-first-startup-e2e-2026-08-11.md
- README.md
- docs/architecture.md
- docs/qa/gcp-e2e-store-readiness-2026-08-11.md