Skip to content

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

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ăngMô tả
StorefrontDuyệt campaign, xem chi tiết sản phẩm, theo dõi slot realtime
Đặt cọcChọn slot → reserve → thanh toán cọc (VietQR)
Thanh toán phần còn lạiSau khi campaign CLOSE và chốt giá tier
Quản lý đơn hàngXem 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ề /login khi 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.json

3. 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

RouteFileRenderMô tả
/app/page.tsxCSRHomepage — hero + active campaigns
/campaignsapp/campaigns/page.tsxCSRDanh sách tất cả campaign
/campaigns/[id]app/campaigns/[id]/page.tsxCSRChi tiết campaign + chọn slot + đặt cọc
/ordersapp/orders/page.tsxCSRĐơn hàng của user (cần auth)
/loginapp/login/page.tsxCSRForm đăng nhập
/registerapp/register/page.tsxCSRForm đăng ký
/how-it-worksapp/how-it-works/page.tsxCSRGiả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 middleware

AuthProvider (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_token từ cookie → gọi /auth/me → populate user
  • Hook useAuth() expose cho mọi component con

Token handling

  • Storage: js-cookie — cookie auth_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/vietqr

Giao thức với Backend

ChiềuProtocolFormat
FE → BEREST JSON over HTTPSAxios + 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ầuGiải pháp
Server state cacheTanStack Query (REST) — cache, refetch, optimistic update
Realtime slot counterSSE (EventSource native) — streaming slot availability
Admin dashboardurql/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

ComponentFileMô tả
Headercomponents/Header.tsxSticky nav, responsive, auth-aware
CampaignCardcomponents/CampaignCard.tsxCard 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ồngGiao thức
Shopper → Next.jsHTTPS
Storefront → Go GatewayREST JSON + JWT Bearer
Gateway → FE (realtime)SSE stream (tương lai)

Telemetry (tương lai)

  • Chưa implement — browsers không tự gửi traceparent header. 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