Appearance
Frontend Architecture — GGHut Storefront
Stack: Next.js 16 (App Router) · React 19 · TailwindCSS 4 · TypeScript
Deploy target: Cloudflare Pages (free, unlimited bandwidth)
Codebase:/nextjs-storefront
MỤC LỤC
- 1. Tổng quan
- 2. Cấu trúc thư mục
- 3. Tech stack chi tiết
- 4. Routing & Pages
- 5. Authentication
- 6. API Layer
- 7. State management & Data fetching
- 8. Component architecture
- 9. Styling
- 10. Types & Contracts
- 11. Vai trò trong hệ thống tổng thể
- 12. Lộ trình phát triển
1. TỔNG QUAN
Frontend là ứng dụng Next.js Storefront — giao diện khách hàng (Shopper) tương tác với hệ thống groupbuy/pre-order.
Chức năng chính:
| Chức năng | Mô tả |
|---|---|
| Storefront | Duyệt campaign, xem chi tiết sản phẩm, theo dõi slot realtime |
| Đặt cọc | Chọn slot → reserve → thanh toán cọc (VietQR) |
| Thanh toán phần còn lại | Sau khi campaign CLOSE và chốt giá tier |
| Quản lý đơn hàng | Xem trạng thái đơn, lịch sử thanh toán |
| Auth | Đăng ký / Đăng nhập / Phân quyền cơ bản |
Nguyên tắc thiết kế:
- Client-side rendering (CSR) cho các page tương tác (campaign detail, checkout)
- Server-side rendering (SSR/SSG) cho trang tĩnh (how-it-works, landing)
- JWT trong cookie — lưu token 7 ngày, tự redirect về
/loginkhi 401 - API-first — mọi dữ liệu lấy từ Go backend qua REST JSON
2. CẤU TRÚC THƯ MỤC
nextjs-storefront/
├── public/ # Static assets (favicon, images...)
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── layout.tsx # Root layout (AuthProvider + Header)
│ │ ├── page.tsx # Homepage (hero + campaign list)
│ │ ├── globals.css # TailwindCSS global styles
│ │ ├── campaigns/
│ │ │ ├── page.tsx # Danh sách tất cả campaign
│ │ │ └── [id]/
│ │ │ └── page.tsx # Chi tiết campaign + chọn slot
│ │ ├── orders/
│ │ │ └── page.tsx # Đơn hàng của user
│ │ ├── login/
│ │ │ └── page.tsx # Trang đăng nhập
│ │ ├── register/
│ │ │ └── page.tsx # Trang đăng ký
│ │ └── how-it-works/
│ │ └── page.tsx # Hướng dẫn quy trình
│ ├── components/ # Shared React components
│ │ ├── Header.tsx # Navigation bar (sticky)
│ │ └── CampaignCard.tsx # Card hiển thị campaign preview
│ ├── hooks/ # Custom React hooks
│ │ └── useAuth.tsx # Auth context + hook (login/register/logout)
│ ├── lib/ # Utilities & API clients
│ │ └── api.ts # Axios instance + API modules
│ └── types/ # TypeScript type definitions
│ └── index.ts # Campaign, Slot, Order, User, DTOs
├── next.config.ts # Next.js configuration
├── tsconfig.json # TypeScript config (path alias @/*)
├── tailwind.config (v4) # TailwindCSS via PostCSS
├── eslint.config.mjs # ESLint config
└── package.json3. TECH STACK CHI TIẾT
┌────────────────────────────────────────────────────────────┐
│ FRONTEND — Next.js Storefront │
├────────────────────────────────────────────────────────────┤
│ Framework : Next.js 16 App Router │
│ UI : React 19 + TailwindCSS 4 │
│ Language : TypeScript 5 (strict) │
│ HTTP : Axios (interceptors cho JWT + error handling) │
│ Auth : JWT (jose) lưu cookie · 7 ngày expiry │
│ State : React useState/useEffect + Context API │
│ Deploy : Cloudflare Pages (free, unlimited BW) │
│ Telemetry : Axios interceptor gửi header W3C traceparent │
└────────────────────────────────────────────────────────────┘Path aliases
jsonc
// tsconfig.json
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
}
}4. ROUTING & PAGES
| Route | File | Render | Mô tả |
|---|---|---|---|
/ | app/page.tsx | CSR | Homepage — hero + active campaigns |
/campaigns | app/campaigns/page.tsx | CSR | Danh sách tất cả campaign |
/campaigns/[id] | app/campaigns/[id]/page.tsx | CSR | Chi tiết campaign + chọn slot + đặt cọc |
/orders | app/orders/page.tsx | CSR | Đơn hàng của user (cần auth) |
/login | app/login/page.tsx | CSR | Form đăng nhập |
/register | app/register/page.tsx | CSR | Form đăng ký |
/how-it-works | app/how-it-works/page.tsx | CSR | Giải thích quy trình groupbuy |
Layout hierarchy
RootLayout (layout.tsx)
├── AuthProvider (context)
│ └── Header (navigation)
│ └── <main>{children}</main>5. AUTHENTICATION
Flow
Browser Go Backend
│ │
│ POST /api/auth/login │
│ {email, password} │
│ ─────────────────────────▶│
│ │ verify credentials
│ {token, user} │ sign JWT (jose)
│ ◀─────────────────────────│
│ │
│ Cookies.set('auth_token') │
│ (expiry: 7 days) │
│ │
│ GET /api/campaigns │
│ Authorization: Bearer ... │
│ ─────────────────────────▶│
│ │ verify JWT middlewareAuthProvider (Context API)
AuthProvider
├── user: User | null
├── isLoading: boolean
├── isAuthenticated: boolean
├── login(email, password)
├── register(email, password, name?, phone?)
├── logout()
└── refreshUser()- Wrap toàn bộ app trong
layout.tsx - On mount: đọc
auth_tokentừ cookie → gọi/auth/me→ populate user - Hook
useAuth()expose cho mọi component con
Token handling
- Storage:
js-cookie— cookieauth_token, 7 ngày - Request interceptor: tự gắn
Authorization: Bearer <token>vào mọi request - Response interceptor: nhận 401 → xoá cookie → redirect
/login
6. API LAYER
Axios instance (src/lib/api.ts)
api (axios)
├── baseURL: NEXT_PUBLIC_API_URL || http://localhost:8080/api
├── Request interceptor → gắn JWT
├── Response interceptor → handle 401
│
├── authAPI
│ ├── login(data) → POST /auth/login
│ ├── register(data) → POST /auth/register
│ ├── logout() → remove cookie
│ └── getMe() → GET /auth/me
│
├── campaignAPI
│ ├── getAll() → GET /campaigns
│ ├── getById(id) → GET /campaigns/:id
│ └── getActive() → GET /campaigns/active
│
├── slotAPI
│ ├── getByCampaign(campaignId) → GET /campaigns/:id/slots
│ ├── reserve(campaignId, slotId) → POST /campaigns/:id/slots/:slotId/reserve
│ └── release(campaignId, slotId) → POST /campaigns/:id/slots/:slotId/release
│
└── orderAPI
├── create(data) → POST /orders
├── getById(id) → GET /orders/:id
├── getMyOrders() → GET /orders/my
├── confirmPayment(data) → POST /orders/payment/confirm
└── getVietQRCode(orderId, type) → GET /orders/:id/payment/vietqrGiao thức với Backend
| Chiều | Protocol | Format |
|---|---|---|
| FE → BE | REST JSON over HTTPS | Axios + JWT Bearer |
| BE → FE (realtime) | SSE (tương lai) | EventSource API |
7. STATE MANAGEMENT & DATA FETCHING
Hiện tại (MVP)
- React useState + useEffect — fetch data on mount, store in local component state
- Context API (
AuthProvider) — global auth state - Không có global store (Redux/Zustand) — đủ cho MVP
Tương lai (theo architecture roadmap)
| Nhu cầu | Giải pháp |
|---|---|
| Server state cache | TanStack Query (REST) — cache, refetch, optimistic update |
| Realtime slot counter | SSE (EventSource native) — streaming slot availability |
| Admin dashboard | urql/Apollo (GraphQL) — khi backend expose GraphQL endpoint |
8. COMPONENT ARCHITECTURE
Component hierarchy
RootLayout
├── Header (sticky nav)
│ ├── Logo + Nav links
│ └── Auth buttons / User menu (conditional)
│
├── HomePage
│ ├── Hero section
│ ├── How-it-works (4 steps)
│ ├── Campaign list
│ │ └── CampaignCard[] (reusable)
│ └── CTA section
│
├── CampaignDetailPage
│ ├── Product image + info
│ ├── Pricing breakdown (deposit / remaining / total)
│ ├── Slot progress bar
│ └── Slot grid (5×N)
│ └── Slot buttons (available / reserved / selected)
│
└── OrdersPage
└── Order list (user's orders)Shared components
| Component | File | Mô tả |
|---|---|---|
Header | components/Header.tsx | Sticky nav, responsive, auth-aware |
CampaignCard | components/CampaignCard.tsx | Card preview: image, price, progress bar, status badge |
9. STYLING
- TailwindCSS v4 — utility-first, no custom CSS file ngoài
globals.css - Responsive: mobile-first, breakpoints
sm/md/lg - Color palette: Indigo primary (
indigo-600), Gray neutral, Green/Orange/Red cho status - Pattern: gradient hero sections, rounded cards with shadow, progress bars
10. TYPES & CONTRACTS
Domain types (src/types/index.ts)
typescript
User {
id, email, name?, phone?, is_admin
}
Campaign {
id, name, description, product_name, product_image?
original_price, deposit_amount, remaining_amount
total_slots, available_slots
start_time, end_time
status: 'draft' | 'active' | 'closed' | 'cancelled'
}
Slot {
id, campaign_id, slot_number
status: 'available' | 'reserved' | 'deposited' | 'completed' | 'cancelled'
reserved_at?, expires_at?
}
Order {
id, user_id, campaign_id, slot_id
deposit_amount, remaining_amount, total_amount
status: 'pending_deposit' | 'deposit_paid' | 'completed' | 'cancelled'
deposit_paid_at?, remaining_paid_at?
}DTO types
typescript
AuthResponse { token, user }
LoginRequest { email, password }
RegisterRequest { email, password, name?, phone? }
CreateOrderRequest { campaign_id, slot_id }
ConfirmPaymentRequest { order_id, payment_type, transaction_ref? }Note: Types này cần đồng bộ với Go backend. Tương lai có thể share qua monorepo package (Zod schemas).
11. VAI TRÒ TRONG HỆ THỐNG TỔNG THỂ
👤 SHOPPER
│
│ ① HTTPS
▼
┌───────────────────────────────────────────┐
│ FRONTEND · Next.js (App Router) │ ◄── YOU ARE HERE
│ Storefront(ISR) · Checkout(SSE) │
│ AdminDash · DraftReview │
└───────┬───────────────────────────────────┘
│ ② REST JSON + JWT
│ (+ SSE trong tương lai)
▼
┌───────────────────────────────────────────┐
│ GATEWAY · Go API Server │
│ JWT · RBAC · Validation │
└───────────────────────────────────────────┘Luồng dữ liệu chính
| # | Luồng | Giao thức |
|---|---|---|
| ① | Shopper → Next.js | HTTPS |
| ② | Storefront → Go Gateway | REST JSON + JWT Bearer |
| ③ | Gateway → FE (realtime) | SSE stream (tương lai) |
Telemetry (tương lai)
- Chưa implement — browsers không tự gửi
traceparentheader. Cần axios interceptor tạo W3C Trace Context (00-{trace-id}-{span-id}-01) và gắn vào mỗi request. - Khi triển khai: trace ID truyền xuyên suốt từ FE → Gateway → Go Engine
12. LỘ TRÌNH PHÁT TRIỂN
Phase 0 — MVP (hiện tại)
- [x] Campaign browsing (list + detail)
- [x] Slot reservation
- [x] Auth (login/register/JWT cookie)
- [x] Order creation
- [x] VietQR payment flow
- [x] Responsive UI (TailwindCSS)
Phase 1 — Realtime + UX
- [ ] SSE realtime slot counter (EventSource)
- [ ] TanStack Query cho server state cache
- [ ] Optimistic update khi reserve slot
- [ ] Loading skeletons thay vì spinner
- [ ] Error boundary + retry UI
Phase 2 — Admin & Review
- [ ] Admin dashboard (campaign CRUD)
- [ ] Draft review UI (crawler → approve/reject)
- [ ] Role-based UI (ẩn/hiện theo permission)
- [ ] Settlement payment flow (thanh toán phần còn lại)
Phase 3 — Multi-tenant
- [ ] Workspace-aware routing
- [ ] Tenant-specific theming
- [ ] Subscription/billing UI
Tài liệu trích xuất từ architecture.md — Frontend Architecture v1.0