Project manual · คู่มือการใช้งานและพัฒนา

น้องนอน · NongNorn

ร้านขายเตียงสัตว์เลี้ยงระดับโลก สองภาษา (ไทย/อังกฤษ) หลายสกุลเงิน หลายสาขา พร้อมระบบ Pet Avatar และผู้ช่วย AI — สไตล์ 70% Awwwards / 30% commerce

1. ภาพรวม

NongNorn คือเว็บอีคอมเมิร์ซขายเตียงสำหรับหมา/แมว ออกแบบให้โตระดับโลกได้ตั้งแต่วันแรก

ด้านเทคโนโลยี
FrameworkNext.js 16 (App Router) · React 19 · TypeScript
StylingTailwind CSS v4 (semantic token, dark mode แบบ class)
DatabaseSupabase — PostgreSQL + PostGIS + Storage + Auth
i18nnext-intl (เส้นทาง /th · /en)
PaymentsStripe (บัตร/คริปโต) + โอนเงิน + อัปสลิป
AIGoogle Gemini (free tier) — ผู้ช่วยแชท
DeployCloudflare (OpenNext Workers) + Cloudflare Stream (วิดีโอ)

โค้ดอยู่บน GitHub: github.com/artwa74/nongnorn

2. เริ่มใช้งาน

ยังไม่ต้องมี Supabase ก็รันได้ — เว็บจะเข้าสู่ โหมดเดโม่ (ข้อมูลตัวอย่าง + avatar น้องตัวอย่าง)

npm install
npm run dev        # เปิด http://localhost:3000  → เด้งไป /th
ใส่คีย์จริงเมื่อพร้อม: ก๊อป .env.example เป็น .env.local แล้วเติมค่า Supabase / Stripe / Cloudflare / Gemini

คำสั่งที่ใช้บ่อย

คำสั่งทำอะไร
npm run devรันเซิร์ฟเวอร์พัฒนา
npm run buildสร้าง production build
npm run db:pushส่ง schema เข้า Supabase
npm run cf:deploydeploy ขึ้น Cloudflare

3. โครงสร้างโปรเจกต์

src/
├─ app/[locale]/        หน้าเว็บ (layout + home + products/[slug])
├─ app/api/assistant/   ผู้ช่วย AI (route handler)
├─ components/
│  ├─ layout/           Navbar, PromoBar, ThemeToggle, LocaleSwitcher
│  ├─ product/          ProductCard, ProductDetail, ProductView
│  ├─ branch/           BranchShowcase
│  ├─ promo/            PromotionsSection
│  ├─ news/             NewsTicker
│  ├─ assistant/        AssistantDock (แชท mascot)
│  └─ ui/               Reveal (motion), Stars
├─ contexts/            PetAvatarContext, ThemeContext
├─ i18n/                routing, request, navigation
└─ lib/                 money, media, mascots, demo-data, cms-demo,
                        supabase/, cloudflare-stream
messages/th.json · messages/en.json     ข้อความสองภาษา
public/PicAvatar/       รูป mascot (malee, mabel)
supabase/migrations/    0001 schema · 0002 media+slips · 0003 cms

4. Design system

โทนอุ่นเฟรนด์ลี กำหนดเป็น token ใน src/app/globals.css สลับ light/dark อัตโนมัติ

สี (light)

Tokenใช้กับHex
paperพื้นหลัง#faf7f2
surfaceการ์ด#ffffff
inkตัวอักษรหลัก#2b2420
mutedตัวอักษรรอง#7a6e63
lineเส้นขอบ#e7ded3
accentสีแบรนด์#a4632e (dark #c8854f)
accent-softพื้นเน้นอ่อน#f1e7dc

ฟอนต์

Latin · Geistไทย · IBM Plex Sans Thai ตั้ง stack แบบ per-glyph — ละตินใช้ Geist, ไทยตกไป IBM Plex Sans Thai อัตโนมัติ

ธีมสี (6 โทน)

เลือกได้จากปุ่มจานสีบน Header หรือหน้า /admin: อบอุ่น (ค่าเริ่มต้น) · ขาว–ฟ้า · เทาเท่ · น้ำผึ้ง · ดินเผา · ดอกไม้ — ทำงานคู่กับ dark/light, จำค่าไว้ใน localStorage (nn.palette) และใช้ได้ทั้งเว็บผ่าน html[data-theme] override ตัวแปรสี

หน้าหลังบ้าน (Studio)

/admin — แดชบอร์ดมี sidebar: ภาพรวม · สินค้า · ออเดอร์ · โปรโมชั่น · ข่าวสาร · รีวิว · มาสคอต · ธีม/หน้าตา. สินค้า/โปรโมชั่น/ข่าว เพิ่ม/แก้/ลบได้จริง (CRUD) เก็บใน localStorage และ หน้าร้านดึงข้อมูลชุดเดียวกัน (ผ่าน CmsContext) — แก้ในหลังบ้านเห็นผลหน้าร้านทันที. ธีมสีตั้งได้เฉพาะในหลังบ้าน (หน้า ธีม/หน้าตา) ส่วนหน้าร้านมีแค่ปุ่ม dark/light. เชื่อม Supabase จริงแล้ว (โปรเจกต์ nongnorn) — สินค้า/โปรโมชั่น/ข่าวอ่านจาก DB. /blog — ฟีดบล็อกสไตล์โซเชียล

วิธีใช้หลังบ้าน (ที่เพิ่มใหม่)

  • สต็อก / Sold out: ใส่จำนวนในช่อง "สต็อก" ตอนแก้สินค้า — ถ้า 0 หน้าร้านจะขึ้น "สินค้าหมด" (การ์ดเป็นขาวดำ ปุ่มกดไม่ได้), ถ้าเหลือน้อยจะขึ้น "เหลือ N ชิ้น"
  • แปลไทย↔อังกฤษ (AI): ในฟอร์มแก้สินค้า/โปรโมชั่น/ข่าว มีปุ่ม TH → EN / EN → TH — พิมพ์ภาษาเดียวแล้วกดให้เติมอีกภาษาอัตโนมัติ (Google Translate)
  • แกลเลอรีตามสี: หน้าสินค้า กดเลือกสี รูปจะเปลี่ยนตามสีนั้น (ถ้าสีนั้นมีรูปของตัวเอง)
  • ออเดอร์จริง (ใหม่): ลูกค้ากด "ยืนยันสั่งซื้อ" ที่หน้าชำระเงิน → คำสั่งซื้อถูกบันทึกลง Supabase จริง แล้วโผล่ที่หน้า /admin/orders ทันที (มีป้าย "ของจริง"). เก็บชื่อ/เบอร์/ที่อยู่/รายการสินค้า/ยอดรวม/วิธีจ่าย. ยังไม่มีออเดอร์ = โชว์ตัวอย่างเดโม่

คอมโพเนนต์หลัก

ปุ่ม pill · chip หมวดหมู่ · badge ส่วนลด · ดาวรีวิว · การ์ดสินค้า · avatar น้อง · มุมโค้ง 8/12/40px · เส้น 0.5px · motion scroll-reveal (เคารพ prefers-reduced-motion)

5. สองภาษา (i18n)

ข้อความ UI อยู่ใน messages/th.json และ messages/en.json ส่วนชื่อสินค้า/สาขาเก็บเป็น jsonb ({"th":...,"en":...}) ใน DB — เพิ่มภาษาใหม่ไม่ต้องแก้ตาราง

เพิ่มภาษา (เช่น จีน)

// src/i18n/routing.ts
locales: ['th','en','zh']      // เพิ่ม 'zh'
// แล้วสร้าง messages/zh.json + เติมคีย์ zh ใน jsonb

6. แก้ไขเนื้อหา

ตอนยังไม่ต่อ DB เนื้อหามาจากไฟล์เดโม่ (src/lib/demo-data.ts, cms-demo.ts) เมื่อต่อ Supabase แล้วให้ดึงจากตารางแทน

เนื้อหาไฟล์เดโม่ตารางจริง
สินค้า / SKU / สต็อกdemo-data.tsproducts · variants · inventory_levels
สาขา + โปรโมทdemo-data.tsbranches
ข่าวสาร (ticker)cms-demo.tsnews
โปรโมชั่นcms-demo.tspromotions
Mascot ผู้ช่วยmascots.tsmascots

7. Mascot & ผู้ช่วย AI

เปลี่ยนรูป/ชื่อ Mascot

วางรูปจริงในโฟลเดอร์ public/PicAvatar/ (ใช้ชื่อเดิม หรือแก้ path ใน src/lib/mascots.ts)

  • malee.svgมาลี ตัวแลบลิ้น ขี้เล่น
  • mabel.svgมาเบล ใจเย็น ดูแลดี

รองรับ .png/.jpg/.webp ด้วย · รูปสี่เหลี่ยมจัตุรัส (1:1) สวยสุด · บุคลิก+คำทักทายแก้ได้ในไฟล์เดียวกัน หรือในตาราง mascots

เปิดผู้ช่วย AI จริง (Google Gemini — ฟรี)

# 1) ขอ API key ฟรีที่ https://aistudio.google.com/apikey
# 2) ใส่ใน .env.local
GEMINI_API_KEY=xxxxxxxx
GEMINI_MODEL=gemini-2.0-flash
ถ้าไม่ใส่คีย์ ผู้ช่วยจะตอบแบบเดโม่ (คำทักทาย + วิธีเปิด AI) — ใส่คีย์แล้วคุยกับลูกค้าได้จริงทันที โค้ดอยู่ที่ src/app/api/assistant/route.ts

AI ฟรีตัวอื่น (สลับได้)

Cloudflare Workers AI (รัน edge เดียวกับ deploy) · Groq (เร็วมาก) · OpenRouter (มีโมเดลฟรีหลายตัว)

8. Supabase (หลังบ้าน)

npx supabase login
npx supabase link --project-ref <project-ref-ของคุณ>
npm run db:push                       # ลง schema 0001–0003
# seed ข้อมูลเริ่มต้น: รัน supabase/seed.sql ใน SQL editor

ตารางหลัก

ตารางหน้าที่
profilesผู้ใช้ (ผูกกับ auth.users) ภาษา/สกุลเงิน/สิทธิ์ staff
pet_profilesรูปน้อง (Pet Avatar) ตามผู้ใช้ข้ามอุปกรณ์
products · variants · variant_pricesสินค้า + SKU (เช่น BED-DOG-BLK-M) + ราคาแต่ละสกุล
branches · inventory_levelsสาขา (PostGIS) + สต็อกต่อสาขา
orders · order_items · paymentsคำสั่งซื้อ + การชำระเงิน
payment_slipsสลิปโอน (เก็บคมชัด ตรวจโดย staff)
mascots · promotions · newsCMS — staff แก้ avatar/โปรโมชั่น/ข่าวได้

ตรรกะเด่น

allocate_order() — เมื่อมีออเดอร์ ระบบหาสาขาที่ มีของ และ ใกล้ที่สุด ด้วย PostGIS แล้วจองสต็อกแบบ atomic กัน oversell · ทุกตารางที่มีข้อมูลผู้ใช้เปิด RLS

เงินเก็บเป็นจำนวนเต็มหน่วยย่อย (สตางค์/cent) เสมอ ห้ามใช้ float — กันปัญหาปัดเศษ (ดู src/lib/money.ts)

9. Deploy (Cloudflare)

npx wrangler login
npm run cf:preview     # ทดสอบบน runtime ของ Workers ในเครื่อง
npm run cf:deploy      # deploy ขึ้นบัญชี Cloudflare

วิดีโอสินค้าส่งขึ้น Cloudflare Stream ซึ่ง transcode เป็น adaptive HLS ให้อัตโนมัติ (เซฟแบนด์วิดท์จริง) — ดู src/lib/cloudflare-stream.ts

รูป/วิดีโอสินค้า = บีบเล็กเซฟแบนด์วิดท์ · สลิปโอน = เก็บเกือบ original ให้อ่านออก (สองเส้นทางแยกกันใน src/lib/media.ts ห้ามรวม)

10. ซื้อขาย & หลังบ้าน

ร้านขายจริงครบวงจร — เงินเก็บเป็น สตางค์ (minor units) ทั้งระบบเสมอ

หน้าร้าน (ลูกค้า)

แคตตาล็อกจริง (variant/สี/ไซซ์/ผ้า) · รูปต่อสี + วิดีโอ · รีวิว · wishlist · ตะกร้า + checkout (โอนเงิน + แนบสลิป) · คูปอง + บัตรของขวัญ + แต้มสะสม ใช้รวมกันได้ · ค่าส่งตามโซน · ติดตามออเดอร์ (ไม่ต้องล็อกอิน) + ยกเลิก/ขอคืนสินค้าเอง · SEO JSON-LD · สินค้าแนะนำ/ดูล่าสุด · ตัวช่วยเลือกไซซ์ตามน้ำหนัก · ศูนย์ช่วยเหลือ/FAQ · แชทสด + ผู้ช่วย AI

หลังบ้าน /admin

สินค้า/คลัง/รับ-กระจาย · ออเดอร์ · แพ็คของ (พิมพ์ใบแพ็ค) · คืนสินค้า (RMA) · ยอดขาย · ลูกค้า · แชท · คูปอง · บัตรของขวัญ · โปรโมชั่น/ข่าว/บล็อก · รีวิว · หน้าแรก/สาขา/มาสคอต/อีเมล · ฟีเจอร์ (สวิตช์กลาง) · ตั้งค่าร้าน · ธีม

โหมด lock หลังบ้าน: ค่าเริ่มต้นเปิดให้เข้าได้ (bootstrap) — เปิด lock ใน ตั้งค่า แล้วจะเหลือเฉพาะบัญชีทีมงาน (profiles.is_staff) ดู src/lib/admin-auth.ts

11. ขายส่ง (B2B)

พอร์ทัลแยกที่ /wholesale-admin (เมนู/หน้าเข้าของตัวเอง ใช้บัญชีทีมงานเดิม) — เปิด/ปิดทั้งระบบด้วยฟีเจอร์ wholesale

  • สมัคร + อนุมัติ — ลูกค้าส่งสมัครที่ /wholesale → อนุมัติ/ปฏิเสธในหลังบ้าน → ผูกบัญชีด้วยอีเมล
  • ราคาขั้นบันได — กลุ่มราคา (tier %) + price rules (ตามจำนวน/variant/สินค้า/กลุ่ม) + พรีวิวราคาสด
  • MOQ + ยกลัง — ตั้งต่อสินค้า บังคับทั้งฝั่งลูกค้าและ server
  • ฝั่ง buyer/wholesale/shop: catalog ราคาส่ง + quick order ด้วย SKU + วางออเดอร์ (จ่ายก่อน/เครดิต) + ประวัติ
  • ใบเสนอราคา (RFQ) — ลูกค้าขอ → แอดมินตั้งราคา → ตอบรับ/แปลงเป็นออเดอร์
  • วางบิล/เครดิต — ออกใบแจ้งหนี้ (auto เมื่อสั่งแบบเครดิต) + มาร์คชำระ + เกินกำหนดอัตโนมัติ

ราคา คิดใหม่ฝั่ง server ตอนวางออเดอร์เสมอ (กันแก้ราคา) · ดู src/lib/wholesale/

12. แต้ม · บัตรของขวัญ · คืนสินค้า

แต้มสะสม & แนะนำเพื่อน

รับแต้มอัตโนมัติตอนสั่งซื้อ (ตั้งอัตราใน ตั้งค่าร้าน) · ใช้แต้มลดเงินตอนชำระ (1 แต้ม = ฿1) · ลิงก์แนะนำเพื่อน /account?ref=CODE → ผู้แนะนำได้แต้มเมื่อเพื่อนสั่งครั้งแรก

บัตรของขวัญ

ออกบัตรในหลังบ้าน (โค้ด + ยอด) · ลูกค้ากรอกตอน checkout → ตัดยอดฝั่ง server กัน double-spend

คืนสินค้า (RMA)

ลูกค้าขอคืนจากหน้าติดตามออเดอร์ → หลังบ้านไล่สถานะ ขอคืน → อนุมัติ → รับของ → คืนเงิน

ค่าส่งตามโซน

ตั้งโซน + ค่าส่งใน ตั้งค่าร้าน → ลูกค้าเลือกโซนตอน checkout (ไม่ตั้ง = ค่าส่งเหมาเดิม)

13. Feature flags & PWA

ทุกฟีเจอร์เปิด/ปิดได้จาก /admin/features (เก็บใน app_settings.site_features) — โค้ดอ่านด้วย useFeature("key") ([[FeatureContext]]) seed จาก server กัน flash · registry: src/lib/features.ts

วิธีเพิ่มฟีเจอร์ใหม่: เพิ่ม entry ใน FEATURES → gate จุดที่ render ด้วย useFeature(key)

PWA

ติดตั้งบนมือถือได้ (manifest + public/sw.js + ปุ่มติดตั้ง) · หลายสกุลเงิน (THB/USD/SGD/EUR ในเมนูตั้งค่า) · A/B testing primitive (src/lib/ab.ts) · a11y: focus-visible + skip link + reduced-motion (ใน globals.css)

ยังต้องใส่คีย์ภายนอกถึงจะครบ: PromptPay/บัตร (เกตเวย์) · LINE OA · RESEND_API_KEY (อีเมล) · OPENAI_API_KEY (AI รูปมาสคอต) · GA4/Meta/TikTok pixel · SENTRY_DSN

14. ปัญหาที่พบบ่อย

เว็บขึ้นข้อมูลตัวอย่าง ไม่ใช่ของจริง?

ยังไม่ได้ใส่ env ของ Supabase — เป็นโหมดเดโม่ ใส่ NEXT_PUBLIC_SUPABASE_URL + ANON_KEY แล้วต่อ DB

ผู้ช่วยตอบว่า "โหมดเดโม่"?

ยังไม่ได้ใส่ GEMINI_API_KEY — ใส่แล้วรีสตาร์ทเซิร์ฟเวอร์

รูปไม่ขึ้น?

โดเมนรูปภายนอกต้องเพิ่มใน next.config.ts ที่ images.remotePatterns

เปลี่ยนฟอนต์ไทย?

แก้ที่ src/app/[locale]/layout.tsx (เปลี่ยน import จาก next/font/google) — ตัวอย่าง: Anuphan, Kanit, Prompt, Bai Jamjuree