/Projects
Day 3
ProjectsCS ChallengeChallengeDay 3

Challenge Day 3: สร้างร้านค้าออนไลน์แบบ full-stack

อ่านก่อน: PERN Stack, PostgreSQL, Express, GitHub

ทำเป็นทีม สร้างร้านค้าเล็ก ๆ ที่ข้อมูลสินค้าและออเดอร์อยู่ในฐานข้อมูลจริง: Supabase เก็บข้อมูล, Express เป็น API, Next.js เป็นหน้าร้าน และทุกการเปลี่ยนแปลงเข้า main ผ่าน pull request

At a glance

ItemDetails
เวลาประมาณ 3 ชั่วโมง
ทีม3–4 คน
StackPostgreSQL (Supabase) · Express · Next.js · Node.js
ผลลัพธ์หน้าร้านที่แสดงสินค้าจากฐานข้อมูล และสั่งซื้อได้จริง

Architecture

shop/                       ← GitHub repo เดียวของทีม
├── client/                 ← Next.js  (http://localhost:3000)
│   └── app/page.tsx        ← แสดงสินค้า + ปุ่มสั่งซื้อ
└── server/                 ← Express  (http://localhost:4000)
    ├── db.js
    └── index.js            ← GET /api/products, POST /api/orders

client ──fetch──▶ server ──SQL──▶ Supabase (PostgreSQL)
คนที่ทำส่วนbranch ตัวอย่าง
1ตารางและข้อมูลใน Supabasefeat/database
2Express APIfeat/api
3หน้าแสดงสินค้าfeat/product-list
4ปุ่มและฟอร์มสั่งซื้อfeat/order-form

Getting started

  1. ตั้ง repo ของทีม

    หัวหน้าทีมสร้าง repo shop เพิ่มเพื่อนเป็น collaborator แล้วทุกคน clone (ดูวิธี)

  2. สร้างฐานข้อมูล

    สร้างโปรเจกต์ Supabase รันคำสั่งสร้าง 3 ตารางจาก PostgreSQL › Structure แล้วเพิ่มสินค้าอย่างน้อย 5 ชิ้น

    insert into products (name, price, stock) values
      ('Latte', 65, 20), ('Americano', 55, 20), ('Matcha', 70, 15),
      ('Croissant', 55, 10), ('Brownie', 45, 12);
  3. สร้าง API

    ในโฟลเดอร์ server/ ทำตาม Express › Installation และวาง route จาก Express › เขียน route แล้วเช็กว่า http://localhost:4000/api/products ได้ JSON

  4. สร้างหน้าร้าน

    npx create-next-app@latest client --yes
    cd client
    npm run dev

    แสดงสินค้าจาก API ใน client/app/page.tsx (Server Component ดึงข้อมูลได้ตรง ๆ)

    // client/app/page.tsx
    import { OrderButton } from "./order-button";
    
    type Product = { id: number; name: string; price: string; stock: number };
    
    export default async function Home() {
      const res = await fetch("http://localhost:4000/api/products", { cache: "no-store" });
      const products: Product[] = await res.json();
    
      return (
        <main className="mx-auto max-w-2xl p-8">
          <h1 className="text-3xl font-bold">Our Shop</h1>
          <ul className="mt-6 grid gap-4">
            {products.map((p) => (
              <li key={p.id} className="flex items-center justify-between rounded-lg border p-4">
                <span>{p.name} · {Number(p.price)} บาท</span>
                <OrderButton productId={p.id} />
              </li>
            ))}
          </ul>
        </main>
      );
    }
  5. ทำปุ่มสั่งซื้อ

    ปุ่มมีการคลิก จึงต้องเป็น Client Component

    // client/app/order-button.tsx
    "use client";
    import { useState } from "react";
    
    export function OrderButton({ productId }: { productId: number }) {
      const [status, setStatus] = useState("");
    
      async function order() {
        setStatus("กำลังสั่ง…");
        const res = await fetch("http://localhost:4000/api/orders", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ customerName: "Guest", items: [{ productId, quantity: 1 }] }),
        });
        const data = await res.json();
        setStatus(res.ok ? "สั่งแล้ว #" + data.id : "ผิดพลาด: " + data.error);
      }
    
      return (
        <button onClick={order} className="rounded-md bg-black px-3 py-1.5 text-white">
          {status || "สั่งซื้อ"}
        </button>
      );
    }
  6. ส่งงานผ่าน pull request

    ทุกคนทำงานใน branch ของตัวเอง เปิด PR ให้เพื่อนรีวิวก่อน merge (ดู flow)

  7. เช็กของจริง

    สั่งซื้อจากหน้าเว็บ แล้วเปิด Table Editor ใน Supabase ดูว่ามีแถวใหม่ใน orders และ order_items

Specification

  • 3 ตารางใน Supabase: products, orders, order_items และสินค้าอย่างน้อย 5 ชิ้น
  • GET /api/products คืนรายการสินค้าเป็น JSON
  • POST /api/orders สร้างออเดอร์และรายการสินค้าในออเดอร์
  • หน้าเว็บ Next.js แสดงสินค้าจาก API (ไม่ได้พิมพ์ข้อมูลไว้ในโค้ด)
  • สั่งซื้อจากหน้าเว็บได้ และเห็นข้อมูลใหม่ใน Supabase
  • ทุกคนในทีมมี pull request ที่ถูก merge อย่างน้อย 1 อัน
  • ไม่มีรหัสฐานข้อมูลอยู่ใน GitHub (.env อยู่ใน .gitignore)

Hints

  • ต้องรัน 2 Terminal พร้อมกัน: server/ ที่พอร์ต 4000 และ client/ ที่พอร์ต 3000
  • error เรื่อง CORS ในเบราว์เซอร์: เช็กว่า app.use(cors()) อยู่ก่อน route ทั้งหมด
  • fetch failed ใน Next.js: เซิร์ฟเวอร์ Express ยังไม่ได้รัน หรือพอร์ตไม่ตรง
  • เชื่อม Supabase ไม่ได้: ใช้ URI แบบ Session pooler และแทน [YOUR-PASSWORD] ด้วยรหัสจริง (ไม่มีวงเล็บ)
  • price จาก PostgreSQL มาเป็น string ให้แปลงด้วย Number(p.price) ก่อนคำนวณ

How to submit

  • ลิงก์ GitHub repo ของทีม
  • ลิงก์ pull request ของแต่ละคน
  • วิดีโอหรือภาพหน้าจอสั้น ๆ ตอนสั่งซื้อแล้วข้อมูลขึ้นใน Supabase

ส่งงานครบทั้ง 3 วัน รับ 1:1 career consultation

Going further

  • ตะกร้าสินค้า สั่งหลายชิ้นในออเดอร์เดียว
  • หน้า Admin ดูออเดอร์ทั้งหมดและเปลี่ยนสถานะด้วย PATCH /api/orders/:id
  • ลด stock ทุกครั้งที่มีคนสั่ง และกันสั่งเกินของที่มี
  • ลองทำร้านเดียวกันแบบ Nextbase: ตัด Express ออก แล้วให้ Next.js คุยกับ Supabase ตรง ๆ
  • Deploy: client/ ขึ้น Vercel และ server/ ขึ้น Vercel แบบ Express แล้วเปลี่ยน URL ของ API เป็น environment variable

Next steps

  • Full-stack Intensive: เรียนต่อแบบเต็ม 6 สัปดาห์ ตั้งแต่ HTML ถึง full-stack app
CS ChallengeLast updated Oct 2026