Challenge Day 3: สร้างร้านค้าออนไลน์แบบ full-stack
ทำเป็นทีม สร้างร้านค้าเล็ก ๆ ที่ข้อมูลสินค้าและออเดอร์อยู่ในฐานข้อมูลจริง: Supabase เก็บข้อมูล, Express เป็น API, Next.js เป็นหน้าร้าน และทุกการเปลี่ยนแปลงเข้า main ผ่าน pull request
At a glance
| Item | Details |
|---|---|
| เวลา | ประมาณ 3 ชั่วโมง |
| ทีม | 3–4 คน |
| Stack | PostgreSQL (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 | ตารางและข้อมูลใน Supabase | feat/database |
| 2 | Express API | feat/api |
| 3 | หน้าแสดงสินค้า | feat/product-list |
| 4 | ปุ่มและฟอร์มสั่งซื้อ | feat/order-form |
Getting started
ตั้ง repo ของทีม
หัวหน้าทีมสร้าง repo
shopเพิ่มเพื่อนเป็น collaborator แล้วทุกคน clone (ดูวิธี)สร้างฐานข้อมูล
สร้างโปรเจกต์ 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);สร้าง API
ในโฟลเดอร์
server/ทำตาม Express › Installation และวาง route จาก Express › เขียน route แล้วเช็กว่าhttp://localhost:4000/api/productsได้ JSONสร้างหน้าร้าน
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> ); }ทำปุ่มสั่งซื้อ
ปุ่มมีการคลิก จึงต้องเป็น 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> ); }ส่งงานผ่าน pull request
ทุกคนทำงานใน branch ของตัวเอง เปิด PR ให้เพื่อนรีวิวก่อน merge (ดู flow)
เช็กของจริง
สั่งซื้อจากหน้าเว็บ แล้วเปิด Table Editor ใน Supabase ดูว่ามีแถวใหม่ใน
ordersและorder_items
Specification
- 3 ตารางใน Supabase:
products,orders,order_itemsและสินค้าอย่างน้อย 5 ชิ้น GET /api/productsคืนรายการสินค้าเป็น JSONPOST /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