1145 204 โครงงานสำหรับนักศึกษาปีสอง (Sophomore Project) สัปดาห์ที่ 5 · ระดับ Practiced (P) · 3(0-6-3)

สถาปัตยกรรมระบบและการสร้างแบบจำลองข้อมูลสำหรับแพลตฟอร์ม Grocery POS

SLIDE 01 / 10 · COURSE ORIENTATION Sprint 1: Architecture & Database Foundation

System Architecture & Data Modeling
สำหรับแพลตฟอร์ม Grocery POS

จากโครงงานปี 1 ที่สกัดสถิติจากไฟล์ CSV แบบ Static สู่โครงงานปี 2 (1145 204) ที่ทีม 4–5 คนต้องออกแบบระบบ POS ร้านขายของชำครบวงจรด้วยฐานข้อมูลเชิงสัมพันธ์ 3NF, สัญญา API ที่ชัดเจน และความทนทานต่อการใช้งานหน้าร้านพร้อมกันหลายจุด

01 · ARCHITECTURE 4-Layer แยก Client, Gateway, Domain และ DB ออกจากกัน
02 · DATA MODEL 8 Tables ออกแบบตามกฎ 3NF พร้อม Snapshot & Locking
03 · API CONTRACT OpenAPI 3.1 REST Endpoints, Status Codes และ Idempotency
04 · RISK & ETHICS ACID + PDPA ป้องกันสต็อกติดลบและปกป้องข้อมูลส่วนบุคคล

เส้นทางพัฒนาการชิ้นงาน POS ในหลักสูตร (ปี 1 → ปี 2 → ปี 3)

ชั้นปี / รายวิชา เป้าหมายเชิงสถาปัตยกรรม โครงสร้างข้อมูล (Data Complexity) ระดับพัฒนาการ
ปี 1 · 1145 103 สกัดและสรุปยอดขายด้วย Python/Pandas ไฟล์ CSV / JSON แบบ Static Log (ลบ PII เบื้องต้น) Reinforced (R)
ปี 2 · 1145 204 (สัปดาห์นี้) พัฒนาระบบ POS หน้าร้าน + คลังสินค้าแบบทีม Agile (Scrum) ฐานข้อมูลเชิงสัมพันธ์ Relational DB (3NF) + REST API Practiced (P)
ปี 3 · DS / SI Majors พยากรณ์สต็อกด้วย AI หรือ Microservices + Offline-First KDS Streaming Transactions / Distributed Event-Driven DB Mastery (M)
SLIDE 02 / 10 · DOMAIN & USE CASES Grocery POS Domain

Grocery POS ซับซ้อนกว่าจุดขายทั่วไปอย่างไร?

ร้านขายของชำและซูเปอร์มินิมาร์ทมีสินค้าหลายพัน SKU ที่ต้องสแกนบาร์โค้ดอย่างรวดเร็ว จัดการสินค้าชั่งน้ำหนัก สินค้ามีวันหมดอายุ และมีแคชเชียร์มากกว่า 1 ช่องทางตัดสต็อกจากคลังเดียวกันในเวลาเดียวกัน

GROCERY DOMAIN CHALLENGES

4 โจทย์เฉพาะทางของร้านขายของชำ

1. Barcode & SKU Lookup ความเร็วสูง
ต้องค้นหา EAN-13 / UPC ได้ภายใน < 50ms ต่อการสแกน 1 ครั้ง
2. สินค้าชั่งน้ำหนัก & หลายหน่วยนับ
จำนวน (quantity) ต้องรองรับทศนิยม (เช่น 0.750 กก.) ไม่ใช่แค่จำนวนเต็ม
3. ล็อตสินค้าและวันหมดอายุ (Batch & Expiry)
แยกตาราง Product ออกจาก Inventory Stock เพื่อรองรับ FIFO/FEFO
4. Multi-Lane Concurrent Checkout
แคชเชียร์ 2 จุดขายสินค้าชิ้นสุดท้ายพร้อมกันต้องไม่เกิดสต็อกติดลบ
INTERACTIVE USE CASE FLOW · CHECK OUT ITEM

คลิกเลือกสถานการณ์เพื่อดู Primary & Alternative Courses

SLIDE 03 / 10 · SYSTEM ARCHITECTURE DIAGRAM C4 Container / Layered View

สถาปัตยกรรมระบบ Grocery POS แบบ 4 ชั้น (คลิกสำรวจแต่ละส่วน)

แผนภาพที่ดีต้องแสดงขอบเขตความรับผิดชอบและทิศทางของ Dependency อย่างชัดเจน ตามหลัก Dependency Inversion (DIP) ชั้น Domain Policy ต้องไม่ผูกติดกับ SQL หรือฮาร์ดแวร์เครื่องสแกนโดยตรง คลิกที่กล่องในแผนภาพเพื่อดูรายละเอียด

LAYER 1 · PRESENTATION / EDGE TERMINALS LAYER 2 · API GATEWAY & SECURITY LAYER 3 · APPLICATION & DOMAIN MODULES (MODULAR MONOLITH) LAYER 4 · PERSISTENCE, CACHE & EXTERNAL GATEWAYS POS Cashier Terminal Web / Electron + Scanner Manager Backoffice Stock, Price, Reports Customer Display / QR PromptPay QR & Receipt REST API Gateway · TLS / JWT Auth / RBAC / Idempotency HTTPS/JSON (/api/v1/*) · Rate Limiter & Schema Validation Catalog Module SKU / UPC Lookup Price & Tax Rules Checkout / Order Cart, VAT, Receipt TDG Interface Inventory Module Atomic Deduction Reorder Alerts Payment Adapter Cash / PromptPay Card Verification PostgreSQL / MySQL (3NF RDBMS) ACID Transactions · Row Locks · Audit Trail Cache / Local Queue Barcode Hot Cache Bank / QR Webhook PromptPay / Card API
SLIDE 04 / 10 · ARCHITECTURAL DECISION Recommended for 1145 204

เลือก Modular Monolith สำหรับทีม 4–5 คน (และหลีกเลี่ยง Cyclic Dependency)

ในโครงงานปี 2 ที่มีเวลาพัฒนา 3 Sprints การแยกเป็น Microservices ตั้งแต่วันแรกเพิ่มภาระ Network, Distributed Transaction และ DevOps เกินความจำเป็น สถาปัตยกรรมที่เหมาะสมที่สุดคือ Modular Monolith ที่แบ่งขอบเขตโมดูลชัดเจนพร้อมต่อยอดเป็น Microservices ในปี 3

ARCHITECTURE COMPARISON

เปรียบเทียบ 3 รูปแบบสถาปัตยกรรม

เกณฑ์พิจารณา Spaghetti Monolith Modular Monolith Microservices
ความเร็วในการพัฒนา (3 Sprints) เร็วช่วงแรก ช้าช่วงท้าย เร็วและคุมคุณภาพได้ ช้า (Infra Overhead สูง)
ACID Transaction ข้าม Order–Stock ทำได้ (1 DB) ทำได้ทันที (1 DB) ซับซ้อน (ต้องใช้ Saga)
การทำงานเป็นทีม 4–5 คน Code ชนกันบ่อย แยก Module / PR ชัดเจน แยก Repo แต่ Debug ยาก
การขยายสู่ Cloud ปี 3 รื้อใหม่ทั้งหมด แยก Service ทีละโมดูลได้ รองรับระดับองค์กร
ACYCLIC DEPENDENCIES PRINCIPLE (ADP)

กติกาจัดวาง Dependency เป็น DAG

ตามหลักวิศวกรรมซอฟต์แวร์ (Robert C. Martin) กราฟการพึ่งพาระหว่าง Package ต้องเป็น Directed Acyclic Graph (DAG) ห้ามอ้างอิงวนกลับไปมา และใช้ Table Data Gateway (TDG) แยก Domain ออกจาก SQL:

POS Domain (Abstract) ← พึ่งพาโดยทุกโมดูล แต่ไม่พึ่งพา DB
↑ OrderGateway / ProductGateway / InventoryGateway (Interfaces)

แนวทางปฏิบัติของทีมปี 2

ห้ามเขียน SQL ใน Controller หรือ Route Handler โดยตรง ให้ผ่าน Gateway/Repository เพื่อให้เขียน Unit Test แบบ In-Memory ได้รวดเร็วไม่ต้องต่อ Database จริงทุกครั้ง
SLIDE 05 / 10 · NORMALIZATION STEPPER 1NF → 2NF → 3NF

Database Normalization: แปลงตารางใบเสร็จ Grocery สู่ 3NF

ตารางเดียวที่เก็บทุกอย่างปนกันก่อให้เกิด Update Anomaly (แก้ชื่อสินค้าหรือเบอร์ผู้ขายต้องแก้ทุกบรรทัด) และ Delete Anomaly กดเลือกแต่ละขั้นเพื่อดูการแยกโครงสร้างข้อมูลทีละระดับ

SLIDE 06 / 10 · RELATIONAL DB SCHEMA / ERD 8 Core Tables · 3NF

Entity-Relationship Diagram (ERD) ของแพลตฟอร์ม Grocery POS

คลิกที่ Entity ใดก็ได้ในแผนภาพ ERD ด้านซ้ายเพื่อตรวจสอบ Primary Key, Foreign Key, Constraints, Indexes และชุดคำสั่ง SQL DDL สำหรับ PostgreSQL ด้านขวา

1 : N 1 : N 1 : N 1 : N 1 : N 1 : N users PK user_id · role_enum orders PK order_id · order_no FK cashier_id, customer_id UQ idempotency_key order_items PK order_item_id FK order_id, product_id unit_price_snapshot payments PK payment_id · FK order_id method_enum (QR/CASH) amount · ref_txn_id products PK product_id · FK cat_id UQ barcode_upc, sku unit_price · unit_type customers (PDPA) PK customer_id phone_hash · consent_flag categories PK category_id name · vat_exempt inventory_stocks PK stock_id · FK product_id qty_on_hand · version 1 : N
POSTGRESQL SCHEMA & CONSTRAINTS

ตาราง orders


          
SLIDE 07 / 10 · DATA DESIGN PRINCIPLES & RISK Critical Project Risk

4 หลักการออกแบบข้อมูลสำคัญ: Snapshot, Concurrency, Idempotency, PDPA

ความเสี่ยงทางเทคนิคหลักที่ระบุในรายวิชา 1145 204 คือการตัดสต็อกพร้อมกันจากหลายจุดขายและการคุ้มครองข้อมูลส่วนบุคคล ทดลองจำลอง Race Condition ด้านล่างเพื่อดูความแตกต่างระหว่างโค้ดที่ปลอดภัยกับโค้ดที่มีช่องโหว่

1. Snapshot Data (ห้าม Join ราคาปัจจุบันในอดีต)

ตาราง order_items ต้องคัดลอก unit_price_snapshot และ tax_rate ณ เวลาขาย หากวันพรุ่งนี้ปรับราคานมสดขึ้น ยอดขายย้อนหลังและใบกำกับภาษีเดิมต้องไม่เพี้ยน

2. PDPA & PII Separation

เก็บข้อมูลระบุตัวตนลูกค้า (เบอร์โทร, ชื่อสมาชิก) แยกในตาราง customers แบบ Hash/Encrypted และส่งออกเฉพาะ customer_id หรือข้อมูลแบบ Anonymous เมื่อนำไปวิเคราะห์ยอดขาย
INTERACTIVE SIMULATOR · CONCURRENT STOCK DEDUCTION

จำลองแคชเชียร์ 2 เครื่องตัดสต็อกสินค้าชิ้นสุดท้ายพร้อมกัน (คงเหลือ 1 ชิ้น)

LANE A · CASHIER 01 สแกน "น้ำดื่ม 1.5L" (qty: 1)
พร้อมทำงาน: รอส่ง Transaction
DATABASE · INVENTORY_STOCKS
คงเหลือในคลัง: 1 ชิ้น
Constraint: CHECK (qty_on_hand >= 0)
LANE B · CASHIER 02 สแกน "น้ำดื่ม 1.5L" (qty: 1)
พร้อมทำงาน: รอส่ง Transaction
-- เลือกโหมดด้านบนเพื่อดูลำดับคำสั่ง SQL และผลลัพธ์ของ Transaction
SLIDE 08 / 10 · API CONTRACTS (OPENAPI / REST) OpenAPI 3.1 Specification

RESTful API Contracts: สัญญาระหว่าง Frontend POS และ Backend

ทีมพัฒนา 4–5 คนสามารถแยกงาน Frontend และ Backend ทำคู่ขนานใน Sprint 2 ได้ก็ต่อเมื่อตกลง OpenAPI Contract ล่วงหน้าให้ชัดทั้ง Path, HTTP Status Code, Idempotency Header และโครงสร้าง Error Response มาตรฐาน

ตาราง Core Endpoints ของแพลตฟอร์ม Grocery POS (/api/v1)

Method & Path หน้าที่ทางธุรกิจ (Use Case) Headers / Constraints Status Codes
GET /products/barcode/{upc} สแกนบาร์โค้ดเพื่อดึงชื่อ ราคา หน่วย และสต็อกคงเหลือ Authorization: Bearer JWT 200 404
POST /orders สร้างคำสั่งซื้อและตัดสต็อกแบบ Atomic Transaction Idempotency-Key: UUID 201 409 Conflict 422
POST /orders/{id}/payments บันทึกการรับชำระเงิน (เงินสด / PromptPay / บัตร) ตรวจสอบยอดชำระ ≥ ยอดสุทธิ 200 409
PATCH /inventory/{productId}/adjust ปรับสต็อกรับเข้า / สินค้าชำรุด (เฉพาะ Manager) Role: MANAGER + Audit Reason 200 403
OPENAPI 3.1 SNIPPET · POST /ORDERS
paths:
  /api/v1/orders:
    post:
      summary: Create POS order & deduct stock atomically
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema: { type: string, format: uuid }
      responses:
        '201': { description: Order created & stock reserved }
        '409': { description: Insufficient stock or duplicate key }
        '422': { description: Validation error (qty <= 0) }
STANDARD ERROR ENVELOPE (RFC 7807 STYLE)
{
  "error": {
    "code": "INSUFFICIENT_STOCK",
    "message": "สินค้า น้ำดื่ม 1.5L เหลือในคลังไม่เพียงพอ (เหลือ 1 ชิ้น)",
    "details": [
      { "product_id": 104, "requested": 2, "available": 1 }
    ],
    "trace_id": "req-9f82a10c"
  }
}
SLIDE 09 / 10 · INTERACTIVE API CONTRACT SANDBOX Try Request & DB Impact

ห้องทดลองจำลอง API Contract (Request → Response → DB State)

เลือกสถานการณ์ทดสอบเพื่อดูว่า Payload ที่ส่งเข้า Backend ถูกตรวจสอบ Validation อย่างไร ส่งคืน HTTP Status Code ใด และเปลี่ยนสถานะแถวข้อมูลในฐานข้อมูล 3NF อย่างไรบ้าง

REQUEST HEADERS & JSON BODY

            
HTTP RESPONSE & DB MUTATION พร้อมจำลอง

            

ผลกระทบต่อ Relational Database

กดปุ่ม "ส่งคำขอจำลอง" เพื่อตรวจสอบคำสั่ง SQL Transaction และแถวข้อมูลที่เปลี่ยนแปลง
SLIDE 10 / 10 · SPRINT 1 DELIVERABLES & SELF-CHECK 1145 204 · Week 5 Lab

Checklist ส่งมอบงานสัปดาห์ที่ 5 และแบบทดสอบทบทวนความเข้าใจ

ทำเครื่องหมายรายการที่ทีมของคุณออกแบบเสร็จแล้วสำหรับ Sprint 1 (ความคืบหน้าจะถูกบันทึกไว้ให้อัตโนมัติ) และทดสอบความเข้าใจ 3 ข้อท้ายคาบเรียน

SPRINT 1 ARCHITECTURE & DATA CHECKLIST 0 / 5 เสร็จสิ้น
QUICK CONCEPT CHECK (3 QUESTIONS) คะแนน: 0 / 3