Skip to main content

Kiến trúc & Tech stack

Tech stack

LớpCông nghệ
FrameworkReact 18 + TypeScript 4.9
BuildCreate React App 5 + CRACO 7
Routingreact-router-dom v6 (BrowserRouter)
StylingTailwind CSS 3 + CSS variables (design tokens)
HTTPAxios 1.3
Formsreact-hook-form 7
Toastreact-hot-toast
Iconslucide-react
CAPTCHA@marsidev/react-turnstile (Cloudflare Turnstile)
Phone inputreact-phone-number-input
QR / Posterqrcode, html-to-image
Datedate-fns
MobileCapacitor 7 (Android wrapper, remote URL mode)
Monorepo@kioskgaming/ui, @kioskgaming/page-loading

Cấu trúc thư mục

kioskgaming_shop/
├── src/
│ ├── index.tsx # Entry point, đăng ký Service Worker
│ ├── App.tsx # Router + AuthProvider
│ ├── index.css # Tailwind + CSS variables
│ ├── config/env.ts # Biến môi trường tập trung
│ ├── constants/index.ts # API URL, storage keys, custom events
│ ├── types/index.ts # TypeScript interfaces
│ ├── services/api.ts # HTTP client + toàn bộ API functions
│ ├── hooks/ # useAuth, ledger hooks, zerox methods
│ ├── pages/ # 18 route pages
│ ├── components/
│ │ ├── auth/ # Login, forgot password, ProtectedRoute
│ │ ├── layout/ # AppLayout (sidebar, header, nav)
│ │ ├── credits/ # Mua credits, crypto wallets
│ │ ├── dashboard/ # Dashboard overview
│ │ ├── finance/ # Withdrawal limits panel
│ │ ├── players/ # Player detail panel
│ │ ├── poster/ # Promo poster templates
│ │ └── ui/ # ModalPortal, empty states
│ └── utils/ # format, ban, phone, ledger helpers
├── public/ # Static assets, PWA manifest, service worker
├── android/ # Capacitor Android wrapper
├── scripts/ # set-android-app-name.js
├── craco.config.js # CRA override (monorepo UI package)
├── capacitor.config.ts # Capacitor remote URL config
├── tailwind.config.js
├── vercel.json # SPA rewrite
└── deploy/nginx-spa.conf.example

Entry points

FileVai trò
src/index.tsxMount React, register Service Worker (production only)
src/App.tsxĐịnh nghĩa routes, bọc AuthProvider
src/services/api.tsLayer tích hợp backend (~1146 dòng)

State management

Không dùng Redux/Zustand. Kiến trúc state:

PatternVị tríMục đích
React Contexthooks/useAuth.tsxAuth state (user, token, login/logout)
Local useStateMỗi page/componentUI state, form, modal
Custom hooksuseShopWalletTransactions, useShopOnlineBalanceLedger, useSupportedZeroxMethodsData fetching có reload
localStorageAuth tokens, user data, zerox methods cache (24h TTL)
Custom Eventswindow.dispatchEventCross-component sync

Custom events

EventConstantKhi nào dispatch
shop-auth-token-changedSHOP_AUTH_TOKEN_CHANGED_EVENTLogin / logout
shop-credit-balance-refreshSHOP_CREDIT_BALANCE_REFRESH_EVENTSau flow thay đổi số dư
auth:unauthorizedAxios interceptor nhận 401

Storage keys

KeyNội dung
shop_auth_tokenBearer token shop
shop_user_dataProfile shop (JSON)
cashier_auth_tokenToken cashier (client riêng, không phải flow chính)
cashier_user_dataProfile cashier

Authentication flow

sequenceDiagram
participant U as Shop user
participant S as Shop Portal
participant B as Backend

U->>S: Nhập loginId + password
S->>B: POST /portal-auth/login
alt Cần OTP (2FA)
B-->>S: needsOtp + pendingToken
U->>S: Nhập OTP
S->>B: POST /shop-auth/verify-otp
end
B-->>S: accessToken + shop profile
S->>S: Lưu token vào localStorage
S->>B: GET /shop/me (refresh profile)
  • Header: Authorization: Bearer {token}
  • 401 → dispatch auth:unauthorized → auto logout
  • ProtectedRoute redirect về /login nếu chưa auth

Biến môi trường

BiếnBắt buộcMô tảDefault
REACT_APP_API_BASE_URLBackend API base URLhttp://localhost:3001/api
REACT_APP_TURNSTILE_ENABLEDKhôngBật Cloudflare Turnstilefalse
REACT_APP_TURNSTILE_SITE_KEYKhi bật TurnstileSite key''
REACT_APP_APP_NAMEKhôngTên app hiển thịKiosk Gaming — Shop
REACT_APP_CLIENT_TELEGRAM_SUPPORT_URLKhôngLink Telegram support
REACT_APP_CLIENT_ANDROID_APK_URLKhôngLink tải APK Android
REACT_APP_CLIENT_IOS_VIDEO_URLKhôngVideo hướng dẫn iOS
PORTKhôngDev server port3004
CAP_SERVER_URLBuild APKRemote URL cho Capacitorhttps://shop.kioskservice.club/
warning

Backend cần set SHOP_FRONTEND_URL trỏ về origin của app để redirect payment về /payment/success/payment/cancelled.


Scripts npm

ScriptMô tả
npm startDev server port 3004 (CRACO)
npm run buildProduction build
npm run cap:sync:devSync Capacitor → https://dev-shop.kioskservice.club/
npm run cap:sync:prodSync Capacitor → https://shop.kioskservice.club/
npm run apk:dev / apk:prodBuild APK debug

Cấu hình đặc biệt

CRACO + Monorepo UI

craco.config.js import configureKioskgamingUi từ ../packages/ui để webpack resolve shared UI package.

Capacitor Android

  • App ID: club.kioskservice.kioskgaming.shop
  • Remote URL mode: không bundle web assets, load từ URL remote
  • Dev: https://dev-shop.kioskservice.club/
  • Prod: https://shop.kioskservice.club/

SPA routing (production)

PlatformConfig
Vercelvercel.json rewrite /(.*) → /index.html
Netlify/Cloudflarepublic/_redirects
Nginxdeploy/nginx-spa.conf.example (try_files)

Service Worker

  • public/sw.js + serviceWorkerRegistration.ts
  • Chỉ register khi NODE_ENV === 'production'

Shared UI package

Components dùng chung từ @kioskgaming/ui:

  • PortalCreditTransactionsLedger, PortalUsdWalletLedgerTable
  • CreditTransactionDetailModal, UsdWalletTransactionDetailModal
  • WithdrawOtpStep, WithdrawBlockedAlert
  • FormField, Modal, Button, Input, Select, Textarea
  • PlayerFraudIndicatorsPanel, SupportDownloadRail

Sơ đồ tổng quan

flowchart TB
subgraph Client["kioskgaming_shop"]
Index[index.tsx] --> App[App.tsx]
App --> Auth[AuthProvider]
Auth --> Router[React Router]
Router --> Public["/login, /forgot-password"]
Router --> Protected["ProtectedRoute + Pages"]
Protected --> Layout[AppLayout]
Layout --> API[services/api.ts]
end

subgraph Backend["kioskgaming_backend"]
API -->|Bearer token| ShopAPI["/shop/*"]
API --> AuthAPI["/shop-auth/*, /portal-auth/*"]
API --> PaymentAPI["/payment/*"]
end

subgraph Storage["Browser"]
Auth --> LS["localStorage: shop_auth_token"]
end