ระบบร้านค้าออนไลน์ของ Korat เกิดขึ้นเพราะแม่ค้าพ่อค้าที่ขายอยู่ในห้องแชท สุดท้ายก็ต้องมีออเดอร์หลุดสักใบ สิ่งที่มาแทนห้องแชทนั้นตั้งใจให้ไม่หวือหวา คือแคตตาล็อกที่ค้นหาและกรองตามหมวดได้ หน้าสินค้าที่บอกสต็อกตั้งแต่ก่อนกด ตะกร้าที่ไม่เคยกำกวมว่าเป็นของร้านไหน และออเดอร์ที่เดินผ่านห้าสถานะที่มีชื่อชัดเจน พร้อมแจ้งเตือนทุกครั้งที่ขยับ
โปรแกรมขายหน้าร้าน ลงสินค้า ตัวเลือก และสต็อก
สินค้าแต่ละชิ้นมีรูป คำอธิบาย สต็อก และราคาที่ลดได้ โดยแสดงราคาลดคู่กับราคาเดิมที่ขีดฆ่าและป้ายเปอร์เซ็นต์ ขนาดของส่วนลดจึงอ่านออกจริง ไม่ใช่ให้เดาเอา เวลาสินค้าหมด คำว่าหมดจะทับอยู่บนรูป ไม่ใช่ไปเจอเอาตอนเช็กเอาต์ นี่คือกฎที่ทั้งแอปยึด อะไรก็ตามที่เปลี่ยนผลของการกด ต้องมองเห็นได้ก่อนกด ปุ่มต้องไม่สัญญาสิ่งที่หน้าจอถัดไปจะปฏิเสธ
ตัวเลือกสินค้าถูกสร้างจากคุณสมบัติ ไม่ใช่พิมพ์เข้าไปทีละอัน ผู้ขายประกาศแกนของมัน เช่น ไซซ์ สี หรืออะไรก็ตามที่สินค้าต่างกันจริง ๆ แล้วทุกการจับคู่ก็กลายเป็นตัวเลือกที่ถือสต็อกของตัวเอง วิธีนี้กันความพังที่พบบ่อยออกจากข้อมูล คือเสื้อตัวเดียวกันถูกลงขายสามรายการแยกกันจนรายงานรวมกันไม่ได้ และมีสต็อกที่ถูกต้องอยู่รายการเดียว
ตะกร้าสินค้า หนึ่งใบต่อหนึ่งร้าน
ตะกร้าหนึ่งใบต่อหนึ่งร้าน การเพิ่มสินค้าจากผู้ขายรายอื่นจะถามก่อนล้างของเดิม แทนที่จะค่อย ๆ สะสมตะกร้าที่คร่อมสี่ร้านโดยไม่บอก นี่คือการปฏิเสธเชิงออกแบบ ไม่ใช่ฟีเจอร์ที่ยังทำไม่เสร็จ ตะกร้าข้ามร้านแปลว่าต้องมีเช็กเอาต์เดียว การคิดค่าส่งเดียว และผู้รับผิดชอบเดียวเมื่อของไม่ถึง ซึ่งไม่มีสักอย่างเลยเมื่อผู้ขายคือธุรกิจท้องถิ่นสี่รายที่ต่างคนต่างมีวิธีส่งของตัวเอง
หนึ่งร้านต่อหนึ่งตะกร้า เป็นความตั้งใจ การสลับร้านจะถามเพื่อล้างตะกร้า ตะกร้าที่คร่อมหลายผู้ขายจะซื่อสัตย์ได้ก็ต่อเมื่อมีเช็กเอาต์เดียวรองรับ และที่นี่ไม่มีเช็กเอาต์กลางของมาร์เก็ตเพลส ทุกออเดอร์เป็นเรื่องระหว่างผู้ซื้อกับธุรกิจหนึ่งราย
ค่าส่งไม่ใช่ฟิลด์ที่แอปส่งขึ้นไป มันถูกอ่านออกมาจากข้อมูลของร้านเองบนเซิร์ฟเวอร์ตอนที่ออเดอร์ถูกสร้าง และคิดเฉพาะกรณีจัดส่งเท่านั้น
เช็กเอาต์ เลือกส่งหรือรับเอง ค่าส่งร้านเป็นคนตั้ง
หน้าเช็กเอาต์ถามเฉพาะสิ่งที่ออเดอร์ต้องใช้จริง คือส่งหรือรับเอง ชื่อ เบอร์โทร ที่อยู่ โน้ต และช่องทางชำระเงิน การเลือกรับเองจะตัดค่าส่งออกไปทั้งก้อน ไม่ใช่โชว์เป็นศูนย์ เพราะสองสถานะนี้ความหมายต่างกัน และเลขศูนย์อ่านแล้วเหมือนบั๊ก ที่อยู่ดึงมาจากสมุดที่อยู่ที่ตั้งค่าเริ่มต้นได้ ออเดอร์ที่สองจึงไม่ต้องพิมพ์ที่อยู่เดิมซ้ำ และเป็นสมุดที่อยู่เล่มเดียวที่ใช้ร่วมกับโปรไฟล์ เพราะที่อยู่ในโปรไฟล์กับที่อยู่จัดส่งคือข้อเท็จจริงเดียวกัน การเก็บสองที่รับประกันว่าสุดท้ายสองชุดนั้นจะไม่ตรงกัน
ตัวค่าส่งเองอยู่ฝั่งเซิร์ฟเวอร์ place_shop_order อ่าน businesses.delivery_fee จากฐานข้อมูลและไม่สนใจค่าที่ไคลเอนต์ส่งมา เหมือนกับที่ฝั่งนั่งกินที่ร้านคิดราคาทุกบรรทัดเอง ฟิลด์จากไคลเอนต์ที่เชื่อได้คือส่วนลดที่ลูกค้ากดให้ตัวเองได้ เซิร์ฟเวอร์เป็นเจ้าของเรื่องเงิน นี่ไม่ใช่นโยบายที่ปิดได้ในหน้าตั้งค่า มันคือที่มาของตัวเลขนั้นเลย
ตามออเดอร์ห้าขั้น ใส่เลขพัสดุ แจ้งเตือนทั้งสองฝั่ง
ออเดอร์เดินผ่านรอยืนยัน ยืนยันแล้ว กำลังแพ็ก จัดส่งแล้ว และส่งถึงแล้ว โดยมียกเลิกและถูกปฏิเสธเป็นปลายทางอีกสองสาย ผู้ซื้อเห็นเป็นแถบความคืบหน้าแทนที่จะเป็นคำว่าสถานะลอย ๆ คำเดียว คำว่า "กำลังแพ็ก" จึงอ่านได้ว่าเป็นตำแหน่งหนึ่งในลำดับที่ยังมีขั้นถัดไป เลขพัสดุถูกแนบตอนขั้นจัดส่ง พร้อมกับผู้ให้บริการขนส่งที่เลือกจากรายการที่แอดมินดูแลไว้ ซึ่งพกแม่แบบ URL ติดตามพัสดุมาด้วย เลขที่ร้านพิมพ์จึงกลายเป็นลิงก์ที่ผู้ซื้อกดเปิดได้ทันที และร้านจะแนบเลขพัสดุโดยไม่ระบุผู้ให้บริการไม่ได้ เพราะเลขที่ไม่รู้ว่าเป็นของเจ้าไหนกลายเป็นลิงก์ไม่ได้
ปลายทางทั้งสองแบบต้องมีเหตุผลกำกับ ลูกค้าที่ยกเลิกต้องบอกว่าทำไม ร้านที่ปฏิเสธก็ต้องบอกว่าทำไม และเหตุผลนั้นเดินทางไปกับออเดอร์ แทนที่จะเป็นข้อความที่เลื่อนหายไปในแชท ทุกการเปลี่ยนสถานะแจ้งเตือนทั้งสองฝั่ง เพราะระบบสั่งของที่ไม่มีแจ้งเตือนแปลว่าร้านพลาดออเดอร์และผู้ซื้อได้แต่เดา
- รอยืนยัน — สั่งแล้ว รอร้านตอบ
- ยืนยันแล้ว — ร้านรับออเดอร์ ผูกมัดแล้ว
- กำลังแพ็ก — กำลังเตรียมของ
- จัดส่งแล้ว — ออกจากร้าน พร้อมเลขพัสดุ
- ส่งถึงแล้ว — ปิดออเดอร์ และผู้ซื้อมีสิทธิ์เขียนรีวิว
โปรแกรมขายหน้าร้าน ออเดอร์ออนไลน์ และระบบจัดการสต๊อก
ธุรกิจค้าปลีกได้ไทล์ในคอนโซลสามอัน คือจุดขายหน้าร้านสำหรับขายต่อหน้า คอนโซลออเดอร์ออนไลน์สำหรับทุกอย่างที่เข้ามาทางแอป และสินค้ากับสต็อกที่เตือนเมื่อของใกล้หมด แดชบอร์ดมีป้ายตัวเลขสดที่รีเฟรชทุกไม่กี่วินาที ออเดอร์ใหม่จึงประกาศตัวเอง ไม่ใช่รอให้คนไปเปิดเจอ การขายหน้าร้านกับการขายผ่านแอปเขียนลงบัญชีเล่มเดียวกัน ยอดขาย สินค้าขายดี และรายชื่อลูกค้า จึงอ่านได้จากคอนโซลร้านค้าที่เดียว
เพราะทั้งสองช่องทางลงที่เดียวกัน รายงานจึงครอบคลุมทั้งร้าน ไม่ใช่แค่ส่วนออนไลน์ ทั้งยอดขาย จำนวนออเดอร์ ยอดเฉลี่ยต่อบิล การแยกตามเงินสด PromptPay และอื่น ๆ ห้าอันดับสินค้าขายดี กราฟแท่งยอดขายเจ็ดวัน และช่วงเวลาวันนี้ เจ็ดวัน สามสิบวัน หรือทั้งหมด ใบเสร็จพิมพ์ซ้ำได้ และสร้างข้อความใบเสร็จสำหรับส่งต่อได้จากข้อมูลชุดเดียวกัน ส่วนใบกำกับภาษียังออกไม่ได้ เพราะออกได้เฉพาะผู้จดทะเบียน VAT และระบบยังไม่ได้บันทึกการจดทะเบียนของร้านไหน รายชื่อลูกค้าก็สร้างจากบัญชีเล่มนั้นเช่นกัน พร้อมโน้ตและแท็กรายคน ประวัติการซื้อ แต้มสะสมตามอัตราที่ร้านตั้งเอง เทียบกับของรางวัลที่ตั้งเองได้
สิทธิ์ของพนักงานคุมด้วยตารางสิทธิ์ที่มีชุดบทบาทสำเร็จรูปและการปรับรายคน ผู้ช่วยขายจึงได้สิทธิ์ดูสินค้าและออเดอร์โดยไม่ต้องเห็นเงินเดือนหรือรายงาน ตารางเดียวกันนี้มีอยู่ในฐานข้อมูลในชื่อ has_capability(business_id, capability) ซึ่งกางบทบาทสำเร็จรูปออกฝั่งเซิร์ฟเวอร์ให้นโยบาย row-level security ใช้ เซิร์ฟเวอร์จึงไม่เคยเชื่อคำของไคลเอนต์ว่าใครถือบทบาทอะไร
โปรแกรมขายหน้าร้านกับร้านออนไลน์ ตั้งเวลาแยกกัน
เวลาเปิดปิดที่ร้านตั้งไว้บอกเรื่องหน้าร้านจริง — เคาน์เตอร์มีคนอยู่ตอนไหน ป้ายเปิดโชว์ตอนไหน ส่วนการสั่งซื้อผ่านหน้าร้านออนไลน์ไม่ได้ถูกกฎนี้กั้นเลย — place_shop_order ไม่มีการเช็กเวลาเปิดปิดใด ๆ ทั้งสิ้น ⇒ ร้านออนไลน์รับออร์เดอร์ต่อเนื่องได้ตลอด แม้ในวันที่หน้าร้านปิด นี่คือการแยกที่ตั้งใจ ไม่ใช่ช่องโหว่ที่ลืมปิด — ร้านที่แพ็กออเดอร์ออนไลน์จากที่บ้าน หรือร้านที่ปิดเคาน์เตอร์ 2 ทุ่มแต่อยากให้หน้าร้านออนไลน์รับออเดอร์ของพรุ่งนี้ได้แม้เที่ยงคืน ต้องการให้ฝั่งออนไลน์เปิดอิสระจากฝั่งกายภาพแบบนี้พอดี
รีวิวสินค้า เขียนได้เฉพาะคนที่ซื้อจริง
รีวิวสินค้าแยกจากรีวิวร้าน และทั้งคู่กั้นด้วยกฎเดียวกัน คือมีเฉพาะลูกค้าที่ระบบพิสูจน์ได้ว่าทำธุรกรรมจริงเท่านั้นที่เขียนได้ สิทธิ์นี้เป็นวิวในฐานข้อมูล และการซื้อคือหนึ่งในประเภทที่นับ เคียงข้างกับการนั่งกินที่ร้าน สั่งเดลิเวอรี เข้าพัก และใช้บริการ คนอื่นทั้งหมดเห็นการ์ดล็อกที่อธิบายว่าทำไมไม่มีปุ่มเขียน แทนที่จะเป็นปุ่มที่กดแล้วล้มเหลว
คะแนนดาวไม่ใช่ตัวเลขที่ใครแก้ได้ ทริกเกอร์ในฐานข้อมูลคำนวณมันใหม่จากแถวรีวิวจริง คะแนนบนการ์ดร้านกับรีวิวในหน้าจึงเถียงกันเองไม่ได้ ผู้ซื้อแก้รีวิวล่าสุดของตัวเองได้ ลบได้ หรือเขียนใหม่ตอนซื้อซ้ำโดยที่อันเก่ายังอยู่ ส่วนร้านตอบกลับแบบสาธารณะได้